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 SoCallbackAction SoCallbackAction.h Inventor/actions/SoCallbackAction.h
35   \brief The SoCallbackAction class invokes callbacks at specific nodes.
36 
37   \ingroup actions
38 
39   This action has mechanisms for tracking traversal position and
40   traversal state.  In combination with the ability to pass geometry
41   primitives to callback actions set by the user, this does for
42   instance make it rather straightforward to extract the geometry of a
43   scene graph.
44 
45   You should be able to use this action for most of your "simple"
46   traversal needs, instead of cooking up your own code, as the
47   SoCallbackAction is rather flexible.
48 
49   A common use of this action is to extract geometry of non-primitive
50   shapes as triangles.  A full-fledged example that demonstrates this
51   on a scenegraph with two spheres follows:
52 
53   \code
54    #include <Inventor/SoDB.h>
55    #include <Inventor/SoPrimitiveVertex.h>
56    #include <Inventor/actions/SoCallbackAction.h>
57    #include <Inventor/nodes/SoCoordinate3.h>
58    #include <Inventor/nodes/SoIndexedFaceSet.h>
59    #include <Inventor/nodes/SoSeparator.h>
60    #include <Inventor/nodes/SoShape.h>
61    #include <Inventor/nodes/SoSphere.h>
62    #include <Inventor/nodes/SoTranslation.h>
63 
64 
65    static SoCoordinate3 * coord3 = NULL;
66    static SoIndexedFaceSet * ifs = NULL;
67 
68    static int coord3idx = 0;
69 
70 
71    static void
72    triangle_cb(void * userdata, SoCallbackAction * action,
73                const SoPrimitiveVertex * v1,
74                const SoPrimitiveVertex * v2,
75                const SoPrimitiveVertex * v3)
76    {
77      const SbVec3f vtx[] = { v1->getPoint(), v2->getPoint(), v3->getPoint() };
78      const SbMatrix mm = action->getModelMatrix();
79 
80      SbVec3f vx[3];
81      for (int j=0; j < 3; j++) { mm.multVecMatrix(vtx[j], vx[j]); }
82 
83      // (This is sub-optimal -- should scan for the same vertex
84      // coordinates already being present in the SoCoordinate3
85      // node. We'll get lots of duplicate coordinates from this.)
86      coord3->point.setNum(coord3->point.getNum() + 3);
87      coord3->point.setValues(coord3idx, 3, vx);
88 
89      int32_t indices[] = { coord3idx, coord3idx + 1, coord3idx + 2, -1 };
90      coord3idx += 3;
91 
92      int oldsize = ifs->coordIndex.getNum();
93      ifs->coordIndex.setNum(oldsize + 4);
94      ifs->coordIndex.setValues(oldsize, 4, indices);
95 
96      // (Note that it would likely be desirable to grab normal vectors,
97      // materials and / or texture coordinates in a real-world
98      // application. How to do this is not shown by the above code,
99      // but it is not much different from the extraction of vertex
100      // coordinates.)
101    }
102 
103 
104    int
105    main(void)
106    {
107      SoDB::init();
108 
109      SoSeparator * root = new SoSeparator;
110      root->addChild(new SoSphere);
111      SoTranslation * trans = new SoTranslation;
112      trans->translation.setValue(10, 0, 0);
113      root->addChild(trans);
114      SoSphere * ss = new SoSphere;
115      ss->radius = 3;
116      root->addChild(ss);
117 
118      root->ref();
119 
120      coord3 = new SoCoordinate3;
121      coord3->point.setNum(0);
122      ifs = new SoIndexedFaceSet;
123      ifs->coordIndex.setNum(0);
124 
125      SoCallbackAction ca;
126      ca.addTriangleCallback(SoShape::getClassTypeId(), triangle_cb, NULL);
127      ca.apply(root);
128 
129      root->unref();
130 
131      // [the generated SoCoordinate3 and SoIndexedFaceSet nodes would now
132      // typically be used in a scenegraph in a viewer, or written to disk
133      // or something]
134 
135      return 0;
136    }
137   \endcode
138 */
139 
140 /*!
141   \typedef void SoTriangleCB(void *userdata, SoCallbackAction *action, const SoPrimitiveVertex *v1, const SoPrimitiveVertex *v2, const SoPrimitiveVertex *v3)
142 
143   \param userdata is a void pointer to any data the application need to
144   know of in the callback function (like for instance a \e this
145   pointer).
146   \param action the action which invoked the callback
147   \param v1 first vertex of the triangle
148   \param v2 second vertex of the triangle
149   \param v3 third vertex of the triangle
150 
151   \sa SoLineSegmentCB, SoPointCB
152 */
153 
154 /*!
155   \typedef void SoLineSegmentCB(void *userdata, SoCallbackAction *action, const SoPrimitiveVertex *v1, const SoPrimitiveVertex *v2)
156 
157   \param userdata is a void pointer to any data the application need to
158   know of in the callback function (like for instance a \e this
159   pointer).
160   \param action the action which invoked the callback
161   \param v1 first vertex of the line
162   \param v2 second vertex of the line
163 
164   \sa setPassCallback() SoPointCB
165 */
166 
167 /*!
168   \typedef void SoPointCB(void *userdata, SoCallbackAction *action, const SoPrimitiveVertex *v)
169 
170   \param userdata is a void pointer to any data the application need to
171   know of in the callback function (like for instance a \e this
172   pointer).
173   \param action the action which invoked the callback
174   \param v the vertex of the point
175 
176   \sa setPassCallback()
177 */
178 
179 
180 /*! \file SoCallbackAction.h */
181 #include <Inventor/actions/SoCallbackAction.h>
182 
183 #include <Inventor/SoPath.h>
184 #include <Inventor/elements/SoComplexityElement.h>
185 #include <Inventor/elements/SoCoordinateElement.h>
186 #include <Inventor/elements/SoCreaseAngleElement.h>
187 #include <Inventor/elements/SoDecimationPercentageElement.h>
188 #include <Inventor/elements/SoFocalDistanceElement.h>
189 #include <Inventor/elements/SoFontNameElement.h>
190 #include <Inventor/elements/SoFontSizeElement.h>
191 #include <Inventor/elements/SoLazyElement.h>
192 #include <Inventor/elements/SoLightAttenuationElement.h>
193 #include <Inventor/elements/SoLinePatternElement.h>
194 #include <Inventor/elements/SoLineWidthElement.h>
195 #include <Inventor/elements/SoMaterialBindingElement.h>
196 #include <Inventor/elements/SoModelMatrixElement.h>
197 #include <Inventor/elements/SoNormalBindingElement.h>
198 #include <Inventor/elements/SoNormalElement.h>
199 #include <Inventor/elements/SoOverrideElement.h>
200 #include <Inventor/elements/SoPickStyleElement.h>
201 #include <Inventor/elements/SoPointSizeElement.h>
202 #include <Inventor/elements/SoProfileCoordinateElement.h>
203 #include <Inventor/elements/SoProfileElement.h>
204 #include <Inventor/elements/SoProjectionMatrixElement.h>
205 #include <Inventor/elements/SoShapeHintsElement.h>
206 #include <Inventor/elements/SoSwitchElement.h>
207 #include <Inventor/elements/SoMultiTextureCoordinateElement.h>
208 #include <Inventor/elements/SoMultiTextureMatrixElement.h>
209 #include <Inventor/elements/SoTextureOverrideElement.h>
210 #include <Inventor/elements/SoUnitsElement.h>
211 #include <Inventor/elements/SoViewVolumeElement.h>
212 #include <Inventor/elements/SoViewingMatrixElement.h>
213 #include <Inventor/elements/SoViewportRegionElement.h>
214 #include <Inventor/elements/SoCacheElement.h>
215 #include <Inventor/elements/SoViewportRegionElement.h>
216 #include <Inventor/elements/SoCullElement.h>
217 #include <Inventor/lists/SoEnabledElementsList.h>
218 #include <Inventor/misc/SoState.h>
219 #include <Inventor/nodes/SoShape.h>
220 #include <Inventor/SbViewportRegion.h>
221 
222 #include "actions/SoSubActionP.h"
223 #include "SbBasicP.h"
224 
225 #ifndef DOXYGEN_SKIP_THIS
226 
227 class SoCallbackData { //internal class
228 public:
SoCallbackData(void * cbfunc=NULL,void * userdata=NULL)229   SoCallbackData(void * cbfunc = NULL, void * userdata = NULL)
230     : func(cbfunc), data(userdata), next(NULL) {}
231 
232 
append(SoCallbackData * newdata)233   void append(SoCallbackData * newdata) {
234     SoCallbackData * cbdata = this;
235     while (cbdata->next != NULL) cbdata = cbdata->next;
236     cbdata->next = newdata;
237   }
238 
deleteAll(void)239   void deleteAll(void) {
240     SoCallbackData * cbdata = this;
241     SoCallbackData * nextptr;
242     while (cbdata) {
243       nextptr = cbdata->next;
244       delete cbdata;
245       cbdata = nextptr;
246     }
247   }
248 
249   SoCallbackAction::Response doNodeCallbacks(SoCallbackAction * action,
250                                              const SoNode * node);
251   void doTriangleCallbacks(SoCallbackAction * action,
252                            const SoPrimitiveVertex * const v1,
253                            const SoPrimitiveVertex * const v2,
254                            const SoPrimitiveVertex * const v3);
255 
256   void doLineSegmentCallbacks(SoCallbackAction * action,
257                               const SoPrimitiveVertex * const v1,
258                               const SoPrimitiveVertex * const v2);
259   void doPointCallbacks(SoCallbackAction * action,
260                         const SoPrimitiveVertex * v);
261 
262 public:
263   void * func;
264   void * data;
265   SoCallbackData * next;
266 };
267 
268 
269 SoCallbackAction::Response
doNodeCallbacks(SoCallbackAction * action,const SoNode * node)270 SoCallbackData::doNodeCallbacks(SoCallbackAction * action,
271                                 const SoNode * node)
272 {
273   SoCallbackData * cbdata = this;
274   SoCallbackAction::Response response = SoCallbackAction::CONTINUE;
275   while (cbdata) {
276     assert(cbdata->func != NULL);
277     SoCallbackAction::SoCallbackActionCB * cbfunc =
278       object_to_function_cast<SoCallbackAction::SoCallbackActionCB *>( cbdata->func);
279     SoCallbackAction::Response ret = cbfunc(cbdata->data, action, node);
280     if (ret == SoCallbackAction::ABORT) return SoCallbackAction::ABORT;
281     if (ret == SoCallbackAction::PRUNE) response = ret;
282     cbdata = cbdata->next;
283   }
284   return response;
285 }
286 
287 void
doTriangleCallbacks(SoCallbackAction * action,const SoPrimitiveVertex * const v1,const SoPrimitiveVertex * const v2,const SoPrimitiveVertex * const v3)288 SoCallbackData::doTriangleCallbacks(SoCallbackAction * action,
289                                     const SoPrimitiveVertex * const v1,
290                                     const SoPrimitiveVertex * const v2,
291                                     const SoPrimitiveVertex * const v3)
292 {
293   SoCallbackData * cbdata = this;
294   while (cbdata) {
295     assert(cbdata->func != NULL);
296     SoTriangleCB * tricb = object_to_function_cast<SoTriangleCB *> (cbdata->func);
297     tricb(cbdata->data, action, v1, v2, v3);
298     cbdata = cbdata->next;
299   }
300 }
301 
302 void
doLineSegmentCallbacks(SoCallbackAction * action,const SoPrimitiveVertex * const v1,const SoPrimitiveVertex * const v2)303 SoCallbackData::doLineSegmentCallbacks(SoCallbackAction * action,
304                                        const SoPrimitiveVertex * const v1,
305                                        const SoPrimitiveVertex * const v2)
306 {
307   SoCallbackData * cbdata = this;
308   while (cbdata) {
309     assert(cbdata->func != NULL);
310     SoLineSegmentCB * linecb = object_to_function_cast<SoLineSegmentCB *>( cbdata->func);
311     linecb(cbdata->data, action, v1, v2);
312     cbdata = cbdata->next;
313   }
314 }
315 
316 void
doPointCallbacks(SoCallbackAction * action,const SoPrimitiveVertex * v)317 SoCallbackData::doPointCallbacks(SoCallbackAction * action,
318                                  const SoPrimitiveVertex * v)
319 {
320   SoCallbackData * cbdata = this;
321   while (cbdata) {
322     assert(cbdata->func != NULL);
323     SoPointCB * ptcb = object_to_function_cast<SoPointCB *>( cbdata->func);
324     ptcb(cbdata->data, action, v);
325     cbdata = cbdata->next;
326   }
327 }
328 
329 // class to hold private, hidden data
330 class SoCallbackActionP {
331 public:
332   SbBool viewportset;
333   SbViewportRegion viewport;
334   SoCallbackAction::Response response;
335   SoNode * currentnode;
336 
337   SbList <SoCallbackData *> precallback;
338   SbList <SoCallbackData *> postcallback;
339 
340   SoCallbackData * pretailcallback;
341   SoCallbackData * posttailcallback;
342 
343   SbList <SoCallbackData *> trianglecallback;
344   SbList <SoCallbackData *> linecallback;
345   SbList <SoCallbackData *> pointcallback;
346 
347   SbBool callbackall;
348 };
349 
350 #endif // !DOXYGEN_SKIP_THIS
351 
352 
353 // ***********************************************************************
354 
355 /*!
356   \typedef Response SoCallbackAction::SoCallbackActionCB(void * userdata, SoCallbackAction * action, const SoNode * node)
357 
358   Callback functions need to be of this type. \a node is at the
359   current traversal point in the scene graph.
360  */
361 
362 /*!
363   \enum SoCallbackAction::Response
364   Response values for callback function.
365  */
366 /*!
367   \var SoCallbackAction::Response SoCallbackAction::CONTINUE
368   Continue traversal as usual.
369  */
370 /*!
371   \var SoCallbackAction::Response SoCallbackAction::ABORT
372   Abort traversal immediately.  No other callbacks are called after
373   this has been returned.
374  */
375 /*!
376   \var SoCallbackAction::Response SoCallbackAction::PRUNE
377   Don't do traversal of neither the current node (if returning from a
378   pre-traversal callback) nor its children.
379 
380   If returned from a pre-callback, the post-callbacks will still be
381   called.  If returned from a post-callback, the behaviour will be the
382   same as for returning CONTINUE.
383 */
384 
385 // ***********************************************************************
386 
387 
388 SO_ACTION_SOURCE(SoCallbackAction);
389 
390 
391 // Override from parent class.
392 void
initClass(void)393 SoCallbackAction::initClass(void)
394 {
395   SO_ACTION_INTERNAL_INIT_CLASS(SoCallbackAction, SoAction);
396 
397   SO_ENABLE(SoCallbackAction, SoViewportRegionElement);
398   SO_ENABLE(SoCallbackAction, SoDecimationTypeElement);
399   SO_ENABLE(SoCallbackAction, SoDecimationPercentageElement);
400   SO_ENABLE(SoCallbackAction, SoOverrideElement);
401   SO_ENABLE(SoCallbackAction, SoTextureOverrideElement);
402   SO_ENABLE(SoCallbackAction, SoLazyElement);
403   SO_ENABLE(SoCallbackAction, SoCacheElement);
404 
405   // view frustum culling is normally not used for this action, but
406   // the application programmer can manually add any number of culling
407   // planes to optimize callback action traversal. This is used by the
408   // SoExtSelection node.
409   SO_ENABLE(SoCallbackAction, SoCullElement);
410 }
411 
412 #define PRIVATE(obj) ((obj)->pimpl)
413 
414 /*!
415   Default constructor. Will set the viewport to a standard
416   viewport with size 640x512.
417 */
SoCallbackAction(void)418 SoCallbackAction::SoCallbackAction(void)
419 {
420   this->commonConstructor();
421 }
422 
423 /*!
424   Constructor which lets you specify the viewport.
425 
426   This constructor is an extension versus the Open Inventor API.
427 */
SoCallbackAction(const SbViewportRegion & vp)428 SoCallbackAction::SoCallbackAction(const SbViewportRegion & vp)
429 {
430   this->commonConstructor();
431   PRIVATE(this)->viewport = vp;
432   PRIVATE(this)->viewportset = TRUE;
433 }
434 
435 void
commonConstructor(void)436 SoCallbackAction::commonConstructor(void)
437 {
438   SO_ACTION_CONSTRUCTOR(SoCallbackAction);
439 
440   PRIVATE(this)->pretailcallback = NULL;
441   PRIVATE(this)->posttailcallback = NULL;
442   PRIVATE(this)->viewportset = FALSE;
443   PRIVATE(this)->callbackall = FALSE;
444 }
445 
446 /*!
447   Sets the viewport region for this action. When set, the viewport
448   element is initialized right before a traversal starts, making it
449   the current viewport.
450 
451   This method is an extension versus the Open Inventor API.
452 */
453 void
setViewportRegion(const SbViewportRegion & vp)454 SoCallbackAction::setViewportRegion(const SbViewportRegion & vp)
455 {
456   PRIVATE(this)->viewport = vp;
457   PRIVATE(this)->viewportset = TRUE;
458 }
459 
460 static void
delete_list_elements(SbList<SoCallbackData * > & cl)461 delete_list_elements(SbList<SoCallbackData *> & cl)
462 {
463   int n = cl.getLength();
464   for (int i = 0; i < n; i++) cl[i]->deleteAll();
465 }
466 
467 /*!
468   Destructor.
469 */
~SoCallbackAction()470 SoCallbackAction::~SoCallbackAction()
471 {
472   delete_list_elements(PRIVATE(this)->precallback);
473   delete_list_elements(PRIVATE(this)->postcallback);
474   delete_list_elements(PRIVATE(this)->trianglecallback);
475   delete_list_elements(PRIVATE(this)->linecallback);
476   delete_list_elements(PRIVATE(this)->pointcallback);
477 
478   if (PRIVATE(this)->pretailcallback) {
479     PRIVATE(this)->pretailcallback->deleteAll();
480   }
481   if (PRIVATE(this)->posttailcallback) {
482     PRIVATE(this)->posttailcallback->deleteAll();
483   }
484 }
485 
486 //
487 // for setting node callbacks. makes sure NULLs are filled in where not set
488 //
489 static void
set_callback_data_idx(SbList<SoCallbackData * > & list,const int idx,void * func,void * data)490 set_callback_data_idx(SbList<SoCallbackData *> & list, const int idx,
491                       void * func, void * data)
492 {
493   int n = list.getLength();
494   while (n <= idx) {
495     list.append(NULL);
496     n++;
497   }
498   if (list[idx] == NULL) list[idx] = new SoCallbackData(func, data);
499   else list[idx]->append(new SoCallbackData(func, data));
500 }
501 
502 static void
set_callback_data(SbList<SoCallbackData * > & list,const SoType type,void * func,void * data)503 set_callback_data(SbList<SoCallbackData *> & list, const SoType type,
504                   void * func, void * data)
505 {
506   SoTypeList derivedtypes;
507   int n = SoType::getAllDerivedFrom(type, derivedtypes);
508   for (int i = 0; i < n; i++) {
509     set_callback_data_idx(list, static_cast<int>(derivedtypes[i].getData()),
510                           func, data);
511   }
512 }
513 
514 /*!
515   Set a function \a cb to call before every node of \a type is
516   traversed. \a cb will be called with \a userdata.
517  */
518 void
addPreCallback(const SoType type,SoCallbackActionCB * cb,void * userdata)519 SoCallbackAction::addPreCallback(const SoType type, SoCallbackActionCB * cb,
520                                  void * userdata)
521 {
522   set_callback_data(PRIVATE(this)->precallback, type, function_to_object_cast<void *>(cb), userdata);
523 }
524 
525 /*!
526   Set a function \a cb to call after every node of \a type has been
527   traversed. \a cb will be called with \a userdata.
528  */
529 void
addPostCallback(const SoType type,SoCallbackActionCB * cb,void * userdata)530 SoCallbackAction::addPostCallback(const SoType type, SoCallbackActionCB * cb,
531                                   void * userdata)
532 {
533   set_callback_data(PRIVATE(this)->postcallback, type, function_to_object_cast<void *>(cb), userdata);
534 }
535 
536 /*!
537   Set a function \a cb to call before the tail of a path is
538   traversed. \a cb will be called with \a userdata.
539  */
540 void
addPreTailCallback(SoCallbackActionCB * cb,void * userdata)541 SoCallbackAction::addPreTailCallback(SoCallbackActionCB * cb, void * userdata)
542 {
543   if (PRIVATE(this)->pretailcallback == NULL)
544     PRIVATE(this)->pretailcallback = new SoCallbackData(function_to_object_cast<void *>(cb), userdata);
545   else
546     PRIVATE(this)->pretailcallback->append(new SoCallbackData(function_to_object_cast<void *>(cb), userdata));
547 }
548 
549 /*!
550   Set a function \a cb to call after the tail of a path has been
551   traversed. \a cb will be called with \a userdata.
552  */
553 void
addPostTailCallback(SoCallbackActionCB * cb,void * userdata)554 SoCallbackAction::addPostTailCallback(SoCallbackActionCB * cb, void * userdata)
555 {
556   if (PRIVATE(this)->posttailcallback == NULL)
557     PRIVATE(this)->posttailcallback = new SoCallbackData(function_to_object_cast<void *>(cb), userdata);
558   else
559     PRIVATE(this)->posttailcallback->append(new SoCallbackData(function_to_object_cast<void *>(cb), userdata));
560 }
561 
562 /*!
563   Set a function \a cb to call when traversing a node of \a type which
564   generates triangle primitives for rendering. \a cb will be called
565   with \a userdata.
566  */
567 void
addTriangleCallback(const SoType type,SoTriangleCB * cb,void * userdata)568 SoCallbackAction::addTriangleCallback(const SoType type, SoTriangleCB * cb,
569                                       void * userdata)
570 {
571   set_callback_data(PRIVATE(this)->trianglecallback, type, function_to_object_cast<void *>(cb), userdata);
572 }
573 
574 /*!
575   Set a function \a cb to call when traversing a node of \a type which
576   generates line primitives for rendering. \a cb will be called with
577   \a userdata.
578  */
579 void
addLineSegmentCallback(const SoType type,SoLineSegmentCB * cb,void * userdata)580 SoCallbackAction::addLineSegmentCallback(const SoType type, SoLineSegmentCB * cb,
581                                          void * userdata)
582 {
583   set_callback_data(PRIVATE(this)->linecallback, type, function_to_object_cast<void *>(cb), userdata);
584 }
585 
586 /*!
587   Set a function \a cb to call when traversing a node of \a type which
588   generates single point primitives for rendering. \a cb will be
589   called with \a userdata.
590  */
591 void
addPointCallback(const SoType type,SoPointCB * cb,void * userdata)592 SoCallbackAction::addPointCallback(const SoType type, SoPointCB * cb,
593                                    void * userdata)
594 {
595   set_callback_data(PRIVATE(this)->pointcallback, type, function_to_object_cast<void *>(cb), userdata);
596 }
597 
598 /************************************************************************************/
599 
600 /*!
601   Returns current decimation type setting.
602  */
603 SoDecimationTypeElement::Type
getDecimationType(void) const604 SoCallbackAction::getDecimationType(void) const
605 {
606   return SoDecimationTypeElement::get(this->state);
607 }
608 
609 /*!
610   Returns current decimation percentage setting.
611  */
612 float
getDecimationPercentage(void) const613 SoCallbackAction::getDecimationPercentage(void) const
614 {
615   return SoDecimationPercentageElement::get(this->state);
616 }
617 
618 /*!
619   Returns current complexity setting.
620  */
621 float
getComplexity(void) const622 SoCallbackAction::getComplexity(void) const
623 {
624   return SoComplexityElement::get(this->state);
625 }
626 
627 /*!
628   Returns current complexity type setting.
629 */
630 SoComplexity::Type
getComplexityType(void) const631 SoCallbackAction::getComplexityType(void) const
632 {
633   return static_cast<SoComplexity::Type>(SoComplexityTypeElement::get(this->state));
634 }
635 
636 /*!
637   Returns current number of coordinates in the state.
638 */
639 int32_t
getNumCoordinates(void) const640 SoCallbackAction::getNumCoordinates(void) const
641 {
642   return SoCoordinateElement::getInstance(this->state)->getNum();
643 }
644 
645 /*!
646   Returns a coordinate triplet from the current state pool of
647   coordinates.
648 */
649 const SbVec3f &
getCoordinate3(const int index) const650 SoCallbackAction::getCoordinate3(const int index) const
651 {
652   return SoCoordinateElement::getInstance(this->state)->get3(index);
653 }
654 
655 /*!
656   Returns a coordinate quartuplet from the current state pool of
657   coordinates.
658 */
659 const SbVec4f &
getCoordinate4(const int index) const660 SoCallbackAction::getCoordinate4(const int index) const
661 {
662   return SoCoordinateElement::getInstance(this->state)->get4(index);
663 }
664 
665 /*!
666   Returns current draw style setting.
667 */
668 SoDrawStyle::Style
getDrawStyle(void) const669 SoCallbackAction::getDrawStyle(void) const
670 {
671   return static_cast<SoDrawStyle::Style>(SoDrawStyleElement::get(this->state));
672 }
673 
674 /*!
675   Returns current line pattern setting.
676 */
677 unsigned short
getLinePattern(void) const678 SoCallbackAction::getLinePattern(void) const
679 {
680   return SoLinePatternElement::get(this->state);
681 }
682 
683 /*!
684   Returns current line width setting.
685 */
686 float
getLineWidth(void) const687 SoCallbackAction::getLineWidth(void) const
688 {
689   return SoLineWidthElement::get(this->state);
690 }
691 
692 /*!
693   Returns current point size setting.
694 */
695 float
getPointSize(void) const696 SoCallbackAction::getPointSize(void) const
697 {
698   return SoPointSizeElement::get(this->state);
699 }
700 
701 /*!
702   Returns current fontname setting.
703 */
704 const SbName &
getFontName(void) const705 SoCallbackAction::getFontName(void) const
706 {
707   return SoFontNameElement::get(this->state);
708 }
709 
710 /*!
711   Returns current fontsize setting.
712 */
713 float
getFontSize(void) const714 SoCallbackAction::getFontSize(void) const
715 {
716   return SoFontSizeElement::get(this->state);
717 }
718 
719 /*!
720   Returns current lightmodel setting.
721 */
722 SoLightModel::Model
getLightModel(void) const723 SoCallbackAction::getLightModel(void) const
724 {
725   return static_cast<SoLightModel::Model>(SoLazyElement::getLightModel(this->state));
726 }
727 
728 /*!
729   Returns current light attenuation setting.
730 */
731 const SbVec3f &
getLightAttenuation(void) const732 SoCallbackAction::getLightAttenuation(void) const
733 {
734   return SoLightAttenuationElement::get(this->state);
735 }
736 
737 
738 /*!
739   Returns current material settings.
740 */
741 void
getMaterial(SbColor & ambient,SbColor & diffuse,SbColor & specular,SbColor & emission,float & shininess,float & transparency,const int index) const742 SoCallbackAction::getMaterial(SbColor & ambient, SbColor & diffuse,
743                               SbColor & specular, SbColor & emission,
744                               float & shininess, float & transparency,
745                               const int index) const
746 {
747   ambient = SoLazyElement::getAmbient(this->state);
748   diffuse = SoLazyElement::getDiffuse(this->state, index);
749   emission = SoLazyElement::getEmissive(this->state);
750   specular = SoLazyElement::getSpecular(this->state);
751   shininess = SoLazyElement::getShininess(this->state);
752   transparency = SoLazyElement::getTransparency(this->state, index);
753 }
754 
755 /*!
756   Returns current materialbinding setting.
757 */
758 SoMaterialBinding::Binding
getMaterialBinding(void) const759 SoCallbackAction::getMaterialBinding(void) const
760 {
761   return static_cast<SoMaterialBinding::Binding>(
762     SoMaterialBindingElement::get(this->state)
763     );
764 }
765 
766 /*!
767   Returns current number of normals in the state.
768 */
769 uint32_t
getNumNormals(void) const770 SoCallbackAction::getNumNormals(void) const
771 {
772   return SoNormalElement::getInstance(this->state)->getNum();
773 }
774 
775 /*!
776   Returns the normal vectors at \a index from the current state.
777 */
778 const SbVec3f &
getNormal(const int index) const779 SoCallbackAction::getNormal(const int index) const
780 {
781   return SoNormalElement::getInstance(this->state)->get(index);
782 }
783 
784 /*!
785   Returns current normalbinding setting.
786 */
787 SoNormalBinding::Binding
getNormalBinding(void) const788 SoCallbackAction::getNormalBinding(void) const
789 {
790   return static_cast<SoNormalBinding::Binding>(
791     SoNormalBindingElement::get(this->state)
792     );
793 }
794 
795 /*!
796   Returns current number of profile coordinates in the state.
797 */
798 int32_t
getNumProfileCoordinates(void) const799 SoCallbackAction::getNumProfileCoordinates(void) const
800 {
801   return SoProfileCoordinateElement::getInstance(this->state)->getNum();
802 }
803 
804 /*!
805   Returns current number of SbVec2f profile coordinates in the state.
806 */
807 const SbVec2f &
getProfileCoordinate2(const int index) const808 SoCallbackAction::getProfileCoordinate2(const int index) const
809 {
810   return SoProfileCoordinateElement::getInstance(this->state)->get2(index);
811 }
812 
813 /*!
814   Returns current number of SbVec3f profile coordinates in the state.
815 */
816 const SbVec3f &
getProfileCoordinate3(const int index) const817 SoCallbackAction::getProfileCoordinate3(const int index) const
818 {
819   return SoProfileCoordinateElement::getInstance(this->state)->get3(index);
820 }
821 
822 /*!
823   Returns current list of profile nodes.
824 */
825 const SoNodeList &
getProfile(void) const826 SoCallbackAction::getProfile(void) const
827 {
828   return SoProfileElement::get(this->state);
829 }
830 
831 /*!
832   Returns current vertexordering shapehint setting.
833 
834   Please note that this is the vertex ordering set by the SoShapeHints
835   node. If you want to find the vertex ordering for VRML nodes you'll
836   need to read this directly from the \a ccw field in those
837   nodes.
838 */
839 SoShapeHints::VertexOrdering
getVertexOrdering(void) const840 SoCallbackAction::getVertexOrdering(void) const
841 {
842   return static_cast<SoShapeHints::VertexOrdering>(
843     SoShapeHintsElement::getVertexOrdering(this->state)
844     );
845 }
846 
847 /*!
848   Returns current shapetype hint setting.
849 
850   Please note that this is the shape type set by the SoShapeHints
851   node. If you want to find the shape type for VRML nodes you'll
852   need to read this directly from the \a solid field in those
853   nodes.
854 */
855 SoShapeHints::ShapeType
getShapeType(void) const856 SoCallbackAction::getShapeType(void) const
857 {
858   return static_cast<SoShapeHints::ShapeType>(
859     SoShapeHintsElement::getShapeType(this->state)
860     );
861 }
862 
863 /*!
864   Returns current facetype hint setting.
865 
866   Please note that this is the face type set by the SoShapeHints
867   node. If you want to find the face type for VRML nodes you'll
868   need to read this directly from the \a convex field in those
869   nodes.
870 
871 */
872 SoShapeHints::FaceType
getFaceType(void) const873 SoCallbackAction::getFaceType(void) const
874 {
875   return static_cast<SoShapeHints::FaceType>(
876     SoShapeHintsElement::getFaceType(this->state)
877     );
878 }
879 
880 /*!
881   Returns current creaseangle setting. Please note that this is the
882   crease angle value set by the SoShapeHints node. If you want to find
883   the crease angle for VRML nodes you'll need to read this directly
884   from the creaseAngle field in those nodes.
885 */
886 float
getCreaseAngle(void) const887 SoCallbackAction::getCreaseAngle(void) const
888 {
889   return SoCreaseAngleElement::get(this->state);
890 }
891 
892 /*!
893   Returns current number of texture coordinates in the traversal
894   state.
895 */
896 int32_t
getNumTextureCoordinates(void) const897 SoCallbackAction::getNumTextureCoordinates(void) const
898 {
899   return SoMultiTextureCoordinateElement::getInstance(this->state)->getNum(0);
900 }
901 
902 /*!
903   Returns SbVec2f texture coordinate at \a index from the texture
904   coordinate pool of the traversal state.
905 */
906 const SbVec2f &
getTextureCoordinate2(const int index) const907 SoCallbackAction::getTextureCoordinate2(const int index) const
908 {
909   return SoMultiTextureCoordinateElement::getInstance(this->state)->get2(0, index);
910 }
911 
912 /*!
913   Returns SbVec3f texture coordinate at \a index from the texture
914   coordinate pool of the traversal state.
915 
916   \COIN_FUNCTION_EXTENSION
917 
918   \since Coin 2.0
919 */
920 const SbVec3f &
getTextureCoordinate3(const int index) const921 SoCallbackAction::getTextureCoordinate3(const int index) const
922 {
923   return SoMultiTextureCoordinateElement::getInstance(this->state)->get3(0, index);
924 }
925 
926 /*!
927   Returns SbVec4f texture coordinate at \a index from the texture
928   coordinate pool of the traversal state.
929 */
930 const SbVec4f &
getTextureCoordinate4(const int index) const931 SoCallbackAction::getTextureCoordinate4(const int index) const
932 {
933   return SoMultiTextureCoordinateElement::getInstance(this->state)->get4(0, index);
934 }
935 
936 /*!
937   Returns current texturecoordinate binding setting.
938 */
939 SoTextureCoordinateBinding::Binding
getTextureCoordinateBinding(void) const940 SoCallbackAction::getTextureCoordinateBinding(void) const
941 {
942   return static_cast<SoTextureCoordinateBinding::Binding>(
943     SoTextureCoordinateBindingElement::get(this->state)
944     );
945 }
946 
947 /*!
948   Returns current texture blend color setting.
949 */
950 const SbColor &
getTextureBlendColor(void) const951 SoCallbackAction::getTextureBlendColor(void) const
952 {
953   return SoMultiTextureImageElement::getBlendColor(this->state, 0);
954 }
955 
956 /*!
957   Returns current texture image settings.
958 */
959 const unsigned char *
getTextureImage(SbVec2s & size,int & numcomps) const960 SoCallbackAction::getTextureImage(SbVec2s & size, int & numcomps) const
961 {
962   return SoMultiTextureImageElement::getImage(state, 0, size, numcomps);
963 }
964 
965 /*!
966   Returns current 3D texture image settings.
967 
968   \COIN_FUNCTION_EXTENSION
969 
970   \since Coin 2.0
971 */
972 const unsigned char *
getTextureImage(SbVec3s & size,int & numcomps) const973 SoCallbackAction::getTextureImage(SbVec3s & size, int & numcomps) const
974 {
975   return SoMultiTextureImageElement::getImage(state, 0, size, numcomps);
976 }
977 
978 /*!
979   Returns current texture transformation matrix setting.
980 */
981 const SbMatrix &
getTextureMatrix(void) const982 SoCallbackAction::getTextureMatrix(void) const
983 {
984   return SoMultiTextureMatrixElement::get(this->state, 0);
985 }
986 
987 /*!
988   Returns current texturemapping model setting.
989 */
990 SoTexture2::Model
getTextureModel(void) const991 SoCallbackAction::getTextureModel(void) const
992 {
993   return static_cast<SoTexture2::Model>( SoMultiTextureImageElement::getModel(this->state, 0));
994 }
995 
996 /*!
997   Returns current texture wrapping setting for the \c S coordinate.
998 */
999 SoTexture2::Wrap
getTextureWrapS(void) const1000 SoCallbackAction::getTextureWrapS(void) const
1001 {
1002   return static_cast<SoTexture2::Wrap>( SoMultiTextureImageElement::getWrapS(this->state,0));
1003 }
1004 
1005 /*!
1006   Returns current texture wrapping setting for the \c T coordinate.
1007 */
1008 SoTexture2::Wrap
getTextureWrapT(void) const1009 SoCallbackAction::getTextureWrapT(void) const
1010 {
1011   return static_cast<SoTexture2::Wrap>(SoMultiTextureImageElement::getWrapT(this->state, 0));
1012 }
1013 
1014 /*!
1015   Returns current texture wrapping setting for the \c R coordinate.
1016 
1017   \COIN_FUNCTION_EXTENSION
1018 
1019   \since Coin 2.0
1020 */
1021 SoTexture2::Wrap
getTextureWrapR(void) const1022 SoCallbackAction::getTextureWrapR(void) const
1023 {
1024   return static_cast<SoTexture2::Wrap>(SoMultiTextureImageElement::getWrapR(this->state, 0));
1025 }
1026 
1027 /*!
1028   Returns current model matrix.
1029 */
1030 const SbMatrix &
getModelMatrix(void) const1031 SoCallbackAction::getModelMatrix(void) const
1032 {
1033   return SoModelMatrixElement::get(this->state);
1034 }
1035 
1036 /*!
1037   Returns current units setting.
1038 */
1039 SoUnits::Units
getUnits(void) const1040 SoCallbackAction::getUnits(void) const
1041 {
1042   return static_cast<SoUnits::Units>(SoUnitsElement::get(this->state));
1043 }
1044 
1045 /*!
1046   Returns current camera focal distance setting.
1047 */
1048 float
getFocalDistance(void) const1049 SoCallbackAction::getFocalDistance(void) const
1050 {
1051   return SoFocalDistanceElement::get(this->state);
1052 }
1053 
1054 /*!
1055   Returns current projection matrix.
1056 */
1057 const SbMatrix &
getProjectionMatrix(void) const1058 SoCallbackAction::getProjectionMatrix(void) const
1059 {
1060   return SoProjectionMatrixElement::get(this->state);
1061 }
1062 
1063 /*!
1064   Returns current viewing matrix.
1065 */
1066 const SbMatrix &
getViewingMatrix(void) const1067 SoCallbackAction::getViewingMatrix(void) const
1068 {
1069   return SoViewingMatrixElement::get(this->state);
1070 }
1071 
1072 /*!
1073   Returns current view volume setting.
1074 */
1075 const SbViewVolume &
getViewVolume(void) const1076 SoCallbackAction::getViewVolume(void) const
1077 {
1078   return SoViewVolumeElement::get(this->state);
1079 }
1080 
1081 /*!
1082   Returns current viewport region setting.
1083 
1084   This method is an extension versus the Open Inventor API.
1085 */
1086 const SbViewportRegion &
getViewportRegion(void) const1087 SoCallbackAction::getViewportRegion(void) const
1088 {
1089   return SoViewportRegionElement::get(this->getState());
1090 }
1091 
1092 /*!
1093   Returns current pickstyle setting.
1094 */
1095 SoPickStyle::Style
getPickStyle(void) const1096 SoCallbackAction::getPickStyle(void) const
1097 {
1098   return static_cast<SoPickStyle::Style>(SoPickStyleElement::get(this->state));
1099 }
1100 
1101 /*!
1102   Returns last SoSwitch::whichChild setting during the traversal.
1103 */
1104 int32_t
getSwitch(void) const1105 SoCallbackAction::getSwitch(void) const
1106 {
1107   return SoSwitchElement::get(this->state);
1108 }
1109 
1110 /************************************************************************************/
1111 
1112 /*!
1113   \COININTERNAL
1114  */
1115 SoCallbackAction::Response
getCurrentResponse(void) const1116 SoCallbackAction::getCurrentResponse(void) const
1117 {
1118   return PRIVATE(this)->response;
1119 }
1120 
1121 /*!
1122   \COININTERNAL
1123 
1124   Invoke all "pre traversal" callbacks.
1125  */
1126 void
invokePreCallbacks(const SoNode * const node)1127 SoCallbackAction::invokePreCallbacks(const SoNode * const node)
1128 {
1129   // reset response if previous node was pruned
1130   if (PRIVATE(this)->response == PRUNE) PRIVATE(this)->response = CONTINUE;
1131 
1132   int idx = static_cast<int>(node->getTypeId().getData());
1133 
1134   if (idx < PRIVATE(this)->precallback.getLength() && PRIVATE(this)->precallback[idx] != NULL) {
1135     PRIVATE(this)->response = PRIVATE(this)->precallback[idx]->doNodeCallbacks(this, node);
1136     if (PRIVATE(this)->response == SoCallbackAction::ABORT) {
1137       this->setTerminated(TRUE);
1138       return;
1139     }
1140   }
1141 
1142   if (this->getWhatAppliedTo() == SoAction::PATH &&
1143       this->getPathAppliedTo()->getTail() == node && PRIVATE(this)->pretailcallback != NULL) {
1144     PRIVATE(this)->response = PRIVATE(this)->pretailcallback->doNodeCallbacks(this, node);
1145     if (PRIVATE(this)->response == SoCallbackAction::ABORT) {
1146       this->setTerminated(TRUE);
1147       return;
1148     }
1149   }
1150   // FIXME: add code to handle pathlist traversal callbacks
1151   // pederb, 19991209
1152 }
1153 
1154 /*!
1155   \COININTERNAL
1156 
1157   Invoke all "post traversal" callbacks.
1158  */
1159 void
invokePostCallbacks(const SoNode * const node)1160 SoCallbackAction::invokePostCallbacks(const SoNode * const node)
1161 {
1162   // reset response if previous node was pruned
1163   if (PRIVATE(this)->response == PRUNE) PRIVATE(this)->response = CONTINUE;
1164 
1165   int idx = static_cast<int>(node->getTypeId().getData());
1166   if (idx < PRIVATE(this)->postcallback.getLength() && PRIVATE(this)->postcallback[idx] != NULL) {
1167     PRIVATE(this)->response = static_cast<Response>(PRIVATE(this)->postcallback[idx]->doNodeCallbacks(this, node));
1168     if (PRIVATE(this)->response == SoCallbackAction::ABORT) {
1169       this->setTerminated(TRUE);
1170       return;
1171     }
1172   }
1173 
1174   if (this->getWhatAppliedTo() == SoAction::PATH &&
1175       this->getPathAppliedTo()->getTail() == node && PRIVATE(this)->posttailcallback) {
1176     PRIVATE(this)->response = PRIVATE(this)->posttailcallback->doNodeCallbacks(this, node);
1177     if (PRIVATE(this)->response == SoCallbackAction::ABORT) {
1178       this->setTerminated(TRUE);
1179       return;
1180     }
1181   }
1182   // FIXME: add code to handle pathlist traversal callbacks
1183   // pederb, 19991209
1184 }
1185 
1186 /*!
1187   \COININTERNAL
1188 
1189   Invoke all "triangle generation" callbacks.
1190  */
1191 void
invokeTriangleCallbacks(const SoShape * const shape,const SoPrimitiveVertex * const v1,const SoPrimitiveVertex * const v2,const SoPrimitiveVertex * const v3)1192 SoCallbackAction::invokeTriangleCallbacks(const SoShape * const shape,
1193                                           const SoPrimitiveVertex * const v1,
1194                                           const SoPrimitiveVertex * const v2,
1195                                           const SoPrimitiveVertex * const v3)
1196 {
1197   int idx = static_cast<int>(shape->getTypeId().getData());
1198   if (idx < PRIVATE(this)->trianglecallback.getLength() && PRIVATE(this)->trianglecallback[idx] != NULL)
1199     PRIVATE(this)->trianglecallback[idx]->doTriangleCallbacks(this, v1, v2, v3);
1200 }
1201 
1202 /*!
1203   \COININTERNAL
1204 
1205   Invoke all "line segment generation" callbacks.
1206  */
1207 void
invokeLineSegmentCallbacks(const SoShape * const shape,const SoPrimitiveVertex * const v1,const SoPrimitiveVertex * const v2)1208 SoCallbackAction::invokeLineSegmentCallbacks(const SoShape * const shape,
1209                                              const SoPrimitiveVertex * const v1,
1210                                              const SoPrimitiveVertex * const v2)
1211 {
1212   int idx = static_cast<int>(shape->getTypeId().getData());
1213   if (idx < PRIVATE(this)->linecallback.getLength() && PRIVATE(this)->linecallback[idx] != NULL)
1214     PRIVATE(this)->linecallback[idx]->doLineSegmentCallbacks(this, v1, v2);
1215 }
1216 
1217 /*!
1218   \COININTERNAL
1219 
1220   Invoke all "point" callbacks.
1221  */
1222 void
invokePointCallbacks(const SoShape * const shape,const SoPrimitiveVertex * const v)1223 SoCallbackAction::invokePointCallbacks(const SoShape * const shape,
1224                                        const SoPrimitiveVertex * const v)
1225 {
1226   int idx = static_cast<int>(shape->getTypeId().getData());
1227   if (idx < PRIVATE(this)->pointcallback.getLength() && PRIVATE(this)->pointcallback[idx] != NULL)
1228     PRIVATE(this)->pointcallback[idx]->doPointCallbacks(this, v);
1229 }
1230 
1231 /*!
1232   \COININTERNAL
1233 
1234   Check from the shape nodes whether or not to generate primitives
1235   from the complex shapes. If there are no callbacks attached to the
1236   node types, making the primitives would only be a waste of CPU.
1237  */
1238 SbBool
shouldGeneratePrimitives(const SoShape * shape) const1239 SoCallbackAction::shouldGeneratePrimitives(const SoShape * shape) const
1240 {
1241   int idx = static_cast<int>(shape->getTypeId().getData());
1242   if (idx < PRIVATE(this)->trianglecallback.getLength() && PRIVATE(this)->trianglecallback[idx])
1243     return TRUE;
1244   if (idx < PRIVATE(this)->linecallback.getLength() && PRIVATE(this)->linecallback[idx])
1245     return TRUE;
1246   if (idx < PRIVATE(this)->pointcallback.getLength() && PRIVATE(this)->pointcallback[idx])
1247     return TRUE;
1248   return FALSE;
1249 }
1250 
1251 /*!
1252   Returns the current tail of the traversal path for the callback
1253   action.
1254  */
1255 SoNode *
getCurPathTail(void)1256 SoCallbackAction::getCurPathTail(void)
1257 {
1258   return PRIVATE(this)->currentnode;
1259 }
1260 
1261 /*!
1262   Used from nodes during traversal to keep a current node pointer in
1263   the action.
1264  */
1265 void
setCurrentNode(SoNode * const node)1266 SoCallbackAction::setCurrentNode(SoNode * const node)
1267 {
1268   PRIVATE(this)->currentnode = node;
1269 }
1270 
1271 // Documented in superclass. Overridden from parent class to
1272 // initialize variables which need to be reset for each traversal.
1273 void
beginTraversal(SoNode * node)1274 SoCallbackAction::beginTraversal(SoNode * node)
1275 {
1276   PRIVATE(this)->response = SoCallbackAction::CONTINUE;
1277   // we set the viewport region element here. This element is not enabled
1278   // for SoCallbackAction in Inventor, bu we think it should be.
1279   // It makes it possible to calculate screen space stuff in
1280   // the callback action callbacks.
1281   if (PRIVATE(this)->viewportset) {
1282     SoViewportRegionElement::set(this->getState(), PRIVATE(this)->viewport);
1283   }
1284   this->traverse(node);
1285 }
1286 
setCallbackAll(SbBool callbackall)1287 void SoCallbackAction::setCallbackAll(SbBool callbackall)
1288 {
1289   PRIVATE(this)->callbackall = callbackall;
1290 }
1291 
isCallbackAll(void) const1292 SbBool SoCallbackAction::isCallbackAll(void) const
1293 {
1294   return PRIVATE(this)->callbackall;
1295 }
1296 
1297 #undef PRIVATE
1298 
1299 #ifdef COIN_TEST_SUITE
1300 
1301 #include <Inventor/nodes/SoSwitch.h>
1302 #include <Inventor/nodes/SoCube.h>
1303 
1304 static SoCallbackAction::Response
preCB(void * userdata,SoCallbackAction *,const SoNode * node)1305 preCB(void * userdata, SoCallbackAction *, const SoNode * node)
1306 {
1307   SbString *str = (SbString *)userdata;
1308   (*str) += node->getName();
1309   return SoCallbackAction::CONTINUE;
1310 }
1311 
BOOST_AUTO_TEST_CASE(callbackall)1312 BOOST_AUTO_TEST_CASE(callbackall)
1313 {
1314   SbString str;
1315   SoSwitch * sw = new SoSwitch;
1316   sw->setName("switch");
1317   SoCube * cube = new SoCube;
1318   cube->setName("cube");
1319   sw->addChild(cube);
1320   sw->ref();
1321 
1322   SoCallbackAction cba;
1323   cba.addPreCallback(SoNode::getClassTypeId(), preCB, &str);
1324   cba.apply(sw);
1325   BOOST_CHECK_MESSAGE(str == "switch", "Should not traverse under switch node");
1326 
1327   str = "";
1328   cba.setCallbackAll(true);
1329   cba.apply(sw);
1330   BOOST_CHECK_MESSAGE(str == "switchcube", "Should traverse under switch node");
1331 
1332   sw->unref();
1333 }
1334 
1335 #endif // COIN_TEST_SUITE
1336