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