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 /*!
34 \class SoRenderManager Inventor/SoRenderManager.h
35 \brief The SoRenderManager class is used for controlling the rendering of a scene graph.
36
37 You can use this class to configure things like clipping planes,
38 rendering mode, stereo rendering and the background color. In
39 earlier versions of Coin/Inventor, this was set up in the GUI
40 toolkits, making it quite hard to make a new Coin viewer for another
41 GUI toolkit. With this new class all that is needed is to create one
42 SoRenderManager instance per viewer/view.
43
44 This class does not handle events for the scene graph/viewer. To do
45 that you can use the \ref SoEventManager class.
46
47 \since Coin 3.0
48 */
49
50 /*! \file SoRenderManager.h */
51 #include <Inventor/SoRenderManager.h>
52
53 #include <algorithm>
54 //FIXME:Need this include early, since including it via SoRenderManagerP.h will cause problems for cygwin. Don't understand the root cause BFG 20090629
55 #include <vector>
56
57 #include <Inventor/system/gl.h>
58 #include <Inventor/nodes/SoInfo.h>
59 #include <Inventor/nodes/SoCamera.h>
60 #include <Inventor/elements/SoDrawStyleElement.h>
61 #include <Inventor/elements/SoComplexityTypeElement.h>
62 #include <Inventor/elements/SoPolygonOffsetElement.h>
63 #include <Inventor/elements/SoMaterialBindingElement.h>
64 #include <Inventor/elements/SoOverrideElement.h>
65 #include <Inventor/elements/SoTextureOverrideElement.h>
66 #include <Inventor/elements/SoTextureQualityElement.h>
67 #include <Inventor/elements/SoLightModelElement.h>
68 #include <Inventor/elements/SoLazyElement.h>
69 #include <Inventor/actions/SoGLRenderAction.h>
70 #include <Inventor/actions/SoAudioRenderAction.h>
71 #include <Inventor/actions/SoGLRenderAction.h>
72 #include <Inventor/sensors/SoOneShotSensor.h>
73 #include <Inventor/fields/SoSFTime.h>
74 #include <Inventor/misc/SoAudioDevice.h>
75 #include <Inventor/SoDB.h>
76
77 #include "coindefs.h"
78 #include "tidbitsp.h"
79 #include "misc/AudioTools.h"
80 #include "coindefs.h"
81
82 #if BOOST_WORKAROUND(COIN_MSVC, <= COIN_MSVC_6_0_VERSION)
83 // symbol length truncation
84 #pragma warning(disable:4786)
85 #endif // VC6.0
86
87 #include "SoRenderManagerP.h"
88
89 /*!
90 \enum SoRenderManager::RenderMode
91
92 Sets how rendering of primitives is done.
93 */
94
95 /*!
96 \var SoRenderManager::RenderMode SoRenderManager::AS_IS
97
98 Render primitives as they are described in the scenegraph.
99 */
100
101 /*!
102 \var SoRenderManager::RenderMode SoRenderManager::WIREFRAME
103
104 Render polygons as wireframe
105 */
106
107 /*!
108 \var SoRenderManager::RenderMode SoRenderManager::POINTS
109
110 Render only the vertices of the polygons and lines.
111 */
112
113 /*!
114 \var SoRenderManager::RenderMode SoRenderManager::WIREFRAME_OVERLAY
115
116 Render a wireframe overlay in addition to the AS_IS mode
117 */
118
119 /*!
120 \var SoRenderManager::RenderMode SoRenderManager::HIDDEN_LINE
121
122 As WIREFRAME, but culls lines which would otherwise not be shown due
123 to geometric culling.
124 */
125
126 /*!
127 \var SoRenderManager::RenderMode SoRenderManager::BOUNDING_BOX
128
129 Only show the bounding box of each object.
130 */
131
132 /*!
133 \enum SoRenderManager::StereoMode
134
135 Manages how to render steroscopic images.
136 */
137
138 /*!
139 \var SoRenderManager::StereoMode SoRenderManager::MONO
140
141 No stereoscopic rendering
142 */
143
144 /*!
145 \var SoRenderManager::StereoMode SoRenderManager::ANAGLYPH
146
147 Anaglyph rendering is used to provide a steroscopic 3D effect, when
148 viewed with 3D glasses. The image is made up of two color layers
149 which are superimposed on each other, and appears as 3 dimensional
150 when viewed through corresponding colored filters(glases)
151 */
152
153 /*!
154 \var SoRenderManager::StereoMode SoRenderManager::SEPARATE_OUTPUT
155
156 Send output to separate buffers.
157 */
158
159 /*!
160 \var SoRenderManager::StereoMode SoRenderManager::QUAD_BUFFER
161
162 Same as SEPARATE_OUTPUT, SEPARATE_OUTPUT is more commonly known as
163 QUAD_BUFFER, when also using double buffering.
164 */
165
166 /*!
167 \var SoRenderManager::StereoMode SoRenderManager::INTERLEAVED_ROWS
168
169 Render every second row as left and right image. If rendered with a
170 polarized projector, polarized filters kan be used to give a 3D
171 effect.
172 */
173
174 /*!
175 \var SoRenderManager::StereoMode SoRenderManager::INTERLEAVED_COLUMNS
176
177 Render every second column as left and right image. If rendered with
178 a polarized projector, polarized filters kan be used to give a 3D
179 effect.
180 */
181
182 /*!
183 \enum SoRenderManager::BufferType
184
185 Buffering strategy
186 */
187
188 /*!
189 \var SoRenderManager::BufferType SoRenderManager::BUFFER_SINGLE
190
191 Output to one buffer
192 */
193
194 /*!
195 \var SoRenderManager::BufferType SoRenderManager::BUFFER_DOUBLE
196
197 Alternate between output buffers
198 */
199
200 /*!
201 \enum SoRenderManager::AutoClippingStrategy
202
203 Strategy for adjusting camera near/far clipping plane
204 */
205
206 /*!
207 \var SoRenderManager::AutoClippingStrategy SoRenderManager::NO_AUTO_CLIPPING
208
209 Turn off automatic clipping. The user needs to set the correct values in the camera.
210 */
211
212 /*!
213 \var SoRenderManager::AutoClippingStrategy SoRenderManager::FIXED_NEAR_PLANE
214
215 Keep near plane at a fixed distance from the camera. The far plane is always set
216 at the end of the bounding box.
217 */
218
219 /*!
220 \var SoRenderManager::AutoClippingStrategy SoRenderManager::VARIABLE_NEAR_PLANE
221
222 Variable adjustment of the nearplane relative to the camera.
223 */
224
225 #define PRIVATE(p) (p->pimpl)
226 #define PUBLIC(p) (p->publ)
227
228 /*!
229 Constructor.
230 */
SoRenderManager(void)231 SoRenderManager::SoRenderManager(void)
232 {
233 assert(SoDB::isInitialized() && "SoDB::init() has not been invoked");
234
235 PRIVATE(this) = new SoRenderManagerP(this);
236
237 PRIVATE(this)->dummynode = new SoInfo;
238 PRIVATE(this)->dummynode->ref();
239
240 PRIVATE(this)->rootsensor = NULL;
241 PRIVATE(this)->scene = NULL;
242 PRIVATE(this)->camera = NULL;
243 PRIVATE(this)->rendercb = NULL;
244 PRIVATE(this)->rendercbdata = NULL;
245
246 PRIVATE(this)->stereostencilmask = NULL;
247 PRIVATE(this)->superimpositions = NULL;
248
249 PRIVATE(this)->doublebuffer = TRUE;
250 PRIVATE(this)->deleteaudiorenderaction = TRUE;
251 PRIVATE(this)->deleteglaction = TRUE;
252 PRIVATE(this)->isactive = TRUE;
253 PRIVATE(this)->texturesenabled = TRUE;
254
255 PRIVATE(this)->nearplanevalue = 0.6f;
256 PRIVATE(this)->stereooffset = 1.0f;
257 PRIVATE(this)->isrgbmode = TRUE;
258 PRIVATE(this)->backgroundcolor.setValue(0.0f, 0.0f, 0.0f, 0.0f);
259 PRIVATE(this)->backgroundindex = 0;
260 PRIVATE(this)->overlaycolor = SbColor(1.0f, 0.0f, 0.0f).getPackedValue();
261 PRIVATE(this)->stereostencilmaskvp = SbViewportRegion(0, 0);
262
263 PRIVATE(this)->stereostenciltype = SoRenderManager::MONO;
264 PRIVATE(this)->rendermode = SoRenderManager::AS_IS;
265 PRIVATE(this)->stereomode = SoRenderManager::MONO;
266 PRIVATE(this)->autoclipping = SoRenderManager::NO_AUTO_CLIPPING;
267 PRIVATE(this)->redrawpri = SoRenderManager::getDefaultRedrawPriority();
268 PRIVATE(this)->redrawshot =
269 new SoOneShotSensor(SoRenderManagerP::redrawshotTriggeredCB, this);
270 PRIVATE(this)->redrawshot->setPriority(PRIVATE(this)->redrawpri);
271
272 PRIVATE(this)->glaction = new SoGLRenderAction(SbViewportRegion(400, 400));
273 PRIVATE(this)->audiorenderaction = new SoAudioRenderAction;
274
275 PRIVATE(this)->clipsensor =
276 new SoNodeSensor(SoRenderManagerP::updateClippingPlanesCB, PRIVATE(this));
277 PRIVATE(this)->clipsensor->setPriority(this->getRedrawPriority() - 1);
278
279 }
280
281 /*!
282 Destructor.
283 */
~SoRenderManager()284 SoRenderManager::~SoRenderManager()
285 {
286 PRIVATE(this)->dummynode->unref();
287
288 if (PRIVATE(this)->deleteglaction) delete PRIVATE(this)->glaction;
289 if (PRIVATE(this)->deleteaudiorenderaction) delete PRIVATE(this)->audiorenderaction;
290 delete PRIVATE(this)->rootsensor;
291 delete PRIVATE(this)->redrawshot;
292
293 if (PRIVATE(this)->superimpositions != NULL) {
294 while (PRIVATE(this)->superimpositions->getLength() > 0) {
295 this->removeSuperimposition((Superimposition *)(*PRIVATE(this)->superimpositions)[0]);
296 }
297 delete PRIVATE(this)->superimpositions;
298 }
299
300 delete PRIVATE(this)->clipsensor;
301
302 if (PRIVATE(this)->scene)
303 PRIVATE(this)->scene->unref();
304 this->setCamera(NULL);
305
306 delete PRIVATE(this);
307 }
308
309 /*!
310 Set the node which is top of the scene graph we're managing. The \a
311 sceneroot node reference count will be increased by 1, and any
312 previously set scene graph top node will have it's reference count
313 decreased by 1.
314
315 \sa getSceneGraph()
316 */
317 void
setSceneGraph(SoNode * const sceneroot)318 SoRenderManager::setSceneGraph(SoNode * const sceneroot)
319 {
320 this->detachClipSensor();
321 this->detachRootSensor();
322 // Don't unref() until after we've set up the new root, in case the
323 // old root == the new sceneroot. (Just to be that bit more robust.)
324 SoNode * oldroot = PRIVATE(this)->scene;
325
326 PRIVATE(this)->scene = sceneroot;
327
328 if (PRIVATE(this)->scene) {
329 PRIVATE(this)->scene->ref();
330 this->attachRootSensor(PRIVATE(this)->scene);
331 this->attachClipSensor(PRIVATE(this)->scene);
332 }
333
334 if (oldroot) oldroot->unref();
335 }
336
337 /*!
338 Returns the pointer to root of scene graph.
339 */
340 SoNode *
getSceneGraph(void) const341 SoRenderManager::getSceneGraph(void) const
342 {
343 return PRIVATE(this)->scene;
344 }
345
346 /*!
347 Sets the camera to be used.
348 */
349 void
setCamera(SoCamera * camera)350 SoRenderManager::setCamera(SoCamera * camera)
351 {
352 // avoid unref() then ref() on the same node
353 if (camera == PRIVATE(this)->camera) return;
354
355 if (PRIVATE(this)->camera) {
356 PRIVATE(this)->camera->unref();
357 }
358 PRIVATE(this)->camera = camera;
359 if (camera) camera->ref();
360 }
361
362 /*!
363 Returns the current camera.
364 */
365 SoCamera *
getCamera(void) const366 SoRenderManager::getCamera(void) const
367 {
368 return PRIVATE(this)->camera;
369 }
370
371 /*
372 Internal callback
373
374 \param[in] data Pointer to SoRenderManager
375
376 \deprecated Will be made private in a later version of Coin
377 */
378 void
nodesensorCB(void * data,SoSensor *)379 SoRenderManager::nodesensorCB(void * data, SoSensor * /* sensor */)
380 {
381 #if COIN_DEBUG && 0 // debug
382 SoDebugError::postInfo("SoRenderManager::nodesensorCB",
383 "detected change in scene graph");
384 #endif // debug
385 ((SoRenderManager *)data)->scheduleRedraw();
386 }
387
388 /*!
389 Attaches this SoRenderManagers rootsensor to a scene
390
391 \param[in] sceneroot scene to attach to
392
393 \deprecated Will be private available in Coin 4
394 */
395 void
attachRootSensor(SoNode * const sceneroot)396 SoRenderManager::attachRootSensor(SoNode * const sceneroot)
397 {
398 if (!PRIVATE(this)->rootsensor) {
399 (SoRenderManagerRootSensor::debug()) ?
400 PRIVATE(this)->rootsensor = new SoRenderManagerRootSensor(SoRenderManager::nodesensorCB, this):
401 PRIVATE(this)->rootsensor = new SoNodeSensor(SoRenderManager::nodesensorCB, this);
402 // set a high priority on the root sensor. The actual redraw
403 // scheduling is handled by the redraw sensor at the correct
404 // priority (root sensor callback triggers the redraw sensor). Set
405 // priority to 1 in the normal case, and 0 if the redraw priority
406 // is actually set to 0
407 PRIVATE(this)->rootsensor->setPriority(PRIVATE(this)->redrawpri == 0 ? 0 : 1);
408 }
409 PRIVATE(this)->rootsensor->attach(sceneroot);
410 }
411
412 /*
413 Detaches the rootsensor from all tracked scenes
414
415 \deprecated Will not be available in Coin 4
416 */
417 void
detachRootSensor(void)418 SoRenderManager::detachRootSensor(void)
419 {
420 if (PRIVATE(this)->rootsensor) {
421 PRIVATE(this)->rootsensor->detach();
422 }
423 }
424
425 /*
426 Attaches this SoRenderManagers clipsensor to a scene
427
428 \param[in] sceneroot scene to attach to
429
430 \deprecated Will not be available in Coin 4
431 */
432 void
attachClipSensor(SoNode * const sceneroot)433 SoRenderManager::attachClipSensor(SoNode * const sceneroot)
434 {
435 PRIVATE(this)->clipsensor->attach(sceneroot);
436 if (PRIVATE(this)->autoclipping != SoRenderManager::NO_AUTO_CLIPPING) {
437 PRIVATE(this)->clipsensor->schedule();
438 }
439 }
440
441 /*
442 Detaches the clipsensor from all tracked scenes
443
444 \deprecated Will not be available in Coin 4
445 */
446 void
detachClipSensor(void)447 SoRenderManager::detachClipSensor(void)
448 {
449 if (PRIVATE(this)->clipsensor->isScheduled()) {
450 PRIVATE(this)->clipsensor->unschedule();
451 }
452 if (PRIVATE(this)->clipsensor->getAttachedNode()) {
453 PRIVATE(this)->clipsensor->detach();
454 }
455 }
456
457 /*!
458 Clears buffers with the backgroundcolor set correctly
459
460 \param[in] color Set to \c TRUE if color buffer should be cleared
461 \param[in] depth Set to \c TRUE if depth buffer should be cleared
462 */
463 void
clearBuffers(SbBool color,SbBool depth)464 SoRenderManager::clearBuffers(SbBool color, SbBool depth)
465 {
466 GLbitfield mask = 0;
467 if (color) mask |= GL_COLOR_BUFFER_BIT;
468 if (depth) mask |= GL_DEPTH_BUFFER_BIT;
469 const SbColor4f bgcol = PRIVATE(this)->backgroundcolor;
470 glClearColor(bgcol[0], bgcol[1], bgcol[2], bgcol[3]);
471 glClear(mask);
472 }
473
474 /*
475 Internal callback
476
477 \param[in] userdata GLbitfield mask
478 \param[in] action Calling action
479
480 \deprecated Will be made private in a later version of Coin
481 */
482 void
prerendercb(void * userdata,SoGLRenderAction * action)483 SoRenderManager::prerendercb(void * userdata, SoGLRenderAction * action)
484 {
485 // remove callback again
486 action->removePreRenderCallback(prerendercb, userdata);
487 // MSVC7 on 64-bit Windows wants it to go through this cast.
488 const uintptr_t bitfield = (uintptr_t)userdata;
489 GLbitfield mask = (GLbitfield)bitfield;
490
491 #if COIN_DEBUG && 0 // debug
492 GLint view[4];
493 glGetIntegerv(GL_VIEWPORT, view);
494 SoDebugError::postInfo("SoRenderManager::prerendercb",
495 "GL_VIEWPORT=<%d, %d, %d, %d>",
496 view[0], view[1], view[2], view[3]);
497 #endif // debug
498
499 // clear the viewport
500 glClear(mask);
501 }
502
503 /*!
504 Add a superimposition for this scene graph. A superimposition can
505 either be a scene rendered in the background, or a scene rendered in
506 the front of the actual scene graph.
507
508 This is useful, for instance, if you want to add a gradient or an
509 image in the background, and for having some HUD info in the
510 foreground.
511
512 Please note that if you use superimpositions, multipass antialiasing
513 have to be handled in the render manager, and not in
514 SoGLRenderAction, so the pass update features in SoGLRenderAction
515 will be disabled.
516
517 \sa SoGLRenderAction::setNumPasses()
518 \sa SoGLRenderAction::setPassUpdate()
519 \sa SoGLRenderAction::setPassCallback()
520 */
521 SoRenderManager::Superimposition *
addSuperimposition(SoNode * scene,uint32_t flags)522 SoRenderManager::addSuperimposition(SoNode * scene,
523 uint32_t flags)
524 {
525 if (!PRIVATE(this)->superimpositions) {
526 PRIVATE(this)->superimpositions = new SbPList;
527 }
528 Superimposition * s = new Superimposition(scene, TRUE, this, flags);
529 PRIVATE(this)->superimpositions->append(s);
530 return s;
531 }
532
533 /*!
534 Removes a superimposition.
535
536 \sa addSuperimposition()
537 */
538 void
removeSuperimposition(Superimposition * s)539 SoRenderManager::removeSuperimposition(Superimposition * s)
540 {
541 int idx = -1;
542 if (!PRIVATE(this)->superimpositions) goto error;
543 if ((idx = PRIVATE(this)->superimpositions->find(s)) == -1) goto error;
544
545 PRIVATE(this)->superimpositions->remove(idx);
546 delete s;
547 return;
548
549 error:
550 #if COIN_DEBUG
551 SoDebugError::post("SoRenderManager::removeSuperimposition",
552 "no such superimposition");
553 #endif // COIN_DEBUG
554 return;
555 }
556
557
558 /*!
559 Render the scene graph.
560
561 All SbBool arguments should normally be \c TRUE, but they can be set
562 to \c FALSE to optimize for special cases (e.g. when doing wireframe
563 rendering one doesn't need a depth buffer).
564
565 \param[in] clearwindow If set to \c TRUE, clear the rendering buffer
566 before drawing.
567
568 \param[in] clearzbuffer If set to \c TRUE, clear the depth buffer
569 values before rendering.
570
571 */
572 void
render(const SbBool clearwindow,const SbBool clearzbuffer)573 SoRenderManager::render(const SbBool clearwindow, const SbBool clearzbuffer)
574 {
575 // FIXME: according to a user, TGS Inventor seems to disable the
576 // redraw SoOneShotSensor while the scene graph is being rendered,
577 // which Coin does not do. SGI Inventor probably has the same
578 // behavior as TGS Inventor. (Should investigate this.)
579 //
580 // pederb suggests keeping the current behavior in Coin, even though
581 // this may cause trouble for code being ported from SGI / TGS
582 // Inventor, as it is convenient to "touch()" a node for triggering
583 // continuous animation. Besides, making Coin compatible with SGI
584 // (?) / TGS Inventor now may cause problems for existing Coin
585 // client code.
586 //
587 // I'm however not too happy with this fairly large incompatibility.
588 // Any usable suggestions for a resolution of this problem would be
589 // welcome.
590 //
591 // 20050809 mortene.
592
593 if (PRIVATE(this)->scene &&
594 // Order is important below, because we don't want to call
595 // SoAudioDevice::instance() unless we need to -- as it triggers
596 // loading the OpenAL library, which should only be loaded on
597 // demand.
598 coin_sound_should_traverse() &&
599 SoAudioDevice::instance()->haveSound() &&
600 SoAudioDevice::instance()->isEnabled())
601 PRIVATE(this)->audiorenderaction->apply(PRIVATE(this)->scene);
602
603 SoGLRenderAction * action = PRIVATE(this)->glaction;
604 const int numpasses = action->getNumPasses();
605
606 // extra care has to be taken if the user attempts to do multipass
607 // antialiasing while using superimpositions
608 if (numpasses > 1 &&
609 PRIVATE(this)->superimpositions &&
610 PRIVATE(this)->superimpositions->getLength()) {
611 action->setNumPasses(1);
612
613 // FIXME: the pass update callback from SoGLRenderAction is not
614 // supported, but this is not a feature anybody is using anymore,
615 // I suspect. We'll document this in the addSuperimposition()
616 // documentation
617
618 // render the first pass normally
619 action->setCurPass(0, numpasses);
620 this->render(action, TRUE, clearwindow, clearzbuffer);
621
622 // check if we have an accumulation buffer, and render additional passes
623 GLint accumbits;
624 glGetIntegerv(GL_ACCUM_RED_BITS, &accumbits);
625 if (!action->hasTerminated() && accumbits > 0) {
626 const float fraction = 1.0f / float(numpasses);
627 glAccum(GL_LOAD, fraction);
628
629 for (int i = 1; (i < numpasses) && !action->hasTerminated(); i++) {
630 action->setCurPass(i, numpasses);
631 this->render(action, TRUE, TRUE, TRUE);
632 glAccum(GL_ACCUM, fraction);
633 }
634 glAccum(GL_RETURN, 1.0f);
635 }
636 action->setCurPass(0, 1);
637 action->setNumPasses(numpasses);
638 }
639 else {
640 // let SoGLRenderAction handle the accumulation buffer
641 this->render(PRIVATE(this)->glaction, TRUE, clearwindow, clearzbuffer);
642 }
643 }
644
645 /*!
646 \copydetails SoRenderManager::render(const SbBool clearwindow, const SbBool clearzbuffer)
647
648 \param[in] initmatrices if true, the projection and modelview
649 matrices are reset to identity
650 \param[in] action Renders with a user supplied action
651 */
652 void
render(SoGLRenderAction * action,const SbBool initmatrices,const SbBool clearwindow,const SbBool clearzbuffer)653 SoRenderManager::render(SoGLRenderAction * action,
654 const SbBool initmatrices,
655 const SbBool clearwindow,
656 const SbBool clearzbuffer)
657 {
658 SbBool clearwindow_tmp = clearwindow; // make sure we only clear the color buffer once
659 PRIVATE(this)->invokePreRenderCallbacks();
660
661 if (PRIVATE(this)->superimpositions) {
662 for (int i = 0; i < PRIVATE(this)->superimpositions->getLength(); i++) {
663 Superimposition * s = (Superimposition *) (*PRIVATE(this)->superimpositions)[i];
664 if (s->getStateFlags() & Superimposition::BACKGROUND) {
665 s->render(action, clearwindow_tmp);
666 clearwindow_tmp = FALSE;
667 }
668 }
669 }
670
671 (this->getStereoMode() == SoRenderManager::MONO) ?
672 this->renderSingle(action, initmatrices, clearwindow_tmp, clearzbuffer):
673 this->renderStereo(action, initmatrices, clearwindow_tmp, clearzbuffer);
674
675 if (PRIVATE(this)->superimpositions) {
676 for (int i = 0; i < PRIVATE(this)->superimpositions->getLength(); i++) {
677 Superimposition * s = (Superimposition *) (*PRIVATE(this)->superimpositions)[i];
678 if (!(s->getStateFlags() & Superimposition::BACKGROUND)) {
679 s->render(action);
680 }
681 }
682 }
683
684 PRIVATE(this)->invokePostRenderCallbacks();
685 }
686
687 /*!
688 Convenience function for \ref SoRenderManager::renderScene
689
690 \param[in] action Renders with a user supplied action
691
692 \param[in] initmatrices if true, the projection and modelview
693 matrices are reset to identity
694
695 \param[in] clearwindow If set to \c TRUE, clear the rendering buffer
696 before drawing.
697
698 \param[in] clearzbuffer If set to \c TRUE, clear the depth buffer
699 values before rendering.
700 */
701 void
actuallyRender(SoGLRenderAction * action,const SbBool initmatrices,const SbBool clearwindow,const SbBool clearzbuffer)702 SoRenderManager::actuallyRender(SoGLRenderAction * action,
703 const SbBool initmatrices,
704 const SbBool clearwindow,
705 const SbBool clearzbuffer)
706 {
707 GLbitfield mask = 0;
708 if (clearwindow) mask |= GL_COLOR_BUFFER_BIT;
709 if (clearzbuffer) mask |= GL_DEPTH_BUFFER_BIT;
710
711 if (initmatrices) {
712 glMatrixMode(GL_PROJECTION);
713 glLoadIdentity();
714 glMatrixMode(GL_MODELVIEW);
715 glLoadIdentity();
716 }
717
718 // If there has been changes in the scene graph leading to a node
719 // sensor detect and schedule before we've gotten around to serving
720 // the current redraw -- remove it. This will prevent infinite loops
721 // in the case of scenegraph modifications between a nodesensor
722 // trigger and SoRenderManager::render() actually being called. It
723 // will also help us avoid "double redraws" at expose events.
724 PRIVATE(this)->lock();
725 if (PRIVATE(this)->rootsensor && PRIVATE(this)->rootsensor->isScheduled()) {
726 #if COIN_DEBUG && 0 // debug
727 SoDebugError::postInfo("SoRenderManager::render",
728 "rootsensor unschedule");
729 #endif // debug
730 PRIVATE(this)->rootsensor->unschedule();
731 }
732 PRIVATE(this)->unlock();
733 // Apply the SoGLRenderAction to the scenegraph root.
734 if (PRIVATE(this)->scene) {
735 this->renderScene(action, PRIVATE(this)->scene, (uint32_t) mask);
736 }
737
738 // Automatically re-triggers rendering if any animation stuff is
739 // connected to the realTime field.
740 if (SoRenderManager::isRealTimeUpdateEnabled()) {
741 // FIXME: it would be more elegant to use a private field class
742 // inheriting SoSFTime ("SFRealTime") which could just be
743 // touch()'ed, and which would do lazy reading of time-of-day on
744 // demand. 20000316 mortene.
745 SoField * realtime = SoDB::getGlobalField("realTime");
746 if (realtime && (realtime->getTypeId() == SoSFTime::getClassTypeId())) {
747 // Note that this should not get in the way of a
748 // app-programmer controlled realTime field, as
749 // enableRealTimeUpdate(FALSE) should then have been called.
750 ((SoSFTime *)realtime)->setValue(SbTime::getTimeOfDay());
751 }
752 }
753 }
754
755 /*!
756 Renders a scene and applies clear state as given by this renderManager
757
758 \param[in] action Action to apply
759 \param[in] scene Scene to render
760 \param[in] clearmask mask to pass to glClear
761 */
762 void
renderScene(SoGLRenderAction * action,SoNode * scene,uint32_t clearmask)763 SoRenderManager::renderScene( SoGLRenderAction * action,
764 SoNode * scene,
765 uint32_t clearmask)
766 {
767 if (clearmask) {
768 if (clearmask & GL_COLOR_BUFFER_BIT) {
769 if (PRIVATE(this)->isrgbmode) {
770 const SbColor4f bgcol = PRIVATE(this)->backgroundcolor;
771 glClearColor(bgcol[0], bgcol[1], bgcol[2], bgcol[3]);
772 }
773 else {
774 glClearIndex((GLfloat) PRIVATE(this)->backgroundindex);
775 }
776 }
777 // Registering a callback is needed since the correct GL viewport
778 // is set by SoGLRenderAction before rendering. It might not be
779 // correct when we get here.
780 // This callback is removed again in the prerendercb function
781 action->addPreRenderCallback(this->prerendercb, (void*) (uintptr_t) clearmask);
782 }
783 action->apply(scene);
784 }
785
786 /*!
787 \brief Render once in correct draw style
788
789 \copydoc SoRenderManager::actuallyRender
790 */
791 void
renderSingle(SoGLRenderAction * action,SbBool initmatrices,SbBool clearwindow,SbBool clearzbuffer)792 SoRenderManager::renderSingle(SoGLRenderAction * action,
793 SbBool initmatrices,
794 SbBool clearwindow,
795 SbBool clearzbuffer)
796 {
797 SoState * state = action->getState();
798 state->push();
799
800 SoNode * node = PRIVATE(this)->dummynode;
801
802 if (!this->isTexturesEnabled()) {
803 SoTextureQualityElement::set(state, node, 0.0f);
804 SoTextureOverrideElement::setQualityOverride(state, TRUE);
805 }
806 switch (this->getRenderMode()) {
807 case SoRenderManager::AS_IS:
808 this->actuallyRender(action, initmatrices, clearwindow, clearzbuffer);
809 break;
810 case SoRenderManager::WIREFRAME:
811 SoDrawStyleElement::set(state, node, SoDrawStyleElement::LINES);
812 SoLightModelElement::set(state, node, SoLightModelElement::BASE_COLOR);
813 SoOverrideElement::setDrawStyleOverride(state, node, TRUE);
814 SoOverrideElement::setLightModelOverride(state, node, TRUE);
815 this->actuallyRender(action, initmatrices, clearwindow, clearzbuffer);
816 break;
817 case SoRenderManager::POINTS:
818 SoDrawStyleElement::set(state, node, SoDrawStyleElement::POINTS);
819 SoLightModelElement::set(state, node, SoLightModelElement::BASE_COLOR);
820 SoOverrideElement::setDrawStyleOverride(state, node, TRUE);
821 SoOverrideElement::setLightModelOverride(state, node, TRUE);
822 this->actuallyRender(action, initmatrices, clearwindow, clearzbuffer);
823 break;
824 case SoRenderManager::HIDDEN_LINE:
825 {
826 // must clear before setting draw mask
827 this->clearBuffers(TRUE, TRUE);
828
829 // only draw into depth buffer
830 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
831 SoMaterialBindingElement::set(state, node, SoMaterialBindingElement::OVERALL);
832 SoLightModelElement::set(state, node, SoLightModelElement::BASE_COLOR);
833 SoPolygonOffsetElement::set(state, node, 1.0f, 1.0f,
834 SoPolygonOffsetElement::FILLED, TRUE);
835 SoOverrideElement::setPolygonOffsetOverride(state, node, TRUE);
836 SoOverrideElement::setLightModelOverride(state, node, TRUE);
837 SoOverrideElement::setMaterialBindingOverride(state, node, TRUE);
838 this->actuallyRender(action, initmatrices, FALSE, FALSE);
839
840 // reenable draw masks
841 glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
842 SoPolygonOffsetElement::set(state, node, 0.0f, 0.0f,
843 SoPolygonOffsetElement::FILLED, FALSE);
844 SoDrawStyleElement::set(state, node, SoDrawStyleElement::LINES);
845 SoOverrideElement::setDrawStyleOverride(state, node, TRUE);
846 SoOverrideElement::setMaterialBindingOverride(state, node, FALSE);
847 this->actuallyRender(action, initmatrices, FALSE, FALSE);
848 }
849 break;
850 case SoRenderManager::WIREFRAME_OVERLAY:
851 SoPolygonOffsetElement::set(state, node, 1.0f, 1.0f,
852 SoPolygonOffsetElement::FILLED, TRUE);
853 SoOverrideElement::setPolygonOffsetOverride(state, node, TRUE);
854 this->actuallyRender(action, initmatrices, clearwindow, clearzbuffer);
855 SoPolygonOffsetElement::set(state, node, 0.0f, 0.0f,
856 SoPolygonOffsetElement::FILLED, FALSE);
857
858 SoLazyElement::setPacked(state, node, 1, &PRIVATE(this)->overlaycolor, TRUE);
859 SoLightModelElement::set(state, node, SoLightModelElement::BASE_COLOR);
860 SoMaterialBindingElement::set(state, node, SoMaterialBindingElement::OVERALL);
861 SoDrawStyleElement::set(state, node, SoDrawStyleElement::LINES);
862 SoOverrideElement::setLightModelOverride(state, node, TRUE);
863 SoOverrideElement::setDiffuseColorOverride(state, node, TRUE);
864 SoOverrideElement::setMaterialBindingOverride(state, node, TRUE);
865 SoOverrideElement::setDrawStyleOverride(state, node, TRUE);
866 this->actuallyRender(action, initmatrices, FALSE, FALSE);
867 break;
868
869 case SoRenderManager::BOUNDING_BOX:
870 SoDrawStyleElement::set(state, node, SoDrawStyleElement::LINES);
871 SoLightModelElement::set(state, node, SoLightModelElement::BASE_COLOR);
872 SoComplexityTypeElement::set(state, node, SoComplexityTypeElement::BOUNDING_BOX);
873 SoOverrideElement::setDrawStyleOverride(state, node, TRUE);
874 SoOverrideElement::setLightModelOverride(state, node, TRUE);
875 SoOverrideElement::setComplexityTypeOverride(state, node, TRUE);
876 this->actuallyRender(action, initmatrices, clearwindow, clearzbuffer);
877 break;
878 default:
879 assert(0 && "unknown rendering mode");
880 break;
881 }
882 state->pop();
883 }
884
885 /*!
886 \brief Render scene according to current stereo mode
887
888 \copydoc SoRenderManager::actuallyRender
889 */
890 void
renderStereo(SoGLRenderAction * action,SbBool initmatrices,SbBool clearwindow,SbBool clearzbuffer)891 SoRenderManager::renderStereo(SoGLRenderAction * action,
892 SbBool initmatrices,
893 SbBool clearwindow,
894 SbBool clearzbuffer)
895 {
896 if (!PRIVATE(this)->camera) return;
897
898 this->clearBuffers(TRUE, TRUE);
899 PRIVATE(this)->camera->setStereoAdjustment(PRIVATE(this)->stereooffset);
900
901 SbBool stenciltestenabled = glIsEnabled(GL_STENCIL_TEST);
902
903 // left eye
904 PRIVATE(this)->camera->setStereoMode(SoCamera::LEFT_VIEW);
905
906 switch (PRIVATE(this)->stereomode) {
907 case SoRenderManager::ANAGLYPH:
908 glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_TRUE);
909 this->renderSingle(action, initmatrices, FALSE, FALSE);
910 break;
911 case SoRenderManager::QUAD_BUFFER:
912 glDrawBuffer(PRIVATE(this)->doublebuffer ? GL_BACK_LEFT : GL_FRONT_LEFT);
913 this->renderSingle(action, initmatrices, clearwindow, clearzbuffer);
914 break;
915 case SoRenderManager::INTERLEAVED_ROWS:
916 case SoRenderManager::INTERLEAVED_COLUMNS:
917 this->initStencilBufferForInterleavedStereo();
918 glEnable(GL_STENCIL_TEST);
919 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
920 glStencilFunc(GL_EQUAL, 0x1, 0x1);
921 this->renderSingle(action, initmatrices, clearwindow, clearzbuffer);
922 break;
923 default:
924 assert(0 && "unknown stereo mode");
925 break;
926 }
927
928 // right eye
929 PRIVATE(this)->camera->setStereoMode(SoCamera::RIGHT_VIEW);
930
931 switch (PRIVATE(this)->stereomode) {
932 case SoRenderManager::ANAGLYPH:
933 glClear(GL_DEPTH_BUFFER_BIT);
934 glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE);
935 this->renderSingle(action, initmatrices, FALSE, TRUE);
936 break;
937 case SoRenderManager::QUAD_BUFFER:
938 glDrawBuffer(PRIVATE(this)->doublebuffer ? GL_BACK_RIGHT : GL_FRONT_RIGHT);
939 this->renderSingle(action, initmatrices, clearwindow, clearzbuffer);
940 break;
941 case SoRenderManager::INTERLEAVED_ROWS:
942 case SoRenderManager::INTERLEAVED_COLUMNS:
943 glStencilFunc(GL_NOTEQUAL, 0x1, 0x1);
944 this->renderSingle(action, initmatrices, FALSE, FALSE);
945 break;
946 default:
947 assert(0 && "unknown stereo mode");
948 break;
949 }
950
951 // restore / post render operations
952 PRIVATE(this)->camera->setStereoMode(SoCamera::MONOSCOPIC);
953
954 switch (PRIVATE(this)->stereomode) {
955 case SoRenderManager::ANAGLYPH:
956 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
957 break;
958 case SoRenderManager::QUAD_BUFFER:
959 glDrawBuffer(PRIVATE(this)->doublebuffer ? GL_BACK : GL_FRONT);
960 break;
961 case SoRenderManager::INTERLEAVED_ROWS:
962 case SoRenderManager::INTERLEAVED_COLUMNS:
963 stenciltestenabled ?
964 glEnable(GL_STENCIL_TEST) :
965 glDisable(GL_STENCIL_TEST);
966 break;
967 default:
968 assert(0 && "unknown stereo mode");
969 break;
970 }
971 }
972
973 /*!
974 Sets strategy for adjusting camera clipping plane
975
976 \see SoRenderManager::AutoClippingStrategy
977 */
978 void
setAutoClipping(AutoClippingStrategy autoclipping)979 SoRenderManager::setAutoClipping(AutoClippingStrategy autoclipping)
980 {
981 PRIVATE(this)->autoclipping = autoclipping;
982
983 if (PRIVATE(this)->scene) {
984 switch (autoclipping) {
985 case SoRenderManager::NO_AUTO_CLIPPING:
986 this->detachClipSensor();
987 break;
988 case SoRenderManager::FIXED_NEAR_PLANE:
989 case SoRenderManager::VARIABLE_NEAR_PLANE:
990 if (!PRIVATE(this)->clipsensor->getAttachedNode()) {
991 PRIVATE(this)->clipsensor->attach(PRIVATE(this)->scene);
992 }
993 PRIVATE(this)->clipsensor->schedule();
994 break;
995 }
996 }
997 }
998
999 /*!
1000 Initializes stencilbuffers for interleaved stereo
1001 */
1002 void
initStencilBufferForInterleavedStereo(void)1003 SoRenderManager::initStencilBufferForInterleavedStereo(void)
1004 {
1005 const SbViewportRegion & currentvp = PRIVATE(this)->glaction->getViewportRegion();
1006 if (PRIVATE(this)->stereostencilmaskvp == currentvp) { return; } // the common case
1007
1008 SoRenderManager::StereoMode s = PRIVATE(this)->stereomode;
1009 assert((s == SoRenderManager::INTERLEAVED_ROWS) ||
1010 (s == SoRenderManager::INTERLEAVED_COLUMNS));
1011
1012 // Find out whether or not we need to regenerate the mask data.
1013 SbBool allocnewmask = (PRIVATE(this)->stereostencilmask == NULL);
1014
1015 const SbVec2s neworigin = currentvp.getViewportOriginPixels();
1016 const SbVec2s newsize = currentvp.getViewportSizePixels();
1017
1018 const SbVec2s oldorigin = PRIVATE(this)->stereostencilmaskvp.getViewportOriginPixels();
1019 const SbVec2s oldsize = PRIVATE(this)->stereostencilmaskvp.getViewportSizePixels();
1020
1021 allocnewmask = allocnewmask ||
1022 ((oldsize[0] + 7) / 8 * oldsize[1]) < ((newsize[0] + 7) / 8 * newsize[1]);
1023
1024 const SbBool fillmask = allocnewmask || (PRIVATE(this)->stereostenciltype != s) ||
1025 ((s == SoRenderManager::INTERLEAVED_ROWS) && (oldsize[0] != newsize[0]));
1026
1027 const SbBool layoutchange = !(PRIVATE(this)->stereostencilmaskvp == currentvp);
1028
1029 const short bytewidth = (newsize[0] + 7) / 8;
1030
1031 if (allocnewmask) {
1032 delete[] PRIVATE(this)->stereostencilmask;
1033 PRIVATE(this)->stereostencilmask = new GLubyte[bytewidth * newsize[1]];
1034 }
1035
1036 PRIVATE(this)->stereostencilmaskvp = currentvp;
1037
1038 if (fillmask) {
1039 GLubyte * mask = PRIVATE(this)->stereostencilmask;
1040
1041 if (s == SoRenderManager::INTERLEAVED_COLUMNS) {
1042 // alternating columns of 0's and 1's
1043 (void)memset(mask, 0x55, bytewidth * newsize[1]);
1044 }
1045 else {
1046 // alternating rows of 0's and 1's
1047 for (short h=0; h < newsize[1]; h++) {
1048 const GLubyte fill = (h % 2) ? 0xff : 0x00;
1049 (void)memset(mask + (h * bytewidth), fill, bytewidth);
1050 }
1051 }
1052
1053 PRIVATE(this)->stereostenciltype = s;
1054 }
1055
1056 if (layoutchange) {
1057 glClearStencil(0x0);
1058
1059 glClear(GL_STENCIL_BUFFER_BIT);
1060 glStencilFunc(GL_ALWAYS, GL_REPLACE, GL_REPLACE);
1061
1062 glMatrixMode(GL_MODELVIEW);
1063 glPushMatrix();
1064 glLoadIdentity();
1065 glMatrixMode(GL_PROJECTION);
1066 glPushMatrix();
1067 glLoadIdentity();
1068
1069 glViewport(neworigin[0], neworigin[1], newsize[0], newsize[1]);
1070
1071 glOrtho(0, newsize[0], 0, newsize[1], -1.0f, 1.0f);
1072
1073 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
1074
1075 // FIXME: I've noticed a problem with this approach. If there is
1076 // something in the window system obscuring part of the canvas
1077 // while this is called (as could e.g. happen with a size
1078 // indicator, as with the Sawfish window manager), the stencil
1079 // mask will not be set up for that part. 20041019 mortene.
1080 //
1081 // UPDATE 20041019 mortene: discussed this with pederb, and we
1082 // believe this may be due to a bug in either the OpenGL driver
1083 // (Nvidia 61.11, Linux) or window system or manager (Sawfish,
1084 // XFree86 v4.1.0.1). Should test on other systems to see if they
1085 // show the same artifact.
1086
1087 glRasterPos2f(0, 0);
1088 glDrawPixels(newsize[0], newsize[1], GL_STENCIL_INDEX, GL_BITMAP,
1089 PRIVATE(this)->stereostencilmask);
1090
1091 glMatrixMode(GL_PROJECTION);
1092 glPopMatrix();
1093 glMatrixMode(GL_MODELVIEW);
1094 glPopMatrix();
1095 }
1096 }
1097
1098 /*!
1099 Reinitialize after parameters affecting the OpenGL context has
1100 changed.
1101 */
1102 void
reinitialize(void)1103 SoRenderManager::reinitialize(void)
1104 {
1105 PRIVATE(this)->glaction->invalidateState();
1106 }
1107
1108 /*!
1109 Redraw at first opportunity as system becomes idle.
1110
1111 Multiple calls to this method before an actual redraw has taken
1112 place will only result in a single redraw of the scene.
1113 */
1114 void
scheduleRedraw(void)1115 SoRenderManager::scheduleRedraw(void)
1116 {
1117 PRIVATE(this)->lock();
1118 if (this->isActive() && PRIVATE(this)->rendercb) {
1119 #if COIN_DEBUG && 0 // debug
1120 SoDebugError::postInfo("SoRenderManager::scheduleRedraw",
1121 "scheduling redrawshot (oneshotsensor) %p",
1122 PRIVATE(this)->redrawshot);
1123 #endif // debug
1124 PRIVATE(this)->redrawshot->schedule();
1125 }
1126 PRIVATE(this)->unlock();
1127 }
1128
1129 /*!
1130 Update window size of our SoGLRenderAction's viewport settings.
1131
1132 Note that this will \e only change the information about window
1133 dimensions, the actual viewport size and origin (ie the rectangle
1134 which redraws are confined to) will stay the same.
1135
1136 \sa setViewportRegion()
1137 */
1138 void
setWindowSize(const SbVec2s & newsize)1139 SoRenderManager::setWindowSize(const SbVec2s & newsize)
1140 {
1141 #if COIN_DEBUG && 0 // debug
1142 SoDebugError::postInfo("SoRenderManager::setWindowSize",
1143 "(%d, %d)", newsize[0], newsize[1]);
1144 #endif // debug
1145
1146 SbViewportRegion region = PRIVATE(this)->glaction->getViewportRegion();
1147 region.setWindowSize(newsize[0], newsize[1]);
1148 PRIVATE(this)->glaction->setViewportRegion(region);
1149 }
1150
1151 /*!
1152 Returns the current render action window size.
1153
1154 \sa setWindowSize()
1155 */
1156 const SbVec2s &
getWindowSize(void) const1157 SoRenderManager::getWindowSize(void) const
1158 {
1159 return PRIVATE(this)->glaction->getViewportRegion().getWindowSize();
1160 }
1161
1162 /*!
1163 Set size of rendering area for the viewport within the current
1164 window.
1165 */
1166 void
setSize(const SbVec2s & newsize)1167 SoRenderManager::setSize(const SbVec2s & newsize)
1168 {
1169 #if COIN_DEBUG && 0 // debug
1170 SoDebugError::postInfo("SoRenderManager::setSize",
1171 "(%d, %d)", newsize[0], newsize[1]);
1172 #endif // debug
1173
1174 SbViewportRegion region = PRIVATE(this)->glaction->getViewportRegion();
1175 SbVec2s origin = region.getViewportOriginPixels();
1176 region.setViewportPixels(origin, newsize);
1177 PRIVATE(this)->glaction->setViewportRegion(region);
1178 }
1179
1180 /*!
1181 Returns size of render area.
1182 */
1183 const SbVec2s &
getSize(void) const1184 SoRenderManager::getSize(void) const
1185 {
1186 return PRIVATE(this)->glaction->getViewportRegion().getViewportSizePixels();
1187 }
1188
1189 /*!
1190 Set \e only the origin of the viewport region within the rendering
1191 window.
1192
1193 \sa setViewportRegion(), setWindowSize()
1194 */
1195 void
setOrigin(const SbVec2s & newOrigin)1196 SoRenderManager::setOrigin(const SbVec2s & newOrigin)
1197 {
1198 #if COIN_DEBUG && 0 // debug
1199 SoDebugError::postInfo("SoRenderManager::setOrigin",
1200 "(%d, %d)", newOrigin[0], newOrigin[1]);
1201 #endif // debug
1202
1203 SbViewportRegion region = PRIVATE(this)->glaction->getViewportRegion();
1204 SbVec2s size = region.getViewportSizePixels();
1205 region.setViewportPixels(newOrigin, size);
1206 PRIVATE(this)->glaction->setViewportRegion(region);
1207 }
1208
1209 /*!
1210 Returns origin of rendering area viewport.
1211
1212 \sa setOrigin()
1213 */
1214 const SbVec2s &
getOrigin(void) const1215 SoRenderManager::getOrigin(void) const
1216 {
1217 return PRIVATE(this)->glaction->getViewportRegion().getViewportOriginPixels();
1218 }
1219
1220 /*!
1221 Update our SoGLRenderAction's viewport settings.
1222
1223 This will change \e both the information about window dimensions and
1224 the actual viewport size and origin.
1225
1226 \sa setWindowSize()
1227 */
1228 void
setViewportRegion(const SbViewportRegion & newregion)1229 SoRenderManager::setViewportRegion(const SbViewportRegion & newregion)
1230 {
1231 PRIVATE(this)->glaction->setViewportRegion(newregion);
1232 }
1233
1234 /*!
1235 Returns current viewport region used by the renderaction and the
1236 event handling.
1237
1238 \sa setViewportRegion()
1239 */
1240 const SbViewportRegion &
getViewportRegion(void) const1241 SoRenderManager::getViewportRegion(void) const
1242 {
1243 return PRIVATE(this)->glaction->getViewportRegion();
1244 }
1245
1246 /*!
1247 Sets color of rendering canvas.
1248 */
1249 void
setBackgroundColor(const SbColor4f & color)1250 SoRenderManager::setBackgroundColor(const SbColor4f & color)
1251 {
1252 PRIVATE(this)->backgroundcolor = color;
1253 }
1254
1255 /*!
1256 Returns color used for clearing the rendering area before rendering
1257 the scene.
1258 */
1259 const SbColor4f &
getBackgroundColor(void) const1260 SoRenderManager::getBackgroundColor(void) const
1261 {
1262 return PRIVATE(this)->backgroundcolor;
1263 }
1264
1265 /*!
1266 Sets color of overlay.
1267 */
1268 void
setOverlayColor(const SbColor4f & color)1269 SoRenderManager::setOverlayColor(const SbColor4f & color)
1270 {
1271 PRIVATE(this)->overlaycolor = color.getPackedValue();
1272 this->scheduleRedraw();
1273 }
1274 /*!
1275 Returns color used rendering overlay.
1276 */
1277 SbColor4f
getOverlayColor(void) const1278 SoRenderManager::getOverlayColor(void) const
1279 {
1280 SbColor4f retVal;
1281 retVal.setPackedValue(PRIVATE(this)->overlaycolor);
1282 return retVal;
1283 }
1284
1285 /*!
1286 Set index of background color in the color lookup table if rendering
1287 in colorindex mode.
1288
1289 Note: colorindex mode is not supported yet in Coin.
1290 */
1291 void
setBackgroundIndex(const int index)1292 SoRenderManager::setBackgroundIndex(const int index)
1293 {
1294 PRIVATE(this)->backgroundindex = index;
1295 }
1296
1297 /*!
1298 Returns index of colormap for background filling.
1299
1300 \sa setBackgroundIndex()
1301 */
1302 int
getBackgroundIndex(void) const1303 SoRenderManager::getBackgroundIndex(void) const
1304 {
1305 return PRIVATE(this)->backgroundindex;
1306 }
1307
1308 /*!
1309 Turn RGB truecolor mode on or off. If you turn truecolor mode off,
1310 colorindex mode will be used instead.
1311 */
1312 void
setRGBMode(const SbBool yes)1313 SoRenderManager::setRGBMode(const SbBool yes)
1314 {
1315 PRIVATE(this)->isrgbmode = yes;
1316 }
1317
1318 /*!
1319 Returns the "truecolor or colorindex" mode flag.
1320 */
1321 SbBool
isRGBMode(void) const1322 SoRenderManager::isRGBMode(void) const
1323 {
1324 return PRIVATE(this)->isrgbmode;
1325 }
1326
1327 /*!
1328 Tell the scenemanager that double buffering is used
1329 */
1330 void
setDoubleBuffer(const SbBool enable)1331 SoRenderManager::setDoubleBuffer(const SbBool enable)
1332 {
1333 PRIVATE(this)->doublebuffer = enable;
1334 }
1335
1336 /*!
1337 returns if the scenemanager is double buffered
1338 */
1339 SbBool
isDoubleBuffer(void) const1340 SoRenderManager::isDoubleBuffer(void) const
1341 {
1342 return PRIVATE(this)->doublebuffer;
1343 }
1344
1345 /*!
1346 Set the callback function \a f to invoke when rendering the
1347 scene. \a userdata will be passed as the first argument of the
1348 function.
1349 */
1350 void
setRenderCallback(SoRenderManagerRenderCB * f,void * const userdata)1351 SoRenderManager::setRenderCallback(SoRenderManagerRenderCB * f,
1352 void * const userdata)
1353 {
1354 PRIVATE(this)->rendercb = f;
1355 PRIVATE(this)->rendercbdata = userdata;
1356 }
1357
1358 /*!
1359 Activate rendering and event handling. Default is \c off.
1360 */
1361 void
activate(void)1362 SoRenderManager::activate(void)
1363 {
1364 PRIVATE(this)->isactive = TRUE;
1365 }
1366
1367 /*!
1368 Deactive rendering and event handling.
1369 */
1370 void
deactivate(void)1371 SoRenderManager::deactivate(void)
1372 {
1373 PRIVATE(this)->isactive = FALSE;
1374 }
1375
1376 /*!
1377 Returns the \e active flag.
1378 */
1379 int
isActive(void) const1380 SoRenderManager::isActive(void) const
1381 {
1382 return PRIVATE(this)->isactive;
1383 }
1384
1385 /*!
1386 Do an immediate redraw by calling the redraw callback function.
1387 */
1388 void
redraw(void)1389 SoRenderManager::redraw(void)
1390 {
1391 if (PRIVATE(this)->rendercb) {
1392 PRIVATE(this)->rendercb(PRIVATE(this)->rendercbdata, this);
1393 }
1394 }
1395
1396 /*!
1397 Returns \c TRUE if the SoRenderManager automatically redraws the
1398 scene upon detecting changes in the scene graph.
1399
1400 The automatic redraw is turned on and off by setting either a valid
1401 callback function with setRenderCallback(), or by passing \c NULL.
1402 */
1403 SbBool
isAutoRedraw(void) const1404 SoRenderManager::isAutoRedraw(void) const
1405 {
1406 return PRIVATE(this)->rendercb != NULL;
1407 }
1408
1409
1410 /*!
1411 Sets the render mode.
1412 */
1413 void
setRenderMode(const RenderMode mode)1414 SoRenderManager::setRenderMode(const RenderMode mode)
1415 {
1416 PRIVATE(this)->rendermode = mode;
1417 this->scheduleRedraw();
1418 PRIVATE(this)->dummynode->touch();
1419 }
1420
1421 /*!
1422 Returns the current render mode.
1423 */
1424 SoRenderManager::RenderMode
getRenderMode(void) const1425 SoRenderManager::getRenderMode(void) const
1426 {
1427 return PRIVATE(this)->rendermode;
1428 }
1429
1430 /*!
1431 Sets the stereo mode.
1432 */
1433 void
setStereoMode(const StereoMode mode)1434 SoRenderManager::setStereoMode(const StereoMode mode)
1435 {
1436 PRIVATE(this)->stereomode = mode;
1437 this->scheduleRedraw();
1438 PRIVATE(this)->dummynode->touch();
1439 }
1440
1441 /*!
1442 Returns the current stereo mode.
1443 */
1444 SoRenderManager::StereoMode
getStereoMode(void) const1445 SoRenderManager::getStereoMode(void) const
1446 {
1447 return PRIVATE(this)->stereomode;
1448 }
1449
1450 /*!
1451 Sets the stereo offset used when doing stereo rendering.
1452 */
1453 void
setStereoOffset(const float offset)1454 SoRenderManager::setStereoOffset(const float offset)
1455 {
1456 PRIVATE(this)->stereooffset = offset;
1457 this->scheduleRedraw();
1458 PRIVATE(this)->dummynode->touch();
1459 }
1460
1461 /*!
1462 Returns the current stereo offset.
1463 */
1464 float
getStereoOffset(void) const1465 SoRenderManager::getStereoOffset(void) const
1466 {
1467 return PRIVATE(this)->stereooffset;
1468 }
1469
1470 /*!
1471 Turn antialiased rendering on or off.
1472
1473 See documentation for SoGLRenderAction::setSmoothing() and
1474 SoGLRenderAction::setNumPasses().
1475 */
1476 void
setAntialiasing(const SbBool smoothing,const int numpasses)1477 SoRenderManager::setAntialiasing(const SbBool smoothing, const int numpasses)
1478 {
1479 PRIVATE(this)->glaction->setSmoothing(smoothing);
1480 PRIVATE(this)->glaction->setNumPasses(numpasses);
1481 this->scheduleRedraw();
1482 }
1483
1484 /*!
1485 Returns rendering pass information.
1486
1487 \sa setAntialiasing()
1488 */
1489 void
getAntialiasing(SbBool & smoothing,int & numpasses) const1490 SoRenderManager::getAntialiasing(SbBool & smoothing, int & numpasses) const
1491 {
1492 smoothing = PRIVATE(this)->glaction->isSmoothing();
1493 numpasses = PRIVATE(this)->glaction->getNumPasses();
1494 }
1495
1496 /*!
1497 Set the \a action to use for rendering. Overrides the default action
1498 made in the constructor.
1499 */
1500 void
setGLRenderAction(SoGLRenderAction * const action)1501 SoRenderManager::setGLRenderAction(SoGLRenderAction * const action)
1502 {
1503 SbBool haveregion = FALSE;
1504 SbViewportRegion region;
1505 if (PRIVATE(this)->glaction) { // remember existing viewport region
1506 region = PRIVATE(this)->glaction->getViewportRegion();
1507 haveregion = TRUE;
1508 }
1509 if (PRIVATE(this)->deleteglaction) {
1510 delete PRIVATE(this)->glaction;
1511 PRIVATE(this)->glaction = NULL;
1512 }
1513
1514 // If action change, we need to invalidate state to enable lazy GL
1515 // elements to be evaluated correctly.
1516 //
1517 // Note that the SGI and TGS Inventor implementations doesn't do
1518 // this -- which smells of a bug.
1519 if (action && action != PRIVATE(this)->glaction) action->invalidateState();
1520 PRIVATE(this)->glaction = action;
1521 PRIVATE(this)->deleteglaction = FALSE;
1522 if (PRIVATE(this)->glaction && haveregion)
1523 PRIVATE(this)->glaction->setViewportRegion(region);
1524 }
1525
1526 /*!
1527 Returns pointer to render action.
1528 */
1529 SoGLRenderAction *
getGLRenderAction(void) const1530 SoRenderManager::getGLRenderAction(void) const
1531 {
1532 return PRIVATE(this)->glaction;
1533 }
1534
1535 /*!
1536 This method returns the current autoclipping strategy.
1537
1538 \sa setAutoClipping
1539 */
1540
1541 SoRenderManager::AutoClippingStrategy
getAutoClipping(void) const1542 SoRenderManager::getAutoClipping(void) const
1543 {
1544 return PRIVATE(this)->autoclipping;
1545 }
1546
1547 /*!
1548 When the SoRenderManager::FIXED_NEAR_PLANE autoclipping strategy is
1549 used, you set the value of the near plane distance with this method.
1550
1551 \sa setAutoClipping, getNearPlaneValue, SoRenderManager::AutoClippingStrategy
1552 */
1553
1554 void
setNearPlaneValue(float value)1555 SoRenderManager::setNearPlaneValue(float value)
1556 {
1557 PRIVATE(this)->nearplanevalue = value;
1558 }
1559
1560 /*!
1561 This method returns the near plane distance value that will be used
1562 when the SoRenderManager::FIXED_NEAR_PLANE autoclipping strategy is used.
1563
1564 Default value is 0.6.
1565
1566 \sa setAutoClipping, setNearPlaneValue, SoRenderManager::AutoClippingStrategy
1567 */
1568
1569 float
getNearPlaneValue(void) const1570 SoRenderManager::getNearPlaneValue(void) const
1571 {
1572 return PRIVATE(this)->nearplanevalue;
1573 }
1574
1575 /*!
1576 Enable/disable textures when rendering.
1577 Defaults to TRUE.
1578
1579 \sa isTexturesEnabled
1580 */
1581
1582 void
setTexturesEnabled(const SbBool onoff)1583 SoRenderManager::setTexturesEnabled(const SbBool onoff)
1584 {
1585 PRIVATE(this)->texturesenabled = onoff;
1586 }
1587
1588 /*!
1589 Returns whether textures are enabled or not.
1590
1591 \sa setTexturesEnabled
1592 */
1593
1594 SbBool
isTexturesEnabled(void) const1595 SoRenderManager::isTexturesEnabled(void) const
1596 {
1597 return PRIVATE(this)->texturesenabled;
1598 }
1599
1600 /*!
1601 Set up the redraw \a priority for the SoOneShotSensor used to
1602 trigger redraws. By setting this lower than for your own sensors,
1603 you can make sure some code is always run before redraw happens.
1604
1605 \sa SoDelayQueueSensor
1606 */
1607 void
setRedrawPriority(const uint32_t priority)1608 SoRenderManager::setRedrawPriority(const uint32_t priority)
1609 {
1610 PRIVATE(this)->redrawpri = priority;
1611
1612 if (PRIVATE(this)->redrawshot) PRIVATE(this)->redrawshot->setPriority(priority);
1613 if (PRIVATE(this)->rootsensor) PRIVATE(this)->rootsensor->setPriority(PRIVATE(this)->redrawpri == 0 ? 0 : 1);
1614 }
1615
1616 /*!
1617 Returns value of priority on the redraw sensor.
1618 */
1619 uint32_t
getRedrawPriority(void) const1620 SoRenderManager::getRedrawPriority(void) const
1621 {
1622 return PRIVATE(this)->redrawpri;
1623 }
1624
1625 /*!
1626 Set the \a action to use for rendering audio. Overrides the default action
1627 made in the constructor.
1628 */
1629 void
setAudioRenderAction(SoAudioRenderAction * const action)1630 SoRenderManager::setAudioRenderAction(SoAudioRenderAction * const action)
1631 {
1632 if (PRIVATE(this)->deleteaudiorenderaction) {
1633 delete PRIVATE(this)->audiorenderaction;
1634 PRIVATE(this)->audiorenderaction = NULL;
1635 }
1636
1637 // If action change, we need to invalidate state to enable lazy GL
1638 // elements to be evaluated correctly.
1639 //
1640 if (action && action != PRIVATE(this)->audiorenderaction) action->invalidateState();
1641 PRIVATE(this)->audiorenderaction = action;
1642 PRIVATE(this)->deleteaudiorenderaction = FALSE;
1643 }
1644
1645 /*!
1646 Returns pointer to audio render action.
1647 */
1648 SoAudioRenderAction *
getAudioRenderAction(void) const1649 SoRenderManager::getAudioRenderAction(void) const
1650 {
1651 return PRIVATE(this)->audiorenderaction;
1652 }
1653
1654 /*!
1655 Returns the default priority of the redraw sensor.
1656
1657 \sa SoDelayQueueSensor, setRedrawPriority()
1658 */
1659 uint32_t
getDefaultRedrawPriority(void)1660 SoRenderManager::getDefaultRedrawPriority(void)
1661 {
1662 return 10000;
1663 }
1664
1665 /*!
1666 Set whether or not for SoRenderManager instances to "touch" the
1667 global \c realTime field after a redraw. If this is not done,
1668 redrawing when animating the scene will only happen as fast as the
1669 \c realTime interval goes (which defaults to 12 times a second).
1670
1671 \sa SoDB::setRealTimeInterval()
1672 */
1673 void
enableRealTimeUpdate(const SbBool flag)1674 SoRenderManager::enableRealTimeUpdate(const SbBool flag)
1675 {
1676 SoRenderManagerP::touchtimer = flag;
1677 if (!SoRenderManagerP::cleanupfunctionset) {
1678 coin_atexit((coin_atexit_f*) SoRenderManagerP::cleanup, CC_ATEXIT_NORMAL);
1679 SoRenderManagerP::cleanupfunctionset = TRUE;
1680 }
1681 }
1682
1683 /*!
1684 Returns whether or not we automatically notifies everything
1685 connected to the \c realTime field after a redraw.
1686 */
1687 SbBool
isRealTimeUpdateEnabled(void)1688 SoRenderManager::isRealTimeUpdateEnabled(void)
1689 {
1690 return SoRenderManagerP::touchtimer;
1691 }
1692
1693
1694 /*!
1695 Adds a function to be called before rendering starts
1696
1697 \param[in] cb function to be called
1698 \param[in] data User specified data to supply to callback function
1699 */
1700 void
addPreRenderCallback(SoRenderManagerRenderCB * cb,void * data)1701 SoRenderManager::addPreRenderCallback(SoRenderManagerRenderCB * cb, void * data)
1702 {
1703 PRIVATE(this)->preRenderCallbacks.push_back(SoRenderManagerP::RenderCBTouple(cb, data));
1704 }
1705
1706
1707 /*!
1708 Removes a prerendercallback.
1709
1710 \pre The tuple (cb, data) must exactly match an earlier call to
1711 SoRenderManager::addPreRenderCallback
1712
1713 \param[in] cb function to be called
1714 \param[in] data User specified data to supply to callback function
1715 */
1716 void
removePreRenderCallback(SoRenderManagerRenderCB * cb,void * data)1717 SoRenderManager::removePreRenderCallback(SoRenderManagerRenderCB * cb, void * data)
1718 {
1719 std::vector<SoRenderManagerP::RenderCBTouple>::iterator findit =
1720 std::find(PRIVATE(this)->preRenderCallbacks.begin(),
1721 PRIVATE(this)->preRenderCallbacks.end(),
1722 SoRenderManagerP::RenderCBTouple(cb, data));
1723 assert(
1724 (findit != PRIVATE(this)->preRenderCallbacks.end())
1725 &&
1726 "Tried to remove a cb,data tuple which doesn't exist"
1727 );
1728 PRIVATE(this)->preRenderCallbacks.erase(findit);
1729 }
1730
1731 /*!
1732 Adds a function to be called after rendering is complete
1733
1734 \param[in] cb function to be called
1735 \param[in] data User specified data to supply to callback function
1736 */
1737 void
addPostRenderCallback(SoRenderManagerRenderCB * cb,void * data)1738 SoRenderManager::addPostRenderCallback(SoRenderManagerRenderCB * cb, void * data)
1739 {
1740 PRIVATE(this)->postRenderCallbacks.push_back(SoRenderManagerP::RenderCBTouple(cb, data));
1741 }
1742
1743 /*!
1744 Removes a postrendercallback.
1745
1746 \pre The tuple (cb, data) must exactly match an earlier call to
1747 SoRenderManager::addPostRenderCallback
1748
1749 \param[in] cb function to be called
1750 \param[in] data User specified data to supply to callback function
1751 */
1752 void
removePostRenderCallback(SoRenderManagerRenderCB * cb,void * data)1753 SoRenderManager::removePostRenderCallback(SoRenderManagerRenderCB * cb, void * data)
1754 {
1755 std::vector<SoRenderManagerP::RenderCBTouple>::iterator findit =
1756 std::find(PRIVATE(this)->postRenderCallbacks.begin(),
1757 PRIVATE(this)->postRenderCallbacks.end(),
1758 SoRenderManagerP::RenderCBTouple(cb, data));
1759 assert(
1760 (findit != PRIVATE(this)->postRenderCallbacks.end())
1761 &&
1762 "Tried to remove a cb,data tuple which doesn't exist"
1763 );
1764 PRIVATE(this)->postRenderCallbacks.erase(findit);
1765 }
1766
1767 #undef PRIVATE
1768 #undef PUBLIC
1769