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 SoPackedColor SoPackedColor.h Inventor/nodes/SoPackedColor.h
35   \brief The SoPackedColor class is a node for setting diffuse and transparency material values.
36 
37   \ingroup nodes
38 
39   This node provides a convenient way of setting diffuse colors and
40   transparency values with packed 32-bit RGBA vectors.
41 
42   <b>FILE FORMAT/DEFAULTS:</b>
43   \code
44     PackedColor {
45         orderedRGBA 0xccccccff
46     }
47   \endcode
48 
49   \sa SoBaseColor
50 */
51 
52 // *************************************************************************
53 
54 // FIXME: the name of the "orderedRGBA" field was actually "rgba" in
55 // the version 2.0 Inventor file format, and the semantics was also
56 // different (reversed order). This means that Inventor 2.0 files with
57 // PackedColor nodes will not import properly at the moment.  20020508 mortene.
58 
59 // *************************************************************************
60 
61 #include <Inventor/nodes/SoPackedColor.h>
62 
63 #include <Inventor/actions/SoCallbackAction.h>
64 #include <Inventor/actions/SoGLRenderAction.h>
65 #include <Inventor/elements/SoOverrideElement.h>
66 #include <Inventor/elements/SoGLLazyElement.h>
67 #include <Inventor/elements/SoGLVBOElement.h>
68 #include <Inventor/C/tidbits.h>
69 
70 #include "nodes/SoSubNodeP.h"
71 #include "rendering/SoVBO.h"
72 
73 
74 // *************************************************************************
75 
76 /*!
77   \var SoMFUInt32 SoPackedColor::orderedRGBA
78 
79   Set of packed 32-bit RGBA vectors.
80 
81   The most significant 24 bits specifies 8 bits each for the red,
82   green and blue components.
83 
84   The least significant 8 bits specifies the transparency value, where
85   0x00 means completely transparent, and 0xff completely opaque.
86 */
87 
88 // *************************************************************************
89 
90 class SoPackedColorP {
91  public:
SoPackedColorP()92   SoPackedColorP() : vbo(NULL) { }
~SoPackedColorP()93   ~SoPackedColorP() { delete this->vbo; }
94   SbBool transparent;
95   SbBool checktransparent;
96   SoVBO * vbo;
97 };
98 
99 #define PRIVATE(obj) obj->pimpl
100 
101 SO_NODE_SOURCE(SoPackedColor);
102 
103 /*!
104   Constructor.
105 */
SoPackedColor()106 SoPackedColor::SoPackedColor()
107 {
108   PRIVATE(this) = new SoPackedColorP;
109   SO_NODE_INTERNAL_CONSTRUCTOR(SoPackedColor);
110 
111   SO_NODE_ADD_FIELD(orderedRGBA, (0xccccccff));
112 
113   PRIVATE(this)->checktransparent = FALSE;
114   PRIVATE(this)->transparent = FALSE;
115 }
116 
117 /*!
118   Destructor.
119 */
~SoPackedColor()120 SoPackedColor::~SoPackedColor()
121 {
122   delete PRIVATE(this);
123 }
124 
125 // Doc from superclass.
126 void
initClass(void)127 SoPackedColor::initClass(void)
128 {
129   SO_NODE_INTERNAL_INIT_CLASS(SoPackedColor, SO_FROM_INVENTOR_2_1);
130 
131   SO_ENABLE(SoCallbackAction, SoLazyElement);
132   SO_ENABLE(SoGLRenderAction, SoGLLazyElement);
133 }
134 
135 // Doc from superclass.
136 void
GLRender(SoGLRenderAction * action)137 SoPackedColor::GLRender(SoGLRenderAction * action)
138 {
139   SoPackedColor::doAction(action);
140 }
141 
142 // Doc from superclass.
143 void
doAction(SoAction * action)144 SoPackedColor::doAction(SoAction * action)
145 {
146   (void) this->isTransparent(); // update cached value for transparent
147 
148   SoState * state = action->getState();
149   const int num = this->orderedRGBA.getNum();
150   if (!this->orderedRGBA.isIgnored() &&
151       num > 0 &&
152       !SoOverrideElement::getDiffuseColorOverride(state)) {
153     SoLazyElement::setPacked(state, this,
154                              num,
155                              this->orderedRGBA.getValues(0),
156                              PRIVATE(this)->transparent);
157 
158     if (state->isElementEnabled(SoGLVBOElement::getClassStackIndex())) {
159       SoBase::staticDataLock();
160       SbBool setvbo = FALSE;
161       if (SoGLVBOElement::shouldCreateVBO(state, num)) {
162         SbBool dirty = FALSE;
163         setvbo = TRUE;
164         if (PRIVATE(this)->vbo == NULL) {
165           PRIVATE(this)->vbo = new SoVBO(GL_ARRAY_BUFFER, GL_STATIC_DRAW);
166           dirty = TRUE;
167         }
168         else if (PRIVATE(this)->vbo->getBufferDataId() != this->getNodeId()) {
169           dirty = TRUE;
170         }
171         if (dirty) {
172           if (coin_host_get_endianness() == COIN_HOST_IS_BIGENDIAN) {
173             PRIVATE(this)->vbo->setBufferData(this->orderedRGBA.getValues(0),
174                                               num*sizeof(uint32_t),
175                                               this->getNodeId());
176           }
177           else {
178             // sigh. Need to swap bytes on little endian systems.
179             const uint32_t * src = this->orderedRGBA.getValues(0);
180             uint32_t * dst = (uint32_t*)
181               PRIVATE(this)->vbo->allocBufferData(num*sizeof(uint32_t),
182                                                   this->getNodeId());
183             for (int i = 0; i < num; i++) {
184               uint32_t tmp = src[i];
185               dst[i] =
186                 (tmp << 24) |
187                 ((tmp & 0xff00) << 8) |
188                 ((tmp & 0xff0000) >> 8) |
189                 (tmp >> 24);
190             }
191           }
192         }
193       }
194       else if (PRIVATE(this)->vbo) {
195         PRIVATE(this)->vbo->setBufferData(NULL, 0, 0);
196       }
197       SoBase::staticDataUnlock();
198       if (setvbo) {
199         SoGLVBOElement::setColorVBO(state, PRIVATE(this)->vbo);
200       }
201     }
202     if (this->isOverride()) {
203       SoOverrideElement::setDiffuseColorOverride(state, this, TRUE);
204     }
205   }
206 }
207 
208 // Doc from superclass.
209 void
callback(SoCallbackAction * action)210 SoPackedColor::callback(SoCallbackAction * action)
211 {
212   SoPackedColor::doAction(action);
213 }
214 
215 /*!
216   Returns \c TRUE if there is at least one RGBA vector in the set
217   which is not completely opaque.
218  */
219 SbBool
isTransparent(void)220 SoPackedColor::isTransparent(void)
221 {
222   if (PRIVATE(this)->checktransparent) {
223     PRIVATE(this)->checktransparent = FALSE;
224     PRIVATE(this)->transparent = FALSE;
225     int n = this->orderedRGBA.getNum();
226     for (int i = 0; i < n; i++) {
227       if ((this->orderedRGBA[i] & 0xff) != 0xff) {
228         PRIVATE(this)->transparent = TRUE;
229         break;
230       }
231     }
232   }
233   return PRIVATE(this)->transparent;
234 }
235 
236 // Documented in superclass.
237 void
notify(SoNotList * list)238 SoPackedColor::notify(SoNotList *list)
239 {
240   // Overridden to check for transparency when orderedRGBA changes.
241 
242   SoField *f = list->getLastField();
243   if (f == &this->orderedRGBA) {
244     PRIVATE(this)->checktransparent = TRUE;
245   }
246   inherited::notify(list);
247 }
248 
249 #undef PRIVATE
250