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 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif // HAVE_CONFIG_H
36
37 #ifdef HAVE_VRML97
38
39 /*!
40 \class SoVRMLVertexShape SoVRMLVertexShape.h Inventor/VRMLnodes/SoVRMLVertexShape.h
41 \brief The SoVRMLVertexShape class is a superclass for vertex based shapes.
42 */
43
44 /*!
45 \var SoSFNode SoVRMLVertexShape::coord
46 Should contain an SoVRMLCoordinate node.
47 */
48
49 /*!
50 \var SoSFNode SoVRMLVertexShape::texCoord
51 Can contain an SoVRMLTextureCoordinate node.
52 */
53
54 /*!
55 \var SoSFNode SoVRMLVertexShape::normal
56 Can contain an SoVRMLNormal node.
57 */
58
59 /*!
60 \var SoSFNode SoVRMLVertexShape::color
61 Can contain an SoVRMLColor node.
62 */
63
64 /*!
65 \var SoSFBool SoVRMLVertexShape::colorPerVertex
66 When TRUE, colors are applied per vertex. Default value is TRUE.
67 */
68
69 /*!
70 \var SoSFBool SoVRMLVertexShape::normalPerVertex
71 When TRUE, normals are applied per vertex. Default value is TRUE.
72 */
73
74 #include <Inventor/VRMLnodes/SoVRMLVertexShape.h>
75
76 #include <cstddef>
77
78 #include <Inventor/VRMLnodes/SoVRMLMacros.h>
79 #include <Inventor/VRMLnodes/SoVRMLNormal.h>
80 #include <Inventor/caches/SoNormalCache.h>
81 #include <Inventor/elements/SoCacheElement.h>
82 #include <Inventor/elements/SoCoordinateElement.h>
83 #include <Inventor/elements/SoLazyElement.h>
84 #include <Inventor/actions/SoGLRenderAction.h>
85 #include <Inventor/misc/SoState.h>
86 #include <Inventor/errors/SoDebugError.h>
87 #ifdef HAVE_THREADS
88 #include <Inventor/threads/SbRWMutex.h>
89 #endif // HAVE_THREADS
90
91 #include "nodes/SoSubNodeP.h"
92
93 // *************************************************************************
94
95 class SoVRMLVertexShapeP {
96 public:
SoVRMLVertexShapeP(void)97 SoVRMLVertexShapeP(void)
98 #ifdef COIN_THREADSAFE
99 : normalcachemutex(SbRWMutex::READ_PRECEDENCE)
100 #endif // COIN_THREADSAFE
101 { }
102
103 SoNormalCache * normalcache;
104 #ifdef COIN_THREADSAFE
105 SbRWMutex normalcachemutex;
106 #endif // COIN_THREADSAFE
107 };
108
109 #define PRIVATE(obj) ((obj)->pimpl)
110
111 // *************************************************************************
112
113 SO_NODE_ABSTRACT_SOURCE(SoVRMLVertexShape);
114
115 // *************************************************************************
116
117 // Doc in parent
118 void
initClass(void)119 SoVRMLVertexShape::initClass(void)
120 {
121 SO_NODE_INTERNAL_INIT_ABSTRACT_CLASS(SoVRMLVertexShape, SO_VRML97_NODE_TYPE);
122 }
123
124 /*!
125 Constructor.
126 */
SoVRMLVertexShape(void)127 SoVRMLVertexShape::SoVRMLVertexShape(void)
128 {
129 PRIVATE(this) = new SoVRMLVertexShapeP;
130 PRIVATE(this)->normalcache = NULL;
131
132 SO_VRMLNODE_INTERNAL_CONSTRUCTOR(SoVRMLVertexShape);
133
134 SO_VRMLNODE_ADD_EXPOSED_FIELD(coord, (NULL));
135 SO_VRMLNODE_ADD_EXPOSED_FIELD(texCoord, (NULL));
136 SO_VRMLNODE_ADD_EXPOSED_FIELD(normal, (NULL));
137 SO_VRMLNODE_ADD_FIELD(color, (NULL));
138 SO_VRMLNODE_ADD_FIELD(colorPerVertex, (TRUE));
139 SO_VRMLNODE_ADD_FIELD(normalPerVertex, (TRUE));
140 }
141
142 /*!
143 Destructor.
144 */
~SoVRMLVertexShape()145 SoVRMLVertexShape::~SoVRMLVertexShape()
146 {
147 if (PRIVATE(this)->normalcache) PRIVATE(this)->normalcache->unref();
148 delete PRIVATE(this);
149 }
150
151 // This documentation block has a copy in shapenodes/VertexShape.cpp.
152 /*!
153 \COININTERNAL
154
155 Subclasses should override this method to generate default normals
156 using the SoNormalBundle class. \c TRUE should be returned if
157 normals were generated, \c FALSE otherwise.
158
159 Default method returns \c FALSE.
160
161 \COIN_FUNCTION_EXTENSION
162 */
163 SbBool
generateDefaultNormals(SoState *,SoNormalBundle *)164 SoVRMLVertexShape::generateDefaultNormals(SoState * ,
165 SoNormalBundle *)
166 {
167 return FALSE;
168 }
169
170
171 // This documentation block has a copy in shapenodes/VertexShape.cpp.
172 /*!
173 \COININTERNAL
174
175 Subclasses should override this method to generate default normals
176 using the SoNormalCache class. This is more effective than using
177 SoNormalGenerator. Return \c TRUE if normals were generated, \c
178 FALSE otherwise.
179
180 Default method just returns \c FALSE.
181
182 \COIN_FUNCTION_EXTENSION
183 */
184 SbBool
generateDefaultNormals(SoState *,SoNormalCache *)185 SoVRMLVertexShape::generateDefaultNormals(SoState * /* state */,
186 SoNormalCache * /* nc */)
187 {
188 return FALSE;
189 }
190
191 void
doAction(SoAction * action)192 SoVRMLVertexShape::doAction(SoAction * action)
193 {
194 SoNode * node;
195
196 node = this->coord.getValue();
197 if (node) node->doAction(action);
198
199 node = this->texCoord.getValue();
200 if (node) node->doAction(action);
201
202 node = this->normal.getValue();
203 if (node) node->doAction(action);
204
205 node = this->color.getValue();
206 if (node) node->doAction(action);
207 }
208
209 void
GLRender(SoGLRenderAction * action)210 SoVRMLVertexShape::GLRender(SoGLRenderAction * action)
211 {
212 SoNode * node;
213
214 node = this->coord.getValue();
215 if (node) node->GLRender(action);
216
217 node = this->texCoord.getValue();
218 if (node) node->GLRender(action);
219
220 node = this->normal.getValue();
221 if (node) node->GLRender(action);
222
223 node = this->color.getValue();
224 if (node) node->GLRender(action);
225 }
226
227 void
getBoundingBox(SoGetBoundingBoxAction * action)228 SoVRMLVertexShape::getBoundingBox(SoGetBoundingBoxAction * action)
229 {
230 inherited::getBoundingBox(action);
231 }
232
233 void
callback(SoCallbackAction * action)234 SoVRMLVertexShape::callback(SoCallbackAction * action)
235 {
236 inherited::callback(action);
237 }
238
239 void
pick(SoPickAction * action)240 SoVRMLVertexShape::pick(SoPickAction * action)
241 {
242 inherited::pick(action);
243 }
244
245 void
notify(SoNotList * list)246 SoVRMLVertexShape::notify(SoNotList * list)
247 {
248 SoField * f = list->getLastField();
249
250 if (f == &this->coord) {
251 this->readLockNormalCache();
252 if (PRIVATE(this)->normalcache) {
253 PRIVATE(this)->normalcache->invalidate();
254 }
255 this->readUnlockNormalCache();
256 }
257 inherited::notify(list);
258 }
259
260 SbBool
shouldGLRender(SoGLRenderAction * action)261 SoVRMLVertexShape::shouldGLRender(SoGLRenderAction * action)
262 {
263 return SoShape::shouldGLRender(action);
264 }
265
266 void
setNormalCache(SoState * state,int num,SbVec3f * normals)267 SoVRMLVertexShape::setNormalCache(SoState * state,
268 int num,
269 SbVec3f * normals)
270 {
271 this->writeLockNormalCache();
272 if (PRIVATE(this)->normalcache) PRIVATE(this)->normalcache->unref();
273 // create new normal cache with no dependencies
274 state->push();
275 PRIVATE(this)->normalcache = new SoNormalCache(state);
276 PRIVATE(this)->normalcache->ref();
277 PRIVATE(this)->normalcache->set(num, normals);
278 // force element dependencies
279 (void) SoCoordinateElement::getInstance(state);
280 state->pop();
281 this->writeUnlockNormalCache();
282 }
283
284 /*!
285
286 Convenience method that can be used by subclasses to return or
287 create a normal cache. If the current cache is not valid, it takes
288 care of unrefing the old cache and pushing and popping the state to
289 create element dependencies when creating the new cache.
290
291 When returning from this method, the normal cache will be
292 read locked, and the caller should call readUnlockNormalCache()
293 when the normals in the cache is no longer needed.
294
295 \COIN_FUNCTION_EXTENSION
296
297 \since Coin 2.0
298 */
299 SoNormalCache *
generateAndReadLockNormalCache(SoState * const state)300 SoVRMLVertexShape::generateAndReadLockNormalCache(SoState * const state)
301 {
302 this->readLockNormalCache();
303 if (PRIVATE(this)->normalcache && PRIVATE(this)->normalcache->isValid(state)) {
304 return PRIVATE(this)->normalcache;
305 }
306 this->readUnlockNormalCache();
307 this->writeLockNormalCache();
308
309 SbBool storeinvalid = SoCacheElement::setInvalid(FALSE);
310
311 if (PRIVATE(this)->normalcache) PRIVATE(this)->normalcache->unref();
312 state->push(); // need to push for cache dependencies
313 PRIVATE(this)->normalcache = new SoNormalCache(state);
314 PRIVATE(this)->normalcache->ref();
315 SoCacheElement::set(state, PRIVATE(this)->normalcache);
316 //
317 // See if the node supports the Coin-way of generating normals
318 //
319 if (!generateDefaultNormals(state, PRIVATE(this)->normalcache)) {
320 // FIXME: implement SoNormalBundle
321 if (generateDefaultNormals(state, (SoNormalBundle *)NULL)) {
322 // FIXME: set generator in normal cache
323 }
324 }
325 state->pop(); // don't forget this pop
326
327 SoCacheElement::setInvalid(storeinvalid);
328 this->writeUnlockNormalCache();
329 this->readLockNormalCache();
330 return PRIVATE(this)->normalcache;
331 }
332
333 SoNormalCache *
getNormalCache(void) const334 SoVRMLVertexShape::getNormalCache(void) const
335 {
336 return PRIVATE(this)->normalcache;
337 }
338
339 /*!
340 Convenience method that returns the current coordinate and normal
341 element. This method is not part of the OIV API.
342 */
343 void
getVertexData(SoState * state,const SoCoordinateElement * & coords,const SbVec3f * & normals,const SbBool neednormals)344 SoVRMLVertexShape::getVertexData(SoState * state,
345 const SoCoordinateElement *& coords,
346 const SbVec3f *& normals,
347 const SbBool neednormals)
348 {
349 coords = SoCoordinateElement::getInstance(state);
350 assert(coords);
351
352 normals = NULL;
353 if (neednormals) {
354 SoVRMLNormal * node = (SoVRMLNormal*) this->normal.getValue();
355 normals = (node && node->vector.getNum()) ? node->vector.getValues(0) : NULL;
356 }
357 }
358
359 /*!
360
361 Read lock the normal cache. This method should be called before
362 fetching the normal cache (using getNormalCache()). When the cached
363 normals are no longer needed, readUnlockNormalCache() must be called.
364
365 It is also possible to use generateAndReadLockNormalCache().
366
367 \COIN_FUNCTION_EXTENSION
368
369 \sa readUnlockNormalCache()
370 \since Coin 2.0
371 */
372 void
readLockNormalCache(void)373 SoVRMLVertexShape::readLockNormalCache(void)
374 {
375 #ifdef COIN_THREADSAFE
376 PRIVATE(this)->normalcachemutex.readLock();
377 #endif // COIN_THREADSAFE
378 }
379
380 /*!
381 Read unlock the normal cache. Should be called when the read-locked
382 cached normals are no longer needed.
383
384 \COIN_FUNCTION_EXTENSION
385
386 \sa readLockNormalCache()
387 \since Coin 2.0
388 */
389 void
readUnlockNormalCache(void)390 SoVRMLVertexShape::readUnlockNormalCache(void)
391 {
392 #ifdef COIN_THREADSAFE
393 PRIVATE(this)->normalcachemutex.readUnlock();
394 #endif // COIN_THREADSAFE
395 }
396
397 // write lock normal cache
398 void
writeLockNormalCache(void)399 SoVRMLVertexShape::writeLockNormalCache(void)
400 {
401 #ifdef COIN_THREADSAFE
402 PRIVATE(this)->normalcachemutex.writeLock();
403 #endif // COIN_THREADSAFE
404 }
405
406 // write unlock normal cache
407 void
writeUnlockNormalCache(void)408 SoVRMLVertexShape::writeUnlockNormalCache(void)
409 {
410 #ifdef COIN_THREADSAFE
411 PRIVATE(this)->normalcachemutex.writeUnlock();
412 #endif // COIN_THREADSAFE
413 }
414
415 #undef PRIVATE
416
417 #endif // HAVE_VRML97
418