From Cedric Pinson, Pulled in osgAnimation from OpenSceneGraph-osgWidget-dev into svn/trunk.

This commit is contained in:
Robert Osfield
2008-11-22 12:14:19 +00:00
parent fdaa75400b
commit 56a2cc65d0
55 changed files with 6623 additions and 3 deletions

View File

@@ -108,6 +108,12 @@ IF(DYNAMIC_OPENSCENEGRAPH)
ADD_SUBDIRECTORY(osgvertexprogram)
ADD_SUBDIRECTORY(osgvolume)
ADD_SUBDIRECTORY(osgwindows)
ADD_SUBDIRECTORY(osganimationtimeline)
ADD_SUBDIRECTORY(osganimationnode)
ADD_SUBDIRECTORY(osganimationmakepath)
ADD_SUBDIRECTORY(osganimationskinning)
ADD_SUBDIRECTORY(osganimationsolid)
# ADD_SUBDIRECTORY(osganimationviewer)
IF (POPPLER_FOUND AND CAIRO_FOUND)
ADD_SUBDIRECTORY(osgpdf)
@@ -176,6 +182,7 @@ IF(DYNAMIC_OPENSCENEGRAPH)
ADD_SUBDIRECTORY(osgwidgetwindow)
ENDIF(BUILD_OSGWIDGET)
IF (LIBVNCSERVER_FOUND)
ADD_SUBDIRECTORY(osgvnc)
ENDIF(LIBVNCSERVER_FOUND)

View File

@@ -0,0 +1,3 @@
SET(TARGET_SRC osganimationmakepath.cpp )
SET(TARGET_ADDED_LIBRARIES osgAnimation )
SETUP_EXAMPLE(osganimationmakepath)

View File

@@ -0,0 +1,337 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*
* Authors:
* Jeremy Moles <jeremy@emperorlinux.com>
* Cedric Pinson <mornifle@plopbyte.net>
*/
#include <iostream>
#include <osg/io_utils>
#include <osg/Geometry>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osg/Material>
#include <osg/MatrixTransform>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgAnimation/Sampler>
class AnimtkUpdateCallback : public osg::NodeCallback
{
public:
META_Object(osgAnimation, AnimtkUpdateCallback);
AnimtkUpdateCallback()
{
_sampler = new osgAnimation::Vec3CubicBezierSampler;
_playing = false;
_lastUpdate = 0;
}
AnimtkUpdateCallback(const AnimtkUpdateCallback& val, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY):
osg::Object(val, copyop),
osg::NodeCallback(val, copyop),
_sampler(val._sampler),
_startTime(val._startTime),
_currentTime(val._currentTime),
_playing(val._playing),
_lastUpdate(val._lastUpdate)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR &&
nv->getFrameStamp() &&
nv->getFrameStamp()->getFrameNumber() != _lastUpdate)
{
_lastUpdate = nv->getFrameStamp()->getFrameNumber();
_currentTime = osg::Timer::instance()->tick();
if (_playing && _sampler.get() && _sampler->getKeyframeContainer())
{
osg::MatrixTransform* transform = dynamic_cast<osg::MatrixTransform*>(node);
if (transform) {
osg::Vec3 result;
float t = osg::Timer::instance()->delta_s(_startTime, _currentTime);
float duration = _sampler->getEndTime() - _sampler->getStartTime();
t = fmod(t, duration);
t += _sampler->getStartTime();
_sampler->getValueAt(t, result);
transform->setMatrix(osg::Matrix::translate(result));
}
}
}
// note, callback is responsible for scenegraph traversal so
// they must call traverse(node,nv) to ensure that the
// scene graph subtree (and associated callbacks) are traversed.
traverse(node,nv);
}
void start() { _startTime = osg::Timer::instance()->tick(); _currentTime = _startTime; _playing = true;}
void stop() { _currentTime = _startTime; _playing = false;}
osg::ref_ptr<osgAnimation::Vec3CubicBezierSampler> _sampler;
osg::Timer_t _startTime;
osg::Timer_t _currentTime;
bool _playing;
int _lastUpdate;
};
class AnimtkStateSetUpdateCallback : public osg::StateSet::Callback
{
public:
META_Object(osgAnimation, AnimtkStateSetUpdateCallback);
AnimtkStateSetUpdateCallback()
{
_sampler = new osgAnimation::Vec4LinearSampler;
_playing = false;
_lastUpdate = 0;
}
AnimtkStateSetUpdateCallback(const AnimtkStateSetUpdateCallback& val, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY):
osg::Object(val, copyop),
osg::StateSet::Callback(val, copyop),
_sampler(val._sampler),
_startTime(val._startTime),
_currentTime(val._currentTime),
_playing(val._playing),
_lastUpdate(val._lastUpdate)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::StateSet* state, osg::NodeVisitor* nv)
{
if (state &&
nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR &&
nv->getFrameStamp() &&
nv->getFrameStamp()->getFrameNumber() != _lastUpdate) {
_lastUpdate = nv->getFrameStamp()->getFrameNumber();
_currentTime = osg::Timer::instance()->tick();
if (_playing && _sampler.get() && _sampler->getKeyframeContainer())
{
osg::Material* material = dynamic_cast<osg::Material*>(state->getAttribute(osg::StateAttribute::MATERIAL));
if (material)
{
osg::Vec4 result;
float t = osg::Timer::instance()->delta_s(_startTime, _currentTime);
float duration = _sampler->getEndTime() - _sampler->getStartTime();
t = fmod(t, duration);
t += _sampler->getStartTime();
_sampler->getValueAt(t, result);
material->setDiffuse(osg::Material::FRONT_AND_BACK, result);
}
}
}
}
void start() { _startTime = osg::Timer::instance()->tick(); _currentTime = _startTime; _playing = true;}
void stop() { _currentTime = _startTime; _playing = false;}
osg::ref_ptr<osgAnimation::Vec4LinearSampler> _sampler;
osg::Timer_t _startTime;
osg::Timer_t _currentTime;
bool _playing;
int _lastUpdate;
};
// This won't really give good results in any situation, but it does demonstrate
// on possible "fast" usage...
class MakePathTimeCallback: public AnimtkUpdateCallback
{
osg::ref_ptr<osg::Geode> _geode;
float _lastAdd;
float _addSeconds;
public:
MakePathTimeCallback(osg::Geode* geode):
_geode(geode),
_lastAdd(0.0f),
_addSeconds(0.08f) {
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
float t = osg::Timer::instance()->delta_s(_startTime, _currentTime);
if(_lastAdd + _addSeconds <= t && t <= 8.0f)
{
osg::Vec3 pos;
_sampler->getValueAt(t, pos);
_geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(pos, 0.5f)));
_geode->dirtyBound();
_lastAdd += _addSeconds;
}
AnimtkUpdateCallback::operator()(node, nv);
}
};
// This will give great results if you DO NOT have VSYNC enabled and can generate
// decent FPS.
class MakePathDistanceCallback: public AnimtkUpdateCallback
{
osg::ref_ptr<osg::Geode> _geode;
osg::Vec3 _lastAdd;
float _threshold;
unsigned int _count;
public:
MakePathDistanceCallback(osg::Geode* geode):
_geode(geode),
_threshold(0.5f),
_count(0) {}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
static bool countReported = false;
float t = osg::Timer::instance()->delta_s(_startTime, _currentTime);
osg::Vec3 pos;
_sampler->getValueAt(t, pos);
osg::Vec3 distance = _lastAdd - pos;
if(t <= 8.0f && distance.length() >= _threshold)
{
_geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(pos, 0.25f)));
_lastAdd = pos;
_count++;
}
else if(t > 8.0f)
{
if(!countReported) std::cout << "Created " << _count << " nodes." << std::endl;
countReported = true;
}
AnimtkUpdateCallback::operator()(node, nv);
}
};
osg::StateSet* setupStateSet()
{
osg::StateSet* st = new osg::StateSet();
st->setAttributeAndModes(new osg::Material(), true);
st->setMode(GL_BLEND, true);
AnimtkStateSetUpdateCallback* callback = new AnimtkStateSetUpdateCallback();
osgAnimation::Vec4KeyframeContainer* keys = callback->_sampler->getOrCreateKeyframeContainer();
keys->push_back(osgAnimation::Vec4Keyframe(0, osg::Vec4(1,0,0,1)));
keys->push_back(osgAnimation::Vec4Keyframe(2, osg::Vec4(0.,1,0,1)));
keys->push_back(osgAnimation::Vec4Keyframe(4, osg::Vec4(0,0,1,1)));
keys->push_back(osgAnimation::Vec4Keyframe(6, osg::Vec4(0,0,1,1)));
keys->push_back(osgAnimation::Vec4Keyframe(8, osg::Vec4(0,1,0,1)));
keys->push_back(osgAnimation::Vec4Keyframe(10, osg::Vec4(1,0,0,1)));
callback->start();
st->setUpdateCallback(callback);
return st;
}
osg::MatrixTransform* setupAnimtkNode(osg::Geode* staticGeode)
{
osg::Vec3 v[4];
v[0] = osg::Vec3( 0, 0, 0);
v[1] = osg::Vec3(20, 40, 60);
v[2] = osg::Vec3(40, 60, 20);
v[3] = osg::Vec3(60, 20, 40);
v[4] = osg::Vec3( 0, 0, 0);
osg::MatrixTransform* node = new osg::MatrixTransform();
AnimtkUpdateCallback* callback = new MakePathDistanceCallback(staticGeode);
osgAnimation::Vec3CubicBezierKeyframeContainer* keys = callback->_sampler->getOrCreateKeyframeContainer();
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(0, osgAnimation::Vec3CubicBezier(
v[0],
v[0] + (v[0] - v[3]),
v[1] - (v[1] - v[0])
)));
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(2, osgAnimation::Vec3CubicBezier(
v[1],
v[1] + (v[1] - v[0]),
v[2] - (v[2] - v[1])
)));
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(4, osgAnimation::Vec3CubicBezier(
v[2],
v[2] + (v[2] - v[1]),
v[3] - (v[3] - v[2])
)));
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(6, osgAnimation::Vec3CubicBezier(
v[3],
v[3] + (v[3] - v[2]),
v[4] - (v[4] - v[3])
)));
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(8, osgAnimation::Vec3CubicBezier(
v[4],
v[4] + (v[4] - v[3]),
v[0] - (v[0] - v[4])
)));
callback->start();
node->setUpdateCallback(callback);
osg::Geode* geode = new osg::Geode();
geode->setStateSet(setupStateSet());
geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), 2)));
node->addChild(geode);
return node;
}
int main(int argc, char** argv)
{
osgViewer::Viewer viewer;
osgGA::TrackballManipulator* tbm = new osgGA::TrackballManipulator();
viewer.setCameraManipulator(tbm);
viewer.addEventHandler(new osgViewer::StatsHandler());
viewer.addEventHandler(new osgViewer::WindowSizeHandler());
osg::Group* root = new osg::Group();
osg::Geode* geode = new osg::Geode();
geode->setStateSet(setupStateSet());
root->setInitialBound(osg::BoundingSphere(osg::Vec3(10,0,20), 50));
root->addChild(setupAnimtkNode(geode));
root->addChild(geode);
viewer.setSceneData(root);
// tbm->setDistance(150);
return viewer.run();
}

