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)

View File

@@ -0,0 +1,103 @@
/* -*-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.
*/
#ifndef OSGANIMATION_ANIMATION_H
#define OSGANIMATION_ANIMATION_H
#include <osg/Object>
#include <osgAnimation/Export>
#include <osgAnimation/Channel>
#include <osg/ref_ptr>
#include <vector>
#include <map>
namespace osgAnimation
{
class OSGANIMATION_EXPORT Animation : public virtual osg::Object
{
public:
META_Object(osgAnimation, Animation)
Animation() : _duration(0), _weight(0), _startTime(0), _playmode(LOOP) {}
Animation(const osgAnimation::Animation& anim, const osg::CopyOp&);
enum PlayMode
{
ONCE,
STAY,
LOOP,
PPONG
};
// addChannel insert the channel and call the computeDuration function
void addChannel (Channel* pChannel);
/** Those accessors let you add and remove channels
* if you modify something that can change the duration
* you are supposed to call computeDuration or setDuration
*/
ChannelList& getChannels();
const ChannelList& getChannels() const;
/** Change the duration of animation
* then evaluate the animation in the range 0-duration
* it stretch the animation in time.
* see computeDuration too
*/
void setDuration(double duration);
/** Compute duration from channel and keyframes
* if the duration is not specified you should
* call this method before using it
*/
void computeDuration();
float getDuration() const;
void setWeight (float weight);
float getWeight() const;
bool update (float time);
void resetTargets();
void setPlaymode (PlayMode mode) { _playmode = mode; }
void setStartTime(float time) { _startTime = time;}
float getStartTime() const { return _startTime;}
protected:
double computeDurationFromChannels() const;
~Animation() {}
std::string _name;
double _duration;
double _originalDuration;
float _weight;
float _startTime;
PlayMode _playmode;
ChannelList _channels;
};
typedef std::vector<osg::ref_ptr<osgAnimation::Animation> > AnimationList;
typedef std::map<std::string, osg::ref_ptr<osgAnimation::Animation> > AnimationMap;
}
#endif

View File

@@ -0,0 +1,58 @@
/* -*-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.
*/
#ifndef OSGANIMATION_ANIMATION_MANAGER_H
#define OSGANIMATION_ANIMATION_MANAGER_H
#include <osg/Group>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/Export>
#include <osg/FrameStamp>
namespace osgAnimation
{
class OSGANIMATION_EXPORT AnimationManager : public AnimationManagerBase
{
public:
META_Node(osgAnimation, AnimationManager);
AnimationManager();
AnimationManager(const AnimationManager& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) :
AnimationManagerBase(b,copyop) {}
virtual ~AnimationManager();
void update (double time);
void playAnimation (Animation* pAnimation, int priority = 0, float weight = 1.0);
bool stopAnimation (Animation* pAnimation);
bool findAnimation (Animation* pAnimation);
bool isPlaying (Animation* pAnimation);
bool isPlaying (const std::string& animationName);
void stopAll();
protected:
typedef std::map<int, AnimationList > AnimationLayers;
AnimationLayers _animationsPlaying;
// clock
double _lastUpdate;
};
}
#endif

View File

@@ -0,0 +1,98 @@
/* -*-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.
*/
#ifndef OSGANIMATION_ANIMATIONMANAGERBASE_H
#define OSGANIMATION_ANIMATIONMANAGERBASE_H
#include <osgAnimation/Animation>
#include <osgAnimation/Export>
#include <osg/FrameStamp>
#include <osg/Group>
namespace osgAnimation
{
class OSGANIMATION_EXPORT AnimationManagerBase : public osg::Group
{
public:
typedef std::set<osg::ref_ptr<Target> > TargetSet;
struct UpdateCallback : public osg::NodeCallback
{
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
AnimationManagerBase* b = dynamic_cast<AnimationManagerBase*>(node);
if (b)
{
if (b->needToLink())
{
/** manager need to link, it means that an animation has been added
so we need to relink all item animated with all animations.
We apply the linker visitor on the manager node to affect
all its children.
But it should not be done here, it should be done in the
update of AnimationManager
*/
b->link();
}
const osg::FrameStamp* fs = nv->getFrameStamp();
b->update(fs->getSimulationTime());
}
}
traverse(node,nv);
}
};
AnimationManagerBase();
AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) :
osg::Group(b,copyop)
{
_animations = b._animations;
_targets = b._targets;
_needToLink = b._needToLink;
}
virtual ~AnimationManagerBase();
virtual void update (double time) = 0;
virtual void buildTargetReference();
virtual void registerAnimation (Animation* animation);
virtual void link();
virtual bool needToLink() const;
const AnimationList& getAnimationList() const { return _animations;}
AnimationMap getAnimationMap() const;
void clearTargets()
{
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->reset();
}
void normalizeTargets()
{
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->normalize();
}
protected:
AnimationList _animations;
TargetSet _targets;
bool _needToLink;
};
}
#endif

View File

@@ -0,0 +1,49 @@
/* -*-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.
*/
#ifndef OSGANIMATION_ASSERT_H
#define OSGANIMATION_ASSERT_H
#include <string>
#include <sstream>
#include <exception>
namespace osgAnimation
{
struct ThrowAssert : public std::exception
{
virtual const char* what() const throw () { return mMsg.c_str();}
std::string mMsg;
ThrowAssert(const std::string& msg, const char* file, int line )
{
std::stringstream ss;
ss << "Assert (" << msg << ") in file " << file << " at line " << line;
mMsg = ss.str();
}
ThrowAssert() {}
virtual ~ThrowAssert() throw () {}
};
}
#ifdef OSGANIMATION_ASSERT_THROW
#define OSGANIMATION_ASSERT(a) if (!(a)) throw osgAnimation::ThrowAssert(std::string(#a),__FILE__,__LINE__);
#else
#define OSGANIMATION_ASSERT(a) {if (!(a)) *((int*)0) = 0;}
#endif
#endif

300
include/osgAnimation/Bone Normal file
View File

@@ -0,0 +1,300 @@
/* -*-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.
*/
#ifndef OSGANIMATION_BONE_H
#define OSGANIMATION_BONE_H
#include <osg/Transform>
#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Node>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Notify>
#include <osg/io_utils>
#include <osgAnimation/Export>
#include <osgAnimation/Target>
#include <osgAnimation/Sampler>
#include <osgAnimation/Channel>
#include <osgAnimation/Keyframe>
#include <osgAnimation/UpdateCallback>
#include <osgAnimation/Animation>
#include <osgAnimation/AnimationManager>
#include <osgAnimation/VertexInfluence>
namespace osgAnimation
{
inline osg::Matrix operator* (const osg::Matrix matrix, double v)
{
osg::Matrix result;
for (int i = 0; i < 16; i++)
result.ptr()[i] = matrix.ptr()[i] * v;
return result;
}
inline osg::Matrix operator+ (const osg::Matrix a, const osg::Matrix b)
{
osg::Matrix result;
for (int i = 0; i < 16; i++)
result.ptr()[i] = a.ptr()[i] + b.ptr()[i];
return result;
}
}
namespace osgAnimation
{
// A bone can't have more than one parent Bone, so sharing a part of Bone's hierarchy
// has not sense. You can share the entire hierarchie but not only a part of
class OSGANIMATION_EXPORT Bone : public osg::Transform
{
public:
typedef osg::ref_ptr<Bone> PointerType;
typedef std::map<std::string, PointerType > BoneMap;
typedef osg::Matrix MatrixType;
META_Node(osgAnimation, Bone);
Bone(const Bone& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) :
osg::Transform(b,copyop),
_position(b._position),
_rotation(b._rotation),
_scale(b._scale) {}
Bone(const std::string& name = "")
{
setName(name);
_needToRecomputeBindMatrix = false;
setUpdateCallback(new UpdateBone);
}
struct BoneMapVisitor : public osg::NodeVisitor
{
BoneMap _map;
BoneMapVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void apply(osg::Node& node) { return; }
void apply(osg::Transform& node)
{
Bone* bone = dynamic_cast<Bone*>(&node);
if (bone)
{
_map[bone->getName()] = bone;
traverse(node);
}
}
};
struct FindNearestParentAnimationManager : public osg::NodeVisitor
{
osg::ref_ptr<osgAnimation::AnimationManagerBase> _manager;
FindNearestParentAnimationManager() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {}
void apply(osg::Group& node)
{
if (_manager.valid())
return;
_manager = dynamic_cast<osgAnimation::AnimationManagerBase*>(&node);
traverse(node);
}
};
class OSGANIMATION_EXPORT UpdateBone : public AnimationUpdateCallback
{
public:
osg::ref_ptr<osgAnimation::Vec3Target> _position;
osg::ref_ptr<osgAnimation::QuatTarget> _quaternion;
osg::ref_ptr<osgAnimation::Vec3Target> _scale;
public:
META_Object(osgAnimation, UpdateBone);
UpdateBone(const UpdateBone& apc,const osg::CopyOp& copyop);
UpdateBone(const std::string& name = "")
{
setName(name);
_quaternion = new osgAnimation::QuatTarget;
_position = new osgAnimation::Vec3Target;
_scale = new osgAnimation::Vec3Target;
}
void update(osgAnimation::Bone& bone)
{
bone.setTranslation(_position->getValue());
bone.setRotation(_quaternion->getValue());
bone.setScale(_scale->getValue());
bone.dirtyBound();
}
bool needLink() const
{
// the idea is to return true if nothing is linked
return !((_position->getCount() + _quaternion->getCount() + _scale->getCount()) > 3);
}
bool link(osgAnimation::Channel* channel)
{
if (channel->getName().find("quaternion") != std::string::npos)
{
osgAnimation::QuatSphericalLinearChannel* qc = dynamic_cast<osgAnimation::QuatSphericalLinearChannel*>(channel);
if (qc)
{
qc->setTarget(_quaternion.get());
return true;
}
}
else if (channel->getName().find("position") != std::string::npos)
{
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
if (vc)
{
vc->setTarget(_position.get());
return true;
}
}
else if (channel->getName().find("scale") != std::string::npos)
{
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
if (vc)
{
vc->setTarget(_scale.get());
return true;
}
}
else
{
std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
}
return false;
}
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
Bone* b = dynamic_cast<Bone*>(node);
if (b && !_manager.valid())
{
FindNearestParentAnimationManager finder;
if (b->getParents().size() > 1)
{
osg::notify(osg::WARN) << "A Bone should not have multi parent ( " << b->getName() << " ) has parents ";
osg::notify(osg::WARN) << "( " << b->getParents()[0]->getName();
for (int i = 1; i < (int)b->getParents().size(); i++)
osg::notify(osg::WARN) << ", " << b->getParents()[i]->getName();
osg::notify(osg::WARN) << ")" << std::endl;
return;
}
b->getParents()[0]->accept(finder);
if (!finder._manager.valid())
{
osg::notify(osg::WARN) << "Warning can't update Bone, path to parent AnimationManagerBase not found" << std::endl;
return;
}
_manager = finder._manager.get();
}
updateLink();
update(*b);
}
traverse(node,nv);
}
};
osg::Vec3 _position;
osg::Quat _rotation;
osg::Vec3 _scale;
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const;
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const;
// flag to recompute bind pose
bool _needToRecomputeBindMatrix;
// bind data
osg::Matrix _bindInBoneSpace;
osg::Matrix _invBindInSkeletonSpace;
// bone updated
osg::Matrix _boneInSkeletonSpace;
Bone* getBoneParent();
const Bone* getBoneParent() const;
void setTranslation(const osg::Vec3& trans) { _position = trans;}
void setRotation(const osg::Quat& quat) { _rotation = quat;}
void setScale(const osg::Vec3& scale) { _scale = scale;}
const osg::Vec3& getTranslation() const { return _position;}
const osg::Quat& getRotation() const { return _rotation;}
osg::Matrix getMatrixInBoneSpace() const { return (osg::Matrix(getRotation())) * osg::Matrix::translate(getTranslation()) * _bindInBoneSpace;}
const osg::Matrix& getBindMatrixInBoneSpace() const { return _bindInBoneSpace; }
const osg::Matrix& getMatrixInSkeletonSpace() const { return _boneInSkeletonSpace; }
const osg::Matrix& getInvBindMatrixInSkeletonSpace() const { return _invBindInSkeletonSpace;}
void setBindMatrixInBoneSpace(const osg::Matrix& matrix)
{
_bindInBoneSpace = matrix;
_needToRecomputeBindMatrix = true;
}
inline bool needToComputeBindMatrix() { return _needToRecomputeBindMatrix;}
virtual void computeBindMatrix();
bool needLink() const;
void setNeedToComputeBindMatrix(bool state) { _needToRecomputeBindMatrix = state; }
/** Add Node to Group.
* If node is not NULL and is not contained in Group then increment its
* reference count, add it to the child list and dirty the bounding
* sphere to force it to recompute on next getBound() and return true for success.
* Otherwise return false. Scene nodes can't be added as child nodes.
*/
virtual bool addChild( Node *child );
BoneMap getBoneMap();
};
inline bool Bone::computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const
{
if (_referenceFrame==RELATIVE_RF)
matrix.preMult(getMatrixInBoneSpace());
else
matrix = getMatrixInBoneSpace();
return true;
}
inline bool Bone::computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const
{
if (_referenceFrame==RELATIVE_RF)
matrix.postMult(osg::Matrix::inverse(getMatrixInBoneSpace()));
else
matrix = osg::Matrix::inverse(getMatrixInBoneSpace());
return true;
}
}
#endif

View File

