changed: gcc8 base update
[opensg.git] / Examples / Simple / 09traverse.cpp
blob170866c5c797bb0e473acac5b0eab0c9a064868b
1 // OpenSG Tutorial Example: Traverse & Attachments
2 //
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.
6 //
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.
9 //
10 // The graphical display is just for show, the interesting stuff is
11 // printed to the console. ;)
14 #ifdef OSG_BUILD_ACTIVE
15 // Headers
16 #include <OSGGLUT.h>
17 #include <OSGConfig.h>
18 #include <OSGSimpleGeometry.h>
19 #include <OSGGLUTWindow.h>
20 #include <OSGSimpleSceneManager.h>
21 #include <OSGBaseFunctions.h>
22 #include <OSGTransform.h>
23 #include <OSGGroup.h>
25 // new headers:
27 // the Action header, containing the traverse() functions
28 #include <OSGAction.h>
29 #else
30 // Headers
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>
40 // new headers:
42 // the Action header, containing the traverse() functions
43 #include <OpenSG/OSGAction.h>
44 #endif
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[] );
59 // redraw the window
60 void display( void )
62 // create the matrix
63 OSG::Matrix m;
64 OSG::Real32 t = glutGet(GLUT_ELAPSED_TIME);
66 // set the transforms' matrices
67 m.setTransform(OSG::Vec3f(0,
68 0,
69 OSG::osgSin(t / 1000.f) * 1.5),
70 OSG::Quaternion(OSG::Vec3f (1, 0, 0),
71 t / 500.f));
73 cyltrans->setMatrix(m);
75 m.setTransform(OSG::Vec3f(OSG::osgSin(t / 2000.f),
76 0,
77 0),
78 OSG::Quaternion(OSG::Vec3f (0, 0, 1),
79 t / 2000.f));
81 tortrans->setMatrix(m);
83 mgr->redraw();
86 void update(void)
88 glutPostRedisplay();
91 /*
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
114 destroyed.
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
130 return res;
133 // This is an example of a traversal state object
135 class travstate
137 public:
139 travstate( void ) : _indent(0) {}
141 OSG::Action::ResultE enter(OSG::Node *node)
143 for(OSG::UInt16 i = 0; i < _indent; i++)
144 SLOG << " ";
146 SLOG << "entering " << node << OSG::endLog;
148 ++_indent;
149 return OSG::Action::Continue;
152 OSG::Action::ResultE leave(OSG::Node *node, OSG::Action::ResultE res)
154 --_indent;
156 for(OSG::UInt16 i = 0; i < _indent; i++)
157 SLOG << " ";
159 SLOG << "leaving " << node << OSG::endLog;
161 // you should return the result that you're passed, to propagate Quits
162 return res;
165 private:
167 OSG::UInt16 _indent;
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());
210 if(geo != NULL)
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)
223 // OSG init
224 OSG::osgInit(argc,argv);
226 // GLUT init
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);
236 gwin->init();
238 // create the scene
240 // create a pretty simple graph: a Group with two Transforms as children,
241 // each of which carries a single Geometry.
243 // The scene group
245 OSG::NodeRefPtr scene = OSG::Node::create();
246 OSG::GroupRefPtr g = OSG::Group::create();
248 scene->setCore(g);
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:
285 enter functions:
286 Action::ResultE enter(Node *node);
288 leave functions:
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
302 below for examples).
305 SLOG << "Variant 1: just print every encountered node" << OSG::endLog;
306 traverse(scene, enter);
308 SLOG << OSG::endLog
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);
318 SLOG << OSG::endLog
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
325 travstate t;
327 SLOG << OSG::endLog
328 << "Variant 4: use an object to hold state for indentation"
329 << OSG::endLog;
330 traverse(scene, boost::bind(&travstate::enter, &t, _1 ),
331 boost::bind(&travstate::leave, &t, _1, _2) );
333 SLOG << OSG::endLog
334 << "Variant 5: don't descend into transforms" << OSG::endLog;
335 traverse(scene, dontEnterTrans, leave);
337 SLOG << OSG::endLog
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
349 mgr->showAll();
352 // GLUT main loop
353 glutMainLoop();
355 return 0;
359 // GLUT callback functions
362 // react to size changes
363 void reshape(int w, int h)
365 mgr->resize(w, h);
366 glutPostRedisplay();
369 // react to mouse button presses
370 void mouse(int button, int state, int x, int y)
372 if (state)
373 mgr->mouseButtonRelease(button, x, y);
374 else
375 mgr->mouseButtonPress(button, x, y);
377 glutPostRedisplay();
380 // react to mouse motions with pressed buttons
381 void motion(int x, int y)
383 mgr->mouseMove(x, y);
384 glutPostRedisplay();
387 // react to keys
388 void keyboard(unsigned char k, int x, int y)
390 switch(k)
392 case 27:
394 // clean up global variables
395 cyltrans = NULL;
396 tortrans = NULL;
397 mgr = NULL;
399 OSG::osgExit();
400 exit(0);
402 break;
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);
423 return winid;