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

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

View File

@@ -0,0 +1,103 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_ANIMATION_H
#define OSGANIMATION_ANIMATION_H
#include <osg/Object>
#include <osgAnimation/Export>
#include <osgAnimation/Channel>
#include <osg/ref_ptr>
#include <vector>
#include <map>
namespace osgAnimation
{
class OSGANIMATION_EXPORT Animation : public virtual osg::Object
{
public:
META_Object(osgAnimation, Animation)
Animation() : _duration(0), _weight(0), _startTime(0), _playmode(LOOP) {}
Animation(const osgAnimation::Animation& anim, const osg::CopyOp&);
enum PlayMode
{
ONCE,
STAY,
LOOP,
PPONG
};
// addChannel insert the channel and call the computeDuration function
void addChannel (Channel* pChannel);
/** Those accessors let you add and remove channels
* if you modify something that can change the duration
* you are supposed to call computeDuration or setDuration
*/
ChannelList& getChannels();
const ChannelList& getChannels() const;
/** Change the duration of animation
* then evaluate the animation in the range 0-duration
* it stretch the animation in time.
* see computeDuration too
*/
void setDuration(double duration);
/** Compute duration from channel and keyframes
* if the duration is not specified you should
* call this method before using it
*/
void computeDuration();
float getDuration() const;
void setWeight (float weight);
float getWeight() const;
bool update (float time);
void resetTargets();
void setPlaymode (PlayMode mode) { _playmode = mode; }
void setStartTime(float time) { _startTime = time;}
float getStartTime() const { return _startTime;}
protected:
double computeDurationFromChannels() const;
~Animation() {}
std::string _name;
double _duration;
double _originalDuration;
float _weight;
float _startTime;
PlayMode _playmode;
ChannelList _channels;
};
typedef std::vector<osg::ref_ptr<osgAnimation::Animation> > AnimationList;
typedef std::map<std::string, osg::ref_ptr<osgAnimation::Animation> > AnimationMap;
}
#endif

View File

@@ -0,0 +1,58 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_ANIMATION_MANAGER_H
#define OSGANIMATION_ANIMATION_MANAGER_H
#include <osg/Group>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/Export>
#include <osg/FrameStamp>
namespace osgAnimation
{
class OSGANIMATION_EXPORT AnimationManager : public AnimationManagerBase
{
public:
META_Node(osgAnimation, AnimationManager);
AnimationManager();
AnimationManager(const AnimationManager& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) :
AnimationManagerBase(b,copyop) {}
virtual ~AnimationManager();
void update (double time);
void playAnimation (Animation* pAnimation, int priority = 0, float weight = 1.0);
bool stopAnimation (Animation* pAnimation);
bool findAnimation (Animation* pAnimation);
bool isPlaying (Animation* pAnimation);
bool isPlaying (const std::string& animationName);
void stopAll();
protected:
typedef std::map<int, AnimationList > AnimationLayers;
AnimationLayers _animationsPlaying;
// clock
double _lastUpdate;
};
}
#endif

View File

@@ -0,0 +1,98 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_ANIMATIONMANAGERBASE_H
#define OSGANIMATION_ANIMATIONMANAGERBASE_H
#include <osgAnimation/Animation>
#include <osgAnimation/Export>
#include <osg/FrameStamp>
#include <osg/Group>
namespace osgAnimation
{
class OSGANIMATION_EXPORT AnimationManagerBase : public osg::Group
{
public:
typedef std::set<osg::ref_ptr<Target> > TargetSet;
struct UpdateCallback : public osg::NodeCallback
{
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
AnimationManagerBase* b = dynamic_cast<AnimationManagerBase*>(node);
if (b)
{
if (b->needToLink())
{
/** manager need to link, it means that an animation has been added
so we need to relink all item animated with all animations.
We apply the linker visitor on the manager node to affect
all its children.
But it should not be done here, it should be done in the
update of AnimationManager
*/
b->link();
}
const osg::FrameStamp* fs = nv->getFrameStamp();
b->update(fs->getSimulationTime());
}
}
traverse(node,nv);
}
};
AnimationManagerBase();
AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) :
osg::Group(b,copyop)
{
_animations = b._animations;
_targets = b._targets;
_needToLink = b._needToLink;
}
virtual ~AnimationManagerBase();
virtual void update (double time) = 0;
virtual void buildTargetReference();
virtual void registerAnimation (Animation* animation);
virtual void link();
virtual bool needToLink() const;
const AnimationList& getAnimationList() const { return _animations;}
AnimationMap getAnimationMap() const;
void clearTargets()
{
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->reset();
}
void normalizeTargets()
{
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->normalize();
}
protected:
AnimationList _animations;
TargetSet _targets;
bool _needToLink;
};
}
#endif

View File

@@ -0,0 +1,49 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_ASSERT_H
#define OSGANIMATION_ASSERT_H
#include <string>
#include <sstream>
#include <exception>
namespace osgAnimation
{
struct ThrowAssert : public std::exception
{
virtual const char* what() const throw () { return mMsg.c_str();}
std::string mMsg;
ThrowAssert(const std::string& msg, const char* file, int line )
{
std::stringstream ss;
ss << "Assert (" << msg << ") in file " << file << " at line " << line;
mMsg = ss.str();
}
ThrowAssert() {}
virtual ~ThrowAssert() throw () {}
};
}
#ifdef OSGANIMATION_ASSERT_THROW
#define OSGANIMATION_ASSERT(a) if (!(a)) throw osgAnimation::ThrowAssert(std::string(#a),__FILE__,__LINE__);
#else
#define OSGANIMATION_ASSERT(a) {if (!(a)) *((int*)0) = 0;}
#endif
#endif

300
include/osgAnimation/Bone Normal file
View File

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

View File

