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 SoGLRenderAction SoGLRenderAction.h Inventor/actions/SoGLRenderAction.h
35 \brief The SoGLRenderAction class renders the scene graph with OpenGL calls.
36
37 \ingroup actions
38
39 Applying this method at a root node for a scene graph, path or
40 pathlist will render all geometry contained within that instance to
41 the current OpenGL context.
42 */
43
44 // *************************************************************************
45
46 /*!
47 \typedef void SoGLRenderPassCB(void * userdata)
48
49 Callback functions for the setPassCallback() method need to be of
50 this type.
51
52 \a userdata is a void pointer to any data the application need to
53 know of in the callback function (like for instance a \e this
54 pointer).
55
56 \sa setPassCallback()
57 */
58
59 // *************************************************************************
60
61 /*! \file SoGLRenderAction.h */
62 #include <Inventor/actions/SoGLRenderAction.h>
63
64 #ifdef HAVE_CONFIG_H
65 #include "config.h"
66 #endif // HAVE_CONFIG_H
67
68 #include <cstdlib>
69 #include <cstring>
70
71 #include <boost/scoped_ptr.hpp>
72 #include <boost/scoped_array.hpp>
73
74 #include <Inventor/C/glue/gl.h>
75 #include <Inventor/C/tidbits.h>
76 #include <Inventor/SbColor.h>
77 #include <Inventor/SbPlane.h>
78 #include <Inventor/SoFullPath.h>
79 #include <Inventor/actions/SoGetBoundingBoxAction.h>
80 #include <Inventor/actions/SoSearchAction.h>
81 #include <Inventor/caches/SoBoundingBoxCache.h>
82 #include <Inventor/elements/SoCacheElement.h>
83 #include <Inventor/elements/SoDecimationPercentageElement.h>
84 #include <Inventor/elements/SoDecimationTypeElement.h>
85 #include <Inventor/elements/SoGLCacheContextElement.h>
86 #include <Inventor/elements/SoGLLazyElement.h>
87 #include <Inventor/elements/SoGLLightIdElement.h>
88 #include <Inventor/elements/SoGLRenderPassElement.h>
89 #include <Inventor/elements/SoGLUpdateAreaElement.h>
90 #include <Inventor/elements/SoGLViewportRegionElement.h>
91 #include <Inventor/elements/SoLazyElement.h>
92 #include <Inventor/elements/SoModelMatrixElement.h>
93 #include <Inventor/elements/SoOverrideElement.h>
94 #include <Inventor/elements/SoProjectionMatrixElement.h>
95 #include <Inventor/elements/SoShapeHintsElement.h>
96 #include <Inventor/elements/SoShapeStyleElement.h>
97 #include <Inventor/elements/SoMultiTextureEnabledElement.h>
98 #include <Inventor/elements/SoTextureOverrideElement.h>
99 #include <Inventor/elements/SoViewVolumeElement.h>
100 #include <Inventor/elements/SoViewingMatrixElement.h>
101 #include <Inventor/elements/SoWindowElement.h>
102 #include <Inventor/elements/SoGLDepthBufferElement.h>
103 #include <Inventor/errors/SoDebugError.h>
104 #include <Inventor/lists/SoCallbackList.h>
105 #include <Inventor/lists/SoEnabledElementsList.h>
106 #include <Inventor/lists/SoPathList.h>
107 #include <Inventor/misc/SoState.h>
108 #include <Inventor/misc/SoGLDriverDatabase.h>
109 #include <Inventor/nodes/SoGroup.h>
110 #include <Inventor/nodes/SoNode.h>
111 #include <Inventor/nodes/SoSeparator.h>
112 #include <Inventor/nodes/SoShape.h>
113 #include <Inventor/nodes/SoShapeHints.h>
114 #include <Inventor/sensors/SoAlarmSensor.h>
115 #include <Inventor/sensors/SoNodeSensor.h>
116 #include <Inventor/C/tidbits.h>
117 #include <Inventor/system/gl.h>
118 #include <Inventor/annex/Profiler/elements/SoProfilerElement.h>
119 #include <Inventor/annex/Profiler/SoProfiler.h>
120
121 #include "coindefs.h"
122 #include "tidbitsp.h"
123 #include "SbBasicP.h"
124 #include "actions/SoActionP.h"
125 #include "actions/SoSubActionP.h"
126 #include "glue/glp.h"
127 #include "glue/simage_wrapper.h"
128 #include "rendering/SoGL.h"
129
130 #include <Inventor/annex/Profiler/nodes/SoProfilerStats.h>
131 #include "profiler/SoProfilerP.h"
132
133 #ifdef HAVE_NODEKITS
134 #include <Inventor/annex/Profiler/nodekits/SoProfilerTopKit.h>
135 #include <Inventor/annex/Profiler/nodekits/SoProfilerVisualizeKit.h>
136 #endif // HAVE_NODEKITS
137
138 // *************************************************************************
139
140 /*!
141 \enum SoGLRenderAction::TransparencyType
142
143 Various settings for how to do rendering of transparent objects in
144 the scene. Some of the settings will provide faster rendering, while
145 others give you better quality rendering.
146
147 Note that doing correct rendering of \e multiple transparent objects
148 often fails, because to be 100% correct, all polygons needs to be
149 rendered in sorted order, and polygons can't intersect each
150 other. In a dynamic scene graph it is often impossible to guarantee
151 that no polygons intersect, and finding an algorithm that does
152 correct sorting of polygons for all possible cases is very hard and
153 time-consuming.
154
155 The highest quality transparency mode in the original SGI / TGS Open
156 Inventor is SoGLRenderAction::SORTED_OBJECT_BLEND, where all
157 transparent objects are rendered in sorted order in a rendering pass
158 after all opaque objects. However, this mode does not sort the
159 polygons, and if you have an object where some polygon A is behind
160 some other polygon B, the transparency will only be correct if A
161 happens to be rendered before B. For other camera angles, where B is
162 behind A, the transparency will not be correct.
163
164 In Coin we have a new transparency mode that solves some of these
165 problems: SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_BLEND. In
166 addition to sorting the objects, all polygons inside each object is
167 also sorted back-to-front when rendering. But, if you have
168 intersecting objects and/or intersecting polygons, even this
169 transparency mode will fail. Also, because of the polygon sorting,
170 this transparency mode is quite slow. It is possible to speed things
171 up using the SoTransparencyType node, though, which enables you to
172 set different transparency modes for different parts of the scene
173 graph. If you have only have a few objects where you need to sort
174 the polygons, you can use
175 SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_BLEND for those, and
176 for instance SoGLRenderAction::SORTED_OBJECT_BLEND for all other
177 transparent objects.
178
179 The highest quality transparency mode in Coin is
180 SoGLRenderAction::SORTED_LAYERS_BLEND. It is also the only mode that
181 overrides all other modes in the scenegraph.
182
183 (One important note about this mode: we've had reports from users
184 that some OpenGL drivers -- possibly particular for some Mac OS X
185 systems -- significantly degrades rendering performance. So be
186 careful and test your application on a wide variety of run-time
187 systems when using SoGLRenderAction::SORTED_LAYERS_BLEND.)
188
189 \sa SoTransparencyType
190 */
191
192 /*!
193 \var SoGLRenderAction::TransparencyType SoGLRenderAction::SCREEN_DOOR
194
195 Transparent triangles are rendered with a dither pattern. This is
196 a fast (on most GFX cards) but not-so-high-quality transparency mode.
197
198 One particular feature of this mode is that you are guaranteed that
199 it always renders the transparent parts of the scene correct with
200 regard to internal depth ordering of objects / polygons, something
201 which is not the case for any other transparency mode.
202
203 Polygons rendered with only transparent textures are not shown as
204 being transparent when using this mode. The reason being that the
205 SCREEN_DOOR mode is working on polygons, not pixels. To render
206 polygons with dither pattern, a material node has to be inserted
207 into the scenegraph with it's transparency field set.
208 */
209
210 /*!
211
212 \var SoGLRenderAction::TransparencyType SoGLRenderAction::ADD
213
214 Transparent objects are rendered using additive alpha blending.
215 Additive blending is probably mostly used to create special
216 transparency effects. The new pixel color is calculated as the
217 current pixel color plus the source pixel color multiplied with the
218 source pixel alpha value.
219
220 */
221
222 /*!
223 \var SoGLRenderAction::TransparencyType SoGLRenderAction::DELAYED_ADD
224
225 SoGLRenderAction::DELAYED_ADD Transparent objects are rendered using
226 additive alpha blending, in a second rendering pass with depth
227 buffer updates disabled.
228
229 */
230
231 /*!
232 \var SoGLRenderAction::TransparencyType SoGLRenderAction::SORTED_OBJECT_ADD
233
234 Transparent objects are rendered using additive alpha blending.
235 Opaque objects are rendered first, and transparent objects are
236 rendered back to front with z-buffer updates disabled.
237
238 */
239
240 /*!
241 \var SoGLRenderAction::TransparencyType SoGLRenderAction::BLEND
242
243 Transparent objects are rendered using multiplicative alpha blending.
244
245 Multiplicative alpha blending is the blending type that is most
246 often used to render transparent objects. The new pixel value is
247 calculated as the old pixel color multiplied with one minus the
248 source alpha value, plus the source pixel color multiplied with the
249 source alpha value.
250
251 We recommend that you use this transparency mode if you have only
252 one transparent object in your scene, and you know that it will be
253 rendered after the opaque objects.
254
255 */
256
257 /*!
258 \var SoGLRenderAction::TransparencyType SoGLRenderAction::DELAYED_BLEND
259
260 Transparent objects are rendered using multiplicative alpha
261 blending, in a second rendering pass with depth buffer updates
262 disabled.
263
264 Use this transparency type when you have one transparent object, or
265 several transparent object that you know will never overlap (when
266 projected to screen). Since the transparent objects are rendered
267 after opaque ones, you'll not have to worry about putting the
268 transparent objects at the end of your scene graph. It will not be
269 as fast as the BLEND transparency type, of course, since the scene
270 graph is traversed twice.
271
272 */
273
274 /*!
275 \var SoGLRenderAction::TransparencyType SoGLRenderAction::SORTED_OBJECT_BLEND
276
277 Transparent objects are rendered using multiplicative alpha
278 blending, Opaque objects are rendered first, and transparent objects
279 are rendered back to front with z-buffer updates disabled.
280
281 Use this transparency mode when you have several transparent object
282 that you know might overlap (when projected to screen). This method
283 will require 1 + num_transparent_objects rendering passes. Path
284 traversal is used when rendering transparent objects, of course, but
285 it might still be slow if you have lots of state changes before your
286 transparent object. When using this mode, we recommend placing the
287 transparent objects as early as possible in the scene graph to
288 minimize traversal overhead.
289 */
290
291 /*!
292 \var SoGLRenderAction::TransparencyType SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_ADD
293
294 This transparency type is a Coin extension versus the original SGI
295 Open Inventor API.
296
297 Transparent objects are rendered back to front, and triangles in
298 each object are sorted back to front before rendering.
299
300 See description for SORTED_OBJECT_SORTED_TRIANGLE_BLEND for more
301 information about this transparency type.
302
303 */
304
305 /*!
306 \var SoGLRenderAction::TransparencyType SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_BLEND
307
308 This transparency type is a Coin extension versus the original SGI
309 Open Inventor API.
310
311 Transparent objects are rendered back to front, and triangles in
312 each object are sorted back to front before rendering.
313
314 Use this transparency type when you have one (or more) transparent
315 object(s) where you know triangles might overlap inside the object.
316 This transparency type might be very slow if you have an object with
317 lots of triangles, since all triangles have to be sorted before
318 rendering, and an unoptimized rendering loop is used when rendering.
319 Lines and points are not sorted before rendering. They are rendered
320 as in the normal SORTED_OBJECT_BLEND transparency type.
321
322 Please note that this transparency mode does not guarantee
323 "correct" transparency rendering. It is almost impossible to find an
324 algorithm that will sort triangles correctly in all cases, and
325 intersecting triangles are not handled. Also, since each object
326 is handled separately, two intersecting object will lead to
327 incorrect transparency.
328 */
329
330 /*!
331 \var SoGLRenderAction::TransparencyType SoGLRenderAction::NONE
332
333 This transparency type is a Coin extension versus the Open Inventor
334 API.
335
336 Turns off transparency for objects, even if transparency is set using
337 an SoMaterial node.
338
339 \since Coin 1.0
340 */
341
342 /*!
343 \var SoGLRenderAction::TransparencyType SoGLRenderAction::SORTED_LAYERS_BLEND
344
345 This transparency type is a Coin extension versus the original SGI
346 Open Inventor API.
347
348 By using this transparency type, the SoGLRenderAction will render
349 normal and intersecting transparent objects correctly independent of
350 rendering order. It is the only transparency type rendering mode
351 which is guaranteed to do so.
352
353 This mode is different from all other modes in that it overrides the
354 SoTransparencyType nodes in the scenegraph; all objects are drawn using
355 SORTED_LAYERS_BLEND.
356
357 There are currently two separate code paths for this mode. Both
358 paths are heavily based on OpenGL extensions. The first method is
359 based on extensions which are only available on NVIDIA chipsets
360 (GeForce3 and above, except GeForce4 MX). These extensions are \c
361 GL_NV_texture_shader, \c GL_NV_texture_rectangle or \c
362 GL_EXT_texture_rectangle, \c GL_NV_register_combiners, \c
363 GL_ARB_shadow and \c GL_ARB_depth_texture. Please note that this
364 transparency type occupy all four texture units on the NVIDIA card
365 for all the rendering passes, except the first. Textured surfaces
366 will therefore only be textured if they are not occluded by another
367 transparent surface.
368
369 The second method utilise the \c GL_ARB_fragment_program
370 extension. This extension is currently supported by the GeForceFX
371 family and the Radeon 9500 and above. This technique is faster than
372 the pure NVIDIA method. The fragment program method will
373 automatically be chosen if possible.
374 Please note that one should beware not to place the near-plane too
375 close to the camera due to the lack of floating point precision
376 control in fragment programs. Doing so may lead to loss of precision
377 around the edges and 'jaggedness' of the transparent geometry.
378
379 Setting the environment variable COIN_SORTED_LAYERS_USE_NVIDIA_RC to
380 '1' will force the use of former code path instead of the latter,
381 even if it is available.
382
383 A rendering context with >= 24 bits depth buffer and 8 bits alpha
384 channel must be the current rendering context for this blending mode
385 to actually become activated. If the current rendering canvas does
386 not have these properties, Coin will fall back on a simpler
387 transparency handling mode. If you are using one of the
388 window-system binding libraries provided by Kongsberg Oil & Gas Technologies,
389 e.g. SoXt, SoQt or SoWin, you will need to explicitly enable this in
390 your viewer. See the API documentation of the \c setAlphaChannel()
391 method of either SoXtGLWidget, SoQtGLWidget or SoWinGLWidget.
392
393 The detection of whether or not the SORTED_LAYERS_BLEND mode can be
394 used will be done automatically by the Coin internals. If one or
395 more of the necessary conditions listed above are unavailable,
396 SoGLRenderAction::SORTED_OBJECT_BLEND will be used as the
397 transparency type instead.
398
399 To be able to render correct transparency independent of object
400 order, one have to render in multiple passes. This technique is
401 based on depth-peeling which strips away depth layers with each
402 successive pass. The number of passes is therefore an indication of
403 how deep into the scene transparent surfaces will be rendered with
404 transparency. A higher number will lead to a lower framerate but
405 higher quality for scenes with a lot of transparent surfaces. The
406 default number of passes is '4'. This number can be specified using
407 the SoGLRenderAction::setSortedLayersNumPasses() or by letting the
408 environment variable \c COIN_NUM_SORTED_LAYERS_PASSES or \c
409 OIV_NUM_SORTED_LAYERS_PASSES specify the number of passes.
410
411 A more detailed presentation of the algorithm is written by Cass
412 Everitt at NVIDIA;
413
414 "Interactive Order-Independent Transparency"
415 http:://developer.nvidia.com/object/order_independent_transparency.html
416
417 \since Coin 2.2
418 \since TGS Inventor 4.0
419 */
420
421 // FIXME:
422 // todo: - Add debug printout info concerning choosen blend method.
423 // - Add GL_[NV/HP]_occlusion_test support making the number of passes adaptive.
424 // - Maybe pbuffer support to eliminate the slow glCopyTexSubImage2D calls.
425 // - Investigate whether the TGS method using only EXT_texture_env_combine is a
426 // feasible method (especially when it comes to speed and number of required
427 // texture units). [If more than two units are needed, then
428 // a GeForce3++ card is required, which again is already
429 // supported using the NVIDIA method.]
430 // (20031128 handegar)
431 //
432
433 /*!
434 \enum SoGLRenderAction::AbortCode
435
436 The return codes which an SoGLRenderAbortCB callback function should
437 use.
438
439 \sa setAbortCallback()
440 */
441 /*!
442 \var SoGLRenderAction::AbortCode SoGLRenderAction::CONTINUE
443 Continue rendering as usual.
444 */
445 /*!
446 \var SoGLRenderAction::AbortCode SoGLRenderAction::ABORT
447 Abort the rendering action immediately.
448 */
449 /*!
450 \var SoGLRenderAction::AbortCode SoGLRenderAction::PRUNE
451 Do not render the current node or any of its children, but continue
452 the rendering traversal.
453 */
454 /*!
455 \var SoGLRenderAction::AbortCode SoGLRenderAction::DELAY
456 Delay rendering of the current node (and its children) until the
457 next rendering pass.
458 */
459
460 /*!
461 \typedef typedef SoGLRenderAction::SoGLRenderAbortCB(void * userdata)
462 Abort callbacks should be of this type.
463 \sa setAbortCallback()
464 */
465
466 /*!
467 \typedef float SoGLSortedObjectOrderCB(void * userdata, SoGLRenderAction * action)
468
469 A callback used for controlling the transparency sorting order.
470
471 \sa setSortedObjectOrderStrategy().
472 \since Coin 2.5
473 */
474
475 /*!
476 \enum SoGLRenderAction::SortedObjectOrderStrategy
477
478 Used for enumerating the different transparency sorting strategies.
479
480 \sa setSortedObjectOrderStrategy().
481 \since Coin 2.5
482 */
483
484 /*!
485 \var SoGLRenderAction::SortedObjectOrderStrategy SoGLRenderAction::BBOX_CENTER
486
487 Do the sorting based on the center of the object bounding box.
488
489 \sa setSortedObjectOrderStrategy().
490 \since Coin 2.5
491 */
492
493 /*!
494 \var SoGLRenderAction::SortedObjectOrderStrategy SoGLRenderAction::BBOX_CLOSEST_CORNER
495
496 Do the sorting based on the bounding box corner closest to the camera.
497
498 \sa setSortedObjectOrderStrategy().
499 \since Coin 2.5
500 */
501
502 /*!
503 \var SoGLRenderAction::SortedObjectOrderStrategy SoGLRenderAction::BBOX_FARTHEST_CORNER
504
505 Do the sorting based on the bounding box corner farthest from the camera.
506
507 \sa setSortedObjectOrderStrategy().
508 \since Coin 2.5
509 */
510
511 /*!
512 \var SoGLRenderAction::SortedObjectOrderStrategy SoGLRenderAction::CUSTOM_CALLBACK
513
514 Use a custom callback to determine the sorting order.
515
516 \sa setSortedObjectOrderStrategy().
517 \since Coin 2.5
518 */
519
520 /*!
521 \enum SoGLRenderAction::TransparentDelayedObjectRenderType
522
523 Enumerates the render types of transparent objects.
524 */
525
526 /*!
527 \var SoGLRenderAction::TransparentDelayedObjectRenderType SoGLRenderAction::ONE_PASS
528
529 Normal one pass rendering. This might cause artifacts for non-solid objects.
530 */
531
532 /*!
533 \var SoGLRenderAction::TransparentDelayedObjectRenderType SoGLRenderAction::NONSOLID_SEPARATE_BACKFACE_PASS
534
535 Non-solid objects are handled in an extra rendering pass. Backfacing
536 polygons are rendered in the first pass, and the front facing in the
537 second pass.
538 */
539
540 // *************************************************************************
541
542 class SoGLRenderActionP {
543 public:
SoGLRenderActionP(void)544 SoGLRenderActionP(void) : action(NULL) { }
545
546 SoGLRenderAction * action;
547 SbViewportRegion viewport;
548 int numpasses;
549 SbBool internal_multipass;
550 SoGLRenderAction::TransparencyType transparencytype;
551 SbBool smoothing;
552 SbBool passupdate;
553 SoGLRenderPassCB * passcallback;
554 void * passcallbackdata;
555 SoGLRenderAction::SoGLRenderAbortCB * abortcallback;
556 void * abortcallbackdata;
557 uint32_t cachecontext;
558 int currentpass;
559 SoPathList delayedpaths;
560 SbBool delayedpathrender;
561 SbBool transparencyrender;
562 SoPathList transpobjpaths;
563 SoPathList sorttranspobjpaths;
564 SbList<float> sorttranspobjdistances;
565 SoGLRenderAction::TransparentDelayedObjectRenderType transpdelayedrendertype;
566 SbBool renderingtranspbackfaces;
567
568 boost::scoped_ptr<SoGetBoundingBoxAction> bboxaction;
569 SbVec2f updateorigin, updatesize;
570 SbBool needglinit;
571 SbBool isrendering;
572 SbBool isrenderingoverlay;
573 SbBool transpobjdepthwrite;
574 SoCallbackList precblist;
575
576 enum { RENDERING_UNSET, RENDERING_SET_DIRECT, RENDERING_SET_INDIRECT };
577 int rendering;
578 SbBool isDirectRendering(const SoState * state) const;
579 int sortedlayersblendpasses;
580
581 SoNode * cachedprofilingsg;
582
583 GLuint depthtextureid;
584 GLuint hilotextureid;
585 boost::scoped_array<GLuint> rgbatextureids;
586 GLuint sortedlayersblendprogramid;
587 unsigned short viewportheight;
588 unsigned short viewportwidth;
589 SbBool sortedlayersblendinitialized;
590 SbMatrix sortedlayersblendprojectionmatrix;
591 int sortedlayersblendcounter;
592 SbBool usenvidiaregistercombiners;
593
594 SoGLRenderAction::SortedObjectOrderStrategy sortedobjectstrategy;
595 SoGLSortedObjectOrderCB * sortedobjectcb;
596 void * sortedobjectclosure;
597
598 void setupSortedLayersBlendTextures(const SoState * state);
599 void doSortedLayersBlendRendering(const SoState * state, SoNode * node);
600 void initSortedLayersBlendRendering(const SoState * state);
601 void renderOneBlendLayer(const SoState * state, SbBool shadow, SbBool update_ztex, SoNode * node);
602 void texgenEnable(SbBool enable);
603 void eyeLinearTexgen();
604
605 // NVIDIA spesific methods for sorted layers blend
606 void setupRegisterCombinersNV();
607 void renderSortedLayersNV(const SoState * state);
608
609 // ARB_fragment_program spesific methods for sorted layers blend
610 void setupFragmentProgram();
611 void renderSortedLayersFP(const SoState * state);
612
613 void setupBlending(SoState * state, const SoGLRenderAction::TransparencyType newtype);
614 void render(SoNode * node);
615 void renderMulti(SoNode * node);
616 void renderSingle(SoNode * node);
617
618 // For transparent paths that need to be sorted
619 void addSortTransPath(SoPath * path);
620
621 void addTransPath(SoPath * path);
622 void doPathSort(void);
623
624 // For profiling mode auto-redraw functionality
625 boost::scoped_ptr<SoAlarmSensor> redrawSensor;
626 static void redrawSensorCB(void * userdata, SoSensor * sensor);
627 boost::scoped_ptr<SoNodeSensor> deleteSensor;
628 static void deleteNodeCB(void * userdata, SoSensor * sensor);
629
630 };
631
632 // *************************************************************************
633
634 SO_ACTION_SOURCE(SoGLRenderAction);
635
636 static int COIN_GLBBOX = 0;
637
638 // *************************************************************************
639
640 // Override from parent class.
641 void
initClass(void)642 SoGLRenderAction::initClass(void)
643 {
644 SO_ACTION_INTERNAL_INIT_CLASS(SoGLRenderAction, SoAction);
645
646 SO_ENABLE(SoGLRenderAction, SoDecimationPercentageElement);
647 SO_ENABLE(SoGLRenderAction, SoDecimationTypeElement);
648 SO_ENABLE(SoGLRenderAction, SoGLLightIdElement);
649 SO_ENABLE(SoGLRenderAction, SoGLRenderPassElement);
650 SO_ENABLE(SoGLRenderAction, SoGLUpdateAreaElement);
651 SO_ENABLE(SoGLRenderAction, SoLazyElement);
652 SO_ENABLE(SoGLRenderAction, SoOverrideElement);
653 SO_ENABLE(SoGLRenderAction, SoTextureOverrideElement);
654 SO_ENABLE(SoGLRenderAction, SoWindowElement);
655 SO_ENABLE(SoGLRenderAction, SoGLViewportRegionElement);
656 SO_ENABLE(SoGLRenderAction, SoGLCacheContextElement);
657
658 const char * env = coin_getenv("COIN_GLBBOX");
659 if (env) {
660 COIN_GLBBOX = atoi(env);
661 }
662 else {
663 COIN_GLBBOX = 0;
664 }
665 }
666
667 // *************************************************************************
668
669
670 static const char * sortedlayersblendprogram =
671 "!!ARBfp1.0\n"
672 "OPTION ARB_precision_hint_nicest;\n"
673 "TEMP tmp;\n"
674 "PARAM c0 = {0, 1, 0.0040000002, 0};\n" // 0.004 = precision delta value for float division
675 "TEMP R0;\n"
676 "TEMP R1;\n"
677 "TEMP H0;\n"
678 "TXP R0.x, fragment.texcoord[3], texture[3], RECT;\n"
679 "RCP R1.x, fragment.texcoord[3].w;\n"
680 "MAD R0.x, fragment.texcoord[3].z, R1.x, -R0.x;\n"
681 "ADD R0.x, c0.z, -R0.x;\n"
682 "CMP H0.x, R0.x, c0.x, c0.y;\n"
683 "MOV H0, -H0.x;\n"
684 "KIL H0;\n"
685 // -- Adding texture from unit 0 --
686 // FIXME: This is a hackish solution. Texture settings like
687 // GL_MODULATE, GL_LUMINANCE etc. are ignored. (20031215 handegar)
688 "TEX tmp, fragment.texcoord[0], texture[0], 2D;\n"
689 "MOV tmp.a, 0;\n"
690 "ADD result.color, fragment.color.primary, tmp;\n"
691 "END";
692
693 #define PRIVATE(obj) ((obj)->pimpl)
694
695 /*!
696 Constructor. Sets up the render action for rendering within the
697 given \a viewportregion.
698 */
SoGLRenderAction(const SbViewportRegion & viewportregion)699 SoGLRenderAction::SoGLRenderAction(const SbViewportRegion & viewportregion)
700 {
701 SO_ACTION_CONSTRUCTOR(SoGLRenderAction);
702
703 PRIVATE(this)->action = this;
704 // Can't just push this on the SoViewportRegionElement stack, as the
705 // state hasn't been made yet.
706 PRIVATE(this)->viewport = viewportregion;
707
708 PRIVATE(this)->passcallback = NULL;
709 PRIVATE(this)->passcallbackdata = NULL;
710 PRIVATE(this)->smoothing = FALSE;
711 PRIVATE(this)->currentpass = 0;
712 PRIVATE(this)->numpasses = 1;
713 PRIVATE(this)->internal_multipass = FALSE;
714 PRIVATE(this)->transparencytype = SoGLRenderAction::BLEND;
715 PRIVATE(this)->delayedpathrender = FALSE;
716 PRIVATE(this)->transparencyrender = FALSE;
717 PRIVATE(this)->isrendering = FALSE;
718 PRIVATE(this)->isrenderingoverlay = FALSE;
719 PRIVATE(this)->passupdate = FALSE;
720 PRIVATE(this)->bboxaction.reset(new SoGetBoundingBoxAction(viewportregion));
721 PRIVATE(this)->updateorigin.setValue(0.0f, 0.0f);
722 PRIVATE(this)->updatesize.setValue(1.0f, 1.0f);
723 PRIVATE(this)->rendering = SoGLRenderActionP::RENDERING_UNSET;
724 PRIVATE(this)->abortcallback = NULL;
725 PRIVATE(this)->cachecontext = 0;
726 PRIVATE(this)->needglinit = TRUE;
727 PRIVATE(this)->sortedlayersblendpasses = 4;
728 PRIVATE(this)->viewportheight = 0;
729 PRIVATE(this)->viewportwidth = 0;
730 PRIVATE(this)->sortedlayersblendinitialized = FALSE;
731 PRIVATE(this)->sortedlayersblendcounter = 0;
732 PRIVATE(this)->usenvidiaregistercombiners = FALSE;
733 PRIVATE(this)->cachedprofilingsg = NULL;
734 PRIVATE(this)->transpobjdepthwrite = FALSE;
735 PRIVATE(this)->transpdelayedrendertype = ONE_PASS;
736 PRIVATE(this)->renderingtranspbackfaces = FALSE;
737
738 PRIVATE(this)->sortedobjectstrategy = BBOX_CENTER;
739 PRIVATE(this)->sortedobjectcb = NULL;
740 PRIVATE(this)->sortedobjectclosure = NULL;
741 }
742
743 /*!
744 Destructor.
745 */
~SoGLRenderAction()746 SoGLRenderAction::~SoGLRenderAction()
747 {
748 }
749
750 /*!
751 Sets the viewport region for rendering. This will then override the
752 region passed in with the constructor.
753 */
754 void
setViewportRegion(const SbViewportRegion & newregion)755 SoGLRenderAction::setViewportRegion(const SbViewportRegion & newregion)
756 {
757 PRIVATE(this)->viewport = newregion;
758 PRIVATE(this)->bboxaction->setViewportRegion(newregion);
759 // The SoViewportRegionElement is not set here, as it is always
760 // initialized before redraw in beginTraversal().
761 }
762
763 /*!
764 Returns the viewport region for the rendering action.
765 */
766 const SbViewportRegion &
getViewportRegion(void) const767 SoGLRenderAction::getViewportRegion(void) const
768 {
769 return PRIVATE(this)->viewport;
770 }
771
772 /*!
773 Sets the area of the OpenGL context canvas we should render into.
774
775 The coordinates for \a origin and \a size should be normalized to be
776 within [0.0, 1.0]. The default settings are <0.0, 0.0> for the \a
777 origin and <1.0, 1.0> for the \a size, using the full size of the
778 rendering canvas.
779 */
780 void
setUpdateArea(const SbVec2f & origin,const SbVec2f & size)781 SoGLRenderAction::setUpdateArea(const SbVec2f & origin, const SbVec2f & size)
782 {
783 PRIVATE(this)->updateorigin = origin;
784 PRIVATE(this)->updatesize = size;
785 }
786
787 /*!
788 Returns information about the area of the rendering context window
789 to be updated.
790 */
791 void
getUpdateArea(SbVec2f & origin,SbVec2f & size) const792 SoGLRenderAction::getUpdateArea(SbVec2f & origin, SbVec2f & size) const
793 {
794 origin = PRIVATE(this)->updateorigin;
795 size = PRIVATE(this)->updatesize;
796 }
797
798 /*!
799 Sets the abort callback. The abort callback is called by the action
800 for each node during traversal to check for abort conditions.
801
802 The callback method should return one of the
803 SoGLRenderAction::AbortCode enum values to indicate how the action
804 should proceed further.
805
806 Since the client SoGLRenderAbortCB callback function only has a
807 single void* argument for the userdata, one has to do some
808 additional work to find out which node the callback was made
809 for. One can do this by for instance passing along the action
810 pointer as userdata, and then call the
811 SoGLRenderAction::getCurPath() method. The tail of the path will
812 then be the last traversed node. Like this:
813
814 \code
815 // set up so we can abort or otherwise intervene with the render
816 // traversal:
817 myRenderAction->setAbortCallback(MyRenderCallback, myRenderAction);
818
819 // [...]
820
821 SoGLRenderAction::AbortCode
822 MyRenderCallback(void * userdata)
823 {
824 SoGLRenderAction * action = (SoGLRenderAction *)userdata;
825 SoNode * lastnode = action->getCurPath()->getTail();
826
827 // [...]
828 return SoGLRenderAction::CONTINUE;
829 }
830 \endcode
831
832 \sa SoGLRenderAction::AbortCode
833 */
834 void
setAbortCallback(SoGLRenderAbortCB * const func,void * const userdata)835 SoGLRenderAction::setAbortCallback(SoGLRenderAbortCB * const func,
836 void * const userdata)
837 {
838 PRIVATE(this)->abortcallback = func;
839 PRIVATE(this)->abortcallbackdata = userdata;
840 }
841
842 /*!
843 Returns the abort callback settings.
844
845 \sa setAbortCallback
846 \since Coin 3.0
847 */
848 void
getAbortCallback(SoGLRenderAbortCB * & func_out,void * & userdata_out) const849 SoGLRenderAction::getAbortCallback(SoGLRenderAbortCB * & func_out,
850 void * & userdata_out) const
851 {
852 func_out = PRIVATE(this)->abortcallback;
853 userdata_out = PRIVATE(this)->abortcallbackdata;
854 }
855
856 /*!
857 Sets the transparency rendering method for transparent objects in
858 the scene graph.
859
860 \sa SoGLRenderAction::TransparencyType
861 */
862 void
setTransparencyType(const TransparencyType type)863 SoGLRenderAction::setTransparencyType(const TransparencyType type)
864 {
865 if (PRIVATE(this)->transparencytype != type) {
866 PRIVATE(this)->transparencytype = type;
867 PRIVATE(this)->needglinit = TRUE;
868 }
869 }
870
871 /*!
872 Returns the transparency rendering type.
873 */
874 SoGLRenderAction::TransparencyType
getTransparencyType(void) const875 SoGLRenderAction::getTransparencyType(void) const
876 {
877 return PRIVATE(this)->transparencytype;
878 }
879
880 /*!
881 Sets (or unsets) smoothing. If the smoothing flag is \c on, Coin
882 will try to use built-in features from the OpenGL implementation to
883 smooth the appearance of otherwise jagged line and point primitives,
884 calling
885
886 \verbatim
887 glEnable(GL_POINT_SMOOTH);
888 glEnable(GL_LINE_SMOOTH);
889 \endverbatim
890
891 ...before rendering the scene.
892
893 This is a simple (and computationally non-intensive) way of doing
894 anti-aliasing.
895
896 Default value for this flag is to be \c off.
897 */
898 void
setSmoothing(const SbBool smooth)899 SoGLRenderAction::setSmoothing(const SbBool smooth)
900 {
901 if (smooth != PRIVATE(this)->smoothing) {
902 PRIVATE(this)->smoothing = smooth;
903 PRIVATE(this)->needglinit = TRUE;
904 }
905 }
906
907 /*!
908 Returns whether smoothing is set or not.
909 */
910 SbBool
isSmoothing(void) const911 SoGLRenderAction::isSmoothing(void) const
912 {
913 return PRIVATE(this)->smoothing;
914 }
915
916 /*!
917 Sets the number of rendering passes. Default is 1, anything greater
918 will enable antialiasing through the use of an OpenGL accumulation
919 buffer.
920 */
921 void
setNumPasses(const int num)922 SoGLRenderAction::setNumPasses(const int num)
923 {
924 PRIVATE(this)->numpasses = num;
925 PRIVATE(this)->internal_multipass = num > 1;
926 }
927
928 /*!
929 Returns the number of rendering passes done on updates.
930 */
931 int
getNumPasses(void) const932 SoGLRenderAction::getNumPasses(void) const
933 {
934 return PRIVATE(this)->numpasses;
935 }
936
937 /*!
938 Sets whether each pass should render to screen or not.
939 */
940 void
setPassUpdate(const SbBool flag)941 SoGLRenderAction::setPassUpdate(const SbBool flag)
942 {
943 PRIVATE(this)->passupdate = flag;
944 }
945
946 /*!
947 Returns the value of the "show intermediate updates" flag.
948
949 \sa setPassUpdate()
950 */
951 SbBool
isPassUpdate(void) const952 SoGLRenderAction::isPassUpdate(void) const
953 {
954 return PRIVATE(this)->passupdate;
955 }
956
957 /*!
958 Sets the pass callback. The callback is called between each
959 rendering pass.
960 */
961 void
setPassCallback(SoGLRenderPassCB * const func,void * const userdata)962 SoGLRenderAction::setPassCallback(SoGLRenderPassCB * const func,
963 void * const userdata)
964 {
965 PRIVATE(this)->passcallback = func;
966 PRIVATE(this)->passcallbackdata = userdata;
967 }
968
969 /*!
970 Sets the OpenGL cache context key, which is used for deciding when
971 to share OpenGL display lists.
972
973 Each SoGLRenderAction has a cache context id. This can be set using
974 SoGLRenderAction::setCacheContext(). The cache context id must be
975 unique, so that different texture objects and display lists are
976 created for uncompatible GL contexts. For instance, when
977 SoGLRenderAction traverses an SoTexture2 node, the node checks if it
978 has a texture object created for the cache context. If not, a new
979 texture object will be created and used when rendering.
980
981 \sa SoGLCacheContextElement::getUniqueCacheContext()
982 */
983 void
setCacheContext(const uint32_t context)984 SoGLRenderAction::setCacheContext(const uint32_t context)
985 {
986 if (context != PRIVATE(this)->cachecontext) {
987 PRIVATE(this)->cachecontext = context;
988 this->invalidateState();
989 }
990 }
991
992 /*!
993 Returns the cache context key for this rendering action instance.
994 */
995 uint32_t
getCacheContext(void) const996 SoGLRenderAction::getCacheContext(void) const
997 {
998 return PRIVATE(this)->cachecontext;
999 }
1000
1001 /*!
1002 Sets the number of passes to render in SoGLRenderAction::SORTED_LAYERS_BLEND
1003 mode. Default number of passes is 4. This number can also be
1004 adjusted by setting the \c COIN_NUM_SORTED_LAYERS_PASSES or
1005 \c OIV_NUM_SORTED_LAYERS_PASSES environment variable.
1006 */
1007 void
setSortedLayersNumPasses(int num)1008 SoGLRenderAction::setSortedLayersNumPasses(int num)
1009 {
1010 PRIVATE(this)->sortedlayersblendpasses = num;
1011 }
1012
1013 /*!
1014 Returns the number of passes to render when in
1015 SoGLRenderAction::SORTED_LAYERS_BLEND mode.
1016 */
1017 int
getSortedLayersNumPasses() const1018 SoGLRenderAction::getSortedLayersNumPasses() const
1019 {
1020 return PRIVATE(this)->sortedlayersblendpasses;
1021 }
1022
1023
1024 // Documented in superclass. Overridden from parent class to
1025 // initialize the OpenGL state.
1026 void
beginTraversal(SoNode * node)1027 SoGLRenderAction::beginTraversal(SoNode * node)
1028 {
1029 if (PRIVATE(this)->cachedprofilingsg == NULL) {
1030 if (node->isOfType(SoGroup::getClassTypeId()) &&
1031 (coin_assert_cast<SoGroup *>(node))->getNumChildren() > 0) {
1032 PRIVATE(this)->cachedprofilingsg = node;
1033
1034 #ifdef HAVE_NODEKITS
1035 SoNode * kit = SoActionP::getProfilerOverlay();
1036 if (kit) {
1037 SoSearchAction sa;
1038 sa.setType(SoProfilerVisualizeKit::getClassTypeId());
1039 sa.setSearchingAll(TRUE);
1040 sa.setInterest(SoSearchAction::ALL);
1041 SbBool oldchildsearch = SoBaseKit::isSearchingChildren();
1042 SoBaseKit::setSearchingChildren(TRUE);
1043 sa.apply(kit);
1044 SoBaseKit::setSearchingChildren(oldchildsearch);
1045 SoPathList plist = sa.getPaths();
1046 for (int i = 0, n = plist.getLength(); i < n; ++i) {
1047 SoFullPath * path = reclassify_cast<SoFullPath *>(plist[i]);
1048 SoNode * tail = path->getTail();
1049 if ((tail != NULL) &&
1050 (tail->isOfType(SoProfilerVisualizeKit::getClassTypeId()))) {
1051 SoProfilerVisualizeKit * viskit = coin_assert_cast<SoProfilerVisualizeKit *>(tail);
1052 viskit->root.setValue(node);
1053 }
1054 }
1055 }
1056 #endif // HAVE_NODEKITS
1057 }
1058 }
1059
1060 if (PRIVATE(this)->isrendering) {
1061 if (PRIVATE(this)->isrenderingoverlay)
1062 this->traverse(node);
1063 else
1064 inherited::beginTraversal(node);
1065 return;
1066 }
1067
1068 // If the environment variable COIN_GLBBOX is set to 1, apply a bbox
1069 // action before rendering. This will make sure bounding box caches
1070 // are updated (needed for view frustum culling). The default
1071 // SoQt/SoWin/SoXt viewers will also apply a SoGetBoundingBoxAction
1072 // so we don't do this by default yet.
1073 if (COIN_GLBBOX) {
1074 PRIVATE(this)->bboxaction->apply(node);
1075 }
1076 int err_before_init = GL_NO_ERROR;
1077
1078 if (sogl_glerror_debugging()) {
1079 err_before_init = glGetError();
1080 }
1081 if (PRIVATE(this)->needglinit) {
1082 PRIVATE(this)->needglinit = FALSE;
1083
1084 // we are always using GL_COLOR_MATERIAL in Coin
1085 glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
1086 glEnable(GL_COLOR_MATERIAL);
1087 glEnable(GL_NORMALIZE);
1088
1089 // initialize the depth function to the default Coin/Inventor
1090 // value. SoGLDepthBufferElement doesn't check for this, it just
1091 // assumes that the function is initialized to GL_LEQUAL, which is
1092 // not correct (the OpenGL specification says the initial value is
1093 // GL_LESS, but I've seen drivers that defaults to GL_LEQUAL as
1094 // well).
1095 glDepthFunc(GL_LEQUAL);
1096
1097 if (PRIVATE(this)->smoothing) {
1098 glEnable(GL_POINT_SMOOTH);
1099 glEnable(GL_LINE_SMOOTH);
1100 }
1101 else {
1102 glDisable(GL_POINT_SMOOTH);
1103 glDisable(GL_LINE_SMOOTH);
1104 }
1105 }
1106
1107 int err_after_init = GL_NO_ERROR;
1108
1109 if (sogl_glerror_debugging()) {
1110 err_after_init = glGetError();
1111 }
1112
1113 if (COIN_DEBUG && ((err_before_init != GL_NO_ERROR) || (err_after_init != GL_NO_ERROR))) {
1114 int err = (err_before_init != GL_NO_ERROR) ? err_before_init : err_after_init;
1115 SoDebugError::postWarning("SoGLRenderAction::beginTraversal",
1116 "GL error %s initialization: %s",
1117 (err_before_init != GL_NO_ERROR) ? "before" : "after",
1118 coin_glerror_string(err));
1119 }
1120
1121 PRIVATE(this)->render(node);
1122 // GL errors after rendering will be caught in SoNode::GLRenderS().
1123 }
1124
1125 // Documented in superclass. Overridden from parent class to clean up
1126 // the lists of objects which were included in the delayed rendering.
1127 void
endTraversal(SoNode * node)1128 SoGLRenderAction::endTraversal(SoNode * node)
1129 {
1130 inherited::endTraversal(node);
1131 if (SoProfilerP::shouldContinuousRender()) {
1132 float delay = SoProfilerP::getContinuousRenderDelay();
1133 if (delay == 0.0f) {
1134 node->touch();
1135 } else {
1136 if (PRIVATE(this)->redrawSensor.get() == NULL) {
1137 PRIVATE(this)->redrawSensor.reset(new SoAlarmSensor);
1138 }
1139 if (PRIVATE(this)->redrawSensor->isScheduled()) {
1140 PRIVATE(this)->redrawSensor->unschedule();
1141 }
1142 PRIVATE(this)->redrawSensor->setFunction(SoGLRenderActionP::redrawSensorCB);
1143 PRIVATE(this)->redrawSensor->setData(node);
1144 PRIVATE(this)->redrawSensor->setTimeFromNow(SbTime(static_cast<double>(delay)));
1145 PRIVATE(this)->redrawSensor->schedule();
1146 if (PRIVATE(this)->deleteSensor.get() == NULL) {
1147 PRIVATE(this)->deleteSensor.reset(new SoNodeSensor);
1148 }
1149 PRIVATE(this)->deleteSensor->setDeleteCallback(SoGLRenderActionP::deleteNodeCB, &(PRIVATE(this).get()));
1150 PRIVATE(this)->deleteSensor->attach(node);
1151
1152 }
1153 }
1154 }
1155
1156 /*
1157 Trigger a delayed redraw of a scene. The request is soming from the
1158 scene graph profiling subsystem.
1159 */
1160 void
redrawSensorCB(void * userdata,SoSensor * COIN_UNUSED_ARG (sensor))1161 SoGLRenderActionP::redrawSensorCB(void * userdata, SoSensor * COIN_UNUSED_ARG(sensor))
1162 {
1163 // FIXME: the node needs to be referenced to avoid touching a deleted node here.
1164 // or use a delete-callback at least to abort the sensor.
1165 assert(userdata);
1166 SoNode * node = static_cast<SoNode *>(userdata);
1167 node->touch();
1168 }
1169
1170 /*
1171 We need this hack because the SoAlarmSensor is not attached to
1172 the node (but has stored its pointer as userdata) and won't be
1173 disabled automatically when the node in question is deleted.
1174 */
1175 void
deleteNodeCB(void * userdata,SoSensor * COIN_UNUSED_ARG (sensor))1176 SoGLRenderActionP::deleteNodeCB(void * userdata, SoSensor * COIN_UNUSED_ARG(sensor))
1177 {
1178 assert(userdata);
1179 SoGLRenderActionP * thisp = static_cast<SoGLRenderActionP *>(userdata);
1180 if (thisp->redrawSensor.get() != NULL) {
1181 thisp->redrawSensor->unschedule();
1182 thisp->redrawSensor->setData(NULL);
1183 }
1184 }
1185
1186 /*!
1187 Used by shape nodes or others which need to know whether or not they
1188 should immediately render themselves or if they should wait until
1189 the next pass. It also enables/disabled blending based on the \a
1190 istransparent parameter.
1191
1192 If you're using an SoCallback or a non-shape node to render your
1193 geometry, you can use this function to make sure your node is only
1194 rendered once. This function consider the \a istransparent
1195 parameter, and when TRUE it will return TRUE on the first pass, and
1196 FALSE on the second pass. For non-transparent objects it returns
1197 FALSE on the first pass, TRUE on the second.
1198
1199 Please note that this function considers the current transparency
1200 type when deciding what to do. It will delay rendering only when the
1201 transparency type is DELAYED_* or SORTED_OBJECT_*. For other
1202 transparency types, transparent objects are rendered in the same
1203 pass as opaque objects.
1204 */
1205 SbBool
handleTransparency(SbBool istransparent)1206 SoGLRenderAction::handleTransparency(SbBool istransparent)
1207 {
1208 SoState * thestate = this->getState();
1209 const cc_glglue *glue = sogl_glue_instance(thestate);
1210
1211 SoGLRenderAction::TransparencyType transptype =
1212 static_cast<SoGLRenderAction::TransparencyType>(
1213 SoShapeStyleElement::getTransparencyType(thestate)
1214 );
1215
1216
1217 if (PRIVATE(this)->transparencytype == SORTED_LAYERS_BLEND) {
1218
1219 // Do not cache anything. We must have full control!
1220 SoCacheElement::invalidate(thestate);
1221
1222 PRIVATE(this)->sortedlayersblendprojectionmatrix =
1223 SoProjectionMatrixElement::get(thestate);
1224
1225 if (!SoMultiTextureEnabledElement::get(thestate, 0)) {
1226 if (glue->has_arb_fragment_program && !PRIVATE(this)->usenvidiaregistercombiners) {
1227 PRIVATE(this)->setupFragmentProgram();
1228 }
1229 else {
1230 PRIVATE(this)->setupRegisterCombinersNV();
1231 }
1232 }
1233
1234 // Must always return FALSE as everything must be rendered to the
1235 // RGBA layers (which are blended together at the end of each
1236 // frame).
1237 return FALSE;
1238 }
1239
1240
1241 // check common cases first
1242 if (!istransparent || transptype == SoGLRenderAction::NONE || transptype == SoGLRenderAction::SCREEN_DOOR) {
1243 if (PRIVATE(this)->smoothing) {
1244 SoLazyElement::enableBlending(thestate, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1245 }
1246 else SoLazyElement::disableBlending(thestate);
1247 return FALSE;
1248 }
1249
1250 // below this point, shape is transparent, and we know that
1251 // transparency type is not SCREEN_DOOR or NONE.
1252
1253 // for the transparency render pass(es) we should always render when
1254 // we get here.
1255 if (PRIVATE(this)->transparencyrender) {
1256 if (PRIVATE(this)->transpdelayedrendertype == NONSOLID_SEPARATE_BACKFACE_PASS) {
1257 if (this->isRenderingTranspBackfaces()) {
1258 if (SoShapeHintsElement::getShapeType(this->state) == SoShapeHintsElement::SOLID) {
1259 // just delay this until the next pass
1260 return TRUE;
1261 }
1262 else {
1263 SoLazyElement::setBackfaceCulling(this->state, TRUE);
1264 }
1265 }
1266 else {
1267 if (SoShapeHintsElement::getShapeType(this->state) != SoShapeHintsElement::SOLID) {
1268 SoLazyElement::setBackfaceCulling(this->state, TRUE);
1269 }
1270 }
1271 }
1272 PRIVATE(this)->setupBlending(thestate, transptype);
1273 return FALSE;
1274 }
1275 // check for special case when rendering delayed paths. we don't
1276 // want to add these objects to the list of transparent objects, but
1277 // render right away.
1278 if (PRIVATE(this)->delayedpathrender) {
1279 PRIVATE(this)->setupBlending(thestate, transptype);
1280 return FALSE;
1281 }
1282 switch (transptype) {
1283 case SoGLRenderAction::ADD:
1284 SoLazyElement::enableBlending(thestate, GL_SRC_ALPHA, GL_ONE);
1285 return FALSE;
1286 case SoGLRenderAction::BLEND:
1287 SoLazyElement::enableBlending(thestate, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1288 return FALSE;
1289 case SoGLRenderAction::DELAYED_ADD:
1290 case SoGLRenderAction::DELAYED_BLEND:
1291 PRIVATE(this)->addTransPath(this->getCurPath()->copy());
1292 SoCacheElement::setInvalid(TRUE);
1293 if (thestate->isCacheOpen()) {
1294 SoCacheElement::invalidate(thestate);
1295 }
1296 return TRUE; // delay render
1297 case SoGLRenderAction::SORTED_OBJECT_ADD:
1298 case SoGLRenderAction::SORTED_OBJECT_BLEND:
1299 case SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_ADD:
1300 case SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_BLEND:
1301 PRIVATE(this)->addSortTransPath(this->getCurPath()->copy());
1302 SoCacheElement::setInvalid(TRUE);
1303 if (thestate->isCacheOpen()) {
1304 SoCacheElement::invalidate(thestate);
1305 }
1306 return TRUE; // delay render
1307 default:
1308 assert(0 && "should not get here");
1309 break;
1310 }
1311 return FALSE;
1312 }
1313
1314 /*!
1315 Sets the current rendering pass to \a passnum. This can be used when
1316 antialiasing is controlled from outside the SoGLRenderAction
1317 instance. \a numpasses is the total number of rendering passes to
1318 be used.
1319
1320 Please note that this will disable any antialiasing set using the
1321 setNumPasses() method. You can reenable the internal antialiasing
1322 again by calling setNumPasses()
1323
1324 \since Coin 3.1
1325 */
1326 void
setCurPass(const int passnum,const int numpasses)1327 SoGLRenderAction::setCurPass(const int passnum, const int numpasses)
1328 {
1329 PRIVATE(this)->currentpass = passnum;
1330 PRIVATE(this)->numpasses = numpasses;
1331 PRIVATE(this)->internal_multipass = FALSE;
1332 }
1333
1334 /*!
1335 Returns the number of the current rendering pass.
1336 */
1337
1338 int
getCurPass(void) const1339 SoGLRenderAction::getCurPass(void) const
1340 {
1341 return PRIVATE(this)->currentpass;
1342 }
1343
1344 /*!
1345 Returns \c TRUE if the render action should abort now based on user
1346 callback.
1347
1348 \sa setAbortCallback()
1349 */
1350 SbBool
abortNow(void)1351 SoGLRenderAction::abortNow(void)
1352 {
1353 if (this->hasTerminated()) return TRUE;
1354
1355 #if COIN_DEBUG && 0 // for dumping the scene graph during GLRender traversals
1356 static int debug = -1;
1357 if (debug == -1) {
1358 const char * env = coin_getenv("COIN_DEBUG_GLRENDER_TRAVERSAL");
1359 debug = env && (atoi(env) > 0);
1360 }
1361 if (debug) {
1362 const SoFullPath * p = (const SoFullPath *)this->getCurPath();
1363 assert(p);
1364 const int len = p->getLength();
1365 for (int i=1; i < len; i++) { printf(" "); }
1366 const SoNode * n = p->getTail();
1367 assert(n);
1368 printf("%p %s (\"%s\")\n",
1369 n, n->getTypeId().getName().getString(),
1370 n->getName().getString());
1371 }
1372 #endif // debug
1373
1374 SbBool abort = FALSE;
1375 if (PRIVATE(this)->abortcallback) {
1376 switch (PRIVATE(this)->abortcallback(PRIVATE(this)->abortcallbackdata)) {
1377 case CONTINUE:
1378 break;
1379 case ABORT:
1380 this->setTerminated(TRUE);
1381 abort = TRUE;
1382 break;
1383 case PRUNE:
1384 // abort this node, but do not abort rendering
1385 abort = TRUE;
1386 break;
1387 case DELAY:
1388 this->addDelayedPath(this->getCurPath()->copy());
1389 // prune this node
1390 abort = TRUE;
1391 break;
1392 }
1393 }
1394 return abort;
1395 }
1396
1397 /*!
1398 Let SoGLRenderAction instance know if application is running on the
1399 local machine or if the rendering instructions are sent over the
1400 network.
1401
1402 The flag is used to optimize rendering. For instance should the
1403 displaylist caching strategy be influenced by this flag to be more
1404 aggressive with the caching when rendering instructions are passed
1405 over the network.
1406
1407 Default value is \c FALSE. The value of the flag will not be changed
1408 internally from the Coin library code, as it is meant to be
1409 controlled from client code -- typically from the SoQt / SoXt /
1410 SoWin / SoGtk libraries.
1411
1412 \sa getRenderingIsRemote()
1413 */
1414 void
setRenderingIsRemote(SbBool isremote)1415 SoGLRenderAction::setRenderingIsRemote(SbBool isremote)
1416 {
1417 PRIVATE(this)->rendering = isremote ?
1418 SoGLRenderActionP::RENDERING_SET_INDIRECT :
1419 SoGLRenderActionP::RENDERING_SET_DIRECT;
1420 }
1421
1422 /*!
1423 Returns whether or not the application is running remotely.
1424
1425 \sa setRenderingIsRemote()
1426 */
1427 SbBool
getRenderingIsRemote(void) const1428 SoGLRenderAction::getRenderingIsRemote(void) const
1429 {
1430 SbBool isdirect;
1431 if (PRIVATE(this)->rendering == SoGLRenderActionP::RENDERING_UNSET) {
1432 isdirect = TRUE;
1433 }
1434 else {
1435 isdirect = PRIVATE(this)->rendering == SoGLRenderActionP::RENDERING_SET_DIRECT;
1436 }
1437 return !isdirect;
1438 }
1439
1440 /*!
1441 Adds a path to the list of paths to render after the current pass.
1442 */
1443 void
addDelayedPath(SoPath * path)1444 SoGLRenderAction::addDelayedPath(SoPath * path)
1445 {
1446 SoState * thestate = this->getState();
1447 SoCacheElement::invalidate(thestate);
1448 assert(!PRIVATE(this)->delayedpathrender);
1449 PRIVATE(this)->delayedpaths.append(path);
1450 }
1451
1452 /*!
1453 Returns a flag indicating whether or not we are currently rendering
1454 from the list of delayed paths of the scene graph.
1455 */
1456 SbBool
isRenderingDelayedPaths(void) const1457 SoGLRenderAction::isRenderingDelayedPaths(void) const
1458 {
1459 return PRIVATE(this)->delayedpathrender;
1460 }
1461
1462 // Remember a path containing a transparent object for later
1463 // rendering. We know path == this->getCurPath() when we get here.
1464 // This method is only used to add paths that are to be rendered after
1465 // all transparent paths that need sorting have been rendered, so no
1466 // need to calculate distances. Just add to list.
1467 void
addTransPath(SoPath * path)1468 SoGLRenderActionP::addTransPath(SoPath * path)
1469 {
1470 this->transpobjpaths.append(path);
1471 }
1472
1473 // Documented in superclass. Overridden to reinitialize GL state on
1474 // next apply.
1475 void
invalidateState(void)1476 SoGLRenderAction::invalidateState(void)
1477 {
1478 inherited::invalidateState();
1479 PRIVATE(this)->needglinit = TRUE;
1480 }
1481
1482 // Sort paths with transparent objects before rendering.
1483 void
doPathSort(void)1484 SoGLRenderActionP::doPathSort(void)
1485 {
1486 // need to cast to SbPList to avoid ref/unref problems, since
1487 // operator[] is overloaded with non-virtual inheritance.
1488 SbPList * plist = &this->sorttranspobjpaths;
1489 float * darray = const_cast<float *>(this->sorttranspobjdistances.getArrayPtr());
1490
1491 int i, j, distance, n = this->sorttranspobjdistances.getLength();
1492 void * ptmp;
1493 float dtmp;
1494
1495 // shell sort algorithm (O(nlog(n))
1496 for (distance = 1; distance <= n/9; distance = 3*distance + 1) ;
1497 for (; distance > 0; distance /= 3) {
1498 for (i = distance; i < n; i++) {
1499 dtmp = darray[i];
1500 ptmp = plist->get(i);
1501 j = i;
1502 while (j >= distance && darray[j-distance] < dtmp) {
1503 darray[j] = darray[j-distance];
1504 plist->set(j, plist->get(j-distance));
1505 j -= distance;
1506 }
1507 darray[j] = dtmp;
1508 plist->set(j, ptmp);
1509 }
1510 }
1511 }
1512
1513 /*!
1514 Adds a callback which is invoked right before the scene graph traversal
1515 starts. All necessary GL initialization is then done (e.g. the viewport
1516 is correctly set), and this callback can be useful to, for instance,
1517 clear the viewport before rendering, or draw a bitmap in the background
1518 before rendering etc.
1519
1520 The callback is only invoked once (before the first rendering pass)
1521 when multi pass rendering is enabled.
1522
1523 Please note that SoSceneManager usually adds a callback to clear the
1524 GL buffers in SoSceneManager::render(). So, if you plan to for
1525 instance draw an image in the color buffer using this callback, you
1526 should make sure that the scene manager doesn't clear the buffer.
1527 This can be done either by calling SoSceneManager::render() with
1528 both arguments FALSE, or, if you're using one of our GUI toolkits
1529 (SoXt/SoQt/SoGtk/SoWin), call setClearBeforeRender() on the viewer.
1530
1531 This method is an extension versus the Open Inventor API.
1532
1533 \sa removePreRenderCallback().
1534 */
1535 void
addPreRenderCallback(SoGLPreRenderCB * func,void * userdata)1536 SoGLRenderAction::addPreRenderCallback(SoGLPreRenderCB * func, void * userdata)
1537 {
1538 PRIVATE(this)->precblist.addCallback(reinterpret_cast<SoCallbackListCB *>(func), userdata);
1539 }
1540
1541 /*!
1542 Removed a callback added with the addPreRenderCallback() method.
1543
1544 This method is an extension versus the Open Inventor API.
1545
1546 \sa addPreRenderCallback()
1547 */
1548 void
removePreRenderCallback(SoGLPreRenderCB * func,void * userdata)1549 SoGLRenderAction::removePreRenderCallback(SoGLPreRenderCB * func, void * userdata)
1550 {
1551 PRIVATE(this)->precblist.removeCallback(reinterpret_cast<SoCallbackListCB *>(func), userdata);
1552 }
1553
1554 /*!
1555
1556 Sets the strategy used for sorting transparent objects.
1557
1558 The \e CUSTOM_CALLBACK strategy enables the user to supply a
1559 callback which is called for each transparent shape. This strategy
1560 can be used if the built in sorting strategies aren't sufficient.
1561
1562 The callback should return a floating point value to be used when
1563 sorting the objects in Coin. This floating point value is
1564 interpreted as a distance to the camera, and objects with higher
1565 values will be sorted behind objects with lower values.
1566
1567 The callback will supply the SoGLRenderAction instance, and the path
1568 to the current object can be found using SoAction::getCurPath().
1569
1570 \since Coin 2.5
1571
1572 */
1573 void
setSortedObjectOrderStrategy(const SortedObjectOrderStrategy strategy,SoGLSortedObjectOrderCB * cb,void * closure)1574 SoGLRenderAction::setSortedObjectOrderStrategy(const SortedObjectOrderStrategy strategy,
1575 SoGLSortedObjectOrderCB * cb,
1576 void * closure)
1577 {
1578 PRIVATE(this)->sortedobjectstrategy = strategy;
1579 PRIVATE(this)->sortedobjectcb = cb;
1580 PRIVATE(this)->sortedobjectclosure = closure;
1581 }
1582
1583 // *************************************************************************
1584 // methods in SoGLRenderActionP
1585
1586 // Private function to save transparent paths that need to be sorted.
1587 // The transparent paths that don't need to be sorted are rendered
1588 // after the sorted ones.
1589 void
addSortTransPath(SoPath * path)1590 SoGLRenderActionP::addSortTransPath(SoPath * path)
1591 {
1592 this->sorttranspobjpaths.append(path);
1593
1594 // check and handle callback first
1595 if ((this->sortedobjectstrategy == SoGLRenderAction::CUSTOM_CALLBACK) &&
1596 (this->sortedobjectcb != NULL)) {
1597 this->sorttranspobjdistances.append(this->sortedobjectcb(this->sortedobjectclosure,
1598 this->action));
1599 return;
1600 }
1601
1602 SoState * state = action->getState();
1603 SoNode * tail = reclassify_cast<SoFullPath *>(path)->getTail();
1604 float dist;
1605 SbBox3f bbox;
1606 // test if we can find the bbox using SoShape::getBoundingBoxCache()
1607 // or SoShape::computeBBox. This is the common case, and quite a lot
1608 // faster than using an SoGetBoundingBoxAction.
1609 if (tail->isOfType(SoShape::getClassTypeId())) { // common case
1610 SoShape * tailshape = coin_assert_cast<SoShape *>(tail);
1611 const SoBoundingBoxCache * bboxcache = tailshape->getBoundingBoxCache();
1612 SbVec3f center;
1613
1614 if (bboxcache && bboxcache->isValid(state)) {
1615 bbox = bboxcache->getProjectedBox();
1616 if (bboxcache->isCenterSet()) center = bboxcache->getCenter();
1617 else center = bbox.getCenter();
1618 }
1619 else {
1620 tailshape->computeBBox(action, bbox, center);
1621 }
1622 SoModelMatrixElement::get(state).multVecMatrix(center, center);
1623 dist = -SoViewVolumeElement::get(state).getPlane(0.0f).getDistance(center);
1624 }
1625 else {
1626 this->bboxaction->setViewportRegion(SoViewportRegionElement::get(state));
1627 this->bboxaction->apply(path);
1628 SbVec3f center = this->bboxaction->getBoundingBox().getCenter();
1629 bbox = this->bboxaction->getBoundingBox();
1630 bbox.transform(SoModelMatrixElement::get(state).inverse());
1631 dist = -SoViewVolumeElement::get(state).getPlane(0.0f).getDistance(center);
1632 }
1633 if ((this->sortedobjectstrategy == SoGLRenderAction::BBOX_CLOSEST_CORNER) ||
1634 (this->sortedobjectstrategy == SoGLRenderAction::BBOX_FARTHEST_CORNER)) {
1635 const SbMatrix & m = SoModelMatrixElement::get(state);
1636 const SbPlane & plane = SoViewVolumeElement::get(state).getPlane(0.0f);
1637 SbVec3f bmin, bmax;
1638 bmin = bbox.getMin();
1639 bmax = bbox.getMax();
1640
1641 for (int i = 0; i < 8; i++) {
1642 SbVec3f tmp(i&1 ? bmin[0] : bmax[0],
1643 i&2 ? bmin[1] : bmax[1],
1644 i&4 ? bmin[2] : bmax[2]);
1645 m.multVecMatrix(tmp, tmp);
1646 float tmpdist = -plane.getDistance(tmp);
1647 if (i == 0) dist = tmpdist;
1648 else {
1649 switch (this->sortedobjectstrategy) {
1650 case SoGLRenderAction::BBOX_CLOSEST_CORNER:
1651 if (tmpdist < dist) dist = tmpdist;
1652 break;
1653 case SoGLRenderAction::BBOX_FARTHEST_CORNER:
1654 if (tmpdist > dist) dist = tmpdist;
1655 break;
1656 default:
1657 assert(0 && "unknown sorting strategy");
1658 break;
1659 }
1660 }
1661 }
1662 }
1663 this->sorttranspobjdistances.append(dist);
1664 }
1665
1666 // Private function which "unwinds" the real value of the "rendering"
1667 // variable.
1668 SbBool
isDirectRendering(const SoState * state) const1669 SoGLRenderActionP::isDirectRendering(const SoState * state) const
1670 {
1671 SbBool isdirect;
1672 if (this->rendering == RENDERING_UNSET) {
1673 const cc_glglue * w = sogl_glue_instance(state);
1674 isdirect = cc_glglue_isdirect(w);
1675 }
1676 else {
1677 isdirect = this->rendering == RENDERING_SET_DIRECT;
1678 }
1679
1680 // Update to keep in sync.
1681 this->action->setRenderingIsRemote(!isdirect);
1682
1683 return isdirect;
1684 }
1685
1686
1687 //
1688 // render the scene. Called from beginTraversal()
1689 //
1690 void
render(SoNode * node)1691 SoGLRenderActionP::render(SoNode * node)
1692 {
1693 this->isrendering = TRUE;
1694
1695 SoState * state = this->action->getState();
1696 state->push();
1697
1698 SoShapeStyleElement::setTransparencyType(state,
1699 this->transparencytype);
1700
1701 SoLazyElement::disableBlending(state);
1702
1703 SoViewportRegionElement::set(state, this->viewport);
1704 SoDepthBufferElement::set(state, TRUE, TRUE,
1705 SoDepthBufferElement::LEQUAL,
1706 SbVec2f(0.0f, 1.0f));
1707 SoLazyElement::setTransparencyType(state,
1708 static_cast<int32_t>(this->transparencytype));
1709
1710 if (this->transparencytype == SoGLRenderAction::SORTED_LAYERS_BLEND) {
1711 SoOverrideElement::setTransparencyTypeOverride(state, node, TRUE);
1712 }
1713
1714 SoLazyElement::setColorMaterial(state, TRUE);
1715
1716 SoGLUpdateAreaElement::set(state,
1717 this->updateorigin, this->updatesize);
1718
1719 SoGLCacheContextElement::set(state, this->cachecontext,
1720 FALSE, !this->isDirectRendering(state));
1721 SoGLRenderPassElement::set(state, 0);
1722
1723 this->precblist.invokeCallbacks(static_cast<void *>(this->action));
1724
1725 if (this->action->getNumPasses() > 1 && this->internal_multipass) {
1726 // Check if the current OpenGL context has an accumulation buffer
1727 // (rendering multiple passes doesn't make much sense otherwise).
1728 GLint accumbits;
1729 glGetIntegerv(GL_ACCUM_RED_BITS, &accumbits);
1730
1731 if (accumbits == 0) {
1732 static SbBool first = TRUE;
1733 if (first) {
1734 SoDebugError::postWarning("SoGLRenderActionP::render",
1735 "Multipass rendering requested,\nbut current "
1736 "GL context has no accumulation buffer - "
1737 "falling back to single pass\nrendering.");
1738 first = FALSE;
1739 }
1740 this->renderSingle(node);
1741 } else {
1742 this->renderMulti(node);
1743 }
1744 } else {
1745 this->renderSingle(node);
1746 }
1747
1748 if (SoProfiler::isOverlayActive()) {
1749 if (node == this->cachedprofilingsg) {
1750 SoNode * profileroverlay = SoActionP::getProfilerOverlay();
1751 if (profileroverlay) {
1752 this->isrenderingoverlay = TRUE;
1753 SoProfiler::enable(FALSE);
1754 this->renderSingle(profileroverlay);
1755 SoProfiler::enable(TRUE);
1756 this->isrenderingoverlay = FALSE;
1757 }
1758 } else {
1759 static SbBool first = TRUE;
1760 if (first) {
1761 SoDebugError::postWarning("SoGLRenderAcionP::render",
1762 "Profiling overlay is only enabled for the first "
1763 "scene graph in the viewer.");
1764 first = FALSE;
1765 }
1766 }
1767 }
1768
1769 state->pop();
1770 this->isrendering = FALSE;
1771 }
1772
1773 //
1774 // render multiple passes (antialiasing)
1775 //
1776 void
renderMulti(SoNode * node)1777 SoGLRenderActionP::renderMulti(SoNode * node)
1778 {
1779 assert(this->numpasses > 1);
1780 float fraction = 1.0f / float(this->numpasses);
1781
1782 int storedpass = this->currentpass;
1783
1784 this->currentpass = 0;
1785 this->renderSingle(node);
1786 if (this->action->hasTerminated()) return;
1787 glAccum(GL_LOAD, fraction);
1788
1789 for (int i = 1; i < this->numpasses; i++) {
1790 if (this->passupdate) {
1791 glAccum(GL_RETURN, float(this->numpasses) / float(i));
1792 }
1793 if (this->passcallback) this->passcallback(this->passcallbackdata);
1794 else glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1795 this->currentpass = i;
1796 this->renderSingle(node);
1797
1798 if (this->action->hasTerminated()) {
1799 this->currentpass = storedpass;
1800 return;
1801 }
1802 glAccum(GL_ACCUM, fraction);
1803 }
1804 this->currentpass = storedpass;
1805 glAccum(GL_RETURN, 1.0f);
1806 }
1807
1808 //
1809 // render a single pass. Might start a transparency or delayed pass
1810 // though.
1811 //
1812 void
renderSingle(SoNode * node)1813 SoGLRenderActionP::renderSingle(SoNode * node)
1814 {
1815 SoState * state = this->action->getState();
1816
1817 SoGLRenderPassElement::set(state, this->currentpass);
1818 SoGLCacheContextElement::set(state, this->cachecontext,
1819 FALSE, !this->isDirectRendering(state));
1820
1821 assert(this->delayedpathrender == FALSE);
1822 assert(this->transparencyrender == FALSE);
1823
1824 // Truncate just in case
1825 this->sorttranspobjpaths.truncate(0);
1826 this->transpobjpaths.truncate(0);
1827 this->sorttranspobjdistances.truncate(0);
1828 this->delayedpaths.truncate(0);
1829
1830 // Do order independent transparency rendering
1831 if (this->transparencytype == SoGLRenderAction::SORTED_LAYERS_BLEND) {
1832 GLint depthbits, alphabits;
1833 glGetIntegerv(GL_DEPTH_BITS, &depthbits);
1834 glGetIntegerv(GL_ALPHA_BITS, &alphabits);
1835
1836 const cc_glglue * w = sogl_glue_instance(state);
1837 // FIXME: What should we do when >8bits per channel becomes normal? (20031125 handegar)
1838 if (SoGLDriverDatabase::isSupported(w, SO_GL_SORTED_LAYERS_BLEND) && (depthbits >= 24) && (alphabits == 8)) {
1839 doSortedLayersBlendRendering(state, node);
1840 }
1841 else {
1842
1843 if (!SoGLDriverDatabase::isSupported(w, SO_GL_SORTED_LAYERS_BLEND))
1844 SoDebugError::postWarning("renderSingle", "Sorted layers blend cannot be enabled "
1845 "due to missing OpenGL extensions. Rendering using "
1846 "SORTED_OBJECTS_BLEND instead.");
1847 else
1848 SoDebugError::postWarning("renderSingle", "Sorted layers blend cannot be enabled if "
1849 "ALPHA size != 8 (currently %d) or DEPTH size < 24 "
1850 "(currently %d). Rendering using SORTED_OBJECTS_BLEND instead.",
1851 alphabits, depthbits);
1852
1853 // Do regular SORTED_OBJECT_BLEND if sorted layers blend is unsupported
1854 this->transparencytype = SoGLRenderAction::SORTED_OBJECT_BLEND;
1855 render(node); // Render again using the fallback transparency type.
1856 }
1857
1858 return;
1859 }
1860
1861 this->action->beginTraversal(node);
1862
1863 if ((this->transpobjpaths.getLength() || this->sorttranspobjpaths.getLength()) &&
1864 !this->action->hasTerminated()) {
1865
1866 this->transparencyrender = TRUE;
1867 // disable writing into the z-buffer when rendering transparent
1868 // objects
1869
1870 if (!this->transpobjdepthwrite) {
1871 SoDepthBufferElement::set(state, TRUE, FALSE,
1872 SoDepthBufferElement::LEQUAL,
1873 SbVec2f(0.0f, 1.0f));
1874 }
1875 SoGLCacheContextElement::set(state, this->cachecontext,
1876 TRUE, !this->isDirectRendering(state));
1877
1878 int numtransppasses = 1;
1879 switch (this->transpdelayedrendertype) {
1880 default:
1881 break;
1882 case SoGLRenderAction::NONSOLID_SEPARATE_BACKFACE_PASS:
1883 numtransppasses = 2;
1884 break;
1885 }
1886
1887 // All paths in the sorttranspobjpaths should be sorted
1888 // back-to-front and rendered
1889 this->doPathSort();
1890 int i;
1891 for (i = 0; i < this->sorttranspobjpaths.getLength(); i++) {
1892 for (int pass = 0; pass < numtransppasses; pass++) {
1893 if (numtransppasses == 2) {
1894 switch (pass) {
1895 case 0:
1896 glCullFace(GL_FRONT);
1897 this->renderingtranspbackfaces = TRUE;
1898 break;
1899 case 1:
1900 glCullFace(GL_BACK);
1901 this->renderingtranspbackfaces = FALSE;
1902 break;
1903 }
1904 }
1905 this->action->apply(this->sorttranspobjpaths[i]);
1906 }
1907 }
1908
1909 for (int pass = 0; pass < numtransppasses; pass++) {
1910 if (numtransppasses == 2) {
1911 switch (pass) {
1912 case 0:
1913 glCullFace(GL_FRONT);
1914 this->renderingtranspbackfaces = TRUE;
1915 break;
1916 case 1:
1917 glCullFace(GL_BACK);
1918 this->renderingtranspbackfaces = FALSE;
1919 break;
1920 }
1921 }
1922 // Render all transparent paths that should not be sorted
1923 this->action->apply(this->transpobjpaths, TRUE);
1924 }
1925 // enable writing again. FIXME: consider if it's ok to push/pop state instead
1926 if (!this->transpobjdepthwrite) {
1927 SoDepthBufferElement::set(state, TRUE, TRUE,
1928 SoDepthBufferElement::LEQUAL,
1929 SbVec2f(0.0f, 1.0f));
1930 }
1931 this->transparencyrender = FALSE;
1932 }
1933
1934 if (this->delayedpaths.getLength() && !this->action->hasTerminated()) {
1935 this->delayedpathrender = TRUE;
1936 this->action->apply(this->delayedpaths, TRUE);
1937 this->delayedpathrender = FALSE;
1938 }
1939
1940 // truncate lists to unref paths.
1941 this->sorttranspobjpaths.truncate(0);
1942 this->transpobjpaths.truncate(0);
1943 this->sorttranspobjdistances.truncate(0);
1944 this->delayedpaths.truncate(0);
1945
1946 }
1947
1948 void
setupBlending(SoState * state,const SoGLRenderAction::TransparencyType transptype)1949 SoGLRenderActionP::setupBlending(SoState * state, const SoGLRenderAction::TransparencyType transptype)
1950 {
1951
1952 switch (transptype) {
1953 case SoGLRenderAction::BLEND:
1954 case SoGLRenderAction::DELAYED_BLEND:
1955 case SoGLRenderAction::SORTED_OBJECT_BLEND:
1956 case SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_BLEND:
1957 SoLazyElement::enableBlending(state, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1958 break;
1959 case SoGLRenderAction::ADD:
1960 case SoGLRenderAction::DELAYED_ADD:
1961 case SoGLRenderAction::SORTED_OBJECT_ADD:
1962 case SoGLRenderAction::SORTED_OBJECT_SORTED_TRIANGLE_ADD:
1963 SoLazyElement::enableBlending(state, GL_SRC_ALPHA, GL_ONE);
1964 break;
1965 default:
1966 assert(0 && "should not get here");
1967 break;
1968 }
1969 }
1970
1971 /*!
1972 Set whether depth buffer updates should be done when rendering
1973 delayed or sorted transparent objects.
1974
1975 \since Coin 3.0
1976 */
1977 void
setDelayedObjDepthWrite(SbBool write)1978 SoGLRenderAction::setDelayedObjDepthWrite(SbBool write)
1979 {
1980 PRIVATE(this)->transpobjdepthwrite = write;
1981 }
1982
1983 /*!
1984 Return whether depth buffer updates should be done when rendering
1985 delayed or sorted transparent objects. Default is FALSE.
1986
1987 \since Coin 3.0
1988 */
1989 SbBool
getDelayedObjDepthWrite(void) const1990 SoGLRenderAction::getDelayedObjDepthWrite(void) const
1991 {
1992 return PRIVATE(this)->transpobjdepthwrite;
1993 }
1994
1995 /*!
1996
1997 Returns TRUE if the action is currently rendering delayed or sorted
1998 transparent objects.
1999
2000 \since Coin 3.0
2001 */
2002 SbBool
isRenderingTranspPaths(void) const2003 SoGLRenderAction::isRenderingTranspPaths(void) const
2004 {
2005 return PRIVATE(this)->transparencyrender;
2006 }
2007
2008 /*!
2009 Returns TRUE if the action is currently rendering backfacing polygons
2010 in NONSOLID_SEPARATE_BACKFACE_PASS mode.
2011
2012 \since Coin 3.0
2013 */
2014 SbBool
isRenderingTranspBackfaces(void) const2015 SoGLRenderAction::isRenderingTranspBackfaces(void) const
2016 {
2017 return PRIVATE(this)->renderingtranspbackfaces;
2018 }
2019
2020 /*!
2021 Sets the render type of delayed or sorted transparent objects. Default is ONE_PASS.
2022
2023 \since Coin 3.0
2024 */
2025 void
setTransparentDelayedObjectRenderType(TransparentDelayedObjectRenderType type)2026 SoGLRenderAction::setTransparentDelayedObjectRenderType(TransparentDelayedObjectRenderType type)
2027 {
2028 PRIVATE(this)->transpdelayedrendertype = type;
2029 }
2030
2031 /*!
2032 Returns the render type of delayed or sorted transparent objects.
2033
2034 \since Coin 3.0
2035 */
2036 SoGLRenderAction::TransparentDelayedObjectRenderType
getTransparentDelayedObjectRenderType(void) const2037 SoGLRenderAction::getTransparentDelayedObjectRenderType(void) const
2038 {
2039 return PRIVATE(this)->transpdelayedrendertype;
2040 }
2041
2042 void
doSortedLayersBlendRendering(const SoState * state,SoNode * node)2043 SoGLRenderActionP::doSortedLayersBlendRendering(const SoState * state, SoNode * node)
2044 {
2045
2046 const cc_glglue *glue = sogl_glue_instance(state);
2047 this->initSortedLayersBlendRendering(state);
2048 this->setupSortedLayersBlendTextures(state);
2049 this->sortedlayersblendinitialized = TRUE;
2050
2051 glDisable(GL_BLEND);
2052
2053 // The 'sortedlayersblendcounter' must be global so that it can be
2054 // reached by 'setupNVRegisterCombiners()' at all times during the
2055 // scenegraph traversals.
2056 for(this->sortedlayersblendcounter=0;
2057 this->sortedlayersblendcounter < this->sortedlayersblendpasses;
2058 this->sortedlayersblendcounter++) {
2059
2060 // FIXME: A trick here would be to do an occlusion test if
2061 // possible (EXT_occlusion_test is more or less free). The choosen
2062 // number of passes would then be treated as the the upper number
2063 // of passes. (20031208 handegar)
2064 renderOneBlendLayer(state, this->sortedlayersblendcounter > 0,
2065 this->sortedlayersblendcounter < (this->sortedlayersblendpasses-1),
2066 node);
2067
2068 }
2069
2070 // Blend together the aquired RGBA layers
2071 if (glue->has_arb_fragment_program && !this->usenvidiaregistercombiners)
2072 renderSortedLayersFP(state);
2073 else
2074 renderSortedLayersNV(state);
2075
2076 }
2077
2078 void
texgenEnable(SbBool enable)2079 SoGLRenderActionP::texgenEnable(SbBool enable)
2080 {
2081 if (enable) {
2082 glEnable(GL_TEXTURE_GEN_S);
2083 glEnable(GL_TEXTURE_GEN_T);
2084 glEnable(GL_TEXTURE_GEN_R);
2085 glEnable(GL_TEXTURE_GEN_Q);
2086 }
2087 else {
2088 glDisable(GL_TEXTURE_GEN_S);
2089 glDisable(GL_TEXTURE_GEN_T);
2090 glDisable(GL_TEXTURE_GEN_R);
2091 glDisable(GL_TEXTURE_GEN_Q);
2092 }
2093 }
2094
2095
2096 void
eyeLinearTexgen()2097 SoGLRenderActionP::eyeLinearTexgen()
2098 {
2099
2100 const float col1[] = { 1, 0, 0, 0 };
2101 const float col2[] = { 0, 1, 0, 0 };
2102 const float col3[] = { 0, 0, 1, 0 };
2103 const float col4[] = { 0, 0, 0, 1 };
2104
2105 glTexGenfv(GL_S,GL_EYE_PLANE, col1);
2106 glTexGenfv(GL_T,GL_EYE_PLANE, col2);
2107 glTexGenfv(GL_R,GL_EYE_PLANE, col3);
2108 glTexGenfv(GL_Q,GL_EYE_PLANE, col4);
2109
2110 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
2111 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
2112 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
2113 glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
2114
2115 }
2116
2117 void
renderOneBlendLayer(const SoState * state,SbBool peel,SbBool updatedepthtexture,SoNode * node)2118 SoGLRenderActionP::renderOneBlendLayer(const SoState * state,
2119 SbBool peel, SbBool updatedepthtexture, SoNode * node)
2120 {
2121
2122 const cc_glglue * glue = sogl_glue_instance(state);
2123
2124 // Setup clearcolor alpha value to 1.0f when blending using NVIDIA
2125 // extensions. Must do this every time to make sure the alpha-value
2126 // stays correct.
2127 GLfloat clearcolor[4];
2128 glGetFloatv(GL_COLOR_CLEAR_VALUE, clearcolor);
2129 if (glue->has_arb_fragment_program && !this->usenvidiaregistercombiners)
2130 glClearColor(clearcolor[0], clearcolor[1], clearcolor[2], 0.0f);
2131 else
2132 glClearColor(clearcolor[0], clearcolor[1], clearcolor[2], 1.0f);
2133 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2134
2135
2136 // Clear all errors before traversal, just in case.
2137 GLenum glerror = sogl_glerror_debugging() ? glGetError() : GL_NO_ERROR;
2138 while (glerror) {
2139 SoDebugError::postWarning("renderOneBlendLayer",
2140 "glError() = %d\n", glerror);
2141 glerror = glGetError();
2142 }
2143
2144 // Do the rendering
2145 this->action->beginTraversal(node);
2146
2147 if(peel) {
2148 if (glue->has_arb_fragment_program && !this->usenvidiaregistercombiners) {
2149 // Fragment program clean-up
2150 glDisable(GL_FRAGMENT_PROGRAM_ARB);
2151 glDisable(GL_TEXTURE_RECTANGLE_EXT);
2152 glDisable(GL_ALPHA_TEST);
2153
2154 cc_glglue_glActiveTexture(glue, GL_TEXTURE3);
2155 glDisable(GL_TEXTURE_RECTANGLE_EXT);
2156 this->texgenEnable(FALSE);
2157
2158 glMatrixMode(GL_TEXTURE);
2159 glLoadIdentity();
2160 glMatrixMode(GL_MODELVIEW);
2161 cc_glglue_glActiveTexture(glue, GL_TEXTURE0);
2162 glDisable(GL_TEXTURE_RECTANGLE_EXT);
2163 glDisable(GL_ALPHA_TEST);
2164
2165 }
2166 else {
2167 // Regular NViDIA register combiner clean-up
2168 cc_glglue_glActiveTexture(glue, GL_TEXTURE3);
2169 glDisable(GL_TEXTURE_RECTANGLE_EXT);
2170 this->texgenEnable(FALSE);
2171
2172 glMatrixMode(GL_TEXTURE);
2173 glLoadIdentity();
2174 glMatrixMode(GL_MODELVIEW);
2175 cc_glglue_glActiveTexture(glue, GL_TEXTURE0);
2176 glDisable(GL_REGISTER_COMBINERS_NV);
2177 glDisable(GL_ALPHA_TEST);
2178
2179 }
2180 }
2181
2182 if (!glue->has_arb_fragment_program || this->usenvidiaregistercombiners)
2183 glDisable(GL_TEXTURE_SHADER_NV);
2184
2185 // FIXME: It might be a smart thing to use PBuffers for the RGBA
2186 // layers instead of copying from the framebuffer. The copying seems
2187 // to be a performance hit for large canvases. (20031127 handegar)
2188
2189 // copy the RGBA of the layer to a texture
2190 glEnable(GL_TEXTURE_RECTANGLE_EXT);
2191 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, this->rgbatextureids[this->sortedlayersblendcounter]);
2192 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, 0, 0,
2193 this->viewportwidth, this->viewportheight);
2194
2195 if (updatedepthtexture) {
2196 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, this->depthtextureid);
2197 glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, 0, 0,
2198 this->viewportwidth, this->viewportheight);
2199 }
2200
2201 }
2202
2203 void
initSortedLayersBlendRendering(const SoState * state)2204 SoGLRenderActionP::initSortedLayersBlendRendering(const SoState * state)
2205 {
2206
2207 if (this->sortedlayersblendinitialized) // Do this only once
2208 return;
2209
2210 // Supporting both the TGS envvar and the COIN envvar. If both are
2211 // present, the COIN envvar will be used.
2212 const char * envtgs = coin_getenv("OIV_NUM_SORTED_LAYERS_PASSES");
2213 if (envtgs && (atoi(envtgs) > 0))
2214 this->sortedlayersblendpasses = atoi(envtgs);
2215
2216 const char * envcoin = coin_getenv("COIN_NUM_SORTED_LAYERS_PASSES");
2217 if (envcoin && (atoi(envcoin) > 0))
2218 this->sortedlayersblendpasses = atoi(envcoin);
2219
2220 const char * envusenvidiarc = coin_getenv("COIN_SORTED_LAYERS_USE_NVIDIA_RC");
2221 if (envusenvidiarc && (atoi(envusenvidiarc) > 0))
2222 this->usenvidiaregistercombiners = TRUE;
2223
2224 this->rgbatextureids.reset(new GLuint[this->sortedlayersblendpasses]);
2225
2226 const cc_glglue * glue = sogl_glue_instance(state);
2227 if (glue->has_arb_fragment_program && !this->usenvidiaregistercombiners) {
2228
2229 // Initialize fragment program
2230 //
2231 // FIXME: the program id must be bound to the current rendering
2232 // context, and deallocated when it is destructed. 20040718 mortene.
2233 glue->glGenProgramsARB(1, &this->sortedlayersblendprogramid);
2234 glue->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, this->sortedlayersblendprogramid);
2235 glue->glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
2236 static_cast<GLsizei>(strlen(sortedlayersblendprogram)),
2237 sortedlayersblendprogram);
2238
2239 // FIXME: Maybe a wrapper for catching fragment program errors
2240 // should be a part of GLUE... (20031204 handegar)
2241 GLint errorPos;
2242 GLenum err = sogl_glerror_debugging() ? glGetError() : GL_NO_ERROR;
2243 if (err) {
2244 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
2245 SoDebugError::postWarning("initSortedLayersBlendRendering",
2246 "Error in fragment program! (byte pos: %d) '%s'.\n",
2247 errorPos, glGetString(GL_PROGRAM_ERROR_STRING_ARB));
2248
2249 }
2250
2251 glDisable(GL_FRAGMENT_PROGRAM_ARB);
2252
2253 }
2254
2255 }
2256
2257 void
setupFragmentProgram()2258 SoGLRenderActionP::setupFragmentProgram()
2259 {
2260
2261 if (this->sortedlayersblendcounter == 0) // Is this not the first pass?
2262 return;
2263 const cc_glglue * glue = sogl_glue_instance(this->action->getState());
2264
2265
2266 glEnable(GL_FRAGMENT_PROGRAM_ARB);
2267 glue->glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, this->sortedlayersblendprogramid);
2268
2269 // UNIT #3
2270 glMatrixMode(GL_MODELVIEW);
2271 cc_glglue_glActiveTexture(glue, GL_TEXTURE3);
2272
2273 glBindTexture(GL_TEXTURE_RECTANGLE_NV, this->depthtextureid);
2274 glEnable(GL_TEXTURE_RECTANGLE_NV);
2275
2276 glPushMatrix();
2277 glLoadIdentity();
2278 this->eyeLinearTexgen();
2279 glPopMatrix();
2280 this->texgenEnable(TRUE);
2281
2282 glMatrixMode(GL_TEXTURE);
2283 glLoadIdentity();
2284 glScalef(this->viewportwidth, this->viewportheight, 1);
2285 glTranslatef(0.5, 0.5, 0.5);
2286 glScalef(0.5, 0.5, 0.5);
2287 glMultMatrixf(static_cast<float *>(this->sortedlayersblendprojectionmatrix));
2288 glMatrixMode(GL_MODELVIEW);
2289
2290 glAlphaFunc(GL_GREATER, 0);
2291 glEnable(GL_ALPHA_TEST);
2292
2293 // UNIT #0
2294 cc_glglue_glActiveTexture(glue, GL_TEXTURE0);
2295
2296 }
2297
2298
2299 void
setupRegisterCombinersNV()2300 SoGLRenderActionP::setupRegisterCombinersNV()
2301 {
2302
2303 //
2304 // Setting up the texture units to handle the sorted layers blending
2305 //
2306 const cc_glglue * glue = sogl_glue_instance(this->action->getState());
2307 glEnable(GL_TEXTURE_SHADER_NV);
2308
2309 // UNIT #0
2310 cc_glglue_glActiveTexture(glue, GL_TEXTURE0);
2311 glBindTexture(GL_TEXTURE_2D, this->hilotextureid);
2312 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
2313
2314 // UNIT #1
2315 cc_glglue_glActiveTexture(glue, GL_TEXTURE1);
2316 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_DOT_PRODUCT_NV);
2317 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0);
2318 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_NONE);
2319
2320 glMatrixMode(GL_MODELVIEW);
2321 glPushMatrix();
2322 glLoadIdentity();
2323 this->eyeLinearTexgen();
2324 this->texgenEnable(TRUE);
2325 glPopMatrix();
2326
2327 glMatrixMode(GL_TEXTURE);
2328 glLoadIdentity();
2329 glTranslatef(0.0f, 0.0f, 0.5f);
2330 glScalef(0.0f, 0.0f, 0.5f);
2331 glMultMatrixf(static_cast<float *>(this->sortedlayersblendprojectionmatrix));
2332 glMatrixMode(GL_MODELVIEW);
2333
2334 // UNIT #2
2335 cc_glglue_glActiveTexture(glue, GL_TEXTURE2);
2336 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_DOT_PRODUCT_DEPTH_REPLACE_NV);
2337 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0);
2338 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_NONE);
2339
2340 glPushMatrix();
2341 glLoadIdentity();
2342 this->eyeLinearTexgen();
2343 this->texgenEnable(TRUE);
2344 glPopMatrix();
2345
2346 glMatrixMode(GL_TEXTURE);
2347 GLdouble m[16];
2348 m[0 + 0] = 0; m[0 + 1] = 0; m[0 + 2] = 0; m[0 + 3] = 0;
2349 m[1*4 + 0] = 0; m[1*4 + 1] = 0; m[1*4 + 2] = 0; m[1*4 + 3] = 0;
2350 m[2*4 + 0] = 0; m[2*4 + 1] = 0; m[2*4 + 2] = 0; m[2*4 + 3] = 0;
2351 m[3*4 + 0] = 0; m[3*4 + 1] = 0; m[3*4 + 2] = 1; m[3*4 + 3] = 0;
2352 glLoadMatrixd(m);
2353 glMultMatrixf(static_cast<float *>(this->sortedlayersblendprojectionmatrix));
2354 glMatrixMode(GL_MODELVIEW);
2355
2356 // UNIT #0
2357 cc_glglue_glActiveTexture(glue, GL_TEXTURE0);
2358
2359 if (this->sortedlayersblendcounter > 0) { // Is this not the first pass?
2360
2361 cc_glglue_glActiveTexture(glue, GL_TEXTURE3);
2362 glTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_RECTANGLE_NV);
2363 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_NONE);
2364
2365 glPushMatrix();
2366 glLoadIdentity();
2367 this->eyeLinearTexgen();
2368 glPopMatrix();
2369 this->texgenEnable(TRUE);
2370
2371 glMatrixMode(GL_TEXTURE);
2372 glLoadIdentity();
2373 glScalef(this->viewportwidth, this->viewportheight, 1);
2374 glTranslatef(.5,.5,.5);
2375 glScalef(.5,.5,.5);
2376 glMultMatrixf(static_cast<float *>(this->sortedlayersblendprojectionmatrix));
2377 glMatrixMode(GL_MODELVIEW);
2378
2379 glBindTexture(GL_TEXTURE_RECTANGLE_NV, this->depthtextureid);
2380 glEnable(GL_TEXTURE_RECTANGLE_NV);
2381
2382 // UNIT #0
2383 cc_glglue_glActiveTexture(glue, GL_TEXTURE0);
2384
2385 //
2386 // Register combiners 1.0 script:
2387 // !!RC1.0
2388 // {
2389 // rgb { spare0 = unsigned_invert(tex3) * col0.a; }
2390 // }
2391 // out.rgb = col0;
2392 // out.a = spare0.b;
2393 //
2394 glue->glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1);
2395 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_TEXTURE3,
2396 GL_UNSIGNED_INVERT_NV, GL_RGB);
2397 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV,
2398 GL_PRIMARY_COLOR_NV, GL_SIGNED_IDENTITY_NV, GL_ALPHA);
2399 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_ZERO,
2400 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2401 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO,
2402 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2403 glue->glCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_SPARE0_NV, GL_DISCARD_NV,
2404 GL_DISCARD_NV, GL_ZERO, GL_ZERO, GL_FALSE, GL_FALSE, GL_FALSE);
2405 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_ZERO,
2406 GL_UNSIGNED_IDENTITY_NV, GL_BLUE);
2407 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_ZERO,
2408 GL_UNSIGNED_IDENTITY_NV, GL_BLUE);
2409 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_C_NV, GL_ZERO,
2410 GL_UNSIGNED_IDENTITY_NV, GL_BLUE);
2411 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_D_NV, GL_ZERO,
2412 GL_UNSIGNED_IDENTITY_NV, GL_BLUE);
2413 glue->glCombinerOutputNV(GL_COMBINER0_NV, GL_ALPHA, GL_DISCARD_NV, GL_DISCARD_NV,
2414 GL_DISCARD_NV, GL_ZERO, GL_ZERO, GL_FALSE, GL_FALSE, GL_FALSE);
2415
2416 glue->glCombinerParameteriNV(GL_COLOR_SUM_CLAMP_NV, 0);
2417 glue->glFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_ZERO,
2418 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2419 glue->glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_ZERO,
2420 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2421 glue->glFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_ZERO,
2422 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2423 glue->glFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_PRIMARY_COLOR_NV,
2424 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2425 glue->glFinalCombinerInputNV(GL_VARIABLE_E_NV, GL_ZERO,
2426 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2427 glue->glFinalCombinerInputNV(GL_VARIABLE_F_NV, GL_ZERO,
2428 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2429 glue->glFinalCombinerInputNV(GL_VARIABLE_G_NV, GL_SPARE0_NV,
2430 GL_UNSIGNED_IDENTITY_NV, GL_BLUE);
2431
2432 glEnable(GL_REGISTER_COMBINERS_NV);
2433
2434 glAlphaFunc(GL_GREATER, 0);
2435 glEnable(GL_ALPHA_TEST);
2436
2437 }
2438
2439 glMatrixMode(GL_MODELVIEW);
2440 }
2441
2442 void
setupSortedLayersBlendTextures(const SoState * state)2443 SoGLRenderActionP::setupSortedLayersBlendTextures(const SoState * state)
2444 {
2445
2446 const SbViewportRegion & vpr = this->action->getViewportRegion();
2447 const SbVec2s & canvassize = vpr.getViewportSizePixels();
2448
2449 // Do we have to reinitialize the textures?
2450 if (((canvassize[1] != this->viewportheight) ||
2451 (canvassize[0] != this->viewportwidth)) ||
2452 !this->sortedlayersblendinitialized) {
2453
2454 const cc_glglue * glue = sogl_glue_instance(state);
2455
2456
2457 if (this->sortedlayersblendinitialized) {
2458 // Remove the old textures to make room for new ones if size has changed.
2459 glDeleteTextures(1, &this->depthtextureid);
2460 glDeleteTextures(this->sortedlayersblendpasses, this->rgbatextureids.get());
2461 }
2462
2463 // Depth texture setup
2464 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2465
2466 // FIXME: the texture id must be bound to the current rendering
2467 // context, and deallocated when it is destructed. 20040718 mortene.
2468 glGenTextures(1, &this->depthtextureid);
2469 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, this->depthtextureid);
2470 glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_DEPTH_COMPONENT24, canvassize[0], canvassize[1],
2471 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
2472 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2473 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2474 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2475 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2476
2477 if (glue->has_arb_fragment_program && !this->usenvidiaregistercombiners) {
2478 // Not disabled as default by NVIDIA when using fragment programs (according to spec.)
2479 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_COMPARE_MODE, GL_NONE);
2480 }
2481 else {
2482 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
2483 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
2484 }
2485
2486 // The "register combiner"-way if explicitly choosen or FP is unavailable
2487 if(this->usenvidiaregistercombiners) {
2488 // HILO texture setup
2489 GLushort HILOtexture[] = {0, 0};
2490 // FIXME: the texture id must be bound to the current rendering
2491 // context, and deallocated when it is destructed. 20040718 mortene.
2492 glGenTextures(1, &this->hilotextureid);
2493 glBindTexture(GL_TEXTURE_2D, this->hilotextureid);
2494 glTexImage2D(GL_TEXTURE_2D, 0, GL_HILO_NV, 1, 1, 0, GL_HILO_NV,
2495 GL_UNSIGNED_SHORT, &HILOtexture);
2496 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2497 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2498 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2499 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2500 }
2501
2502
2503 // RGBA layers setup
2504 // FIXME: What if channels are > 8 bits? This must be examined
2505 // closer... [Only highend ATI cards supports these resolutions if
2506 // I'm not mistaken.] (20031126 handegar)
2507 //
2508 // FIXME: the texture ids must be bound to the current rendering
2509 // context, and deallocated when it is destructed. 20040718 mortene.
2510 glGenTextures(this->sortedlayersblendpasses, this->rgbatextureids.get());
2511 for (int i=0;i<sortedlayersblendpasses;++i) {
2512 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, this->rgbatextureids[i]);
2513 glCopyTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA8, 0, 0, canvassize[0], canvassize[1], 0);
2514 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2515 glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2516 }
2517
2518 this->viewportwidth = canvassize[0];
2519 this->viewportheight = canvassize[1];
2520
2521 }
2522
2523 }
2524
2525 void
renderSortedLayersFP(const SoState * state)2526 SoGLRenderActionP::renderSortedLayersFP(const SoState * state)
2527 {
2528
2529 const cc_glglue * glue = sogl_glue_instance(state);
2530
2531 glMatrixMode(GL_PROJECTION);
2532 glLoadIdentity();
2533 glOrtho(0, this->viewportwidth, 0, this->viewportheight, -1, 1);
2534 glMatrixMode(GL_MODELVIEW);
2535 glLoadIdentity();
2536
2537 glDisable(GL_DEPTH_TEST);
2538 glClear(GL_COLOR_BUFFER_BIT);
2539
2540 SbBool cullface = glIsEnabled(GL_CULL_FACE);
2541 SbBool lighting = glIsEnabled(GL_LIGHTING);
2542
2543 glDisable(GL_CULL_FACE);
2544 glDisable(GL_FRAGMENT_PROGRAM_ARB);
2545 glDisable(GL_ALPHA_TEST);
2546
2547 cc_glglue_glActiveTexture(glue, GL_TEXTURE0);
2548
2549 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2550
2551 glEnable(GL_BLEND);
2552 glDisable(GL_LIGHTING);
2553 glColor3f(1.0f,1.0f,1.0f);
2554 glEnable(GL_TEXTURE_RECTANGLE_EXT);
2555
2556 for(int i=this->sortedlayersblendpasses-1;i>=0;--i) {
2557 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, this->rgbatextureids[i]);
2558 glBegin(GL_QUADS);
2559 glTexCoord2f(0, 0);
2560 glVertex2f(0, 0);
2561 glTexCoord2f(0, this->viewportheight);
2562 glVertex2f(0, this->viewportheight);
2563 glTexCoord2f(this->viewportwidth, this->viewportheight);
2564 glVertex2f(this->viewportwidth, this->viewportheight);
2565 glTexCoord2f(this->viewportwidth, 0);
2566 glVertex2f(this->viewportwidth, 0);
2567 glEnd();
2568 }
2569
2570 glDisable(GL_TEXTURE_RECTANGLE_EXT);
2571
2572 glDisable(GL_BLEND);
2573 glEnable(GL_DEPTH_TEST);
2574
2575 if (cullface)
2576 glEnable(GL_CULL_FACE);
2577
2578 if (lighting)
2579 glEnable(GL_LIGHTING);
2580
2581 }
2582
2583 void
renderSortedLayersNV(const SoState * state)2584 SoGLRenderActionP::renderSortedLayersNV(const SoState * state)
2585 {
2586
2587 const cc_glglue * glue = sogl_glue_instance(state);
2588
2589 glMatrixMode(GL_PROJECTION);
2590 glLoadIdentity();
2591 glOrtho(0, this->viewportwidth, 0, this->viewportheight, -1, 1);
2592 glMatrixMode(GL_MODELVIEW);
2593 glLoadIdentity();
2594
2595 glDisable(GL_DEPTH_TEST);
2596 glClear(GL_COLOR_BUFFER_BIT);
2597
2598
2599 // Must make sure that the GL_CULL_FACE state is preserved if the scene
2600 // contains both solid and non-solid shapes.
2601 SbBool cullface = glIsEnabled(GL_CULL_FACE);
2602 glDisable(GL_CULL_FACE);
2603
2604 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2605 glEnable(GL_BLEND);
2606
2607 cc_glglue_glActiveTexture(glue, GL_TEXTURE0);
2608
2609 //
2610 // Register combiners 1.0 script:
2611 // !!RC1.0
2612 // rgb.out = tex0;
2613 // rgb.a = tex0;
2614 //
2615 glue->glCombinerParameteriNV(GL_NUM_GENERAL_COMBINERS_NV, 1);
2616 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_A_NV, GL_ZERO,
2617 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2618 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_B_NV, GL_ZERO,
2619 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2620 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_C_NV, GL_ZERO,
2621 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2622 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_RGB, GL_VARIABLE_D_NV, GL_ZERO,
2623 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2624 glue->glCombinerOutputNV(GL_COMBINER0_NV, GL_RGB, GL_DISCARD_NV, GL_DISCARD_NV,
2625 GL_DISCARD_NV, GL_ZERO, GL_ZERO, GL_FALSE, GL_FALSE, GL_FALSE);
2626 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_A_NV, GL_ZERO,
2627 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
2628 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_B_NV, GL_ZERO,
2629 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
2630 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_C_NV, GL_ZERO,
2631 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
2632 glue->glCombinerInputNV(GL_COMBINER0_NV, GL_ALPHA, GL_VARIABLE_D_NV, GL_ZERO,
2633 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
2634 glue->glCombinerOutputNV(GL_COMBINER0_NV, GL_ALPHA, GL_DISCARD_NV, GL_DISCARD_NV,
2635 GL_DISCARD_NV, GL_ZERO, GL_ZERO, GL_FALSE, GL_FALSE, GL_FALSE);
2636
2637 glue->glCombinerParameteriNV(GL_COLOR_SUM_CLAMP_NV, 0);
2638 glue->glFinalCombinerInputNV(GL_VARIABLE_A_NV, GL_ZERO,
2639 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2640 glue->glFinalCombinerInputNV(GL_VARIABLE_B_NV, GL_ZERO,
2641 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2642 glue->glFinalCombinerInputNV(GL_VARIABLE_C_NV, GL_ZERO,
2643 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2644 glue->glFinalCombinerInputNV(GL_VARIABLE_D_NV, GL_TEXTURE0,
2645 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2646 glue->glFinalCombinerInputNV(GL_VARIABLE_E_NV, GL_ZERO,
2647 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2648 glue->glFinalCombinerInputNV(GL_VARIABLE_F_NV, GL_ZERO,
2649 GL_UNSIGNED_IDENTITY_NV, GL_RGB);
2650 glue->glFinalCombinerInputNV(GL_VARIABLE_G_NV, GL_TEXTURE0,
2651 GL_UNSIGNED_IDENTITY_NV, GL_ALPHA);
2652
2653 glEnable(GL_REGISTER_COMBINERS_NV);
2654 glEnable(GL_TEXTURE_RECTANGLE_EXT);
2655
2656 for(int i=this->sortedlayersblendpasses-1;i>=0;--i) {
2657 glBindTexture(GL_TEXTURE_RECTANGLE_EXT, this->rgbatextureids[i]);
2658 glBegin(GL_QUADS);
2659 glTexCoord2f(0, 0);
2660 glVertex2f(0, 0);
2661 glTexCoord2f(0, this->viewportheight);
2662 glVertex2f(0, this->viewportheight);
2663 glTexCoord2f(this->viewportwidth, this->viewportheight);
2664 glVertex2f(this->viewportwidth, this->viewportheight);
2665 glTexCoord2f(this->viewportwidth, 0);
2666 glVertex2f(this->viewportwidth, 0);
2667 glEnd();
2668 }
2669
2670 glDisable(GL_REGISTER_COMBINERS_NV);
2671 glDisable(GL_TEXTURE_RECTANGLE_EXT);
2672
2673 glDisable(GL_BLEND);
2674 glEnable(GL_DEPTH_TEST);
2675
2676 if (cullface)
2677 glEnable(GL_CULL_FACE);
2678
2679 }
2680
2681 // *************************************************************************
2682
2683 #undef PRIVATE
2684