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