1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 #include "SoRenderManagerP.h"
34 #include "coindefs.h"
35
36 #include <Inventor/nodes/SoInfo.h>
37 #include <Inventor/nodes/SoCamera.h>
38 #include <Inventor/nodes/SoPerspectiveCamera.h>
39 #include <Inventor/actions/SoGLRenderAction.h>
40 #include <Inventor/actions/SoGetBoundingBoxAction.h>
41 #include <Inventor/actions/SoGetMatrixAction.h>
42 #include <Inventor/actions/SoSearchAction.h>
43 #include <Inventor/actions/SoGLRenderAction.h>
44
45 SbBool SoRenderManagerP::touchtimer = TRUE;
46 SbBool SoRenderManagerP::cleanupfunctionset = FALSE;
47 int SoRenderManagerRootSensor::debugrootnotifications = -1;
48
49 #define PRIVATE(p) (p->pimpl)
50 #define PUBLIC(p) (p->publ)
51
52 #define INHERIT_TRANSPARENCY_TYPE -1
53
SoRenderManagerP(SoRenderManager * publ)54 SoRenderManagerP::SoRenderManagerP(SoRenderManager * publ)
55 {
56 this->publ = publ;
57 this->getmatrixaction = NULL;
58 this->getbboxaction = NULL;
59 this->searchaction = NULL;
60 }
61
~SoRenderManagerP()62 SoRenderManagerP::~SoRenderManagerP()
63 {
64 delete this->getmatrixaction;
65 delete this->getbboxaction;
66 delete this->searchaction;
67 }
68
69 // Internal callback.
70 void
redrawshotTriggeredCB(void * data,SoSensor *)71 SoRenderManagerP::redrawshotTriggeredCB(void * data, SoSensor * /* sensor */)
72 {
73 #if COIN_DEBUG && 0 // debug
74 SoDebugError::postInfo("SoRenderManager::redrawshotTriggeredCB", "start");
75 #endif // debug
76
77 SoRenderManager * thisp = (SoRenderManager *) data;
78
79 // Need to recheck the "active" flag, as it could have changed since
80 // it was tested in the SoRenderManager::scheduleRedraw() call.
81 if (PRIVATE(thisp)->isactive) { thisp->redraw(); }
82
83 #if COIN_DEBUG && 0 // debug
84 SoDebugError::postInfo("SoRenderManager::redrawshotTriggeredCB", "done\n\n");
85 #endif // debug
86 }
87
88 void
cleanup(void)89 SoRenderManagerP::cleanup(void)
90 {
91 SoRenderManagerP::touchtimer = TRUE;
92 SoRenderManagerP::cleanupfunctionset = FALSE;
93 }
94
95 void
updateClippingPlanesCB(void * closure,SoSensor * COIN_UNUSED_ARG (sensor))96 SoRenderManagerP::updateClippingPlanesCB(void * closure, SoSensor * COIN_UNUSED_ARG(sensor))
97 {
98 SoRenderManagerP * thisp = (SoRenderManagerP *) closure;
99 if (thisp->autoclipping != SoRenderManager::NO_AUTO_CLIPPING) {
100 thisp->setClippingPlanes();
101 }
102 }
103
104 void
setClippingPlanes(void)105 SoRenderManagerP::setClippingPlanes(void)
106 {
107 SoCamera * camera = this->camera;
108 SoNode * scene = this->scene;
109 if (!camera || !scene) return;
110
111 SbViewportRegion vp = this->glaction->getViewportRegion();
112
113 if (!this->getbboxaction) {
114 this->getbboxaction = new SoGetBoundingBoxAction(vp);
115 } else {
116 this->getbboxaction->setViewportRegion(vp);
117 }
118 this->getbboxaction->apply(scene);
119
120 SbXfBox3f xbox = this->getbboxaction->getXfBoundingBox();
121 SbMatrix cammat;
122 SbMatrix inverse;
123 this->getCameraCoordinateSystem(cammat, inverse);
124 xbox.transform(inverse);
125
126 SbMatrix mat;
127 mat.setTranslate(- camera->position.getValue());
128 xbox.transform(mat);
129 mat = camera->orientation.getValue().inverse();
130 xbox.transform(mat);
131 SbBox3f box = xbox.project();
132
133 float nearval = -box.getMax()[2];
134 float farval = -box.getMin()[2];
135
136 if (farval <= 0.0f) return;
137
138 if (camera->isOfType(SoPerspectiveCamera::getClassTypeId())) {
139 float nearlimit;
140 if (this->autoclipping == SoRenderManager::FIXED_NEAR_PLANE) {
141 nearlimit = this->nearplanevalue;
142 } else {
143 int depthbits = -1; // FIXME: (20070628 frodo)
144 if (depthbits < 0) depthbits = 32;
145 int use_bits = (int) (float(depthbits) * (1.0f - this->nearplanevalue));
146 float r = (float) pow(2.0, double(use_bits));
147 nearlimit = farval / r;
148 }
149
150 if (nearlimit >= farval) {
151 nearlimit = farval / 5000.0f;
152 }
153
154 if (nearval < nearlimit) {
155 nearval = nearlimit;
156 }
157 }
158
159 const float SLACK = 0.001f;
160 const float newnear = nearval * (1.0f - SLACK);
161 const float newfar = farval * (1.0f + SLACK);
162
163 const float neareps = nearval * SLACK * SLACK;
164 const float fareps = farval * SLACK * SLACK;
165
166 const float oldnear = camera->nearDistance.getValue();
167 const float oldfar = camera->farDistance.getValue();
168
169 // check that the values have changed before setting the fields to
170 // avoid continuous redraws on static scenes. Use an epsilon value
171 // when comparing
172
173 if (SbAbs(oldnear - newnear) > SbAbs(neareps)) {
174 camera->nearDistance = newnear;
175 }
176 if (SbAbs(oldfar - newfar) > SbAbs(fareps)) {
177 camera->farDistance = newfar;
178 }
179 }
180
181 void
getCameraCoordinateSystem(SbMatrix & matrix,SbMatrix & inverse)182 SoRenderManagerP::getCameraCoordinateSystem(SbMatrix & matrix,
183 SbMatrix & inverse)
184 {
185 SoCamera * camera = this->camera;
186 SoNode * scene = this->scene;
187 assert(camera && scene);
188
189 matrix = inverse = SbMatrix::identity();
190
191 if (!this->searchaction) {
192 this->searchaction = new SoSearchAction;
193 }
194
195 this->searchaction->reset();
196 this->searchaction->setSearchingAll(TRUE);
197 this->searchaction->setInterest(SoSearchAction::FIRST);
198 this->searchaction->setNode(camera);
199 this->searchaction->apply(scene);
200
201 if (this->searchaction->getPath()) {
202 if (!this->getmatrixaction) {
203 this->getmatrixaction =
204 new SoGetMatrixAction(this->glaction->getViewportRegion());
205 } else {
206 this->getmatrixaction->setViewportRegion(this->glaction->getViewportRegion());
207 }
208 this->getmatrixaction->apply(this->searchaction->getPath());
209 matrix = this->getmatrixaction->getMatrix();
210 inverse = this->getmatrixaction->getInverse();
211 }
212 this->searchaction->reset();
213 }
214
215 //**********************************************************************************
216 // Superimposition
217 //**********************************************************************************
218
219 class SuperimpositionP {
220 public:
221 SoNode * scene;
222 SbBool enabled;
223 SoRenderManager * manager;
224 SoNodeSensor * sensor;
225 uint32_t stateflags;
226 int transparencytype;
227 };
228
Superimposition(SoNode * scene,SbBool enabled,SoRenderManager * manager,uint32_t flags)229 SoRenderManager::Superimposition::Superimposition(SoNode * scene,
230 SbBool enabled,
231 SoRenderManager * manager,
232 uint32_t flags)
233 {
234 assert(scene != NULL);
235 PRIVATE(this) = new SuperimpositionP;
236
237 PRIVATE(this)->scene = scene;
238 PRIVATE(this)->scene->ref();
239
240 PRIVATE(this)->enabled = enabled;
241 PRIVATE(this)->stateflags = flags;
242
243 PRIVATE(this)->transparencytype = INHERIT_TRANSPARENCY_TYPE;
244
245 PRIVATE(this)->manager = manager;
246 PRIVATE(this)->sensor = new SoNodeSensor(Superimposition::changeCB, this);
247 PRIVATE(this)->sensor->attach(PRIVATE(this)->scene);
248 }
249
~Superimposition()250 SoRenderManager::Superimposition::~Superimposition()
251 {
252 PRIVATE(this)->scene->unref();
253 delete PRIVATE(this)->sensor;
254 delete PRIVATE(this);
255 }
256
257 int
getStateFlags(void) const258 SoRenderManager::Superimposition::getStateFlags(void) const
259 {
260 return PRIVATE(this)->stateflags;
261 }
262
263 void
render(SoGLRenderAction * action,SbBool clearcolorbuffer)264 SoRenderManager::Superimposition::render(SoGLRenderAction * action, SbBool clearcolorbuffer)
265 {
266 if (!PRIVATE(this)->enabled) return;
267
268 SoGLRenderAction::TransparencyType oldttype = action->getTransparencyType();
269 if (PRIVATE(this)->transparencytype != INHERIT_TRANSPARENCY_TYPE) {
270 action->setTransparencyType((SoGLRenderAction::TransparencyType) PRIVATE(this)->transparencytype);
271 }
272 SbBool zbufferwason = glIsEnabled(GL_DEPTH_TEST) ? TRUE : FALSE;
273
274 PRIVATE(this)->stateflags & Superimposition::ZBUFFERON ?
275 glEnable(GL_DEPTH_TEST):
276 glDisable(GL_DEPTH_TEST);
277
278 GLbitfield clearflags = clearcolorbuffer ? GL_COLOR_BUFFER_BIT : 0;
279 if (PRIVATE(this)->stateflags & Superimposition::CLEARZBUFFER) {
280 clearflags |= GL_DEPTH_BUFFER_BIT;
281 }
282
283 PRIVATE(this)->manager->renderScene(action, PRIVATE(this)->scene, (uint32_t) clearflags);
284
285 zbufferwason ?
286 glEnable(GL_DEPTH_TEST):
287 glDisable(GL_DEPTH_TEST);
288
289 if (PRIVATE(this)->transparencytype != INHERIT_TRANSPARENCY_TYPE) {
290 action->setTransparencyType(oldttype);
291 }
292 }
293
294 void
setEnabled(SbBool yes)295 SoRenderManager::Superimposition::setEnabled(SbBool yes)
296 {
297 PRIVATE(this)->enabled = yes;
298 }
299
300 void
changeCB(void * data,SoSensor * COIN_UNUSED_ARG (sensor))301 SoRenderManager::Superimposition::changeCB(void * data, SoSensor * COIN_UNUSED_ARG(sensor))
302 {
303 Superimposition * thisp = (Superimposition *) data;
304 assert(thisp && PRIVATE(thisp)->manager);
305 if (PRIVATE(thisp)->stateflags & Superimposition::AUTOREDRAW) {
306 PRIVATE(thisp)->manager->scheduleRedraw();
307 }
308 }
309
310 void
setTransparencyType(SoGLRenderAction::TransparencyType type)311 SoRenderManager::Superimposition::setTransparencyType(SoGLRenderAction::TransparencyType type)
312 {
313 PRIVATE(this)->transparencytype = (int) type;
314 }
315
316 void
invokePreRenderCallbacks(void)317 SoRenderManagerP::invokePreRenderCallbacks(void)
318 {
319 std::vector<RenderCBTouple>::const_iterator cbit =
320 this->preRenderCallbacks.begin();
321 while (cbit != this->preRenderCallbacks.end()) {
322 cbit->first(cbit->second, PUBLIC(this));
323 ++cbit;
324 }
325 }
326
327 void
invokePostRenderCallbacks(void)328 SoRenderManagerP::invokePostRenderCallbacks(void)
329 {
330 std::vector<RenderCBTouple>::const_iterator cbit =
331 this->postRenderCallbacks.begin();
332 while (cbit != this->postRenderCallbacks.end()) {
333 cbit->first(cbit->second, PUBLIC(this));
334 ++cbit;
335 }
336 }
337
338 #undef INHERIT_TRANSPARENCY_TYPE
339 #undef PRIVATE
340 #undef PUBLIC
341
342 void
notify(SoNotList * l)343 SoRenderManagerRootSensor::notify(SoNotList * l)
344 {
345 l->print();
346 (void)fprintf(stdout, "end\n");
347
348 inherited::notify(l);
349 }
350
351 SbBool
debug(void)352 SoRenderManagerRootSensor::debug(void)
353 {
354 if (SoRenderManagerRootSensor::debugrootnotifications == -1) {
355 const char * env = coin_getenv("COIN_DEBUG_ROOT_NOTIFICATIONS");
356 SoRenderManagerRootSensor::debugrootnotifications = env && (atoi(env) > 0);
357 }
358 return SoRenderManagerRootSensor::debugrootnotifications ? TRUE : FALSE;
359 }
360