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