1 // OpenSG Tutorial Example: Attachments
3 // In many cases there is a need to attach some data to existing structures
4 // instead of deriving new classes. Many systems have a void* userdata
5 // to do that. OpenSG uses the more flexible concept of Attachments.
8 #ifdef OSG_BUILD_ACTIVE
12 #include <OSGConfig.h>
13 #include <OSGSimpleGeometry.h>
14 #include <OSGGLUTWindow.h>
15 #include <OSGSimpleSceneManager.h>
16 #include <OSGAction.h>
17 #include <OSGSceneFileHandler.h>
20 #include <OSGAttachment.h>
21 #include <OSGNameAttachment.h>
22 #include <OSGVoidPAttachment.h>
25 These two headers are needed to define the new MyAttachment type below
27 #include <OSGSimpleAttachment.h>
30 #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/OSGAction.h>
37 #include <OpenSG/OSGSceneFileHandler.h>
40 #include <OpenSG/OSGAttachment.h>
41 #include <OpenSG/OSGNameAttachment.h>
42 #include <OpenSG/OSGVoidPAttachment.h>
45 These two headers are needed to define the new MyAttachment type below
47 #include <OpenSG/OSGSimpleAttachment.h>
50 // The SimpleSceneManager to manage simple applications
51 OSG::SimpleSceneManagerRefPtr mgr
;
53 // forward declaration so we can have the interesting stuff upfront
54 int setupGLUT(int *argc
, char *argv
[]);
56 // Helper class to find a named node
57 // This class uses the NameAttachment directly, see below for more on name
62 NamedNodeFinder(void) : _found(), _name() {}
64 OSG::Node
*operator() (OSG::Node
*root
, const std::string
&name
)
69 traverse(root
, boost::bind(&NamedNodeFinder::checkNode
, this, _1
));
76 // %$#%$#% OS X trashes check symbol so we need to use checkNode
77 OSG::Action::ResultE
checkNode(OSG::Node
*node
)
79 OSG::Attachment
*a
= node
->findAttachment(OSG::Name::getClassType());
83 OSG::Name
*n
= dynamic_cast<OSG::Name
*>(a
);
85 if(n
->getField().getValue() == _name
)
88 return OSG::Action::Quit
;
92 return OSG::Action::Continue
;
95 OSG::NodeRefPtr _found
;
100 Define a simple Attachment using only a single Field
102 You need to define the type of the field and a couple names and put it
103 into the AttachmentDesc. This is a trait used to define a SimpleAttachment
106 Access to the value is done via the getField() method (see below).
108 This is just a convenience class for simple attachments. If you need
109 more complex attachments you have to define them just like any other
110 FieldContainer and derive them from Attachment. See Examples/NewTypes
111 for info on how to do that.
113 Note that if you want to put this into a library and use it from the outside
114 you have to make sure that the static _type and _desc members are only
115 instantiated in the library, not in the user's code. The procedure is the
116 same for any FieldContainer, see Examples/NewTypes for details.
118 struct MyAttachmentDesc
120 typedef OSG::SFInt32 FieldTypeT
;
122 static const OSG::Char8
*getTypeName (void)
127 static const OSG::Char8
*getFieldName (void)
132 static const OSG::Char8
*getGroupName (void)
137 static const OSG::Char8
*getParentTypeName(void)
142 static OSG::InitContainerF
getInitMethod(void) { return NULL
; }
146 The following three specializations need to be in the OpenSG namespace.
150 OSG_SIMPLEATTACHMENT_INST(MyAttachmentDesc
);
153 SimpleAttachment
<MyAttachmentDesc
>::TypeObject
&
154 SimpleAttachment
<MyAttachmentDesc
>::getType(void)
160 const SimpleAttachment
<MyAttachmentDesc
>::TypeObject
&
161 SimpleAttachment
<MyAttachmentDesc
>::getType(void) const
167 SimpleAttachment
<MyAttachmentDesc
>::TypeObject
&
168 SimpleAttachment
<MyAttachmentDesc
>::getClassType(void)
176 Give the new attachment a simple name to refer to it.
178 typedef SimpleAttachment
<MyAttachmentDesc
> MyAttachment
;
181 Generate all the different pointer types.
183 OSG_GEN_CONTAINERPTR(MyAttachment
);
187 // Initialize GLUT & OpenSG and set up the scene
188 int main(int argc
, char **argv
)
191 OSG::osgInit(argc
,argv
);
194 int winid
= setupGLUT(&argc
, argv
);
196 // open a new scope, because the pointers below should go out of scope
197 // before entering glutMainLoop.
198 // Otherwise OpenSG will complain about objects being alive after shutdown.
200 // the connection between GLUT and OpenSG
201 OSG::GLUTWindowRefPtr gwin
= OSG::GLUTWindow::create();
202 gwin
->setGlutId(winid
);
207 OSG::NodeRefPtr scene
;
211 FWARNING(("No file given!\n"));
213 scene
= OSG::makeTorus(.5, 2, 16, 16);
217 scene
= OSG::SceneFileHandler::the()->read(argv
[1]);
221 An Attachment is a special field container that can be attached to
222 many of the internal classes like Nodes, NodeCores and many others.
223 There can be multiple Attachments attached to an object.
225 Attachments can be attached to all FieldContainers that are derived from
226 AttachmentContainer. This includes most higher-level classes in the
227 system, like Nodes, NodeCores, Windows, Viewports etc. See the
228 inheritance graph for details.
230 One predefined kind of Attachment is the Name, which can
231 keep the name of an object. Some of loaders (e.g. the WRL loader)
232 create these kinds of Attachments for named nodes.
236 An Attachment is a FieldContainer and as such needs to be created using
239 OSG::NameRefPtr name
= OSG::Name::create();
242 The NameAttachment only has a single field, there's no need to use the
245 name
->editFieldPtr()->setValue("Scene");
248 Attach the name to the scene node.
250 scene
->addAttachment(name
);
253 Check if the scene has a Name attachment
255 Attachments are categorized by the GroupID of their class. Every
256 AttachmentContainer generally keeps only one attachment of a specific
259 OSG::AttachmentRefPtr a
;
261 a
= scene
->findAttachment(OSG::Name::getClassType());
265 OSG::NameRefPtr n
= OSG::dynamic_pointer_cast
<OSG::Name
>(a
);
267 SLOG
<< "Node name: " << n
->getField().getValue() << OSG::endLog
;
271 SLOG
<< "Node has no name!" << OSG::endLog
;
275 As names are used quite often there are two convenience functions
276 that wrap the code given above: setName and getName. They are declared
277 in OSGSimpleAttachments.h.
281 SLOG
<< "Node is named: " << getName(scene
) << OSG::endLog
;
285 SLOG
<< "Node is unnamed." << OSG::endLog
;
288 setName(scene
, "Scene");
291 // use the NamedNodeFinder helper to find a named object
294 OSG::NodeRefPtr found
;
296 found
= f(scene
, "Scene");
297 SLOG
<< "Found object " << found
<< " named Scene." << OSG::endLog
;
299 found
= f(scene
, "TF_DETAIL");
302 SLOG
<< "Found no object named TF_DETAIL (did you load the tie?)."
307 SLOG
<< "Found object " << found
<< " named TF_DETAIL."
313 // Use the simple attachment defined above
315 OSG::MyAttachmentRefPtr mya
= OSG::MyAttachment::create();
317 mya
->editFieldPtr()->setValue(42);
319 // attach it to the scene
320 scene
->addAttachment(mya
);
322 // and check if it's still there
323 a
= scene
->findAttachment(OSG::MyAttachment::getClassType());
327 OSG::MyAttachmentRefPtr m
=
328 OSG::dynamic_pointer_cast
<OSG::MyAttachment
>(a
);
330 SLOG
<< "Node my value: " << m
->getField().getValue()
335 SLOG
<< "Node has no myAttachment!" << OSG::endLog
;
339 In case you don't want to create a new Attachment or cannot do that
340 because it needs to reference external data, you just attach a void*
341 using the VoidPAttachment. This is somewhat equivalent to the standard
344 Note that the referenced data will not be threadsafe. Every thread has
345 its own copy of the reference, but if if multiple threads reference the
346 same data they can interfere.
348 Future versions will have some provisions to allow making this
349 threadsafe. Stay tuned.
352 OSG::VoidPAttachmentRefPtr myvoid
= OSG::VoidPAttachment::create();
353 OSG::UInt32 dummy
= 1234;
355 myvoid
->editFieldPtr()->setValue(&dummy
);
357 // attach it to the scene
358 scene
->addAttachment(myvoid
);
360 // and check if it's still there
361 a
= scene
->findAttachment(OSG::VoidPAttachment::getClassType());
365 OSG::VoidPAttachmentRefPtr m
=
366 OSG::dynamic_pointer_cast
<OSG::VoidPAttachment
>(a
);
368 SLOG
<< "Node voidp value: "
369 << *(static_cast<OSG::UInt32
*>(m
->getField().getValue()))
374 SLOG
<< "Node has no voidp attachment!" << OSG::endLog
;
378 // create the SimpleSceneManager helper
379 mgr
= OSG::SimpleSceneManager::create();
381 // tell the manager what to manage
382 mgr
->setWindow(gwin
);
383 mgr
->setRoot (scene
);
385 // show the whole scene
396 // GLUT callback functions
405 // react to size changes
406 void reshape(int w
, int h
)
412 // react to mouse button presses
413 void mouse(int button
, int state
, int x
, int y
)
416 mgr
->mouseButtonRelease(button
, x
, y
);
418 mgr
->mouseButtonPress(button
, x
, y
);
423 // react to mouse motions with pressed buttons
424 void motion(int x
, int y
)
426 mgr
->mouseMove(x
, y
);
431 void keyboard(unsigned char k
, int x
, int y
)
437 // clean up global variables
446 // setup the GLUT library which handles the windows for us
447 int setupGLUT(int *argc
, char *argv
[])
449 glutInit(argc
, argv
);
450 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
452 int winid
= glutCreateWindow("OpenSG");
454 glutReshapeFunc(reshape
);
455 glutDisplayFunc(display
);
456 glutMouseFunc(mouse
);
457 glutMotionFunc(motion
);
458 glutKeyboardFunc(keyboard
);