@@ -0,0 +1,136 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_CHANNEL_H
#define OSGANIMATION_CHANNEL_H
#include <osgAnimation/Export>
#include <osgAnimation/Sampler>
#include <osgAnimation/Target>
#include <osgAnimation/Assert>
#include <osg/Referenced>
#include <string>
namespace osgAnimation
{
class OSGANIMATION_EXPORT Channel : public osg::Referenced
{
public:
Channel();
virtual ~Channel();
virtual void update(float time) = 0;
virtual void reset() = 0;
virtual Target* getTarget() = 0;
const std::string& getName() const;
void setName(const std::string& name);
virtual float getStartTime() const = 0;
virtual float getEndTime() const = 0;
const std::string& getTargetName() const;
void setTargetName(const std::string& name);
float getWeight() const;
void setWeight(float w);
virtual Sampler* getSampler() = 0;
virtual const Sampler* getSampler() const = 0;
protected:
std::string _targetName;
std::string _name;
float _weight;
};
template <typename SamplerType>
class TemplateChannel : public Channel
{
public:
typedef typename SamplerType::UsingType UsingType;
typedef TemplateTarget<UsingType> TargetType;
typedef TemplateKeyframeContainer<typename SamplerType::KeyframeType> KeyframeContainerType;
TemplateChannel (SamplerType* s = 0,TargetType* target = 0)
{
if (target)
_target = target;
else
_target = new TargetType;
_sampler = s;
}
virtual ~TemplateChannel() {}
virtual void update(float time)
{
// skip if weight == 0
if (_weight < 1e-4)
return;
typename SamplerType::UsingType value;
_sampler->getValueAt(time, value);
_target->update(_weight, value);
}
virtual void reset() { _target->reset(); }
virtual Target* getTarget() { return _target.get();}
SamplerType* getOrCreateSampler()
{
if (!_sampler.valid())
_sampler = new SamplerType;
return _sampler.get();
}
Sampler* getSampler() { return _sampler.get(); }
const Sampler* getSampler() const { return _sampler.get(); }
SamplerType* getSamplerTyped() { return _sampler.get();}
const SamplerType* getSamplerTyped() const { return _sampler.get();}
void setSampler(SamplerType* sampler) { _sampler = sampler; }
TargetType* getTargetTyped() { return _target.get(); }
void setTarget(TargetType* target) { _target = target; }
virtual float getStartTime() const { OSGANIMATION_ASSERT(_sampler.valid() && "no sampler attached to channel"); return _sampler->getStartTime(); }
virtual float getEndTime() const { OSGANIMATION_ASSERT(_sampler.valid() && "no sampler attached to channel"); return _sampler->getEndTime(); }
protected:
osg::ref_ptr<TargetType> _target;
osg::ref_ptr<SamplerType> _sampler;
};
typedef std::vector<osg::ref_ptr<osgAnimation::Channel> > ChannelList;
typedef TemplateChannel<DoubleLinearSampler> DoubleLinearChannel;
typedef TemplateChannel<FloatLinearSampler> FloatLinearChannel;
typedef TemplateChannel<Vec2LinearSampler> Vec2LinearChannel;
typedef TemplateChannel<Vec3LinearSampler> Vec3LinearChannel;
typedef TemplateChannel<Vec4LinearSampler> Vec4LinearChannel;
typedef TemplateChannel<QuatSphericalLinearSampler> QuatSphericalLinearChannel;
typedef TemplateChannel<FloatCubicBezierSampler> FloatCubicBezierChannel;
typedef TemplateChannel<DoubleCubicBezierSampler> DoubleCubicBezierChannel;
typedef TemplateChannel<Vec2CubicBezierSampler> Vec2CubicBezierChannel;
typedef TemplateChannel<Vec3CubicBezierSampler> Vec3CubicBezierChannel;
typedef TemplateChannel<Vec4CubicBezierSampler> Vec4CubicBezierChannel;
}
#endif

View File

@@ -0,0 +1,56 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_CUBIC_BEZIER_H
#define OSGANIMATION_CUBIC_BEZIER_H
#include <osg/Vec2>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
namespace osgAnimation
{
template <class T>
struct TemplateCubicBezier
{
T mPoint[3];
const T& getP0() const { return mPoint[0];}
const T& getP1() const { return mPoint[1];}
const T& getP2() const { return mPoint[2];}
TemplateCubicBezier(const T& v0, const T& v1, const T& v2)
{
mPoint[0] = v0;
mPoint[1] = v1;
mPoint[2] = v2;
}
TemplateCubicBezier() {}
const T& getPosition() const { return mPoint[0];}
const T& getTangentPoint1() const { return mPoint[1];}
const T& getTangentPoint2() const { return mPoint[2];}
};
typedef TemplateCubicBezier<float> FloatCubicBezier;
typedef TemplateCubicBezier<double> DoubleCubicBezier;
typedef TemplateCubicBezier<osg::Vec2> Vec2CubicBezier;
typedef TemplateCubicBezier<osg::Vec3> Vec3CubicBezier;
typedef TemplateCubicBezier<osg::Vec4> Vec4CubicBezier;
}
#endif

View File