@@ -0,0 +1,136 @@
/* -*-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.
*/
#ifndef OSGANIMATION_CHANNEL_H
#define OSGANIMATION_CHANNEL_H
#include <osgAnimation/Export>
#include <osgAnimation/Sampler>
#include <osgAnimation/Target>
#include <osgAnimation/Assert>
#include <osg/Referenced>
#include <string>
namespace osgAnimation
{
class OSGANIMATION_EXPORT Channel : public osg::Referenced
{
public:
Channel();
virtual ~Channel();
virtual void update(float time) = 0;
virtual void reset() = 0;
virtual Target* getTarget() = 0;
const std::string& getName() const;
void setName(const std::string& name);
virtual float getStartTime() const = 0;
virtual float getEndTime() const = 0;
const std::string& getTargetName() const;
void setTargetName(const std::string& name);
float getWeight() const;
void setWeight(float w);
virtual Sampler* getSampler() = 0;
virtual const Sampler* getSampler() const = 0;
protected:
std::string _targetName;
std::string _name;
float _weight;
};
template <typename SamplerType>
class TemplateChannel : public Channel
{
public:
typedef typename SamplerType::UsingType UsingType;
typedef TemplateTarget<UsingType> TargetType;
typedef TemplateKeyframeContainer<typename SamplerType::KeyframeType> KeyframeContainerType;
TemplateChannel (SamplerType* s = 0,TargetType* target = 0)
{
if (target)
_target = target;
else
_target = new TargetType;
_sampler = s;
}
virtual ~TemplateChannel() {}
virtual void update(float time)
{
// skip if weight == 0
if (_weight < 1e-4)
return;
typename SamplerType::UsingType value;
_sampler->getValueAt(time, value);
_target->update(_weight, value);
}
virtual void reset() { _target->reset(); }
virtual Target* getTarget() { return _target.get();}
SamplerType* getOrCreateSampler()
{
if (!_sampler.valid())
_sampler = new SamplerType;
return _sampler.get();
}
Sampler* getSampler() { return _sampler.get(); }
const Sampler* getSampler() const { return _sampler.get(); }
SamplerType* getSamplerTyped() { return _sampler.get();}
const SamplerType* getSamplerTyped() const { return _sampler.get();}
void setSampler(SamplerType* sampler) { _sampler = sampler; }
TargetType* getTargetTyped() { return _target.get(); }
void setTarget(TargetType* target) { _target = target; }
virtual float getStartTime() const { OSGANIMATION_ASSERT(_sampler.valid() && "no sampler attached to channel"); return _sampler->getStartTime(); }
virtual float getEndTime() const { OSGANIMATION_ASSERT(_sampler.valid() && "no sampler attached to channel"); return _sampler->getEndTime(); }
protected:
osg::ref_ptr<TargetType> _target;
osg::ref_ptr<SamplerType> _sampler;
};
typedef std::vector<osg::ref_ptr<osgAnimation::Channel> > ChannelList;
typedef TemplateChannel<DoubleLinearSampler> DoubleLinearChannel;
typedef TemplateChannel<FloatLinearSampler> FloatLinearChannel;
typedef TemplateChannel<Vec2LinearSampler> Vec2LinearChannel;
typedef TemplateChannel<Vec3LinearSampler> Vec3LinearChannel;
typedef TemplateChannel<Vec4LinearSampler> Vec4LinearChannel;
typedef TemplateChannel<QuatSphericalLinearSampler> QuatSphericalLinearChannel;
typedef TemplateChannel<FloatCubicBezierSampler> FloatCubicBezierChannel;
typedef TemplateChannel<DoubleCubicBezierSampler> DoubleCubicBezierChannel;
typedef TemplateChannel<Vec2CubicBezierSampler> Vec2CubicBezierChannel;
typedef TemplateChannel<Vec3CubicBezierSampler> Vec3CubicBezierChannel;
typedef TemplateChannel<Vec4CubicBezierSampler> Vec4CubicBezierChannel;
}
#endif

View File

@@ -0,0 +1,56 @@
/* -*-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.
*/
#ifndef OSGANIMATION_CUBIC_BEZIER_H
#define OSGANIMATION_CUBIC_BEZIER_H
#include <osg/Vec2>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
namespace osgAnimation
{
template <class T>
struct TemplateCubicBezier
{
T mPoint[3];
const T& getP0() const { return mPoint[0];}
const T& getP1() const { return mPoint[1];}
const T& getP2() const { return mPoint[2];}
TemplateCubicBezier(const T& v0, const T& v1, const T& v2)
{
mPoint[0] = v0;
mPoint[1] = v1;
mPoint[2] = v2;
}
TemplateCubicBezier() {}
const T& getPosition() const { return mPoint[0];}
const T& getTangentPoint1() const { return mPoint[1];}
const T& getTangentPoint2() const { return mPoint[2];}
};
typedef TemplateCubicBezier<float> FloatCubicBezier;
typedef TemplateCubicBezier<double> DoubleCubicBezier;
typedef TemplateCubicBezier<osg::Vec2> Vec2CubicBezier;
typedef TemplateCubicBezier<osg::Vec3> Vec3CubicBezier;
typedef TemplateCubicBezier<osg::Vec4> Vec4CubicBezier;
}
#endif

View File

@@ -0,0 +1,238 @@
/* -*-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.
*/
#ifndef OSGANIMATION_EASE_MOTION_H
#define OSGANIMATION_EASE_MOTION_H
namespace osgAnimation {
struct LinearFunction
{
inline static void getValueAt(float t, float& result) { result = t;}
};
struct OutBounceFunction
{
inline static void getValueAt(float t, float& result)
{
if ((t) < (1/2.75))
{
result = 7.5625 * t * t;
}
else if (t < (2/2.75))
{
t = t - (1.5/2.75);
result = 7.5625* t * t + .75;
}
else if (t < (2.5/2.75))
{
t = t - (2.25/2.75);
result = 7.5625 * t * t + .9375;
}
else
{
t = t - (2.625/2.75);
result = 7.5625* t * t + .984375;
}
}
};
struct InBounceFunction
{
inline static void getValueAt(float t, float& result)
{
OutBounceFunction::getValueAt(1-t, result);
result = 1 - result;
}
};
struct InOutBounceFunction
{
inline static void getValueAt(float t, float& result)
{
if (t < 0.5)
{
InBounceFunction::getValueAt(t * 2, result);
result *= 0.5;
}
else
{
OutBounceFunction::getValueAt(t * 2 - 1 , result);
result = result * 0.5 + 0.5;
}
}
};
struct OutQuadFunction
{
inline static void getValueAt(float t, float& result) { result = - (t * (t -2.0));}
};
struct InQuadFunction
{
inline static void getValueAt(float t, float& result) { result = t*t;}
};
struct InOutQuadFunction
{
inline static void getValueAt(float t, float& result)
{
t = t * 2.0;
if (t < 1.0)
result = 0.5 * t * t;
else
{
t = t - 1.0;
result = - 0.5 * t * ( t - 2) - 1;
}
}
};
struct OutCubicFunction
{
inline static void getValueAt(float t, float& result) { t = t-1.0; result = t*t*t + 1;}
};
struct InCubicFunction
{
inline static void getValueAt(float t, float& result) { result = t*t*t;}
};
struct InOutCubicFunction
{
inline static void getValueAt(float t, float& result)
{
t = t * 2;
if (t < 1.0)
result = 0.5 * t * t * t;
else {
t = t - 2;
result = 0.5 * t * t * t + 2;
}
}
};
class Motion
{
public:
typedef float value_type;
enum TimeBehaviour
{
CLAMP,
LOOP,
};
Motion(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : _time(0), _b(startValue), _c(changeValue), _d(duration), _behaviour(tb) {}
virtual ~Motion() {}
void reset() { setTime(0);}
float getTime() const { return _time; }
void update(float dt)
{
_time += dt;
switch (_behaviour)
{
case CLAMP:
if (_time > _d)
_time = _d;
else if (_time < 0.0)
_time = 0.0;
break;
case LOOP:
_time = fmodf(_time, _d);
break;
}
}
void setTime(float time) { _time = time; update(0);}
void getValue(value_type& result) const { getValueAt(_time, result); }
value_type getValue() const
{
value_type result;
getValueAt(_time, result);
return result;
}
void getValueAt(float time, value_type& result) const
{
getValueInNormalizedRange(time/_d, result);
result = result * _c + _b;
}
value_type getValueAt(float time) const
{
value_type result;
getValueAt(time, result);
return result;
}
virtual void getValueInNormalizedRange(float t, value_type& result) const = 0;
protected:
float _time;
float _b;
float _c;
float _d;
TimeBehaviour _behaviour;
};
template <typename T>
struct MathMotionTemplate : public Motion
{
MathMotionTemplate(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : Motion(startValue, duration, changeValue, tb) {}
virtual void getValueInNormalizedRange(float t, value_type& result) const { T::getValueAt(t, result); }
};
template <class T>
struct SamplerMotionTemplate : public Motion
{
T _sampler;
SamplerMotionTemplate(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : Motion(startValue, duration, changeValue, tb) {}
T& getSampler() { return _sampler;}
const T& getSampler() const { return _sampler;}
virtual void getValueInNormalizedRange(float t, value_type& result) const
{
if (!_sampler.getKeyframeContainer())
{
result = 0;
return;
}
float size = _sampler.getEndTime() - _sampler.getStartTime();
t = t * size + _sampler.getStartTime();
_sampler.getValueAt(t, result);
}
};
// linear
typedef MathMotionTemplate<LinearFunction > LinearMotion;
// cubic
typedef MathMotionTemplate<OutCubicFunction > OutCubicMotion;
typedef MathMotionTemplate<InCubicFunction> InCubicMotion;
typedef MathMotionTemplate<InOutCubicFunction> InOutCubicMotion;
// quad
typedef MathMotionTemplate<OutQuadFunction > OutQuadMotion;
typedef MathMotionTemplate<InQuadFunction> InQuadMotion;
typedef MathMotionTemplate<InOutQuadFunction> InOutQuadMotion;
// bounce
typedef MathMotionTemplate<OutBounceFunction > OutBounceMotion;
typedef MathMotionTemplate<InBounceFunction> InBounceMotion;
typedef MathMotionTemplate<InOutBounceFunction> InOutBounceMotion;
}
#endif

View File

@@ -0,0 +1,65 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* 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.
*/
// The following symbol has a underscore suffix for compatibility.
#ifndef OSGANIMATION_EXPORT_
#define OSGANIMATION_EXPORT_ 1
#if defined(_MSC_VER)
#pragma warning( disable : 4244 )
#pragma warning( disable : 4251 )
#pragma warning( disable : 4267 )
#pragma warning( disable : 4275 )
#pragma warning( disable : 4290 )
#pragma warning( disable : 4786 )
#pragma warning( disable : 4305 )
#pragma warning( disable : 4996 )
#endif
#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined( __BCPLUSPLUS__) || defined( __MWERKS__)
# if defined( OSG_LIBRARY_STATIC )
# define OSGANIMATION_EXPORT
# elif defined( OSGANIMATION_LIBRARY )
# define OSGANIMATION_EXPORT __declspec(dllexport)
# else
# define OSGANIMATION_EXPORT __declspec(dllimport)
#endif
#else
#define OSGANIMATION_EXPORT
#endif
// set up define for whether member templates are supported by VisualStudio compilers.
#ifdef _MSC_VER
# if (_MSC_VER >= 1300)
# define __STL_MEMBER_TEMPLATES
# endif
#endif
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
/**
\namespace osgAnimation
The osgAnimation library provides general purpose utility classes for animation.
*/
#endif

View File

@@ -0,0 +1,206 @@
/* -*-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.
*/
#ifndef OSGANIMATION_INTERPOLATOR_H
#define OSGANIMATION_INTERPOLATOR_H
#include <osgAnimation/Assert>
#include <osgAnimation/Interpolator>
#include <osgAnimation/Keyframe>
namespace osgAnimation
{
template <class TYPE, class KEY>
class TemplateInterpolatorBase
{
public:
typedef KEY KeyframeType;
typedef TYPE UsingType;
public:
mutable int _lastKeyAccess;
TemplateInterpolatorBase() : _lastKeyAccess(-1) {}
void reset() { _lastKeyAccess = -1; }
int getKeyIndexFromTime(const TemplateKeyframeContainer<KEY>& keys, float time) const
{
OSGANIMATION_ASSERT(!keys.empty() && "no keys");
OSGANIMATION_ASSERT(time >= keys.front().getTime() && time <= keys.back().getTime() && "bad range");
// todo use a cache
int key_size = keys.size();
const TemplateKeyframe<KeyframeType>* keysVector = &keys.front();
for (int i = 0; i < key_size-1; i++)
{
float time0 = keysVector[i].getTime();
float time1 = keysVector[i+1].getTime();
#ifndef OSGANIMATION_NO_EXTRA_CHECK
if ( time0>time1 )
OSGANIMATION_ASSERT(0 && "invalid input data");
#endif
if ( time >= time0 && time < time1 )
{
_lastKeyAccess = i;
return i;
}
}
std::cout << time << " first key " << keysVector[0].getTime() << " last key " << keysVector[key_size-1].getTime() << std::endl;
*((int *)0) = 0;
OSGANIMATION_ASSERT(0 && "impossible has happened");
return -1;
}
};
template <class TYPE, class KEY=TYPE>
class TemplateLinearInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
public:
TemplateLinearInterpolator() {}
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, float time, TYPE& result) const
{
if (time >= keyframes.back().getTime())
{
result = keyframes.back().getValue();
return;
}
else if (time <= keyframes.front().getTime())
{
result = keyframes.front().getValue();
return;
}
int i = getKeyIndexFromTime(keyframes,time);
float blend = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
const TYPE& v1 = keyframes[i].getValue();
const TYPE& v2 = keyframes[i+1].getValue();
result = v1*(1-blend) + v2*blend;
}
};
template <class TYPE, class KEY=TYPE>
class TemplateSphericalLinearInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
public:
TemplateSphericalLinearInterpolator() {}
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, float time, TYPE& result) const
{
if (time >= keyframes.back().getTime())
{
result = keyframes.back().getValue();
return;
}
else if (time <= keyframes.front().getTime())
{
result = keyframes.front().getValue();
return;
}
int i = getKeyIndexFromTime(keyframes,time);
float blend = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
const TYPE& q1 = keyframes[i].getValue();
const TYPE& q2 = keyframes[i+1].getValue();
result.slerp(blend,q1,q2);
}
};
template <class TYPE, class KEY>
class TemplateLinearPackedInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
public:
TemplateLinearPackedInterpolator() {}
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, float time, TYPE& result) const
{
if (time >= keyframes.back().getTime())
{
keyframes.back().getValue().uncompress(keyframes.mScale, keyframes.mMin, result);
return;
}
else if (time <= keyframes.front().getTime())
{
keyframes.front().getValue().uncompress(keyframes.mScale, keyframes.mMin, result);
return;
}
int i = getKeyIndexFromTime(keyframes,time);
float blend = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
TYPE v1,v2;
keyframes[i].getValue().uncompress(keyframes.mScale, keyframes.mMin, v1);
keyframes[i+1].getValue().uncompress(keyframes.mScale, keyframes.mMin, v2);
result = v1*(1-blend) + v2*blend;
}
};
// http://en.wikipedia.org/wiki/B%C3%A9zier_curve
template <class TYPE, class KEY=TYPE>
class TemplateCubicBezierInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
public:
TemplateCubicBezierInterpolator() {}
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, float time, TYPE& result) const
{
if (time >= keyframes.back().getTime())
{
result = keyframes.back().getValue().getPosition();
return;
}
else if (time <= keyframes.front().getTime())
{
result = keyframes.front().getValue().getPosition();
return;
}
int i = getKeyIndexFromTime(keyframes,time);
float t = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
float one_minus_t = 1.0-t;
float one_minus_t2 = one_minus_t * one_minus_t;
float one_minus_t3 = one_minus_t2 * one_minus_t;
float t2 = t * t;
TYPE v0 = keyframes[i].getValue().getPosition() * one_minus_t3;
TYPE v1 = keyframes[i].getValue().getTangentPoint1() * (3.0 * t * one_minus_t2);
TYPE v2 = keyframes[i].getValue().getTangentPoint2() * (3.0 * t2 * one_minus_t);
TYPE v3 = keyframes[i+1].getValue().getPosition() * (t2 * t);
result = v0 + v1 + v2 + v3;
}
};
typedef TemplateLinearInterpolator<double, double> DoubleLinearInterpolator;
typedef TemplateLinearInterpolator<float, float> FloatLinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec2, osg::Vec2> Vec2LinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec3, osg::Vec3> Vec3LinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec3, Vec3Packed> Vec3PackedLinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec4, osg::Vec4> Vec4LinearInterpolator;
typedef TemplateSphericalLinearInterpolator<osg::Quat, osg::Quat> QuatSphericalLinearInterpolator;
typedef TemplateCubicBezierInterpolator<float, FloatCubicBezier > FloatCubicBezierInterpolator;
typedef TemplateCubicBezierInterpolator<double, DoubleCubicBezier> DoubleCubicBezierInterpolator;
typedef TemplateCubicBezierInterpolator<osg::Vec2, Vec2CubicBezier> Vec2CubicBezierInterpolator;
typedef TemplateCubicBezierInterpolator<osg::Vec3, Vec3CubicBezier> Vec3CubicBezierInterpolator;
typedef TemplateCubicBezierInterpolator<osg::Vec4, Vec4CubicBezier> Vec4CubicBezierInterpolator;
}
#endif