View File

@@ -0,0 +1,3 @@
#SET(TARGET_SRC osganimationnode.cpp )
#SET(TARGET_ADDED_LIBRARIES osgAnimation )
#SETUP_EXAMPLE(osganimationnode)

View File

@@ -0,0 +1,272 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <iostream>
#include <osg/Geometry>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osg/MatrixTransform>
#include <osg/Material>
#include <osgAnimation/Sampler>
class AnimtkUpdateCallback : public osg::NodeCallback
{
public:
META_Object(osgAnimation, AnimtkUpdateCallback);
AnimtkUpdateCallback()
{
_sampler = new osgAnimation::Vec3CubicBezierSampler;
_playing = false;
_lastUpdate = 0;
}
AnimtkUpdateCallback(const AnimtkUpdateCallback& val, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY):
osg::Object(val, copyop),
osg::NodeCallback(val, copyop),
_sampler(val._sampler),
_startTime(val._startTime),
_currentTime(val._currentTime),
_playing(val._playing),
_lastUpdate(val._lastUpdate)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR &&
nv->getFrameStamp() &&
nv->getFrameStamp()->getFrameNumber() != _lastUpdate) {
_lastUpdate = nv->getFrameStamp()->getFrameNumber();
_currentTime = osg::Timer::instance()->tick();
if (_playing && _sampler.get() && _sampler->getKeyframeContainer()) {
osg::MatrixTransform* transform = dynamic_cast<osg::MatrixTransform*>(node);
if (transform) {
osg::Vec3 result;
float t = osg::Timer::instance()->delta_s(_startTime, _currentTime);
float duration = _sampler->getEndTime() - _sampler->getStartTime();
t = fmod(t, duration);
t += _sampler->getStartTime();
_sampler->getValueAt(t, result);
transform->setMatrix(osg::Matrix::translate(result));
}
}
}
// note, callback is responsible for scenegraph traversal so
// they must call traverse(node,nv) to ensure that the
// scene graph subtree (and associated callbacks) are traversed.
traverse(node,nv);
}
void start() { _startTime = osg::Timer::instance()->tick(); _currentTime = _startTime; _playing = true;}
void stop() { _currentTime = _startTime; _playing = false;}
osg::ref_ptr<osgAnimation::Vec3CubicBezierSampler> _sampler;
osg::Timer_t _startTime;
osg::Timer_t _currentTime;
bool _playing;
int _lastUpdate;
};
class AnimtkStateSetUpdateCallback : public osg::StateSet::Callback
{
public:
META_Object(osgAnimation, AnimtkStateSetUpdateCallback);
AnimtkStateSetUpdateCallback()
{
_sampler = new osgAnimation::Vec4LinearSampler;
_playing = false;
_lastUpdate = 0;
}
AnimtkStateSetUpdateCallback(const AnimtkStateSetUpdateCallback& val, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY):
osg::Object(val, copyop),
osg::StateSet::Callback(val, copyop),
_sampler(val._sampler),
_startTime(val._startTime),
_currentTime(val._currentTime),
_playing(val._playing),
_lastUpdate(val._lastUpdate)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::StateSet* state, osg::NodeVisitor* nv)
{
if (state &&
nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR &&
nv->getFrameStamp() &&
nv->getFrameStamp()->getFrameNumber() != _lastUpdate)
{
_lastUpdate = nv->getFrameStamp()->getFrameNumber();
_currentTime = osg::Timer::instance()->tick();
if (_playing && _sampler.get() && _sampler->getKeyframeContainer())
{
osg::Material* material = dynamic_cast<osg::Material*>(state->getAttribute(osg::StateAttribute::MATERIAL));
if (material)
{
osg::Vec4 result;
float t = osg::Timer::instance()->delta_s(_startTime, _currentTime);
float duration = _sampler->getEndTime() - _sampler->getStartTime();
t = fmod(t, duration);
t += _sampler->getStartTime();
_sampler->getValueAt(t, result);
material->setDiffuse(osg::Material::FRONT_AND_BACK, result);
}
}
}
}
void start() { _startTime = osg::Timer::instance()->tick(); _currentTime = _startTime; _playing = true;}
void stop() { _currentTime = _startTime; _playing = false;}
osg::ref_ptr<osgAnimation::Vec4LinearSampler> _sampler;
osg::Timer_t _startTime;
osg::Timer_t _currentTime;
bool _playing;
int _lastUpdate;
};
osg::Geode* createAxis()
{
osg::Geode* geode = new osg::Geode;
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry());
osg::ref_ptr<osg::Vec3Array> vertices (new osg::Vec3Array());
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 10.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 10.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 10.0));
geometry->setVertexArray (vertices.get());
osg::ref_ptr<osg::Vec4Array> colors (new osg::Vec4Array());
colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
geometry->setColorArray (colors.get());
geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,6));
geode->addDrawable( geometry.get() );
geode->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
return geode;
}
osg::StateSet* setupStateSet()
{
osg::StateSet* st = new osg::StateSet;
st->setAttributeAndModes(new osg::Material, true);
st->setMode(GL_BLEND, true);
AnimtkStateSetUpdateCallback* callback = new AnimtkStateSetUpdateCallback;
osgAnimation::Vec4KeyframeContainer* keys = callback->_sampler->getOrCreateKeyframeContainer();
keys->push_back(osgAnimation::Vec4Keyframe(0, osg::Vec4(0,0,0,0)));
keys->push_back(osgAnimation::Vec4Keyframe(2, osg::Vec4(0.5,0,0,0.5)));
keys->push_back(osgAnimation::Vec4Keyframe(4, osg::Vec4(0,0.5,0,1)));
keys->push_back(osgAnimation::Vec4Keyframe(6, osg::Vec4(0,0,0.5,1)));
keys->push_back(osgAnimation::Vec4Keyframe(8, osg::Vec4(1,1,1,0.5)));
keys->push_back(osgAnimation::Vec4Keyframe(10, osg::Vec4(0,0,0,0)));
callback->start();
st->setUpdateCallback(callback);
return st;
}
osg::Node* setupCube()
{
osg::Geode* geode = new osg::Geode;
geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f,0.0f,0.0f),2)));
geode->setStateSet(setupStateSet());
return geode;
}
osg::MatrixTransform* setupAnimtkNode()
{
osg::Vec3 v[4];
v[0] = osg::Vec3(0,0,0);
v[1] = osg::Vec3(10,-50,0);
v[2] = osg::Vec3(30,-10,20);
v[3] = osg::Vec3(-10,20,-20);
v[4] = osg::Vec3(0,0,0);
osg::MatrixTransform* node = new osg::MatrixTransform;
AnimtkUpdateCallback* callback = new AnimtkUpdateCallback;
osgAnimation::Vec3CubicBezierKeyframeContainer* keys = callback->_sampler->getOrCreateKeyframeContainer();
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(0, osgAnimation::Vec3CubicBezier(
v[0], // pos
v[0] + (v[0] - v[3]), // p1
v[1] - (v[1] - v[0]) // p2
)));
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(2, osgAnimation::Vec3CubicBezier(
v[1], // pos
v[1] + (v[1] - v[0]),
v[2] - (v[2] - v[1])
)));
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(4, osgAnimation::Vec3CubicBezier(
v[2], // pos
v[2] + (v[2] - v[1]),
v[3] - (v[3] - v[2])
)));
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(6, osgAnimation::Vec3CubicBezier(
v[3], // pos
v[3] + (v[3] - v[2]),
v[4] - (v[4] - v[3])
)));
keys->push_back(osgAnimation::Vec3CubicBezierKeyframe(8, osgAnimation::Vec3CubicBezier(
v[4], // pos
v[4] + (v[4] - v[3]),
v[0] - (v[0] - v[4])
)));
callback->start();
node->setUpdateCallback(callback);
node->addChild(setupCube());
return node;
}
int main (int argc, char* argv[])
{
osgViewer::Viewer viewer;
osgGA::TrackballManipulator* manipulator = new osgGA::TrackballManipulator();
viewer.setCameraManipulator(manipulator);
osg::Group* root = new osg::Group;
root->setInitialBound(osg::BoundingSphere(osg::Vec3(10,0,10), 30));
root->addChild(createAxis());
osg::MatrixTransform* node = setupAnimtkNode();
node->addChild(createAxis());
root->addChild(node);
viewer.setSceneData( root );
viewer.realize();
while (!viewer.done())
{
viewer.frame();
}
}

