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 SoLazyElement Inventor/elements/SoLazyElement.h
35   \brief The SoLazyElement class is used to handle material and shape properties.
36 
37   \ingroup elements
38 
39   So[GL]LazyElement is, as the name implies, an element that is lazy
40   about sending things to OpenGL. The changes are not sent to OpenGL
41   until SoGLLazyElement::send() is called. This means that you can
42   change the state of certain attributes several times, but the state
43   will only be sent to OpenGL once.
44 
45   When creating a new shape node in Coin, it's a common operation to
46   modify the OpenGL diffuse color.  There are several ways you can
47   send the color to OpenGL. If you're not going to use the color
48   outside your node, you can just as well send it using plain
49   OpenGL. You can also set the color in the element, and then force a
50   send by using SoGLLazyElement::send(state,
51   SoLazyElement::DIFFUSE_MASK).
52 
53   However, when creating an extension shape node, it's always
54   recommended to create an instance of SoMaterialBundle on the
55   stack. If this instance is created after you update SoLazyElement
56   with a new color, the new color will be sent to OpenGL when you call
57   SoMaterialBundle::sendFirst(). This call will also update all other
58   lazy OpenGL state, and it's actually required to either use
59   SoMaterialBundle::sendFirst() or call SoGLLazyElement::send(state,
60   SoLazyElement::ALL_MASK) when creating a shape node.
61 
62   If you decide to send the color to OpenGL using glColor*(), you
63   should notify SoGLLazyElement about this by calling
64   SoGLLazyElement::reset(state, SoLazyElement::DIFFUSE_MASK). This
65   will notify SoGLLazyElement that the current OpenGL diffuse color is
66   unknown.
67 */
68 
69 #include "coindefs.h"
70 #include "tidbitsp.h"
71 #include "SbBasicP.h"
72 
73 #include <Inventor/elements/SoLazyElement.h>
74 
75 #include <cassert>
76 #include <cstring>
77 
78 #include <Inventor/actions/SoGLRenderAction.h>
79 #include <Inventor/elements/SoShapeStyleElement.h>
80 #include <Inventor/elements/SoGLVBOElement.h>
81 #include <Inventor/fields/SoMFColor.h>
82 #include <Inventor/fields/SoMFFloat.h>
83 #include <Inventor/misc/SoState.h>
84 #include <Inventor/nodes/SoNode.h>
85 
86 static SbColor * lazy_defaultdiffuse = NULL;
87 static float * lazy_defaulttransp = NULL;
88 static int32_t * lazy_defaultindex = NULL;
89 static uint32_t * lazy_defaultpacked = NULL;
90 static SbColor * lazy_unpacked = NULL;
91 
92 extern "C" {
93 
94 static void
lazyelement_cleanup(void)95 lazyelement_cleanup(void)
96 {
97   delete lazy_defaultdiffuse;
98   delete lazy_defaulttransp;
99   delete lazy_defaultindex;
100   delete lazy_defaultpacked;
101   delete lazy_unpacked;
102   lazy_defaultdiffuse = NULL; // Only need to NULL this; see initClass().
103 }
104 
105 } // extern "C"
106 
107 // helper functions to handle default diffuse/transp values
108 static SbUniqueId
get_diffuse_node_id(SoNode * node,const int numdiffuse,const SbColor * color)109 get_diffuse_node_id(SoNode * node, const int numdiffuse,
110                     const SbColor * color)
111 {
112   if (numdiffuse == 1 && color[0] == SbColor(0.8f, 0.8f, 0.8f)) return 0;
113   return node->getNodeId();
114 }
115 
116 static SbUniqueId
get_transp_node_id(SoNode * node,const int numtransp,const float * transp)117 get_transp_node_id(SoNode * node, const int numtransp,
118                    const float * transp)
119 {
120   if (numtransp == 1 && transp[0] == 0.0f) return 0;
121   return node->getNodeId();
122 }
123 
124 
125 SO_ELEMENT_SOURCE(SoLazyElement);
126 
127 /*!
128   This static method initializes static data for the
129   SoDiffuseColorElement class.
130 */
131 
132 void
initClass()133 SoLazyElement::initClass()
134 {
135   SO_ELEMENT_INIT_CLASS(SoLazyElement, inherited);
136 
137   if (lazy_defaultdiffuse == NULL) {
138     lazy_defaultdiffuse = new SbColor;
139     lazy_defaulttransp = new float;
140     lazy_defaultindex = new int32_t;
141     lazy_defaultpacked = new uint32_t;
142     lazy_unpacked = new SbColor;
143 
144     *lazy_defaultdiffuse = getDefaultDiffuse();
145     *lazy_defaulttransp = getDefaultTransparency();
146     *lazy_defaultindex = getDefaultColorIndex();
147     *lazy_defaultpacked = getDefaultPacked();
148 
149     coin_atexit(lazyelement_cleanup, CC_ATEXIT_NORMAL);
150   }
151 }
152 
153 // ! FIXME: write doc
154 
~SoLazyElement()155 SoLazyElement::~SoLazyElement()
156 {
157 }
158 
159 // ! FIXME: write doc
160 
161 void
init(SoState * COIN_UNUSED_ARG (state))162 SoLazyElement::init(SoState * COIN_UNUSED_ARG(state))
163 {
164   this->coinstate.ambient = this->getDefaultAmbient();
165   this->coinstate.specular = this->getDefaultSpecular();
166   this->coinstate.emissive = this->getDefaultEmissive();
167   this->coinstate.shininess = this->getDefaultShininess();
168   this->coinstate.blending = FALSE;
169   this->coinstate.blend_sfactor = 0;
170   this->coinstate.blend_dfactor = 0;
171   this->coinstate.alpha_blend_sfactor = 0;
172   this->coinstate.alpha_blend_dfactor = 0;
173   this->coinstate.lightmodel = PHONG;
174   this->coinstate.packeddiffuse = FALSE;
175   this->coinstate.numdiffuse = 1;
176   this->coinstate.numtransp = 1;
177   this->coinstate.diffusearray = lazy_defaultdiffuse;
178   this->coinstate.packedarray = lazy_defaultpacked;
179   this->coinstate.transparray = lazy_defaulttransp;
180   this->coinstate.colorindexarray = lazy_defaultindex;
181   this->coinstate.istransparent = FALSE;
182   this->coinstate.transptype = static_cast<int32_t>(SoGLRenderAction::BLEND);
183   this->coinstate.diffusenodeid = 0;
184   this->coinstate.transpnodeid = 0;
185   this->coinstate.stipplenum = 0;
186   this->coinstate.vertexordering = CCW;
187   this->coinstate.twoside = FALSE;
188   this->coinstate.culling = FALSE;
189   this->coinstate.flatshading = FALSE;
190   this->coinstate.alphatestfunc = 0;
191   this->coinstate.alphatestvalue = 0.5f;
192 }
193 
194 // ! FIXME: write doc
195 
196 void
push(SoState * state)197 SoLazyElement::push(SoState *state)
198 {
199   inherited::push(state);
200   const SoLazyElement * prev = coin_assert_cast<const SoLazyElement *>(this->getNextInStack());
201   this->coinstate = prev->coinstate;
202 }
203 
204 
205 /*!
206   Will always return TRUE in Coin.
207 */
208 SbBool
matches(const SoElement * COIN_UNUSED_ARG (element)) const209 SoLazyElement::matches(const SoElement * COIN_UNUSED_ARG(element)) const
210 {
211   assert(0 && "should never happen");
212   return TRUE;
213 }
214 
215 /*!
216   Just returns NULL in Coin.
217 */
218 SoElement *
copyMatchInfo(void) const219 SoLazyElement::copyMatchInfo(void) const
220 {
221   assert(0 && "should never happen");
222   return NULL;
223 }
224 
225 /*!
226   Internal function used for resetting the OpenGL state before FBO
227   rendering.
228 */
229 void
setToDefault(SoState * state)230 SoLazyElement::setToDefault(SoState * state)
231 {
232   SoLazyElement * elem = SoLazyElement::getWInstance(state);
233   elem->SoLazyElement::init(state);
234 }
235 
236 // ! FIXME: write doc
237 
238 void
setDiffuse(SoState * state,SoNode * node,int32_t numcolors,const SbColor * colors,SoColorPacker * packer)239 SoLazyElement::setDiffuse(SoState * state, SoNode * node, int32_t numcolors,
240                           const SbColor * colors, SoColorPacker * packer)
241 {
242   if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
243     SoGLVBOElement::setColorVBO(state, NULL);
244   }
245   SoLazyElement * elem = SoLazyElement::getInstance(state);
246   if (numcolors && (elem->coinstate.diffusenodeid !=
247                     get_diffuse_node_id(node, numcolors, colors))) {
248     elem = getWInstance(state);
249     elem->setDiffuseElt(node, numcolors, colors, packer);
250     if (state->isCacheOpen()) elem->lazyDidSet(DIFFUSE_MASK);
251   }
252   else if (state->isCacheOpen()) {
253     elem->lazyDidntSet(DIFFUSE_MASK);
254   }
255 }
256 
257 // ! FIXME: write doc
258 
259 void
setTransparency(SoState * state,SoNode * node,int32_t numvalues,const float * transparency,SoColorPacker * packer)260 SoLazyElement::setTransparency(SoState *state, SoNode *node, int32_t numvalues,
261                                const float * transparency, SoColorPacker * packer)
262 {
263   if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
264     SoGLVBOElement::setColorVBO(state, NULL);
265   }
266   SoLazyElement * elem = SoLazyElement::getInstance(state);
267   if (numvalues && (elem->coinstate.transpnodeid !=
268                     get_transp_node_id(node, numvalues, transparency))) {
269     elem = getWInstance(state);
270     elem->setTranspElt(node, numvalues, transparency, packer);
271     if (state->isCacheOpen()) elem->lazyDidSet(TRANSPARENCY_MASK);
272   }
273   else if (state->isCacheOpen()) {
274     elem->lazyDidntSet(TRANSPARENCY_MASK);
275   }
276   SoShapeStyleElement::setTransparentMaterial(state, elem->coinstate.istransparent);
277 }
278 
279 // ! FIXME: write doc
280 
281 void
setPacked(SoState * state,SoNode * node,int32_t numcolors,const uint32_t * colors,const SbBool packedtransparency)282 SoLazyElement::setPacked(SoState * state, SoNode * node,
283                          int32_t numcolors, const uint32_t * colors,
284                          const SbBool packedtransparency)
285 {
286   if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
287     SoGLVBOElement::setColorVBO(state, NULL);
288   }
289   SoLazyElement * elem = SoLazyElement::getInstance(state);
290   if (numcolors && elem->coinstate.diffusenodeid != node->getNodeId()) {
291     elem = getWInstance(state);
292     elem->setPackedElt(node, numcolors, colors, packedtransparency);
293     if (state->isCacheOpen()) elem->lazyDidSet(TRANSPARENCY_MASK|DIFFUSE_MASK);
294   }
295   else if (state->isCacheOpen()) {
296     elem->lazyDidntSet(TRANSPARENCY_MASK|DIFFUSE_MASK);
297   }
298   SoShapeStyleElement::setTransparentMaterial(state, elem->coinstate.istransparent);
299 }
300 
301 // ! FIXME: write doc
302 
303 void
setColorIndices(SoState * state,SoNode * node,int32_t numindices,const int32_t * indices)304 SoLazyElement::setColorIndices(SoState *state, SoNode *node,
305                                int32_t numindices, const int32_t * indices)
306 {
307   SoLazyElement * elem = SoLazyElement::getInstance(state);
308   if (numindices && elem->coinstate.diffusenodeid != node->getNodeId()) {
309     elem = getWInstance(state);
310     elem->setColorIndexElt(node, numindices, indices);
311     if (state->isCacheOpen()) elem->lazyDidSet(DIFFUSE_MASK);
312   }
313   else if (state->isCacheOpen()) {
314     elem->lazyDidntSet(DIFFUSE_MASK);
315   }
316 }
317 
318 // ! FIXME: write doc
319 
320 void
setAmbient(SoState * state,const SbColor * color)321 SoLazyElement::setAmbient(SoState *state, const SbColor* color)
322 {
323   SoLazyElement * elem = SoLazyElement::getInstance(state);
324   if (elem->coinstate.ambient != *color) {
325     elem = getWInstance(state);
326     elem->setAmbientElt(color);
327     if (state->isCacheOpen()) elem->lazyDidSet(AMBIENT_MASK);
328   }
329   else if (state->isCacheOpen()) {
330     elem->lazyDidntSet(AMBIENT_MASK);
331   }
332 }
333 
334 // ! FIXME: write doc
335 
336 void
setEmissive(SoState * state,const SbColor * color)337 SoLazyElement::setEmissive(SoState *state, const SbColor* color)
338 {
339   SoLazyElement * elem = SoLazyElement::getInstance(state);
340   if (elem->coinstate.emissive != *color) {
341     elem = getWInstance(state);
342     elem->setEmissiveElt(color);
343     if (state->isCacheOpen()) elem->lazyDidSet(EMISSIVE_MASK);
344   }
345   else if (state->isCacheOpen()) {
346     elem->lazyDidntSet(EMISSIVE_MASK);
347   }
348 }
349 
350 // ! FIXME: write doc
351 
352 void
setSpecular(SoState * state,const SbColor * color)353 SoLazyElement::setSpecular(SoState *state, const SbColor* color)
354 {
355   SoLazyElement * elem = SoLazyElement::getInstance(state);
356   if (elem->coinstate.specular != *color) {
357     elem = getWInstance(state);
358     elem->setSpecularElt(color);
359     if (state->isCacheOpen()) elem->lazyDidSet(SPECULAR_MASK);
360   }
361   else if (state->isCacheOpen()) {
362     elem->lazyDidntSet(SPECULAR_MASK);
363   }
364 }
365 
366 // ! FIXME: write doc
367 
368 void
setShininess(SoState * state,float value)369 SoLazyElement::setShininess(SoState *state, float value)
370 {
371   SoLazyElement * elem = SoLazyElement::getInstance(state);
372   if (SbAbs(elem->coinstate.shininess - value) > SO_LAZY_SHINY_THRESHOLD) {
373     elem = getWInstance(state);
374     elem->setShininessElt(value);
375     if (state->isCacheOpen()) elem->lazyDidSet(SHININESS_MASK);
376   }
377   else if (state->isCacheOpen()) {
378     elem->lazyDidntSet(SHININESS_MASK);
379   }
380 }
381 
382 // ! FIXME: write doc
383 
384 void
setColorMaterial(SoState * COIN_UNUSED_ARG (state),SbBool COIN_UNUSED_ARG (value))385 SoLazyElement::setColorMaterial(SoState * COIN_UNUSED_ARG(state), SbBool COIN_UNUSED_ARG(value))
386 {
387 }
388 
389 // ! FIXME: write doc
390 
391 void
enableBlending(SoState * state,int sfactor,int dfactor)392 SoLazyElement::enableBlending(SoState * state,  int sfactor, int dfactor)
393 {
394   SoLazyElement::enableSeparateBlending(state, sfactor, dfactor, 0, 0);
395 }
396 
397 void
enableSeparateBlending(SoState * state,int sfactor,int dfactor,int alpha_sfactor,int alpha_dfactor)398 SoLazyElement::enableSeparateBlending(SoState * state,
399                                       int sfactor, int dfactor,
400                                       int alpha_sfactor, int alpha_dfactor)
401 {
402   SoLazyElement * elem = SoLazyElement::getInstance(state);
403   if (!elem->coinstate.blending ||
404       elem->coinstate.blend_sfactor != sfactor ||
405       elem->coinstate.blend_dfactor != dfactor ||
406       elem->coinstate.alpha_blend_sfactor != alpha_sfactor ||
407       elem->coinstate.alpha_blend_dfactor != alpha_dfactor) {
408     elem = getWInstance(state);
409     elem->enableBlendingElt(sfactor, dfactor, alpha_sfactor, alpha_dfactor);
410     if (state->isCacheOpen()) elem->lazyDidSet(BLENDING_MASK);
411   }
412   else if (state->isCacheOpen()) {
413     elem->lazyDidntSet(BLENDING_MASK);
414   }
415 }
416 
417 // ! FIXME: write doc
418 
419 void
disableBlending(SoState * state)420 SoLazyElement::disableBlending(SoState * state)
421 {
422   SoLazyElement * elem = SoLazyElement::getInstance(state);
423   if (elem->coinstate.blending) {
424     elem = getWInstance(state);
425     elem->disableBlendingElt();
426     if (state->isCacheOpen()) elem->lazyDidSet(BLENDING_MASK);
427   }
428   else if (state->isCacheOpen()) {
429     elem->lazyDidntSet(BLENDING_MASK);
430   }
431 }
432 
433 // ! FIXME: write doc
434 
435 void
setLightModel(SoState * state,const int32_t model)436 SoLazyElement::setLightModel(SoState * state, const int32_t model)
437 {
438   SoLazyElement * elem = SoLazyElement::getInstance(state);
439   if (elem->coinstate.lightmodel != model) {
440     elem = getWInstance(state);
441     elem->setLightModelElt(state, model);
442     if (state->isCacheOpen()) elem->lazyDidSet(LIGHT_MODEL_MASK);
443   }
444   else if (state->isCacheOpen()) {
445     elem->lazyDidntSet(LIGHT_MODEL_MASK);
446   }
447 }
448 
449 // ! FIXME: write doc
450 
451 const SbColor &
getDiffuse(SoState * state,int index)452 SoLazyElement::getDiffuse(SoState * state, int index)
453 {
454   SoLazyElement * elem = getInstance(state);
455   if (elem->coinstate.packeddiffuse) {
456     float dummy;
457     return lazy_unpacked->setPackedValue(elem->coinstate.packedarray[index], dummy);
458   }
459   return elem->coinstate.diffusearray[index];
460 }
461 
462 // ! FIXME: write doc
463 
464 float
getTransparency(SoState * state,int index)465 SoLazyElement::getTransparency(SoState *state, int index)
466 {
467   SoLazyElement * elem = getInstance(state);
468 
469   if (elem->coinstate.packeddiffuse) {
470     float transp;
471     SbColor dummy;
472     const int numt = elem->coinstate.numdiffuse;
473     dummy.setPackedValue(elem->coinstate.packedarray[index < numt ? index : numt-1], transp);
474     return transp;
475   }
476   const int numt = elem->coinstate.numtransp;
477   return elem->coinstate.transparray[index < numt ? index : numt-1];
478 }
479 
480 // ! FIXME: write doc
481 
482 const uint32_t *
getPackedColors(SoState * state)483 SoLazyElement::getPackedColors(SoState * state)
484 {
485   SoLazyElement * elem = getInstance(state);
486   return elem->coinstate.packedarray;
487 }
488 
489 // ! FIXME: write doc
490 
491 const int32_t *
getColorIndices(SoState * state)492 SoLazyElement::getColorIndices(SoState * state)
493 {
494   SoLazyElement * elem = getInstance(state);
495   return elem->coinstate.colorindexarray;
496 }
497 
498 // ! FIXME: write doc
499 
500 int32_t
getColorIndex(SoState * state,int num)501 SoLazyElement::getColorIndex(SoState * state, int num)
502 {
503   SoLazyElement * elem = getInstance(state);
504   return elem->coinstate.colorindexarray[num];
505 }
506 
507 // ! FIXME: write doc
508 
509 const SbColor &
getAmbient(SoState * state)510 SoLazyElement::getAmbient(SoState * state)
511 {
512   SoLazyElement * elem = getInstance(state);
513   return elem->coinstate.ambient;
514 }
515 
516 // ! FIXME: write doc
517 
518 const SbColor &
getEmissive(SoState * state)519 SoLazyElement::getEmissive(SoState * state)
520 {
521   SoLazyElement * elem = getInstance(state);
522   return elem->coinstate.emissive;
523 }
524 
525 // ! FIXME: write doc
526 
527 const SbColor &
getSpecular(SoState * state)528 SoLazyElement::getSpecular(SoState * state)
529 {
530   SoLazyElement * elem = getInstance(state);
531   return elem->coinstate.specular;
532 }
533 
534 // ! FIXME: write doc
535 
536 float
getShininess(SoState * state)537 SoLazyElement::getShininess(SoState * state)
538 {
539   SoLazyElement * elem = getInstance(state);
540   return elem->coinstate.shininess;
541 }
542 
543 // ! FIXME: write doc
544 
545 SbBool
getColorMaterial(SoState * COIN_UNUSED_ARG (state))546 SoLazyElement::getColorMaterial(SoState * COIN_UNUSED_ARG(state))
547 {
548   return TRUE;
549 }
550 
551 // ! FIXME: write doc
552 
553 SbBool
getBlending(SoState * state,int & sfactor,int & dfactor)554 SoLazyElement::getBlending(SoState * state, int & sfactor, int & dfactor)
555 {
556   SoLazyElement * elem = getInstance(state);
557   sfactor = elem->coinstate.blend_sfactor;
558   dfactor = elem->coinstate.blend_dfactor;
559   return elem->coinstate.blending;
560 }
561 
562 SbBool
getAlphaBlending(SoState * state,int & sfactor,int & dfactor)563 SoLazyElement::getAlphaBlending(SoState * state, int & sfactor, int & dfactor)
564 {
565   SoLazyElement * elem = getInstance(state);
566   sfactor = elem->coinstate.alpha_blend_sfactor;
567   dfactor = elem->coinstate.alpha_blend_dfactor;
568 
569   return elem->coinstate.blending && (sfactor != 0) && (dfactor != 0);
570 }
571 
572 // ! FIXME: write doc
573 
574 int32_t
getLightModel(SoState * state)575 SoLazyElement::getLightModel(SoState * state)
576 {
577   SoLazyElement * elem = getInstance(state);
578   return elem->coinstate.lightmodel;
579 }
580 
581 SbBool
getTwoSidedLighting(SoState * state)582 SoLazyElement::getTwoSidedLighting(SoState * state)
583 {
584   SoLazyElement * elem = getInstance(state);
585   return elem->coinstate.twoside;
586 }
587 
588 // ! FIXME: write doc
589 int
getAlphaTest(SoState * state,float & value)590 SoLazyElement::getAlphaTest(SoState * state, float & value)
591 {
592   SoLazyElement * elem = getInstance(state);
593   value = elem->coinstate.alphatestvalue;
594   return elem->coinstate.alphatestfunc;
595 }
596 
597 // ! FIXME: write doc
598 
599 int32_t
getNumDiffuse(void) const600 SoLazyElement::getNumDiffuse(void) const
601 {
602   return this->coinstate.numdiffuse;
603 }
604 
605 // ! FIXME: write doc
606 
607 int32_t
getNumTransparencies(void) const608 SoLazyElement::getNumTransparencies(void) const
609 {
610   if (this->coinstate.packeddiffuse) {
611     return this->coinstate.numdiffuse;
612   }
613   return this->coinstate.numtransp;
614 }
615 
616 // ! FIXME: write doc
617 
618 int32_t
getNumColorIndices(void) const619 SoLazyElement::getNumColorIndices(void) const
620 {
621   return this->coinstate.numdiffuse;
622 }
623 
624 // ! FIXME: write doc
625 
626 SbBool
isPacked(void) const627 SoLazyElement::isPacked(void) const
628 {
629   return this->coinstate.packeddiffuse;
630 }
631 
632 // ! FIXME: write doc
633 
634 SbBool
isTransparent(void) const635 SoLazyElement::isTransparent(void) const
636 {
637   return this->coinstate.istransparent;
638 }
639 
640 // ! FIXME: write doc
641 
642 SoLazyElement *
getInstance(SoState * state)643 SoLazyElement::getInstance(SoState *state)
644 {
645   return
646     coin_safe_cast<SoLazyElement *>
647     (
648      state->getElementNoPush(classStackIndex)
649      );
650 }
651 
652 // ! FIXME: write doc
653 
654 float
getDefaultAmbientIntensity(void)655 SoLazyElement::getDefaultAmbientIntensity(void)
656 {
657   return 0.2f;
658 }
659 
660 // ! FIXME: write doc
661 
662 SbColor
getDefaultDiffuse(void)663 SoLazyElement::getDefaultDiffuse(void)
664 {
665   return SbColor(0.8f, 0.8f, 0.8f);
666 }
667 
668 // ! FIXME: write doc
669 
670 SbColor
getDefaultAmbient(void)671 SoLazyElement::getDefaultAmbient(void)
672 {
673   return SbColor(0.2f, 0.2f, 0.2f);
674 }
675 
676 // ! FIXME: write doc
677 
678 SbColor
getDefaultSpecular(void)679 SoLazyElement::getDefaultSpecular(void)
680 {
681   return SbColor(0.0f, 0.0f, 0.0f);
682 }
683 
684 // ! FIXME: write doc
685 
686 SbColor
getDefaultEmissive(void)687 SoLazyElement::getDefaultEmissive(void)
688 {
689   return SbColor(0.0f, 0.0f, 0.0f);
690 }
691 
692 // ! FIXME: write doc
693 
694 float
getDefaultShininess(void)695 SoLazyElement::getDefaultShininess(void)
696 {
697   return 0.2f;
698 }
699 
700 // ! FIXME: write doc
701 
702 uint32_t
getDefaultPacked(void)703 SoLazyElement::getDefaultPacked(void)
704 {
705   return 0xccccccff;
706 }
707 
708 // ! FIXME: write doc
709 
710 float
getDefaultTransparency(void)711 SoLazyElement::getDefaultTransparency(void)
712 {
713   return 0.0f;
714 }
715 
716 // ! FIXME: write doc
717 
718 int32_t
getDefaultLightModel(void)719 SoLazyElement::getDefaultLightModel(void)
720 {
721   return static_cast<int32_t>(SoLazyElement::PHONG);
722 }
723 
724 // ! FIXME: write doc
725 
726 int32_t
getDefaultColorIndex(void)727 SoLazyElement::getDefaultColorIndex(void)
728 {
729   return 0;
730 }
731 
732 // ! FIXME: write doc
733 
734 void
setMaterials(SoState * state,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)735 SoLazyElement::setMaterials(SoState * state, SoNode *node, uint32_t bitmask,
736                             SoColorPacker * packer,
737                             const SbColor * diffuse,
738                             const int numdiffuse,
739                             const float * transp,
740                             const int numtransp,
741                             const SbColor & ambient,
742                             const SbColor & emissive,
743                             const SbColor & specular,
744                             const float shininess,
745                             const SbBool istransparent)
746 {
747   if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
748     SoGLVBOElement::setColorVBO(state, NULL);
749   }
750   SoLazyElement * elem = SoLazyElement::getInstance(state);
751 
752   uint32_t eltbitmask = 0;
753   if (bitmask & DIFFUSE_MASK) {
754     if (elem->coinstate.diffusenodeid !=
755         get_diffuse_node_id(node, numdiffuse, diffuse)) {
756       eltbitmask |= DIFFUSE_MASK;
757     }
758   }
759   if (bitmask & TRANSPARENCY_MASK) {
760     if (elem->coinstate.transpnodeid != get_transp_node_id(node, numtransp, transp)) {
761       eltbitmask |= TRANSPARENCY_MASK;
762     }
763   }
764   if (bitmask & AMBIENT_MASK) {
765     if (elem->coinstate.ambient != ambient) {
766       eltbitmask |= AMBIENT_MASK;
767     }
768   }
769   if (bitmask & EMISSIVE_MASK) {
770     if (elem->coinstate.emissive != emissive) {
771       eltbitmask |= EMISSIVE_MASK;
772     }
773   }
774   if (bitmask & SPECULAR_MASK) {
775     if (elem->coinstate.specular != specular) {
776       eltbitmask |= SPECULAR_MASK;
777     }
778   }
779   if (bitmask & SHININESS_MASK) {
780     if (SbAbs(elem->coinstate.shininess-shininess) > SO_LAZY_SHINY_THRESHOLD) {
781       eltbitmask |= SHININESS_MASK;
782     }
783   }
784 
785   SoLazyElement * welem = NULL;
786 
787   if (eltbitmask) {
788     welem = getWInstance(state);
789     welem->setMaterialElt(node, eltbitmask, packer, diffuse,
790                           numdiffuse, transp, numtransp,
791                           ambient, emissive, specular, shininess,
792                           istransparent);
793     if (state->isCacheOpen()) welem->lazyDidSet(eltbitmask);
794   }
795 
796   if ((eltbitmask != bitmask) && state->isCacheOpen()) {
797     if (welem) elem = welem;
798     elem->lazyDidntSet((~eltbitmask) & bitmask);
799   }
800   if (bitmask & TRANSPARENCY_MASK) {
801     SoShapeStyleElement::setTransparentMaterial(state, istransparent);
802   }
803 }
804 
805 void
setVertexOrdering(SoState * state,VertexOrdering ordering)806 SoLazyElement::setVertexOrdering(SoState * state, VertexOrdering ordering)
807 {
808   SoLazyElement * elem = SoLazyElement::getInstance(state);
809   if (elem->coinstate.vertexordering != ordering) {
810     elem = getWInstance(state);
811     elem->setVertexOrderingElt(ordering);
812     if (state->isCacheOpen()) elem->lazyDidSet(VERTEXORDERING_MASK);
813   }
814   else if (state->isCacheOpen()) {
815     elem->lazyDidntSet(VERTEXORDERING_MASK);
816   }
817 }
818 
819 void
setBackfaceCulling(SoState * state,SbBool onoff)820 SoLazyElement::setBackfaceCulling(SoState * state, SbBool onoff)
821 {
822   SoLazyElement * elem = SoLazyElement::getInstance(state);
823   if (elem->coinstate.culling != onoff) {
824     elem = getWInstance(state);
825     elem->setBackfaceCullingElt(onoff);
826     if (state->isCacheOpen()) elem->lazyDidSet(CULLING_MASK);
827   }
828   else if (state->isCacheOpen()) {
829     elem->lazyDidntSet(CULLING_MASK);
830   }
831 }
832 
833 void
setTwosideLighting(SoState * state,SbBool onoff)834 SoLazyElement::setTwosideLighting(SoState * state, SbBool onoff)
835 {
836   SoLazyElement * elem = SoLazyElement::getInstance(state);
837   if (elem->coinstate.twoside != onoff) {
838     elem = getWInstance(state);
839     elem->setTwosideLightingElt(onoff);
840     if (state->isCacheOpen()) elem->lazyDidSet(TWOSIDE_MASK);
841   }
842   else if (state->isCacheOpen()) {
843     elem->lazyDidntSet(TWOSIDE_MASK);
844   }
845 }
846 
847 void
setShadeModel(SoState * state,SbBool flatshading)848 SoLazyElement::setShadeModel(SoState * state, SbBool flatshading)
849 {
850   SoLazyElement * elem = SoLazyElement::getInstance(state);
851 
852   if (elem->coinstate.flatshading != flatshading) {
853     elem = getWInstance(state);
854     elem->setShadeModelElt(flatshading);
855     if (state->isCacheOpen()) elem->lazyDidSet(SHADE_MODEL_MASK);
856   }
857   else if (state->isCacheOpen()) {
858     elem->lazyDidntSet(SHADE_MODEL_MASK);
859   }
860 }
861 
862 void
setAlphaTest(SoState * state,int func,float value)863 SoLazyElement::setAlphaTest(SoState * state, int func, float value)
864 {
865   SoLazyElement * elem = SoLazyElement::getInstance(state);
866   if (elem->coinstate.alphatestfunc != func ||
867       elem->coinstate.alphatestvalue != value) {
868     elem = getWInstance(state);
869     elem->setAlphaTestElt(func, value);
870     if (state->isCacheOpen()) elem->lazyDidSet(ALPHATEST_MASK);
871   }
872   else if (state->isCacheOpen()) {
873     elem->lazyDidntSet(ALPHATEST_MASK);
874   }
875 }
876 
877 
878 // ! FIXME: write doc
879 
880 SoLazyElement *
getWInstance(SoState * state)881 SoLazyElement::getWInstance(SoState * state)
882 {
883   // don't use SoElement::getConstElement() as this will cause
884   // cache dependencies.
885   return
886     coin_safe_cast<SoLazyElement *>
887     (
888      state->getElement(classStackIndex)
889      );
890 }
891 
892 // ! FIXME: write doc
893 
894 const uint32_t *
getPackedPointer(void) const895 SoLazyElement::getPackedPointer(void) const
896 {
897   return this->coinstate.packedarray;
898 }
899 
900 // ! FIXME: write doc
901 
902 const SbColor *
getDiffusePointer(void) const903 SoLazyElement::getDiffusePointer(void) const
904 {
905   return this->coinstate.diffusearray;
906 }
907 
908 // ! FIXME: write doc
909 
910 const int32_t *
getColorIndexPointer(void) const911 SoLazyElement::getColorIndexPointer(void) const
912 {
913   assert(0 && "color index mode is not supported in Coin");
914   return NULL;
915 }
916 
917 // ! FIXME: write doc
918 
919 const float *
getTransparencyPointer(void) const920 SoLazyElement::getTransparencyPointer(void) const
921 {
922   return this->coinstate.transparray;
923 }
924 
925 // ! FIXME: write doc
926 
927 void
setTransparencyType(SoState * state,int32_t type)928 SoLazyElement::setTransparencyType(SoState *state, int32_t type)
929 {
930   SoLazyElement * elem = SoLazyElement::getInstance(state);
931   if (elem->coinstate.transptype != type) {
932     getWInstance(state)->setTranspTypeElt(type);
933   }
934 }
935 
936 
937 void
setDiffuseElt(SoNode * node,int32_t numcolors,const SbColor * colors,SoColorPacker * COIN_UNUSED_ARG (packer))938 SoLazyElement::setDiffuseElt(SoNode * node,  int32_t numcolors,
939                              const SbColor * colors, SoColorPacker * COIN_UNUSED_ARG(packer))
940 {
941   this->coinstate.diffusenodeid = get_diffuse_node_id(node, numcolors, colors);
942   this->coinstate.diffusearray = colors;
943   this->coinstate.numdiffuse = numcolors;
944   this->coinstate.packeddiffuse = FALSE;
945 }
946 
947 void
setPackedElt(SoNode * node,int32_t numcolors,const uint32_t * colors,const SbBool packedtransparency)948 SoLazyElement::setPackedElt(SoNode * node, int32_t numcolors,
949                             const uint32_t * colors, const SbBool packedtransparency)
950 {
951   this->coinstate.diffusenodeid = node->getNodeId();
952   this->coinstate.transpnodeid = node->getNodeId();
953   this->coinstate.numdiffuse = numcolors;
954   this->coinstate.packedarray = colors;
955   this->coinstate.packeddiffuse = TRUE;
956   this->coinstate.istransparent = packedtransparency;
957 
958   int alpha = colors[0] & 0xff;
959   float transp = float(255-alpha)/255.0f;
960   this->coinstate.stipplenum = SbClamp(static_cast<int>(transp * 64.0f), 0, 64);
961 }
962 
963 void
setColorIndexElt(SoNode * COIN_UNUSED_ARG (node),int32_t numindices,const int32_t * indices)964 SoLazyElement::setColorIndexElt(SoNode * COIN_UNUSED_ARG(node), int32_t numindices,
965                                 const int32_t * indices)
966 {
967   this->coinstate.colorindexarray = indices;
968   this->coinstate.numdiffuse = numindices;
969   this->coinstate.packeddiffuse = FALSE;
970 }
971 
972 void
setTranspElt(SoNode * node,int32_t numtransp,const float * transp,SoColorPacker * COIN_UNUSED_ARG (packer))973 SoLazyElement::setTranspElt(SoNode * node, int32_t numtransp,
974                             const float * transp, SoColorPacker * COIN_UNUSED_ARG(packer))
975 {
976   this->coinstate.transpnodeid = get_transp_node_id(node, numtransp, transp);
977   this->coinstate.transparray = transp;
978   this->coinstate.numtransp = numtransp;
979   this->coinstate.stipplenum = SbClamp(static_cast<int>(transp[0] * 64.0f), 0, 64);
980 
981   this->coinstate.istransparent = FALSE;
982   for (int i = 0; i < numtransp; i++) {
983     if (transp[i] > 0.0f) {
984       this->coinstate.istransparent = TRUE;
985       break;
986     }
987   }
988 }
989 
990 
991 void
setTranspTypeElt(int32_t type)992 SoLazyElement::setTranspTypeElt(int32_t type)
993 {
994   this->coinstate.transptype = type;
995 }
996 
997 void
setAmbientElt(const SbColor * color)998 SoLazyElement::setAmbientElt(const SbColor* color)
999 {
1000   this->coinstate.ambient = *color;
1001 }
1002 
1003 void
setEmissiveElt(const SbColor * color)1004 SoLazyElement::setEmissiveElt(const SbColor* color)
1005 {
1006   this->coinstate.emissive = *color;
1007 }
1008 
1009 void
setSpecularElt(const SbColor * color)1010 SoLazyElement::setSpecularElt(const SbColor* color)
1011 {
1012   this->coinstate.specular = *color;
1013 }
1014 
1015 void
setShininessElt(float value)1016 SoLazyElement::setShininessElt(float value)
1017 {
1018   this->coinstate.shininess = value;
1019 }
1020 
1021 void
setColorMaterialElt(SbBool COIN_UNUSED_ARG (value))1022 SoLazyElement::setColorMaterialElt(SbBool COIN_UNUSED_ARG(value))
1023 {
1024 }
1025 
1026 void
enableBlendingElt(int sfactor,int dfactor,int alpha_sfactor,int alpha_dfactor)1027 SoLazyElement::enableBlendingElt(int sfactor, int dfactor, int alpha_sfactor, int alpha_dfactor)
1028 {
1029   this->coinstate.blending = TRUE;
1030   this->coinstate.blend_sfactor = sfactor;
1031   this->coinstate.blend_dfactor = dfactor;
1032   this->coinstate.alpha_blend_sfactor = alpha_sfactor;
1033   this->coinstate.alpha_blend_dfactor = alpha_dfactor;
1034 }
1035 
1036 void
disableBlendingElt(void)1037 SoLazyElement::disableBlendingElt(void)
1038 {
1039   this->coinstate.blending = FALSE;
1040 }
1041 
1042 void
setLightModelElt(SoState * state,int32_t model)1043 SoLazyElement::setLightModelElt(SoState * state, int32_t model)
1044 {
1045   SoShapeStyleElement::setLightModel(state, model);
1046   this->coinstate.lightmodel = model;
1047 }
1048 
1049 void
setMaterialElt(SoNode * node,uint32_t bitmask,SoColorPacker * COIN_UNUSED_ARG (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)1050 SoLazyElement::setMaterialElt(SoNode * node, uint32_t bitmask,
1051                               SoColorPacker * COIN_UNUSED_ARG(packer),
1052                               const SbColor * diffuse, const int numdiffuse,
1053                               const float * transp, const int numtransp,
1054                               const SbColor & ambient,
1055                               const SbColor & emissive,
1056                               const SbColor & specular,
1057                               const float shininess,
1058                               const SbBool istransparent)
1059 {
1060   if (bitmask & DIFFUSE_MASK) {
1061     this->coinstate.diffusenodeid = get_diffuse_node_id(node, numdiffuse, diffuse);
1062     this->coinstate.diffusearray = diffuse;
1063     this->coinstate.numdiffuse = numdiffuse;
1064     this->coinstate.packeddiffuse = FALSE;
1065   }
1066   if (bitmask & TRANSPARENCY_MASK) {
1067     this->coinstate.transpnodeid = get_transp_node_id(node, numtransp, transp);
1068     this->coinstate.transparray = transp;
1069     this->coinstate.numtransp = numtransp;
1070     this->coinstate.stipplenum = SbClamp(static_cast<int>(transp[0] * 64.0f), 0, 64);
1071     // check for common case
1072     if (numtransp == 1 && transp[0] == 0.0f) {
1073       this->coinstate.transpnodeid = 0;
1074       this->coinstate.istransparent = FALSE;
1075     }
1076     else {
1077       this->coinstate.istransparent = istransparent;
1078     }
1079   }
1080   if (bitmask & AMBIENT_MASK) {
1081     this->coinstate.ambient = ambient;
1082   }
1083   if (bitmask & EMISSIVE_MASK) {
1084     this->coinstate.emissive = emissive;
1085   }
1086   if (bitmask & SPECULAR_MASK) {
1087     this->coinstate.specular = specular;
1088   }
1089   if (bitmask & SHININESS_MASK) {
1090     this->coinstate.shininess = shininess;
1091   }
1092 }
1093 
1094 void
setVertexOrderingElt(VertexOrdering ordering)1095 SoLazyElement::setVertexOrderingElt(VertexOrdering ordering)
1096 {
1097   this->coinstate.vertexordering = ordering;
1098 }
1099 
1100 void
setBackfaceCullingElt(SbBool onoff)1101 SoLazyElement::setBackfaceCullingElt(SbBool onoff)
1102 {
1103   this->coinstate.culling = onoff;
1104 }
1105 
1106 void
setTwosideLightingElt(SbBool onoff)1107 SoLazyElement::setTwosideLightingElt(SbBool onoff)
1108 {
1109   this->coinstate.twoside = onoff;
1110 }
1111 
1112 void
setShadeModelElt(SbBool flatshading)1113 SoLazyElement::setShadeModelElt(SbBool flatshading)
1114 {
1115   this->coinstate.flatshading = flatshading;
1116 }
1117 
1118 void
setAlphaTestElt(int func,float value)1119 SoLazyElement::setAlphaTestElt(int func, float value)
1120 {
1121   this->coinstate.alphatestfunc = func;
1122   this->coinstate.alphatestvalue = value;
1123 }
1124 
1125 
1126 // SoColorPacker class. FIXME: move to separate file and document, pederb, 2002-09-09
1127 
1128 static uint32_t colorpacker_default = 0xccccccff;
1129 
SoColorPacker(void)1130 SoColorPacker::SoColorPacker(void)
1131 {
1132   this->array = &colorpacker_default;
1133   this->arraysize = 0;
1134   this->diffuseid = 0;
1135   this->transpid = 0;
1136 }
1137 
~SoColorPacker()1138 SoColorPacker::~SoColorPacker()
1139 {
1140   if (this->array != &colorpacker_default) {
1141     delete[] this->array;
1142   }
1143 }
1144 
1145 void
reallocate(const int32_t size)1146 SoColorPacker::reallocate(const int32_t size)
1147 {
1148   assert(size > this->arraysize);
1149   uint32_t * newarray = new uint32_t[size];
1150   if (this->array != &colorpacker_default) {
1151     delete[] this->array;
1152   }
1153   this->array = newarray;
1154   this->arraysize = size;
1155 }
1156 
1157 void
lazyDidSet(uint32_t COIN_UNUSED_ARG (mask))1158 SoLazyElement::lazyDidSet(uint32_t COIN_UNUSED_ARG(mask))
1159 {
1160 }
1161 
1162 void
lazyDidntSet(uint32_t COIN_UNUSED_ARG (mask))1163 SoLazyElement::lazyDidntSet(uint32_t COIN_UNUSED_ARG(mask))
1164 {
1165 }
1166