@@ -0,0 +1,238 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_EASE_MOTION_H
#define OSGANIMATION_EASE_MOTION_H
namespace osgAnimation {
struct LinearFunction
{
inline static void getValueAt(float t, float& result) { result = t;}
};
struct OutBounceFunction
{
inline static void getValueAt(float t, float& result)
{
if ((t) < (1/2.75))
{
result = 7.5625 * t * t;
}
else if (t < (2/2.75))
{
t = t - (1.5/2.75);
result = 7.5625* t * t + .75;
}
else if (t < (2.5/2.75))
{
t = t - (2.25/2.75);
result = 7.5625 * t * t + .9375;
}
else
{
t = t - (2.625/2.75);
result = 7.5625* t * t + .984375;
}
}
};
struct InBounceFunction
{
inline static void getValueAt(float t, float& result)
{
OutBounceFunction::getValueAt(1-t, result);
result = 1 - result;
}
};
struct InOutBounceFunction
{
inline static void getValueAt(float t, float& result)
{
if (t < 0.5)
{
InBounceFunction::getValueAt(t * 2, result);
result *= 0.5;
}
else
{
OutBounceFunction::getValueAt(t * 2 - 1 , result);
result = result * 0.5 + 0.5;
}
}
};
struct OutQuadFunction
{
inline static void getValueAt(float t, float& result) { result = - (t * (t -2.0));}
};
struct InQuadFunction
{
inline static void getValueAt(float t, float& result) { result = t*t;}
};
struct InOutQuadFunction
{
inline static void getValueAt(float t, float& result)
{
t = t * 2.0;
if (t < 1.0)
result = 0.5 * t * t;
else
{
t = t - 1.0;
result = - 0.5 * t * ( t - 2) - 1;
}
}
};
struct OutCubicFunction
{
inline static void getValueAt(float t, float& result) { t = t-1.0; result = t*t*t + 1;}
};
struct InCubicFunction
{
inline static void getValueAt(float t, float& result) { result = t*t*t;}
};
struct InOutCubicFunction
{
inline static void getValueAt(float t, float& result)
{
t = t * 2;
if (t < 1.0)
result = 0.5 * t * t * t;
else {
t = t - 2;
result = 0.5 * t * t * t + 2;
}
}
};
class Motion
{
public:
typedef float value_type;
enum TimeBehaviour
{
CLAMP,
LOOP,
};
Motion(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : _time(0), _b(startValue), _c(changeValue), _d(duration), _behaviour(tb) {}
virtual ~Motion() {}
void reset() { setTime(0);}
float getTime() const { return _time; }
void update(float dt)
{
_time += dt;
switch (_behaviour)
{
case CLAMP:
if (_time > _d)
_time = _d;
else if (_time < 0.0)
_time = 0.0;
break;
case LOOP:
_time = fmodf(_time, _d);
break;
}
}
void setTime(float time) { _time = time; update(0);}
void getValue(value_type& result) const { getValueAt(_time, result); }
value_type getValue() const
{
value_type result;
getValueAt(_time, result);
return result;
}
void getValueAt(float time, value_type& result) const
{
getValueInNormalizedRange(time/_d, result);
result = result * _c + _b;
}
value_type getValueAt(float time) const
{
value_type result;
getValueAt(time, result);
return result;
}
virtual void getValueInNormalizedRange(float t, value_type& result) const = 0;
protected:
float _time;
float _b;
float _c;
float _d;
TimeBehaviour _behaviour;
};
template <typename T>
struct MathMotionTemplate : public Motion
{
MathMotionTemplate(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : Motion(startValue, duration, changeValue, tb) {}
virtual void getValueInNormalizedRange(float t, value_type& result) const { T::getValueAt(t, result); }
};
template <class T>
struct SamplerMotionTemplate : public Motion
{
T _sampler;
SamplerMotionTemplate(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : Motion(startValue, duration, changeValue, tb) {}
T& getSampler() { return _sampler;}
const T& getSampler() const { return _sampler;}
virtual void getValueInNormalizedRange(float t, value_type& result) const
{
if (!_sampler.getKeyframeContainer())
{
result = 0;
return;
}
float size = _sampler.getEndTime() - _sampler.getStartTime();
t = t * size + _sampler.getStartTime();
_sampler.getValueAt(t, result);
}
};
// linear
typedef MathMotionTemplate<LinearFunction > LinearMotion;
// cubic
typedef MathMotionTemplate<OutCubicFunction > OutCubicMotion;
typedef MathMotionTemplate<InCubicFunction> InCubicMotion;
typedef MathMotionTemplate<InOutCubicFunction> InOutCubicMotion;
// quad
typedef MathMotionTemplate<OutQuadFunction > OutQuadMotion;
typedef MathMotionTemplate<InQuadFunction> InQuadMotion;
typedef MathMotionTemplate<InOutQuadFunction> InOutQuadMotion;
// bounce
typedef MathMotionTemplate<OutBounceFunction > OutBounceMotion;
typedef MathMotionTemplate<InBounceFunction> InBounceMotion;
typedef MathMotionTemplate<InOutBounceFunction> InOutBounceMotion;
}
#endif

View File

@@ -0,0 +1,65 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
// The following symbol has a underscore suffix for compatibility.
#ifndef OSGANIMATION_EXPORT_
#define OSGANIMATION_EXPORT_ 1
#if defined(_MSC_VER)
#pragma warning( disable : 4244 )
#pragma warning( disable : 4251 )
#pragma warning( disable : 4267 )
#pragma warning( disable : 4275 )
#pragma warning( disable : 4290 )
#pragma warning( disable : 4786 )
#pragma warning( disable : 4305 )
#pragma warning( disable : 4996 )
#endif
#if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) || defined( __BCPLUSPLUS__) || defined( __MWERKS__)
# if defined( OSG_LIBRARY_STATIC )
# define OSGANIMATION_EXPORT
# elif defined( OSGANIMATION_LIBRARY )
# define OSGANIMATION_EXPORT __declspec(dllexport)
# else
# define OSGANIMATION_EXPORT __declspec(dllimport)
#endif
#else
#define OSGANIMATION_EXPORT
#endif
// set up define for whether member templates are supported by VisualStudio compilers.
#ifdef _MSC_VER
# if (_MSC_VER >= 1300)
# define __STL_MEMBER_TEMPLATES
# endif
#endif
/* Define NULL pointer value */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
/**
\namespace osgAnimation
The osgAnimation library provides general purpose utility classes for animation.
*/
#endif

View File

@@ -0,0 +1,206 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_INTERPOLATOR_H
#define OSGANIMATION_INTERPOLATOR_H
#include <osgAnimation/Assert>
#include <osgAnimation/Interpolator>
#include <osgAnimation/Keyframe>
namespace osgAnimation
{
template <class TYPE, class KEY>
class TemplateInterpolatorBase
{
public:
typedef KEY KeyframeType;
typedef TYPE UsingType;
public:
mutable int _lastKeyAccess;
TemplateInterpolatorBase() : _lastKeyAccess(-1) {}
void reset() { _lastKeyAccess = -1; }
int getKeyIndexFromTime(const TemplateKeyframeContainer<KEY>& keys, float time) const
{
OSGANIMATION_ASSERT(!keys.empty() && "no keys");
OSGANIMATION_ASSERT(time >= keys.front().getTime() && time <= keys.back().getTime() && "bad range");
// todo use a cache
int key_size = keys.size();
const TemplateKeyframe<KeyframeType>* keysVector = &keys.front();
for (int i = 0; i < key_size-1; i++)
{
float time0 = keysVector[i].getTime();
float time1 = keysVector[i+1].getTime();
#ifndef OSGANIMATION_NO_EXTRA_CHECK
if ( time0>time1 )
OSGANIMATION_ASSERT(0 && "invalid input data");
#endif
if ( time >= time0 && time < time1 )
{
_lastKeyAccess = i;
return i;
}
}
std::cout << time << " first key " << keysVector[0].getTime() << " last key " << keysVector[key_size-1].getTime() << std::endl;
*((int *)0) = 0;
OSGANIMATION_ASSERT(0 && "impossible has happened");
return -1;
}
};
template <class TYPE, class KEY=TYPE>
class TemplateLinearInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
public:
TemplateLinearInterpolator() {}
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, float time, TYPE& result) const
{
if (time >= keyframes.back().getTime())
{
result = keyframes.back().getValue();
return;
}
else if (time <= keyframes.front().getTime())
{
result = keyframes.front().getValue();
return;
}
int i = getKeyIndexFromTime(keyframes,time);
float blend = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
const TYPE& v1 = keyframes[i].getValue();
const TYPE& v2 = keyframes[i+1].getValue();
result = v1*(1-blend) + v2*blend;
}
};
template <class TYPE, class KEY=TYPE>
class TemplateSphericalLinearInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
public:
TemplateSphericalLinearInterpolator() {}
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, float time, TYPE& result) const
{
if (time >= keyframes.back().getTime())
{
result = keyframes.back().getValue();
return;
}
else if (time <= keyframes.front().getTime())
{
result = keyframes.front().getValue();
return;
}
int i = getKeyIndexFromTime(keyframes,time);
float blend = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
const TYPE& q1 = keyframes[i].getValue();
const TYPE& q2 = keyframes[i+1].getValue();
result.slerp(blend,q1,q2);
}
};
template <class TYPE, class KEY>
class TemplateLinearPackedInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
public:
TemplateLinearPackedInterpolator() {}
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, float time, TYPE& result) const
{
if (time >= keyframes.back().getTime())
{
keyframes.back().getValue().uncompress(keyframes.mScale, keyframes.mMin, result);
return;
}
else if (time <= keyframes.front().getTime())
{
keyframes.front().getValue().uncompress(keyframes.mScale, keyframes.mMin, result);
return;
}
int i = getKeyIndexFromTime(keyframes,time);
float blend = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
TYPE v1,v2;
keyframes[i].getValue().uncompress(keyframes.mScale, keyframes.mMin, v1);
keyframes[i+1].getValue().uncompress(keyframes.mScale, keyframes.mMin, v2);
result = v1*(1-blend) + v2*blend;
}
};
// http://en.wikipedia.org/wiki/B%C3%A9zier_curve
template <class TYPE, class KEY=TYPE>
class TemplateCubicBezierInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
public:
TemplateCubicBezierInterpolator() {}
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, float time, TYPE& result) const
{
if (time >= keyframes.back().getTime())
{
result = keyframes.back().getValue().getPosition();
return;
}
else if (time <= keyframes.front().getTime())
{
result = keyframes.front().getValue().getPosition();
return;
}
int i = getKeyIndexFromTime(keyframes,time);
float t = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
float one_minus_t = 1.0-t;
float one_minus_t2 = one_minus_t * one_minus_t;
float one_minus_t3 = one_minus_t2 * one_minus_t;
float t2 = t * t;
TYPE v0 = keyframes[i].getValue().getPosition() * one_minus_t3;
TYPE v1 = keyframes[i].getValue().getTangentPoint1() * (3.0 * t * one_minus_t2);
TYPE v2 = keyframes[i].getValue().getTangentPoint2() * (3.0 * t2 * one_minus_t);
TYPE v3 = keyframes[i+1].getValue().getPosition() * (t2 * t);
result = v0 + v1 + v2 + v3;
}
};
typedef TemplateLinearInterpolator<double, double> DoubleLinearInterpolator;
typedef TemplateLinearInterpolator<float, float> FloatLinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec2, osg::Vec2> Vec2LinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec3, osg::Vec3> Vec3LinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec3, Vec3Packed> Vec3PackedLinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec4, osg::Vec4> Vec4LinearInterpolator;
typedef TemplateSphericalLinearInterpolator<osg::Quat, osg::Quat> QuatSphericalLinearInterpolator;
typedef TemplateCubicBezierInterpolator<float, FloatCubicBezier > FloatCubicBezierInterpolator;
typedef TemplateCubicBezierInterpolator<double, DoubleCubicBezier> DoubleCubicBezierInterpolator;
typedef TemplateCubicBezierInterpolator<osg::Vec2, Vec2CubicBezier> Vec2CubicBezierInterpolator;
typedef TemplateCubicBezierInterpolator<osg::Vec3, Vec3CubicBezier> Vec3CubicBezierInterpolator;
typedef TemplateCubicBezierInterpolator<osg::Vec4, Vec4CubicBezier> Vec4CubicBezierInterpolator;
}
#endif