View File

@@ -0,0 +1,3 @@
SET(TARGET_SRC osganimationskinning.cpp )
SET(TARGET_ADDED_LIBRARIES osgAnimation )
SETUP_EXAMPLE(osganimationskinning)

View File

@@ -0,0 +1,267 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <iostream>
#include <osg/Geometry>
#include <osg/MatrixTransform>
#include <osg/Geode>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osgUtil/SmoothingVisitor>
#include <osg/io_utils>
#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/Skinning>
osg::Geode* createAxis()
{
osg::Geode* geode (new osg::Geode());
osg::Geometry* geometry (new osg::Geometry());
osg::Vec3Array* vertices (new osg::Vec3Array());
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 1.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 1.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 1.0));
geometry->setVertexArray (vertices);
osg::Vec4Array* colors (new osg::Vec4Array());
colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
geometry->setColorArray (colors);
geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,6));
geode->addDrawable( geometry );
return geode;
}
osgAnimation::RigGeometry* createTesselatedBox(int nsplit, float size)
{
osgAnimation::RigGeometry* geometry = new osgAnimation::RigGeometry;
osg::ref_ptr<osg::Vec3Array> vertices (new osg::Vec3Array());
osg::ref_ptr<osg::Vec3Array> colors (new osg::Vec3Array());
geometry->setVertexArray (vertices.get());
geometry->setColorArray (colors.get());
geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);
float step = size / nsplit;
float s = 0.5/4.0;
for (int i = 0; i < nsplit; i++)
{
float x = -1 + i * step;
std::cout << x << std::endl;
vertices->push_back (osg::Vec3 ( x, s, s));
vertices->push_back (osg::Vec3 ( x, -s, s));
vertices->push_back (osg::Vec3 ( x, -s, -s));
vertices->push_back (osg::Vec3 ( x, s, -s));
osg::Vec3 c (0,0,0);
c[i%3] = 1;
colors->push_back (c);
colors->push_back (c);
colors->push_back (c);
colors->push_back (c);
}
osg::ref_ptr<osg::UIntArray> array = new osg::UIntArray;
for (int i = 0; i < nsplit - 1; i++)
{
int base = i * 4;
array->push_back(base);
array->push_back(base+1);
array->push_back(base+4);
array->push_back(base+1);
array->push_back(base+5);
array->push_back(base+4);
array->push_back(base+3);
array->push_back(base);
array->push_back(base+4);
array->push_back(base+7);
array->push_back(base+3);
array->push_back(base+4);
array->push_back(base+5);
array->push_back(base+1);
array->push_back(base+2);
array->push_back(base+2);
array->push_back(base+6);
array->push_back(base+5);
array->push_back(base+2);
array->push_back(base+3);
array->push_back(base+7);
array->push_back(base+6);
array->push_back(base+2);
array->push_back(base+7);
}
geometry->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, array->size(), &array->front()));
geometry->setUseDisplayList( false );
return geometry;
}
void initVertexMap(osgAnimation::Bone* b0,
osgAnimation::Bone* b1,
osgAnimation::Bone* b2,
osgAnimation::RigGeometry* geom,
osg::Vec3Array* array)
{
osgAnimation::VertexInfluenceSet vertexesInfluences;
osgAnimation::VertexInfluenceMap* vim = new osgAnimation::VertexInfluenceMap;
(*vim)[b0->getName()].setName(b0->getName());
(*vim)[b1->getName()].setName(b1->getName());
(*vim)[b2->getName()].setName(b2->getName());
for (int i = 0; i < (int)array->size(); i++)
{
float val = (*array)[i][0];
std::cout << val << std::endl;
if (val >= -1 && val <= 0)
(*vim)[b0->getName()].push_back(osgAnimation::VertexIndexWeight(i,1));
else if ( val > 0 && val <= 1)
(*vim)[b1->getName()].push_back(osgAnimation::VertexIndexWeight(i,1));
else if ( val > 1)
(*vim)[b2->getName()].push_back(osgAnimation::VertexIndexWeight(i,1));
}
geom->setInfluenceMap(vim);
}
int main (int argc, char* argv[])
{
osgViewer::Viewer viewer;
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
osg::ref_ptr<osgAnimation::Skeleton> skelroot = new osgAnimation::Skeleton;
osg::ref_ptr<osgAnimation::Bone> root = new osgAnimation::Bone;
{
root->setBindMatrixInBoneSpace(osg::Matrix::identity());
root->setBindMatrixInBoneSpace(osg::Matrix::translate(-1,0,0));
root->setName("root");
}
osg::ref_ptr<osgAnimation::Bone> right0 = new osgAnimation::Bone;
right0->setBindMatrixInBoneSpace(osg::Matrix::translate(1,0,0));
right0->setName("right0");
osg::ref_ptr<osgAnimation::Bone> right1 = new osgAnimation::Bone;
right1->setBindMatrixInBoneSpace(osg::Matrix::translate(1,0,0));
right1->setName("right1");
root->addChild(right0.get());
right0->addChild(right1.get());
skelroot->addChild(root.get());
osg::ref_ptr<osgAnimation::AnimationManager> manager = new osgAnimation::AnimationManager;
osgAnimation::Animation* anim = new osgAnimation::Animation;
{
osgAnimation::QuatKeyframeContainer* keys0 = new osgAnimation::QuatKeyframeContainer;
osg::Quat rotate;
rotate.makeRotate(osg::PI_2, osg::Vec3(0,0,1));
keys0->push_back(osgAnimation::QuatKeyframe(0,osg::Quat(0,0,0,1)));
keys0->push_back(osgAnimation::QuatKeyframe(3,rotate));
keys0->push_back(osgAnimation::QuatKeyframe(6,rotate));
osgAnimation::QuatSphericalLinearSampler* sampler = new osgAnimation::QuatSphericalLinearSampler;
sampler->setKeyframeContainer(keys0);
osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(right0->getUpdateCallback());
cb->setName("right0");
osgAnimation::QuatSphericalLinearChannel* channel = new osgAnimation::QuatSphericalLinearChannel(sampler);
channel->setName("quaternion");
channel->setTargetName("right0");
//cb->link(channel);
anim->addChannel(channel);
}
{
osgAnimation::QuatKeyframeContainer* keys1 = new osgAnimation::QuatKeyframeContainer;
osg::Quat rotate;
rotate.makeRotate(osg::PI_2, osg::Vec3(0,0,1));
keys1->push_back(osgAnimation::QuatKeyframe(0,osg::Quat(0,0,0,1)));
keys1->push_back(osgAnimation::QuatKeyframe(3,osg::Quat(0,0,0,1)));
keys1->push_back(osgAnimation::QuatKeyframe(6,rotate));
osgAnimation::QuatSphericalLinearSampler* sampler = new osgAnimation::QuatSphericalLinearSampler;
sampler->setKeyframeContainer(keys1);
osgAnimation::QuatSphericalLinearChannel* channel = new osgAnimation::QuatSphericalLinearChannel(sampler);
osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(right1->getUpdateCallback());
cb->setName("right1");
channel->setName("quaternion");
channel->setTargetName("right1");
//cb->link(channel);
anim->addChannel(channel);
}
manager->registerAnimation(anim);
manager->buildTargetReference();
// let's start !
manager->playAnimation(anim);
// we will use local data from the skeleton
osg::Group* scene = new osg::Group;
osg::MatrixTransform* rootTransform = new osg::MatrixTransform;
rootTransform->setMatrix(osg::Matrix::rotate(osg::PI_2,osg::Vec3(1,0,0)));
right0->addChild(createAxis());
right0->setDataVariance(osg::Object::DYNAMIC);
right1->addChild(createAxis());
right1->setDataVariance(osg::Object::DYNAMIC);
osg::MatrixTransform* trueroot = new osg::MatrixTransform;
trueroot->setMatrix(osg::Matrix(root->getMatrixInBoneSpace().ptr()));
trueroot->addChild(createAxis());
trueroot->setDataVariance(osg::Object::DYNAMIC);
rootTransform->addChild(manager.get());
scene->addChild(rootTransform);
manager->addChild(skelroot.get());
osgAnimation::RigGeometry* geom = createTesselatedBox(4, 4.0);
osg::Geode* geode = new osg::Geode;
geode->addDrawable(geom);
skelroot->addChild(geode);
osg::ref_ptr<osg::Vec3Array> src = dynamic_cast<osg::Vec3Array*>(geom->getVertexArray());
geom->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
geom->setDataVariance(osg::Object::DYNAMIC);
OSGANIMATION_ASSERT(src);
initVertexMap(root.get(), right0.get(), right1.get(), geom, src.get());
geom->buildVertexSet();
geom->buildTransformer(skelroot.get());
// let's run !
viewer.setSceneData( scene );
viewer.realize();
while (!viewer.done())
{
viewer.frame();
}
return 0;
}

