1 // OpenSG Tutorial Example: Loading
3 // This example shows how to load a scene file using OpenSG.
4 // The supported formats right now are VRML97, OBJ, OFF and RAW, so just
5 // calling this program with a scene file as a parameter should load the scene
11 #include "OSGConfig.h"
12 #include "OSGSimpleGeometry.h"
13 #include "OSGGLUTWindow.h"
14 #include "OSGSimpleSceneManager.h"
15 #include "OSGAction.h"
16 #include "OSGSceneGraphUtils.h"
20 // the general scene file loading handler
21 #include "OSGSceneFileHandler.h"
23 #include "OSGFieldContainerUtils.h"
24 #include "OSGChunkOverrideGroup.h"
25 #include "OSGPolygonChunk.h"
26 #include "OSGGeoFunctions.h"
28 #include "OSGSkinnedGeometry.h"
29 #include "OSGShaderProgram.h"
30 #include "OSGShaderProgramChunk.h"
32 #include "OSGAnimation.h"
33 #include "OSGAnimBindAction.h"
34 #include "OSGAnimKeyFrameTemplate.h"
35 #include "OSGGlobalsAttachment.h"
36 #include "OSGComponentTransform.h"
37 #include "OSGTransform.h"
38 #include "OSGSkeletonJoint.h"
40 typedef std::vector
<OSG::NodeUnrecPtr
> NodeStore
;
41 typedef std::vector
<OSG::MaterialUnrecPtr
> MaterialStore
;
45 OSG::AnimationUnrecPtr anim
;
48 AnimInfo(void) : anim(NULL
), on(false) {}
51 typedef std::vector
<AnimInfo
> AnimStore
;
53 // The SimpleSceneManager to manage simple applications
54 OSG::SimpleSceneManagerRefPtr mgr
= NULL
;
55 OSG::NodeUnrecPtr sceneN
; // scene from file
56 OSG::NodeUnrecPtr rootN
; // root
57 OSG::ChunkOverrideGroupUnrecPtr root
;
58 OSG::PolygonChunkUnrecPtr polyChunk
;
60 NodeStore normalsGeoN
;
62 NodeStore skinnedGeoN
;
63 MaterialStore skinnedGeoMat
;
65 bool normalsActive
= false;
66 OSG::Real32 normalsLen
= 1.f
;
67 OSG::Int32 currAnim
= 0;
70 OSG::ShaderProgramUnrecPtr vpSkin
;
71 OSG::ShaderProgramUnrecPtr fpSkin
;
72 OSG::ShaderProgramChunkUnrecPtr shSkin
;
73 OSG::ChunkMaterialUnrecPtr matSkin
;
75 const std::string
vpCode(
79 "void calcSkin(inout vec4 pos, inout vec3 norm,\n"
80 " in vec4 matIdx, in vec4 weight);\n"
82 "varying vec4 position;\n"
83 "varying vec3 normal;\n"
87 " vec4 pos = gl_Vertex;\n"
88 " vec3 norm = gl_Normal;\n"
89 " vec4 matIdx = gl_MultiTexCoord2;\n"
90 " vec4 weight = gl_MultiTexCoord3;\n"
92 " calcSkin(pos, norm, matIdx, weight);\n"
94 " gl_Position = gl_ModelViewProjectionMatrix * pos;\n"
95 " position = gl_Position;\n"
96 " normal = gl_NormalMatrix * norm;\n"
100 const std::string
fpCode(
103 "varying vec4 position;\n"
104 "varying vec3 normal;\n"
108 " vec3 pos = position.xyz / position.w;\n"
109 " vec3 norm = normalize(normal);\n"
110 " vec3 lightDir = normalize(vec3(1,1,1));\n"
111 " float NdotL = max(0, dot(norm, lightDir));\n"
112 " vec3 diffCol = vec3(0.4, 0.4, 0.6);\n"
113 " diffCol *= NdotL;\n"
114 " gl_FragColor = vec4(diffCol, 1.);\n"
118 // forward declaration so we can have the interesting stuff upfront
119 int setupGLUT( int *argc
, char *argv
[] );
121 void init (int argc
, char *argv
[]);
123 void printHelp(void);
124 void collectGeometry (OSG::Node
*node
);
125 void constructNormalsGeo(OSG::Node
*pRootN
);
127 void processAnim (OSG::Node
*node
);
130 // Initialize GLUT & OpenSG and set up the scene
131 int main(int argc
, char *argv
[])
144 void init(int argc
, char *argv
[])
146 OSG::osgInit(argc
, argv
);
148 int glutWinId
= setupGLUT(&argc
, argv
);
150 // the connection between GLUT and OpenSG
151 OSG::GLUTWindowUnrecPtr gwin
= OSG::GLUTWindow::create();
152 gwin
->setGlutId(glutWinId
);
156 root
= OSG::ChunkOverrideGroup::create();
157 rootN
= OSG::makeNodeFor(root
);
161 FWARNING(("No file given!\n"));
162 FWARNING(("Supported file formats:\n"));
164 OSG::SceneFileHandler::the()->print();
165 sceneN
= OSG::makeTorus(.5, 2, 16, 16);
170 All scene file loading is handled via the SceneFileHandler.
172 sceneN
= OSG::SceneFileHandler::the()->read(argv
[1]);
175 OSG::TransformUnrecPtr xform
= OSG::Transform::create();
176 OSG::NodeUnrecPtr xformN
= OSG::makeNodeFor(xform
);
178 // xform->editMatrix().setTranslate(OSG::Vec3f(100.f, 0.f, 0.f));
179 // xform->editMatrix().setRotate(OSG::Quaternion(OSG::Vec3f(0.f, 1.f, 0.f), 0.3f * OSG::Pi));
181 OSG::NodeUnrecPtr boxN
= OSG::makeBox(1.f
, 1.f
, 5.f
, 1, 1, 1);
183 xformN
->addChild(sceneN
);
184 rootN
->addChild(xformN
);
185 rootN
->addChild(boxN
);
187 OSG::commitChanges();
189 // collect geometries in the scene
190 collectGeometry(rootN
);
192 // construct skin shader
193 vpSkin
= OSG::ShaderProgram::createVertexShader ();
194 vpSkin
->setProgram(vpCode
);
196 fpSkin
= OSG::ShaderProgram::createFragmentShader();
197 fpSkin
->setProgram(fpCode
);
199 shSkin
= OSG::ShaderProgramChunk::create();
200 shSkin
->addShader(vpSkin
);
201 shSkin
->addShader(fpSkin
);
203 matSkin
= OSG::ChunkMaterial::create();
204 matSkin
->addChunk(shSkin
);
206 // process animations
209 // create the SimpleSceneManager helper
210 mgr
= OSG::SimpleSceneManager::create();
212 // tell the manager what to manage
213 mgr
->setWindow(gwin
);
214 mgr
->setRoot (rootN
);
216 // show the whole scene
234 normalsGeoN
.clear();
236 skinnedGeoN
.clear();
237 skinnedGeoMat
.clear();
243 std::cout
<< "Keys:\n"
246 << " t trackball mode\n"
247 << " q toggle statistics\n"
248 << " h toggle headlight\n"
249 << " b toggle backface culling\n"
250 << " w toggle wireframe\n"
251 << " n toggle normals\n"
252 << " m/M de/increase normals length\n"
253 << " v toggle bounding volumes\n"
254 << " p print scene graph\n"
255 << " d toggle skinned geo draw mode\n"
259 OSG::Action::ResultE
doCollectGeometry(OSG::Node
*node
)
263 std::cerr
<< "WARNING: collectGeometry called with node == NULL"
265 return OSG::Action::Continue
;
268 OSG::NodeCore
*core
= node
->getCore();
272 std::cerr
<< "WARNING: collectGeometry called with core == NULL"
274 return OSG::Action::Continue
;
277 if(core
->getType().isDerivedFrom(OSG::Geometry::getClassType()))
279 geoN
.push_back(node
);
282 if(core
->getType().isDerivedFrom(OSG::SkinnedGeometry::getClassType()))
284 skinnedGeoN
.push_back(node
);
286 OSG::SkinnedGeometry
*sgeo
=
287 dynamic_cast<OSG::SkinnedGeometry
*>(core
);
288 skinnedGeoMat
.push_back(sgeo
->getMaterial());
290 sgeo
->setRenderMode(OSG::SkinnedGeometry::RMUnskinned
);
293 return OSG::Action::Continue
;
296 void collectGeometry(OSG::Node
*pRootN
)
298 OSG::traverse(pRootN
, &doCollectGeometry
);
300 std::cout
<< "collectGeometry: num geo [" << geoN
.size()
301 << "] num skinned geo [" << skinnedGeoN
.size()
306 void constructNormalsGeo(OSG::Node
*pRootN
)
308 NodeStore::const_iterator nIt
= normalsGeoN
.begin();
309 NodeStore::const_iterator nEnd
= normalsGeoN
.end ();
311 // remove existing normals
312 for(; nIt
!= nEnd
; ++nIt
)
313 (*nIt
)->getParent()->subChild(*nIt
);
317 // construct and add new normals
321 for(; nIt
!= nEnd
; ++nIt
)
324 dynamic_cast<OSG::Geometry
*>((*nIt
)->getCore());
325 OSG::NodeUnrecPtr normGeoN
=
326 OSG::calcVertexNormalsGeo(geo
, normalsLen
);
328 normalsGeoN
.push_back(normGeoN
);
330 (*nIt
)->addChild(normGeoN
);
334 void processAnim(OSG::Node
*node
)
336 OSG::commitChangesAndClear();
338 // register AnimBindAction callbacks -- temporarily done here
339 OSG::AnimBindAction::registerEnterDefault(
340 OSG::ComponentTransform::getClassType(),
341 &OSG::bindEnterDefault
);
342 OSG::AnimBindAction::registerEnterDefault(
343 OSG::Transform::getClassType(),
344 &OSG::bindEnterDefault
);
347 OSG::GlobalsAttachment
*ga
= dynamic_cast<OSG::GlobalsAttachment
*>(
348 node
->findAttachment(OSG::GlobalsAttachment::getClassType()));
352 std::cerr
<< "WARNING: processAnim: no GlobalsAttachment found"
357 OSG::GlobalsAttachment::MFElementsType::const_iterator eIt
=
358 ga
->getMFElements()->begin();
359 OSG::GlobalsAttachment::MFElementsType::const_iterator eEnd
=
360 ga
->getMFElements()->end ();
362 for(; eIt
!= eEnd
; ++eIt
)
364 OSG::AnimKeyFrameTemplate
*animTmpl
=
365 dynamic_cast<OSG::AnimKeyFrameTemplate
*>(*eIt
);
370 std::cout
<< "instantiating anim template [" << animTmpl
->getName()
371 << "] with [" << animTmpl
->getMFSources()->size()
372 << "] sources [" << animTmpl
->getMFTargetIds()->size()
373 << "] targetIds" << std::endl
;
377 ai
.anim
= animTmpl
->instantiate(node
);
378 ai
.anim
->setEnabled(false);
384 void toggleAnim(OSG::UInt32 index
, bool loop
)
386 if(anims
[index
].on
== true)
388 std::cout
<< "STOP anim " << index
<< std::endl
;
389 anims
[index
].anim
->stop ();
390 anims
[index
].anim
->reset();
391 anims
[index
].anim
->setEnabled(false);
392 anims
[index
].on
= false;
398 std::cout
<< "START LOOP anim " << index
<< std::endl
;
399 anims
[index
].anim
->startLoop(OSG::FrameHandler::the()->getTimeStamp());
403 std::cout
<< "START anim " << index
<< std::endl
;
404 anims
[index
].anim
->start(OSG::FrameHandler::the()->getTimeStamp());
407 anims
[index
].anim
->setEnabled(true);
408 anims
[index
].on
= true;
412 void printXForm(OSG::SceneGraphPrinter
*sgp
, OSG::NodeCore
*core
)
414 OSG::Transform
*xform
= dynamic_cast<OSG::Transform
*>(core
);
416 sgp
->indentStream() << "matrix:\n" << xform
->getMatrix();
419 void printJoint(OSG::SceneGraphPrinter
*sgp
, OSG::NodeCore
*core
)
421 OSG::SkeletonJoint
*joint
= dynamic_cast<OSG::SkeletonJoint
*>(core
);
423 sgp
->indentStream() << "matrix:\n" << joint
->getMatrix();
426 void printVolume(OSG::SceneGraphPrinter
*sgp
, OSG::NodeCore
*core
)
428 sgp
->indentStream() << " volume " << sgp
->getCurrNode()->getVolume()
433 // GLUT callback functions
439 // std::cout << ">> FRAME START" << std::endl;
441 static OSG::Time tAcc
= 0;
442 static OSG::UInt32 fc
= 0;
444 OSG::Time t0
= OSG::getSystemTime();
446 OSG::FrameHandler::the()->frame();
448 OSG::commitChangesAndClear();
453 OSG::Time t1
= OSG::getSystemTime();
460 std::cout
<< "frame count [" << fc
461 << "] fc/tAcc [" << (fc
/tAcc
)
462 << "] tAcc/fc [" << (1000.f
* (tAcc
/fc
))
463 << "] ms tAcc [" << tAcc
<< "] s" << std::endl
;
469 // std::cout << "<< FRAME END" << std::endl;
471 // mgr->getWindow()->registerConstant(GL_MAX_VERTEX_UNIFORM_COMPONENTS );
472 // mgr->getWindow()->registerConstant(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS);
474 // OSG::Real32 maxVPUniforms =
475 // mgr->getWindow()->getConstantValue(GL_MAX_VERTEX_UNIFORM_COMPONENTS);
476 // OSG::Real32 maxFPUniforms =
477 // mgr->getWindow()->getConstantValue(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS);
479 // std::cout << "GL_MAX_VERTEX_UNIFORM_COMPONENTS [" << maxVPUniforms
480 // << "] GL_MAX_FRAGMENT_UNIFORM_COMPONENTS [" << maxFPUniforms
481 // << "]" << std::endl;
484 // react to size changes
485 void reshape(int w
, int h
)
491 // react to mouse button presses
492 void mouse(int button
, int state
, int x
, int y
)
496 mgr
->mouseButtonRelease(button
, x
, y
);
498 mgr
->mouseButtonPress(button
, x
, y
);
503 // react to mouse motions with pressed buttons
504 void motion(int x
, int y
)
507 mgr
->mouseMove(x
, y
);
512 void keyboard(unsigned char k
, int , int )
526 mgr
->setNavigationMode(OSG::Navigator::FLY
);
527 std::cout
<< "Fly mode" << std::endl
;
532 mgr
->setNavigationMode(OSG::Navigator::TRACKBALL
);
533 std::cout
<< "Trackball mode" << std::endl
;
538 mgr
->setStatistics(!mgr
->getStatistics());
539 std::cout
<< "Statistics "
540 << (mgr
->getStatistics() ? "enabled" : "disabled")
546 mgr
->setHeadlight(!mgr
->getHeadlightState());
547 std::cout
<< "Headlight "
548 << (mgr
->getHeadlightState() ? "enabled" : "disabled")
554 if(polyChunk
== NULL
)
556 polyChunk
= OSG::PolygonChunk::create();
557 root
->addChunk(polyChunk
);
560 if(polyChunk
->getCullFace() == GL_NONE
)
562 polyChunk
->setCullFace(GL_BACK
);
563 std::cout
<< "Backface culling enabled" << std::endl
;
567 polyChunk
->setCullFace(GL_NONE
);
568 std::cout
<< "Backface culling disabled" << std::endl
;
574 if(polyChunk
== NULL
)
576 polyChunk
= OSG::PolygonChunk::create();
577 root
->addChunk(polyChunk
);
580 if(polyChunk
->getFrontMode() == GL_FILL
)
582 polyChunk
->setFrontMode(GL_LINE
);
583 polyChunk
->setBackMode (GL_LINE
);
584 std::cout
<< "Wireframe enabled" << std::endl
;
588 polyChunk
->setFrontMode(GL_FILL
);
589 polyChunk
->setBackMode (GL_FILL
);
590 std::cout
<< "Wireframe disabled" << std::endl
;
596 if(normalsActive
== true)
598 normalsActive
= false;
600 NodeStore::const_iterator ngIt
= normalsGeoN
.begin();
601 NodeStore::const_iterator ngEnd
= normalsGeoN
.end ();
603 for(; ngIt
!= ngEnd
; ++ngIt
)
605 (*ngIt
)->setTravMask(0);
608 std::cout
<< "Normals disabled" << std::endl
;
612 normalsActive
= true;
614 if(normalsGeoN
.empty() == true)
615 constructNormalsGeo(sceneN
);
617 NodeStore::const_iterator ngIt
= normalsGeoN
.begin();
618 NodeStore::const_iterator ngEnd
= normalsGeoN
.end ();
620 for(; ngIt
!= ngEnd
; ++ngIt
)
622 (*ngIt
)->setTravMask(OSG::TypeTraits
<OSG::UInt32
>::BitsSet
);
625 std::cout
<< "Normals enabled" << std::endl
;
632 constructNormalsGeo(sceneN
);
633 std::cout
<< "Normals length " << normalsLen
<< std::endl
;
639 constructNormalsGeo(sceneN
);
640 std::cout
<< "Normals length " << normalsLen
<< std::endl
;
645 mgr
->getRenderAction()->setVolumeDrawing(
646 !mgr
->getRenderAction()->getVolumeDrawing());
647 std::cout
<< "Volume drawing: "
648 << (mgr
->getRenderAction()->getVolumeDrawing() ? "enabled" : "disabled")
654 OSG::SceneGraphPrinter
sgp(mgr
->getRoot());
655 sgp
.addPrintFunc(OSG::SkinnedGeometry::getClassType(),
657 sgp
.printDownTree(std::cout
);
659 NodeStore::const_iterator nIt
= skinnedGeoN
.begin();
660 NodeStore::const_iterator nEnd
= skinnedGeoN
.end ();
662 for(OSG::UInt32 i
= 0; nIt
!= nEnd
; ++nIt
, ++i
)
664 OSG::SkinnedGeometry
*sgeo
= dynamic_cast<OSG::SkinnedGeometry
*>(
667 std::cout
<< "Skeleton:\n";
668 OSG::SceneGraphPrinter
skelPrinter(sgeo
->getSkeleton()->getRoots(0));
669 skelPrinter
.addPrintFunc(OSG::Transform ::getClassType(),
671 //skelPrinter.addPrintFunc(OSG::SkeletonJoint::getClassType(),
673 skelPrinter
.printDownTree(std::cout
);
682 std::cout
<< "Showing all of scene." << std::endl
;
688 if(anims
.empty() == false)
692 currAnim
= anims
.size() - 1;
694 std::cout
<< "Current anim [" << currAnim
<< "] - ["
695 << anims
[currAnim
].anim
->getTemplate()->getName()
702 if(anims
.empty() == false)
705 if(currAnim
>= OSG::Int32(anims
.size()))
708 std::cout
<< "Current anim [" << currAnim
<< "] - ["
709 << anims
[currAnim
].anim
->getTemplate()->getName()
717 toggleAnim(currAnim
, false);
723 toggleAnim(currAnim
, true);
728 NodeStore::const_iterator nIt
= skinnedGeoN
.begin();
729 NodeStore::const_iterator nEnd
= skinnedGeoN
.end ();
731 for(OSG::UInt32 i
= 0; nIt
!= nEnd
; ++nIt
, ++i
)
733 OSG::SkinnedGeometry
*sgeo
= dynamic_cast<OSG::SkinnedGeometry
*>(
736 if(sgeo
->getRenderMode() == OSG::SkinnedGeometry::RMSkinnedCPU
)
738 std::cout
<< "Enabling SkinnedGeo GPU mode ["
739 << sgeo
<< "]" << std::endl
;
741 sgeo
->setRenderMode(OSG::SkinnedGeometry::RMSkinnedGPU
);
742 sgeo
->setMaterial (matSkin
);
744 else if(sgeo
->getRenderMode() == OSG::SkinnedGeometry::RMSkinnedGPU
)
746 std::cout
<< "Enabling SkinnedGeo SKELETON mode ["
747 << sgeo
<< "]" << std::endl
;
749 sgeo
->setRenderMode(OSG::SkinnedGeometry::RMSkeleton
);
750 sgeo
->setMaterial (skinnedGeoMat
[i
]);
752 else if(sgeo
->getRenderMode() == OSG::SkinnedGeometry::RMSkeleton
)
754 std::cout
<< "Enabling SkinnedGeo UNSKINNED mode ["
755 << sgeo
<< "]" << std::endl
;
757 sgeo
->setRenderMode(OSG::SkinnedGeometry::RMUnskinned
);
758 sgeo
->setMaterial (skinnedGeoMat
[i
]);
762 std::cout
<< "Enabling SkinnedGeo CPU mode ["
763 << sgeo
<< "]" << std::endl
;
765 sgeo
->setRenderMode(OSG::SkinnedGeometry::RMSkinnedCPU
);
766 sgeo
->setMaterial(skinnedGeoMat
[i
]);
773 mgr
->getRenderAction()->setFrustumCulling(
774 !mgr
->getRenderAction()->getFrustumCulling());
776 std::cout
<< "Frustum culling: "
777 << (mgr
->getRenderAction()->getFrustumCulling() ? "enabled" : "disabled")
783 NodeStore::const_iterator nIt
= skinnedGeoN
.begin();
784 NodeStore::const_iterator nEnd
= skinnedGeoN
.end ();
786 for(OSG::UInt32 i
= 0; nIt
!= nEnd
; ++nIt
, ++i
)
788 OSG::SkinnedGeometry
*sgeo
= dynamic_cast<OSG::SkinnedGeometry
*>(
791 OSG::Skeleton
*skel
= sgeo
->getSkeleton();
793 OSG::Skeleton::MFRootsType::const_iterator rIt
=
794 skel
->getMFRoots()->begin();
795 OSG::Skeleton::MFRootsType::const_iterator rEnd
=
796 skel
->getMFRoots()->end ();
798 for(OSG::UInt32 j
= 0; rIt
!= rEnd
; ++rIt
, ++j
)
800 std::cout
<< "Skeleton [" << i
<< "] @ [" << skel
801 << "] root [" << j
<< "]\n";
803 OSG::SceneGraphPrinter
sgp(*rIt
);
804 sgp
.printDownTree(std::cout
);
806 std::cout
<< std::endl
;
827 // setup the GLUT library which handles the windows for us
828 int setupGLUT(int *argc
, char *argv
[])
830 glutInit(argc
, argv
);
831 glutInitDisplayMode(GLUT_RGB
| GLUT_DEPTH
| GLUT_DOUBLE
);
833 int winid
= glutCreateWindow("OpenSG");
835 glutReshapeFunc(reshape
);
836 glutDisplayFunc(display
);
838 glutMouseFunc(mouse
);
839 glutMotionFunc(motion
);
840 glutKeyboardFunc(keyboard
);