View File

@@ -0,0 +1,130 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_KEYFRAME_H
#define OSGANIMATION_KEYFRAME_H
#include <string>
#include <osg/Referenced>
#include <osgAnimation/Vec3Packed>
#include <osgAnimation/CubicBezier>
#include <osg/Quat>
#include <osg/Vec4>
#include <osg/Vec3>
#include <osg/Vec2>
namespace osgAnimation
{
class Keyframe
{
public:
float getTime() const { return _time; }
void setTime(float time) { _time = time; }
protected:
float _time;
};
template <class T>
class TemplateKeyframe : public Keyframe
{
protected:
T _value;
public:
TemplateKeyframe () {}
~TemplateKeyframe () {}
TemplateKeyframe (float time, const T& value)
{
_time = time;
_value = value;
}
void setValue(const T& value) { _value = value;}
const T& getValue() const { return _value;}
};
class KeyframeContainer : public osg::Referenced
{
public:
KeyframeContainer() {}
virtual unsigned int size() const = 0;
protected:
~KeyframeContainer() {}
std::string _name;
};
template <class T>
class TemplateKeyframeContainer : public std::vector<TemplateKeyframe<T> >, public KeyframeContainer
{
public:
// const char* getKeyframeType() { return #T ;}
TemplateKeyframeContainer() {}
typedef TemplateKeyframe<T> KeyType;
virtual unsigned int size() const { return (unsigned int)std::vector<TemplateKeyframe<T> >::size(); }
};
template <>
class TemplateKeyframeContainer<Vec3Packed> : public std::vector<TemplateKeyframe<Vec3Packed> >, public KeyframeContainer
{
public:
typedef TemplateKeyframe<Vec3Packed> KeyType;
TemplateKeyframeContainer() {}
const char* getKeyframeType() { return "Vec3Packed" ;}
void init(const osg::Vec3f& min, const osg::Vec3f& scale) { _min = min; _scale = scale; }
osg::Vec3f _min;
osg::Vec3f _scale;
};
typedef TemplateKeyframe<float> FloatKeyframe;
typedef TemplateKeyframeContainer<float> FloatKeyframeContainer;
typedef TemplateKeyframe<osg::Vec2> Vec2Keyframe;
typedef TemplateKeyframeContainer<osg::Vec2> Vec2KeyframeContainer;
typedef TemplateKeyframe<osg::Vec3> Vec3Keyframe;
typedef TemplateKeyframeContainer<osg::Vec3> Vec3KeyframeContainer;
typedef TemplateKeyframe<osg::Vec4> Vec4Keyframe;
typedef TemplateKeyframeContainer<osg::Vec4> Vec4KeyframeContainer;
typedef TemplateKeyframe<osg::Quat> QuatKeyframe;
typedef TemplateKeyframeContainer<osg::Quat> QuatKeyframeContainer;
typedef TemplateKeyframe<Vec3Packed> Vec3PackedKeyframe;
typedef TemplateKeyframeContainer<Vec3Packed> Vec3PackedKeyframeContainer;
typedef TemplateKeyframe<FloatCubicBezier> FloatCubicBezierKeyframe;
typedef TemplateKeyframeContainer<FloatCubicBezier> FloatCubicBezierKeyframeContainer;
typedef TemplateKeyframe<DoubleCubicBezier> DoubleCubicBezierKeyframe;
typedef TemplateKeyframeContainer<DoubleCubicBezier> DoubleCubicBezierKeyframeContainer;
typedef TemplateKeyframe<Vec2CubicBezier> Vec2CubicBezierKeyframe;
typedef TemplateKeyframeContainer<Vec2CubicBezier> Vec2CubicBezierKeyframeContainer;
typedef TemplateKeyframe<Vec3CubicBezier> Vec3CubicBezierKeyframe;
typedef TemplateKeyframeContainer<Vec3CubicBezier> Vec3CubicBezierKeyframeContainer;
typedef TemplateKeyframe<Vec4CubicBezier> Vec4CubicBezierKeyframe;
typedef TemplateKeyframeContainer<Vec4CubicBezier> Vec4CubicBezierKeyframeContainer;
}
#endif