View File

@@ -0,0 +1,3 @@
SET(TARGET_SRC osganimationsolid.cpp )
SET(TARGET_ADDED_LIBRARIES osgAnimation )
SETUP_EXAMPLE(osganimationsolid)

View File

@@ -0,0 +1,118 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <iostream>
#include <osg/Geometry>
#include <osg/Shape>
#include <osg/ShapeDrawable>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osg/MatrixTransform>
#include <osgAnimation/AnimationManager>
#include <osgAnimation/Channel>
#include <osgAnimation/UpdateCallback>
using namespace osgAnimation;
osg::ref_ptr<osg::Geode> createAxis()
{
osg::ref_ptr<osg::Geode> geode (new osg::Geode());
osg::ref_ptr<osg::Geometry> geometry (new osg::Geometry());
osg::ref_ptr<osg::Vec3Array> vertices (new osg::Vec3Array());
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 10.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 10.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 10.0));
geometry->setVertexArray (vertices.get());
osg::ref_ptr<osg::Vec4Array> colors (new osg::Vec4Array());
colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
geometry->setColorArray (colors.get());
geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,6));
geode->addDrawable( geometry.get() );
geode->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
return geode;
}
int main (int argc, char* argv[])
{
osgViewer::Viewer viewer;
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
osg::Group* root = new osg::Group;
osg::ref_ptr<osg::Geode> axe = createAxis();
osg::ref_ptr<osg::Geode> geode = new osg::Geode;
geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f,0.0f,0.0f),0.5)));
osg::ref_ptr<osg::MatrixTransform> trans = new osg::MatrixTransform();
trans->setName("AnimatedNode");
trans->setDataVariance(osg::Object::DYNAMIC);
trans->setUpdateCallback(new osgAnimation::UpdateTransform("AnimatedCallback"));
trans->setMatrix(osg::Matrix::identity());
trans->addChild (geode.get());
root->addChild (axe.get());
root->addChild (trans.get());
// Define a scheduler for our animations
osgAnimation::AnimationManager* mng = new osgAnimation::AnimationManager();
mng->addChild(root);
// And we finaly define our channel
osgAnimation::Vec3LinearChannel* channelAnimation1 = new osgAnimation::Vec3LinearChannel;
channelAnimation1->setTargetName("AnimatedCallback");
channelAnimation1->setName("position");
channelAnimation1->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec3Keyframe(0, osg::Vec3(0,0,0)));
channelAnimation1->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec3Keyframe(2, osg::Vec3(1,1,0)));
osgAnimation::Animation* anim1 = new osgAnimation::Animation;
anim1->addChannel(channelAnimation1);
anim1->setPlaymode(osgAnimation::Animation::PPONG);
osgAnimation::Vec3LinearChannel* channelAnimation2 = new osgAnimation::Vec3LinearChannel;
channelAnimation2->setTargetName("AnimatedCallback");
channelAnimation2->setName("euler");
channelAnimation2->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec3Keyframe(0, osg::Vec3(0,0,0)));
channelAnimation2->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec3Keyframe(1.5, osg::Vec3(2*osg::PI,0,0)));
osgAnimation::Animation* anim2 = new osgAnimation::Animation;
anim2->addChannel(channelAnimation2);
anim2->setPlaymode(osgAnimation::Animation::LOOP);
// We register all animation inside the scheduler
mng->registerAnimation(anim1);
mng->registerAnimation(anim2);
mng->playAnimation(anim1);
mng->playAnimation(anim2);
viewer.setSceneData( mng );
return viewer.run();
}