View File

@@ -0,0 +1,130 @@
/* -*-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.
*/
#ifndef OSGANIMATION_KEYFRAME_H
#define OSGANIMATION_KEYFRAME_H
#include <string>
#include <osg/Referenced>
#include <osgAnimation/Vec3Packed>
#include <osgAnimation/CubicBezier>
#include <osg/Quat>
#include <osg/Vec4>
#include <osg/Vec3>
#include <osg/Vec2>
namespace osgAnimation
{
class Keyframe
{
public:
float getTime() const { return _time; }
void setTime(float time) { _time = time; }
protected:
float _time;
};
template <class T>
class TemplateKeyframe : public Keyframe
{
protected:
T _value;
public:
TemplateKeyframe () {}
~TemplateKeyframe () {}
TemplateKeyframe (float time, const T& value)
{
_time = time;
_value = value;
}
void setValue(const T& value) { _value = value;}
const T& getValue() const { return _value;}
};
class KeyframeContainer : public osg::Referenced
{
public:
KeyframeContainer() {}
virtual unsigned int size() const = 0;
protected:
~KeyframeContainer() {}
std::string _name;
};
template <class T>
class TemplateKeyframeContainer : public std::vector<TemplateKeyframe<T> >, public KeyframeContainer
{
public:
// const char* getKeyframeType() { return #T ;}
TemplateKeyframeContainer() {}
typedef TemplateKeyframe<T> KeyType;
virtual unsigned int size() const { return (unsigned int)std::vector<TemplateKeyframe<T> >::size(); }
};
template <>
class TemplateKeyframeContainer<Vec3Packed> : public std::vector<TemplateKeyframe<Vec3Packed> >, public KeyframeContainer
{
public:
typedef TemplateKeyframe<Vec3Packed> KeyType;
TemplateKeyframeContainer() {}
const char* getKeyframeType() { return "Vec3Packed" ;}
void init(const osg::Vec3f& min, const osg::Vec3f& scale) { _min = min; _scale = scale; }
osg::Vec3f _min;
osg::Vec3f _scale;
};
typedef TemplateKeyframe<float> FloatKeyframe;
typedef TemplateKeyframeContainer<float> FloatKeyframeContainer;
typedef TemplateKeyframe<osg::Vec2> Vec2Keyframe;
typedef TemplateKeyframeContainer<osg::Vec2> Vec2KeyframeContainer;
typedef TemplateKeyframe<osg::Vec3> Vec3Keyframe;
typedef TemplateKeyframeContainer<osg::Vec3> Vec3KeyframeContainer;
typedef TemplateKeyframe<osg::Vec4> Vec4Keyframe;
typedef TemplateKeyframeContainer<osg::Vec4> Vec4KeyframeContainer;
typedef TemplateKeyframe<osg::Quat> QuatKeyframe;
typedef TemplateKeyframeContainer<osg::Quat> QuatKeyframeContainer;
typedef TemplateKeyframe<Vec3Packed> Vec3PackedKeyframe;
typedef TemplateKeyframeContainer<Vec3Packed> Vec3PackedKeyframeContainer;
typedef TemplateKeyframe<FloatCubicBezier> FloatCubicBezierKeyframe;
typedef TemplateKeyframeContainer<FloatCubicBezier> FloatCubicBezierKeyframeContainer;
typedef TemplateKeyframe<DoubleCubicBezier> DoubleCubicBezierKeyframe;
typedef TemplateKeyframeContainer<DoubleCubicBezier> DoubleCubicBezierKeyframeContainer;
typedef TemplateKeyframe<Vec2CubicBezier> Vec2CubicBezierKeyframe;
typedef TemplateKeyframeContainer<Vec2CubicBezier> Vec2CubicBezierKeyframeContainer;
typedef TemplateKeyframe<Vec3CubicBezier> Vec3CubicBezierKeyframe;
typedef TemplateKeyframeContainer<Vec3CubicBezier> Vec3CubicBezierKeyframeContainer;
typedef TemplateKeyframe<Vec4CubicBezier> Vec4CubicBezierKeyframe;
typedef TemplateKeyframeContainer<Vec4CubicBezier> Vec4CubicBezierKeyframeContainer;
}
#endif

View File

@@ -0,0 +1,50 @@
/* -*-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.
*/
#ifndef OSGANIMATION_NODE_VISITOR_H
#define OSGANIMATION_NODE_VISITOR_H
#include <osg/NodeVisitor>
#include <osgAnimation/Animation>
#include <osgAnimation/UpdateCallback>
namespace osgAnimation
{
struct LinkVisitor : public osg::NodeVisitor
{
AnimationList _animations;
unsigned int _nbLinkedTarget;
LinkVisitor(Animation* animation) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _animations.push_back(animation); _nbLinkedTarget = 0;}
LinkVisitor(const AnimationList& animations) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _animations = animations; _nbLinkedTarget = 0;}
void apply(osg::Node& node)
{
osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(node.getUpdateCallback());
if (cb)
{
int result = 0;
for (int i = 0; i < (int)_animations.size(); i++)
{
result += cb->link(_animations[i].get());
_nbLinkedTarget += result;
}
std::cout << "LinkVisitor links " << result << " for \"" << cb->getName() << '"' << std::endl;
}
traverse(node);
}
};
}
#endif

View File

@@ -0,0 +1,159 @@
/* -*-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.
*/
#ifndef OSGANIMATION_RIGGEOMETRY_H
#define OSGANIMATION_RIGGEOMETRY_H
#include <osgAnimation/Export>
#include <osgAnimation/Skinning>
#include <osgAnimation/Skeleton>
#include <osg/Geometry>
namespace osgAnimation
{
class OSGANIMATION_EXPORT RigGeometry : public osg::Geometry
{
public:
struct FindNearestParentSkeleton : public osg::NodeVisitor
{
osg::ref_ptr<osgAnimation::Skeleton> _root;
FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {}
void apply(osg::Transform& node)
{
if (_root.valid())
return;
_root = dynamic_cast<osgAnimation::Skeleton*>(&node);
traverse(node);
}
};
struct UpdateVertex : public osg::Drawable::UpdateCallback
{
virtual void update(osg::NodeVisitor*, osg::Drawable* drw)
{
RigGeometry* geom = dynamic_cast<RigGeometry*>(drw);
if (!geom)
return;
if (!geom->getSkeleton() && !geom->getParents().empty())
{
FindNearestParentSkeleton finder;
if (geom->getParents().size() > 1)
osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << geom->getName() << " )" << std::endl;
geom->getParents()[0]->accept(finder);
if (!finder._root.valid())
return;
geom->buildVertexSet();
geom->buildTransformer(finder._root.get());
}
if (!geom->getSkeleton())
return;
if (geom->getNeedToComputeMatrix())
geom->computeMatrixFromRootSkeleton();
geom->transformSoftwareMethod();
}
};
/** BuildVertexTransformerVisitor is used to setup RigGeometry drawable
* throw a subgraph.
*/
struct BuildVertexTransformerVisitor : public osg::NodeVisitor
{
osg::ref_ptr<Skeleton> _root;
BuildVertexTransformerVisitor(Skeleton* root): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _root = root;}
void apply(osg::Geode& node)
{
int num = node.getNumDrawables();
for (int i = 0; i < num; i++) {
RigGeometry* geom = dynamic_cast<RigGeometry*>(node.getDrawable(i));
if (geom)
{
geom->buildVertexSet();
geom->buildTransformer(_root.get());
}
}
}
};
RigGeometry()
{
setUseDisplayList(false);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
_needToComputeMatrix = true;
_matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity();
}
RigGeometry(const osg::Geometry& b) : osg::Geometry(b, osg::CopyOp::SHALLOW_COPY)
{
setUseDisplayList(false);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
_needToComputeMatrix = true;
_matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity();
}
RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) :
osg::Geometry(b,copyop),
_positionSource(b._positionSource),
_normalSource(b._normalSource),
_vertexInfluenceSet(b._vertexInfluenceSet),
_vertexInfluenceMap(b._vertexInfluenceMap),
_transformVertexes(b._transformVertexes),
_needToComputeMatrix(b._needToComputeMatrix) {}
virtual osg::Object* cloneType() const { return new RigGeometry(); }
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new RigGeometry(*this,copyop); }
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const RigGeometry*>(obj)!=NULL; }
virtual const char* libraryName() const { return "osgAnimation"; }
virtual const char* className() const { return "RigGeometry"; }
void setInfluenceMap(osgAnimation::VertexInfluenceMap* vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; }
const osgAnimation::VertexInfluenceMap* getInfluenceMap() const { return _vertexInfluenceMap.get();}
osgAnimation::VertexInfluenceMap* getInfluenceMap() { return _vertexInfluenceMap.get();}
void buildVertexSet();
void buildTransformer(Skeleton* root);
void computeMatrixFromRootSkeleton();
void setNeedToComputeMatrix(bool state) { _needToComputeMatrix = state;}
bool getNeedToComputeMatrix() const { return _needToComputeMatrix;}
const Skeleton* getSkeleton() const;
Skeleton* getSkeleton();
virtual void transformSoftwareMethod();
const osgAnimation::VertexInfluenceSet& getVertexInfluenceSet() const { return _vertexInfluenceSet;}
std::vector<osg::Vec3> _positionSource;
std::vector<osg::Vec3> _normalSource;
osgAnimation::VertexInfluenceSet _vertexInfluenceSet;
osg::ref_ptr<osgAnimation::VertexInfluenceMap> _vertexInfluenceMap;
osgAnimation::TransformVertexFunctor _transformVertexes;
osg::Matrix _matrixFromSkeletonToGeometry;
osg::Matrix _invMatrixFromSkeletonToGeometry;
osg::observer_ptr<Skeleton> _root;
bool _needToComputeMatrix;
};
}
#endif

View File