View File

@@ -0,0 +1,50 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_NODE_VISITOR_H
#define OSGANIMATION_NODE_VISITOR_H
#include <osg/NodeVisitor>
#include <osgAnimation/Animation>
#include <osgAnimation/UpdateCallback>
namespace osgAnimation
{
struct LinkVisitor : public osg::NodeVisitor
{
AnimationList _animations;
unsigned int _nbLinkedTarget;
LinkVisitor(Animation* animation) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _animations.push_back(animation); _nbLinkedTarget = 0;}
LinkVisitor(const AnimationList& animations) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _animations = animations; _nbLinkedTarget = 0;}
void apply(osg::Node& node)
{
osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(node.getUpdateCallback());
if (cb)
{
int result = 0;
for (int i = 0; i < (int)_animations.size(); i++)
{
result += cb->link(_animations[i].get());
_nbLinkedTarget += result;
}
std::cout << "LinkVisitor links " << result << " for \"" << cb->getName() << '"' << std::endl;
}
traverse(node);
}
};
}
#endif

View File

@@ -0,0 +1,159 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_RIGGEOMETRY_H
#define OSGANIMATION_RIGGEOMETRY_H
#include <osgAnimation/Export>
#include <osgAnimation/Skinning>
#include <osgAnimation/Skeleton>
#include <osg/Geometry>
namespace osgAnimation
{
class OSGANIMATION_EXPORT RigGeometry : public osg::Geometry
{
public:
struct FindNearestParentSkeleton : public osg::NodeVisitor
{
osg::ref_ptr<osgAnimation::Skeleton> _root;
FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {}
void apply(osg::Transform& node)
{
if (_root.valid())
return;
_root = dynamic_cast<osgAnimation::Skeleton*>(&node);
traverse(node);
}
};
struct UpdateVertex : public osg::Drawable::UpdateCallback
{
virtual void update(osg::NodeVisitor*, osg::Drawable* drw)
{
RigGeometry* geom = dynamic_cast<RigGeometry*>(drw);
if (!geom)
return;
if (!geom->getSkeleton() && !geom->getParents().empty())
{
FindNearestParentSkeleton finder;
if (geom->getParents().size() > 1)
osg::notify(osg::WARN) << "A RigGeometry should not have multi parent ( " << geom->getName() << " )" << std::endl;
geom->getParents()[0]->accept(finder);
if (!finder._root.valid())
return;
geom->buildVertexSet();
geom->buildTransformer(finder._root.get());
}
if (!geom->getSkeleton())
return;
if (geom->getNeedToComputeMatrix())
geom->computeMatrixFromRootSkeleton();
geom->transformSoftwareMethod();
}
};
/** BuildVertexTransformerVisitor is used to setup RigGeometry drawable
* throw a subgraph.
*/
struct BuildVertexTransformerVisitor : public osg::NodeVisitor
{
osg::ref_ptr<Skeleton> _root;
BuildVertexTransformerVisitor(Skeleton* root): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _root = root;}
void apply(osg::Geode& node)
{
int num = node.getNumDrawables();
for (int i = 0; i < num; i++) {
RigGeometry* geom = dynamic_cast<RigGeometry*>(node.getDrawable(i));
if (geom)
{
geom->buildVertexSet();
geom->buildTransformer(_root.get());
}
}
}
};
RigGeometry()
{
setUseDisplayList(false);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
_needToComputeMatrix = true;
_matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity();
}
RigGeometry(const osg::Geometry& b) : osg::Geometry(b, osg::CopyOp::SHALLOW_COPY)
{
setUseDisplayList(false);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
_needToComputeMatrix = true;
_matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity();
}
RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) :
osg::Geometry(b,copyop),
_positionSource(b._positionSource),
_normalSource(b._normalSource),
_vertexInfluenceSet(b._vertexInfluenceSet),
_vertexInfluenceMap(b._vertexInfluenceMap),
_transformVertexes(b._transformVertexes),
_needToComputeMatrix(b._needToComputeMatrix) {}
virtual osg::Object* cloneType() const { return new RigGeometry(); }
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new RigGeometry(*this,copyop); }
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const RigGeometry*>(obj)!=NULL; }
virtual const char* libraryName() const { return "osgAnimation"; }
virtual const char* className() const { return "RigGeometry"; }
void setInfluenceMap(osgAnimation::VertexInfluenceMap* vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; }
const osgAnimation::VertexInfluenceMap* getInfluenceMap() const { return _vertexInfluenceMap.get();}
osgAnimation::VertexInfluenceMap* getInfluenceMap() { return _vertexInfluenceMap.get();}
void buildVertexSet();
void buildTransformer(Skeleton* root);
void computeMatrixFromRootSkeleton();
void setNeedToComputeMatrix(bool state) { _needToComputeMatrix = state;}
bool getNeedToComputeMatrix() const { return _needToComputeMatrix;}
const Skeleton* getSkeleton() const;
Skeleton* getSkeleton();
virtual void transformSoftwareMethod();
const osgAnimation::VertexInfluenceSet& getVertexInfluenceSet() const { return _vertexInfluenceSet;}
std::vector<osg::Vec3> _positionSource;
std::vector<osg::Vec3> _normalSource;
osgAnimation::VertexInfluenceSet _vertexInfluenceSet;
osg::ref_ptr<osgAnimation::VertexInfluenceMap> _vertexInfluenceMap;
osgAnimation::TransformVertexFunctor _transformVertexes;
osg::Matrix _matrixFromSkeletonToGeometry;
osg::Matrix _invMatrixFromSkeletonToGeometry;
osg::observer_ptr<Skeleton> _root;
bool _needToComputeMatrix;
};
}
#endif