View File

@@ -0,0 +1,3 @@
SET(TARGET_SRC osganimationtimeline.cpp )
SET(TARGET_ADDED_LIBRARIES osgAnimation )
SETUP_EXAMPLE(osganimationtimeline)

View File

@@ -0,0 +1,209 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <iostream>
#include <osgDB/ReadFile>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/DriveManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgGA/StateSetManipulator>
#include <osgGA/AnimationPathManipulator>
#include <osgGA/TerrainManipulator>
#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/Skinning>
#include <osgAnimation/Timeline>
#include <osgAnimation/AnimationManagerBase>
struct NoseBegin : public osgAnimation::Action::Callback
{
virtual void operator()(osgAnimation::Action* action)
{
std::cout << "sacrebleu, it scratches my nose, let me scratch it" << std::endl;
std::cout << "process NoseBegin call back " << action->getName() << std::endl << std::endl;
}
};
struct NoseEnd : public osgAnimation::Action::Callback
{
virtual void operator()(osgAnimation::Action* action)
{
std::cout << "shhhrt shrrrrt shhhhhhrrrrt, haaa it's better"<< std::endl;
std::cout << "process NoseEnd call back " << action->getName() << std::endl << std::endl;
}
};
struct ExampleTimelineUsage : public osgGA::GUIEventHandler
{
osg::ref_ptr<osgAnimation::StripAnimation> _mainLoop;
osg::ref_ptr<osgAnimation::StripAnimation> _scratchHead;
osg::ref_ptr<osgAnimation::StripAnimation> _scratchNose;
osg::ref_ptr<osgAnimation::AnimationManagerTimeline> _manager;
bool _releaseKey;
ExampleTimelineUsage(osgAnimation::AnimationManagerTimeline* manager)
{
_releaseKey = false;
_manager = manager;
osgAnimation::AnimationMap map = _manager->getAnimationMap();
_mainLoop = new osgAnimation::StripAnimation(map["Idle_Main"].get(),0.0,0.0);
_mainLoop->setLoop(0); // means forever
_scratchHead = new osgAnimation::StripAnimation(map["Idle_Head_Scratch.02"].get(),0.2,0.3);
_scratchHead->setLoop(1); // one time
map["Idle_Nose_Scratch.01"]->setDuration(10.0); // set this animation duration to 10 seconds
_scratchNose = new osgAnimation::StripAnimation(map["Idle_Nose_Scratch.01"].get(),0.2,0.3);
_scratchNose->setLoop(1); // one time
// add the main loop at priority 0 at time 0.
osgAnimation::Timeline* tml = _manager->getTimeline();
tml->play();
tml->addActionAt(0.0, _mainLoop.get(), 0);
// add a scratch head priority 1 at 3.0 second.
tml->addActionAt(5.0, _scratchHead.get(), 1);
// populate time with scratch head
for (int i = 1; i < 20; i++)
{
// we add a scratch head priority 1 each 10 second
// note:
// it's possible to add the same instance more then once on the timeline
// the only things you need to take care is if you remove it. It will remove
// all instance that exist on the timeline. If you need to differtiate
// it's better to create a new instance
tml->addActionAt(5.0 + 10.0 * i, _scratchHead.get(), 1);
}
// we will add the scratch nose action only when the player hit a key
// in the operator()
// now we will add callback at end and begin of animation of Idle_Nose_Scratch.02
_scratchNose->setCallback(0.0, new NoseBegin);
_scratchNose->setCallback(_scratchNose->getNumFrames()-1, new NoseEnd);
}
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
if (ea.getEventType() == osgGA::GUIEventAdapter::KEYUP)
{
_releaseKey = true;
}
return false;
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
if (_releaseKey) // we hit a key and release it execute an action
{
osgAnimation::Timeline* tml = _manager->getTimeline();
// dont play if already playing
if (!tml->isActive(_scratchNose.get()))
{
// add this animation on top of two other
// we add one to evaluate the animation at the next frame, else we
// will miss the current frame
tml->addActionAt(tml->getCurrentFrame() + 1, _scratchNose.get(), 2);
}
_releaseKey = false;
}
}
else
{
osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>(nv);
if (ev && ev->getActionAdapter() && !ev->getEvents().empty())
{
for(osgGA::EventQueue::Events::iterator itr = ev->getEvents().begin();
itr != ev->getEvents().end();
++itr)
{
handleWithCheckAgainstIgnoreHandledEventsMask(*(*itr), *(ev->getActionAdapter()), node, nv);
}
}
}
traverse(node, nv);
}
};
int main (int argc, char* argv[])
{
std::cerr << "This example workd only with osgAnimation/nathan.osg" << std::endl;
osg::ArgumentParser psr(&argc, argv);
osgViewer::Viewer viewer(psr);
osg::ref_ptr<osg::Group> group = new osg::Group();
std::string file = "osgAnimation/nathan.osg";
if(argc >= 2)
file = psr[1];
// replace the manager
osgAnimation::AnimationManagerBase* animationManager = dynamic_cast<osgAnimation::AnimationManagerBase*>(osgDB::readNodeFile(file));
if(!animationManager)
{
std::cerr << "Couldn't convert the file's toplevel object into an AnimationManager." << std::endl;
return 1;
}
osg::ref_ptr<osgAnimation::AnimationManagerTimeline> tl = new osgAnimation::AnimationManagerTimeline(*animationManager);
animationManager->removeChildren(0, animationManager->getNumChildren());
ExampleTimelineUsage* callback = new ExampleTimelineUsage(tl.get());
group->addChild(tl.get());
group->setEventCallback(callback);
group->setUpdateCallback(callback);
// add the state manipulator
viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
// add the thread model handler
viewer.addEventHandler(new osgViewer::ThreadingHandler);
// add the window size toggle handler
viewer.addEventHandler(new osgViewer::WindowSizeHandler);
// add the stats handler
viewer.addEventHandler(new osgViewer::StatsHandler);
// add the help handler
viewer.addEventHandler(new osgViewer::HelpHandler(psr.getApplicationUsage()));
// add the LOD Scale handler
viewer.addEventHandler(new osgViewer::LODScaleHandler);
// add the screen capture handler
viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
viewer.setSceneData(group.get());
return viewer.run();
}

