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 SoIndexedShape SoIndexedShape.h Inventor/nodes/SoIndexedShape.h
35 \brief The SoIndexedShape class is the superclass for all indexed vertex shapes.
36
37 \ingroup nodes
38
39 This is an abstract class which contains storage for four fields for
40 indices to coordinates, normals, materials and texture coordinates
41 for it's subclasses.
42 */
43
44 #include <Inventor/nodes/SoIndexedShape.h>
45
46 #include <Inventor/actions/SoAction.h>
47 #include <Inventor/elements/SoCoordinateElement.h>
48 #include <Inventor/elements/SoShapeHintsElement.h>
49 #include <Inventor/elements/SoNormalBindingElement.h>
50 #include <Inventor/elements/SoTextureCoordinateBindingElement.h>
51 #include <Inventor/errors/SoDebugError.h>
52 #include <Inventor/caches/SoNormalCache.h>
53 #include <Inventor/nodes/SoVertexProperty.h>
54
55 #include "nodes/SoSubNodeP.h"
56 #include "coindefs.h" // COIN_OBSOLETED()
57
58 /*!
59 \var SoMFInt32 SoIndexedShape::coordIndex
60 Coordinate indices.
61 */
62 /*!
63 \var SoMFInt32 SoIndexedShape::materialIndex
64 Material indices.
65 */
66 /*!
67 \var SoMFInt32 SoIndexedShape::normalIndex
68 Normal indices.
69 */
70 /*!
71 \var SoMFInt32 SoIndexedShape::textureCoordIndex
72 Texture coordinate indices.
73 */
74
75
76 SO_NODE_ABSTRACT_SOURCE(SoIndexedShape);
77
78 /*!
79 Constructor.
80 */
SoIndexedShape()81 SoIndexedShape::SoIndexedShape()
82 {
83 SO_NODE_INTERNAL_CONSTRUCTOR(SoIndexedShape);
84
85 SO_NODE_ADD_FIELD(coordIndex,(0));
86 SO_NODE_ADD_FIELD(materialIndex,(-1));
87 SO_NODE_ADD_FIELD(normalIndex,(-1));
88 SO_NODE_ADD_FIELD(textureCoordIndex,(-1));
89 }
90
91 /*!
92 Destructor.
93 */
~SoIndexedShape()94 SoIndexedShape::~SoIndexedShape()
95 {
96 }
97
98 // Documented in superclass.
99 void
initClass(void)100 SoIndexedShape::initClass(void)
101 {
102 SO_NODE_INTERNAL_INIT_ABSTRACT_CLASS(SoIndexedShape, SO_FROM_INVENTOR_1);
103 }
104
105 // Collects common error msg code for computeBBox() for both
106 // Coordinate3 and Coordinate4 loops.
107 static void
error_idx_out_of_bounds(const SoIndexedShape * node,int idxidx,int upper)108 error_idx_out_of_bounds(const SoIndexedShape * node, int idxidx, int upper)
109 {
110 SbName n = node->getName();
111 SbString ns(" ");
112 ns += n;
113
114 SbName t = node->getTypeId().getName();
115
116 SbString bounds;
117 if (upper > 0) {
118 // (Note: the if-expression above should have been "upper >= 0",
119 // if it weren't for the default SoCoordinateElement containing
120 // one default coordinate.)
121 bounds.sprintf("should be within [0, %d]", upper);
122 }
123 else {
124 bounds = "but no coordinates are available from the state!";
125 }
126
127 SoDebugError::post("SoIndexedShape::computeBBox",
128 "coordinate index nr %d for %snode%s of type %s is "
129 "out of bounds: is %d, %s",
130 idxidx,
131 (n == "") ? "<unnamed> " : "",
132 (n != "") ? ns.getString() : "",
133 t.getString(),
134 node->coordIndex[idxidx],
135 bounds.getString());
136 }
137
138 // Documented in superclass. Overridden to calculate bounding box of
139 // all indexed coordinates, using the coordIndex field.
140 void
computeBBox(SoAction * action,SbBox3f & box,SbVec3f & center)141 SoIndexedShape::computeBBox(SoAction * action, SbBox3f & box, SbVec3f & center)
142 {
143 assert(box.isEmpty());
144 SoState * state = action->getState();
145
146 const SoCoordinateElement * coordelem = NULL;
147 SoNode *vpnode = this->vertexProperty.getValue();
148 SoVertexProperty *vp =
149 (vpnode && vpnode->isOfType(SoVertexProperty::getClassTypeId())) ?
150 (SoVertexProperty *)vpnode : NULL;
151 SbBool vpvtx = vp && (vp->vertex.getNum() > 0);
152 if (!vpvtx) {
153 coordelem = SoCoordinateElement::getInstance(state);
154 }
155
156 const int numcoords = vpvtx ? vp->vertex.getNum() : coordelem->getNum();
157 int numacc = 0; // to calculate weighted center point
158 center.setValue(0.0f, 0.0f, 0.0f);
159
160 if (vpvtx || coordelem->is3D()) {
161 const SbVec3f * coords = vpvtx ?
162 vp->vertex.getValues(0) :
163 coordelem->getArrayPtr3();
164
165 const int32_t * ptr = this->coordIndex.getValues(0);
166 const int32_t * endptr = ptr + this->coordIndex.getNum();
167 while (ptr < endptr) {
168 const int idx = *ptr++;
169 if (idx < numcoords) {
170 if (idx >= 0) {
171 box.extendBy(coords[idx]);
172 center += coords[idx];
173 numacc++;
174 }
175 }
176 #if COIN_DEBUG
177 else {
178 const ptrdiff_t faultyidxpos = (ptr - this->coordIndex.getValues(0)) - 1;
179 error_idx_out_of_bounds(this, (int)faultyidxpos, numcoords - 1);
180 if (numcoords <= 1) break; // give only one error msg on missing coords
181 // (the default state is that there's a default
182 // SoCoordinateElement element with a single default
183 // coordinate point setup)
184 }
185 #endif // COIN_DEBUG
186 }
187 }
188 else {
189 SbVec3f tmp;
190 const SbVec4f * coords = coordelem->getArrayPtr4();
191 const int32_t * ptr = this->coordIndex.getValues(0);
192 const int32_t * endptr = ptr + this->coordIndex.getNum();
193 while (ptr < endptr) {
194 int idx = *ptr++;
195 if (idx < numcoords) {
196 if (idx >= 0) {
197 SbVec4f h = coords[idx];
198 h.getReal(tmp);
199 box.extendBy(tmp);
200 center += tmp;
201 numacc++;
202 }
203 }
204 #if COIN_DEBUG
205 else {
206 const ptrdiff_t faultyidxpos = (ptr - this->coordIndex.getValues(0)) - 1;
207 error_idx_out_of_bounds(this, (int)faultyidxpos, numcoords - 1);
208 if (numcoords <= 1) break; // give only one error msg on missing coords
209 // (the default state is that there's a default
210 // SoCoordinateElement element with a single default
211 // coordinate point setup)
212 }
213 #endif // COIN_DEBUG
214 }
215 }
216 if (numacc) center /= (float) numacc;
217 }
218
219 /*!
220 Returns whether texture coordinates should be indexed or not.
221
222 \sa SoTextureCoordinateBinding
223 */
224 SbBool
areTexCoordsIndexed(SoAction * action)225 SoIndexedShape::areTexCoordsIndexed(SoAction * action)
226 {
227 return SoTextureCoordinateBindingElement::get(action->getState()) ==
228 SoTextureCoordinateBindingElement::PER_VERTEX_INDEXED;
229 }
230
231 /*!
232 Starting at index position \a startCoord, returns the number of
233 indices until either the end of index array or a separator index (-1).
234 */
235 int
getNumVerts(const int startCoord)236 SoIndexedShape::getNumVerts(const int startCoord)
237 {
238 const int32_t * ptr = this->coordIndex.getValues(0);
239 const int32_t * endptr = ptr + this->coordIndex.getNum();
240 ptr += startCoord;
241 int cnt = 0;
242 while (ptr < endptr && *ptr >= 0) cnt++, ptr++;
243 return cnt;
244 }
245
246 /*!
247 Not implemented. Probably only used for internal purposes in SGI's
248 original Open Inventor, which means it should have been private.
249
250 Let us know if you need this method for any code you are porting and
251 we'll look into implement it properly.
252 */
253 void
setupIndices(const int,const int,const SbBool,const SbBool)254 SoIndexedShape::setupIndices(const int /* numParts */,
255 const int /* numFaces */,
256 const SbBool /* needNormals */,
257 const SbBool /* needTexCoords */)
258 {
259 COIN_OBSOLETED();
260 }
261
262 /*!
263 Not implemented. Probably only used for internal purposes in SGI's
264 original Open Inventor, which means it should have been private.
265
266 Let us know if you need this method for any code you are porting and
267 we'll look into implement it properly.
268 */
269 const int32_t *
getNormalIndices()270 SoIndexedShape::getNormalIndices()
271 {
272 COIN_OBSOLETED();
273 return NULL;
274 }
275
276 /*!
277 Not implemented. Probably only used for internal purposes in SGI's
278 original Open Inventor, which means it should have been private.
279
280 Let us know if you need this method for any code you are porting and
281 we'll look into implement it properly.
282 */
283 const int32_t *
getColorIndices()284 SoIndexedShape::getColorIndices()
285 {
286 COIN_OBSOLETED();
287 return NULL;
288 }
289
290 /*!
291 Not implemented. Probably only used for internal purposes in SGI's
292 original Open Inventor, which means it should have been private.
293
294 Let us know if you need this method for any code you are porting and
295 we'll look into implement it properly.
296 */
297 const int32_t *
getTexCoordIndices()298 SoIndexedShape::getTexCoordIndices()
299 {
300 COIN_OBSOLETED();
301 return NULL;
302 }
303
304 /*!
305 Convenience method that will fetch data needed for rendering or
306 generating primitives. Takes care of normal cache.
307
308 This method was not part of the original SGI Open Inventor API, and
309 is an extension specific for Coin.
310 */
311 SbBool
getVertexData(SoState * state,const SoCoordinateElement * & coords,const SbVec3f * & normals,const int32_t * & cindices,const int32_t * & nindices,const int32_t * & tindices,const int32_t * & mindices,int & numcindices,const SbBool needNormals,SbBool & normalCacheUsed)312 SoIndexedShape::getVertexData(SoState * state,
313 const SoCoordinateElement *& coords,
314 const SbVec3f *& normals,
315 const int32_t *& cindices,
316 const int32_t *& nindices,
317 const int32_t *& tindices,
318 const int32_t *& mindices,
319 int & numcindices,
320 const SbBool needNormals,
321 SbBool & normalCacheUsed)
322 {
323 SoVertexShape::getVertexData(state, coords, normals, needNormals);
324
325 cindices = this->coordIndex.getValues(0);
326 numcindices = this->coordIndex.getNum();
327
328 mindices = this->materialIndex.getValues(0);
329 if (this->materialIndex.getNum() <= 0 || mindices[0] < 0) mindices = NULL;
330
331 tindices = this->textureCoordIndex.getValues(0);
332 if (this->textureCoordIndex.getNum() <= 0 || tindices[0] < 0) tindices = NULL;
333
334 normalCacheUsed = FALSE;
335 nindices = NULL;
336 if (needNormals) {
337 nindices = this->normalIndex.getValues(0);
338 if (this->normalIndex.getNum() <= 0 || nindices[0] < 0) nindices = NULL;
339
340 if (normals == NULL) {
341 SoNormalCache * nc = this->generateAndReadLockNormalCache(state);
342 normals = nc->getNormals();
343 nindices = nc->getIndices();
344 normalCacheUsed = TRUE;
345
346 // if no normals were generated, unlock normal cache before
347 // returning
348 if (normals == NULL) {
349 this->readUnlockNormalCache();
350 normalCacheUsed = FALSE;
351 }
352 }
353 }
354 return TRUE;
355 }
356