View File

@@ -0,0 +1,124 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_SAMPLER_H
#define OSGANIMATION_SAMPLER_H
#include <vector>
#include <iostream>
#include <osg/Referenced>
#include <osg/ref_ptr>
#include <osgAnimation/Keyframe>
#include <osgAnimation/Interpolator>
#include <osgAnimation/Assert>
namespace osgAnimation
{
class Sampler : public osg::Referenced
{
public:
virtual KeyframeContainer* getKeyframeContainer() = 0;
virtual const KeyframeContainer* getKeyframeContainer() const = 0;
protected:
};
// Sampler generic
template <class F>
class TemplateSampler : public Sampler
{
public:
typedef typename F::KeyframeType KeyframeType;
typedef TemplateKeyframeContainer<KeyframeType> KeyframeContainerType;
typedef typename F::UsingType UsingType;
typedef F FunctorType;
TemplateSampler() {}
~TemplateSampler() {}
void getValueAt(float time, UsingType& result) const { _functor.getValue(*_keyframes, time, result);}
void setKeyframeContainer(KeyframeContainerType* kf) { _keyframes = kf;}
virtual KeyframeContainer* getKeyframeContainer() { return _keyframes.get(); }
virtual const KeyframeContainer* getKeyframeContainer() const { return _keyframes.get();}
KeyframeContainerType* getKeyframeContainerTyped() { return _keyframes.get();}
const KeyframeContainerType* getKeyframeContainerTyped() const { return _keyframes.get();}
KeyframeContainerType* getOrCreateKeyframeContainer()
{
if (_keyframes != 0)
return _keyframes.get();
_keyframes = new KeyframeContainerType;
return _keyframes.get();
}
float getStartTime() const
{
OSGANIMATION_ASSERT(_keyframes.valid() && !_keyframes->empty() && "no keyframes");
return _keyframes->front().getTime();
}
float getEndTime() const
{
OSGANIMATION_ASSERT(_keyframes.valid() && !_keyframes->empty() && "no keyframes");
return _keyframes->back().getTime();
}
protected:
FunctorType _functor;
osg::ref_ptr<KeyframeContainerType> _keyframes;
};
template<typename VALUESAMPLERTYPE, typename TIMESAMPLERTYPE>
class TemplateCompositeSampler : public osg::Referenced
{
VALUESAMPLERTYPE& _value;
TIMESAMPLERTYPE& _time;
public:
typedef typename VALUESAMPLERTYPE::FunctorType::UsingType UsingType;
typedef typename VALUESAMPLERTYPE::FunctorType::KeyframeType KeyframeType;
TemplateCompositeSampler(VALUESAMPLERTYPE& value, TIMESAMPLERTYPE& time) : _value(value), _time(time)
{
}
void getValueAt(float time, typename VALUESAMPLERTYPE::FunctorType::UsingType& result)
{
float newtime;
_time.getValueAt(time, newtime);
_value.getValueAt(newtime, result);
}
float getStartTime() const {return _time.getStartTime(); }
float getEndTime() const {return _time.getEndTime();}
};
typedef TemplateSampler<DoubleLinearInterpolator> DoubleLinearSampler;
typedef TemplateSampler<FloatLinearInterpolator> FloatLinearSampler;
typedef TemplateSampler<Vec2LinearInterpolator> Vec2LinearSampler;
typedef TemplateSampler<Vec3LinearInterpolator> Vec3LinearSampler;
typedef TemplateSampler<Vec4LinearInterpolator> Vec4LinearSampler;
typedef TemplateSampler<QuatSphericalLinearInterpolator> QuatSphericalLinearSampler;
typedef TemplateSampler<FloatCubicBezierInterpolator> FloatCubicBezierSampler;
typedef TemplateSampler<DoubleCubicBezierInterpolator> DoubleCubicBezierSampler;
typedef TemplateSampler<Vec2CubicBezierInterpolator> Vec2CubicBezierSampler;
typedef TemplateSampler<Vec3CubicBezierInterpolator> Vec3CubicBezierSampler;
typedef TemplateSampler<Vec4CubicBezierInterpolator> Vec4CubicBezierSampler;
};
#endif

