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 SoVertexShape SoVertexShape.h Inventor/nodes/SoVertexShape.h
35 \brief The SoVertexShape class is the superclass for all vertex based shapes.
36
37 \ingroup nodes
38
39 Basically, every polygon-, line- or point-based shape will inherit
40 this class. It contains methods for organizing the normal cache,
41 and also holds the SoVertexShape::vertexProperty field which can be
42 used to set vertex data inside the node.
43 */
44
45 // *************************************************************************
46
47 #include <Inventor/nodes/SoVertexShape.h>
48
49 #ifdef HAVE_CONFIG_H
50 #include <config.h>
51 #endif // HAVE_CONFIG_H
52
53 #include <Inventor/actions/SoGLRenderAction.h>
54 #include <Inventor/caches/SoNormalCache.h>
55 #include <Inventor/elements/SoCacheElement.h>
56 #include <Inventor/elements/SoCoordinateElement.h>
57 #include <Inventor/elements/SoCreaseAngleElement.h>
58 #include <Inventor/elements/SoGLShapeHintsElement.h>
59 #include <Inventor/elements/SoNormalElement.h>
60 #include <Inventor/misc/SoState.h>
61 #include <Inventor/nodes/SoVertexProperty.h>
62 #include <Inventor/threads/SbRWMutex.h>
63
64 #include "nodes/SoSubNodeP.h"
65 #include "tidbitsp.h"
66
67 // *************************************************************************
68
69 /*!
70 \var SoSFNode SoVertexShape::vertexProperty
71
72 If you set the vertexProperty field, it should be with an
73 SoVertexProperty node. Otherwise it will simply be
74 ignored. Nodetypes inheriting SoVertexShape will then get their
75 coordinate data from the vertexProperty node instead of from the
76 global traversal state.
77
78 The vertexProperty field of SoVertexShape-derived nodes breaks
79 somewhat with the basic design of Open Inventor, as its contents are
80 not passed to the global state. This is done to provide a simple
81 path to highly optimized rendering of vertexbased shapes.
82
83 \sa SoVertexProperty
84
85 \since Coin 1.0
86 \since SGI Inventor 2.1
87 */
88
89 // *************************************************************************
90
91 class SoVertexShapeP {
92 public:
93 SoNormalCache * normalcache;
94
95 // we can use a per-instance mutex here instead of this class-wide
96 // one, but we go for the class-wide one since at least MSWindows
97 // might have a rather strict limit on the total amount of mutex
98 // resources a process / user can hold at any one time.
99 //
100 // i haven't looked too hard at the affected code regions in the
101 // sub-classes, however. it might be that a class-wide lock can
102 // cause significantly less efficient execution in a multi-threaded
103 // environment. if so, we will have to come up with something better
104 // than just a class-wide lock (a mutex pool or something, i
105 // suppose).
106 //
107 // -mortene.
108 static SbRWMutex * normalcachemutex;
109
110 static void cleanup(void);
111 };
112
113 // called by atexit
114 void
cleanup(void)115 SoVertexShapeP::cleanup(void)
116 {
117 delete SoVertexShapeP::normalcachemutex;
118 SoVertexShapeP::normalcachemutex = NULL;
119 }
120
121 SbRWMutex * SoVertexShapeP::normalcachemutex = NULL;
122
123 #define PRIVATE(obj) ((obj)->pimpl)
124
125 // *************************************************************************
126
127 SO_NODE_ABSTRACT_SOURCE(SoVertexShape);
128
129 // *************************************************************************
130
131
132 // doc from superclass
133 void
initClass(void)134 SoVertexShape::initClass(void)
135 {
136 SO_NODE_INTERNAL_INIT_ABSTRACT_CLASS(SoVertexShape, SO_FROM_INVENTOR_1);
137
138 #ifdef COIN_THREADSAFE
139 SoVertexShapeP::normalcachemutex = new SbRWMutex(SbRWMutex::READ_PRECEDENCE);
140 #endif // COIN_THREADSAFE
141
142 coin_atexit((coin_atexit_f *)SoVertexShapeP::cleanup, CC_ATEXIT_NORMAL);
143 }
144
145 /*!
146 Constructor.
147 */
SoVertexShape(void)148 SoVertexShape::SoVertexShape(void)
149 {
150 PRIVATE(this) = new SoVertexShapeP;
151 PRIVATE(this)->normalcache = NULL;
152
153 SO_NODE_INTERNAL_CONSTRUCTOR(SoVertexShape);
154
155 SO_NODE_ADD_FIELD(vertexProperty, (NULL));
156 }
157
158 /*!
159 Destructor.
160 */
~SoVertexShape()161 SoVertexShape::~SoVertexShape()
162 {
163 if (PRIVATE(this)->normalcache) PRIVATE(this)->normalcache->unref();
164 delete PRIVATE(this);
165 }
166
167 // *************************************************************************
168
169 // Documented in superclass.
170 void
notify(SoNotList * nl)171 SoVertexShape::notify(SoNotList * nl)
172 {
173 this->readLockNormalCache();
174 if (PRIVATE(this)->normalcache) PRIVATE(this)->normalcache->invalidate();
175 this->readUnlockNormalCache();
176 inherited::notify(nl);
177 }
178
179 // This documentation block has a copy in vrml97/VertexShape.cpp.
180 /*!
181 \COININTERNAL
182
183 Subclasses should override this method to generate default normals
184 using the SoNormalBundle class. \c TRUE should be returned if
185 normals were generated, \c FALSE otherwise.
186
187 Default method returns \c FALSE.
188
189 \COIN_FUNCTION_EXTENSION
190 */
191 SbBool
generateDefaultNormals(SoState *,SoNormalBundle *)192 SoVertexShape::generateDefaultNormals(SoState *, SoNormalBundle *)
193 {
194 return FALSE;
195 }
196
197 // This documentation block has a copy in vrml97/VertexShape.cpp.
198 /*!
199 \COININTERNAL
200
201 Subclasses should override this method to generate default normals
202 using the SoNormalCache class. This is more effective than using
203 SoNormalGenerator. Return \c TRUE if normals were generated, \c
204 FALSE otherwise.
205
206 Default method just returns \c FALSE.
207
208 \COIN_FUNCTION_EXTENSION
209 */
210 SbBool
generateDefaultNormals(SoState *,SoNormalCache *)211 SoVertexShape::generateDefaultNormals(SoState * /* state */,
212 SoNormalCache * /* nc */)
213 {
214 return FALSE;
215 }
216
217 // doc from superclass
218 SbBool
shouldGLRender(SoGLRenderAction * action)219 SoVertexShape::shouldGLRender(SoGLRenderAction * action)
220 {
221 return SoShape::shouldGLRender(action);
222 }
223
224 /*!
225 Sets normal cache to contain the normals specified by \a normals and \a num,
226 and forces cache dependencies on coordinates, shape hints and crease angle.
227 */
228 void
setNormalCache(SoState * const state,const int num,const SbVec3f * normals)229 SoVertexShape::setNormalCache(SoState * const state,
230 const int num,
231 const SbVec3f * normals)
232 {
233 this->writeLockNormalCache();
234 if (PRIVATE(this)->normalcache) PRIVATE(this)->normalcache->unref();
235 // create new normal cache with no dependencies
236 state->push();
237 PRIVATE(this)->normalcache = new SoNormalCache(state);
238 PRIVATE(this)->normalcache->ref();
239 PRIVATE(this)->normalcache->set(num, normals);
240 // force element dependencies
241 (void) SoCoordinateElement::getInstance(state);
242 (void) SoShapeHintsElement::getVertexOrdering(state);
243 (void) SoCreaseAngleElement::get(state);
244 state->pop();
245 this->writeUnlockNormalCache();
246 }
247
248 /*!
249 Returns the current normal cache, or NULL if there is none.
250 */
251 SoNormalCache *
getNormalCache(void) const252 SoVertexShape::getNormalCache(void) const
253 {
254 return PRIVATE(this)->normalcache;
255 }
256
257 /*!
258
259 Convenience method that can be used by subclasses to return or
260 create a normal cache. If the current cache is not valid, it takes
261 care of unrefing the old cache and pushing and popping the state to
262 create element dependencies when creating the new cache.
263
264 When returning from this method, the normal cache will be
265 read locked, and the caller should call readUnlockNormalCache()
266 when the normals in the cache is no longer needed.
267
268 \COIN_FUNCTION_EXTENSION
269
270 \since Coin 2.0
271 */
272 SoNormalCache *
generateAndReadLockNormalCache(SoState * const state)273 SoVertexShape::generateAndReadLockNormalCache(SoState * const state)
274 {
275 this->readLockNormalCache();
276 if (PRIVATE(this)->normalcache && PRIVATE(this)->normalcache->isValid(state)) {
277 return PRIVATE(this)->normalcache;
278 }
279 this->readUnlockNormalCache();
280 this->writeLockNormalCache();
281
282 SbBool storeinvalid = SoCacheElement::setInvalid(FALSE);
283
284 if (PRIVATE(this)->normalcache) PRIVATE(this)->normalcache->unref();
285 state->push(); // need to push for cache dependencies
286 PRIVATE(this)->normalcache = new SoNormalCache(state);
287 PRIVATE(this)->normalcache->ref();
288 SoCacheElement::set(state, PRIVATE(this)->normalcache);
289 //
290 // See if the node supports the Coin-way of generating normals
291 //
292 if (!generateDefaultNormals(state, PRIVATE(this)->normalcache)) {
293 // FIXME: implement SoNormalBundle
294 if (generateDefaultNormals(state, (SoNormalBundle *)NULL)) {
295 // FIXME: set generator in normal cache
296 }
297 }
298 state->pop(); // don't forget this pop
299
300 SoCacheElement::setInvalid(storeinvalid);
301 this->writeUnlockNormalCache();
302 this->readLockNormalCache();
303 return PRIVATE(this)->normalcache;
304 }
305
306 /*!
307 Convenience method that returns the current coordinate and normal
308 element. This method is not part of the OIV API.
309 */
310 void
getVertexData(SoState * state,const SoCoordinateElement * & coords,const SbVec3f * & normals,const SbBool neednormals)311 SoVertexShape::getVertexData(SoState * state,
312 const SoCoordinateElement *& coords,
313 const SbVec3f *& normals,
314 const SbBool neednormals)
315 {
316 coords = SoCoordinateElement::getInstance(state);
317 assert(coords);
318
319 normals = NULL;
320 if (neednormals) {
321 normals = SoNormalElement::getInstance(state)->getArrayPtr();
322 }
323 }
324
325 // doc from superclass
326 void
write(SoWriteAction * action)327 SoVertexShape::write(SoWriteAction * action)
328 {
329 inherited::write(action);
330 }
331
332 // *************************************************************************
333
334 /*!
335 Read lock the normal cache. This method should be called before
336 fetching the normal cache (using getNormalCache()). When the cached
337 normals are no longer needed, readUnlockNormalCache() must be called.
338
339 It is also possible to use generateAndReadLockNormalCache().
340
341 \COIN_FUNCTION_EXTENSION
342
343 \sa readUnlockNormalCache()
344 \since Coin 2.0
345 */
346 void
readLockNormalCache(void)347 SoVertexShape::readLockNormalCache(void)
348 {
349 if (SoVertexShapeP::normalcachemutex) {
350 SoVertexShapeP::normalcachemutex->readLock();
351 }
352 }
353
354 /*!
355 Read unlock the normal cache. Should be called when the read-locked
356 cached normals are no longer needed.
357
358 \sa readLockNormalCache()
359 \since Coin 2.0
360 */
361 void
readUnlockNormalCache(void)362 SoVertexShape::readUnlockNormalCache(void)
363 {
364 if (SoVertexShapeP::normalcachemutex) {
365 SoVertexShapeP::normalcachemutex->readUnlock();
366 }
367 }
368
369 void
writeLockNormalCache(void)370 SoVertexShape::writeLockNormalCache(void)
371 {
372 if (SoVertexShapeP::normalcachemutex) {
373 SoVertexShapeP::normalcachemutex->writeLock();
374 }
375 }
376
377 void
writeUnlockNormalCache(void)378 SoVertexShape::writeUnlockNormalCache(void)
379 {
380 if (SoVertexShapeP::normalcachemutex) {
381 SoVertexShapeP::normalcachemutex->writeUnlock();
382 }
383 }
384
385 // *************************************************************************
386
387 #undef PRIVATE
388