View File

@@ -0,0 +1,123 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*
* Authors:
* Cedric Pinson <mornifle@plopbyte.net>
* jeremy Moles <jeremy@emperorlinux.com>
*/
#ifndef ANIMTKVIEWER_H
#define ANIMTKVIEWER_H
#include <osg/Node>
#include <osgDB/ReadFile>
#include <osgAnimation/AnimationManager>
class AnimtkViewerModelController
{
public:
typedef std::vector<std::string> AnimationMapVector;
static AnimtkViewerModelController& instance()
{
static AnimtkViewerModelController avmc;
return avmc;
}
static bool setModel(osgAnimation::AnimationManager* model)
{
AnimtkViewerModelController& self = instance();
self._model = model;
self._map = self._model->getAnimationMap();
for(osgAnimation::AnimationMap::iterator it = self._map.begin(); it != self._map.end(); it++)
self._amv.push_back(it->first);
return true;
}
bool list()
{
std::cout << "Animation List:" << std::endl;
for(osgAnimation::AnimationMap::iterator it = _map.begin(); it != _map.end(); it++)
std::cout << it->first << std::endl;
return true;
}
bool play()
{
if(_focus < _amv.size())
{
std::cout << "Play " << _amv[_focus] << std::endl;
_model->playAnimation(_map[_amv[_focus]].get());
return true;
}
return false;
}
bool stop()
{
if(_focus < _amv.size())
{
std::cout << "Stop " << _amv[_focus] << std::endl;
_model->stopAnimation(_map[_amv[_focus]].get());
return true;
}
return false;
}
bool next()
{
_focus = (_focus + 1) % _map.size();
std::cout << "Current now is " << _amv[_focus] << std::endl;
return true;
}
bool previous()
{
_focus = (_map.size() + _focus - 1) % _map.size();
std::cout << "Current now is " << _amv[_focus] << std::endl;
return true;
}
bool playByName(const std::string& name)
{
for(unsigned int i = 0; i < _amv.size(); i++) if(_amv[i] == name) _focus = i;
_model->playAnimation(_map[name].get());
return true;
}
const std::string& getCurrentAnimationName() const
{
return _amv[_focus];
}
const AnimationMapVector& getAnimationMap() const
{
return _amv;
}
private:
osg::ref_ptr<osgAnimation::AnimationManager> _model;
osgAnimation::AnimationMap _map;
AnimationMapVector _amv;
unsigned int _focus;
AnimtkViewerModelController():
_model(0),
_focus(0) {}
};
#endif

View File

@@ -0,0 +1,116 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*
* Authors:
* Cedric Pinson <mornifle@plopbyte.net>
* jeremy Moles <jeremy@emperorlinux.com>
*/
#include "AnimtkViewerKeyHandler"
#include "AnimtkViewerGUI"
#include <iostream>
#include <osg/io_utils>
#include <osg/Geometry>
#include <osg/MatrixTransform>
#include <osg/Geode>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgWidget/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgGA/StateSetManipulator>
#include <osgDB/ReadFile>
const int WIDTH = 1440;
const int HEIGHT = 900;
osg::Geode* createAxis()
{
osg::Geode* geode = new osg::Geode();
osg::Geometry* geometry = new osg::Geometry();
osg::Vec3Array* vertices = new osg::Vec3Array();
osg::Vec4Array* colors = new osg::Vec4Array();
vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
vertices->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));
vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
vertices->push_back(osg::Vec3(0.0f, 1.0f, 0.0f));
vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));
vertices->push_back(osg::Vec3(0.0f, 0.0f, 1.0f));
colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back(osg::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
colors->push_back(osg::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
geometry->setVertexArray(vertices);
geometry->setColorArray(colors);
geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES, 0, 6));
geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
geode->addDrawable(geometry);
return geode;
}
int main(int argc, char** argv)
{
osg::ArgumentParser psr(&argc, argv);
if(argc < 2)
{
std::cerr << "usage: AnimtkViewer <file.osg>" << std::endl;
return 1;
}
osgViewer::Viewer viewer(psr);
osg::ref_ptr<osg::Group> group = new osg::Group();
osgAnimation::AnimationManager* animationManager = dynamic_cast<osgAnimation::AnimationManager*>(osgDB::readNodeFile(psr[1]));
if(!animationManager)
{
std::cerr << "Couldn't convert the file's toplevel object into an AnimationManager." << std::endl;
return 1;
}
// Set our Singleton's model.
AnimtkViewerModelController::setModel(animationManager);
animationManager->addChild(createAxis());
AnimtkViewerGUI* gui = new AnimtkViewerGUI(&viewer, WIDTH, HEIGHT, 0x1234);
osg::Camera* camera = gui->createParentOrthoCamera();
animationManager->setNodeMask(0x0001);
group->addChild(animationManager);
group->addChild(camera);
viewer.addEventHandler(new AnimtkKeyEventHandler());
viewer.addEventHandler(new osgViewer::StatsHandler());
viewer.addEventHandler(new osgViewer::WindowSizeHandler());
viewer.addEventHandler(new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()));
viewer.addEventHandler(new osgWidget::MouseHandler(gui));
viewer.addEventHandler(new osgWidget::KeyboardHandler(gui));
viewer.addEventHandler(new osgWidget::ResizeHandler(gui, camera));
viewer.setSceneData(group.get());
viewer.setUpViewInWindow(40, 40, WIDTH, HEIGHT);
return viewer.run();
}

View File