View File

@@ -0,0 +1,44 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_SKELETON_H
#define OSGANIMATION_SKELETON_H
#include <osg/MatrixTransform>
#include <osgAnimation/Bone>
#include <osgAnimation/Export>
namespace osgAnimation
{
class OSGANIMATION_EXPORT Skeleton : public Bone
{
public:
META_Node(osgAnimation, Skeleton);
struct UpdateCallback : public osg::NodeCallback
{
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
};
Skeleton(const Skeleton& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : Bone(b,copyop) {}
Skeleton();
void computeBindMatrix() { _invBindInSkeletonSpace = osg::Matrix::inverse(_bindInBoneSpace); }
};
}
#endif

View File

@@ -0,0 +1,167 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_SKINNING_H
#define OSGANIMATION_SKINNING_H
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>
#include <osgAnimation/Assert>
#include <osgAnimation/VertexInfluence>
#include <osgAnimation/Bone>
#include <osg/Matrix>
#include <osg/Vec3>
#include <osg/Quat>
namespace osgAnimation
{
class TransformVertexFunctor
{
public:
typedef osg::Matrix MatrixType;
typedef osgAnimation::Bone BoneType;
typedef Bone::BoneMap BoneMap;
class BoneWeight
{
public:
BoneWeight(BoneType* bone, float weight) : _bone(bone), _weight(weight) {}
const BoneType* getBone() const { return &(*_bone); }
float getWeight() const { return _weight; }
protected:
osg::ref_ptr<BoneType> _bone;
float _weight;
};
typedef std::vector<BoneWeight> BoneWeightList;
typedef std::vector<int> VertexList;
class UniqBoneSetVertexSet
{
public:
BoneWeightList& getBones() { return _bones; }
VertexList& getVertexes() { return _vertexes; }
void computeMatrixForVertexSet()
{
if (_bones.empty())
{
osg::notify(osg::WARN) << "TransformVertexFunctor::UniqBoneSetVertexSet no bones found" << std::endl;
_result = MatrixType::identity();
return;
}
_result = MatrixType(0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0);
int size = _bones.size();
for (int i = 0; i < size; i++)
{
const BoneType* bone = _bones[i].getBone();
const MatrixType& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace();
const MatrixType& matrix = bone->getMatrixInSkeletonSpace();
double w = _bones[i].getWeight();
_result = _result + ( (invBindMatrix * matrix ) * w);
}
}
const MatrixType& getMatrix() const { return _result;}
protected:
BoneWeightList _bones;
VertexList _vertexes;
MatrixType _result;
};
void init(const BoneMap& map, const osgAnimation::VertexInfluenceSet::UniqVertexSetToBoneSetList& influence)
{
_boneSetVertexSet.clear();
int size = influence.size();
_boneSetVertexSet.resize(size);
for (int i = 0; i < size; i++)
{
const osgAnimation::VertexInfluenceSet::UniqVertexSetToBoneSet& inf = influence[i];
int nbBones = inf.getBones().size();
for (int b = 0; b < nbBones; b++)
{
const std::string& bname = inf.getBones()[b].getBoneName();
float weight = inf.getBones()[b].getWeight();
if (map.find(bname) == map.end())
{
std::cerr << "Warning TransformVertexFunctor Bone " << bname << " not found, skip the influence group " <<bname << std::endl;
continue;
}
BoneMap::const_iterator it = map.find(bname);
if (it == map.end())
std::cerr << "Warning TransformVertexFunctor does not find bone " << bname << " in the map" << std::endl;
BoneType* bone = it->second.get();
_boneSetVertexSet[i].getBones().push_back(BoneWeight(bone, weight));
}
_boneSetVertexSet[i].getVertexes() = inf.getVertexes();
}
}
template <class V> void compute(const V* src, V* dst)
{
OSGANIMATION_ASSERT(src != dst);
int size = _boneSetVertexSet.size();
for (int i = 0; i < size; i++)
{
UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i];
uniq.computeMatrixForVertexSet();
const MatrixType& matrix = uniq.getMatrix();
const VertexList& vertexes = uniq.getVertexes();
int vertexSize = vertexes.size();
for (int j = 0; j < vertexSize; j++)
{
int idx = vertexes[j];
dst[idx] = src[idx] * matrix;
}
}
}
template <class V> void compute(const MatrixType& transform, const MatrixType& invTransform, const V* src, V* dst)
{
OSGANIMATION_ASSERT(src != dst);
int size = _boneSetVertexSet.size();
for (int i = 0; i < size; i++)
{
UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i];
uniq.computeMatrixForVertexSet();
MatrixType matrix = transform * uniq.getMatrix() * invTransform;
const VertexList& vertexes = uniq.getVertexes();
int vertexSize = vertexes.size();
for (int j = 0; j < vertexSize; j++)
{
int idx = vertexes[j];
dst[idx] = src[idx] * matrix;
}
}
}
protected:
std::vector<UniqBoneSetVertexSet> _boneSetVertexSet;
};
}
#endif

132
include/osgAnimation/Target Normal file
View File