@@ -0,0 +1,124 @@
/* -*-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.
*/
#ifndef OSGANIMATION_SAMPLER_H
#define OSGANIMATION_SAMPLER_H
#include <vector>
#include <iostream>
#include <osg/Referenced>
#include <osg/ref_ptr>
#include <osgAnimation/Keyframe>
#include <osgAnimation/Interpolator>
#include <osgAnimation/Assert>
namespace osgAnimation
{
class Sampler : public osg::Referenced
{
public:
virtual KeyframeContainer* getKeyframeContainer() = 0;
virtual const KeyframeContainer* getKeyframeContainer() const = 0;
protected:
};
// Sampler generic
template <class F>
class TemplateSampler : public Sampler
{
public:
typedef typename F::KeyframeType KeyframeType;
typedef TemplateKeyframeContainer<KeyframeType> KeyframeContainerType;
typedef typename F::UsingType UsingType;
typedef F FunctorType;
TemplateSampler() {}
~TemplateSampler() {}
void getValueAt(float time, UsingType& result) const { _functor.getValue(*_keyframes, time, result);}
void setKeyframeContainer(KeyframeContainerType* kf) { _keyframes = kf;}
virtual KeyframeContainer* getKeyframeContainer() { return _keyframes.get(); }
virtual const KeyframeContainer* getKeyframeContainer() const { return _keyframes.get();}
KeyframeContainerType* getKeyframeContainerTyped() { return _keyframes.get();}
const KeyframeContainerType* getKeyframeContainerTyped() const { return _keyframes.get();}
KeyframeContainerType* getOrCreateKeyframeContainer()
{
if (_keyframes != 0)
return _keyframes.get();
_keyframes = new KeyframeContainerType;
return _keyframes.get();
}
float getStartTime() const
{
OSGANIMATION_ASSERT(_keyframes.valid() && !_keyframes->empty() && "no keyframes");
return _keyframes->front().getTime();
}
float getEndTime() const
{
OSGANIMATION_ASSERT(_keyframes.valid() && !_keyframes->empty() && "no keyframes");
return _keyframes->back().getTime();
}
protected:
FunctorType _functor;
osg::ref_ptr<KeyframeContainerType> _keyframes;
};
template<typename VALUESAMPLERTYPE, typename TIMESAMPLERTYPE>
class TemplateCompositeSampler : public osg::Referenced
{
VALUESAMPLERTYPE& _value;
TIMESAMPLERTYPE& _time;
public:
typedef typename VALUESAMPLERTYPE::FunctorType::UsingType UsingType;
typedef typename VALUESAMPLERTYPE::FunctorType::KeyframeType KeyframeType;
TemplateCompositeSampler(VALUESAMPLERTYPE& value, TIMESAMPLERTYPE& time) : _value(value), _time(time)
{
}
void getValueAt(float time, typename VALUESAMPLERTYPE::FunctorType::UsingType& result)
{
float newtime;
_time.getValueAt(time, newtime);
_value.getValueAt(newtime, result);
}
float getStartTime() const {return _time.getStartTime(); }
float getEndTime() const {return _time.getEndTime();}
};
typedef TemplateSampler<DoubleLinearInterpolator> DoubleLinearSampler;
typedef TemplateSampler<FloatLinearInterpolator> FloatLinearSampler;
typedef TemplateSampler<Vec2LinearInterpolator> Vec2LinearSampler;
typedef TemplateSampler<Vec3LinearInterpolator> Vec3LinearSampler;
typedef TemplateSampler<Vec4LinearInterpolator> Vec4LinearSampler;
typedef TemplateSampler<QuatSphericalLinearInterpolator> QuatSphericalLinearSampler;
typedef TemplateSampler<FloatCubicBezierInterpolator> FloatCubicBezierSampler;
typedef TemplateSampler<DoubleCubicBezierInterpolator> DoubleCubicBezierSampler;
typedef TemplateSampler<Vec2CubicBezierInterpolator> Vec2CubicBezierSampler;
typedef TemplateSampler<Vec3CubicBezierInterpolator> Vec3CubicBezierSampler;
typedef TemplateSampler<Vec4CubicBezierInterpolator> Vec4CubicBezierSampler;
};
#endif

View File

@@ -0,0 +1,44 @@
/* -*-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.
*/
#ifndef OSGANIMATION_SKELETON_H
#define OSGANIMATION_SKELETON_H
#include <osg/MatrixTransform>
#include <osgAnimation/Bone>
#include <osgAnimation/Export>
namespace osgAnimation
{
class OSGANIMATION_EXPORT Skeleton : public Bone
{
public:
META_Node(osgAnimation, Skeleton);
struct UpdateCallback : public osg::NodeCallback
{
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
};
Skeleton(const Skeleton& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : Bone(b,copyop) {}
Skeleton();
void computeBindMatrix() { _invBindInSkeletonSpace = osg::Matrix::inverse(_bindInBoneSpace); }
};
}
#endif

View File

@@ -0,0 +1,167 @@
/* -*-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.
*/
#ifndef OSGANIMATION_SKINNING_H
#define OSGANIMATION_SKINNING_H
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <osgAnimation/Assert>
#include <osgAnimation/VertexInfluence>
#include <osgAnimation/Bone>
#include <osg/Matrix>
#include <osg/Vec3>
#include <osg/Quat>
namespace osgAnimation
{
class TransformVertexFunctor
{
public:
typedef osg::Matrix MatrixType;
typedef osgAnimation::Bone BoneType;
typedef Bone::BoneMap BoneMap;
class BoneWeight
{
public:
BoneWeight(BoneType* bone, float weight) : _bone(bone), _weight(weight) {}
const BoneType* getBone() const { return &(*_bone); }
float getWeight() const { return _weight; }
protected:
osg::ref_ptr<BoneType> _bone;
float _weight;
};
typedef std::vector<BoneWeight> BoneWeightList;
typedef std::vector<int> VertexList;
class UniqBoneSetVertexSet
{
public:
BoneWeightList& getBones() { return _bones; }
VertexList& getVertexes() { return _vertexes; }
void computeMatrixForVertexSet()
{
if (_bones.empty())
{
osg::notify(osg::WARN) << "TransformVertexFunctor::UniqBoneSetVertexSet no bones found" << std::endl;
_result = MatrixType::identity();
return;
}
_result = MatrixType(0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0);
int size = _bones.size();
for (int i = 0; i < size; i++)
{
const BoneType* bone = _bones[i].getBone();
const MatrixType& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace();
const MatrixType& matrix = bone->getMatrixInSkeletonSpace();
double w = _bones[i].getWeight();
_result = _result + ( (invBindMatrix * matrix ) * w);
}
}
const MatrixType& getMatrix() const { return _result;}
protected:
BoneWeightList _bones;
VertexList _vertexes;
MatrixType _result;
};
void init(const BoneMap& map, const osgAnimation::VertexInfluenceSet::UniqVertexSetToBoneSetList& influence)
{
_boneSetVertexSet.clear();
int size = influence.size();
_boneSetVertexSet.resize(size);
for (int i = 0; i < size; i++)
{
const osgAnimation::VertexInfluenceSet::UniqVertexSetToBoneSet& inf = influence[i];
int nbBones = inf.getBones().size();
for (int b = 0; b < nbBones; b++)
{
const std::string& bname = inf.getBones()[b].getBoneName();
float weight = inf.getBones()[b].getWeight();
if (map.find(bname) == map.end())
{
std::cerr << "Warning TransformVertexFunctor Bone " << bname << " not found, skip the influence group " <<bname << std::endl;
continue;
}
BoneMap::const_iterator it = map.find(bname);
if (it == map.end())
std::cerr << "Warning TransformVertexFunctor does not find bone " << bname << " in the map" << std::endl;
BoneType* bone = it->second.get();
_boneSetVertexSet[i].getBones().push_back(BoneWeight(bone, weight));
}
_boneSetVertexSet[i].getVertexes() = inf.getVertexes();
}
}
template <class V> void compute(const V* src, V* dst)
{
OSGANIMATION_ASSERT(src != dst);
int size = _boneSetVertexSet.size();
for (int i = 0; i < size; i++)
{
UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i];
uniq.computeMatrixForVertexSet();
const MatrixType& matrix = uniq.getMatrix();
const VertexList& vertexes = uniq.getVertexes();
int vertexSize = vertexes.size();
for (int j = 0; j < vertexSize; j++)
{
int idx = vertexes[j];
dst[idx] = src[idx] * matrix;
}
}
}
template <class V> void compute(const MatrixType& transform, const MatrixType& invTransform, const V* src, V* dst)
{
OSGANIMATION_ASSERT(src != dst);
int size = _boneSetVertexSet.size();
for (int i = 0; i < size; i++)
{
UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i];
uniq.computeMatrixForVertexSet();
MatrixType matrix = transform * uniq.getMatrix() * invTransform;
const VertexList& vertexes = uniq.getVertexes();
int vertexSize = vertexes.size();
for (int j = 0; j < vertexSize; j++)
{
int idx = vertexes[j];
dst[idx] = src[idx] * matrix;
}
}
}
protected:
std::vector<UniqBoneSetVertexSet> _boneSetVertexSet;
};
}
#endif

132
include/osgAnimation/Target Normal file
View File

@@ -0,0 +1,132 @@
/* -*-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.
*/
#ifndef OSGANIMATION_TARGET_H
#define OSGANIMATION_TARGET_H
#include <vector>
#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Vec2>
#include <osg/Vec4>
#include <osg/Referenced>
#include <osgAnimation/Export>
namespace osgAnimation
{
class Channel;
class OSGANIMATION_EXPORT Target : public osg::Referenced
{
public:
Target();
virtual ~Target();
virtual void normalize() = 0;
float getWeight() const { return _weight; }
void reset() { _weight = 0;}
int getCount() const { return referenceCount(); }
protected:
void addWeight(float w) { _weight += w; }
float _weight;
};
template <class T>
class TemplateTarget : public Target
{
public:
TemplateTarget() {}
TemplateTarget(const T& v) { setValue(v); }
void update(float weight, const T& val)
{
if (!_weight)
_target = val * weight;
else
{
weight = (1.0 - _weight) * weight;
_target += val * weight;
}
addWeight(weight);
}
const T& getValue() const { return _target;}
void normalize()
{
float weightSummed = getWeight();
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1) < 1e-4)
return;
(_target) /= weightSummed;
}
void setValue(const T& value) { _target = value;}
protected:
T _target;
};
// Target Specialisation for Quaternions
template <>
class TemplateTarget< osg::Quat > : public Target
{
public:
TemplateTarget () {}
const osg::Quat& getValue() const { return _target;}
void update(float weight, const osg::Quat& val)
{
if (!_weight)
_target = val * weight;
else
{
weight = (1.0 - _weight) * weight;
_target += val * weight;
}
addWeight(weight);
}
// maybe normalize could be non virtual and put on ITarget
void normalize()
{
float weightSummed = getWeight();
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1.0) < 1e-4)
return;
(_target) /= weightSummed;
}
void setValue(const osg::Quat& value) { _target = value;}
protected:
osg::Quat _target;
};
typedef TemplateTarget<osg::Quat> QuatTarget;
typedef TemplateTarget<osg::Vec3> Vec3Target;
typedef TemplateTarget<osg::Vec4> Vec4Target;
typedef TemplateTarget<osg::Vec2> Vec2Target;
typedef TemplateTarget<float> FloatTarget;
typedef TemplateTarget<double> DoubleTarget;
}
#endif

View File