@@ -0,0 +1,46 @@
/* -*-c++-*-
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
Authors:
Jeremy Moles <jeremy@emperorlinux.com>
Cedric Pinson <mornifle@plopbyte.net>
*/
#ifndef ANIMTKVIEWERGUI_H
#define ANIMTKVIEWERGUI_H
#include <osgWidget/WindowManager>
class AnimtkViewerGUI: public osgWidget::WindowManager {
osg::ref_ptr<osgWidget::Box> _buttonBox;
osg::ref_ptr<osgWidget::Box> _listBox;
osg::ref_ptr<osgWidget::Box> _labelBox;
protected:
osgWidget::Widget* _createButton(const std::string&);
bool _buttonPush(osgWidget::Event&);
bool _listMouseHover(osgWidget::Event&);
void _createButtonBox();
void _createListBox();
void _createLabelBox();
public:
AnimtkViewerGUI(osgViewer::View*, float, float, unsigned int);
};
#endif

View File

@@ -0,0 +1,407 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*
* Authors:
* Cedric Pinson <mornifle@plopbyte.net>
* jeremy Moles <jeremy@emperorlinux.com>
*/
#include "AnimtkViewer"
#include "AnimtkViewerGUI"
#include <osg/Version>
#include <osgWidget/WindowManager>
#include <osgAnimation/EaseMotion>
const std::string IMAGE_PATH = "osgAnimation/Images/";
template <class T>
struct Sampler: public osg::Drawable::UpdateCallback
{
T _motion;
Sampler() {
}
};
typedef Sampler<osgAnimation::OutQuadMotion> WidgetSampler;
struct ButtonFunctor: public WidgetSampler
{
float _direction;
float _previous;
const float _speed;
ButtonFunctor(): _speed(5) { _direction = -_speed; _previous = 0;}
bool enter(osgWidget::Event& ev)
{
_direction = _speed;
return true;
}
bool leave(osgWidget::Event& ev)
{
_direction = -_speed;
return true;
}
void update(osg::NodeVisitor* nv , osg::Drawable* geom)
{
const osg::FrameStamp* f = nv->getFrameStamp();
float dt = f->getSimulationTime() - _previous;
_previous = f->getSimulationTime();
update(dt,dynamic_cast<osgWidget::Widget*>(geom));
}
void update(float t, osgWidget::Widget* w)
{
if (!w) return;
_motion.update(t*_direction);
float val = _motion.getValue()*0.5;
val += 0.5;
if (val >= 1.0)
val = 1.0;
w->setColor(osg::Vec4(val, val, val, 1));
}
};
struct LabelFunctor: public WidgetSampler
{
float _previous;
bool _active;
const float _fadeOutTime;
osgAnimation::OutCubicMotion _scaleSampler;
LabelFunctor():
_fadeOutTime(1.5f)
{
_previous = 0.0f;
_active = false;
_scaleSampler = osgAnimation::OutCubicMotion(0.5, 1.0, 1.0);
}
void setActive(bool active)
{
_active = active;
if(active) _motion.reset();
_scaleSampler.reset();
}
void update(osg::NodeVisitor* nv , osg::Drawable* geom)
{
const osg::FrameStamp* f = nv->getFrameStamp();
float st = f->getSimulationTime();
float dt = st - _previous;
_previous = st;
if(!_active) return;
update(dt, dynamic_cast<osgWidget::Label*>(geom));
updateScale(dt, dynamic_cast<osgWidget::Label*>(geom));
}
void update(float t, osgWidget::Label* w)
{
if(!w) return;
_motion.update(t / _fadeOutTime);
float val = _motion.getValue();
if(val >= 1.0f) {
_motion.reset();
_active = false;
}
w->setFontColor(osg::Vec4(0.0f, 0.0f, 0.0f, (1.0f - val) * 0.7f));
}
void updateScale(float t, osgWidget::Label* w)
{
_scaleSampler.update(t);
float val = _scaleSampler.getValue();
osgWidget::Window* win = w->getParent();
win->setScale(val);
win->update();
}
};
struct ListFunctor: public osg::NodeCallback
{
float _previous;
int _direction;
osgAnimation::InQuadMotion _transformSampler;
ListFunctor()
{
_direction = 1;
_previous = 0;
_transformSampler.update(1.0f);
}
void toggleShown()
{
if(_direction == 1) _direction = -1;
else _direction = 1;
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
const osg::FrameStamp* f = nv->getFrameStamp();
float st = f->getSimulationTime();
float dt = st - _previous;
_previous = st;
_transformSampler.update((dt * _direction) / 0.5f);
float val = _transformSampler.getValue();
if(val > 1.0f || val < 0.0f) return;
osgWidget::Window* win = dynamic_cast<osgWidget::Window*>(node);
float w = win->getWidth();
float wmw = win->getWindowManager()->getWidth();
win->setX((wmw - w) + (val * w));
win->update();
}
};
// This is a temporary hack to "prevent" dragging on Widgets and Windows.
bool eatDrag(osgWidget::Event&)
{
return true;
}
AnimtkViewerGUI::AnimtkViewerGUI(osgViewer::View* view, float w, float h, unsigned int mask):
osgWidget::WindowManager(view, w, h, mask, 0)
{
_createButtonBox();
_createLabelBox();
_createListBox();
_labelBox->setAnchorHorizontal(osgWidget::Window::HA_LEFT);
_labelBox->setY(74.0f);
_labelBox->setVisibilityMode(osgWidget::Window::VM_ENTIRE);
_listBox->setOrigin(getWidth(), 74.0f);
addChild(_buttonBox.get());
addChild(_labelBox.get());
addChild(_listBox.get());
resizeAllWindows();
// Remember, you can't call resizePercent until AFTER the box is parented
// by a WindowManager; how could it possibly resize itself if it doesn't know
// how large it's viewable area is?
_buttonBox->resizePercent(100.0f);
_buttonBox->resizeAdd(0.0f, 10.0f);
}
osgWidget::Widget* AnimtkViewerGUI::_createButton(const std::string& name)
{
osgWidget::Widget* b = new osgWidget::Widget(name, 64.0f, 64.0f);
if(!b) return 0;
b->setImage(IMAGE_PATH + name + ".png", true);
b->setEventMask(osgWidget::EVENT_MASK_MOUSE_DRAG);
ButtonFunctor* bt = new ButtonFunctor();
b->setUpdateCallback(bt);
b->addCallback(new osgWidget::Callback(&ButtonFunctor::enter, bt, osgWidget::EVENT_MOUSE_ENTER));
b->addCallback(new osgWidget::Callback(&ButtonFunctor::leave, bt, osgWidget::EVENT_MOUSE_LEAVE));
b->addCallback(new osgWidget::Callback(&AnimtkViewerGUI::_buttonPush, this, osgWidget::EVENT_MOUSE_PUSH));
b->addCallback(new osgWidget::Callback(&eatDrag, osgWidget::EVENT_MOUSE_DRAG));
return b;
}
bool AnimtkViewerGUI::_listMouseHover(osgWidget::Event& ev)
{
osgWidget::Label* l = dynamic_cast<osgWidget::Label*>(ev.getWidget());
if(!l) return false;
if(ev.type == osgWidget::EVENT_MOUSE_ENTER) l->setFontColor(1.0f, 1.0f, 1.0f, 1.0f);
else if(ev.type == osgWidget::EVENT_MOUSE_LEAVE) l->setFontColor(1.0f, 1.0f, 1.0f, 0.3f);
else if(ev.type == osgWidget::EVENT_MOUSE_PUSH) {
AnimtkViewerModelController::instance().playByName(ev.getWidget()->getName());
}
else return false;
return true;
}
bool AnimtkViewerGUI::_buttonPush(osgWidget::Event& ev)
{
if(!ev.getWidget()) return false;
osgWidget::Label* l = static_cast<osgWidget::Label*>(_labelBox->getByName("label"));
if(!l) return false;
LabelFunctor* lf = dynamic_cast<LabelFunctor*>(l->getUpdateCallback());
if(!lf) return false;
// We're safe at this point, so begin processing.
AnimtkViewerModelController& mc = AnimtkViewerModelController::instance();
std::string name = ev.getWidget()->getName();
if(name == "play") mc.play();
else if(name == "stop") mc.stop();
else if(name == "next")
{
mc.next();
l->setFontColor(osg::Vec4(0.0f, 0.0f, 0.0f, 0.7f));
l->setLabel(mc.getCurrentAnimationName());
lf->setActive(true);
}
else if(name == "back")
{
mc.previous();
l->setFontColor(osg::Vec4(0.0f, 0.0f, 0.0f, 0.7f));
l->setLabel(mc.getCurrentAnimationName());
lf->setActive(true);
}
else if(name == "pause")
{
}
else if(name == "open")
{
ListFunctor* lsf = dynamic_cast<ListFunctor*>(_listBox->getUpdateCallback());
if(!lsf) return false;
lsf->toggleShown();
}
else return false;
return true;
}
void AnimtkViewerGUI::_createButtonBox()
{
_buttonBox = new osgWidget::Box("buttonBox", osgWidget::Box::HORIZONTAL);
osgWidget::Widget* space = new osgWidget::Widget("nullSpace", 0.0f, 0.0f);
osgWidget::Widget* back = _createButton("back");
osgWidget::Widget* next = _createButton("next");
osgWidget::Widget* play = _createButton("play");
osgWidget::Widget* pause = _createButton("pause");
osgWidget::Widget* stop = _createButton("stop");
osgWidget::Widget* open = _createButton("open");
space->setCanFill(true);
space->setColor(0.0f, 0.0f, 0.0f, 0.0f);
_buttonBox->addWidget(space);
_buttonBox->addWidget(back);
_buttonBox->addWidget(next);
_buttonBox->addWidget(play);
_buttonBox->addWidget(pause);
_buttonBox->addWidget(stop);
_buttonBox->addWidget(open);
_buttonBox->addWidget(osg::clone(space, "space1", osg::CopyOp::DEEP_COPY_ALL));
_buttonBox->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.7f);
_buttonBox->setEventMask(osgWidget::EVENT_MASK_MOUSE_DRAG);
_buttonBox->addCallback(new osgWidget::Callback(&eatDrag, osgWidget::EVENT_MOUSE_DRAG));
}
void AnimtkViewerGUI::_createListBox()
{
_listBox = new osgWidget::Box("listBox", osgWidget::Box::VERTICAL);
const AnimtkViewerModelController::AnimationMapVector& amv =
AnimtkViewerModelController::instance().getAnimationMap()
;
for(
AnimtkViewerModelController::AnimationMapVector::const_iterator i = amv.begin();
i != amv.end();
i++
)
{
osgWidget::Label* label = new osgWidget::Label(*i);
label->setCanFill(true);
label->setFont("fonts/Vera.ttf");
label->setFontSize(15);
label->setFontColor(1.0f, 1.0f, 1.0f, 0.3f);
label->setPadding(5.0f);
label->setAlignHorizontal(osgWidget::Widget::HA_RIGHT);
label->setLabel(*i);
label->setEventMask(osgWidget::EVENT_MASK_MOUSE_DRAG);
label->addCallback(new osgWidget::Callback(&AnimtkViewerGUI::_listMouseHover, this, osgWidget::EVENT_MOUSE_ENTER));
label->addCallback(new osgWidget::Callback(&AnimtkViewerGUI::_listMouseHover, this, osgWidget::EVENT_MOUSE_LEAVE));
label->addCallback(new osgWidget::Callback(&AnimtkViewerGUI::_listMouseHover, this, osgWidget::EVENT_MOUSE_PUSH));
_listBox->addWidget(label);
}
ListFunctor* lf = new ListFunctor();
_listBox->setUpdateCallback(lf);
_listBox->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.7f);
}
void AnimtkViewerGUI::_createLabelBox()
{
_labelBox = new osgWidget::Box("labelBox", osgWidget::Box::VERTICAL);
osgWidget::Label* label = new osgWidget::Label("label");
label->setFont("fonts/Vera.ttf");
label->setFontSize(50);
label->setFontColor(0.0f, 0.0f, 0.0f, 0.7f);
label->setAlignHorizontal(osgWidget::Widget::HA_LEFT);
label->setPadding(10.0f);
LabelFunctor* lf = new LabelFunctor();
label->setUpdateCallback(lf);
_labelBox->addWidget(label);
_labelBox->getBackground()->setColor(0.0f, 0.0f, 0.0f, 0.0f);
}

