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