@@ -0,0 +1,563 @@
/* -*-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.
*/
#ifndef OSGANIMATION_TIMELINE_H
#define OSGANIMATION_TIMELINE_H
#include <osg/Object>
#include <map>
#include <vector>
#include <cmath>
#include <osg/Notify>
#include <osg/Group>
#include <osgAnimation/Animation>
#include <osgAnimation/AnimationManagerBase>
namespace osgAnimation
{
class Action : public virtual osg::Object
{
public:
class Callback : public virtual osg::Object
{
public:
Callback(){}
Callback(const Callback& nc,const osg::CopyOp&) {}
META_Object(osgAnimation,Callback);
virtual void operator()(Action* action) {}
void addNestedCallback(Callback* callback)
{
if (_nested.valid())
_nested->addNestedCallback(callback);
else
_nested = callback;
}
protected:
osg::ref_ptr<Callback> _nested;
};
typedef std::map<unsigned int, osg::ref_ptr<Callback> > FrameCallback;
META_Object(osgAnimation, Action);
Action()
{
_numberFrame = 25;
_fps = 25;
_speed = 1.0;
_loop = 1;
}
Action(const Action& nc,const osg::CopyOp&) {}
void setCallback(double when, Callback* callback)
{
setCallback(static_cast<unsigned int>(floor(when*_fps)), callback);
}
void setCallback(unsigned int frame, Callback* callback)
{
if (_framesCallback[frame].valid())
_framesCallback[frame]->addNestedCallback(callback);
else
_framesCallback[frame] = callback;
}
Callback* getCallback(unsigned int frame)
{
if (_framesCallback.find(frame) == _framesCallback.end())
return 0;
return _framesCallback[frame].get();
}
void setNumFrames(unsigned int numFrames) { _numberFrame = numFrames;}
void setDuration(double duration) { _numberFrame = static_cast<unsigned int>(floor(duration * _fps)); }
unsigned int getNumFrames() const { return _numberFrame;}
double getDuration() const { return _numberFrame * 1.0 / _fps; }
// 0 means infini else it's the number of loop
virtual void setLoop(int nb) { _loop = nb; }
virtual unsigned int getLoop() const { return _loop;}
// get the number of loop, the frame relative to loop.
// return true if in range, and false if out of range.
bool evaluateFrame(unsigned int frame, unsigned int& resultframe, unsigned int& nbloop )
{
nbloop = frame / getNumFrames();
resultframe = frame;
if (frame > getNumFrames()-1)
{
if (!getLoop())
resultframe = frame % getNumFrames();
else
{
if (nbloop >= getLoop())
return false;
else
resultframe = frame % getNumFrames();
}
}
return true;
}
virtual void evaluate(unsigned int frame)
{
unsigned int frameInAction;
unsigned int loopDone;
if (!evaluateFrame(frame, frameInAction, loopDone))
osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " << frameInAction << " finished" << std::endl;
else
osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " << frame << " relative to loop " << frameInAction << " no loop " << loopDone<< std::endl;
}
virtual void evaluateCallback(unsigned int frame)
{
unsigned int frameInAction;
unsigned int loopDone;
if (!evaluateFrame(frame, frameInAction, loopDone))
return;
frame = frameInAction;
if (_framesCallback.find(frame) != _framesCallback.end())
{
std::cout << getName() << " evaluate callback " << _framesCallback[frame]->getName() << " at " << frame << std::endl;
(*_framesCallback[frame])(this);
}
}
protected:
FrameCallback _framesCallback;
double _speed;
unsigned int _fps;
unsigned int _numberFrame;
unsigned int _loop;
enum State
{
Play,
Stop,
};
State _state;
};
class Timeline : public virtual osg::Object
{
protected:
typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
typedef std::vector<FrameAction> ActionList;
typedef std::map<int, ActionList> ActionLayers;
ActionLayers _actions;
double _lastUpdate;
double _speed;
unsigned int _currentFrame;
unsigned int _fps;
unsigned int _numberFrame;
unsigned int _previousFrameEvaluated;
bool _loop;
bool _initFirstFrame;
enum State
{
Play,
Stop,
};
State _state;
// to manage pending operation
bool _evaluating;
struct Command
{
Command():_priority(0) {}
Command(int priority, const FrameAction& action) : _priority(priority), _action(action) {}
int _priority;
FrameAction _action;
};
typedef std::vector<Command> CommandList;
CommandList _addActionOperations;
ActionList _removeActionOperations;
void setEvaluating(bool state) { _evaluating = state;}
void processPendingOperation()
{
// process all pending add action operation
while( !_addActionOperations.empty())
{
internalAddAction(_addActionOperations.back()._priority, _addActionOperations.back()._action);
_addActionOperations.pop_back();
}
// process all pending remove action operation
while( !_removeActionOperations.empty())
{
internalRemoveAction(_removeActionOperations.back().second);
_removeActionOperations.pop_back();
}
}
void internalRemoveAction(Action* action)
{
for (ActionLayers::iterator it = _actions.begin(); it != _actions.end(); it++)
{
ActionList& fa = it->second;
for (unsigned int i = 0; i < fa.size(); i++)
if (fa[i].second.get() == action)
{
fa.erase(fa.begin() + i);
return;
}
}
}
void internalAddAction(int priority, const FrameAction& ftl)
{
_actions[priority].push_back(ftl);
}
public:
META_Object(osgAnimation, Timeline);
Timeline()
{
_lastUpdate = 0;
_currentFrame = 0;
_fps = 25;
_speed = 1.0;
_state = Stop;
_initFirstFrame = false;
_previousFrameEvaluated = 0;
_evaluating = 0;
_numberFrame = -1; // something like infinity
setName("Timeline");
}
Timeline(const Timeline& nc,const osg::CopyOp&) {}
State getStatus() const { return _state; }
const ActionList& getActionLayer(int i)
{
return _actions[i];
}
unsigned int getCurrentFrame() const { return _currentFrame;}
double getCurrentTime() const { return _currentFrame * 1.0 / _fps;}
void play() { _state = Play; }
void gotoFrame(unsigned int frame) { _currentFrame = frame; }
void stop() { _state = Stop; }
bool getEvaluating() const { return _evaluating;}
bool isActive(Action* activeAction)
{
// update from high priority to low priority
for( ActionLayers::iterator iterAnim = _actions.begin(); iterAnim != _actions.end(); ++iterAnim )
{
// update all animation
ActionList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
Action* action = list[i].second.get();
if (action == activeAction)
{
unsigned int firstFrame = list[i].first;
// check if current frame of timeline hit an action interval
if (_currentFrame >= firstFrame &&
_currentFrame < (firstFrame + action->getNumFrames()) )
return true;
}
}
}
return false;
}
void removeAction(Action* action)
{
if (getEvaluating())
_removeActionOperations.push_back(FrameAction(0, action));
else
internalRemoveAction(action);
}
virtual void addActionAt(unsigned int frame, Action* action, int priority = 0)
{
if (getEvaluating())
_addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
else
internalAddAction(priority, FrameAction(frame, action));
}
virtual void addActionAt(double t, Action* action, int priority = 0)
{
unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
addActionAt(frame, action, priority);
}
virtual void evaluate(unsigned int frame)
{
setEvaluating(true);
osg::notify(osg::DEBUG_INFO) << getName() << " evaluate frame " << _currentFrame << std::endl;
// update from high priority to low priority
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
{
// update all animation
ActionList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
unsigned int firstFrame = list[i].first;
Action* action = list[i].second.get();
// check if current frame of timeline hit an action interval
if (frame >= firstFrame &&
frame < (firstFrame + action->getNumFrames()) )
action->evaluate(frame - firstFrame);
}
}
setEvaluating(false);
// evaluate callback after updating all animation
evaluateCallback(frame);
_previousFrameEvaluated = frame;
}
virtual void evaluateCallback(unsigned int frame)
{
// update from high priority to low priority
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
{
// update all animation
ActionList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
unsigned int firstFrame = list[i].first;
Action* action = list[i].second.get();
// check if current frame of timeline hit an action interval
if (frame >= firstFrame &&
frame < (firstFrame + action->getNumFrames()) )
action->evaluateCallback(frame - firstFrame);
}
}
processPendingOperation();
}
virtual void update(double simulationTime)
{
// first time we call update we generate one frame
if (!_initFirstFrame)
{
_lastUpdate = simulationTime;
_initFirstFrame = true;
evaluate(_currentFrame);
}
// find the number of frame pass since the last update
double delta = (simulationTime - _lastUpdate);
double nbframes = delta * _fps * _speed;
unsigned int nb = static_cast<unsigned int>(floor(nbframes));
for (unsigned int i = 0; i < nb; i++)
{
if (_state == Play)
_currentFrame++;
evaluate(_currentFrame);
}
if (nb)
{
_lastUpdate += ((double)nb) / _fps;
}
}
};
// blend in from 0 to weight in duration
class BlendIn : public Action
{
double _weight;
osg::ref_ptr<Animation> _animation;
public:
BlendIn(Animation* animation, double duration, double weight)
{
_animation = animation;
_weight = weight;
float d = duration * _fps;
setNumFrames(static_cast<unsigned int>(floor(d)) + 1);
setName("BlendIn");
}
double getWeight() const { return _weight;}
virtual void evaluate(unsigned int frame)
{
Action::evaluate(frame);
// frame + 1 because the start is 0 and we want to start the blend in at the first
// frame.
double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
double w = _weight;
if (frame < getNumFrames() -1 ) // the last frame we set the target weight the user asked
w = _weight * ratio;
_animation->setWeight(w);
}
};
// blend in from 0 to weight in duration
class BlendOut : public Action
{
double _weight;
osg::ref_ptr<Animation> _animation;
public:
BlendOut(Animation* animation, double duration)
{
_animation = animation;
float d = duration * _fps;
setNumFrames(static_cast<unsigned int>(floor(d) + 1));
_weight = 1.0;
setName("BlendOut");
}
double getWeight() const { return _weight;}
virtual void evaluate(unsigned int frame)
{
Action::evaluate(frame);
// frame + 1 because the start is 0 and we want to start the blend in at the first
// frame.
double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
double w = 0.0;
if (frame < getNumFrames() -1 ) // the last frame we set the target weight the user asked
w = _weight * (1.0-ratio);
_animation->setWeight(w);
}
};
class ActionAnimation : public Action
{
public:
ActionAnimation(Animation* animation) : _animation(animation)
{
setDuration(animation->getDuration());
setName(animation->getName());
}
virtual void evaluate(unsigned int frame)
{
Action::evaluate(frame);
_animation->update(frame * 1.0/_fps);
}
Animation* getAnimation() { return _animation.get(); }
protected:
osg::ref_ptr<Animation> _animation;
};
// encapsulate animation with blend in blend out for classic usage
class StripAnimation : public Action
{
protected:
typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
public:
StripAnimation(Animation* animation, double blendInDuration, double blendOutDuration, double blendInWeightTarget = 1.0 )
{
_blendIn = new BlendIn(animation, blendInDuration, blendInWeightTarget);
_animation = new ActionAnimation(animation);
unsigned int start = static_cast<unsigned int>(floor((_animation->getDuration() - blendOutDuration) * _fps));
_blendOut = FrameAction(start, new BlendOut(animation, blendOutDuration));
setName(animation->getName() + "_Strip");
_blendIn->setName(_animation->getName() + "_" + _blendIn->getName());
_blendOut.second->setName(_animation->getName() + "_" + _blendOut.second->getName());
setDuration(animation->getDuration());
}
ActionAnimation* getActionAnimation() { return _animation.get(); }
BlendIn* getBlendIn() { return _blendIn.get(); }
BlendOut* getBlendOut() { return dynamic_cast<BlendOut*>(_blendOut.second.get()); }
const ActionAnimation* getActionAnimation() const { return _animation.get(); }
const BlendIn* getBlendIn() const { return _blendIn.get(); }
const BlendOut* getBlendOut() const { return dynamic_cast<BlendOut*>(_blendOut.second.get()); }
unsigned int getLoop() const { return _animation->getLoop(); }
void setLoop(unsigned int loop)
{
_animation->setLoop(loop);
if (!loop)
setDuration(-1);
else
setDuration(loop * _animation->getDuration());
// duration changed re evaluate the blendout duration
unsigned int start = static_cast<unsigned int>(floor((getDuration() - _blendOut.second->getDuration()) * _fps));
_blendOut = FrameAction(start, _blendOut.second);
}
virtual void evaluate(unsigned int frame)
{
if (frame > getNumFrames() - 1)
return;
Action::evaluate(frame);
if (frame < _blendIn->getNumFrames())
_blendIn->evaluate(frame);
if (frame >= _blendOut.first)
_blendOut.second->evaluate(frame - _blendOut.first);
_animation->evaluate(frame);
}
protected:
osg::ref_ptr<BlendIn> _blendIn;
FrameAction _blendOut;
osg::ref_ptr<ActionAnimation> _animation;
};
class RunAction : public Action::Callback
{
protected:
osg::ref_ptr<Timeline> _tm;
osg::ref_ptr<Action> _action;
public:
RunAction(Timeline* tm, Action* a) : _tm(tm), _action(a) {}
virtual void operator()(Action* action)
{
_tm->addActionAt(_tm->getCurrentFrame(), _action.get()); // warning we are trsversing the vector
}
};
class AnimationManagerTimeline : public AnimationManagerBase
{
protected:
osg::ref_ptr<Timeline> _timeline;
public:
META_Node(osgAnimation, AnimationManagerTimeline);
AnimationManagerTimeline();
AnimationManagerTimeline(const AnimationManagerBase& manager);
AnimationManagerTimeline(const AnimationManagerTimeline& nc,const osg::CopyOp&) {}
Timeline* getTimeline() { return _timeline.get(); }
void update(double time);
};
}
#endif

View File

@@ -0,0 +1,68 @@
/* -*-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.
*/
#ifndef OSGANIMATION_UPDATE_CALLBACK_H
#define OSGANIMATION_UPDATE_CALLBACK_H
#include <osg/Vec3>
#include <osg/NodeCallback>
#include <osg/observer_ptr>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/Export>
namespace osgAnimation
{
class OSGANIMATION_EXPORT AnimationUpdateCallback : public osg::NodeCallback
{
protected:
osg::observer_ptr<osgAnimation::AnimationManagerBase> _manager;
public:
AnimationUpdateCallback(const std::string& name = "") { setName(name); }
AnimationUpdateCallback(const AnimationUpdateCallback& apc,const osg::CopyOp& copyop);
osgAnimation::AnimationManagerBase* getAnimationManager();
virtual bool needLink() const = 0;
virtual bool link(osgAnimation::Channel* channel) = 0;
virtual int link(osgAnimation::Animation* animation);
virtual void updateLink();
};
class OSGANIMATION_EXPORT UpdateTransform : public AnimationUpdateCallback
{
protected:
osg::ref_ptr<osgAnimation::Vec3Target> _euler;
osg::ref_ptr<osgAnimation::Vec3Target> _position;
osg::ref_ptr<osgAnimation::Vec3Target> _scale;
public:
META_Object(osgAnimation, UpdateTransform);
UpdateTransform(const std::string& name = "");
UpdateTransform(const UpdateTransform& apc,const osg::CopyOp& copyop);
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
void update(osg::MatrixTransform& mat);
void update(osg::PositionAttitudeTransform& pat);
bool needLink() const;
bool link(osgAnimation::Channel* channel);
};
}
#endif

View File

@@ -0,0 +1,118 @@
/* -*-c++-*-
*/
//****************************************************************************//
// loader.cpp //
// Copyright (C) 2001, 2002 Bruno 'Beosil' Heidelberger //
//****************************************************************************//
// This library is free software; you can redistribute it and/or modify it //
// under the terms of the GNU Lesser General Public License as published by //
// the Free Software Foundation; either version 2.1 of the License, or (at //
// your option) any later version. //
//****************************************************************************//
/*****************************************************************************/
/** Loads a core compressed keyframe instance.
*
* This function loads a core compressed keyframe instance from a data source.
*
* @param dataSrc The data source to load the core compressed keyframe instance from.
*
* @return One of the following values:
* \li a pointer to the core keyframe
* \li \b 0 if an error happened
* Authors
* Igor Kravchenko
* Cedric Pinson <mornifle@plopbyte.net>
*****************************************************************************/
#ifndef OSGANIMATION_PACKED_H
#define OSGANIMATION_PACKED_H
#include <float.h>
#include <vector>
#include <osg/Vec3>
#include <osg/Math>
namespace osgAnimation
{
struct Vec3Packed
{
typedef unsigned int uint32_t;
uint32_t m32bits;
Vec3Packed(uint32_t val): m32bits(val) {}
Vec3Packed(): m32bits(0) {}
void uncompress(const osg::Vec3& scale, const osg::Vec3& min, osg::Vec3& result) const
{
uint32_t pt[3];
pt[0] = m32bits & 0x7ff;
pt[1] = (m32bits >> 11) & 0x7ff;
pt[2] = m32bits >> 22;
result[0] = scale[0] * pt[0] + min[0];
result[1] = scale[1] * pt[1] + min[1];
result[2] = scale[2] * pt[2] + min[2];
}
void compress(const osg::Vec3f& src, const osg::Vec3f& min, const osg::Vec3f& scaleInv)
{
uint32_t srci[3];
srci[0] = osg::minimum(static_cast<uint32_t>(((src[0] - min[0] )*scaleInv[0])), uint32_t(2047));
srci[1] = osg::minimum(static_cast<uint32_t>(((src[1] - min[1] )*scaleInv[1])), uint32_t(2047));
srci[2] = osg::minimum(static_cast<uint32_t>(((src[2] - min[2] )*scaleInv[2])), uint32_t(1023));
m32bits = srci[0] + (srci[1] << 11) + (srci[2] << 22);
}
};
struct Vec3ArrayPacked
{
std::vector<Vec3Packed> mVecCompressed;
osg::Vec3 mMin;
osg::Vec3 mScale;
osg::Vec3 mScaleInv;
void analyze(const std::vector<osg::Vec3>& src)
{
//analyze the keys
mMin.set(FLT_MAX, FLT_MAX, FLT_MAX);
osg::Vec3 maxp(-FLT_MAX, -FLT_MAX, -FLT_MAX);
int nb = (int)src.size();
for(int i = 0; i < nb; i++)
{
const osg::Vec3 &pos = src[i];
for(int j = 0; j < 3; j++)
{
maxp[j] = osg::maximum(pos[j],maxp[j]);
mMin[j] = osg::minimum(pos[j],mMin[j]);
}
}
osg::Vec3 diff = maxp - mMin;
mScaleInv.set(0,0,0);
if (diff[0] != 0)
mScaleInv[0] = 2047.0/diff[0];
if (diff[1] != 0)
mScaleInv[1] = 2047.0/diff[1];
if (diff[2] != 0)
mScaleInv[2] = 1023.0/diff[2];
mScale[0] = diff[0] / 2047;
mScale[1] = diff[1] / 2047;
mScale[2] = diff[2] / 1023;
}
void compress(const std::vector<osg::Vec3>& src)
{
mVecCompressed.resize(src.size());
// save all core keyframes
for(int i = 0; i < (int)src.size(); i++)
mVecCompressed[i].compress(src[i], mMin, mScaleInv);
}
};
}
#endif

