From Cedric Pinson, Pulled in osgAnimation from OpenSceneGraph-osgWidget-dev into svn/trunk.
This commit is contained in:
@@ -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)
|
||||
|
||||
3
examples/osganimationmakepath/CMakeLists.txt
Normal file
3
examples/osganimationmakepath/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
SET(TARGET_SRC osganimationmakepath.cpp )
|
||||
SET(TARGET_ADDED_LIBRARIES osgAnimation )
|
||||
SETUP_EXAMPLE(osganimationmakepath)
|
||||
337
examples/osganimationmakepath/osganimationmakepath.cpp
Normal file
337
examples/osganimationmakepath/osganimationmakepath.cpp
Normal 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();
|
||||
}
|
||||
3
examples/osganimationnode/CMakeLists.txt
Normal file
3
examples/osganimationnode/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
#SET(TARGET_SRC osganimationnode.cpp )
|
||||
#SET(TARGET_ADDED_LIBRARIES osgAnimation )
|
||||
#SETUP_EXAMPLE(osganimationnode)
|
||||
272
examples/osganimationnode/osganimationnode.cpp
Normal file
272
examples/osganimationnode/osganimationnode.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
3
examples/osganimationskinning/CMakeLists.txt
Normal file
3
examples/osganimationskinning/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
SET(TARGET_SRC osganimationskinning.cpp )
|
||||
SET(TARGET_ADDED_LIBRARIES osgAnimation )
|
||||
SETUP_EXAMPLE(osganimationskinning)
|
||||
267
examples/osganimationskinning/osganimationskinning.cpp
Normal file
267
examples/osganimationskinning/osganimationskinning.cpp
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
3
examples/osganimationsolid/CMakeLists.txt
Normal file
3
examples/osganimationsolid/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
SET(TARGET_SRC osganimationsolid.cpp )
|
||||
SET(TARGET_ADDED_LIBRARIES osgAnimation )
|
||||
SETUP_EXAMPLE(osganimationsolid)
|
||||
118
examples/osganimationsolid/osganimationsolid.cpp
Normal file
118
examples/osganimationsolid/osganimationsolid.cpp
Normal 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();
|
||||
}
|
||||
3
examples/osganimationtimeline/CMakeLists.txt
Normal file
3
examples/osganimationtimeline/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
SET(TARGET_SRC osganimationtimeline.cpp )
|
||||
SET(TARGET_ADDED_LIBRARIES osgAnimation )
|
||||
SETUP_EXAMPLE(osganimationtimeline)
|
||||
209
examples/osganimationtimeline/osganimationtimeline.cpp
Normal file
209
examples/osganimationtimeline/osganimationtimeline.cpp
Normal 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();
|
||||
}
|
||||
|
||||
|
||||
123
examples/osganimationviewer/AnimtkViewer
Normal file
123
examples/osganimationviewer/AnimtkViewer
Normal 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
|
||||
116
examples/osganimationviewer/AnimtkViewer.cpp
Normal file
116
examples/osganimationviewer/AnimtkViewer.cpp
Normal 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();
|
||||
}
|
||||
46
examples/osganimationviewer/AnimtkViewerGUI
Normal file
46
examples/osganimationviewer/AnimtkViewerGUI
Normal 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
|
||||
407
examples/osganimationviewer/AnimtkViewerGUI.cpp
Normal file
407
examples/osganimationviewer/AnimtkViewerGUI.cpp
Normal 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);
|
||||
}
|
||||
53
examples/osganimationviewer/AnimtkViewerKeyHandler
Normal file
53
examples/osganimationviewer/AnimtkViewerKeyHandler
Normal 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
|
||||
63
examples/osganimationviewer/AnimtkViewerKeyHandler.cpp
Normal file
63
examples/osganimationviewer/AnimtkViewerKeyHandler.cpp
Normal 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;
|
||||
}
|
||||
7
examples/osganimationviewer/CMakeLists.txt
Normal file
7
examples/osganimationviewer/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
SET(TARGET_SRC
|
||||
AnimtkViewer.cpp
|
||||
AnimtkViewerKeyHandler.cpp
|
||||
AnimtkViewerGUI.cpp
|
||||
)
|
||||
SET(TARGET_ADDED_LIBRARIES osgAnimation osgWidget)
|
||||
SETUP_EXAMPLE(osganimationviewer)
|
||||
103
include/osgAnimation/Animation
Normal file
103
include/osgAnimation/Animation
Normal 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
|
||||
58
include/osgAnimation/AnimationManager
Normal file
58
include/osgAnimation/AnimationManager
Normal 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
|
||||
98
include/osgAnimation/AnimationManagerBase
Normal file
98
include/osgAnimation/AnimationManagerBase
Normal 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
|
||||
49
include/osgAnimation/Assert
Normal file
49
include/osgAnimation/Assert
Normal 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
300
include/osgAnimation/Bone
Normal 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
|
||||
136
include/osgAnimation/Channel
Normal file
136
include/osgAnimation/Channel
Normal 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
|
||||
56
include/osgAnimation/CubicBezier
Normal file
56
include/osgAnimation/CubicBezier
Normal 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
|
||||
238
include/osgAnimation/EaseMotion
Normal file
238
include/osgAnimation/EaseMotion
Normal 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
|
||||
65
include/osgAnimation/Export
Normal file
65
include/osgAnimation/Export
Normal 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
|
||||
206
include/osgAnimation/Interpolator
Normal file
206
include/osgAnimation/Interpolator
Normal 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
|
||||
130
include/osgAnimation/Keyframe
Normal file
130
include/osgAnimation/Keyframe
Normal 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
|
||||
50
include/osgAnimation/LinkVisitor
Normal file
50
include/osgAnimation/LinkVisitor
Normal 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
|
||||
159
include/osgAnimation/RigGeometry
Normal file
159
include/osgAnimation/RigGeometry
Normal 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
|
||||
124
include/osgAnimation/Sampler
Normal file
124
include/osgAnimation/Sampler
Normal 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
|
||||
44
include/osgAnimation/Skeleton
Normal file
44
include/osgAnimation/Skeleton
Normal 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
|
||||
167
include/osgAnimation/Skinning
Normal file
167
include/osgAnimation/Skinning
Normal 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
132
include/osgAnimation/Target
Normal 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
|
||||
563
include/osgAnimation/Timeline
Normal file
563
include/osgAnimation/Timeline
Normal 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
|
||||
68
include/osgAnimation/UpdateCallback
Normal file
68
include/osgAnimation/UpdateCallback
Normal 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
|
||||
118
include/osgAnimation/Vec3Packed
Normal file
118
include/osgAnimation/Vec3Packed
Normal 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
|
||||
108
include/osgAnimation/VertexInfluence
Normal file
108
include/osgAnimation/VertexInfluence
Normal 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
|
||||
@@ -6,14 +6,15 @@ FOREACH( mylibfolder
|
||||
osgUtil
|
||||
osgGA
|
||||
osgText
|
||||
osgManipulator
|
||||
osgSim
|
||||
osgViewer
|
||||
osgAnimation
|
||||
osgFX
|
||||
osgManipulator
|
||||
osgParticle
|
||||
osgShadow
|
||||
osgSim
|
||||
osgTerrain
|
||||
osgVolume
|
||||
osgViewer
|
||||
)
|
||||
|
||||
ADD_SUBDIRECTORY(${mylibfolder})
|
||||
|
||||
147
src/osgAnimation/Animation.cpp
Normal file
147
src/osgAnimation/Animation.cpp
Normal 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();
|
||||
}
|
||||
141
src/osgAnimation/AnimationManager.cpp
Normal file
141
src/osgAnimation/AnimationManager.cpp
Normal 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;
|
||||
}
|
||||
71
src/osgAnimation/AnimationManagerBase.cpp
Normal file
71
src/osgAnimation/AnimationManagerBase.cpp
Normal 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
104
src/osgAnimation/Bone.cpp
Normal 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;
|
||||
}
|
||||
56
src/osgAnimation/CMakeLists.txt
Normal file
56
src/osgAnimation/CMakeLists.txt
Normal 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)
|
||||
29
src/osgAnimation/Channel.cpp
Normal file
29
src/osgAnimation/Channel.cpp
Normal 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;}
|
||||
|
||||
93
src/osgAnimation/RigGeometry.cpp
Normal file
93
src/osgAnimation/RigGeometry.cpp
Normal 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(); }
|
||||
94
src/osgAnimation/Skeleton.cpp
Normal file
94
src/osgAnimation/Skeleton.cpp
Normal 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());
|
||||
}
|
||||
22
src/osgAnimation/Target.cpp
Normal file
22
src/osgAnimation/Target.cpp
Normal 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() {}
|
||||
49
src/osgAnimation/Timeline.cpp
Normal file
49
src/osgAnimation/Timeline.cpp
Normal 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);
|
||||
}
|
||||
|
||||
170
src/osgAnimation/UpdateCallback.cpp
Normal file
170
src/osgAnimation/UpdateCallback.cpp
Normal 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;
|
||||
}
|
||||
130
src/osgAnimation/VertexInfluence.cpp
Normal file
130
src/osgAnimation/VertexInfluence.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ SET(TARGET_COMMON_LIBRARIES
|
||||
#
|
||||
# NodeKit/Psudo loader plugins
|
||||
#
|
||||
ADD_SUBDIRECTORY(osgAnimation)
|
||||
ADD_SUBDIRECTORY(osgFX)
|
||||
ADD_SUBDIRECTORY(osgParticle)
|
||||
ADD_SUBDIRECTORY(osgSim)
|
||||
|
||||
9
src/osgPlugins/osgAnimation/CMakeLists.txt
Normal file
9
src/osgPlugins/osgAnimation/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
SET(TARGET_SRC
|
||||
ReaderWriter.cpp
|
||||
)
|
||||
|
||||
SET(TARGET_ADDED_LIBRARIES osgAnimation )
|
||||
#### end var setup ###
|
||||
SETUP_PLUGIN(osganimation)
|
||||
|
||||
|
||||
491
src/osgPlugins/osgAnimation/ReaderWriter.cpp
Normal file
491
src/osgPlugins/osgAnimation/ReaderWriter.cpp
Normal 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
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user