1 // OpenSG Tutorial Example: Traverse & Attachments
3 // This example shows how to traverse the graph and work on each node.
4 // The traverse() functions can be used for that. They need functors to pass
5 // the functions to be called around, which are also introduced here.
7 // It also shows how to downcast pointers in OpenSG to get from a generic
8 // pointer, e.g. a NodeCorePtr to the specific class, e.g. GeometryPtr.
10 // The graphical display is just for show, the interesting stuff is
11 // printed to the console. ;)
14 #ifdef OSG_BUILD_ACTIVE
17 #include <OSGConfig.h>
18 #include <OSGSimpleGeometry.h>
19 #include <OSGGLUTWindow.h>
20 #include <OSGSimpleSceneManager.h>
21 #include <OSGBaseFunctions.h>
22 #include <OSGTransform.h>
27 // the Action header, containing the traverse() functions
28 #include <OSGAction.h>
31 #include <OpenSG/OSGGLUT.h>
32 #include <OpenSG/OSGConfig.h>
33 #include <OpenSG/OSGSimpleGeometry.h>
34 #include <OpenSG/OSGGLUTWindow.h>
35 #include <OpenSG/OSGSimpleSceneManager.h>
36 #include <OpenSG/OSGBaseFunctions.h>
37 #include <OpenSG/OSGTransform.h>
38 #include <OpenSG/OSGGroup.h>
42 // the Action header, containing the traverse() functions
43 #include <OpenSG/OSGAction.h>
46 // boost::bind - to allow member functions as traversal functors
47 #include <boost/bind.hpp>
49 // a separate transformation for every object
50 OSG::TransformRefPtr cyltrans
, tortrans
;
53 // The SimpleSceneManager to manage simple applications
54 OSG::SimpleSceneManagerRefPtr mgr
;
56 // forward declaration so we can have the interesting stuff upfront
57 int setupGLUT( int *argc
, char *argv
[] );
64 OSG::Real32 t
= glutGet(GLUT_ELAPSED_TIME
);
66 // set the transforms' matrices
67 m
.setTransform(OSG::Vec3f(0,
69 OSG::osgSin(t
/ 1000.f
) * 1.5),
70 OSG::Quaternion(OSG::Vec3f (1, 0, 0),
73 cyltrans
->setMatrix(m
);
75 m
.setTransform(OSG::Vec3f(OSG::osgSin(t
/ 2000.f
),
78 OSG::Quaternion(OSG::Vec3f (0, 0, 1),
81 tortrans
->setMatrix(m
);
92 The traverse() functions used below need a function that is called for
93 every node encountered. There are two variants.
95 One just calls one function when it enters the node. The other in addition
96 calls another function when it leaves the node on the way up, i.e. after
97 all children of the node have been processed.
99 The return values define how the traversal continues after this function.
101 Returning Action::Continue will just continue the traversal. Action::Skip
102 will not go deeper but skip all children of this node (and their children
103 etc.). Action::Quit will abort the traversal on the spot and just unwind
104 the enters on the way up.
106 You may notice that the traversal functions do not take NodeRefPtr
107 arguments, but raw Node * instead. This is true for all OpenSG functions
108 and prevents unecessary increments/decrements of the reference count only
109 to pass a pointer to a function.
110 Note that this works because the objects are alive for the duration of
111 the function call anyways. If the arguments to a function are stored in
112 some data structure to be used later (e.g. from a different function) you
113 should store the pointer in a RefPtr to prevent the object from being
117 // these are the trivial traversal function, they just print and return
118 OSG::Action::ResultE
enter(OSG::Node
*node
)
120 SLOG
<< "entering " << node
<< OSG::endLog
;
122 return OSG::Action::Continue
;
125 OSG::Action::ResultE
leave(OSG::Node
*node
, OSG::Action::ResultE res
)
127 SLOG
<< "leaving " << node
<< ", got code " << res
<< OSG::endLog
;
129 // you should return the result that you're passed, to propagate Quits
133 // This is an example of a traversal state object
139 travstate( void ) : _indent(0) {}
141 OSG::Action::ResultE
enter(OSG::Node
*node
)
143 for(OSG::UInt16 i
= 0; i
< _indent
; i
++)
146 SLOG
<< "entering " << node
<< OSG::endLog
;
149 return OSG::Action::Continue
;
152 OSG::Action::ResultE
leave(OSG::Node
*node
, OSG::Action::ResultE res
)
156 for(OSG::UInt16 i
= 0; i
< _indent
; i
++)
159 SLOG
<< "leaving " << node
<< OSG::endLog
;
161 // you should return the result that you're passed, to propagate Quits
170 // a traversal functions that does not descend below transformations
173 It also shows how to access the node core of a given node. After making
174 sure that the core is indeed the expected type (using the isDerivedFrom())
175 call use <FieldContainerTyep>Ptr::dcast() to downcast the core. ::dcast()
176 acts comparable to dynamic_cast. dcast() works for all kinds of field
177 containers and is not restricted to Nodes or NodeCores.
180 OSG::Action::ResultE
dontEnterTrans(OSG::Node
*node
)
182 SLOG
<< "entering " << node
<< OSG::endLog
;
184 if(node
->getCore()->getType().isDerivedFrom(OSG::Transform::getClassType()))
186 OSG::Transform
*t
= dynamic_cast<OSG::Transform
*>(node
->getCore());
188 SLOG
<< "derived from transform, skipping children" << OSG::endLog
;
189 SLOG
<< "Matrix: " << OSG::endLog
<< t
->getMatrix();
190 return OSG::Action::Skip
;
192 return OSG::Action::Continue
;
196 // a traversal functions that quits as soon as it finds a Geometry
199 This function uses the fact that ::dcast() acts like dynamic_cast. It tries
200 to dcast the core to a GeometryPtr, and tests the result to see if it
201 actually was derived from Geometry.
204 OSG::Action::ResultE
quitGeo(OSG::Node
*node
)
206 SLOG
<< "entering " << node
<< OSG::endLog
;
208 OSG::Geometry
*geo
= dynamic_cast<OSG::Geometry
*>(node
->getCore());
212 SLOG
<< "derived from geometry, quitting" << OSG::endLog
;
213 return OSG::Action::Quit
;
215 return OSG::Action::Continue
;
220 // Initialize GLUT & OpenSG and set up the scene
221 int main(int argc
, char **argv
)
224 OSG::osgInit(argc
,argv
);
227 int winid
= setupGLUT(&argc
, argv
);
229 // open a new scope, because the pointers below should go out of scope
230 // before entering glutMainLoop.
231 // Otherwise OpenSG will complain about objects being alive after shutdown.
233 // the connection between GLUT and OpenSG
234 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
235 gwin
->setGlutId(winid
);
240 // create a pretty simple graph: a Group with two Transforms as children,
241 // each of which carries a single Geometry.
245 OSG::NodeRefPtr scene
= OSG::Node::create();
246 OSG::GroupRefPtr g
= OSG::Group::create();
250 // The cylinder and its transformation
251 OSG::NodeRefPtr cyl
= OSG::makeCylinder( 1.4f
, .3f
, 8, true, true, true );
253 cyltrans
= OSG::Transform::create();
255 OSG::NodeRefPtr cyltransnode
= OSG::Node::create();
257 cyltransnode
->setCore (cyltrans
);
258 cyltransnode
->addChild(cyl
);
260 // add it to the scene
261 scene
->addChild(cyltransnode
);
263 // The torus and its transformation
264 OSG::NodeRefPtr torus
= OSG::makeTorus( .2f
, 1, 8, 12 );
266 tortrans
= OSG::Transform::create();
268 OSG::NodeRefPtr tortransnode
= OSG::Node::create();
270 tortransnode
->setCore (tortrans
);
271 tortransnode
->addChild(torus
);
273 // add it to the scene
274 scene
->addChild(tortransnode
);
276 // now traverse the scene
279 There are four variants of the traverse() function.
281 It can either be called for a single node or for a vector nodes. And
282 they can either call a function just when entering the node, or in
283 addition when leaving the node. The signatures of the functions are:
286 Action::ResultE enter(Node *node);
289 Action::ResultE leave(Node *node, Action::ResultE res);
291 The functions that are called are wrapped in functors. A functor is an
292 object that contains a function or method, which can be called through
293 the functor. OpenSG uses boost::function for this purpose and
294 provides appriopriate typedefs for enter and leave functors as
295 TraverseEnterFunctor and TraverseLeaveFunctor (see OSGAction.h).
297 In order to call member functions through a functor an object of
298 the correct type has to be available (there has to an object to
299 take the role of this for the member function). To store an
300 instance of an object in a functor use boost::bind to bind the
301 first argument of the member function functor to the object (see
305 SLOG
<< "Variant 1: just print every encountered node" << OSG::endLog
;
306 traverse(scene
, enter
);
309 << "Variant 2: just print every encountered node, using a"
310 << " vector of nodes" << OSG::endLog
;
312 std::vector
<OSG::Node
*> nodevec
;
313 nodevec
.push_back(tortransnode
);
314 nodevec
.push_back(cyltransnode
);
316 traverse(nodevec
, enter
);
319 << "Variant 3: just print every encountered node on entering"
320 << " and leaving" << OSG::endLog
;
322 traverse(scene
, enter
, leave
);
324 // now use a travstate object to hold additional data
328 << "Variant 4: use an object to hold state for indentation"
330 traverse(scene
, boost::bind(&travstate::enter
, &t
, _1
),
331 boost::bind(&travstate::leave
, &t
, _1
, _2
) );
334 << "Variant 5: don't descend into transforms" << OSG::endLog
;
335 traverse(scene
, dontEnterTrans
, leave
);
338 << "Variant 6: quit when you find a geometry" << OSG::endLog
;
339 traverse(scene
, quitGeo
, leave
);
341 // create the SimpleSceneManager helper
342 mgr
= OSG::SimpleSceneManager::create();
344 // tell the manager what to manage
345 mgr
->setWindow(gwin
);
346 mgr
->setRoot (scene
);
348 // show the whole scene
359 // GLUT callback functions
362 // react to size changes
363 void reshape(int w
, int h
)
369 // react to mouse button presses
370 void mouse(int button
, int state
, int x
, int y
)
373 mgr
->mouseButtonRelease(button
, x
, y
);
375 mgr
->mouseButtonPress(button
, x
, y
);
380 // react to mouse motions with pressed buttons
381 void motion(int x
, int y
)
383 mgr
->mouseMove(x
, y
);
388 void keyboard(unsigned char k
, int x
, int y
)
394 // clean up global variables
406 // setup the GLUT library which handles the windows for us
407 int setupGLUT(int *argc
, char *argv
[])
409 glutInit(argc
, argv
);
410 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
412 int winid
= glutCreateWindow("OpenSG");
414 glutReshapeFunc(reshape
);
415 glutDisplayFunc(display
);
416 glutMouseFunc(mouse
);
417 glutMotionFunc(motion
);
418 glutKeyboardFunc(keyboard
);
420 // call the redraw function whenever there's nothing else to do
421 glutIdleFunc(update
);