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