@@ -0,0 +1,132 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_TARGET_H
#define OSGANIMATION_TARGET_H
#include <vector>
#include <osg/Quat>
#include <osg/Vec3>
#include <osg/Vec2>
#include <osg/Vec4>
#include <osg/Referenced>
#include <osgAnimation/Export>
namespace osgAnimation
{
class Channel;
class OSGANIMATION_EXPORT Target : public osg::Referenced
{
public:
Target();
virtual ~Target();
virtual void normalize() = 0;
float getWeight() const { return _weight; }
void reset() { _weight = 0;}
int getCount() const { return referenceCount(); }
protected:
void addWeight(float w) { _weight += w; }
float _weight;
};
template <class T>
class TemplateTarget : public Target
{
public:
TemplateTarget() {}
TemplateTarget(const T& v) { setValue(v); }
void update(float weight, const T& val)
{
if (!_weight)
_target = val * weight;
else
{
weight = (1.0 - _weight) * weight;
_target += val * weight;
}
addWeight(weight);
}
const T& getValue() const { return _target;}
void normalize()
{
float weightSummed = getWeight();
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1) < 1e-4)
return;
(_target) /= weightSummed;
}
void setValue(const T& value) { _target = value;}
protected:
T _target;
};
// Target Specialisation for Quaternions
template <>
class TemplateTarget< osg::Quat > : public Target
{
public:
TemplateTarget () {}
const osg::Quat& getValue() const { return _target;}
void update(float weight, const osg::Quat& val)
{
if (!_weight)
_target = val * weight;
else
{
weight = (1.0 - _weight) * weight;
_target += val * weight;
}
addWeight(weight);
}
// maybe normalize could be non virtual and put on ITarget
void normalize()
{
float weightSummed = getWeight();
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1.0) < 1e-4)
return;
(_target) /= weightSummed;
}
void setValue(const osg::Quat& value) { _target = value;}
protected:
osg::Quat _target;
};
typedef TemplateTarget<osg::Quat> QuatTarget;
typedef TemplateTarget<osg::Vec3> Vec3Target;
typedef TemplateTarget<osg::Vec4> Vec4Target;
typedef TemplateTarget<osg::Vec2> Vec2Target;
typedef TemplateTarget<float> FloatTarget;
typedef TemplateTarget<double> DoubleTarget;
}
#endif

View File

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

View File

@@ -0,0 +1,68 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_UPDATE_CALLBACK_H
#define OSGANIMATION_UPDATE_CALLBACK_H
#include <osg/Vec3>
#include <osg/NodeCallback>
#include <osg/observer_ptr>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/Export>
namespace osgAnimation
{
class OSGANIMATION_EXPORT AnimationUpdateCallback : public osg::NodeCallback
{
protected:
osg::observer_ptr<osgAnimation::AnimationManagerBase> _manager;
public:
AnimationUpdateCallback(const std::string& name = "") { setName(name); }
AnimationUpdateCallback(const AnimationUpdateCallback& apc,const osg::CopyOp& copyop);
osgAnimation::AnimationManagerBase* getAnimationManager();
virtual bool needLink() const = 0;
virtual bool link(osgAnimation::Channel* channel) = 0;
virtual int link(osgAnimation::Animation* animation);
virtual void updateLink();
};
class OSGANIMATION_EXPORT UpdateTransform : public AnimationUpdateCallback
{
protected:
osg::ref_ptr<osgAnimation::Vec3Target> _euler;
osg::ref_ptr<osgAnimation::Vec3Target> _position;
osg::ref_ptr<osgAnimation::Vec3Target> _scale;
public:
META_Object(osgAnimation, UpdateTransform);
UpdateTransform(const std::string& name = "");
UpdateTransform(const UpdateTransform& apc,const osg::CopyOp& copyop);
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
void update(osg::MatrixTransform& mat);
void update(osg::PositionAttitudeTransform& pat);
bool needLink() const;
bool link(osgAnimation::Channel* channel);
};
}
#endif

View File

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

View File

@@ -0,0 +1,108 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_VERTEX_INFLUENCES_H
#define OSGANIMATION_VERTEX_INFLUENCES_H
#include <osg/Object>
#include <osgAnimation/Export>
#include <map>
#include <vector>
#include <string>
namespace osgAnimation
{
// first is vertex index, and second the weight, the
typedef std::pair<int, float> VertexIndexWeight;
typedef std::vector<VertexIndexWeight> VertexList;
class OSGANIMATION_EXPORT VertexInfluence : public VertexList
{
public:
const std::string& getName() const { return _name;}
void setName(const std::string& name) { _name = name;}
protected:
// the name is the bone to link to
std::string _name;
};
// typedef std::map<std::string, VertexInfluence> VertexInfluenceMap;
class VertexInfluenceMap : public std::map<std::string, VertexInfluence> , public osg::Object
{
public:
META_Object(osgAnimation, VertexInfluenceMap);
VertexInfluenceMap() {}
VertexInfluenceMap(const osgAnimation::VertexInfluenceMap& infl, const osg::CopyOp&) {;}
};
// this class manage VertexInfluence database by mesh
// reference bones per vertex ...
class VertexInfluenceSet
{
public:
typedef std::vector<VertexInfluence> BoneToVertexList;
class BoneWeight
{
public:
BoneWeight(const std::string& name, float weight) : _boneName(name), _weight(weight) {}
const std::string& getBoneName() const { return _boneName; }
float getWeight() const { return _weight; }
void setWeight(float weight) { _weight = weight; }
bool operator==(const BoneWeight& b) const { return (_boneName == b.getBoneName() && _weight == b.getWeight()); }
protected:
std::string _boneName;
float _weight;
};
typedef std::vector<BoneWeight> BoneWeightList;
typedef std::map<int,BoneWeightList> VertexIndexToBoneWeightMap;
class UniqVertexSetToBoneSet
{
public:
void setBones(BoneWeightList& bones) { _bones = bones;}
const BoneWeightList& getBones() const { return _bones;}
std::vector<int>& getVertexes() { return _vertexes;}
const std::vector<int>& getVertexes() const { return _vertexes;}
protected:
std::vector<int> _vertexes;
BoneWeightList _bones; // here we could limit matrix operation by caching (weight * matrix)
};
typedef std::vector<UniqVertexSetToBoneSet> UniqVertexSetToBoneSetList;
const UniqVertexSetToBoneSetList& getUniqVertexSetToBoneSetList() const { return _uniqVertexSetToBoneSet;}
void addVertexInfluence(const VertexInfluence& v) { _bone2Vertexes.push_back(v); }
void buildVertex2BoneList();
void buildUniqVertexSetToBoneSetList();
void clear()
{
_bone2Vertexes.clear();
_bone2Vertexes.clear();
_uniqVertexSetToBoneSet.clear();
}
protected:
BoneToVertexList _bone2Vertexes;
VertexIndexToBoneWeightMap _vertex2Bones;
UniqVertexSetToBoneSetList _uniqVertexSetToBoneSet;
};
}
#endif