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 SoGLLazyElement Inventor/elements/SoGLLazyElement.h
35   \brief The SoGLLazyElement class is meant to optimize GL rendering.
36 
37   \ingroup elements
38 
39   This is just a wrap-around implementation for compatibility. It should
40   (hopefully) work in the same way as the Inventor class though.
41 */
42 
43 // FIXME: is the above class doc comment still correct? Or do we have
44 // an implementation of this class in the same manner as the other
45 // Inventors now? 20040702 mortene.
46 
47 // *************************************************************************
48 
49 #include <Inventor/elements/SoGLLazyElement.h>
50 
51 #include <cassert>
52 
53 #include <Inventor/C/glue/gl.h>
54 #include <Inventor/SbImage.h>
55 #include <Inventor/SoFullPath.h>
56 #include <Inventor/actions/SoGLRenderAction.h>
57 #include <Inventor/bundles/SoMaterialBundle.h>
58 #include <Inventor/elements/SoGLCacheContextElement.h>
59 #include <Inventor/elements/SoGLDisplayList.h>
60 #include <Inventor/elements/SoGLMultiTextureEnabledElement.h>
61 #include <Inventor/elements/SoGLMultiTextureImageElement.h>
62 #include <Inventor/elements/SoShapeStyleElement.h>
63 #include <Inventor/elements/SoTextureCombineElement.h>
64 #include <Inventor/elements/SoGLShaderProgramElement.h>
65 #include <Inventor/errors/SoDebugError.h>
66 #include <Inventor/errors/SoDebugError.h>
67 #include <Inventor/misc/SoState.h>
68 #include <Inventor/nodes/SoNode.h>
69 #include <Inventor/C/tidbits.h>
70 #include "../../rendering/SoVBO.h"
71 #include <coindefs.h> // COIN_OBSOLETED
72 
73 #include "../../shaders/SoGLShaderProgram.h"
74 
75 // *************************************************************************
76 
77 #define FLAG_FORCE_DIFFUSE      0x0001
78 #define FLAG_DIFFUSE_DEPENDENCY 0x0002
79 
80 #if COIN_DEBUG
81 // #define GLLAZY_DEBUG(_x_) (SoDebugError::postInfo(COIN_STUB_FUNC, _x_))
82 #define GLLAZY_DEBUG(x)
83 #else
84 #define GLLAZY_DEBUG(x)
85 #endif
86 
87 #ifdef HAVE_CONFIG_H
88 #include <config.h>
89 #endif // HAVE_CONFIG_H
90 
91 // Some data and functions to create Bayer dither matrices (used for
92 // screen door transparency)
93 static unsigned char stipple_patterns[64 + 1][32 * 4];
94 static uint32_t two_by_two[] = {0, 2, 3, 1};
95 
96 //
97 // Used to generate a matrix twice the size of the input
98 //
99 static void
generate_next_matrix(uint32_t * old,int oldsize,uint32_t * matrix)100 generate_next_matrix(uint32_t * old, int oldsize,
101                      uint32_t * matrix)
102 {
103   int i,j;
104   int newsize = oldsize << 1;
105   for (i = 0; i <  newsize; i++) {
106     for (j = 0; j < newsize; j++) {
107       matrix[i*newsize+j] = 4 * old[(i%oldsize)*oldsize + (j%oldsize)];
108       matrix[i*newsize+j] += two_by_two[(i/oldsize)*2 + (j/oldsize)];
109     }
110   }
111 }
112 
113 //
114 // Creates a matrix by starting with a 2x2 and doubling until size
115 //
116 static void
make_dither_matrix(uint32_t * ptr,int size)117 make_dither_matrix(uint32_t * ptr, int size)
118 {
119   int currsize = 2;
120 
121   uint32_t * currmatrix = two_by_two;
122   uint32_t * nextmatrix = NULL;
123   int nextsize;
124 
125   while (currsize < size) {
126     nextsize = currsize << 1;
127     nextmatrix = new uint32_t[nextsize*nextsize];
128     generate_next_matrix(currmatrix, currsize, nextmatrix);
129     if (currmatrix != two_by_two) delete[] currmatrix;
130     currmatrix = nextmatrix;
131     currsize = nextsize;
132   }
133   // copy matrix
134   int i;
135   for (i = 0; i < size*size; i++)
136     ptr[i] = currmatrix[i];
137 
138   if (currmatrix != two_by_two) delete[] currmatrix;
139 }
140 
141 //
142 // Sets a bit bitnr bits from ptr
143 //
144 static void
set_bit(int bitnr,unsigned char * ptr)145 set_bit(int bitnr, unsigned char * ptr)
146 {
147   int byte = bitnr / 8;
148   int bit = bitnr % 8;
149 
150   unsigned char mask = (unsigned char) (0x80 >> bit);
151 
152   ptr[byte] |= mask;
153 }
154 
155 //
156 // Create a bitmap from a 32x32 matrix
157 //
158 static void
create_matrix_bitmap(int intensity,unsigned char * bitmap,uint32_t * matrix,int size)159 create_matrix_bitmap(int intensity, unsigned char * bitmap,
160                      uint32_t * matrix, int size)
161 {
162   int cnt = 0;
163   int i,j;
164   for (i = 0; i < 32*4; i++) bitmap[i] = 0;
165   for (i = 0; i < size; i++) {
166     for (j = 0; j < size; j++) {
167       if (matrix[i*size+j] > (uint32_t) intensity) {
168         set_bit(i*32+j, bitmap);
169         cnt++;
170       }
171     }
172   }
173 }
174 
175 
176 SO_ELEMENT_SOURCE(SoGLLazyElement);
177 
178 /*!
179   This static method initializes static data for the
180   SoDiffuseColorElement class.
181 */
182 
183 void
initClass()184 SoGLLazyElement::initClass()
185 {
186   SO_ELEMENT_INIT_CLASS(SoGLLazyElement, inherited);
187 
188   // create stipple patterns
189   int i;
190   uint32_t matrix[32*32];
191   make_dither_matrix((uint32_t*)matrix, 32);
192   for (i = 0; i <= 64; i++) {
193     int intensity = (32 * 32 * i) / 64 - 1;
194     create_matrix_bitmap((intensity >= 0) ? intensity : 0,
195                          stipple_patterns[i], (uint32_t*) matrix, 32);
196   }
197 }
198 
199 // ! FIXME: write doc
200 
~SoGLLazyElement()201 SoGLLazyElement::~SoGLLazyElement()
202 {
203 }
204 
205 //! FIXME: write doc
206 SoGLLazyElement *
getInstance(const SoState * state)207 SoGLLazyElement::getInstance(const SoState *state)
208 {
209   return (SoGLLazyElement*)
210     state->getConstElement(classStackIndex);
211 }
212 
213 inline void
sendPackedDiffuse(const uint32_t col) const214 SoGLLazyElement::sendPackedDiffuse(const uint32_t col) const
215 {
216   glColor4ub((unsigned char)((col>>24)&0xff),
217              (unsigned char)((col>>16)&0xff),
218              (unsigned char)((col>>8)&0xff),
219              (unsigned char)(col&0xff));
220   this->glstate.diffuse = col;
221   this->cachebitmask |= DIFFUSE_MASK;
222 }
223 
224 inline void
sendLightModel(const int32_t model) const225 SoGLLazyElement::sendLightModel(const int32_t model) const
226 {
227   if (model == PHONG) glEnable(GL_LIGHTING);
228   else glDisable(GL_LIGHTING);
229   this->glstate.lightmodel = model;
230   this->cachebitmask |= LIGHT_MODEL_MASK;
231 }
232 
233 inline void
sendFlatshading(const SbBool onoff) const234 SoGLLazyElement::sendFlatshading(const SbBool onoff) const
235 {
236   if (onoff) glShadeModel(GL_FLAT);
237   else glShadeModel(GL_SMOOTH);
238   this->glstate.flatshading = (int32_t) onoff;
239   this->cachebitmask |= SHADE_MODEL_MASK;
240 }
241 
242 inline void
sendAlphaTest(int func,float value) const243 SoGLLazyElement::sendAlphaTest(int func, float value) const
244 {
245   if (func) {
246     glAlphaFunc((GLenum) func, value);
247     glEnable(GL_ALPHA_TEST);
248   }
249   else {
250     glDisable(GL_ALPHA_TEST);
251   }
252   this->cachebitmask |= ALPHATEST_MASK;
253   this->glstate.alphatestfunc = func;
254   this->glstate.alphatestvalue = value;
255 }
256 
257 
258 inline void
sendVertexOrdering(const VertexOrdering ordering) const259 SoGLLazyElement::sendVertexOrdering(const VertexOrdering ordering) const
260 {
261   glFrontFace(ordering == CW ? GL_CW : GL_CCW);
262   this->glstate.vertexordering = (int32_t) ordering;
263   this->cachebitmask |= VERTEXORDERING_MASK;
264 }
265 
266 inline void
sendTwosideLighting(const SbBool onoff) const267 SoGLLazyElement::sendTwosideLighting(const SbBool onoff) const
268 {
269   glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, onoff ? GL_TRUE : GL_FALSE);
270   this->glstate.twoside = (int32_t) onoff;
271   this->cachebitmask |= TWOSIDE_MASK;
272 }
273 
274 inline void
sendBackfaceCulling(const SbBool onoff) const275 SoGLLazyElement::sendBackfaceCulling(const SbBool onoff) const
276 {
277   if (onoff) glEnable(GL_CULL_FACE);
278   else glDisable(GL_CULL_FACE);
279   this->glstate.culling = onoff;
280   this->cachebitmask |= CULLING_MASK;
281 }
282 
283 static inline void
send_gl_material(GLenum pname,const SbColor & color)284 send_gl_material(GLenum pname, const SbColor & color)
285 {
286   GLfloat col[4];
287   color.getValue(col[0], col[1], col[2]);
288   col[3] = 1.0f;
289   glMaterialfv(GL_FRONT_AND_BACK, pname, col);
290 }
291 
292 
293 inline void
sendAmbient(const SbColor & color) const294 SoGLLazyElement::sendAmbient(const SbColor & color) const
295 {
296   send_gl_material(GL_AMBIENT, color);
297   this->glstate.ambient = color;
298   this->cachebitmask |= AMBIENT_MASK;
299 }
300 
301 inline void
sendEmissive(const SbColor & color) const302 SoGLLazyElement::sendEmissive(const SbColor & color) const
303 {
304   send_gl_material(GL_EMISSION, color);
305   this->glstate.emissive = color;
306   this->cachebitmask |= EMISSIVE_MASK;
307 }
308 
309 inline void
sendSpecular(const SbColor & color) const310 SoGLLazyElement::sendSpecular(const SbColor & color) const
311 {
312   send_gl_material(GL_SPECULAR, color);
313   this->glstate.specular = color;
314   this->cachebitmask |= SPECULAR_MASK;
315 }
316 
317 inline void
sendShininess(const float shine) const318 SoGLLazyElement::sendShininess(const float shine) const
319 {
320   glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shine*128.0f);
321   this->glstate.shininess = shine;
322   this->cachebitmask |= SHININESS_MASK;
323 }
324 
325 inline void
sendTransparency(const int stipplenum) const326 SoGLLazyElement::sendTransparency(const int stipplenum) const
327 {
328   if (stipplenum == 0) {
329     glDisable(GL_POLYGON_STIPPLE);
330   }
331   else {
332     if (this->glstate.stipplenum <= 0) glEnable(GL_POLYGON_STIPPLE);
333     glPolygonStipple(stipple_patterns[stipplenum]);
334   }
335   this->glstate.stipplenum = stipplenum;
336   this->cachebitmask |= TRANSPARENCY_MASK;
337 }
338 
339 inline void
enableBlending(const int sfactor,const int dfactor) const340 SoGLLazyElement::enableBlending(const int sfactor, const int dfactor) const
341 {
342   glEnable(GL_BLEND);
343   glBlendFunc((GLenum) sfactor, (GLenum) dfactor);
344   this->glstate.blending = TRUE;
345   this->glstate.blend_sfactor = sfactor;
346   this->glstate.blend_dfactor = dfactor;
347   this->glstate.alpha_blend_sfactor = 0;
348   this->glstate.alpha_blend_dfactor = 0;
349   this->cachebitmask |= BLENDING_MASK;
350 }
351 
352 inline void
enableSeparateBlending(const cc_glglue * glue,const int sfactor,const int dfactor,const int alpha_sfactor,const int alpha_dfactor) const353 SoGLLazyElement::enableSeparateBlending(const cc_glglue * glue,
354                                         const int sfactor,
355                                         const int dfactor,
356                                         const int alpha_sfactor,
357                                         const int alpha_dfactor) const
358 {
359   glEnable(GL_BLEND);
360 
361   if (cc_glglue_has_blendfuncseparate(glue)) {
362     cc_glglue_glBlendFuncSeparate(glue, sfactor, dfactor, alpha_sfactor, alpha_dfactor);
363   }
364   else {
365       // fall back to normal blending
366     glBlendFunc((GLenum) sfactor, (GLenum) dfactor);
367   }
368   this->glstate.blending = TRUE;
369   this->glstate.blend_sfactor = sfactor;
370   this->glstate.blend_dfactor = dfactor;
371   this->glstate.alpha_blend_sfactor = alpha_sfactor;
372   this->glstate.alpha_blend_dfactor = alpha_dfactor;
373   this->cachebitmask |= BLENDING_MASK;
374 }
375 
376 inline void
disableBlending(void) const377 SoGLLazyElement::disableBlending(void) const
378 {
379   glDisable(GL_BLEND);
380   this->glstate.blending = FALSE;
381   this->cachebitmask |= BLENDING_MASK;
382 }
383 
384 void
init(SoState * stateptr)385 SoGLLazyElement::init(SoState * stateptr)
386 {
387   inherited::init(stateptr);
388   this->state = stateptr; // needed to send GL texture
389   this->colorindex = FALSE;
390   this->glstate.ambient.setValue(-1.0f, -1.0f, -1.0f);
391   this->glstate.emissive.setValue(-1.0f, -1.0f, -1.0f);
392   this->glstate.specular.setValue(-1.0f, -1.0f, -1.0f);
393   this->glstate.shininess = -1.0f;
394   this->glstate.lightmodel = -1;
395   this->glstate.blending = -1;
396   this->glstate.blend_sfactor = -1;
397   this->glstate.blend_dfactor = -1;
398   this->glstate.alpha_blend_sfactor = -1;
399   this->glstate.alpha_blend_dfactor = -1;
400   this->glstate.stipplenum = -1;
401   this->glstate.vertexordering = -1;
402   this->glstate.twoside = -1;
403   this->glstate.culling = -1;
404   this->glstate.flatshading = -1;
405   this->glstate.alphatestfunc = -1;
406   this->glstate.alphatestvalue = -1.0f;
407   this->glstate.diffuse = 0xccccccff;
408   this->glstate.diffusenodeid = 0;
409   this->glstate.transpnodeid = 0;
410   this->packedpointer = NULL;
411   // when doing screen door rendering, we need to always supply 0xff as alpha.
412   this->transpmask = (this->coinstate.transptype == SoGLRenderAction::SCREEN_DOOR) ? 0xff : 0x00;
413   this->colorpacker = NULL;
414   this->precachestate = NULL;
415   this->postcachestate = NULL;
416   this->opencacheflags = 0;
417 
418   // initialize this here to avoid UMR reports from
419   // Purify. cachebitmask is updated even when there are no open
420   // caches. It is only used (and properly initialized) when recording
421   // a cache though.
422   this->cachebitmask = 0;
423 
424   glDisable(GL_POLYGON_STIPPLE);
425 
426   GLboolean rgba;
427   glGetBooleanv(GL_RGBA_MODE, &rgba);
428   if (!rgba) this->colorindex = TRUE;
429   else {
430     this->sendPackedDiffuse(0xccccccff);
431   }
432 }
433 
434 void
push(SoState * stateptr)435 SoGLLazyElement::push(SoState * stateptr)
436 {
437   inherited::push(stateptr);
438   SoGLLazyElement * prev = (SoGLLazyElement*) this->getNextInStack();
439   this->state = stateptr; // needed to send GL texture
440   this->glstate = prev->glstate;
441   this->colorindex = prev->colorindex;
442   this->transpmask = prev->transpmask;
443   this->colorpacker = prev->colorpacker;
444   this->precachestate = prev->precachestate;
445   this->postcachestate = prev->postcachestate;
446   this->didsetbitmask = prev->didsetbitmask;
447   this->didntsetbitmask = prev->didntsetbitmask;
448   this->cachebitmask = prev->cachebitmask;
449   this->opencacheflags = prev->opencacheflags;
450 }
451 
452 void
pop(SoState * stateptr,const SoElement * prevtopelement)453 SoGLLazyElement::pop(SoState *stateptr, const SoElement * prevtopelement)
454 {
455   inherited::pop(stateptr, prevtopelement);
456   SoGLLazyElement * prev = (SoGLLazyElement*) prevtopelement;
457   this->glstate = prev->glstate;
458   this->colorindex = prev->colorindex;
459   this->didsetbitmask = prev->didsetbitmask;
460   this->didntsetbitmask = prev->didntsetbitmask;
461   this->cachebitmask = prev->cachebitmask;
462   this->opencacheflags = prev->opencacheflags;
463 }
464 
465 //! FIXME: write doc
466 
467 void
sendAllMaterial(SoState * state)468 SoGLLazyElement::sendAllMaterial(SoState * state)
469 {
470   SoGLLazyElement * elem = getInstance(state);
471   elem->send(state, ALL_MASK);
472 }
473 
474 //! FIXME: write doc
475 
476 void
sendNoMaterial(SoState * state)477 SoGLLazyElement::sendNoMaterial(SoState * state)
478 {
479   SoGLLazyElement * elem = getInstance(state);
480   elem->send(state, NO_COLOR_MASK);
481 }
482 
483 //! FIXME: write doc
484 
485 void
sendOnlyDiffuseColor(SoState * state)486 SoGLLazyElement::sendOnlyDiffuseColor(SoState * state)
487 {
488   SoGLLazyElement * elem = getInstance(state);
489   elem->send(state, DIFFUSE_ONLY_MASK);
490 }
491 
492 //! FIXME: write doc
493 
494 void
sendDiffuseByIndex(const int index) const495 SoGLLazyElement::sendDiffuseByIndex(const int index) const
496 {
497   int safeindex = index;
498 #if COIN_DEBUG
499   if (index < 0 || index >= this->coinstate.numdiffuse) {
500     static int first = 1;
501     if (first) {
502       SoFullPath * path = (SoFullPath*) this->state->getAction()->getCurPath();
503       SoNode * tail = path->getTail();
504       SbName name = tail->getName();
505       SoDebugError::postWarning("SoGLLazyElement::sendDiffuseByIndex",
506                                 "index %d out of bounds [0, %d] in node %p: %s "
507                                 "(this warning will only be printed once, but there "
508                                 "might be more errors)",
509                                 index,
510                                 this->coinstate.numdiffuse-1,
511                                 tail, name != SbName::empty() ? name.getString() : "<noname>");
512       first = 0;
513     }
514 
515     safeindex = SbClamp((long) index, (long) 0, (long) (this->coinstate.numdiffuse-1));
516   }
517 #endif // COIN_DEBUG
518 
519   if (this->colorindex) {
520     glIndexi((GLint)this->coinstate.colorindexarray[safeindex]);
521   }
522   else {
523     uint32_t col = this->packedpointer[safeindex] | this->transpmask;
524     // this test is really not necessary. SoMaterialBundle does the
525     // same test.  We also need to send the color here to work around
526     // an nVIDIA bug
527     // if (col != this->glstate.diffuse)
528     this->sendPackedDiffuse(col);
529   }
530 }
531 
532 //! FIXME: write doc
533 
534 SbBool
isColorIndex(SoState * state)535 SoGLLazyElement::isColorIndex(SoState * state)
536 {
537   SoGLLazyElement * elem = getInstance(state);
538   return elem->colorindex;
539 }
540 
541 //! FIXME: write doc
542 
543 void
send(const SoState * stateptr,uint32_t mask) const544 SoGLLazyElement::send(const SoState * stateptr, uint32_t mask) const
545 {
546   if (this->colorpacker) {
547     if (!this->colorpacker->diffuseMatch(this->coinstate.diffusenodeid) ||
548         !this->colorpacker->transpMatch(this->coinstate.transpnodeid)) {
549       this->packColors(this->colorpacker);
550     }
551     this->packedpointer = this->colorpacker->getPackedColors();
552   }
553   else this->packedpointer = this->coinstate.packedarray;
554 
555   assert(this->packedpointer);
556 
557   int stipplenum;
558 
559   for (int i = 0; (i < LAZYCASES_LAST)&&mask; i++, mask>>=1) {
560     if (mask&1) {
561       switch (i) {
562       case LIGHT_MODEL_CASE:
563         if (this->coinstate.lightmodel != this->glstate.lightmodel) {
564           SoGLShaderProgram * prog = SoGLShaderProgramElement::get((SoState*) stateptr);
565           if (prog) prog->updateCoinParameter((SoState*)stateptr, SbName("coin_light_model"), this->coinstate.lightmodel);
566           this->sendLightModel(this->coinstate.lightmodel);
567         }
568         break;
569       case DIFFUSE_CASE:
570         if (this->precachestate) {
571           // we are currently building a cache. Check if we're using
572           // colors from a material node outside the cache.
573           if ((this->precachestate->diffusenodeid == this->coinstate.diffusenodeid) ||
574               (this->precachestate->transpnodeid == this->coinstate.transpnodeid)) {
575             this->opencacheflags |= FLAG_DIFFUSE_DEPENDENCY;
576           }
577         }
578         if (this->opencacheflags & FLAG_FORCE_DIFFUSE) {
579           // we always send the first diffuse color for the first
580           // material in an open cache
581           if (this->colorindex) {
582             glIndexi((GLint)this->coinstate.colorindexarray[0]);
583           }
584           else {
585             this->sendPackedDiffuse(this->packedpointer[0]|this->transpmask);
586           }
587           this->opencacheflags &= ~FLAG_FORCE_DIFFUSE;
588         }
589         else {
590           this->sendDiffuseByIndex(0);
591         }
592         break;
593       case AMBIENT_CASE:
594         if (this->coinstate.ambient != this->glstate.ambient) {
595           this->sendAmbient(this->coinstate.ambient);
596         }
597         break;
598       case SPECULAR_CASE:
599         if (this->coinstate.specular != this->glstate.specular) {
600           this->sendSpecular(this->coinstate.specular);
601         }
602         break;
603       case EMISSIVE_CASE:
604         if (this->coinstate.emissive != this->glstate.emissive) {
605           this->sendEmissive(this->coinstate.emissive);
606         }
607         break;
608       case SHININESS_CASE:
609         if (this->coinstate.shininess != this->glstate.shininess) {
610           this->sendShininess(this->coinstate.shininess);
611         }
612         break;
613       case BLENDING_CASE:
614         if (this->coinstate.blending) {
615           if (this->glstate.blending != this->coinstate.blending ||
616               this->coinstate.blend_sfactor != this->glstate.blend_sfactor ||
617               this->coinstate.blend_dfactor != this->glstate.blend_dfactor ||
618               this->coinstate.alpha_blend_sfactor != this->glstate.alpha_blend_sfactor ||
619               this->coinstate.alpha_blend_dfactor != this->glstate.alpha_blend_dfactor) {
620             if ((this->coinstate.alpha_blend_sfactor != 0) &&
621                 (this->coinstate.alpha_blend_dfactor != 0)) {
622               this->enableSeparateBlending(cc_glglue_instance(SoGLCacheContextElement::get((SoState*)stateptr)),
623                                            this->coinstate.blend_sfactor,
624                                            this->coinstate.blend_dfactor,
625                                            this->coinstate.alpha_blend_sfactor,
626                                            this->coinstate.alpha_blend_dfactor);
627             }
628             else {
629               this->enableBlending(this->coinstate.blend_sfactor, this->coinstate.blend_dfactor);
630             }
631           }
632         }
633         else {
634           if (this->coinstate.blending != this->glstate.blending) {
635             this->disableBlending();
636           }
637         }
638         break;
639       case TRANSPARENCY_CASE:
640         stipplenum =
641           this->coinstate.transptype == SoGLRenderAction::SCREEN_DOOR ?
642           this->coinstate.stipplenum : 0;
643 
644         if (stipplenum != this->glstate.stipplenum) {
645           this->sendTransparency(stipplenum);
646         }
647         break;
648       case VERTEXORDERING_CASE:
649         if (this->glstate.vertexordering != this->coinstate.vertexordering) {
650           this->sendVertexOrdering(this->coinstate.vertexordering);
651         }
652         break;
653       case CULLING_CASE:
654         if (this->glstate.culling != this->coinstate.culling) {
655           this->sendBackfaceCulling(this->coinstate.culling);
656         }
657         break;
658       case TWOSIDE_CASE:
659         if (this->glstate.twoside != this->coinstate.twoside) {
660           SoGLShaderProgram * prog = SoGLShaderProgramElement::get((SoState*) stateptr);
661           if (prog) prog->updateCoinParameter((SoState*)stateptr, SbName("coin_two_sided_lighting"), this->coinstate.twoside);
662           this->sendTwosideLighting(this->coinstate.twoside);
663         }
664         break;
665       case SHADE_MODEL_CASE:
666         if (this->glstate.flatshading != this->coinstate.flatshading) {
667           this->sendFlatshading(this->coinstate.flatshading);
668         }
669         break;
670       case ALPHATEST_CASE:
671         if (this->glstate.alphatestfunc != (int32_t) this->coinstate.alphatestfunc ||
672             this->glstate.alphatestvalue != this->coinstate.alphatestvalue) {
673             this->sendAlphaTest(this->coinstate.alphatestfunc, this->coinstate.alphatestvalue);
674         }
675         break;
676       }
677 
678     }
679   }
680 }
681 
682 //! FIXME: write doc
683 
684 void
sendVPPacked(SoState * COIN_UNUSED_ARG (stateptr),const unsigned char * COIN_UNUSED_ARG (pcolor))685 SoGLLazyElement::sendVPPacked(SoState* COIN_UNUSED_ARG(stateptr), const unsigned char* COIN_UNUSED_ARG(pcolor))
686 {
687   assert(0 && "Not implemented yet. Provided for API compatibility.");
688 }
689 
690 /*!
691   Reset element GL state (set state to invalid). Use this method to
692   notify this element when you use your own GL code that changes the
693   OpenGL state.
694 */
695 void
reset(SoState * stateptr,uint32_t mask) const696 SoGLLazyElement::reset(SoState * stateptr,  uint32_t mask) const
697 {
698   SoGLLazyElement * elem = getInstance(stateptr);
699 
700   if (stateptr->isCacheOpen()) {
701     elem->cachebitmask |= mask;
702   }
703 
704   for (int i = 0; (i < LAZYCASES_LAST)&&mask; i++, mask>>=1) {
705     if (mask&1) {
706       switch (i) {
707       case LIGHT_MODEL_CASE:
708         elem->glstate.lightmodel = -1;
709         break;
710       case DIFFUSE_CASE:
711         elem->sendPackedDiffuse(0xccccccff);
712         break;
713       case AMBIENT_CASE:
714         elem->glstate.ambient = SbColor(-1.f, -1.0f, -1.0f);
715         break;
716       case SPECULAR_CASE:
717         elem->glstate.specular = SbColor(-1.0f, -1.0f, -1.0f);
718         break;
719       case EMISSIVE_CASE:
720         elem->glstate.emissive = SbColor(-1.0f, -1.0f, -1.0f);
721         break;
722       case SHININESS_CASE:
723         elem->glstate.shininess = -1.0f;
724         break;
725       case BLENDING_CASE:
726         elem->glstate.blending = -1;
727         elem->glstate.blend_sfactor = -1;
728         elem->glstate.blend_dfactor = -1;
729         elem->glstate.alpha_blend_sfactor = -1;
730         elem->glstate.alpha_blend_dfactor = -1;
731         break;
732       case TRANSPARENCY_CASE:
733         elem->glstate.stipplenum = -1;
734         break;
735       case VERTEXORDERING_CASE:
736         elem->glstate.vertexordering = -1;
737         break;
738       case CULLING_CASE:
739         elem->glstate.culling = -1;
740         break;
741       case TWOSIDE_CASE:
742         elem->glstate.twoside = -1;
743         break;
744       case SHADE_MODEL_CASE:
745         elem->glstate.flatshading = -1;
746         break;
747       case ALPHATEST_CASE:
748         elem->glstate.alphatestfunc = -1;
749         elem->glstate.alphatestvalue = -1.0f;
750         break;
751       }
752     }
753   }
754 }
755 
756 void
sendPackedDiffuse(SoState * state,const uint32_t diffuse)757 SoGLLazyElement::sendPackedDiffuse(SoState * state, const uint32_t diffuse)
758 {
759   SbBool cacheopen = state->isCacheOpen();
760   SoGLLazyElement * elem = getInstance(state);
761   if (elem->glstate.diffuse != diffuse) {
762     elem->sendPackedDiffuse(diffuse);
763     if (cacheopen) elem->lazyDidSet(DIFFUSE_MASK|TRANSPARENCY_MASK);
764   }
765   else if (cacheopen) {
766     elem->lazyDidntSet(DIFFUSE_MASK|TRANSPARENCY_MASK);
767   }
768 }
769 
770 void
sendLightModel(SoState * state,const int32_t model)771 SoGLLazyElement::sendLightModel(SoState * state, const int32_t model)
772 {
773   SbBool cacheopen = state->isCacheOpen();
774   SoGLLazyElement * elem = getInstance(state);
775   if (elem->glstate.lightmodel != model) {
776     elem->sendLightModel(model);
777     if (cacheopen) elem->lazyDidSet(LIGHT_MODEL_MASK);
778   }
779   else if (cacheopen) {
780     elem->lazyDidntSet(LIGHT_MODEL_MASK);
781   }
782 }
783 
784 void
sendFlatshading(SoState * state,const SbBool onoff)785 SoGLLazyElement::sendFlatshading(SoState * state, const SbBool onoff)
786 {
787   SbBool cacheopen = state->isCacheOpen();
788   SoGLLazyElement * elem = getInstance(state);
789   if (elem->glstate.flatshading != onoff) {
790     elem->sendFlatshading(onoff);
791     if (cacheopen) elem->lazyDidSet(SHADE_MODEL_MASK);
792   }
793   else if (cacheopen) {
794     elem->lazyDidntSet(SHADE_MODEL_MASK);
795   }
796 }
797 
798 void
sendVertexOrdering(SoState * state,const VertexOrdering ordering)799 SoGLLazyElement::sendVertexOrdering(SoState * state, const VertexOrdering ordering)
800 {
801   SbBool cacheopen = state->isCacheOpen();
802   SoGLLazyElement * elem = getInstance(state);
803   if (elem->glstate.vertexordering != (int32_t) ordering) {
804     elem->sendVertexOrdering(ordering);
805     if (cacheopen) elem->lazyDidSet(VERTEXORDERING_MASK);
806   }
807   else if (cacheopen) {
808     elem->lazyDidntSet(VERTEXORDERING_MASK);
809   }
810 }
811 
812 void
sendTwosideLighting(SoState * state,const SbBool onoff)813 SoGLLazyElement::sendTwosideLighting(SoState * state, const SbBool onoff)
814 {
815   SbBool cacheopen = state->isCacheOpen();
816   SoGLLazyElement * elem = getInstance(state);
817   if (elem->glstate.twoside != (int32_t) onoff) {
818     elem->sendTwosideLighting(onoff);
819     if (cacheopen) elem->lazyDidSet(TWOSIDE_MASK);
820   }
821   else if (cacheopen) {
822     elem->lazyDidntSet(TWOSIDE_MASK);
823   }
824 }
825 
826 void
sendBackfaceCulling(SoState * state,const SbBool onoff)827 SoGLLazyElement::sendBackfaceCulling(SoState * state, const SbBool onoff)
828 {
829   SbBool cacheopen = state->isCacheOpen();
830   SoGLLazyElement * elem = getInstance(state);
831   if (elem->glstate.culling != (int32_t) onoff) {
832     elem->sendBackfaceCulling(onoff);
833     if (cacheopen) elem->lazyDidSet(CULLING_MASK);
834   }
835   else if (cacheopen) {
836     elem->lazyDidntSet(CULLING_MASK);
837   }
838 }
839 
840 void
setDiffuseElt(SoNode * node,int32_t numcolors,const SbColor * colors,SoColorPacker * packer)841 SoGLLazyElement::setDiffuseElt(SoNode * node,  int32_t numcolors,
842                                const SbColor * colors, SoColorPacker * packer)
843 {
844   inherited::setDiffuseElt(node, numcolors, colors, packer);
845   this->colorpacker = packer;
846 }
847 
848 void
setPackedElt(SoNode * node,int32_t numcolors,const uint32_t * colors,const SbBool packedtransparency)849 SoGLLazyElement::setPackedElt(SoNode * node, int32_t numcolors,
850                               const uint32_t * colors, const SbBool packedtransparency)
851 {
852   inherited::setPackedElt(node, numcolors, colors, packedtransparency);
853   this->colorpacker = NULL;
854   this->packedpointer = colors;
855 }
856 
857 void
setColorIndexElt(SoNode * node,int32_t numindices,const int32_t * indices)858 SoGLLazyElement::setColorIndexElt(SoNode * node, int32_t numindices,
859                                   const int32_t * indices)
860 {
861   inherited::setColorIndexElt(node, numindices, indices);
862 }
863 
864 void
setTranspElt(SoNode * node,int32_t numtransp,const float * transp,SoColorPacker * packer)865 SoGLLazyElement::setTranspElt(SoNode * node, int32_t numtransp,
866                               const float * transp, SoColorPacker * packer)
867 {
868   inherited::setTranspElt(node, numtransp, transp, packer);
869   this->colorpacker = packer;
870 }
871 
872 
873 void
setTranspTypeElt(int32_t type)874 SoGLLazyElement::setTranspTypeElt(int32_t type)
875 {
876   inherited::setTranspTypeElt(type);
877   this->transpmask = type == SoGLRenderAction::SCREEN_DOOR ? 0xff : 0x00;
878 }
879 
880 void
setAmbientElt(const SbColor * color)881 SoGLLazyElement::setAmbientElt(const SbColor* color)
882 {
883   inherited::setAmbientElt(color);
884 }
885 
886 void
setEmissiveElt(const SbColor * color)887 SoGLLazyElement::setEmissiveElt(const SbColor* color)
888 {
889   inherited::setEmissiveElt(color);
890 }
891 
892 void
setSpecularElt(const SbColor * color)893 SoGLLazyElement::setSpecularElt(const SbColor* color)
894 {
895   inherited::setSpecularElt(color);
896 }
897 
898 void
setShininessElt(float value)899 SoGLLazyElement::setShininessElt(float value)
900 {
901   inherited::setShininessElt(value);
902 }
903 
904 void
setColorMaterialElt(SbBool value)905 SoGLLazyElement::setColorMaterialElt(SbBool value)
906 {
907   inherited::setColorMaterialElt(value);
908 }
909 
910 void
enableBlendingElt(int sfactor,int dfactor,int alpha_sfactor,int alpha_dfactor)911 SoGLLazyElement::enableBlendingElt(int sfactor, int dfactor, int alpha_sfactor, int alpha_dfactor)
912 {
913   inherited::enableBlendingElt(sfactor, dfactor, alpha_sfactor, alpha_dfactor);
914 }
915 
916 void
disableBlendingElt(void)917 SoGLLazyElement::disableBlendingElt(void)
918 {
919   inherited::disableBlendingElt();
920 }
921 
922 void
setLightModelElt(SoState * stateptr,int32_t model)923 SoGLLazyElement::setLightModelElt(SoState * stateptr, int32_t model)
924 {
925   inherited::setLightModelElt(stateptr, model);
926 }
927 
928 void
setMaterialElt(SoNode * node,uint32_t bitmask,SoColorPacker * packer,const SbColor * diffuse,const int numdiffuse,const float * transp,const int numtransp,const SbColor & ambient,const SbColor & emissive,const SbColor & specular,const float shininess,const SbBool istransparent)929 SoGLLazyElement::setMaterialElt(SoNode * node, uint32_t bitmask,
930                                 SoColorPacker * packer,
931                                 const SbColor * diffuse, const int numdiffuse,
932                                 const float * transp, const int numtransp,
933                                 const SbColor & ambient,
934                                 const SbColor & emissive,
935                                 const SbColor & specular,
936                                 const float shininess,
937                                 const SbBool istransparent)
938 {
939   inherited::setMaterialElt(node, bitmask,
940                             packer, diffuse, numdiffuse,
941                             transp, numtransp, ambient,
942                             emissive, specular, shininess, istransparent);
943   this->colorpacker = packer;
944 }
945 
946 void
setVertexOrderingElt(VertexOrdering ordering)947 SoGLLazyElement::setVertexOrderingElt(VertexOrdering ordering)
948 {
949   inherited::setVertexOrderingElt(ordering);
950 }
951 
952 void
setBackfaceCullingElt(SbBool onoff)953 SoGLLazyElement::setBackfaceCullingElt(SbBool onoff)
954 {
955   inherited::setBackfaceCullingElt(onoff);
956 }
957 
958 void
setTwosideLightingElt(SbBool onoff)959 SoGLLazyElement::setTwosideLightingElt(SbBool onoff)
960 {
961   inherited::setTwosideLightingElt(onoff);
962 }
963 
964 void
setShadeModelElt(SbBool flatshading)965 SoGLLazyElement::setShadeModelElt(SbBool flatshading)
966 {
967   inherited::setShadeModelElt(flatshading);
968 }
969 
970 void
setAlphaTestElt(int func,float value)971 SoGLLazyElement::setAlphaTestElt(int func, float value)
972 {
973   inherited::setAlphaTestElt(func, value);
974 }
975 
976 void
packColors(SoColorPacker * packer) const977 SoGLLazyElement::packColors(SoColorPacker * packer) const
978 {
979   const int n = this->coinstate.numdiffuse;
980   const SbColor * diffuse = this->coinstate.diffusearray;
981   const int numtransp = this->coinstate.numtransp;
982   const float * transp = this->coinstate.transparray;
983 
984   if (packer->getSize() < n) packer->reallocate(n);
985   uint32_t * ptr = packer->getPackedColors();
986 
987   int ti = 0;
988 
989   for (int i = 0; i < n; i++) {
990     ptr[i] = diffuse[i].getPackedValue(transp[ti]);
991     if (ti < numtransp-1) ti++;
992   }
993 
994   packer->setNodeIds(this->coinstate.diffusenodeid,
995                      this->coinstate.transpnodeid);
996 }
997 
998 void
beginCaching(SoState * state,GLState * prestate,GLState * poststate)999 SoGLLazyElement::beginCaching(SoState * state, GLState * prestate,
1000                               GLState * poststate)
1001 {
1002   SoGLLazyElement * elem = getInstance(state);
1003   elem->send(state, ALL_MASK); // send lazy state before starting to build cache
1004   *prestate = elem->glstate; // copy current GL state
1005   prestate->diffusenodeid = elem->coinstate.diffusenodeid;
1006   prestate->transpnodeid = elem->coinstate.transpnodeid;
1007   elem->precachestate = prestate;
1008   elem->postcachestate = poststate;
1009   elem->precachestate->cachebitmask = 0;
1010   elem->postcachestate->cachebitmask = 0;
1011   elem->didsetbitmask = 0;
1012   elem->didntsetbitmask = 0;
1013   elem->cachebitmask = 0;
1014   elem->opencacheflags = 0;
1015 }
1016 
1017 void
endCaching(SoState * state)1018 SoGLLazyElement::endCaching(SoState * state)
1019 {
1020   SoGLLazyElement * elem = getInstance(state);
1021 
1022   *elem->postcachestate = elem->glstate;
1023   elem->postcachestate->cachebitmask = elem->cachebitmask;
1024   elem->precachestate->cachebitmask = elem->didntsetbitmask;
1025 
1026   // unset diffuse mask since it's used by the dependency test
1027   elem->precachestate->cachebitmask &= ~DIFFUSE_MASK;
1028 
1029   // set diffuse mask if this cache depends on a material outside the
1030   // cache.
1031   if (elem->opencacheflags & FLAG_DIFFUSE_DEPENDENCY) {
1032     elem->precachestate->cachebitmask |= DIFFUSE_MASK;
1033   }
1034 
1035   elem->precachestate = NULL;
1036   elem->postcachestate = NULL;
1037   elem->opencacheflags = 0;
1038 }
1039 
1040 void
postCacheCall(const SoState * state,const GLState * poststate)1041 SoGLLazyElement::postCacheCall(const SoState * state, const GLState * poststate)
1042 {
1043   SoGLLazyElement * elem = getInstance(state);
1044   uint32_t mask = poststate->cachebitmask;
1045 
1046   for (int i = 0; (i < LAZYCASES_LAST)&&mask; i++, mask>>=1) {
1047     if (mask&1) {
1048       switch (i) {
1049       case LIGHT_MODEL_CASE:
1050         elem->glstate.lightmodel = poststate->lightmodel;
1051         break;
1052       case DIFFUSE_CASE:
1053         elem->glstate.diffuse = poststate->diffuse;
1054         break;
1055       case AMBIENT_CASE:
1056         elem->glstate.ambient = poststate->ambient;
1057         break;
1058       case SPECULAR_CASE:
1059         elem->glstate.specular = poststate->specular;
1060         break;
1061       case EMISSIVE_CASE:
1062         elem->glstate.emissive = poststate->emissive;
1063         break;
1064       case SHININESS_CASE:
1065         elem->glstate.shininess = poststate->shininess;
1066         break;
1067       case BLENDING_CASE:
1068         elem->glstate.blending = poststate->blending;
1069         elem->glstate.blend_sfactor = poststate->blend_sfactor;
1070         elem->glstate.blend_dfactor = poststate->blend_dfactor;
1071         elem->glstate.alpha_blend_sfactor = poststate->alpha_blend_sfactor;
1072         elem->glstate.alpha_blend_dfactor = poststate->alpha_blend_dfactor;
1073         break;
1074       case TRANSPARENCY_CASE:
1075         elem->glstate.stipplenum = poststate->stipplenum;
1076         break;
1077       case VERTEXORDERING_CASE:
1078         elem->glstate.vertexordering = poststate->vertexordering;
1079         break;
1080       case CULLING_CASE:
1081         elem->glstate.culling = poststate->culling;
1082         break;
1083       case TWOSIDE_CASE:
1084         elem->glstate.twoside = poststate->twoside;
1085         break;
1086       case SHADE_MODEL_CASE:
1087         elem->glstate.flatshading = poststate->flatshading;
1088         break;
1089       case ALPHATEST_CASE:
1090         elem->glstate.alphatestfunc = poststate->alphatestfunc;
1091         elem->glstate.alphatestvalue = poststate->alphatestvalue;
1092         break;
1093       }
1094     }
1095   }
1096 }
1097 
1098 SbBool
preCacheCall(const SoState * state,const GLState * prestate)1099 SoGLLazyElement::preCacheCall(const SoState * state, const GLState * prestate)
1100 {
1101   SoGLLazyElement * elem = getInstance(state);
1102 
1103   struct CoinState & curr = elem->coinstate;
1104   uint32_t mask = prestate->cachebitmask;
1105 
1106   for (int i = 0; (i < LAZYCASES_LAST)&&mask; i++, mask>>=1) {
1107     if (mask&1) {
1108       switch (i) {
1109       case LIGHT_MODEL_CASE:
1110         if (curr.lightmodel != prestate->lightmodel) {
1111           GLLAZY_DEBUG("light model failed");
1112           return FALSE;
1113         }
1114         break;
1115       case DIFFUSE_CASE:
1116         // this is a special case, since we can have multiple diffuse
1117         // and transparency values. Check the node ids.
1118         if ((prestate->diffusenodeid != curr.diffusenodeid) ||
1119             (prestate->transpnodeid != curr.transpnodeid)) {
1120           GLLAZY_DEBUG("material dependency failed");
1121           return FALSE;
1122         }
1123         break;
1124       case AMBIENT_CASE:
1125         if (curr.ambient != prestate->ambient) {
1126           GLLAZY_DEBUG("ambient failed");
1127           return FALSE;
1128         }
1129         break;
1130       case SPECULAR_CASE:
1131         if (curr.specular != prestate->specular) {
1132           GLLAZY_DEBUG("specular failed");
1133           return FALSE;
1134         }
1135         break;
1136       case EMISSIVE_CASE:
1137         if (curr.emissive != prestate->emissive) {
1138           GLLAZY_DEBUG("emissive failed");
1139           return FALSE;
1140         }
1141         break;
1142       case SHININESS_CASE:
1143         if (curr.shininess != prestate->shininess) {
1144           GLLAZY_DEBUG("shininess failed");
1145           return FALSE;
1146         }
1147         break;
1148       case BLENDING_CASE:
1149         if (curr.blending != prestate->blending) {
1150           GLLAZY_DEBUG("blending failed");
1151           return FALSE;
1152         }
1153         if (prestate->blending) {
1154           if (curr.blend_sfactor != prestate->blend_sfactor ||
1155               curr.blend_dfactor != prestate->blend_dfactor ||
1156               curr.alpha_blend_sfactor != prestate->alpha_blend_sfactor ||
1157               curr.alpha_blend_dfactor != prestate->alpha_blend_dfactor) {
1158             GLLAZY_DEBUG("blending failed");
1159             return FALSE;
1160           }
1161         }
1162         break;
1163       case TRANSPARENCY_CASE:
1164         if (curr.stipplenum != prestate->stipplenum) {
1165           GLLAZY_DEBUG("transparency failed");
1166           return FALSE;
1167         }
1168         break;
1169       case VERTEXORDERING_CASE:
1170         if (curr.vertexordering != prestate->vertexordering) {
1171           GLLAZY_DEBUG("vertexordering failed");
1172           return FALSE;
1173         }
1174         break;
1175       case CULLING_CASE:
1176         if (curr.culling != prestate->culling) {
1177           GLLAZY_DEBUG("culling failed");
1178           return FALSE;
1179         }
1180         break;
1181       case TWOSIDE_CASE:
1182         if (curr.twoside != prestate->twoside) {
1183           GLLAZY_DEBUG("twoside failed");
1184           return FALSE;
1185         }
1186         break;
1187       case SHADE_MODEL_CASE:
1188         if (curr.flatshading != prestate->flatshading) {
1189           GLLAZY_DEBUG("shade model failed");
1190           return FALSE;
1191         }
1192         break;
1193       case ALPHATEST_CASE:
1194         if (curr.alphatestfunc != prestate->alphatestfunc ||
1195             curr.alphatestvalue != prestate->alphatestvalue) {
1196           GLLAZY_DEBUG("alphatest failed");
1197           return FALSE;
1198         }
1199         break;
1200       }
1201     }
1202   }
1203   return TRUE;
1204 }
1205 
1206 
1207 void
lazyDidSet(uint32_t mask)1208 SoGLLazyElement::lazyDidSet(uint32_t mask)
1209 {
1210   if (mask & DIFFUSE_MASK) {
1211     if (!(this->didsetbitmask & DIFFUSE_MASK)) {
1212       // to be safe, always send first diffuse when a cache is open
1213       this->opencacheflags |= FLAG_FORCE_DIFFUSE;
1214     }
1215   }
1216   this->didsetbitmask |= mask;
1217 }
1218 
1219 void
lazyDidntSet(uint32_t mask)1220 SoGLLazyElement::lazyDidntSet(uint32_t mask)
1221 {
1222   if (mask & DIFFUSE_MASK) {
1223     if (!(this->didsetbitmask & DIFFUSE_MASK)) {
1224       // to be safe, always send first diffuse when a cache is open
1225       this->didsetbitmask |= DIFFUSE_MASK;
1226       this->opencacheflags = FLAG_FORCE_DIFFUSE;
1227     }
1228   }
1229   this->didntsetbitmask |= mask&(~this->didsetbitmask);
1230 }
1231 
1232 void
updateColorVBO(SoVBO * vbo)1233 SoGLLazyElement::updateColorVBO(SoVBO * vbo)
1234 {
1235   if (this->colorpacker) {
1236     SbUniqueId maxid = this->colorpacker->getDiffuseId();
1237     SbUniqueId tid = this->colorpacker->getTranspId();
1238     if (tid > maxid) {
1239       maxid = tid;
1240     }
1241     SbUniqueId vboid = vbo->getBufferDataId();
1242     if (vboid != maxid) {
1243       const int n = this->coinstate.numdiffuse;
1244       // need to update the VBO
1245       const uint32_t * src = this->colorpacker->getPackedColors();
1246       if (coin_host_get_endianness() == COIN_HOST_IS_BIGENDIAN) {
1247         vbo->setBufferData(src, n * sizeof(uint32_t),
1248                            maxid);
1249       }
1250       else {
1251         uint32_t * dst = (uint32_t*)
1252           vbo->allocBufferData(n * sizeof(uint32_t),
1253                                maxid);
1254         for (int i = 0; i < n; i++) {
1255           uint32_t tmp = src[i];
1256           dst[i] =
1257             (tmp << 24) |
1258             ((tmp & 0xff00) << 8) |
1259             ((tmp & 0xff0000) >> 8) |
1260             (tmp >> 24);
1261         }
1262       }
1263     }
1264   }
1265 }
1266 
1267 /*!
1268   Merge cache info from a child cache (when doing nested caching)
1269   into the current cache.
1270 */
1271 void
mergeCacheInfo(SoState * state,SoGLLazyElement::GLState * childprestate,SoGLLazyElement::GLState * childpoststate)1272 SoGLLazyElement::mergeCacheInfo(SoState * state,
1273                                 SoGLLazyElement::GLState * childprestate,
1274                                 SoGLLazyElement::GLState * childpoststate)
1275 {
1276   SoGLLazyElement * elt = SoGLLazyElement::getInstance(state);
1277 
1278   // just add pre-dependencies from child cache
1279   elt->lazyDidntSet(childprestate->cachebitmask);
1280 
1281   // update current element's didsetbitmask
1282   elt->lazyDidSet(childpoststate->cachebitmask);
1283 
1284   // also update cachebitmask so that the current cache knows about the changes
1285   // done by the child cache
1286   elt->cachebitmask |= childpoststate->cachebitmask;
1287 }
1288 
1289 #undef FLAG_FORCE_DIFFUSE
1290 #undef FLAG_DIFFUSE_DEPENDENCY
1291 #undef GLLAZY_DEBUG
1292