View File

@@ -0,0 +1,53 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors:
*
* Cedric Pinson <mornifle@plopbyte.net>
*
*/
#ifndef ANIMTKVIEWER_KEYHANDLER_H
#define ANIMTKVIEWER_KEYHANDLER_H
#include "AnimtkViewer"
#include <osgGA/GUIEventHandler>
class AnimtkKeyEventHandler : public osgGA::GUIEventHandler
{
public:
AnimtkKeyEventHandler();
bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa,
osg::Object*, osg::NodeVisitor*);
void printUsage() const;
protected:
enum Binding
{
List,
Help,
Play,
Next,
Prev,
};
std::map<Binding, int> _actionKeys;
};
#endif

View File

@@ -0,0 +1,63 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors:
*
* Cedric Pinson <mornifle@plopbyte.net>
*
*/
#include "AnimtkViewerKeyHandler"
AnimtkKeyEventHandler::AnimtkKeyEventHandler()
{
_actionKeys[List] = 'l';
_actionKeys[Help] = 'h';
_actionKeys[Play] = 'p';
_actionKeys[Next] = ']';
_actionKeys[Prev] = '[';
}
void AnimtkKeyEventHandler::printUsage() const
{
std::cout << (char) _actionKeys.find(Help)->second << " for Help" << std::endl;
std::cout << (char) _actionKeys.find(List)->second << " for List" << std::endl;
std::cout << (char) _actionKeys.find(Play)->second << " for Play" << std::endl;
std::cout << (char) _actionKeys.find(Next)->second << " for selext Next item" << std::endl;
std::cout << (char) _actionKeys.find(Prev)->second << " for selext Previous item" << std::endl;
}
bool AnimtkKeyEventHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa,
osg::Object*, osg::NodeVisitor*)
{
AnimtkViewerModelController& mc = AnimtkViewerModelController::instance();
if(ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN)
{
if (ea.getKey() == _actionKeys[List]) return mc.list();
else if (ea.getKey() == _actionKeys[Play]) return mc.play();
else if (ea.getKey() == _actionKeys[Next]) return mc.next();
else if (ea.getKey() == _actionKeys[Prev]) return mc.previous();
else if (ea.getKey() == _actionKeys[Help])
{
printUsage();
return true;
}
}
return false;
}

View File

@@ -0,0 +1,7 @@
SET(TARGET_SRC
AnimtkViewer.cpp
AnimtkViewerKeyHandler.cpp
AnimtkViewerGUI.cpp
)
SET(TARGET_ADDED_LIBRARIES osgAnimation osgWidget)
SETUP_EXAMPLE(osganimationviewer)