View File

@@ -0,0 +1,108 @@
/* -*-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.
*/
#ifndef OSGANIMATION_VERTEX_INFLUENCES_H
#define OSGANIMATION_VERTEX_INFLUENCES_H
#include <osg/Object>
#include <osgAnimation/Export>
#include <map>
#include <vector>
#include <string>
namespace osgAnimation
{
// first is vertex index, and second the weight, the
typedef std::pair<int, float> VertexIndexWeight;
typedef std::vector<VertexIndexWeight> VertexList;
class OSGANIMATION_EXPORT VertexInfluence : public VertexList
{
public:
const std::string& getName() const { return _name;}
void setName(const std::string& name) { _name = name;}
protected:
// the name is the bone to link to
std::string _name;
};
// typedef std::map<std::string, VertexInfluence> VertexInfluenceMap;
class VertexInfluenceMap : public std::map<std::string, VertexInfluence> , public osg::Object
{
public:
META_Object(osgAnimation, VertexInfluenceMap);
VertexInfluenceMap() {}
VertexInfluenceMap(const osgAnimation::VertexInfluenceMap& infl, const osg::CopyOp&) {;}
};
// this class manage VertexInfluence database by mesh
// reference bones per vertex ...
class VertexInfluenceSet
{
public:
typedef std::vector<VertexInfluence> BoneToVertexList;
class BoneWeight
{
public:
BoneWeight(const std::string& name, float weight) : _boneName(name), _weight(weight) {}
const std::string& getBoneName() const { return _boneName; }
float getWeight() const { return _weight; }
void setWeight(float weight) { _weight = weight; }
bool operator==(const BoneWeight& b) const { return (_boneName == b.getBoneName() && _weight == b.getWeight()); }
protected:
std::string _boneName;
float _weight;
};
typedef std::vector<BoneWeight> BoneWeightList;
typedef std::map<int,BoneWeightList> VertexIndexToBoneWeightMap;
class UniqVertexSetToBoneSet
{
public:
void setBones(BoneWeightList& bones) { _bones = bones;}
const BoneWeightList& getBones() const { return _bones;}
std::vector<int>& getVertexes() { return _vertexes;}
const std::vector<int>& getVertexes() const { return _vertexes;}
protected:
std::vector<int> _vertexes;
BoneWeightList _bones; // here we could limit matrix operation by caching (weight * matrix)
};
typedef std::vector<UniqVertexSetToBoneSet> UniqVertexSetToBoneSetList;
const UniqVertexSetToBoneSetList& getUniqVertexSetToBoneSetList() const { return _uniqVertexSetToBoneSet;}
void addVertexInfluence(const VertexInfluence& v) { _bone2Vertexes.push_back(v); }
void buildVertex2BoneList();
void buildUniqVertexSetToBoneSetList();
void clear()
{
_bone2Vertexes.clear();
_bone2Vertexes.clear();
_uniqVertexSetToBoneSet.clear();
}
protected:
BoneToVertexList _bone2Vertexes;
VertexIndexToBoneWeightMap _vertex2Bones;
UniqVertexSetToBoneSetList _uniqVertexSetToBoneSet;
};
}
#endif

View File

@@ -6,14 +6,15 @@ FOREACH( mylibfolder
osgUtil
osgGA
osgText
osgManipulator
osgSim
osgViewer
osgAnimation
osgFX
osgManipulator
osgParticle
osgShadow
osgSim
osgTerrain
osgVolume
osgViewer
)
ADD_SUBDIRECTORY(${mylibfolder})

View File

@@ -0,0 +1,147 @@
/* -*-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 <osgAnimation/Animation>
using namespace osgAnimation;
Animation::Animation(const osgAnimation::Animation& anim, const osg::CopyOp& c)
{
_duration = anim._duration;
_originalDuration = anim._originalDuration;
_weight = anim._weight;
_startTime = anim._startTime;
_playmode = anim._playmode;
}
void Animation::addChannel(Channel* pChannel)
{
_channels.push_back(pChannel);
if (!_duration)
computeDuration();
else
_originalDuration = computeDurationFromChannels();
}
double Animation::computeDurationFromChannels() const
{
double tmin = 1e5;
double tmax = -1e5;
ChannelList::const_iterator chan;
for( chan=_channels.begin(); chan!=_channels.end(); chan++ )
{
float min = (*chan)->getStartTime();
if (min < tmin)
tmin = min;
float max = (*chan)->getEndTime();
if (max > tmax)
tmax = max;
}
return tmax-tmin;
}
void Animation::computeDuration()
{
_duration = computeDurationFromChannels();
_originalDuration = _duration;
}
osgAnimation::ChannelList& Animation::getChannels()
{
return _channels;
}
const osgAnimation::ChannelList& Animation::getChannels() const
{
return _channels;
}
void Animation::setDuration(double duration)
{
_originalDuration = computeDurationFromChannels();
_duration = duration;
}
float Animation::getDuration() const
{
return _duration;
}
float Animation::getWeight () const
{
return _weight;
}
void Animation::setWeight (float weight)
{
_weight = weight;
}
bool Animation::update (float time)
{
if (!_duration) // if not initialized then do it
computeDuration();
double ratio = _originalDuration / _duration;
float t = (time - _startTime) * ratio;
switch (_playmode)
{
case ONCE:
if (t > _duration)
return false;
break;
case STAY:
if (t > _duration)
t = _duration;
break;
case LOOP:
if (!_duration)
t = _startTime;
else if (t > _duration)
t = fmodf(t, _duration);
// std::cout << "t " << t << " duration " << _duration << std::endl;
break;
case PPONG:
if (!_duration)
t = _startTime;
else
{
int tt = (int) (t / _duration);
t = fmodf(t, _duration);
if (tt%2)
t = _duration - t;
}
break;
}
// std::cout << "t " << t << " / " << _duration << std::endl;
ChannelList::const_iterator chan;
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
{
(*chan)->setWeight(_weight);
(*chan)->update(t);
}
return true;
}
void Animation::resetTargets()
{
ChannelList::const_iterator chan;
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
(*chan)->reset();
}

View File

@@ -0,0 +1,141 @@
/* -*-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 <osgAnimation/AnimationManager>
#include <osgAnimation/LinkVisitor>
#include <osgAnimation/Assert>
using namespace osgAnimation;
AnimationManager::~AnimationManager() {}
void AnimationManager::stopAll()
{
// loop over all playing animation
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
(*it)->resetTargets();
}
_animationsPlaying.clear();
}
AnimationManager::AnimationManager()
{
_lastUpdate = 0;
}
void AnimationManager::playAnimation(Animation* pAnimation, int priority, float weight)
{
bool r = findAnimation(pAnimation);
OSGANIMATION_ASSERT(r && "This animation is not registered");
if ( isPlaying(pAnimation) )
stopAnimation(pAnimation);
_animationsPlaying[priority].push_back(pAnimation);
pAnimation->setStartTime(_lastUpdate);
pAnimation->setWeight(weight);
}
bool AnimationManager::stopAnimation(Animation* pAnimation)
{
// search though the layer and remove animation
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
if( (*it) == pAnimation )
{
(*it)->resetTargets();
list.erase(it);
return true;
}
}
return false;
}
void AnimationManager::update (double time)
{
if (!_lastUpdate)
_lastUpdate = time;
// could filtered with an active flag
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->reset();
// update from high priority to low priority
for( AnimationLayers::reverse_iterator iterAnim = _animationsPlaying.rbegin(); iterAnim != _animationsPlaying.rend(); ++iterAnim )
{
// update all animation
std::vector<int> toremove;
AnimationList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
if (! list[i]->update(time))
toremove.push_back(i);
}
// remove finished animation
while (!toremove.empty())
{
list.erase(list.begin() + toremove.back());
toremove.pop_back();
}
}
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->normalize();
}
bool AnimationManager::findAnimation(Animation* pAnimation)
{
for( AnimationList::const_iterator iterAnim = _animations.begin(); iterAnim != _animations.end(); ++iterAnim )
{
if ( (*iterAnim) == pAnimation )
return true;
}
return false;
}
bool AnimationManager::isPlaying(Animation* pAnimation)
{
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
if ( (*it) == pAnimation )
return true;
}
return false;
}
bool AnimationManager::isPlaying(const std::string& name)
{
// loop over all playing animation
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
if ( (*it)->getName() == name )
return true;
}
return false;
}

View File

@@ -0,0 +1,71 @@
/* -*-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 <osgAnimation/AnimationManagerBase>
#include <osgAnimation/LinkVisitor>
#include <osgAnimation/Assert>
using namespace osgAnimation;
AnimationManagerBase::~AnimationManagerBase() {}
AnimationManagerBase::AnimationManagerBase()
{
setUpdateCallback(new UpdateCallback);
_needToLink = false;
}
void AnimationManagerBase::buildTargetReference()
{
_targets.clear();
for( AnimationList::iterator iterAnim = _animations.begin(); iterAnim != _animations.end(); ++iterAnim )
{
Animation* anim = (*iterAnim).get();
for (ChannelList::iterator it = anim->getChannels().begin();
it != anim->getChannels().end();
it++)
_targets.insert((*it)->getTarget());
}
}
void AnimationManagerBase::registerAnimation (Animation* animation)
{
_needToLink = true;
_animations.push_back(animation);
buildTargetReference();
}
bool AnimationManagerBase::needToLink() const { return _needToLink; }
void AnimationManagerBase::link()
{
LinkVisitor linker(_animations);
accept(linker);
_needToLink = false;
buildTargetReference();
}
osgAnimation::AnimationMap AnimationManagerBase::getAnimationMap() const
{
osgAnimation::AnimationMap map;
for (AnimationList::const_iterator it = _animations.begin(); it != _animations.end(); it++)
map[(*it)->getName()] = *it;
return map;
}

104
src/osgAnimation/Bone.cpp Normal file
View File

@@ -0,0 +1,104 @@
/* -*-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 <osgAnimation/Skinning>
#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
osgAnimation::Bone::UpdateBone::UpdateBone(const osgAnimation::Bone::UpdateBone& apc,const osg::CopyOp& copyop):
osgAnimation::AnimationUpdateCallback(apc, copyop),
_position(apc._position),
_quaternion(apc._quaternion),
_scale(apc._scale)
{
}
void osgAnimation::Bone::computeBindMatrix()
{
_invBindInSkeletonSpace = osg::Matrix::inverse(_bindInBoneSpace);
const Bone* parent = getBoneParent();
_needToRecomputeBindMatrix = false;
if (!parent)
{
#if 0
// no more parent means, we get the skeleton
if (getParents().empty()) {
osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl;
return;
} else if (getParents().size() > 1) {
osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you have more than one parent in a skeleton structure (" << getName() <<") unknown behaviour" << std::endl;
return;
}
osgAnimation::Skeleton* skel = dynamic_cast<osgAnimation::Skeleton*>(getParents()[0]);
if (!skel) {
osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl;
return;
}
_invBindInSkeletonSpace = osg::Matrix::inverse(skel->getMatrix()) * _invBindInSkeletonSpace;
#else
osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl;
#endif
return;
}
_invBindInSkeletonSpace = parent->getInvBindMatrixInSkeletonSpace() * _invBindInSkeletonSpace;
}
osgAnimation::Bone* osgAnimation::Bone::getBoneParent()
{
if (getParents().empty())
return 0;
osg::Node::ParentList parents = getParents();
for (osg::Node::ParentList::iterator it = parents.begin(); it != parents.end(); it++)
{
Bone* pb = dynamic_cast<Bone*>(*it);
if (pb)
return pb;
}
return 0;
}
const osgAnimation::Bone* osgAnimation::Bone::getBoneParent() const
{
if (getParents().empty())
return 0;
const osg::Node::ParentList& parents = getParents();
for (osg::Node::ParentList::const_iterator it = parents.begin(); it != parents.end(); it++)
{
const Bone* pb = dynamic_cast<const Bone*>(*it);
if (pb)
return pb;
}
return 0;
}
/** Add Node to Group.
* If node is not NULL and is not contained in Group then increment its
* reference count, add it to the child list and dirty the bounding
* sphere to force it to recompute on next getBound() and return true for success.
* Otherwise return false. Scene nodes can't be added as child nodes.
*/
bool osgAnimation::Bone::addChild( Node *child )
{
Bone* bone = dynamic_cast<Bone*>(child);
if (bone)
bone->setNeedToComputeBindMatrix(true);
return osg::Group::addChild(child);
}
osgAnimation::Bone::BoneMap osgAnimation::Bone::getBoneMap()
{
BoneMapVisitor mapVisitor;
this->accept(mapVisitor);
return mapVisitor._map;
}

View File

@@ -0,0 +1,56 @@
IF (DYNAMIC_OPENSCENEGRAPH)
ADD_DEFINITIONS(-DOSGANIMATION_LIBRARY)
ELSE (DYNAMIC_OPENSCENEGRAPH)
ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC)
ENDIF(DYNAMIC_OPENSCENEGRAPH)
SET(LIB_NAME osgAnimation)
SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME})
SET(LIB_PUBLIC_HEADERS
${HEADER_PATH}/Export
${HEADER_PATH}/Bone
${HEADER_PATH}/Skeleton
${HEADER_PATH}/Channel
${HEADER_PATH}/Sampler
${HEADER_PATH}/Interpolator
${HEADER_PATH}/Target
${HEADER_PATH}/Animation
${HEADER_PATH}/Keyframe
${HEADER_PATH}/Skinning
${HEADER_PATH}/CubicBezier
${HEADER_PATH}/Vec3Packed
${HEADER_PATH}/AnimationManager
${HEADER_PATH}/AnimationManagerBase
${HEADER_PATH}/UpdateCallback
${HEADER_PATH}/LinkVisitor
${HEADER_PATH}/VertexInfluence
${HEADER_PATH}/EaseMotion
${HEADER_PATH}/Assert
${HEADER_PATH}/Timeline
)
ADD_LIBRARY(${LIB_NAME}
${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC}
${LIB_PUBLIC_HEADERS}
Channel.cpp
Target.cpp
Animation.cpp
Bone.cpp
RigGeometry.cpp
AnimationManager.cpp
AnimationManagerBase.cpp
Skeleton.cpp
VertexInfluence.cpp
UpdateCallback.cpp
Timeline.cpp
)
LINK_INTERNAL(${LIB_NAME}
osg
)
LINK_CORELIB_DEFAULT(${LIB_NAME})
INCLUDE(ModuleInstall OPTIONAL)

View File

@@ -0,0 +1,29 @@
/* -*-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 <osgAnimation/Channel>
using namespace osgAnimation;
Channel::Channel() { _weight=1; }
Channel::~Channel() {}
const std::string& Channel::getName() const { return _name; }
void Channel::setName (const std::string& name) { _name = name; }
const std::string& Channel::getTargetName() const { return _targetName;}
void Channel::setTargetName (const std::string& name) { _targetName = name; }
float Channel::getWeight() const { return _weight;}
void Channel::setWeight(float w) { _weight = w;}

View File

@@ -0,0 +1,93 @@
/* -*-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 <osgAnimation/RigGeometry>
void osgAnimation::RigGeometry::buildTransformer(Skeleton* root)
{
Bone::BoneMap bm = root->getBoneMap();
_transformVertexes.init(bm, _vertexInfluenceSet.getUniqVertexSetToBoneSetList());
_root = root;
}
void osgAnimation::RigGeometry::buildVertexSet()
{
if (!_vertexInfluenceMap.valid())
{
osg::notify(osg::WARN) << "buildVertexSet can't be called without VertexInfluence already set to the RigGeometry ( " << getName() << " ) " << std::endl;
return;
}
_vertexInfluenceSet.clear();
for (osgAnimation::VertexInfluenceMap::iterator it = _vertexInfluenceMap->begin();
it != _vertexInfluenceMap->end();
it++)
_vertexInfluenceSet.addVertexInfluence(it->second);
_vertexInfluenceSet.buildVertex2BoneList();
_vertexInfluenceSet.buildUniqVertexSetToBoneSetList();
std::cout << "uniq groups " << _vertexInfluenceSet.getUniqVertexSetToBoneSetList().size() << " for " << getName() << std::endl;
}
void osgAnimation::RigGeometry::computeMatrixFromRootSkeleton()
{
if (!_root.valid())
{
osg::notify(osg::WARN) << "Warning " << className() <<"::computeMatrixFromRootSkeleton if you have this message it means you miss to call buildTransformer(Skeleton* root), or your RigGeometry (" << getName() <<") is not attached to a Skeleton subgraph" << std::endl;
return;
}
osg::MatrixList mtxList = getParent(0)->getWorldMatrices(_root.get());
_matrixFromSkeletonToGeometry = mtxList[0];
_invMatrixFromSkeletonToGeometry = osg::Matrix::inverse(_matrixFromSkeletonToGeometry);
_needToComputeMatrix = false;
}
void osgAnimation::RigGeometry::transformSoftwareMethod()
{
// std::cout << getName() << " _matrixFromSkeletonToGeometry" << _matrixFromSkeletonToGeometry << std::endl;
osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(getVertexArray());
if (pos && _positionSource.size() != pos->size())
{
_positionSource = std::vector<osg::Vec3>(pos->begin(),pos->end());
getVertexArray()->setDataVariance(osg::Object::DYNAMIC);
}
osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(getNormalArray());
if (normal && _normalSource.size() != normal->size())
{
_normalSource = std::vector<osg::Vec3>(normal->begin(),normal->end());
getNormalArray()->setDataVariance(osg::Object::DYNAMIC);
}
if (!_positionSource.empty())
{
_transformVertexes.compute<osg::Vec3>(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_positionSource.front(), &pos->front());
pos->dirty();
}
if (!_normalSource.empty())
{
_transformVertexes.compute<osg::Vec3>(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_normalSource.front(), &normal->front());
normal->dirty();
}
dirtyBound();
}
const osgAnimation::Skeleton* osgAnimation::RigGeometry::getSkeleton() const { return _root.get(); }
osgAnimation::Skeleton* osgAnimation::RigGeometry::getSkeleton() { return _root.get(); }

View File

@@ -0,0 +1,94 @@
/* -*-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 <osgAnimation/Skeleton>
#include <osgAnimation/Bone>
using namespace osgAnimation;
struct computeBindMatrixVisitor : public osg::NodeVisitor
{
osg::Matrix _skeleton;
computeBindMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void apply(osg::Node& node) { return ;}
void apply(osg::Transform& node)
{
Bone* bone = dynamic_cast<Bone*>(&node);
if (!bone)
return;
bone->computeBindMatrix();
traverse(node);
}
};
struct updateMatrixVisitor : public osg::NodeVisitor
{
osg::Matrix _skeleton;
updateMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void apply(osg::Node& node) { return ;}
void apply(osg::Transform& node)
{
// the idea is to traverse the skeleton or bone but to stop if other node is found
Bone* bone = dynamic_cast<Bone*>(&node);
if (!bone)
return;
Bone* parent = bone->getBoneParent();
if (bone->needToComputeBindMatrix())
{
computeBindMatrixVisitor visitor;
bone->accept(visitor);
}
if (parent)
bone->_boneInSkeletonSpace = bone->getMatrixInBoneSpace() * bone->getBoneParent()->getMatrixInSkeletonSpace();
else
bone->_boneInSkeletonSpace = bone->getMatrixInBoneSpace();// * _skeleton;
traverse(node);
}
};
void Skeleton::UpdateCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
Skeleton* b = dynamic_cast<Skeleton*>(node);
if (b)
{
// apply the updater only on the root bone, The udpateMatrixVisitor will
// traverse only bone and will update only bone. Then we continu on the classic
// process. It's important to update Bone before other things because the update
// of RigGeometry need it
updateMatrixVisitor visitor;
#if 0
visitor._skeleton = b->getMatrix();
int numChildren = b->getNumChildren();
for (int i = 0; i < numChildren; i++)
{
b->getChild(i)->accept(visitor);
}
#else
b->accept(visitor);
#endif
}
}
traverse(node,nv);
}
Skeleton::Skeleton()
{
setUpdateCallback(new UpdateCallback());
}

View File

@@ -0,0 +1,22 @@
/* -*-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 <osgAnimation/Target>
#include <osgAnimation/Channel>
using namespace osgAnimation;
Target::Target() { reset();}
Target::~Target() {}

View File

@@ -0,0 +1,49 @@
/* -*-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 <osgAnimation/Timeline>
using namespace osgAnimation;
// temporary
// the problem comes that the AnimationManagerBase should only a group
// and it's data should be in an update callback
struct TimelineAdaptator : public Timeline
{
osg::ref_ptr<AnimationManagerTimeline> _manager;
TimelineAdaptator(AnimationManagerTimeline* manager) : _manager(manager) {}
void evaluate(unsigned int frame)
{
_manager->clearTargets();
Timeline::evaluate(frame);
_manager->normalizeTargets();
}
};
AnimationManagerTimeline::AnimationManagerTimeline()
{
_timeline = new TimelineAdaptator(this);
}
AnimationManagerTimeline::AnimationManagerTimeline(const AnimationManagerBase& manager) : AnimationManagerBase(manager)
{
_timeline = new TimelineAdaptator(this);
}
void AnimationManagerTimeline::update(double time)
{
_timeline->update(time);
}

View File

@@ -0,0 +1,170 @@
/* -*-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 <osgAnimation/UpdateCallback>
#include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform>
using namespace osgAnimation;
osgAnimation::AnimationManagerBase* AnimationUpdateCallback::getAnimationManager() { return _manager.get(); }
AnimationUpdateCallback::AnimationUpdateCallback(const AnimationUpdateCallback& apc,const osg::CopyOp& copyop):
osg::NodeCallback(apc, copyop),
_manager(apc._manager) {}
int AnimationUpdateCallback::link(osgAnimation::Animation* animation)
{
int nbLinks = 0;
for (osgAnimation::ChannelList::iterator it = animation->getChannels().begin();
it != animation->getChannels().end();
it++)
{
std::string targetName = (*it)->getTargetName();
if (targetName == getName())
{
link((*it).get());
nbLinks++;
}
}
return nbLinks;
}
void AnimationUpdateCallback::updateLink()
{
if (_manager.valid())
{
if (needLink())
{
/** this item is not linked yet then we do it for all animation
registered in the manager.
Maybe this function should be on the manager side like
_manager->linkItem(Bone);
*/
AnimationMap map = _manager->getAnimationMap();
for (AnimationMap::iterator it = map.begin(); it != map.end(); it++)
link(it->second.get());
_manager->buildTargetReference();
}
}
}
UpdateTransform::UpdateTransform(const UpdateTransform& apc,const osg::CopyOp& copyop)
: AnimationUpdateCallback(apc, copyop),
_euler(apc._euler),
_position(apc._position),
_scale(apc._scale)
{
}
UpdateTransform::UpdateTransform(const std::string& name) : AnimationUpdateCallback(name)
{
_euler = new osgAnimation::Vec3Target;
_position = new osgAnimation::Vec3Target;
_scale = new osgAnimation::Vec3Target(osg::Vec3(1,1,1));
}
/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateTransform::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
osg::MatrixTransform* matrix = dynamic_cast<osg::MatrixTransform*>(node);
if (matrix)
{
update(*matrix);
}
else
{
osg::PositionAttitudeTransform* pat = dynamic_cast<osg::PositionAttitudeTransform*>(node);
if (pat)
update(*pat);
}
}
traverse(node,nv);
}
void UpdateTransform::update(osg::MatrixTransform& mat)
{
float z = _euler->getValue()[2];
float x = _euler->getValue()[0];
float y = _euler->getValue()[1];
osg::Matrix m =
osg::Matrix::rotate(x,1.0,0.0,0.0) *
osg::Matrix::rotate(y,0.0,1.0,0.0) *
osg::Matrix::rotate(z,0.0,0.0,1.0);
mat.setMatrix(osg::Matrix::scale(_scale->getValue()) *
m *
osg::Matrix::translate(_position->getValue()));
mat.dirtyBound();
}
void UpdateTransform::update(osg::PositionAttitudeTransform& pat)
{
float heading = _euler->getValue()[0];
float pitch = _euler->getValue()[1];
float roll = _euler->getValue()[2];
osg::Matrix m = osg::Matrix::rotate(roll,0.0,1.0,0.0) * osg::Matrix::rotate(pitch,1.0,0.0,0.0) * osg::Matrix::rotate(-heading,0.0,0.0,1.0);
osg::Quat q = m.getRotate();
pat.setPosition(_position->getValue());
pat.setScale(_scale->getValue());
pat.setAttitude(q);
pat.dirtyBound();
}
bool UpdateTransform::needLink() const
{
// the idea is to return true if nothing is linked
return !((_position->getCount() + _euler->getCount() + _scale->getCount()) > 3);
}
bool UpdateTransform::link(osgAnimation::Channel* channel)
{
if (channel->getName().find("euler") != std::string::npos)
{
osgAnimation::Vec3LinearChannel* qc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
if (qc)
{
qc->setTarget(_euler.get());
return true;
}
}
else if (channel->getName().find("position") != std::string::npos)
{
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
if (vc)
{
vc->setTarget(_position.get());
return true;
}
}
else if (channel->getName().find("scale") != std::string::npos)
{
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
if (vc)
{
vc->setTarget(_scale.get());
return true;
}
}
else
{
std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
}
return false;
}

View File

@@ -0,0 +1,130 @@
/* -*-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 <osgAnimation/VertexInfluence>
#include <iostream>
#include <algorithm>
using namespace osgAnimation;
// this class manage VertexInfluence database by mesh
// reference bones per vertex ...
void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
{
_vertex2Bones.clear();
for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); it++)
{
const VertexInfluence& vi = (*it);
int size = vi.size();
for (int i = 0; i < size; i++)
{
VertexIndexWeight viw = vi[i];
int index = viw.first;
float weight = viw.second;
if (vi.getName().empty())
std::cout << "osgAnimation::VertexInfluenceSet::buildVertex2BoneList warning vertex " << index << " is not assigned to a bone" << std::endl;
_vertex2Bones[index].push_back(BoneWeight(vi.getName(), weight));
}
}
// normalize weight per vertex
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); it++)
{
BoneWeightList& bones = it->second;
int size = bones.size();
float sum = 0;
for (int i = 0; i < size; i++)
sum += bones[i].getWeight();
if (sum < 1e-4)
{
std::cerr << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << it->first << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
}
else
{
float mult = 1.0/sum;
for (int i = 0; i < size; i++)
bones[i].setWeight(bones[i].getWeight() * mult);
}
}
}
// sort by name and weight
struct SortByNameAndWeight : public std::less<osgAnimation::VertexInfluenceSet::BoneWeight>
{
bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeight& b0,
const osgAnimation::VertexInfluenceSet::BoneWeight& b1) const
{
if (b0.getBoneName() < b1.getBoneName())
return true;
else if (b0.getBoneName() > b1.getBoneName())
return false;
if (b0.getWeight() < b1.getWeight())
return true;
return false;
}
};
struct SortByBoneWeightList : public std::less<osgAnimation::VertexInfluenceSet::BoneWeightList>
{
bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeightList& b0,
const osgAnimation::VertexInfluenceSet::BoneWeightList& b1) const
{
if (b0.size() < b1.size())
return true;
else if (b0.size() > b1.size())
return false;
int size = b0.size();
for (int i = 0; i < size; i++)
{
bool result = SortByNameAndWeight()(b0[i], b1[i]);
if (result)
return true;
else if (SortByNameAndWeight()(b1[i], b0[i]))
return false;
}
return false;
}
};
void osgAnimation::VertexInfluenceSet::buildUniqVertexSetToBoneSetList()
{
_uniqVertexSetToBoneSet.clear();
typedef std::map<BoneWeightList,UniqVertexSetToBoneSet, SortByBoneWeightList> UnifyBoneGroup;
UnifyBoneGroup unifyBuffer;
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); it++)
{
BoneWeightList bones = it->second;
int vertexIndex = it->first;
// sort the vector to have a consistent key
std::sort(bones.begin(), bones.end(), SortByNameAndWeight());
// we use the vector<BoneWeight> as key to differentiate group
UnifyBoneGroup::iterator result = unifyBuffer.find(bones);
if (result == unifyBuffer.end())
unifyBuffer[bones].setBones(bones);
unifyBuffer[bones].getVertexes().push_back(vertexIndex);
}
_uniqVertexSetToBoneSet.reserve(unifyBuffer.size());
for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); it++)
{
_uniqVertexSetToBoneSet.push_back(it->second);
}
}

View File

@@ -33,6 +33,7 @@ SET(TARGET_COMMON_LIBRARIES
#
# NodeKit/Psudo loader plugins
#
ADD_SUBDIRECTORY(osgAnimation)
ADD_SUBDIRECTORY(osgFX)
ADD_SUBDIRECTORY(osgParticle)
ADD_SUBDIRECTORY(osgSim)

View File

@@ -0,0 +1,9 @@
SET(TARGET_SRC
ReaderWriter.cpp
)
SET(TARGET_ADDED_LIBRARIES osgAnimation )
#### end var setup ###
SETUP_PLUGIN(osganimation)

View File

@@ -0,0 +1,491 @@
/* -*-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 <osgDB/Registry>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/ReaderWriter>
#include <osgAnimation/AnimationManager>
#include <osgAnimation/VertexInfluence>
#include <osgAnimation/Animation>
#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/UpdateCallback>
#include <osgDB/Registry>
#include <osgDB/Input>
#include <osgDB/Output>
using namespace osgDB;
using namespace osg;
bool Bone_readLocalData(Object& obj, Input& fr)
{
osgAnimation::Bone& bone = dynamic_cast<osgAnimation::Bone&>(obj);
osg::Quat att;
bool iteratorAdvanced = false;
if (fr.matchSequence("bindQuaternion %f %f %f %f"))
{
fr[1].getFloat(att[0]);
fr[2].getFloat(att[1]);
fr[3].getFloat(att[2]);
fr[4].getFloat(att[3]);
fr += 5;
iteratorAdvanced = true;
}
osg::Vec3d pos(0,0,0);
if (fr.matchSequence("bindPosition %f %f %f"))
{
fr[1].getFloat(pos[0]);
fr[2].getFloat(pos[1]);
fr[3].getFloat(pos[2]);
fr += 4;
iteratorAdvanced = true;
}
osg::Vec3d scale(1,1,1);
if (fr.matchSequence("bindScale %f %f %f"))
{
fr[1].getFloat(scale[0]);
fr[2].getFloat(scale[1]);
fr[3].getFloat(scale[2]);
fr += 4;
iteratorAdvanced = true;
}
bone.setBindMatrixInBoneSpace( osg::Matrix(att) * osg::Matrix::translate(pos));
if (bone.getUpdateCallback() && bone.getUpdateCallback()->getName().empty() && bone.getUpdateCallback()->getNestedCallback())
bone.setUpdateCallback(bone.getUpdateCallback()->getNestedCallback()); // skip the default callback build in constructor of Bone
return iteratorAdvanced;
}
bool Bone_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::Bone& bone = dynamic_cast<const osgAnimation::Bone&>(obj);
osg::Vec3 t;
osg::Quat r;
osg::Vec3 s;
osg::Quat rs;
bone.getBindMatrixInBoneSpace().decompose(t,r,s,rs);
fw.indent() << "bindQuaternion " << r << std::endl;
fw.indent() << "bindPosition " << t << std::endl;
fw.indent() << "bindScale " << s << std::endl;
return true;
}
RegisterDotOsgWrapperProxy g_atkBoneProxy
(
new osgAnimation::Bone,
"osgAnimation::Bone",
"Object Node Transform osgAnimation::Bone Group",
&Bone_readLocalData,
&Bone_writeLocalData
);
bool Skeleton_readLocalData(Object& obj, Input& fr)
{
return false;
}
bool Skeleton_writeLocalData(const Object& obj, Output& fr)
{
return true;
}
RegisterDotOsgWrapperProxy g_atkRootSkeletonProxy
(
new osgAnimation::Skeleton,
"osgAnimation::Skeleton",
"Object Node Transform osgAnimation::Bone osgAnimation::Skeleton Group",
&Skeleton_readLocalData,
&Skeleton_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
bool Animation_readLocalData(Object& obj, Input& fr)
{
osgAnimation::Animation& anim = dynamic_cast<osgAnimation::Animation&>(obj);
bool iteratorAdvanced = false;
int nbChannels = 0;
if (fr.matchSequence("num_channels %i"))
{
fr[1].getInt(nbChannels);
fr += 2;
iteratorAdvanced = true;
}
for (int i = 0; i < nbChannels; i++)
{
if (fr.matchSequence("Channel {"))
{
fr += 2;
std::string name = "unknown";
if (fr.matchSequence("name %s"))
{
name = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
std::string target = "unknown";
if (fr.matchSequence("target %s"))
{
target = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
std::string type;
int nbKeys;
if (fr.matchSequence("Keyframes %s %i {"))
{
type = fr[1].getStr();
fr[2].getInt(nbKeys);
fr += 4;
iteratorAdvanced = true;
osgAnimation::Channel* channel = 0;
if (type == "Quat")
{
osgAnimation::QuatSphericalLinearChannel* c = new osgAnimation::QuatSphericalLinearChannel;
c->getOrCreateSampler()->getOrCreateKeyframeContainer();
channel = c;
}
else if (type == "Vec3")
{
channel = new osgAnimation::Vec3LinearChannel;
osgAnimation::Vec3LinearChannel* c = new osgAnimation::Vec3LinearChannel;
c->getOrCreateSampler()->getOrCreateKeyframeContainer();
channel = c;
}
if (channel)
{
for (int k = 0; k < nbKeys; k++)
{
if (type == "Quat")
{
osg::Quat q;
float time;
fr.matchSequence("key %f %f %f %f %f");
fr[1].getFloat(time);
fr[2].getFloat(q[0]);
fr[3].getFloat(q[1]);
fr[4].getFloat(q[2]);
fr[5].getFloat(q[3]);
fr += 6;
osgAnimation::QuatSphericalLinearChannel* c = dynamic_cast<osgAnimation::QuatSphericalLinearChannel*>(channel);
c->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::QuatKeyframe(time, q));
iteratorAdvanced = true;
}
else if (type == "Vec3")
{
osg::Vec3 v;
float time;
fr.matchSequence("key %f %f %f %f");
fr[1].getFloat(time);
fr[2].getFloat(v[0]);
fr[3].getFloat(v[1]);
fr[4].getFloat(v[2]);
fr += 5;
osgAnimation::Vec3LinearChannel* c = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
c->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec3Keyframe(time, v));
iteratorAdvanced = true;
}
}
channel->setName(name);
channel->setTargetName(target);
anim.addChannel(channel);
}
if (fr.matchSequence("}")) // keyframes
fr += 1;
if (fr.matchSequence("}")) // channel
fr += 1;
}
}
}
return iteratorAdvanced;
}
bool Animation_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::Animation& anim = dynamic_cast<const osgAnimation::Animation&>(obj);
fw.indent() << "num_channels " << anim.getChannels().size() << std::endl;
for (unsigned int i = 0; i < anim.getChannels().size(); i++)
{
fw.indent() << "Channel {" << std::endl;
fw.moveIn();
fw.indent() << "name \"" << anim.getChannels()[i]->getName() << "\"" << std::endl;
fw.indent() << "target \"" << anim.getChannels()[i]->getTargetName() << "\"" << std::endl;
std::string type = "unknown";
if (anim.getChannels()[i]->getName() == std::string("quaternion"))
{
type = "Quat";
}
else if (anim.getChannels()[i]->getName() == std::string("rotation"))
{
type = "Quat";
}
else if (anim.getChannels()[i]->getName() == std::string("euler"))
{
type = "Vec3";
}
else if (anim.getChannels()[i]->getName() == std::string("scale"))
{
type = "Vec3";
}
else if (anim.getChannels()[i]->getName() == std::string("position"))
{
type = "Vec3";
}
osgAnimation::KeyframeContainer* kf = anim.getChannels()[i]->getSampler()->getKeyframeContainer();
fw.indent() << "Keyframes \"" << type << "\" " << kf->size() << " {" << std::endl;
fw.moveIn();
for (unsigned int k = 0; k < kf->size(); k++)
{
if (type == "Vec3")
{
osgAnimation::Vec3KeyframeContainer* kk = dynamic_cast<osgAnimation::Vec3KeyframeContainer*>(kf);
fw.indent() << "key " << (*kk)[k].getTime() << " " << (*kk)[k].getValue() << std::endl;
}
else if ( type == "Quat")
{
osgAnimation::QuatKeyframeContainer* kk = dynamic_cast<osgAnimation::QuatKeyframeContainer*>(kf);
fw.indent() << "key " << (*kk)[k].getTime() << " " << (*kk)[k].getValue() << std::endl;
}
}
fw.moveOut();
fw.indent() << "}" << std::endl;
fw.moveOut();
fw.indent() << "}" << std::endl;
}
return true;
}
RegisterDotOsgWrapperProxy g_atkAnimationProxy
(
new osgAnimation::Animation,
"osgAnimation::Animation",
"Object osgAnimation::Animation",
&Animation_readLocalData,
&Animation_writeLocalData
);
bool AnimationManager_readLocalData(Object& obj, Input& fr)
{
osgAnimation::AnimationManager& manager = dynamic_cast<osgAnimation::AnimationManager&>(obj);
int nbAnims = 0;
bool iteratorAdvanced = false;
if (fr.matchSequence("num_animations %i"))
{
fr[1].getInt(nbAnims);
fr += 2;
iteratorAdvanced = true;
}
for (int i = 0; i < nbAnims; i++)
{
Object* o = fr.readObject();
osgAnimation::Animation* a = dynamic_cast<osgAnimation::Animation*>(o);
if (a)
{
manager.registerAnimation(a);
iteratorAdvanced = true;
}
else
osg::notify(osg::WARN)<<"Warning: can't read an animation object"<< std::endl;
}
return iteratorAdvanced;
}
bool AnimationManager_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::AnimationManager& manager = dynamic_cast<const osgAnimation::AnimationManager&>(obj);
osgAnimation::AnimationMap map = manager.getAnimationMap();
int nbanims = map.size();
fw.indent() << "num_animations " << nbanims << std::endl;
for (osgAnimation::AnimationMap::iterator it = map.begin(); it != map.end(); it++)
{
if (!fw.writeObject(*it->second))
osg::notify(osg::WARN)<<"Warning: can't write an animation object"<< std::endl;
}
return true;
}
RegisterDotOsgWrapperProxy g_atkAnimationManagerProxy
(
new osgAnimation::AnimationManager,
"osgAnimation::AnimationManager",
"Object Node Group osgAnimation::AnimationManager",
&AnimationManager_readLocalData,
&AnimationManager_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
bool RigGeometry_readLocalData(Object& obj, Input& fr)
{
osgAnimation::RigGeometry& geom = dynamic_cast<osgAnimation::RigGeometry&>(obj);
osg::ref_ptr<osgAnimation::VertexInfluenceMap> vmap = new osgAnimation::VertexInfluenceMap;
int nbGroups = 0;
bool iteratorAdvanced = false;
if (fr.matchSequence("num_influences %i"))
{
fr[1].getInt(nbGroups);
fr += 2;
iteratorAdvanced = true;
}
for (int i = 0; i < nbGroups; i++)
{
int nbVertexes = 0;
std::string name;
if (fr.matchSequence("osgAnimation::VertexInfluence %s %i {"))
{
name = fr[1].getStr();
fr[2].getInt(nbVertexes);
fr += 4;
iteratorAdvanced = true;
}
osgAnimation::VertexInfluence vi;
vi.setName(name);
vi.reserve(nbVertexes);
for (int j = 0; j < nbVertexes; j++)
{
int index = -1;
float weight = 1;
if (fr.matchSequence("%i %f"))
{
fr[0].getInt(index);
fr[1].getFloat(weight);
fr += 2;
iteratorAdvanced = true;
}
vi.push_back(osgAnimation::VertexIndexWeight(index, weight));
}
if (fr.matchSequence("}"))
{
fr+=1;
}
(*vmap)[name] = vi;
}
if (!vmap->empty())
geom.setInfluenceMap(vmap.get());
return iteratorAdvanced;
}
bool RigGeometry_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::RigGeometry& geom = dynamic_cast<const osgAnimation::RigGeometry&>(obj);
const osgAnimation::VertexInfluenceMap* vm = geom.getInfluenceMap();
if (!vm)
return true;
fw.indent() << "num_influences " << vm->size() << std::endl;
fw.moveIn();
for (osgAnimation::VertexInfluenceMap::const_iterator it = vm->begin(); it != vm->end(); it++)
{
std::string name = it->first;
if (name.empty())
name = "Empty";
fw.indent() << "osgAnimation::VertexInfluence \"" << name << "\" " << it->second.size() << " {" << std::endl;
fw.moveIn();
const osgAnimation::VertexInfluence& vi = it->second;
for (osgAnimation::VertexInfluence::const_iterator itv = vi.begin(); itv != vi.end(); itv++)
{
fw.indent() << itv->first << " " << itv->second << std::endl;
}
fw.moveOut();
fw.indent() << "}" << std::endl;
}
fw.moveOut();
return true;
}
RegisterDotOsgWrapperProxy g_atkRigGeometryProxy
(
new osgAnimation::RigGeometry,
"osgAnimation::RigGeometry",
"Object Drawable osgAnimation::RigGeometry Geometry",
&RigGeometry_readLocalData,
&RigGeometry_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
bool UpdateBone_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
return iteratorAdvanced;
}
bool UpdateBone_writeLocalData(const Object& obj, Output& fw)
{
return true;
}
RegisterDotOsgWrapperProxy g_atkUpdateBoneProxy
(
new osgAnimation::Bone::UpdateBone,
"osgAnimation::UpdateBone",
"Object osgAnimation::UpdateBone",
&UpdateBone_readLocalData,
&UpdateBone_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
bool UpdateTransform_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
return iteratorAdvanced;
}
bool UpdateTransform_writeLocalData(const Object& obj, Output& fw)
{
return true;
}
RegisterDotOsgWrapperProxy g_atkUpdateTransformProxy
(
new osgAnimation::UpdateTransform,
"osgAnimation::UpdateTransform",
"Object osgAnimation::UpdateTransform",
&UpdateTransform_readLocalData,
&UpdateTransform_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);