2.8 branch: backport of osgAnimation from svn head 11026.

This commit is contained in:
Paul MARTZ
2010-03-13 20:55:16 +00:00
parent 15fd3bdcc2
commit 38e68ed7f1
84 changed files with 6677 additions and 1331 deletions

147
include/osgAnimation/Action Normal file
View File

@@ -0,0 +1,147 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_ACTION_H
#define OSGANIMATION_ACTION_H
#include <osgAnimation/Export>
#include <osgAnimation/Animation>
#include <osgAnimation/ActionVisitor>
#include <osgAnimation/FrameAction>
#include <iostream>
#define META_Action(library,name) \
virtual osg::Object* cloneType() const { return new name (); } \
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new name (*this,copyop); } \
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const name *>(obj)!=NULL; } \
virtual const char* className() const { return #name; } \
virtual const char* libraryName() const { return #library; } \
virtual void accept(osgAnimation::ActionVisitor& nv) { nv.apply(*this); } \
namespace osgAnimation
{
class OSGANIMATION_EXPORT Action : public osg::Object
{
public:
class Callback : public osg::Object
{
public:
Callback(){}
Callback(const Callback& nc,const osg::CopyOp&) :
_nestedCallback(nc._nestedCallback) {}
META_Object(osgAnimation,Callback);
virtual void operator()(Action* action, osgAnimation::ActionVisitor* nv) {}
Callback* getNestedCallback() { return _nestedCallback.get(); }
void addNestedCallback(Callback* callback)
{
if (callback) {
if (_nestedCallback.valid())
_nestedCallback->addNestedCallback(callback);
else
_nestedCallback = callback;
}
}
void removeCallback(Callback* cb)
{
if (!cb)
return;
if (_nestedCallback.get() == cb)
_nestedCallback = _nestedCallback->getNestedCallback();
else if (_nestedCallback.valid())
_nestedCallback->removeCallback(cb);
}
protected:
osg::ref_ptr<Callback> _nestedCallback;
};
typedef std::map<unsigned int, osg::ref_ptr<Callback> > FrameCallback;
META_Action(osgAnimation, Action);
Action();
Action(const Action&,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 removeCallback(Callback*);
Callback* getFrameCallback(unsigned int frame);
Callback* getFrameCallback(double time);
unsigned int getFramesPerSecond() const { return _fps; }
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 );
virtual void traverse(ActionVisitor& visitor) {}
//virtual void evaluate(unsigned int frame);
protected:
FrameCallback _framesCallback;
double _speed;
unsigned int _fps;
unsigned int _numberFrame;
unsigned int _loop;
enum Status
{
Play,
Stop
};
Status _state;
};
}
#endif

View File

@@ -0,0 +1,41 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_ACTION_ANIMATION_H
#define OSGANIMATION_ACTION_ANIMATION_H
#include <osgAnimation/Action>
#include <osgAnimation/Export>
namespace osgAnimation {
class OSGANIMATION_EXPORT ActionAnimation : public Action
{
public:
META_Action(osgAnimation, ActionAnimation);
ActionAnimation();
ActionAnimation(const ActionAnimation& a, const osg::CopyOp& c);
ActionAnimation(Animation* animation);
void updateAnimation(unsigned int frame, int priority);
Animation* getAnimation() { return _animation.get(); }
protected:
osg::ref_ptr<Animation> _animation;
};
}
#endif

View File

@@ -0,0 +1,44 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_ACTION_BLENDIN_H
#define OSGANIMATION_ACTION_BLENDIN_H
#include <osgAnimation/Action>
#include <osgAnimation/Export>
namespace osgAnimation {
/// blend in from 0 to weight in duration
class OSGANIMATION_EXPORT ActionBlendIn : public Action
{
public:
META_Action(osgAnimation, ActionBlendIn);
ActionBlendIn();
ActionBlendIn(const ActionBlendIn& a, const osg::CopyOp& c);
ActionBlendIn(Animation* animation, double duration, double weight);
double getWeight() const { return _weight;}
Animation* getAnimation() { return _animation.get(); }
void computeWeight(unsigned int frame);
protected:
double _weight;
osg::ref_ptr<Animation> _animation;
};
}
#endif

View File

@@ -0,0 +1,45 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_ACTION_BLENDOUT_H
#define OSGANIMATION_ACTION_BLENDOUT_H
#include <osgAnimation/Action>
#include <osgAnimation/Export>
namespace osgAnimation {
/// blend out from weight to 0 in duration
class OSGANIMATION_EXPORT ActionBlendOut : public Action
{
public:
META_Action(osgAnimation, ActionBlendOut);
ActionBlendOut();
ActionBlendOut(const ActionBlendOut& a, const osg::CopyOp& c);
ActionBlendOut(Animation* animation, double duration);
Animation* getAnimation() { return _animation.get(); }
double getWeight() const { return _weight;}
void computeWeight(unsigned int frame);
protected:
double _weight;
osg::ref_ptr<Animation> _animation;
};
}
#endif

View File

@@ -0,0 +1,41 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_ACTION_CALLBACK_H
#define OSGANIMATION_ACTION_CALLBACK_H
#include <osgAnimation/Export>
#include <osgAnimation/Action>
namespace osgAnimation
{
/** Callback used to run new action on the timeline.*/
class OSGANIMATION_EXPORT RunAction : public Action::Callback
{
public:
RunAction(Action* a, int priority = 0) : _action(a), _priority(priority) {}
virtual void operator()(Action* action, ActionVisitor* visitor);
Action* getAction() const { return _action.get(); }
int getPriority() const { return _priority; }
protected:
osg::ref_ptr<Action> _action;
int _priority;
};
}
#endif

View File

@@ -0,0 +1,57 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_ACTION_STRIPANIMATION_H
#define OSGANIMATION_ACTION_STRIPANIMATION_H
#include <osgAnimation/Action>
#include <osgAnimation/Export>
#include <osgAnimation/FrameAction>
#include <osgAnimation/ActionBlendIn>
#include <osgAnimation/ActionBlendOut>
#include <osgAnimation/ActionAnimation>
namespace osgAnimation
{
// encapsulate animation with blend in blend out for classic usage
class OSGANIMATION_EXPORT ActionStripAnimation : public Action
{
public:
META_Action(osgAnimation, ActionStripAnimation);
ActionStripAnimation() {}
ActionStripAnimation(const ActionStripAnimation& a, const osg::CopyOp& c);
ActionStripAnimation(Animation* animation, double blendInDuration = 0.0, double blendOutDuration = 0.0, double blendInWeightTarget = 1.0 );
ActionAnimation* getAnimation();
ActionBlendIn* getBlendIn();
ActionBlendOut* getBlendOut();
const ActionAnimation* getAnimation() const;
const ActionBlendIn* getBlendIn() const;
const ActionBlendOut* getBlendOut() const;
unsigned int getBlendOutStartFrame() const;
unsigned int getLoop() const;
void setLoop(unsigned int loop);
void traverse(ActionVisitor& visitor);
protected:
typedef std::pair<unsigned int, osg::ref_ptr<ActionBlendOut> > FrameBlendOut;
osg::ref_ptr<ActionBlendIn> _blendIn;
FrameBlendOut _blendOut;
osg::ref_ptr<ActionAnimation> _animation;
};
}
#endif

View File

@@ -0,0 +1,117 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_ACTIONVISITOR_H
#define OSGANIMATION_ACTIONVISITOR_H
#include <vector>
#include <osgAnimation/Export>
#include <osg/Referenced>
#include <osgAnimation/FrameAction>
namespace osgAnimation
{
class Timeline;
class Action;
class ActionBlendIn;
class ActionBlendOut;
class ActionAnimation;
class ActionStripAnimation;
#define META_ActionVisitor(library,name) \
virtual const char* libraryName() const { return #library; }\
virtual const char* className() const { return #name; }
class OSGANIMATION_EXPORT ActionVisitor : public osg::Referenced
{
public:
META_ActionVisitor(osgAnimation, ActionVisitor);
ActionVisitor();
void traverse(Action& visitor);
void pushFrameActionOnStack(const FrameAction& fa);
void popFrameAction();
void pushTimelineOnStack(Timeline* tm);
void popTimeline();
Timeline* getCurrentTimeline();
void setCurrentLayer(int layer) { _currentLayer = layer;}
int getCurrentLayer() const { return _currentLayer; }
const std::vector<FrameAction>& getStackedFrameAction() const { return _stackFrameAction; }
virtual void apply(Action& action);
virtual void apply(Timeline& tm);
virtual void apply(ActionBlendIn& action);
virtual void apply(ActionBlendOut& action);
virtual void apply(ActionAnimation& action);
virtual void apply(ActionStripAnimation& action);
protected:
std::vector<FrameAction> _stackFrameAction;
std::vector<Timeline*> _stackTimeline;
int _currentLayer;
};
class OSGANIMATION_EXPORT UpdateActionVisitor : public osgAnimation::ActionVisitor
{
protected:
unsigned int _frame;
unsigned int _currentAnimationPriority;
public:
META_ActionVisitor(osgAnimation, UpdateActionVisitor);
UpdateActionVisitor();
void setFrame(unsigned int frame) { _frame = frame;}
bool isActive(Action& action) const;
unsigned int getLocalFrame() const;
void apply(Timeline& action);
void apply(Action& action);
void apply(ActionBlendIn& action);
void apply(ActionBlendOut& action);
void apply(ActionAnimation& action);
void apply(ActionStripAnimation& action);
};
class OSGANIMATION_EXPORT ClearActionVisitor : public osgAnimation::ActionVisitor
{
public:
enum ClearType {
BEFORE_FRAME,
AFTER_FRAME
};
META_ActionVisitor(osgAnimation, ClearActionVisitor);
ClearActionVisitor(ClearType type = BEFORE_FRAME);
void setFrame(unsigned int frame) { _frame = frame;}
void apply(Timeline& action);
void apply(Action& action);
protected:
unsigned int _frame;
std::vector<osg::ref_ptr<Action> > _remove;
ClearType _clearType;
};
}
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -31,7 +31,7 @@ namespace osgAnimation
META_Object(osgAnimation, Animation)
Animation() : _duration(0), _weight(0), _startTime(0), _playmode(LOOP) {}
Animation(const osgAnimation::Animation& anim, const osg::CopyOp&);
Animation(const osgAnimation::Animation&, const osg::CopyOp&);
enum PlayMode
{
@@ -71,10 +71,12 @@ namespace osgAnimation
void setWeight (float weight);
float getWeight() const;
bool update (float time);
bool update (float time, int priority = 0);
void resetTargets();
void setPlaymode (PlayMode mode) { _playmode = mode; }
PlayMode getPlayMode() const { return _playmode; }
void setStartTime(float time) { _startTime = time;}
float getStartTime() const { return _startTime;}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -12,9 +12,10 @@
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_ANIMATION_MANAGER_BASE_H
#define OSGANIMATION_ANIMATION_MANAGER_BASE_H
#ifndef OSGANIMATION_ANIMATION_MANAGER_BASE
#define OSGANIMATION_ANIMATION_MANAGER_BASE 1
#include <osgAnimation/LinkVisitor>
#include <osgAnimation/Animation>
#include <osgAnimation/Export>
#include <osg/FrameStamp>
@@ -33,7 +34,8 @@ namespace osgAnimation
AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY);
virtual ~AnimationManagerBase();
virtual void buildTargetReference();
virtual void registerAnimation (Animation* animation);
virtual void registerAnimation (Animation*);
virtual void unregisterAnimation (Animation*);
virtual void link(osg::Node* subgraph);
virtual void update(double t) = 0;
virtual bool needToLink() const;
@@ -42,16 +44,26 @@ namespace osgAnimation
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
/// Operation that must be done each frame
/** Reset the value of targets
this Operation must be done each frame */
void clearTargets();
void normalizeTargets();
LinkVisitor* getOrCreateLinkVisitor();
void setLinkVisitor(LinkVisitor*);
/// set a flag to define the behaviour
void setAutomaticLink(bool);
bool isAutomaticLink() const;
void dirty();
protected:
osg::ref_ptr<LinkVisitor> _linker;
AnimationList _animations;
TargetSet _targets;
bool _needToLink;
bool _automaticLink;
};
}
#endif

View File

@@ -0,0 +1,72 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_UPDATE_CALLBACK
#define OSGANIMATION_ANIMATION_UPDATE_CALLBACK 1
#include <osg/Object>
#include <osgAnimation/Channel>
#include <osgAnimation/Animation>
#include <string>
namespace osgAnimation
{
class AnimationUpdateCallbackBase : public virtual osg::Object
{
public:
virtual bool link(Channel* channel) = 0;
virtual int link(Animation* animation) = 0;
};
template <class T>
class AnimationUpdateCallback : public AnimationUpdateCallbackBase, public T
{
public:
AnimationUpdateCallback() {}
AnimationUpdateCallback(const std::string& name) { T::setName(name);}
AnimationUpdateCallback(const AnimationUpdateCallback& apc,const osg::CopyOp& copyop): T(apc, copyop) {}
META_Object(osgAnimation, AnimationUpdateCallback<T>);
const std::string& getName() const { return T::getName(); }
bool link(Channel* channel) { return 0; }
int link(Animation* animation)
{
if (T::getName().empty())
{
osg::notify(osg::WARN) << "An update callback has no name, it means it could link only with \"\" named Target, often an error, discard" << std::endl;
return 0;
}
int nbLinks = 0;
for (ChannelList::iterator it = animation->getChannels().begin();
it != animation->getChannels().end();
++it)
{
std::string targetName = (*it)->getTargetName();
if (targetName == T::getName())
{
AnimationUpdateCallbackBase* a = this;
a->link((*it).get());
nbLinks++;
}
}
return nbLinks;
}
};
}
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,39 +10,26 @@
* 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 <cedric.pinson@plopbyte.net>
* Michael Platings <mplatings@pixelpower.com>
*/
#ifndef OSGANIMATION_BONE_H
#define OSGANIMATION_BONE_H
#ifndef OSGANIMATION_BONE
#define OSGANIMATION_BONE 1
#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 <osg/MatrixTransform>
#include <osgAnimation/Export>
#include <osgAnimation/Target>
#include <osgAnimation/Sampler>
#include <osgAnimation/Channel>
#include <osgAnimation/Keyframe>
#include <osgAnimation/UpdateCallback>
#include <osgAnimation/Animation>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/VertexInfluence>
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
// makes no sense. You can share the entire hierarchy but not only a part of it.
class OSGANIMATION_EXPORT Bone : public osg::MatrixTransform
{
public:
typedef osg::ref_ptr<Bone> PointerType;
typedef std::map<std::string, PointerType > BoneMap;
typedef osg::Matrix MatrixType;
META_Node(osgAnimation, Bone);
@@ -51,230 +38,24 @@ namespace osgAnimation
void setDefaultUpdateCallback(const std::string& name = "");
struct BoneMapVisitor : public osg::NodeVisitor
{
BoneMap _map;
BoneMapVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
META_NodeVisitor("osgAnimation","BoneMapVisitor")
void apply(osg::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::Node& node)
{
if (_manager.valid())
return;
osg::NodeCallback* callback = node.getUpdateCallback();
while (callback)
{
_manager = dynamic_cast<osgAnimation::AnimationManagerBase*>(callback);
if (_manager.valid())
return;
callback = callback->getNestedCallback();
}
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);
}
};
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const;
virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const;
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& getMatrixInBoneSpace() const { return getMatrix();}
const osg::Matrix& getMatrixInSkeletonSpace() const { return _boneInSkeletonSpace; }
const osg::Matrix& getInvBindMatrixInSkeletonSpace() const { return _invBindInSkeletonSpace;}
void setMatrixInSkeletonSpace(const osg::Matrix& matrix) { _boneInSkeletonSpace = matrix; }
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();
void setInvBindMatrixInSkeletonSpace(const osg::Matrix& matrix) { _invBindInSkeletonSpace = matrix; }
protected:
osg::Vec3 _position;
osg::Quat _rotation;
osg::Vec3 _scale;
// flag to recompute bind pose
bool _needToRecomputeBindMatrix;
// bind data
osg::Matrix _bindInBoneSpace;
osg::Matrix _invBindInSkeletonSpace;
// bone updated
osg::Matrix _boneInSkeletonSpace;
};
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;
}
typedef std::map<std::string, osg::ref_ptr<Bone> > BoneMap;
}
#endif

View File

@@ -0,0 +1,42 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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 <cedric.pinson@plopbyte.net>
*/
#ifndef OSGANIMATION_BONEMAP_VISITOR
#define OSGANIMATION_BONEMAP_VISITOR 1
#include <osgAnimation/Export>
#include <osgAnimation/Bone>
#include <osg/NodeVisitor>
namespace osgAnimation
{
class OSGANIMATION_EXPORT BoneMapVisitor : public osg::NodeVisitor
{
public:
META_NodeVisitor("osgAnimation","BoneMapVisitor")
BoneMapVisitor();
void apply(osg::Node&);
void apply(osg::Transform& node);
const BoneMap& getBoneMap() const;
protected:
BoneMap _map;
};
}
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,7 +10,11 @@
* 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 <cedric.pinson@plopbyte.net>
* Michael Platings <mplatings@pixelpower.com>
*/
#ifndef OSGANIMATION_CHANNEL_H
#define OSGANIMATION_CHANNEL_H
@@ -29,11 +33,14 @@ namespace osgAnimation
public:
Channel();
Channel(const Channel& channel);
virtual ~Channel();
virtual Channel* clone() const = 0;
virtual void update(float time) = 0;
virtual void update(float time, float weight, int priority) = 0;
virtual void reset() = 0;
virtual Target* getTarget() = 0;
virtual bool setTarget(Target*) = 0;
const std::string& getName() const;
void setName(const std::string& name);
@@ -44,17 +51,18 @@ namespace osgAnimation
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;
// create a keyframe container from current target value
// with one key only, can be used for debug or to create
// easily a default channel from an existing one
virtual bool createKeyframeContainerFromTargetValue() = 0;
protected:
std::string _targetName;
std::string _name;
float _weight;
};
@@ -66,8 +74,19 @@ namespace osgAnimation
typedef typename SamplerType::UsingType UsingType;
typedef TemplateTarget<UsingType> TargetType;
typedef TemplateKeyframeContainer<typename SamplerType::KeyframeType> KeyframeContainerType;
Channel* clone() const { return new TemplateChannel<SamplerType>(*this); }
TemplateChannel (SamplerType* s = 0,TargetType* target = 0)
TemplateChannel (const TemplateChannel& channel) :
Channel(channel)
{
if (channel.getTargetTyped())
_target = new TargetType(*channel.getTargetTyped());
if (channel.getSamplerTyped())
_sampler = new SamplerType(*channel.getSamplerTyped());
}
TemplateChannel (SamplerType* s = 0,TargetType* target = 0)
{
if (target)
_target = target;
@@ -76,20 +95,42 @@ namespace osgAnimation
_sampler = s;
}
virtual bool createKeyframeContainerFromTargetValue()
{
if (!_target.valid()) // no target it does not make sense to do it
{
return false;
}
// create a key from current target value
typename KeyframeContainerType::KeyType key(0, _target->getValue());
// recreate the keyframe container
getOrCreateSampler()->setKeyframeContainer(0);
getOrCreateSampler()->getOrCreateKeyframeContainer();
// add the key
_sampler->getKeyframeContainerTyped()->push_back(key);
return true;
}
virtual ~TemplateChannel() {}
virtual void update(float time)
virtual void update(float time, float weight, int priority)
{
// skip if weight == 0
if (_weight < 1e-4)
if (weight < 1e-4)
return;
typename SamplerType::UsingType value;
_sampler->getValueAt(time, value);
_target->update(_weight, value);
_target->update(weight, value, priority);
}
virtual void reset() { _target->reset(); }
virtual Target* getTarget() { return _target.get();}
virtual bool setTarget(Target* target)
{
_target = dynamic_cast<TargetType*>(target);
return _target.get() == target;
}
SamplerType* getOrCreateSampler()
SamplerType* getOrCreateSampler()
{
if (!_sampler.valid())
_sampler = new SamplerType;
@@ -104,6 +145,7 @@ namespace osgAnimation
void setSampler(SamplerType* sampler) { _sampler = sampler; }
TargetType* getTargetTyped() { return _target.get(); }
const TargetType* getTargetTyped() const { return _target.get(); }
void setTarget(TargetType* target) { _target = target; }
virtual float getStartTime() const { return _sampler->getStartTime(); }
@@ -116,13 +158,21 @@ namespace osgAnimation
typedef std::vector<osg::ref_ptr<osgAnimation::Channel> > ChannelList;
typedef TemplateChannel<DoubleStepSampler> DoubleStepChannel;
typedef TemplateChannel<FloatStepSampler> FloatStepChannel;
typedef TemplateChannel<Vec2StepSampler> Vec2StepChannel;
typedef TemplateChannel<Vec3StepSampler> Vec3StepChannel;
typedef TemplateChannel<Vec4StepSampler> Vec4StepChannel;
typedef TemplateChannel<QuatStepSampler> QuatStepChannel;
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<MatrixLinearSampler> MatrixLinearChannel;
typedef TemplateChannel<FloatCubicBezierSampler> FloatCubicBezierChannel;
typedef TemplateChannel<DoubleCubicBezierSampler> DoubleCubicBezierChannel;

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -12,38 +12,61 @@
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_CUBIC_BEZIER_H
#define OSGANIMATION_CUBIC_BEZIER_H
#ifndef OSGANIMATION_CUBIC_BEZIER
#define OSGANIMATION_CUBIC_BEZIER 1
#include <osg/Vec2>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
namespace osgAnimation
{
template <class T>
struct TemplateCubicBezier
class 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;
}
public:
TemplateCubicBezier() {}
const T& getPosition() const { return mPoint[0];}
const T& getTangentPoint1() const { return mPoint[1];}
const T& getTangentPoint2() const { return mPoint[2];}
};
TemplateCubicBezier(const T& p, const T& i, const T& o) : _position(p), _controlPointIn(i), _controlPointOut(o)
{
}
// Constructor with value only
TemplateCubicBezier(const T& p) : _position(p), _controlPointIn(p), _controlPointOut(p)
{
}
const T& getPosition() const { return _position;}
const T& getControlPointIn() const { return _controlPointIn;}
const T& getControlPointOut() const { return _controlPointOut;}
T& getPosition() { return _position;}
T& getControlPointIn() { return _controlPointIn;}
T& getControlPointOut() { return _controlPointOut;}
void setPosition(const T& v) {_position = v;}
void setControlPointIn(const T& v) {_controlPointIn = v;}
void setControlPointOut(const T& v) {_controlPointOut = v;}
// steaming operators.
friend std::ostream& operator << (std::ostream& output, const TemplateCubicBezier<T>& tcb)
{
output << tcb._position << " "
<< tcb._controlPointIn << " "
<< tcb._controlPointOut;
return output; // to enable cascading
}
friend std::istream& operator >> (std::istream& input, TemplateCubicBezier<T>& tcb)
{
input >> tcb._position >> tcb._controlPointIn >> tcb._controlPointOut;
return input;
}
protected:
T _position, _controlPointIn, _controlPointOut;
};
typedef TemplateCubicBezier<float> FloatCubicBezier;
typedef TemplateCubicBezier<double> DoubleCubicBezier;

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,10 +10,10 @@
* 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
#ifndef OSGANIMATION_EASE_MOTION
#define OSGANIMATION_EASE_MOTION 1
#include <osg/Referenced>
#include <osg/ref_ptr>
@@ -21,9 +21,8 @@
#include <osg/Math>
#include <vector>
namespace osgAnimation {
namespace osgAnimation
{
struct OutBounceFunction
{
inline static void getValueAt(float t, float& result)
@@ -76,14 +75,12 @@ namespace osgAnimation {
}
};
/// Linear function
struct LinearFunction
{
inline static void getValueAt(float t, float& result) { result = t;}
};
/// Quad function
struct OutQuadFunction
{
@@ -94,46 +91,47 @@ namespace osgAnimation {
{
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)
{
t *= 2.0;
if (t < 1.0)
result = 0.5 * t * t;
else
{
t = t - 1.0;
result = - 0.5 * t * ( t - 2) - 1;
t -= 1.0;
result = - 0.5 * (t * ( t - 2) - 1);
}
}
};
/// Cubic function
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;
t *= 2.0f;
if (t < 1.0f)
result = 0.5f * t * t * t;
else {
t = t - 2;
result = 0.5 * t * t * t + 2;
t -= 2.0f;
result = 0.5 * (t * t * t + 2.0f);
}
}
};
/// Quart function
struct InQuartFunction
{
@@ -160,7 +158,191 @@ namespace osgAnimation {
}
};
/// Elastic function
struct OutElasticFunction
{
inline static void getValueAt(float t, float& result)
{
result = pow(2.0f, -10.0f * t) * sinf((t - 0.3f / 4.0f) * (2.0f * osg::PI) / 0.3f) + 1.0f;
}
};
struct InElasticFunction
{
inline static void getValueAt(float t, float& result)
{
OutElasticFunction::getValueAt(1.0f - t, result);
result = 1.0f - result;
}
};
struct InOutElasticFunction
{
inline static void getValueAt(float t, float& result)
{
t *= 2.0f;
if (t < 1.0f)
{
t -= 1.0f;
result = -0.5 * (1.0f * pow(2.0f, 10.0f * t) * sinf((t - 0.45f / 4.0f) * (2.0f * osg::PI) / 0.45f));
}
else
{
t -= 1.0f;
result = pow(2.0f, -10.0f * t) * sinf((t - 0.45f / 4.0f) * (2.0f * osg::PI) / 0.45f) * 0.5f + 1.0f;
}
}
};
// Sine function
struct OutSineFunction
{
inline static void getValueAt(float t, float& result)
{
result = sinf(t * (osg::PI / 2.0f));
}
};
struct InSineFunction
{
inline static void getValueAt(float t, float& result)
{
result = -cosf(t * (osg::PI / 2.0f)) + 1.0f;
}
};
struct InOutSineFunction
{
inline static void getValueAt(float t, float& result)
{
result = -0.5f * (cosf((osg::PI * t)) - 1.0f);
}
};
// Back function
struct OutBackFunction
{
inline static void getValueAt(float t, float& result)
{
t -= 1.0f;
result = t * t * ((1.70158 + 1.0f) * t + 1.70158) + 1.0f;
}
};
struct InBackFunction
{
inline static void getValueAt(float t, float& result)
{
result = t * t * ((1.70158 + 1.0f) * t - 1.70158);
}
};
struct InOutBackFunction
{
inline static void getValueAt(float t, float& result)
{
float s = 1.70158 * 1.525f;
t *= 2.0f;
if (t < 1.0f)
{
result = 0.5f * (t * t * ((s + 1.0f) * t - s));
}
else
{
float p = t -= 2.0f;
result = 0.5f * ((p) * t * ((s + 1.0f) * t + s) + 2.0f);
}
}
};
// Circ function
struct OutCircFunction
{
inline static void getValueAt(float t, float& result)
{
t -= 1.0f;
result = sqrt(1.0f - t * t);
}
};
struct InCircFunction
{
inline static void getValueAt(float t, float& result)
{
result = -(sqrt(1.0f - (t * t)) - 1.0f);
}
};
struct InOutCircFunction
{
inline static void getValueAt(float t, float& result)
{
t *= 2.0f;
if (t < 1.0f)
{
result = -0.5f * (sqrt(1.0f - t * t) - 1.0f);
}
else
{
t -= 2.0f;
result = 0.5f * (sqrt(1 - t * t) + 1.0f);
}
}
};
// Expo function
struct OutExpoFunction
{
inline static void getValueAt(float t, float& result)
{
if(t == 1.0f)
{
result = 0.0f;
}
else
{
result = -powf(2.0f, -10.0f * t) + 1.0f;
}
}
};
struct InExpoFunction
{
inline static void getValueAt(float t, float& result)
{
if(t == 0.0f)
{
result = 0.0f;
}
else
{
result = powf(2.0f, 10.0f * (t - 1.0f));
}
}
};
struct InOutExpoFunction
{
inline static void getValueAt(float t, float& result)
{
if(t == 0.0f || t == 1.0f)
{
result = 0.0f;
}
else
{
t *= 2.0f;
if(t < 1.0f)
{
result = 0.5f * powf(2.0f, 10.0f * (t - 1.0f));
}
else
{
result = 0.5f * (-powf(2.0f, -10.0f * (t - 1.0f)) + 2.0f);
}
}
}
};
class Motion : public osg::Referenced
{
@@ -278,7 +460,7 @@ namespace osgAnimation {
osg::notify(osg::WARN) << "CompositeMotion::getValueInNormalizedRange no Motion in the CompositeMotion, add motion to have result" << std::endl;
return;
}
for (MotionList::const_iterator it = _motions.begin(); it != _motions.end(); it++)
for (MotionList::const_iterator it = _motions.begin(); it != _motions.end(); ++it)
{
const Motion* motion = static_cast<const Motion*>(it->get());
float durationInRange = motion->getDuration() / getDuration();
@@ -314,13 +496,35 @@ namespace osgAnimation {
typedef MathMotionTemplate<InQuartFunction> InQuartMotion;
typedef MathMotionTemplate<InOutQuartFunction> InOutQuartMotion;
// bounce
typedef MathMotionTemplate<OutBounceFunction > OutBounceMotion;
typedef MathMotionTemplate<InBounceFunction> InBounceMotion;
typedef MathMotionTemplate<InOutBounceFunction> InOutBounceMotion;
// elastic
typedef MathMotionTemplate<OutElasticFunction > OutElasticMotion;
typedef MathMotionTemplate<InElasticFunction > InElasticMotion;
typedef MathMotionTemplate<InOutElasticFunction > InOutElasticMotion;
// sine
typedef MathMotionTemplate<OutSineFunction > OutSineMotion;
typedef MathMotionTemplate<InSineFunction > InSineMotion;
typedef MathMotionTemplate<InOutSineFunction > InOutSineMotion;
// back
typedef MathMotionTemplate<OutBackFunction > OutBackMotion;
typedef MathMotionTemplate<InBackFunction > InBackMotion;
typedef MathMotionTemplate<InOutBackFunction > InOutBackMotion;
// circ
typedef MathMotionTemplate<OutCircFunction > OutCircMotion;
typedef MathMotionTemplate<InCircFunction > InCircMotion;
typedef MathMotionTemplate<InOutCircFunction > InOutCircMotion;
// expo
typedef MathMotionTemplate<OutExpoFunction > OutExpoMotion;
typedef MathMotionTemplate<InExpoFunction > InExpoMotion;
typedef MathMotionTemplate<InOutExpoFunction > InOutExpoMotion;
}
#endif

View File

@@ -0,0 +1,26 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_FRAMEACTION_H
#define OSGANIMATION_FRAMEACTION_H
#include <map>
#include <osg/ref_ptr>
namespace osgAnimation
{
class Action;
typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
}
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,13 +10,16 @@
* 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 <cedric.pinson@plopbyte.net>
* Michael Platings <mplatings@pixelpower.com>
*/
#ifndef OSGANIMATION_INTERPOLATOR_H
#define OSGANIMATION_INTERPOLATOR_H
#ifndef OSGANIMATION_INTERPOLATOR
#define OSGANIMATION_INTERPOLATOR 1
#include <osg/Notify>
#include <osgAnimation/Interpolator>
#include <osgAnimation/Keyframe>
namespace osgAnimation
@@ -61,6 +64,32 @@ namespace osgAnimation
};
template <class TYPE, class KEY=TYPE>
class TemplateStepInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
public:
TemplateStepInterpolator() {}
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);
result = keyframes[i].getValue();
}
};
template <class TYPE, class KEY=TYPE>
class TemplateLinearInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
{
@@ -176,14 +205,22 @@ namespace osgAnimation
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 v1 = keyframes[i].getValue().getControlPointIn() * (3.0 * t * one_minus_t2);
TYPE v2 = keyframes[i].getValue().getControlPointOut() * (3.0 * t2 * one_minus_t);
TYPE v3 = keyframes[i+1].getValue().getPosition() * (t2 * t);
result = v0 + v1 + v2 + v3;
}
};
typedef TemplateStepInterpolator<double, double> DoubleStepInterpolator;
typedef TemplateStepInterpolator<float, float> FloatStepInterpolator;
typedef TemplateStepInterpolator<osg::Vec2, osg::Vec2> Vec2StepInterpolator;
typedef TemplateStepInterpolator<osg::Vec3, osg::Vec3> Vec3StepInterpolator;
typedef TemplateStepInterpolator<osg::Vec3, Vec3Packed> Vec3PackedStepInterpolator;
typedef TemplateStepInterpolator<osg::Vec4, osg::Vec4> Vec4StepInterpolator;
typedef TemplateStepInterpolator<osg::Quat, osg::Quat> QuatStepInterpolator;
typedef TemplateLinearInterpolator<double, double> DoubleLinearInterpolator;
typedef TemplateLinearInterpolator<float, float> FloatLinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec2, osg::Vec2> Vec2LinearInterpolator;
@@ -191,6 +228,7 @@ namespace osgAnimation
typedef TemplateLinearInterpolator<osg::Vec3, Vec3Packed> Vec3PackedLinearInterpolator;
typedef TemplateLinearInterpolator<osg::Vec4, osg::Vec4> Vec4LinearInterpolator;
typedef TemplateSphericalLinearInterpolator<osg::Quat, osg::Quat> QuatSphericalLinearInterpolator;
typedef TemplateLinearInterpolator<osg::Matrixf, osg::Matrixf> MatrixLinearInterpolator;
typedef TemplateCubicBezierInterpolator<float, FloatCubicBezier > FloatCubicBezierInterpolator;
typedef TemplateCubicBezierInterpolator<double, DoubleCubicBezier> DoubleCubicBezierInterpolator;

View File

@@ -23,6 +23,7 @@
#include <osg/Vec4>
#include <osg/Vec3>
#include <osg/Vec2>
#include <osg/Matrixf>
namespace osgAnimation
{
@@ -98,6 +99,9 @@ namespace osgAnimation
typedef TemplateKeyframe<float> FloatKeyframe;
typedef TemplateKeyframeContainer<float> FloatKeyframeContainer;
typedef TemplateKeyframe<double> DoubleKeyframe;
typedef TemplateKeyframeContainer<double> DoubleKeyframeContainer;
typedef TemplateKeyframe<osg::Vec2> Vec2Keyframe;
typedef TemplateKeyframeContainer<osg::Vec2> Vec2KeyframeContainer;
@@ -111,17 +115,24 @@ namespace osgAnimation
typedef TemplateKeyframe<osg::Quat> QuatKeyframe;
typedef TemplateKeyframeContainer<osg::Quat> QuatKeyframeContainer;
typedef TemplateKeyframe<osg::Matrixf> MatrixKeyframe;
typedef TemplateKeyframeContainer<osg::Matrixf> MatrixKeyframeContainer;
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;

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -16,37 +16,39 @@
#define OSGANIMATION_NODE_VISITOR_H
#include <osg/NodeVisitor>
#include <osg/StateSet>
#include <osgAnimation/Animation>
#include <osgAnimation/UpdateCallback>
namespace osgAnimation
{
class AnimationUpdateCallbackBase;
struct LinkVisitor : public osg::NodeVisitor
/** This class is instancied by the AnimationManagerBase, it will link animation target to updatecallback that have the same name
*/
class OSGANIMATION_EXPORT LinkVisitor : public osg::NodeVisitor
{
public:
LinkVisitor();
META_NodeVisitor("osgAnimation","LinkVisitor");
void apply(osg::Node& node);
void apply(osg::Geode& node);
AnimationList& getAnimationList();
void reset();
unsigned int getNbLinkedTarget() const { return _nbLinkedTarget; }
protected:
void handle_stateset(osg::StateSet* stateset);
void link(osgAnimation::AnimationUpdateCallbackBase* cb);
// animation list to link
AnimationList _animations;
// number of success link done
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;}
META_NodeVisitor("osgAnimation","LinkVisitor")
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);
}
};
}

View File

@@ -0,0 +1,154 @@
/* -*-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_MORPHGEOMETRY_H
#define OSGANIMATION_MORPHGEOMETRY_H
#include <osgAnimation/Export>
#include <osgAnimation/AnimationUpdateCallback>
#include <osg/Geometry>
namespace osgAnimation
{
class OSGANIMATION_EXPORT MorphGeometry : public osg::Geometry
{
public:
enum Method {
NORMALIZED,
RELATIVE
};
class MorphTarget
{
protected:
osg::ref_ptr<osg::Geometry> _geom;
float _weight;
public:
MorphTarget(osg::Geometry* geom, float w = 1.0) : _geom(geom), _weight(w) {}
void setWeight(float weight) { _weight = weight; }
const float getWeight() const { return _weight; }
osg::Geometry* getGeometry() { return _geom.get(); }
const osg::Geometry* getGeometry() const { return _geom.get(); }
void setGeometry(osg::Geometry* geom) { _geom = geom; }
};
typedef std::vector<MorphTarget> MorphTargetList;
struct UpdateVertex : public osg::Drawable::UpdateCallback
{
virtual void update(osg::NodeVisitor*, osg::Drawable* drw)
{
MorphGeometry* geom = dynamic_cast<MorphGeometry*>(drw);
if (!geom)
return;
geom->transformSoftwareMethod();
}
};
MorphGeometry();
MorphGeometry(const osg::Geometry& b);
MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
virtual osg::Object* cloneType() const { return new MorphGeometry(); }
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MorphGeometry(*this,copyop); }
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const MorphGeometry*>(obj)!=NULL; }
virtual const char* libraryName() const { return "osgAnimation"; }
virtual const char* className() const { return "MorphGeometry"; }
virtual void transformSoftwareMethod();
/** Set the morphing method. */
void setMethod(Method method) { _method = method; }
/** Get the morphing method. */
inline Method getMethod() const { return _method; }
/** Set flag for morphing normals. */
void setMorphNormals(bool morphNormals) { _morphNormals = morphNormals; }
/** Get the flag for morphing normals. */
inline bool getMorphNormals() const { return _morphNormals; }
/** Add a \c MorphTarget to the \c MorphGeometry.
* If \c MorphTarget is not \c NULL and is not contained in the \c MorphGeometry
* then increment its reference count, add it to the MorphTargets list and
* dirty the bounding sphere to force it to be recomputed on the next
* call to \c getBound().
* @param morphTarget The \c MorphTarget to be added to the \c MorphGeometry.
* @param weight The weight to be added to the \c MorphGeometry.
* @return \c true for success; \c false otherwise.
*/
virtual void addMorphTarget( osg::Geometry *morphTarget, float weight = 1.0 ) { _morphTargets.push_back(MorphTarget(morphTarget, weight)); _dirty = true; }
void setWeight(unsigned int index, float morphWeight)
{
if (index < _morphTargets.size())
{
_morphTargets[index].setWeight(morphWeight);
dirty();
}
}
/** Set the MorphGeometry dirty.*/
void dirty() { _dirty = true; }
/** Get the list of MorphTargets.*/
const MorphTargetList& getMorphTargetList() const { return _morphTargets; }
/** Get the list of MorphTargets. Warning if you modify this array you will have to call dirty() */
MorphTargetList& getMorphTargetList() { return _morphTargets; }
/** Return the \c MorphTarget at position \c i.*/
inline const MorphTarget& getMorphTarget( unsigned int i ) const { return _morphTargets[i]; }
/** Return the \c MorphTarget at position \c i.*/
inline MorphTarget& getMorphTarget( unsigned int i ) { return _morphTargets[i]; }
protected:
/// Do we need to recalculate the morphed geometry?
bool _dirty;
Method _method;
MorphTargetList _morphTargets;
std::vector<osg::Vec3> _positionSource;
std::vector<osg::Vec3> _normalSource;
/// Do we also morph between normals?
bool _morphNormals;
};
class OSGANIMATION_EXPORT UpdateMorph : public AnimationUpdateCallback<osg::NodeCallback>
{
protected:
std::map<int, osg::ref_ptr<osgAnimation::FloatTarget> > _weightTargets;
public:
META_Object(osgAnimation, UpdateMorph);
UpdateMorph(const std::string& name = "");
UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop);
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
bool needLink() const;
bool link(osgAnimation::Channel* channel);
};
}
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -16,8 +16,9 @@
#define OSGANIMATION_RIGGEOMETRY_H
#include <osgAnimation/Export>
#include <osgAnimation/Skinning>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigTransform>
#include <osgAnimation/VertexInfluence>
#include <osg/Geometry>
namespace osgAnimation
@@ -28,49 +29,63 @@ namespace osgAnimation
public:
RigGeometry();
RigGeometry(const osg::Geometry& b);
// RigGeometry(const osg::Geometry& b);
RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
META_Object(osgAnimation, RigGeometry);
void setInfluenceMap(osgAnimation::VertexInfluenceMap* vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; }
const osgAnimation::VertexInfluenceMap* getInfluenceMap() const { return _vertexInfluenceMap.get();}
osgAnimation::VertexInfluenceMap* getInfluenceMap() { return _vertexInfluenceMap.get();}
void setInfluenceMap(VertexInfluenceMap* vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; }
const VertexInfluenceMap* getInfluenceMap() const { return _vertexInfluenceMap.get();}
VertexInfluenceMap* getInfluenceMap() { return _vertexInfluenceMap.get();}
const Skeleton* getSkeleton() const;
Skeleton* getSkeleton();
// will be used by the update callback to init correctly the rig mesh
void setSkeleton(Skeleton*);
void setNeedToComputeMatrix(bool state) { _needToComputeMatrix = state;}
bool getNeedToComputeMatrix() const { return _needToComputeMatrix;}
void buildVertexSet();
void buildTransformer(Skeleton* root);
// this build the internal database about vertex influence and bones
void buildVertexInfluenceSet();
const VertexInfluenceSet& getVertexInfluenceSet() const;
void computeMatrixFromRootSkeleton();
virtual void transformSoftwareMethod();
const osgAnimation::VertexInfluenceSet& getVertexInfluenceSet() const { return _vertexInfluenceSet;}
const std::vector<osg::Vec3>& getPositionSource() const { return _positionSource;}
const std::vector<osg::Vec3>& getNormalSource() const { return _normalSource;}
// set implementation of rig method
void setRigTransformImplementation(RigTransform*);
RigTransform* getRigTransformImplementation();
virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
void update();
const osg::Matrix& getMatrixFromSkeletonToGeometry() const;
const osg::Matrix& getInvMatrixFromSkeletonToGeometry() const;
osg::Geometry* getSourceGeometry();
const osg::Geometry* getSourceGeometry() const;
void setSourceGeometry(osg::Geometry* geometry);
void copyFrom(osg::Geometry& from);
protected:
osg::ref_ptr<osg::Geometry> _geometry;
osg::ref_ptr<RigTransform> _rigTransformImplementation;
std::vector<osg::Vec3> _positionSource;
std::vector<osg::Vec3> _normalSource;
osgAnimation::VertexInfluenceSet _vertexInfluenceSet;
osg::ref_ptr<osgAnimation::VertexInfluenceMap> _vertexInfluenceMap;
osgAnimation::TransformVertexFunctor _transformVertexes;
VertexInfluenceSet _vertexInfluenceSet;
osg::ref_ptr<VertexInfluenceMap> _vertexInfluenceMap;
osg::Matrix _matrixFromSkeletonToGeometry;
osg::Matrix _invMatrixFromSkeletonToGeometry;
osg::observer_ptr<Skeleton> _root;
bool _needToComputeMatrix;
struct FindNearestParentSkeleton : public osg::NodeVisitor
{
osg::ref_ptr<osgAnimation::Skeleton> _root;
osg::ref_ptr<Skeleton> _root;
FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {}
void apply(osg::Transform& node)
{
@@ -89,7 +104,7 @@ namespace osgAnimation
RigGeometry* geom = dynamic_cast<RigGeometry*>(drw);
if (!geom)
return;
if (!geom->getSkeleton() && !geom->getParents().empty())
if (!geom->getSkeleton() && !geom->getParents().empty())
{
FindNearestParentSkeleton finder;
if (geom->getParents().size() > 1)
@@ -97,9 +112,12 @@ namespace osgAnimation
geom->getParents()[0]->accept(finder);
if (!finder._root.valid())
{
osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeomtry ( " << geom->getName() << " )" << std::endl;
return;
geom->buildVertexSet();
geom->buildTransformer(finder._root.get());
}
geom->buildVertexInfluenceSet();
geom->setSkeleton(finder._root.get());
}
if (!geom->getSkeleton())
@@ -107,34 +125,10 @@ namespace osgAnimation
if (geom->getNeedToComputeMatrix())
geom->computeMatrixFromRootSkeleton();
geom->transformSoftwareMethod();
geom->update();
}
};
/** 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;}
META_NodeVisitor("osgAnimation","BuildVertexTransformerVisitor")
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());
}
}
}
};
};
}

View File

@@ -0,0 +1,36 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_RIGTRANSFORM
#define OSGANIMATION_RIGTRANSFORM 1
#include <osg/Referenced>
namespace osgAnimation
{
class RigGeometry;
class RigTransform : public osg::Referenced
{
public:
RigTransform() {}
virtual ~RigTransform() {}
virtual void operator()(RigGeometry& geometry) {}
};
}
#endif

View File

@@ -0,0 +1,85 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_RIG_TRANSFORM_HARDWARE
#define OSGANIMATION_RIG_TRANSFORM_HARDWARE 1
#include <osgAnimation/Export>
#include <osgAnimation/RigTransform>
#include <osgAnimation/VertexInfluence>
#include <osgAnimation/Bone>
#include <osg/Matrix>
#include <osg/Array>
namespace osgAnimation
{
class RigGeometry;
/// This class manage format for hardware skinning
class OSGANIMATION_EXPORT RigTransformHardware : public RigTransform
{
public:
typedef osg::Matrix MatrixType;
typedef osgAnimation::Bone BoneType;
typedef std::vector<osg::ref_ptr<osg::Vec4Array> > BoneWeightAttribList;
typedef std::vector<osg::ref_ptr<BoneType> > BonePalette;
typedef std::vector<osg::Matrix> MatrixPalette;
struct IndexWeightEntry
{
int _boneIndex;
float _boneWeight;
IndexWeightEntry() { _boneIndex = 0; _boneWeight = 0;}
IndexWeightEntry(int index, float weight) { _boneIndex = index; _boneWeight = weight;}
int getIndex() const { return _boneIndex; }
float getWeight() const { return _boneWeight; }
};
typedef std::vector<std::vector<IndexWeightEntry> > VertexIndexWeightList;
RigTransformHardware();
osg::Vec4Array* getVertexAttrib(int index);
int getNumVertexAttrib();
osg::Uniform* getMatrixPaletteUniform();
void computeMatrixPaletteUniform(const osg::Matrix& transformFromSkeletonToGeometry, const osg::Matrix& invTransformFromSkeletonToGeometry);
int getNumBonesPerVertex() const;
int getNumVertexes() const;
bool createPalette(int nbVertexes, BoneMap boneMap, const VertexInfluenceSet::VertexIndexToBoneWeightMap& vertexIndexToBoneWeightMap);
virtual void operator()(RigGeometry&);
void setShader(osg::Shader*);
protected:
bool init(RigGeometry&);
BoneWeightAttribList createVertexAttribList();
osg::Uniform* createVertexUniform();
int _bonesPerVertex;
int _nbVertexes;
VertexIndexWeightList _vertexIndexMatrixWeightList;
BonePalette _bonePalette;
BoneWeightAttribList _boneWeightAttribArrays;
osg::ref_ptr<osg::Uniform> _uniformMatrixPalette;
osg::ref_ptr<osg::Shader> _shader;
bool _needInit;
};
}
#endif

View File

@@ -0,0 +1,172 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_RIGTRANSFORM_SOFTWARE
#define OSGANIMATION_RIGTRANSFORM_SOFTWARE 1
#include <osgAnimation/Export>
#include <osgAnimation/RigTransform>
#include <osgAnimation/Bone>
#include <osgAnimation/VertexInfluence>
#include <osg/observer_ptr>
namespace osgAnimation
{
class RigGeometry;
/// This class manage format for hardware skinning
class OSGANIMATION_EXPORT RigTransformSoftware : public RigTransform
{
public:
RigTransformSoftware();
virtual void operator()(RigGeometry&);
class BoneWeight
{
public:
BoneWeight(Bone* bone, float weight) : _bone(bone), _weight(weight) {}
const Bone* getBone() const { return _bone.get(); }
float getWeight() const { return _weight; }
void setWeight(float w) { _weight = w; }
protected:
osg::observer_ptr<Bone> _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 resetMatrix()
{
_result.set(0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 1);
}
void accummulateMatrix(const osg::Matrix& invBindMatrix, const osg::Matrix& matrix, osg::Matrix::value_type weight)
{
osg::Matrix m = invBindMatrix * matrix;
osg::Matrix::value_type* ptr = m.ptr();
osg::Matrix::value_type* ptrresult = _result.ptr();
ptrresult[0] += ptr[0] * weight;
ptrresult[1] += ptr[1] * weight;
ptrresult[2] += ptr[2] * weight;
ptrresult[4] += ptr[4] * weight;
ptrresult[5] += ptr[5] * weight;
ptrresult[6] += ptr[6] * weight;
ptrresult[8] += ptr[8] * weight;
ptrresult[9] += ptr[9] * weight;
ptrresult[10] += ptr[10] * weight;
ptrresult[12] += ptr[12] * weight;
ptrresult[13] += ptr[13] * weight;
ptrresult[14] += ptr[14] * weight;
}
void computeMatrixForVertexSet()
{
if (_bones.empty())
{
osg::notify(osg::WARN) << this << " RigTransformSoftware::UniqBoneSetVertexSet no bones found" << std::endl;
_result = osg::Matrix::identity();
return;
}
resetMatrix();
int size = _bones.size();
for (int i = 0; i < size; i++)
{
const Bone* bone = _bones[i].getBone();
if (!bone)
{
osg::notify(osg::WARN) << this << " RigTransformSoftware::computeMatrixForVertexSet Warning a bone is null, skip it" << std::endl;
continue;
}
const osg::Matrix& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace();
const osg::Matrix& matrix = bone->getMatrixInSkeletonSpace();
osg::Matrix::value_type w = _bones[i].getWeight();
accummulateMatrix(invBindMatrix, matrix, w);
}
}
const osg::Matrix& getMatrix() const { return _result;}
protected:
BoneWeightList _bones;
VertexList _vertexes;
osg::Matrix _result;
};
template <class V> void compute(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst)
{
// the result of matrix mult should be cached to be used for vertexes transform and normal transform and maybe other computation
int size = _boneSetVertexSet.size();
for (int i = 0; i < size; i++)
{
UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i];
uniq.computeMatrixForVertexSet();
osg::Matrix 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;
}
}
}
template <class V> void computeNormal(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst)
{
int size = _boneSetVertexSet.size();
for (int i = 0; i < size; i++)
{
UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i];
uniq.computeMatrixForVertexSet();
osg::Matrix 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] = osg::Matrix::transform3x3(src[idx],matrix);
}
}
}
protected:
bool init(RigGeometry&);
void initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexSetToBoneSetList& influence);
std::vector<UniqBoneSetVertexSet> _boneSetVertexSet;
bool _needInit;
};
}
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,7 +10,11 @@
* 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 <cedric.pinson@plopbyte.net>
* Michael Platings <mplatings@pixelpower.com>
*/
#ifndef OSGANIMATION_SAMPLER_H
#define OSGANIMATION_SAMPLER_H
@@ -108,12 +112,21 @@ namespace osgAnimation
};
typedef TemplateSampler<DoubleStepInterpolator> DoubleStepSampler;
typedef TemplateSampler<FloatStepInterpolator> FloatStepSampler;
typedef TemplateSampler<Vec2StepInterpolator> Vec2StepSampler;
typedef TemplateSampler<Vec3StepInterpolator> Vec3StepSampler;
typedef TemplateSampler<Vec4StepInterpolator> Vec4StepSampler;
typedef TemplateSampler<QuatStepInterpolator> QuatStepSampler;
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<MatrixLinearInterpolator> MatrixLinearSampler;
typedef TemplateSampler<FloatCubicBezierInterpolator> FloatCubicBezierSampler;
typedef TemplateSampler<DoubleCubicBezierInterpolator> DoubleCubicBezierSampler;
typedef TemplateSampler<Vec2CubicBezierInterpolator> Vec2CubicBezierSampler;

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -12,33 +12,36 @@
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_SKELETON_H
#define OSGANIMATION_SKELETON_H
#ifndef OSGANIMATION_SKELETON
#define OSGANIMATION_SKELETON 1
#include <osg/MatrixTransform>
#include <osgAnimation/Bone>
#include <osgAnimation/Export>
#include <osg/MatrixTransform>
namespace osgAnimation
{
class OSGANIMATION_EXPORT Skeleton : public Bone
class OSGANIMATION_EXPORT Skeleton : public osg::MatrixTransform
{
public:
META_Node(osgAnimation, Skeleton);
struct OSGANIMATION_EXPORT UpdateSkeleton : public osg::NodeCallback
class OSGANIMATION_EXPORT UpdateSkeleton : public osg::NodeCallback
{
public:
META_Object(osgAnimation, UpdateSkeleton);
UpdateSkeleton() {}
UpdateSkeleton(const UpdateSkeleton& us, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : osg::NodeCallback(us, copyop) {}
UpdateSkeleton();
UpdateSkeleton(const UpdateSkeleton&, const osg::CopyOp&);
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
bool needToValidate() const;
protected:
bool _needValidate;
};
Skeleton(const Skeleton& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : Bone(b,copyop) {}
Skeleton();
void setDefaultUpdateCallback(void);
void computeBindMatrix() { _invBindInSkeletonSpace = osg::Matrix::inverse(_bindInBoneSpace); }
Skeleton(const Skeleton&, const osg::CopyOp&);
void setDefaultUpdateCallback();
};
}

View File

@@ -0,0 +1,54 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_STACKED_MATRIX_ELEMENT
#define OSGANIMATION_STACKED_MATRIX_ELEMENT 1
#include <osg/Object>
#include <osgAnimation/Export>
#include <osgAnimation/StackedTransformElement>
#include <osgAnimation/Target>
namespace osgAnimation
{
class OSGANIMATION_EXPORT StackedMatrixElement : public StackedTransformElement
{
public:
META_Object(osgAnimation, StackedMatrixElement);
StackedMatrixElement();
StackedMatrixElement(const StackedMatrixElement&, const osg::CopyOp&);
StackedMatrixElement(const std::string& name, const osg::Matrix& matrix);
StackedMatrixElement(const osg::Matrix& matrix);
void applyToMatrix(osg::Matrix& matrix) const { matrix = _matrix * matrix; }
osg::Matrix getAsMatrix() const { return _matrix; }
const osg::Matrix& getMatrix() const { return _matrix;}
void setMatrix(const osg::Matrix& matrix) { _matrix = matrix;}
bool isIdentity() const { return _matrix.isIdentity(); }
void update();
virtual Target* getOrCreateTarget();
virtual Target* getTarget() {return _target.get();}
virtual const Target* getTarget() const {return _target.get();}
protected:
osg::Matrix _matrix;
osg::ref_ptr<MatrixTarget> _target;
};
}
#endif

View File

@@ -0,0 +1,54 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_STACKED_QUATERNION_ELEMENT
#define OSGANIMATION_STACKED_QUATERNION_ELEMENT 1
#include <osgAnimation/Export>
#include <osgAnimation/StackedTransformElement>
#include <osgAnimation/Target>
namespace osgAnimation
{
class OSGANIMATION_EXPORT StackedQuaternionElement : public StackedTransformElement
{
public:
META_Object(osgAnimation, StackedQuaternionElement);
StackedQuaternionElement();
StackedQuaternionElement(const StackedQuaternionElement&, const osg::CopyOp&);
StackedQuaternionElement(const std::string&, const osg::Quat& q = osg::Quat(0,0,0,1));
StackedQuaternionElement(const osg::Quat&);
void applyToMatrix(osg::Matrix& matrix) const;
osg::Matrix getAsMatrix() const;
bool isIdentity() const;
void update();
const osg::Quat& getQuaternion() const;
void setQuaternion(const osg::Quat&);
virtual Target* getOrCreateTarget();
virtual Target* getTarget();
virtual const Target* getTarget() const;
protected:
osg::Quat _quaternion;
osg::ref_ptr<QuatTarget> _target;
};
}
#endif

View File

@@ -0,0 +1,59 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_STACKED_ROTATE_AXIS_ELEMENT
#define OSGANIMATION_STACKED_ROTATE_AXIS_ELEMENT 1
#include <osgAnimation/Export>
#include <osgAnimation/StackedTransformElement>
#include <osgAnimation/Target>
#include <osg/Vec3>
namespace osgAnimation
{
class OSGANIMATION_EXPORT StackedRotateAxisElement : public StackedTransformElement
{
public:
META_Object(osgAnimation, StackedRotateAxisElement);
StackedRotateAxisElement();
StackedRotateAxisElement(const StackedRotateAxisElement&, const osg::CopyOp&);
StackedRotateAxisElement(const std::string& name, const osg::Vec3& axis, double angle);
StackedRotateAxisElement(const osg::Vec3& axis, double angle);
void applyToMatrix(osg::Matrix& matrix) const;
osg::Matrix getAsMatrix() const;
bool isIdentity() const { return (_angle == 0); }
void update();
const osg::Vec3& getAxis() const;
const double getAngle() const;
void setAxis(const osg::Vec3&);
void setAngle(const double&);
virtual Target* getOrCreateTarget();
virtual Target* getTarget() {return _target.get();}
virtual const Target* getTarget() const {return _target.get();}
protected:
osg::Vec3 _axis;
double _angle;
osg::ref_ptr<FloatTarget> _target;
};
}
#endif

View File

@@ -0,0 +1,56 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_STACKED_SCALE_ELEMENT
#define OSGANIMATION_STACKED_SCALE_ELEMENT 1
#include <osg/Object>
#include <osgAnimation/Export>
#include <osgAnimation/StackedTransformElement>
#include <osgAnimation/Target>
namespace osgAnimation
{
class OSGANIMATION_EXPORT StackedScaleElement : public StackedTransformElement
{
public:
META_Object(osgAnimation, StackedScaleElement)
StackedScaleElement();
StackedScaleElement(const StackedScaleElement&, const osg::CopyOp&);
StackedScaleElement(const std::string& name, const osg::Vec3& scale = osg::Vec3(1,1,1));
StackedScaleElement(const osg::Vec3& scale);
void applyToMatrix(osg::Matrix& matrix) const;
osg::Matrix getAsMatrix() const;
bool isIdentity() const;
void update();
const osg::Vec3& getScale() const;
void setScale(const osg::Vec3& scale);
virtual Target* getOrCreateTarget();
virtual Target* getTarget();
virtual const Target* getTarget() const;
protected:
osg::Vec3 _scale;
osg::ref_ptr<Vec3Target> _target;
};
}
#endif

View File

@@ -0,0 +1,42 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_STACKED_TRANSFORM
#define OSGANIMATION_STACKED_TRANSFORM 1
#include <osg/MixinVector>
#include <osgAnimation/Export>
#include <osgAnimation/StackedTransformElement>
namespace osgAnimation
{
class OSGANIMATION_EXPORT StackedTransform : public osg::MixinVector<osg::ref_ptr<StackedTransformElement> >
{
public:
StackedTransform();
StackedTransform(const StackedTransform&, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
void update();
const osg::Matrix& getMatrix() const;
protected:
osg::Matrix _matrix;
};
}
#endif

View File

@@ -0,0 +1,42 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_STACKED_TRANSFORM_ELEMENT
#define OSGANIMATION_STACKED_TRANSFORM_ELEMENT 1
#include <osgAnimation/Export>
#include <osg/Object>
#include <osg/Matrix>
namespace osgAnimation
{
class Target;
class OSGANIMATION_EXPORT StackedTransformElement : public osg::Object
{
public:
StackedTransformElement() {}
StackedTransformElement(const StackedTransformElement& rhs, const osg::CopyOp& c) : osg::Object(rhs, c) {}
virtual void applyToMatrix(osg::Matrix& matrix) const = 0;
virtual osg::Matrix getAsMatrix() const = 0;
virtual bool isIdentity() const = 0;
virtual void update() = 0;
virtual Target* getOrCreateTarget() {return 0;}
virtual Target* getTarget() {return 0;}
virtual const Target* getTarget() const {return 0;}
};
}
#endif

View File

@@ -0,0 +1,54 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_STACKED_TRANSLATE_ELEMENT
#define OSGANIMATION_STACKED_TRANSLATE_ELEMENT 1
#include <osgAnimation/Export>
#include <osgAnimation/StackedTransformElement>
#include <osgAnimation/Target>
namespace osgAnimation
{
class OSGANIMATION_EXPORT StackedTranslateElement : public StackedTransformElement
{
public:
META_Object(osgAnimation, StackedTranslateElement);
StackedTranslateElement();
StackedTranslateElement(const StackedTranslateElement&, const osg::CopyOp&);
StackedTranslateElement(const std::string&, const osg::Vec3& translate = osg::Vec3(0,0,0));
StackedTranslateElement(const osg::Vec3& translate);
void applyToMatrix(osg::Matrix& matrix) const;
osg::Matrix getAsMatrix() const;
bool isIdentity() const;
void update();
const osg::Vec3& getTranslate() const;
void setTranslate(const osg::Vec3& );
virtual Target* getOrCreateTarget();
virtual Target* getTarget();
virtual const Target* getTarget() const;
protected:
osg::Vec3 _translate;
osg::ref_ptr<Vec3Target> _target;
};
}
#endif

View File

@@ -0,0 +1,113 @@
/* -*-c++-*-
* Copyright (C) 2009 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_STATSHANDLER_H
#define OSGANIMATION_STATSHANDLER_H
#include <osgAnimation/Timeline>
#include <osgGA/GUIEventHandler>
#include <osgViewer/ViewerBase>
#include <osgViewer/Viewer>
#include <osgText/Text>
namespace osgAnimation
{
#if 0
struct StatAction
{
std::string _name;
osg::ref_ptr<osg::Group> _group;
osg::ref_ptr<osg::Geode> _label;
osg::ref_ptr<osg::MatrixTransform> _graph;
osg::ref_ptr<osgText::Text> _textLabel;
void init(osg::Stats* stats, const std::string& name, const osg::Vec3& pos, float width, float heigh, const osg::Vec4& color);
void setPosition(const osg::Vec3& pos);
void setAlpha(float v);
};
#endif
/** Event handler for adding on screen stats reporting to Viewers.*/
class OSGANIMATION_EXPORT StatsHandler : public osgGA::GUIEventHandler
{
public:
StatsHandler();
enum StatsType
{
NO_STATS = 0,
FRAME_RATE = 1,
LAST = 2
};
void setKeyEventTogglesOnScreenStats(int key) { _keyEventTogglesOnScreenStats = key; }
int getKeyEventTogglesOnScreenStats() const { return _keyEventTogglesOnScreenStats; }
void setKeyEventPrintsOutStats(int key) { _keyEventPrintsOutStats = key; }
int getKeyEventPrintsOutStats() const { return _keyEventPrintsOutStats; }
double getBlockMultiplier() const { return _blockMultiplier; }
void reset();
osg::Camera* getCamera() { return _camera.get(); }
const osg::Camera* getCamera() const { return _camera.get(); }
virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
/** Get the keyboard and mouse usage of this manipulator.*/
virtual void getUsage(osg::ApplicationUsage& usage) const;
protected:
void setUpHUDCamera(osgViewer::ViewerBase* viewer);
osg::Geometry* createBackgroundRectangle(const osg::Vec3& pos, const float width, const float height, osg::Vec4& color);
osg::Geometry* createGeometry(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks);
osg::Geometry* createFrameMarkers(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numBlocks);
osg::Geometry* createTick(const osg::Vec3& pos, float height, const osg::Vec4& colour, unsigned int numTicks);
osg::Node* createCameraTimeStats(const std::string& font, osg::Vec3& pos, float startBlocks, bool acquireGPUStats, float characterSize, osg::Stats* viewerStats, osg::Camera* camera);
void setUpScene(osgViewer::Viewer* viewer);
int _keyEventTogglesOnScreenStats;
int _keyEventPrintsOutStats;
int _statsType;
bool _initialized;
osg::ref_ptr<osg::Camera> _camera;
osg::ref_ptr<osg::Switch> _switch;
osg::ref_ptr<osg::Group> _group;
unsigned int _frameRateChildNum;
unsigned int _numBlocks;
double _blockMultiplier;
float _statsWidth;
float _statsHeight;
// std::map<std::string, StatAction > _actions;
};
}
#endif

View File

@@ -0,0 +1,53 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_STATSVISITOR_H
#define OSGANIMATION_STATSVISITOR_H
#include <osgAnimation/Export>
#include <osgAnimation/ActionVisitor>
#include <osg/Stats>
#include <vector>
namespace osgAnimation
{
class OSGANIMATION_EXPORT StatsActionVisitor : public osgAnimation::UpdateActionVisitor
{
protected:
osg::ref_ptr<osg::Stats> _stats;
std::vector<std::string> _channels;
public:
META_ActionVisitor(osgAnimation, StatsActionVisitor);
StatsActionVisitor();
StatsActionVisitor(osg::Stats* stats, unsigned int frame);
void reset();
const std::vector<std::string>& getChannels() const { return _channels; }
osg::Stats* getStats() { return _stats.get(); }
void setStats(osg::Stats* stats) { _stats = stats; }
void setFrame(unsigned int frame) { _frame = frame; }
void apply(Timeline& action);
void apply(Action& action);
void apply(ActionBlendIn& action);
void apply(ActionBlendOut& action);
void apply(ActionAnimation& action);
void apply(ActionStripAnimation& action);
};
}
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -34,15 +34,14 @@ namespace osgAnimation
public:
Target();
virtual ~Target();
virtual void normalize() = 0;
float getWeight() const { return _weight; }
void reset() { _weight = 0;}
virtual ~Target() {}
void reset() { _weight = 0; _priorityWeight = 0; }
int getCount() const { return referenceCount(); }
float getWeight() const { return _weight; }
protected:
void addWeight(float w) { _weight += w; }
float _weight;
float _priorityWeight;
int _lastPriority;
};
@@ -51,75 +50,78 @@ namespace osgAnimation
{
public:
TemplateTarget() {}
TemplateTarget() : _target() {}
TemplateTarget(const T& v) { setValue(v); }
TemplateTarget(const TemplateTarget& v) { setValue(v.getValue()); }
void update(float weight, const T& val)
inline void lerp(float t, const T& a, const T& b);
/**
* The priority is used to detect a change of priority
* It's important to update animation target in priority
* order. eg:
* all animation with priority 1
* all animation with priority 0
* all animation with priority -1
* ...
*/
void update(float weight, const T& val, int priority)
{
if (!_weight)
_target = val * weight;
if (_weight || _priorityWeight)
{
if (_lastPriority != priority)
{
// change in priority
// add to weight with the same previous priority cumulated weight
_weight += _priorityWeight * (1.0 - _weight);
_priorityWeight = 0;
_lastPriority = priority;
}
_priorityWeight += weight;
float t = (1.0 - _weight) * weight / _priorityWeight;
lerp(t, _target, val);
}
else
{
weight = (1.0 - _weight) * weight;
_target += val * weight;
_priorityWeight = weight;
_lastPriority = priority;
_target = val;
}
addWeight(weight);
}
const T& getValue() const { return _target;}
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;}
void setValue(const T& value) { _target = value; }
protected:
T _target;
};
// Target Specialisation for Quaternions
template <>
class TemplateTarget< osg::Quat > : public Target
template <class T>
inline void TemplateTarget<T>::lerp(float t, const T& a, const T& b)
{
public:
TemplateTarget () {}
_target = a * (1.0f - t) + b * t;
}
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()
template <>
inline void TemplateTarget<osg::Quat>::lerp(float t, const osg::Quat& a, const osg::Quat& b)
{
if (a.asVec4() * b.asVec4() < 0.0)
{
float weightSummed = getWeight();
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1.0) < 1e-4)
return;
(_target) /= weightSummed;
_target = a * (1.0f - t) + b * -t;
}
else
{
_target = a * (1.0f - t) + b * t;
}
void setValue(const osg::Quat& value) { _target = value;}
protected:
osg::Quat::value_type len2 = _target.length2();
if ( len2 != 1.0 && len2 != 0.0)
_target *= 1.0/sqrt(len2);
}
osg::Quat _target;
};
typedef TemplateTarget<osg::Matrixf> MatrixTarget;
typedef TemplateTarget<osg::Quat> QuatTarget;
typedef TemplateTarget<osg::Vec3> Vec3Target;
typedef TemplateTarget<osg::Vec4> Vec4Target;

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -12,180 +12,88 @@
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_TIMELINE_H
#define OSGANIMATION_TIMELINE_H
#ifndef OSGANIMATION_TIMELINE
#define OSGANIMATION_TIMELINE 1
#include <osgAnimation/Export>
#include <osg/Object>
#include <map>
#include <vector>
#include <osg/observer_ptr>
#include <osg/Notify>
#include <osg/Group>
#include <osgAnimation/Animation>
#include <osg/Stats>
#include <osgAnimation/Action>
#include <osgAnimation/FrameAction>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/StatsVisitor>
namespace osgAnimation
{
class Action : public osg::Object
class OSGANIMATION_EXPORT Timeline : public Action
{
public:
class Callback : public osg::Object
{
public:
Callback(){}
Callback(const Callback&,const osg::CopyOp&) {}
Timeline();
Timeline(const Timeline& nc,const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY);
META_Object(osgAnimation,Callback);
virtual void operator()(Action* /*action*/) {}
void addNestedCallback(Callback* callback)
{
if (_nested.valid())
_nested->addNestedCallback(callback);
else
_nested = callback;
}
META_Action(osgAnimation, Timeline);
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&,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
enum TimelineStatus
{
Play,
Stop
};
State _state;
};
TimelineStatus getStatus() const { return _state; }
class Timeline : public osg::Object
{
protected:
typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
typedef std::vector<FrameAction> ActionList;
typedef std::map<int, ActionList> ActionLayers;
enum State
{
Play,
Stop
};
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);
void removeAction(Action* action);
virtual void addActionAt(unsigned int frame, Action* action, int priority = 0);
virtual void addActionAt(double t, Action* action, int priority = 0);
void addActionNow(Action* action, int priority = 0);
void clearActions();
virtual void update(double simulationTime);
void setLastFrameEvaluated(unsigned int frame) { _previousFrameEvaluated = frame; }
void setEvaluating(bool state) { _evaluating = state;}
void traverse(ActionVisitor& visitor);
void setStats(osg::Stats* stats);
osg::Stats* getStats();
void collectStats(bool state);
osgAnimation::StatsActionVisitor* getStatsVisitor();
const ActionLayers& getActionLayers() const { return _actions; }
void processPendingOperation();
void setAnimationManager(AnimationManagerBase*);
protected:
osg::observer_ptr<AnimationManagerBase> _animationManager;
ActionLayers _actions;
double _lastUpdate;
double _speed;
unsigned int _currentFrame;
unsigned int _fps;
unsigned int _numberFrame;
unsigned int _previousFrameEvaluated;
bool _loop;
bool _initFirstFrame;
State _state;
TimelineStatus _state;
bool _collectStats;
osg::ref_ptr<osg::Stats> _stats;
osg::ref_ptr<osgAnimation::StatsActionVisitor> _statsVisitor;
// to manage pending operation
bool _evaluating;
@@ -202,331 +110,9 @@ namespace osgAnimation
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.get());
_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);
}
void internalRemoveAction(Action* action);
void internalAddAction(int priority, const FrameAction& ftl);
public:
META_Object(osgAnimation, Timeline);
Timeline();
Timeline(const Timeline& nc,const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY);
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
}
};

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,10 +10,10 @@
* 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_ANIMATION_MANAGER_H
#define OSGANIMATION_TIMELINE_ANIMATION_MANAGER_H
#ifndef OSGANIMATION_TIMELINE_ANIMATION_MANAGER
#define OSGANIMATION_TIMELINE_ANIMATION_MANAGER 1
#include <osgAnimation/Export>
#include <osgAnimation/AnimationManagerBase>
@@ -23,21 +23,21 @@
namespace osgAnimation
{
class OSGANIMATION_EXPORT TimelineAnimationManager : public AnimationManagerBase
{
protected:
osg::ref_ptr<Timeline> _timeline;
class OSGANIMATION_EXPORT TimelineAnimationManager : public AnimationManagerBase
{
protected:
osg::ref_ptr<Timeline> _timeline;
public:
META_Object(osgAnimation, TimelineAnimationManager);
TimelineAnimationManager();
TimelineAnimationManager(const AnimationManagerBase& manager);
TimelineAnimationManager(const TimelineAnimationManager& nc,const osg::CopyOp&);
public:
META_Object(osgAnimation, TimelineAnimationManager);
TimelineAnimationManager();
TimelineAnimationManager(const AnimationManagerBase& manager);
TimelineAnimationManager(const TimelineAnimationManager& nc,const osg::CopyOp&);
Timeline* getTimeline() { return _timeline.get(); }
const Timeline* getTimeline() const { return _timeline.get(); }
void update(double time);
};
Timeline* getTimeline() { return _timeline.get(); }
const Timeline* getTimeline() const { return _timeline.get(); }
void update(double time);
};
}

View File

@@ -0,0 +1,36 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_BONE
#define OSGANIMATION_UPDATE_BONE 1
#include <osgAnimation/Export>
#include <osgAnimation/UpdateMatrixTransform>
namespace osgAnimation
{
class OSGANIMATION_EXPORT UpdateBone : public UpdateMatrixTransform
{
public:
META_Object(osgAnimation, UpdateBone);
UpdateBone(const std::string& name = "");
UpdateBone(const UpdateBone&,const osg::CopyOp&);
void operator()(osg::Node* node, osg::NodeVisitor* nv);
};
}
#endif

View File

@@ -0,0 +1,46 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_MATERIAL
#define OSGANIMATION_UPDATE_MATERIAL 1
#include <osgAnimation/AnimationUpdateCallback>
#include <osgAnimation/Export>
#include <osg/StateAttribute>
#include <osg/Material>
namespace osgAnimation
{
class OSGANIMATION_EXPORT UpdateMaterial : public AnimationUpdateCallback<osg::StateAttributeCallback>
{
protected:
osg::ref_ptr<Vec4Target> _diffuse;
public:
META_Object(osgAnimation, UpdateMaterial);
UpdateMaterial(const std::string& name = "");
UpdateMaterial(const UpdateMaterial& apc,const osg::CopyOp& copyop);
/** Callback method called by the NodeVisitor when visiting a node.*/
virtual void operator () (osg::StateAttribute*, osg::NodeVisitor*);
void update(osg::Material& material);
bool link(Channel* channel);
Vec4Target* getDiffuse();
};
}
#endif

View File

@@ -0,0 +1,48 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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_MATRIX_TRANSFORM
#define OSGANIMATION_UPDATE_MATRIX_TRANSFORM 1
#include <osgAnimation/Export>
#include <osgAnimation/AnimationUpdateCallback>
#include <osgAnimation/StackedTransform>
#include <osg/NodeCallback>
namespace osgAnimation
{
class OSGANIMATION_EXPORT UpdateMatrixTransform : public AnimationUpdateCallback<osg::NodeCallback>
{
public:
META_Object(osgAnimation, UpdateMatrixTransform);
UpdateMatrixTransform(const std::string& name = "");
UpdateMatrixTransform(const UpdateMatrixTransform& apc,const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
// Callback method called by the NodeVisitor when visiting a node.
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
virtual bool link(osgAnimation::Channel* channel);
StackedTransform& getStackedTransforms() { return _transforms;}
const StackedTransform& getStackedTransforms() const { return _transforms;}
protected:
StackedTransform _transforms;
};
}
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -12,8 +12,8 @@
* OpenSceneGraph Public License for more details.
*/
#ifndef OSGANIMATION_VERTEX_INFLUENCES_H
#define OSGANIMATION_VERTEX_INFLUENCES_H
#ifndef OSGANIMATION_VERTEX_INFLUENCE
#define OSGANIMATION_VERTEX_INFLUENCE 1
#include <osg/Object>
#include <osgAnimation/Export>
@@ -38,8 +38,6 @@ namespace osgAnimation
std::string _name;
};
// typedef std::map<std::string, VertexInfluence> VertexInfluenceMap;
class VertexInfluenceMap : public std::map<std::string, VertexInfluence> , public osg::Object
{
public:
@@ -52,7 +50,7 @@ namespace osgAnimation
// this class manage VertexInfluence database by mesh
// reference bones per vertex ...
class VertexInfluenceSet
class OSGANIMATION_EXPORT VertexInfluenceSet
{
public:
typedef std::vector<VertexInfluence> BoneToVertexList;
@@ -73,7 +71,7 @@ namespace osgAnimation
typedef std::vector<BoneWeight> BoneWeightList;
typedef std::map<int,BoneWeightList> VertexIndexToBoneWeightMap;
class UniqVertexSetToBoneSet
class UniqVertexSetToBoneSet
{
public:
void setBones(BoneWeightList& bones) { _bones = bones;}
@@ -88,14 +86,12 @@ namespace osgAnimation
typedef std::vector<UniqVertexSetToBoneSet> UniqVertexSetToBoneSetList;
const UniqVertexSetToBoneSetList& getUniqVertexSetToBoneSetList() const { return _uniqVertexSetToBoneSet;}
void addVertexInfluence(const VertexInfluence& v) { _bone2Vertexes.push_back(v); }
void addVertexInfluence(const VertexInfluence& v);
void buildVertex2BoneList();
void buildUniqVertexSetToBoneSetList();
void clear()
{
_bone2Vertexes.clear();
_uniqVertexSetToBoneSet.clear();
}
void clear();
const VertexIndexToBoneWeightMap& getVertexToBoneList() const;
protected:
BoneToVertexList _bone2Vertexes;
VertexIndexToBoneWeightMap _vertex2Bones;

View File

@@ -0,0 +1,83 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/Action>
using namespace osgAnimation;
Action::Action()
{
_numberFrame = 25;
_fps = 25;
_speed = 1.0;
_loop = 1;
}
Action::Action(const Action&,const osg::CopyOp&) {}
Action::Callback* Action::getFrameCallback(unsigned int frame)
{
if (_framesCallback.find(frame) != _framesCallback.end())
{
return _framesCallback[frame].get();
}
return 0;
}
void Action::removeCallback(Callback* cb)
{
std::vector<unsigned int> keyToRemove;
for (FrameCallback::iterator it = _framesCallback.begin(); it != _framesCallback.end(); ++it)
{
if (it->second.get())
{
if (it->second.get() == cb)
{
it->second = it->second->getNestedCallback();
if (!it->second.valid())
keyToRemove.push_back(it->first);
}
else
{
it->second->removeCallback(cb);
}
}
}
for (std::vector<unsigned int>::iterator it = keyToRemove.begin(); it != keyToRemove.end(); ++it)
_framesCallback.erase(*it);
}
Action::Callback* Action::getFrameCallback(double time)
{
unsigned int frame = static_cast<unsigned int>(floor(time * _fps));
return getFrameCallback(frame);
}
bool osgAnimation::Action::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;
}

View File

@@ -0,0 +1,32 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionAnimation>
using namespace osgAnimation;
ActionAnimation::ActionAnimation() {}
ActionAnimation::ActionAnimation(const ActionAnimation& a, const osg::CopyOp& c) : Action(a,c) { _animation = a._animation;}
ActionAnimation::ActionAnimation(Animation* animation) : _animation(animation)
{
Action::setDuration(animation->getDuration());
setName(animation->getName());
}
void ActionAnimation::updateAnimation(unsigned int frame, int priority)
{
_animation->update(frame * 1.0/_fps, priority);
}

View File

@@ -0,0 +1,45 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionBlendIn>
using namespace osgAnimation;
ActionBlendIn::ActionBlendIn() : _weight(0) {}
ActionBlendIn::ActionBlendIn(const ActionBlendIn& a, const osg::CopyOp& c) : Action(a,c)
{
_weight = a._weight;
_animation = a._animation;
}
ActionBlendIn::ActionBlendIn(Animation* animation, double duration, double weight)
{
_animation = animation;
_weight = weight;
float d = duration * _fps;
setNumFrames(static_cast<unsigned int>(floor(d)) + 1);
setName("BlendIn");
}
void ActionBlendIn::computeWeight(unsigned int 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 * ratio;
osg::notify(osg::DEBUG_INFO) << getName() << " BlendIn frame " << frame << " weight " << w << std::endl;
_animation->setWeight(w);
}

View File

@@ -0,0 +1,41 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionBlendOut>
using namespace osgAnimation;
ActionBlendOut::ActionBlendOut() : _weight(0) {}
ActionBlendOut::ActionBlendOut(const ActionBlendOut& a, const osg::CopyOp& c) : Action(a,c)
{
_weight = a._weight;
_animation = a._animation;
}
ActionBlendOut::ActionBlendOut(Animation* animation, double duration)
{
_animation = animation;
float d = duration * _fps;
setNumFrames(static_cast<unsigned int>(floor(d) + 1));
_weight = 1.0;
setName("BlendOut");
}
void ActionBlendOut::computeWeight(unsigned int frame)
{
double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
double w = _weight * (1.0-ratio);
osg::notify(osg::DEBUG_INFO) << getName() << " BlendOut frame " << frame << " weight " << w << std::endl;
_animation->setWeight(w);
}

View File

@@ -0,0 +1,23 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionCallback>
#include <osgAnimation/Timeline>
void osgAnimation::RunAction::operator()(Action* action, ActionVisitor* visitor)
{
Timeline* tm = visitor->getCurrentTimeline();
tm->addActionNow(_action.get(), _priority);
}

View File

@@ -0,0 +1,88 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/ActionStripAnimation>
using namespace osgAnimation;
ActionAnimation* ActionStripAnimation::getAnimation() { return _animation.get(); }
ActionBlendIn* ActionStripAnimation::getBlendIn() { return _blendIn.get(); }
ActionBlendOut* ActionStripAnimation::getBlendOut() { return _blendOut.second.get(); }
const ActionAnimation* ActionStripAnimation::getAnimation() const { return _animation.get(); }
const ActionBlendIn* ActionStripAnimation::getBlendIn() const { return _blendIn.get(); }
const ActionBlendOut* ActionStripAnimation::getBlendOut() const { return _blendOut.second.get(); }
unsigned int ActionStripAnimation::getBlendOutStartFrame() const { return _blendOut.first; }
unsigned int ActionStripAnimation::getLoop() const { return _animation->getLoop(); }
ActionStripAnimation::ActionStripAnimation(const ActionStripAnimation& a, const osg::CopyOp& c) : Action(a,c)
{
_animation = a._animation;
_blendIn = a._blendIn;
_blendOut = a._blendOut;
}
ActionStripAnimation::ActionStripAnimation(Animation* animation, double blendInDuration, double blendOutDuration, double blendInWeightTarget)
{
_blendIn = new ActionBlendIn(animation, blendInDuration, blendInWeightTarget);
_animation = new ActionAnimation(animation);
unsigned int start = static_cast<unsigned int>(floor((_animation->getDuration() - blendOutDuration) * _fps));
_blendOut = FrameBlendOut(start, new ActionBlendOut(animation, blendOutDuration));
setName(animation->getName() + "_Strip");
_blendIn->setName(_animation->getName() + "_" + _blendIn->getName());
_blendOut.second->setName(_animation->getName() + "_" + _blendOut.second->getName());
setDuration(animation->getDuration());
}
void ActionStripAnimation::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 = FrameBlendOut(start, _blendOut.second);
}
void ActionStripAnimation::traverse(ActionVisitor& visitor)
{
if (_blendIn.valid())
{
unsigned int f = visitor.getStackedFrameAction().back().first;
visitor.pushFrameActionOnStack(FrameAction(f,_blendIn.get()));
_blendIn->accept(visitor);
visitor.popFrameAction();
}
if (_blendOut.second.valid())
{
unsigned int f = visitor.getStackedFrameAction().back().first;
visitor.pushFrameActionOnStack(FrameAction(f + _blendOut.first,_blendOut.second.get()));
_blendOut.second.get()->accept(visitor);
visitor.popFrameAction();
}
if (_animation.valid())
{
unsigned int f = visitor.getStackedFrameAction().back().first;
visitor.pushFrameActionOnStack(FrameAction(f,_animation.get()));
_animation->accept(visitor);
visitor.popFrameAction();
}
}

View File

@@ -0,0 +1,184 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/Action>
#include <osgAnimation/ActionBlendIn>
#include <osgAnimation/ActionBlendOut>
#include <osgAnimation/ActionStripAnimation>
#include <osgAnimation/ActionAnimation>
#include <osgAnimation/ActionVisitor>
#include <osgAnimation/Timeline>
using namespace osgAnimation;
ActionVisitor::ActionVisitor()
{
_currentLayer = 0;
}
void ActionVisitor::pushFrameActionOnStack(const FrameAction& fa) { _stackFrameAction.push_back(fa); }
void ActionVisitor::popFrameAction() { _stackFrameAction.pop_back(); }
void ActionVisitor::pushTimelineOnStack(Timeline* tm) { _stackTimeline.push_back(tm); }
void ActionVisitor::popTimeline() { _stackTimeline.pop_back(); }
void ActionVisitor::apply(Action& action) { traverse(action); }
void ActionVisitor::apply(Timeline& tm) { tm.traverse(*this); }
void ActionVisitor::apply(ActionBlendIn& action) { apply(static_cast<Action&>(action));}
void ActionVisitor::apply(ActionBlendOut& action) { apply(static_cast<Action&>(action)); }
void ActionVisitor::apply(ActionAnimation& action) { apply(static_cast<Action&>(action)); }
void ActionVisitor::apply(ActionStripAnimation& action) { apply(static_cast<Action&>(action)); }
void ActionVisitor::traverse(Action& action)
{
action.traverse(*this);
}
Timeline* ActionVisitor::getCurrentTimeline()
{
if (_stackTimeline.empty())
return 0;
return _stackTimeline.back();
}
UpdateActionVisitor::UpdateActionVisitor()
{
_frame = 0;
_currentAnimationPriority = 0;
}
void UpdateActionVisitor::apply(Timeline& tm)
{
_currentAnimationPriority = 0;
tm.setEvaluating(true);
tm.traverse(*this);
tm.setEvaluating(false);
tm.setLastFrameEvaluated(_frame);
}
bool UpdateActionVisitor::isActive(Action& action) const
{
FrameAction fa = _stackFrameAction.back();
if (_frame < fa.first)
return false;
if (!fa.second.valid())
return false;
unsigned int f = getLocalFrame();
unsigned int frameInAction;
unsigned int loopDone;
return action.evaluateFrame(f, frameInAction, loopDone);
}
unsigned int UpdateActionVisitor::getLocalFrame() const
{
return _frame - _stackFrameAction.back().first;
}
void UpdateActionVisitor::apply(Action& action)
{
if (isActive(action))
{
unsigned int frame = getLocalFrame();
unsigned int frameInAction;
unsigned int loopDone;
bool result = action.evaluateFrame(frame, frameInAction, loopDone);
if (!result)
{
osg::notify(osg::DEBUG_INFO) << action.getName() << " Action frame " << frameInAction << " finished" << std::endl;
return;
}
osg::notify(osg::DEBUG_INFO) << action.getName() << " Action frame " << frame << " relative to loop " << frameInAction << " no loop " << loopDone<< std::endl;
frame = frameInAction;
Action::Callback* cb = action.getFrameCallback(frame);
while (cb)
{
osg::notify(osg::DEBUG_INFO) << action.getName() << " evaluate callback " << cb->getName() << " at " << frame << std::endl;
(*cb)(&action, this);
cb = cb->getNestedCallback();
}
}
}
void UpdateActionVisitor::apply(ActionBlendIn& action)
{
if (isActive(action))
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
action.computeWeight(frame);
}
}
void UpdateActionVisitor::apply(ActionBlendOut& action)
{
if (isActive(action))
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
action.computeWeight(frame);
}
}
void UpdateActionVisitor::apply(ActionAnimation& action)
{
if (isActive(action))
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
int pri = static_cast<int>(_currentAnimationPriority);
_currentAnimationPriority++;
action.updateAnimation(frame, -pri);
}
}
void UpdateActionVisitor::apply(ActionStripAnimation& action)
{
if (isActive(action))
{
apply(static_cast<Action&>(action));
action.traverse(*this);
}
}
ClearActionVisitor::ClearActionVisitor(ClearType type) : _clearType(type)
{
}
void ClearActionVisitor::apply(Timeline& tm)
{
_remove.clear();
tm.traverse(*this);
for (int i = 0; i < (int)_remove.size(); i++)
tm.removeAction(_remove[i].get());
}
void ClearActionVisitor::apply(Action& action)
{
FrameAction fa = _stackFrameAction.back();
switch( _clearType) {
case BEFORE_FRAME:
if (_frame > fa.first)
_remove.push_back(&action);
break;
case AFTER_FRAME:
if (_frame - fa.first > action.getNumFrames())
_remove.push_back(&action);
break;
}
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -16,13 +16,18 @@
using namespace osgAnimation;
Animation::Animation(const osgAnimation::Animation& anim, const osg::CopyOp& c)
Animation::Animation(const osgAnimation::Animation& anim, const osg::CopyOp& copyop): osg::Object(anim, copyop),
_duration(anim._duration),
_originalDuration(anim._originalDuration),
_weight(anim._weight),
_startTime(anim._startTime),
_playmode(anim._playmode)
{
_duration = anim._duration;
_originalDuration = anim._originalDuration;
_weight = anim._weight;
_startTime = anim._startTime;
_playmode = anim._playmode;
const ChannelList& cl = anim.getChannels();
for (ChannelList::const_iterator it = cl.begin(); it != cl.end(); ++it)
{
addChannel(it->get()->clone());
}
}
@@ -90,7 +95,7 @@ void Animation::setWeight (float weight)
_weight = weight;
}
bool Animation::update (float time)
bool Animation::update (float time, int priority)
{
if (!_duration) // if not initialized then do it
computeDuration();
@@ -128,13 +133,10 @@ bool Animation::update (float time)
break;
}
// std::cout << "t " << t << " / " << _duration << std::endl;
ChannelList::const_iterator chan;
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
{
(*chan)->setWeight(_weight);
(*chan)->update(t);
(*chan)->update(t, _weight, priority);
}
return true;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -14,6 +14,7 @@
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/LinkVisitor>
#include <algorithm>
using namespace osgAnimation;
@@ -21,23 +22,27 @@ AnimationManagerBase::~AnimationManagerBase() {}
AnimationManagerBase::AnimationManagerBase()
{
_needToLink = false;
_needToLink = false;
_automaticLink = true;
}
void AnimationManagerBase::clearTargets()
{
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); ++it)
(*it).get()->reset();
}
void AnimationManagerBase::normalizeTargets()
void AnimationManagerBase::dirty()
{
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->normalize();
_needToLink = true;
}
void AnimationManagerBase::setAutomaticLink(bool state) { _automaticLink = state; }
bool AnimationManagerBase::isAutomaticLink() const { return _automaticLink; }
void AnimationManagerBase::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
if (needToLink())
{
@@ -57,22 +62,30 @@ void AnimationManagerBase::operator()(osg::Node* node, osg::NodeVisitor* nv)
}
AnimationManagerBase::AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop) : osg::NodeCallback(b,copyop)
AnimationManagerBase::AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop) : osg::NodeCallback(b,copyop)
{
_animations = b._animations;
_targets = b._targets;
_needToLink = b._needToLink;
const AnimationList& animationList = b.getAnimationList();
for (AnimationList::const_iterator it = animationList.begin();
it != animationList.end();
++it)
{
Animation* animation = dynamic_cast<osgAnimation::Animation*>(it->get()->clone(copyop));
_animations.push_back(animation);
}
_needToLink = true;
_automaticLink = b._automaticLink;
buildTargetReference();
}
void AnimationManagerBase::buildTargetReference()
{
_targets.clear();
for( AnimationList::iterator iterAnim = _animations.begin(); iterAnim != _animations.end(); ++iterAnim )
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++)
++it)
_targets.insert((*it)->getTarget());
}
}
@@ -85,14 +98,38 @@ void AnimationManagerBase::registerAnimation (Animation* animation)
buildTargetReference();
}
bool AnimationManagerBase::needToLink() const { return _needToLink; }
void AnimationManagerBase::unregisterAnimation (Animation* animation)
{
AnimationList::iterator it = std::find(_animations.begin(), _animations.end(), animation);
if (it != _animations.end())
{
_animations.erase(it);
}
buildTargetReference();
}
bool AnimationManagerBase::needToLink() const { return _needToLink && isAutomaticLink(); }
void AnimationManagerBase::setLinkVisitor(LinkVisitor* visitor)
{
_linker = visitor;
}
LinkVisitor* AnimationManagerBase::getOrCreateLinkVisitor()
{
if (!_linker.valid())
_linker = new LinkVisitor;
return _linker.get();
}
void AnimationManagerBase::link(osg::Node* subgraph)
{
LinkVisitor linker(_animations);
subgraph->accept(linker);
LinkVisitor* linker = getOrCreateLinkVisitor();
linker->getAnimationList().clear();
linker->getAnimationList() = _animations;
subgraph->accept(*linker);
_needToLink = false;
buildTargetReference();
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -38,7 +38,7 @@ void BasicAnimationManager::stopAll()
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
for (AnimationList::iterator it = list.begin(); it != list.end(); ++it)
(*it)->resetTargets();
}
_animationsPlaying.clear();
@@ -47,14 +47,14 @@ void BasicAnimationManager::stopAll()
void BasicAnimationManager::playAnimation(Animation* pAnimation, int priority, float weight)
{
if (!findAnimation(pAnimation))
{
return;
}
if ( isPlaying(pAnimation) )
stopAnimation(pAnimation);
_animationsPlaying[priority].push_back(pAnimation);
// for debug
//std::cout << "player Animation " << pAnimation->getName() << " at " << _lastUpdate << std::endl;
pAnimation->setStartTime(_lastUpdate);
pAnimation->setWeight(weight);
}
@@ -62,10 +62,10 @@ void BasicAnimationManager::playAnimation(Animation* pAnimation, int priority, f
bool BasicAnimationManager::stopAnimation(Animation* pAnimation)
{
// search though the layer and remove animation
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
for (AnimationList::iterator it = list.begin(); it != list.end(); ++it)
if( (*it) == pAnimation )
{
(*it)->resetTargets();
@@ -79,11 +79,10 @@ bool BasicAnimationManager::stopAnimation(Animation* pAnimation)
void BasicAnimationManager::update (double time)
{
if (!_lastUpdate)
_lastUpdate = time;
_lastUpdate = time; // keep time of last update
// could filtered with an active flag
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); ++it)
(*it).get()->reset();
// update from high priority to low priority
@@ -91,11 +90,20 @@ void BasicAnimationManager::update (double time)
{
// update all animation
std::vector<int> toremove;
int priority = iterAnim->first;
AnimationList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
if (! list[i]->update(time))
if (! list[i]->update(time, priority))
{
// debug
// std::cout << list[i]->getName() << " finished at " << time << std::endl;
toremove.push_back(i);
} else
{
// debug
//std::cout << list[i]->getName() << " updated" << std::endl;
}
}
// remove finished animation
@@ -105,9 +113,6 @@ void BasicAnimationManager::update (double time)
toremove.pop_back();
}
}
for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++)
(*it).get()->normalize();
}
@@ -127,7 +132,7 @@ bool BasicAnimationManager::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++)
for (AnimationList::iterator it = list.begin(); it != list.end(); ++it)
if ( (*it) == pAnimation )
return true;
}
@@ -140,7 +145,7 @@ bool BasicAnimationManager::isPlaying(const std::string& name)
for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim )
{
AnimationList& list = iterAnim->second;
for (AnimationList::iterator it = list.begin(); it != list.end(); it++)
for (AnimationList::iterator it = list.begin(); it != list.end(); ++it)
if ( (*it)->getName() == name )
return true;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -12,36 +12,25 @@
* OpenSceneGraph Public License for more details.
*/
#include <osgAnimation/Skinning>
#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
#include <osgAnimation/UpdateBone>
#include <osgAnimation/BoneMapVisitor>
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)
using namespace osgAnimation;
Bone::Bone(const Bone& b, const osg::CopyOp& copyop) : osg::MatrixTransform(b,copyop), _invBindInSkeletonSpace(b._invBindInSkeletonSpace), _boneInSkeletonSpace(b._boneInSkeletonSpace)
{
}
osgAnimation::Bone::Bone(const Bone& b, const osg::CopyOp& copyop)
: osg::Transform(b,copyop),
_position(b._position),
_rotation(b._rotation),
_scale(b._scale)
{
}
osgAnimation::Bone::Bone(const std::string& name)
Bone::Bone(const std::string& name)
{
if (!name.empty())
setName(name);
_needToRecomputeBindMatrix = false;
}
void osgAnimation::Bone::setDefaultUpdateCallback(const std::string& name)
void Bone::setDefaultUpdateCallback(const std::string& name)
{
std::string cbName = name;
if (cbName.empty())
@@ -49,42 +38,12 @@ void osgAnimation::Bone::setDefaultUpdateCallback(const std::string& name)
setUpdateCallback(new UpdateBone(cbName));
}
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()
Bone* Bone::getBoneParent()
{
if (getParents().empty())
return 0;
osg::Node::ParentList parents = getParents();
for (osg::Node::ParentList::iterator it = parents.begin(); it != parents.end(); it++)
for (osg::Node::ParentList::iterator it = parents.begin(); it != parents.end(); ++it)
{
Bone* pb = dynamic_cast<Bone*>(*it);
if (pb)
@@ -92,12 +51,12 @@ osgAnimation::Bone* osgAnimation::Bone::getBoneParent()
}
return 0;
}
const osgAnimation::Bone* osgAnimation::Bone::getBoneParent() const
const Bone* 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++)
for (osg::Node::ParentList::const_iterator it = parents.begin(); it != parents.end(); ++it)
{
const Bone* pb = dynamic_cast<const Bone*>(*it);
if (pb)
@@ -105,25 +64,3 @@ const osgAnimation::Bone* osgAnimation::Bone::getBoneParent() const
}
return 0;
}
/** Add Node to Group.
* If node is not NULL and is not contained in Group then increment its
* reference count, add it to the child list and dirty the bounding
* sphere to force it to recompute on next getBound() and return true for success.
* Otherwise return false. Scene nodes can't be added as child nodes.
*/
bool osgAnimation::Bone::addChild( Node *child )
{
Bone* bone = dynamic_cast<Bone*>(child);
if (bone)
bone->setNeedToComputeBindMatrix(true);
return osg::Group::addChild(child);
}
osgAnimation::Bone::BoneMap osgAnimation::Bone::getBoneMap()
{
BoneMapVisitor mapVisitor;
this->accept(mapVisitor);
return mapVisitor._map;
}

View File

@@ -0,0 +1,42 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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 <cedric.pinson@plopbyte.net>
*/
#include <osgAnimation/BoneMapVisitor>
#include <osgAnimation/Skeleton>
using namespace osgAnimation;
BoneMapVisitor::BoneMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void BoneMapVisitor::apply(osg::Node&) { return; }
void BoneMapVisitor::apply(osg::Transform& node)
{
Bone* bone = dynamic_cast<Bone*>(&node);
if (bone)
{
_map[bone->getName()] = bone;
traverse(node);
}
Skeleton* skeleton = dynamic_cast<Skeleton*>(&node);
if (skeleton)
traverse(node);
}
const BoneMap& BoneMapVisitor::getBoneMap() const
{
return _map;
}

View File

@@ -1,60 +1,108 @@
IF (DYNAMIC_OPENSCENEGRAPH)
IF(DYNAMIC_OPENSCENEGRAPH)
ADD_DEFINITIONS(-DOSGANIMATION_LIBRARY)
ELSE (DYNAMIC_OPENSCENEGRAPH)
ELSE()
ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC)
ENDIF(DYNAMIC_OPENSCENEGRAPH)
ENDIF()
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}/Action
${HEADER_PATH}/ActionAnimation
${HEADER_PATH}/ActionBlendIn
${HEADER_PATH}/ActionBlendOut
${HEADER_PATH}/ActionCallback
${HEADER_PATH}/ActionStripAnimation
${HEADER_PATH}/ActionVisitor
${HEADER_PATH}/Animation
${HEADER_PATH}/Keyframe
${HEADER_PATH}/Skinning
${HEADER_PATH}/CubicBezier
${HEADER_PATH}/Vec3Packed
${HEADER_PATH}/BasicAnimationManager
${HEADER_PATH}/TimelineAnimationManager
${HEADER_PATH}/AnimationManagerBase
${HEADER_PATH}/UpdateCallback
${HEADER_PATH}/LinkVisitor
${HEADER_PATH}/VertexInfluence
${HEADER_PATH}/AnimationUpdateCallback
${HEADER_PATH}/BasicAnimationManager
${HEADER_PATH}/Bone
${HEADER_PATH}/BoneMapVisitor
${HEADER_PATH}/Channel
${HEADER_PATH}/CubicBezier
${HEADER_PATH}/EaseMotion
${HEADER_PATH}/Assert
${HEADER_PATH}/Timeline
${HEADER_PATH}/Export
${HEADER_PATH}/FrameAction
${HEADER_PATH}/Interpolator
${HEADER_PATH}/Keyframe
${HEADER_PATH}/LinkVisitor
${HEADER_PATH}/MorphGeometry
${HEADER_PATH}/RigGeometry
${HEADER_PATH}/RigTransform
${HEADER_PATH}/RigTransformHardware
${HEADER_PATH}/RigTransformSoftware
${HEADER_PATH}/Sampler
${HEADER_PATH}/Skeleton
${HEADER_PATH}/StackedMatrixElement
${HEADER_PATH}/StackedQuaternionElement
${HEADER_PATH}/StackedRotateAxisElement
${HEADER_PATH}/StackedScaleElement
${HEADER_PATH}/StackedTransformElement
${HEADER_PATH}/StackedTranslateElement
${HEADER_PATH}/StackedTransform
${HEADER_PATH}/StatsVisitor
${HEADER_PATH}/StatsHandler
${HEADER_PATH}/Target
${HEADER_PATH}/Timeline
${HEADER_PATH}/TimelineAnimationManager
${HEADER_PATH}/UpdateBone
${HEADER_PATH}/UpdateMaterial
${HEADER_PATH}/UpdateMatrixTransform
${HEADER_PATH}/Vec3Packed
${HEADER_PATH}/VertexInfluence
)
ADD_LIBRARY(${LIB_NAME}
${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC}
${LIB_PUBLIC_HEADERS}
Channel.cpp
Target.cpp
Action.cpp
ActionAnimation.cpp
ActionBlendIn.cpp
ActionBlendOut.cpp
ActionCallback.cpp
ActionStripAnimation.cpp
ActionVisitor.cpp
Animation.cpp
Bone.cpp
RigGeometry.cpp
AnimationManager.cpp
BasicAnimationManager.cpp
TimelineAnimationManager.cpp
AnimationManagerBase.cpp
BasicAnimationManager.cpp
Bone.cpp
BoneMapVisitor.cpp
Channel.cpp
LinkVisitor.cpp
MorphGeometry.cpp
RigGeometry.cpp
RigTransformHardware.cpp
RigTransformSoftware.cpp
Skeleton.cpp
VertexInfluence.cpp
UpdateCallback.cpp
StackedMatrixElement.cpp
StackedQuaternionElement.cpp
StackedRotateAxisElement.cpp
StackedScaleElement.cpp
StackedTransform.cpp
StackedTranslateElement.cpp
StatsVisitor.cpp
StatsHandler.cpp
Target.cpp
TimelineAnimationManager.cpp
Timeline.cpp
UpdateBone.cpp
UpdateMaterial.cpp
UpdateMatrixTransform.cpp
VertexInfluence.cpp
${OPENSCENEGRAPH_VERSIONINFO_RC}
)
LINK_INTERNAL(${LIB_NAME}
osg
osgText
osgGA
osgViewer
OpenThreads
)

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -15,15 +15,16 @@
#include <osgAnimation/Channel>
using namespace osgAnimation;
Channel::Channel() { _weight=1; }
Channel::Channel() {}
Channel::~Channel() {}
Channel::Channel(const Channel& channel) : osg::Referenced(channel),
_targetName(channel._targetName),
_name(channel._name)
{
}
const std::string& Channel::getName() const { return _name; }
void Channel::setName (const std::string& name) { _name = name; }
const std::string& Channel::getTargetName() const { return _targetName;}
void Channel::setTargetName (const std::string& name) { _targetName = name; }
float Channel::getWeight() const { return _weight;}
void Channel::setWeight(float w) { _weight = w;}

View File

@@ -0,0 +1,87 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/LinkVisitor>
#include <osgAnimation/AnimationUpdateCallback>
#include <osg/Notify>
#include <osg/Geode>
using namespace osgAnimation;
LinkVisitor::LinkVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
{
_nbLinkedTarget = 0;
}
void LinkVisitor::reset()
{
_nbLinkedTarget = 0;
}
AnimationList& LinkVisitor::getAnimationList()
{
return _animations;
}
void LinkVisitor::link(AnimationUpdateCallbackBase* cb)
{
int result = 0;
for (int i = 0; i < (int)_animations.size(); i++)
{
result += cb->link(_animations[i].get());
_nbLinkedTarget += result;
}
osg::notify(osg::NOTICE) << "LinkVisitor links " << result << " for \"" << cb->getName() << '"' << std::endl;
}
void LinkVisitor::handle_stateset(osg::StateSet* stateset)
{
if (!stateset)
return;
osg::StateSet::AttributeList& attr = stateset->getAttributeList();
for (osg::StateSet::AttributeList::iterator it = attr.begin(); it != attr.end(); ++it)
{
osg::StateAttribute* sattr = it->second.first.get();
osgAnimation::AnimationUpdateCallbackBase* cb = dynamic_cast<osgAnimation::AnimationUpdateCallbackBase*>(sattr->getUpdateCallback());
if (cb)
link(cb);
}
}
void LinkVisitor::apply(osg::Node& node)
{
osg::StateSet* st = node.getStateSet();
if (st)
handle_stateset(st);
osg::NodeCallback* cb = node.getUpdateCallback();
while (cb)
{
osgAnimation::AnimationUpdateCallbackBase* cba = dynamic_cast<osgAnimation::AnimationUpdateCallbackBase*>(cb);
if (cba)
link(cba);
cb = cb->getNestedCallback();
}
traverse(node);
}
void LinkVisitor::apply(osg::Geode& node)
{
for (unsigned int i = 0; i < node.getNumDrawables(); i++)
{
osg::Drawable* drawable = node.getDrawable(i);
if (drawable && drawable->getStateSet())
handle_stateset(drawable->getStateSet());
}
apply(static_cast<osg::Node&>(node));
}

View File

@@ -0,0 +1,277 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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:
*
* Roland Smeenk
* Cedric Pinson <cedric.pinson@plopbyte.net>
*
*/
#include <osg/Geode>
#include <osgAnimation/MorphGeometry>
#include <stdlib.h>
using namespace osgAnimation;
MorphGeometry::MorphGeometry() :
_dirty(false),
_method(NORMALIZED),
_morphNormals(true)
{
setUseDisplayList(false);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
setUseVertexBufferObjects(true);
}
MorphGeometry::MorphGeometry(const osg::Geometry& b) :
osg::Geometry(b, osg::CopyOp::DEEP_COPY_ARRAYS),
_dirty(false),
_method(NORMALIZED),
_morphNormals(true)
{
setUseDisplayList(false);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
setUseVertexBufferObjects(true);
if (b.getInternalOptimizedGeometry())
computeInternalOptimizedGeometry();
}
MorphGeometry::MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop) :
osg::Geometry(b,copyop),
_dirty(b._dirty),
_method(b._method),
_morphTargets(b._morphTargets),
_positionSource(b._positionSource),
_normalSource(b._normalSource),
_morphNormals(b._morphNormals)
{
setUseDisplayList(false);
setUseVertexBufferObjects(true);
if (b.getInternalOptimizedGeometry())
computeInternalOptimizedGeometry();
}
void MorphGeometry::transformSoftwareMethod()
{
if (_dirty)
{
// See if we have an internal optimized geometry
osg::Geometry* morphGeometry = this;
if (_internalOptimizedGeometry.valid())
morphGeometry = _internalOptimizedGeometry.get();
osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(morphGeometry->getVertexArray());
if (pos && _positionSource.size() != pos->size())
{
_positionSource = std::vector<osg::Vec3>(pos->begin(),pos->end());
pos->setDataVariance(osg::Object::DYNAMIC);
}
osg::Vec3Array* normal = dynamic_cast<osg::Vec3Array*>(morphGeometry->getNormalArray());
if (normal && _normalSource.size() != normal->size())
{
_normalSource = std::vector<osg::Vec3>(normal->begin(),normal->end());
normal->setDataVariance(osg::Object::DYNAMIC);
}
if (!_positionSource.empty())
{
bool initialized = false;
if (_method == NORMALIZED)
{
// base * 1 - (sum of weights) + sum of (weight * target)
float baseWeight = 0;
for (unsigned int i=0; i < _morphTargets.size(); i++)
{
baseWeight += _morphTargets[i].getWeight();
}
baseWeight = 1 - baseWeight;
if (baseWeight != 0)
{
initialized = true;
for (unsigned int i=0; i < pos->size(); i++)
{
(*pos)[i] = _positionSource[i] * baseWeight;
}
if (_morphNormals)
{
for (unsigned int i=0; i < normal->size(); i++)
{
(*normal)[i] = _normalSource[i] * baseWeight;
}
}
}
}
else //if (_method == RELATIVE)
{
// base + sum of (weight * target)
initialized = true;
for (unsigned int i=0; i < pos->size(); i++)
{
(*pos)[i] = _positionSource[i];
}
if (_morphNormals)
{
for (unsigned int i=0; i < normal->size(); i++)
{
(*normal)[i] = _normalSource[i];
}
}
}
for (unsigned int i=0; i < _morphTargets.size(); i++)
{
if (_morphTargets[i].getWeight() > 0)
{
// See if any the targets use the internal optimized geometry
osg::Geometry* targetGeometry = _morphTargets[i].getGeometry()->getInternalOptimizedGeometry();
if (!targetGeometry)
targetGeometry = _morphTargets[i].getGeometry();
osg::Vec3Array* targetPos = dynamic_cast<osg::Vec3Array*>(targetGeometry->getVertexArray());
osg::Vec3Array* targetNormals = dynamic_cast<osg::Vec3Array*>(targetGeometry->getNormalArray());
if (initialized)
{
// If vertices are initialized, add the morphtargets
for (unsigned int j=0; j < pos->size(); j++)
{
(*pos)[j] += (*targetPos)[j] * _morphTargets[i].getWeight();
}
if (_morphNormals)
{
for (unsigned int j=0; j < normal->size(); j++)
{
(*normal)[j] += (*targetNormals)[j] * _morphTargets[i].getWeight();
}
}
}
else
{
// If not initialized, initialize with this morph target
initialized = true;
for (unsigned int j=0; j < pos->size(); j++)
{
(*pos)[j] = (*targetPos)[j] * _morphTargets[i].getWeight();
}
if (_morphNormals)
{
for (unsigned int j=0; j < normal->size(); j++)
{
(*normal)[j] = (*targetNormals)[j] * _morphTargets[i].getWeight();
}
}
}
}
}
pos->dirty();
if (_morphNormals)
{
for (unsigned int j=0; j < normal->size(); j++)
{
(*normal)[j].normalize();
}
normal->dirty();
}
}
dirtyBound();
_dirty = false;
}
}
UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) :
osg::Object(apc, copyop),
AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
{
}
UpdateMorph::UpdateMorph(const std::string& name) : AnimationUpdateCallback<osg::NodeCallback>(name)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateMorph::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
osg::Geode* geode = dynamic_cast<osg::Geode*>(node);
if (geode)
{
unsigned int numDrawables = geode->getNumDrawables();
for (unsigned int i = 0; i != numDrawables; ++i)
{
osgAnimation::MorphGeometry* morph = dynamic_cast<osgAnimation::MorphGeometry*>(geode->getDrawable(i));
if (morph)
{
// Update morph weights
std::map<int, osg::ref_ptr<osgAnimation::FloatTarget> >::iterator iter = _weightTargets.begin();
while (iter != _weightTargets.end())
{
if (iter->second->getValue() >= 0)
{
morph->setWeight(iter->first, iter->second->getValue());
}
++iter;
}
}
}
}
}
traverse(node,nv);
}
bool UpdateMorph::needLink() const
{
// the idea is to return true if nothing is linked
return (_weightTargets.size() == 0);
}
bool UpdateMorph::link(osgAnimation::Channel* channel)
{
// Typically morph geometries only have the weights for morph targets animated
// Expect a weight value
// TODO Should we make this more generic to handle other things than single values?
int weightIndex = atoi(channel->getName().c_str());
if (weightIndex >= 0)
{
osgAnimation::FloatTarget* ft = _weightTargets[weightIndex].get();
if (!ft)
{
ft = new osgAnimation::FloatTarget;
_weightTargets[weightIndex] = ft;
}
return channel->setTarget(ft);
}
else
{
osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
}
return false;
}

View File

@@ -1,129 +1,209 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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:
* 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.
*
* Cedric Pinson <mornifle@plopbyte.net>
*
* 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 <osgAnimation/RigGeometry>
#include <osgAnimation/RigTransformSoftware>
#include <sstream>
#include <osg/GL2Extensions>
using namespace osgAnimation;
// The idea is to compute a bounding box with a factor x of the first step we compute the bounding box
class RigComputeBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback
{
public:
RigComputeBoundingBoxCallback(double factor = 2.0) : _computed(false), _factor(factor) {}
void reset() { _computed = false; }
virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const
{
const osgAnimation::RigGeometry& rig = dynamic_cast<const osgAnimation::RigGeometry&>(drawable);
// if a valid inital bounding box is set we use it without asking more
if (rig.getInitialBound().valid())
return rig.getInitialBound();
if (_computed)
return _boundingBox;
// if the computing of bb is invalid (like no geometry inside)
// then dont tag the bounding box as computed
osg::BoundingBox bb = rig.computeBound();
if (!bb.valid())
return bb;
_boundingBox.expandBy(bb);
osg::Vec3 center = _boundingBox.center();
osg::Vec3 vec = (_boundingBox._max-center)*_factor;
_boundingBox.expandBy(center + vec);
_boundingBox.expandBy(center - vec);
_computed = true;
// osg::notify(osg::NOTICE) << "build the bounding box for RigGeometry " << rig.getName() << " " << _boundingBox._min << " " << _boundingBox._max << std::endl;
return _boundingBox;
}
protected:
mutable bool _computed;
double _factor;
mutable osg::BoundingBox _boundingBox;
};
RigGeometry::RigGeometry()
{
setUseDisplayList(false);
_supportsDisplayList = false;
setUseVertexBufferObjects(true);
setUpdateCallback(new UpdateVertex);
setDataVariance(osg::Object::DYNAMIC);
_needToComputeMatrix = true;
_matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity();
// disable the computation of boundingbox for the rig mesh
setComputeBoundingBoxCallback(new RigComputeBoundingBoxCallback);
}
RigGeometry::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::RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop) :
RigGeometry::RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop) :
osg::Geometry(b,copyop),
_positionSource(b._positionSource),
_normalSource(b._normalSource),
_geometry(b._geometry),
_vertexInfluenceSet(b._vertexInfluenceSet),
_vertexInfluenceMap(b._vertexInfluenceMap),
_transformVertexes(b._transformVertexes),
_needToComputeMatrix(b._needToComputeMatrix)
_needToComputeMatrix(b._needToComputeMatrix)
{
// we dont copy the RigImplementation yet. because the RigImplementation need to be initialized in a valid graph, with a skeleton ...
// dont know yet what to do with a clone of a RigGeometry
}
void RigGeometry::buildTransformer(Skeleton* root)
const osg::Matrix& RigGeometry::getMatrixFromSkeletonToGeometry() const { return _matrixFromSkeletonToGeometry; }
const osg::Matrix& RigGeometry::getInvMatrixFromSkeletonToGeometry() const { return _invMatrixFromSkeletonToGeometry;}
void RigGeometry::drawImplementation(osg::RenderInfo& renderInfo) const
{
Bone::BoneMap bm = root->getBoneMap();
_transformVertexes.init(bm, _vertexInfluenceSet.getUniqVertexSetToBoneSetList());
_root = root;
osg::Geometry::drawImplementation(renderInfo);
}
void RigGeometry::buildVertexSet()
void RigGeometry::buildVertexInfluenceSet()
{
if (!_vertexInfluenceMap.valid())
if (!_vertexInfluenceMap.valid())
{
osg::notify(osg::WARN) << "buildVertexSet can't be called without VertexInfluence already set to the RigGeometry ( " << getName() << " ) " << std::endl;
osg::notify(osg::WARN) << "buildVertexInfluenceSet 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++)
++it)
_vertexInfluenceSet.addVertexInfluence(it->second);
_vertexInfluenceSet.buildVertex2BoneList();
_vertexInfluenceSet.buildUniqVertexSetToBoneSetList();
std::cout << "uniq groups " << _vertexInfluenceSet.getUniqVertexSetToBoneSetList().size() << " for " << getName() << std::endl;
osg::notify(osg::NOTICE) << "uniq groups " << _vertexInfluenceSet.getUniqVertexSetToBoneSetList().size() << " for " << getName() << std::endl;
}
void RigGeometry::computeMatrixFromRootSkeleton()
void RigGeometry::computeMatrixFromRootSkeleton()
{
if (!_root.valid())
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];
osg::Matrix notRoot = _root->getMatrix();
_matrixFromSkeletonToGeometry = mtxList[0] * osg::Matrix::inverse(notRoot);
_invMatrixFromSkeletonToGeometry = osg::Matrix::inverse(_matrixFromSkeletonToGeometry);
_needToComputeMatrix = false;
}
void RigGeometry::transformSoftwareMethod()
void RigGeometry::update()
{
setUseDisplayList(false);
setUseVertexBufferObjects(true);
// std::cout << getName() << " _matrixFromSkeletonToGeometry" << _matrixFromSkeletonToGeometry << std::endl;
osg::Vec3Array* pos = dynamic_cast<osg::Vec3Array*>(getVertexArray());
if (pos && _positionSource.size() != pos->size())
if (!getRigTransformImplementation())
{
_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);
_rigTransformImplementation = new RigTransformSoftware;
}
if (!_positionSource.empty())
{
_transformVertexes.compute<osg::Vec3>(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_positionSource.front(), &pos->front());
pos->dirty();
}
if (!_normalSource.empty())
{
_transformVertexes.computeNormal<osg::Vec3>(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_normalSource.front(), &normal->front());
normal->dirty();
}
if (getUseDisplayList())
dirtyDisplayList();
dirtyBound();
RigTransform& implementation = *getRigTransformImplementation();
(implementation)(*this);
}
const osgAnimation::Skeleton* RigGeometry::getSkeleton() const { return _root.get(); }
osgAnimation::Skeleton* RigGeometry::getSkeleton() { return _root.get(); }
void RigGeometry::copyFrom(osg::Geometry& from)
{
bool copyToSelf = (this==&from);
osg::Geometry& target = *this;
if (!copyToSelf) target.setStateSet(from.getStateSet());
// copy over primitive sets.
if (!copyToSelf) target.getPrimitiveSetList() = from.getPrimitiveSetList();
if (from.getVertexArray())
{
if (!copyToSelf) target.setVertexArray(from.getVertexArray());
}
target.setNormalBinding(from.getNormalBinding());
if (from.getNormalArray())
{
if (!copyToSelf) target.setNormalArray(from.getNormalArray());
}
target.setColorBinding(from.getColorBinding());
if (from.getColorArray())
{
if (!copyToSelf) target.setColorArray(from.getColorArray());
}
target.setSecondaryColorBinding(from.getSecondaryColorBinding());
if (from.getSecondaryColorArray())
{
if (!copyToSelf) target.setSecondaryColorArray(from.getSecondaryColorArray());
}
target.setFogCoordBinding(from.getFogCoordBinding());
if (from.getFogCoordArray())
{
if (!copyToSelf) target.setFogCoordArray(from.getFogCoordArray());
}
for(unsigned int ti=0;ti<from.getNumTexCoordArrays();++ti)
{
if (from.getTexCoordArray(ti))
{
if (!copyToSelf) target.setTexCoordArray(ti,from.getTexCoordArray(ti));
}
}
ArrayDataList& arrayList = from.getVertexAttribArrayList();
for(unsigned int vi=0;vi< arrayList.size();++vi)
{
ArrayData& arrayData = arrayList[vi];
if (arrayData.array.valid())
{
if (!copyToSelf) target.setVertexAttribData(vi,arrayData);
}
}
}
const VertexInfluenceSet& RigGeometry::getVertexInfluenceSet() const { return _vertexInfluenceSet;}
const Skeleton* RigGeometry::getSkeleton() const { return _root.get(); }
Skeleton* RigGeometry::getSkeleton() { return _root.get(); }
void RigGeometry::setSkeleton(Skeleton* root) { _root = root;}
RigTransform* RigGeometry::getRigTransformImplementation() { return _rigTransformImplementation.get(); }
void RigGeometry::setRigTransformImplementation(RigTransform* rig) { _rigTransformImplementation = rig; }
osg::Geometry* RigGeometry::getSourceGeometry() { return _geometry.get(); }
const osg::Geometry* RigGeometry::getSourceGeometry() const { return _geometry.get(); }
void RigGeometry::setSourceGeometry(osg::Geometry* geometry) { _geometry = geometry; }

View File

@@ -0,0 +1,272 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/RigTransformHardware>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/BoneMapVisitor>
#include <sstream>
using namespace osgAnimation;
RigTransformHardware::RigTransformHardware()
{
_needInit = true;
_bonesPerVertex = 0;
_nbVertexes = 0;
}
osg::Vec4Array* RigTransformHardware::getVertexAttrib(int index)
{
if (index >= (int)_boneWeightAttribArrays.size())
return 0;
return _boneWeightAttribArrays[index].get();
}
int RigTransformHardware::getNumVertexAttrib()
{
return _boneWeightAttribArrays.size();
}
osg::Uniform* RigTransformHardware::getMatrixPaletteUniform()
{
return _uniformMatrixPalette.get();
}
void RigTransformHardware::computeMatrixPaletteUniform(const osg::Matrix& transformFromSkeletonToGeometry, const osg::Matrix& invTransformFromSkeletonToGeometry)
{
for (int i = 0; i < (int)_bonePalette.size(); i++)
{
osg::ref_ptr<Bone> bone = _bonePalette[i].get();
const osg::Matrix& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace();
const osg::Matrix& boneMatrix = bone->getMatrixInSkeletonSpace();
osg::Matrix resultBoneMatrix = invBindMatrix * boneMatrix;
osg::Matrix result = transformFromSkeletonToGeometry * resultBoneMatrix * invTransformFromSkeletonToGeometry;
if (!_uniformMatrixPalette->setElement(i, result))
osg::notify(osg::WARN) << "RigTransformHardware::computeUniformMatrixPalette can't set uniform at " << i << " elements" << std::endl;
}
}
int RigTransformHardware::getNumBonesPerVertex() const { return _bonesPerVertex;}
int RigTransformHardware::getNumVertexes() const { return _nbVertexes;}
bool RigTransformHardware::createPalette(int nbVertexes, BoneMap boneMap, const VertexInfluenceSet::VertexIndexToBoneWeightMap& vertexIndexToBoneWeightMap)
{
typedef std::map<std::string, int> BoneNameCountMap;
typedef std::map<std::string, int> BoneNamePaletteIndex;
BoneNamePaletteIndex bname2palette;
BonePalette palette;
BoneNameCountMap boneNameCountMap;
// init vertex attribute data
VertexIndexWeightList vertexIndexWeight;
vertexIndexWeight.resize(nbVertexes);
int maxBonePerVertex = 0;
for (VertexInfluenceSet::VertexIndexToBoneWeightMap::const_iterator it = vertexIndexToBoneWeightMap.begin(); it != vertexIndexToBoneWeightMap.end(); ++it)
{
int vertexIndex = it->first;
const VertexInfluenceSet::BoneWeightList& boneWeightList = it->second;
int bonesForThisVertex = 0;
for (VertexInfluenceSet::BoneWeightList::const_iterator it = boneWeightList.begin(); it != boneWeightList.end(); ++it)
{
const VertexInfluenceSet::BoneWeight& bw = *it;
if (boneNameCountMap.find(bw.getBoneName()) != boneNameCountMap.end())
{
boneNameCountMap[bw.getBoneName()]++;
bonesForThisVertex++; // count max number of bones per vertexes
vertexIndexWeight[vertexIndex].push_back(IndexWeightEntry(bname2palette[bw.getBoneName()],bw.getWeight()));
}
else if (fabs(bw.getWeight()) > 1e-2) // dont use bone with weight too small
{
if (boneMap.find(bw.getBoneName()) == boneMap.end())
{
osg::notify(osg::INFO) << "RigTransformHardware::createPalette can't find bone " << bw.getBoneName() << " skip this influence" << std::endl;
continue;
}
boneNameCountMap[bw.getBoneName()] = 1; // for stats
bonesForThisVertex++;
palette.push_back(boneMap[bw.getBoneName()]);
bname2palette[bw.getBoneName()] = palette.size()-1;
vertexIndexWeight[vertexIndex].push_back(IndexWeightEntry(bname2palette[bw.getBoneName()],bw.getWeight()));
}
else
{
osg::notify(osg::WARN) << "RigTransformHardware::createPalette Bone " << bw.getBoneName() << " has a weight " << bw.getWeight() << " for vertex " << vertexIndex << " this bone will not be in the palette" << std::endl;
}
}
maxBonePerVertex = osg::maximum(maxBonePerVertex, bonesForThisVertex);
}
osg::notify(osg::INFO) << "RigTransformHardware::createPalette maximum number of bone per vertex is " << maxBonePerVertex << std::endl;
osg::notify(osg::INFO) << "RigTransformHardware::createPalette matrix palette has " << boneNameCountMap.size() << " entries" << std::endl;
for (BoneNameCountMap::iterator it = boneNameCountMap.begin(); it != boneNameCountMap.end(); ++it)
{
osg::notify(osg::INFO) << "RigTransformHardware::createPalette Bone " << it->first << " is used " << it->second << " times" << std::endl;
}
osg::notify(osg::INFO) << "RigTransformHardware::createPalette will use " << boneNameCountMap.size() * 4 << " uniforms" << std::endl;
for (int i = 0 ; i < (int)vertexIndexWeight.size(); i++)
vertexIndexWeight[i].resize(maxBonePerVertex);
_nbVertexes = nbVertexes;
_bonesPerVertex = maxBonePerVertex;
_bonePalette = palette;
_vertexIndexMatrixWeightList = vertexIndexWeight;
_uniformMatrixPalette = createVertexUniform();
_boneWeightAttribArrays = createVertexAttribList();
return true;
}
//
// create vertex attribute by 2 bones
// vec4(boneIndex0, weight0, boneIndex1, weight1)
// if more bones are needed then other attributes are created
// vec4(boneIndex2, weight2, boneIndex3, weight3)
// the idea is to use this format to have a granularity smaller
// than the 4 bones using two vertex attributes
//
RigTransformHardware::BoneWeightAttribList RigTransformHardware::createVertexAttribList()
{
BoneWeightAttribList arrayList;
int nbArray = static_cast<int>(ceilf(getNumBonesPerVertex() * 0.5));
if (!nbArray)
return arrayList;
arrayList.resize(nbArray);
for (int i = 0; i < nbArray; i++)
{
osg::ref_ptr<osg::Vec4Array> array = new osg::Vec4Array;
arrayList[i] = array;
int nbVertexes = getNumVertexes();
array->resize(nbVertexes);
for (int j = 0; j < nbVertexes; j++)
{
for (int b = 0; b < 2; b++)
{
// the granularity is 2 so if we have only one bone
// it's convenient to init the second with a weight 0
int boneIndexInList = i*2 + b;
int boneIndexInVec4 = b*2;
(*array)[j][0 + boneIndexInVec4] = 0;
(*array)[j][1 + boneIndexInVec4] = 0;
if (boneIndexInList < getNumBonesPerVertex())
{
float boneIndex = static_cast<float>(_vertexIndexMatrixWeightList[j][boneIndexInList].getIndex());
float boneWeight = _vertexIndexMatrixWeightList[j][boneIndexInList].getWeight();
// fill the vec4
(*array)[j][0 + boneIndexInVec4] = boneIndex;
(*array)[j][1 + boneIndexInVec4] = boneWeight;
}
}
}
}
return arrayList;
}
osg::Uniform* RigTransformHardware::createVertexUniform()
{
osg::Uniform* uniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "matrixPalette", _bonePalette.size());
return uniform;
}
void RigTransformHardware::setShader(osg::Shader* shader)
{
_shader = shader;
}
bool RigTransformHardware::init(RigGeometry& geom)
{
osg::Geometry& source = *geom.getSourceGeometry();
osg::Vec3Array* positionSrc = dynamic_cast<osg::Vec3Array*>(source.getVertexArray());
if (!positionSrc)
{
osg::notify(osg::WARN) << "RigTransformHardware no vertex array in the geometry " << geom.getName() << std::endl;
return false;
}
if (!geom.getSkeleton())
{
osg::notify(osg::WARN) << "RigTransformHardware no skeleton set in geometry " << geom.getName() << std::endl;
return false;
}
// copy shallow from source geometry to rig
geom.copyFrom(source);
BoneMapVisitor mapVisitor;
geom.getSkeleton()->accept(mapVisitor);
BoneMap bm = mapVisitor.getBoneMap();
if (!createPalette(positionSrc->size(),bm, geom.getVertexInfluenceSet().getVertexToBoneList()))
return false;
osg::ref_ptr<osg::Program> program = new osg::Program;
program->setName("HardwareSkinning");
if (!_shader.valid())
_shader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"skinning.vert");
if (!_shader.valid()) {
osg::notify(osg::WARN) << "RigTransformHardware can't load VertexShader" << std::endl;
return false;
}
// replace max matrix by the value from uniform
{
std::string str = _shader->getShaderSource();
std::string toreplace = std::string("MAX_MATRIX");
std::size_t start = str.find(toreplace);
std::stringstream ss;
ss << getMatrixPaletteUniform()->getNumElements();
str.replace(start, toreplace.size(), ss.str());
_shader->setShaderSource(str);
osg::notify(osg::INFO) << "Shader " << str << std::endl;
}
int attribIndex = 11;
int nbAttribs = getNumVertexAttrib();
for (int i = 0; i < nbAttribs; i++)
{
std::stringstream ss;
ss << "boneWeight" << i;
program->addBindAttribLocation(ss.str(), attribIndex + i);
geom.setVertexAttribData(attribIndex + i, osg::Geometry::ArrayData(getVertexAttrib(i),osg::Geometry::BIND_PER_VERTEX));
osg::notify(osg::INFO) << "set vertex attrib " << ss.str() << std::endl;
}
program->addShader(_shader.get());
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
ss->addUniform(getMatrixPaletteUniform());
ss->addUniform(new osg::Uniform("nbBonesPerVertex", getNumBonesPerVertex()));
ss->setAttributeAndModes(program.get());
geom.setStateSet(ss.get());
_needInit = false;
return true;
}
void RigTransformHardware::operator()(RigGeometry& geom)
{
if (_needInit)
if (!init(geom))
return;
computeMatrixPaletteUniform(geom.getMatrixFromSkeletonToGeometry(), geom.getInvMatrixFromSkeletonToGeometry());
}

View File

@@ -0,0 +1,144 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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 <osgAnimation/RigTransformSoftware>
#include <osgAnimation/BoneMapVisitor>
#include <osgAnimation/RigGeometry>
using namespace osgAnimation;
RigTransformSoftware::RigTransformSoftware()
{
_needInit = true;
}
bool RigTransformSoftware::init(RigGeometry& geom)
{
if (!geom.getSkeleton())
return false;
BoneMapVisitor mapVisitor;
geom.getSkeleton()->accept(mapVisitor);
BoneMap bm = mapVisitor.getBoneMap();
initVertexSetFromBones(bm, geom.getVertexInfluenceSet().getUniqVertexSetToBoneSetList());
if (geom.getSourceGeometry())
geom.copyFrom(*geom.getSourceGeometry());
geom.setVertexArray(0);
geom.setNormalArray(0);
_needInit = false;
return true;
}
void RigTransformSoftware::operator()(RigGeometry& geom)
{
if (_needInit)
if (!init(geom))
return;
if (!geom.getSourceGeometry()) {
osg::notify(osg::WARN) << this << " RigTransformSoftware no source geometry found on RigGeometry" << std::endl;
return;
}
osg::Geometry& source = *geom.getSourceGeometry();
osg::Geometry& destination = geom;
osg::Vec3Array* positionSrc = dynamic_cast<osg::Vec3Array*>(source.getVertexArray());
osg::Vec3Array* positionDst = dynamic_cast<osg::Vec3Array*>(destination.getVertexArray());
if (positionSrc && (!positionDst || (positionDst->size() != positionSrc->size()) ) )
{
if (!positionDst)
{
positionDst = new osg::Vec3Array;
positionDst->setDataVariance(osg::Object::DYNAMIC);
destination.setVertexArray(positionDst);
}
*positionDst = *positionSrc;
}
osg::Vec3Array* normalSrc = dynamic_cast<osg::Vec3Array*>(source.getNormalArray());
osg::Vec3Array* normalDst = dynamic_cast<osg::Vec3Array*>(destination.getNormalArray());
if (normalSrc && (!normalDst || (normalDst->size() != normalSrc->size()) ) )
{
if (!normalDst)
{
normalDst = new osg::Vec3Array;
normalDst->setDataVariance(osg::Object::DYNAMIC);
destination.setNormalArray(normalDst);
destination.setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
}
*normalDst = *normalSrc;
}
if (positionDst && !positionDst->empty())
{
compute<osg::Vec3>(geom.getMatrixFromSkeletonToGeometry(),
geom.getInvMatrixFromSkeletonToGeometry(),
&positionSrc->front(),
&positionDst->front());
positionDst->dirty();
}
if (normalDst && !normalDst->empty())
{
computeNormal<osg::Vec3>(geom.getMatrixFromSkeletonToGeometry(),
geom.getInvMatrixFromSkeletonToGeometry(),
&normalSrc->front(),
&normalDst->front());
normalDst->dirty();
}
}
void RigTransformSoftware::initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexSetToBoneSetList& influence)
{
_boneSetVertexSet.clear();
int size = influence.size();
_boneSetVertexSet.resize(size);
for (int i = 0; i < size; i++)
{
const VertexInfluenceSet::UniqVertexSetToBoneSet& inf = influence[i];
int nbBones = inf.getBones().size();
BoneWeightList& boneList = _boneSetVertexSet[i].getBones();
double sumOfWeight = 0;
for (int b = 0; b < nbBones; b++)
{
const std::string& bname = inf.getBones()[b].getBoneName();
float weight = inf.getBones()[b].getWeight();
BoneMap::const_iterator it = map.find(bname);
if (it == map.end())
{
osg::notify(osg::WARN) << "RigTransformSoftware Bone " << bname << " not found, skip the influence group " <<bname << std::endl;
continue;
}
Bone* bone = it->second.get();
boneList.push_back(BoneWeight(bone, weight));
sumOfWeight += weight;
}
// if a bone referenced by a vertexinfluence is missed it can make the sum less than 1.0
// so we check it and renormalize the all weight bone
const double threshold = 1e-4;
if (!_boneSetVertexSet[i].getBones().empty() &&
(sumOfWeight < 1.0 - threshold || sumOfWeight > 1.0 + threshold))
{
for (int b = 0; b < (int)boneList.size(); b++)
boneList[b].setWeight(boneList[b].getWeight() / sumOfWeight);
}
_boneSetVertexSet[i].getVertexes() = inf.getVertexes();
}
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -14,29 +14,29 @@
#include <osgAnimation/Skeleton>
#include <osgAnimation/Bone>
#include <osg/Notify>
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);
}
};
Skeleton::Skeleton() {}
Skeleton::Skeleton(const Skeleton& b, const osg::CopyOp& copyop) : osg::MatrixTransform(b,copyop) {}
struct updateMatrixVisitor : public osg::NodeVisitor
Skeleton::UpdateSkeleton::UpdateSkeleton() : _needValidate(true) {}
Skeleton::UpdateSkeleton::UpdateSkeleton(const UpdateSkeleton& us, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : osg::Object(us, copyop), osg::NodeCallback(us, copyop)
{
osg::Matrix _skeleton;
updateMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void apply(osg::Node& node) { return ;}
_needValidate = true;
}
bool Skeleton::UpdateSkeleton::needToValidate() const
{
return _needValidate;
}
class ValidateSkeletonVisitor : public osg::NodeVisitor
{
public:
ValidateSkeletonVisitor(): 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
@@ -44,45 +44,50 @@ struct updateMatrixVisitor : public osg::NodeVisitor
if (!bone)
return;
Bone* parent = bone->getBoneParent();
if (bone->needToComputeBindMatrix())
bool foundNonBone = false;
for (unsigned int i = 0; i < bone->getNumChildren(); ++i)
{
computeBindMatrixVisitor visitor;
bone->accept(visitor);
if (dynamic_cast<Bone*>(bone->getChild(i)))
{
if (foundNonBone)
{
osg::notify(osg::WARN) <<
"Warning: a Bone was found after a non-Bone child "
"within a Skeleton. Children of a Bone must be ordered "
"with all child Bones first for correct update order." << std::endl;
setTraversalMode(TRAVERSE_NONE);
return;
}
}
else
{
foundNonBone = true;
}
}
if (parent)
bone->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace() * bone->getBoneParent()->getMatrixInSkeletonSpace());
else
bone->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace());
traverse(node);
}
};
void Skeleton::UpdateSkeleton::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
if (nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
Skeleton* b = dynamic_cast<Skeleton*>(node);
if (b)
Skeleton* skeleton = dynamic_cast<Skeleton*>(node);
if (_needValidate && skeleton)
{
// 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;
b->accept(visitor);
ValidateSkeletonVisitor visitor;
for (unsigned int i = 0; i < skeleton->getNumChildren(); ++i)
{
osg::Node* child = skeleton->getChild(i);
child->accept(visitor);
}
_needValidate = false;
}
}
traverse(node,nv);
}
Skeleton::Skeleton()
{
}
void Skeleton::setDefaultUpdateCallback()
{
setUpdateCallback(new Skeleton::UpdateSkeleton );

View File

@@ -0,0 +1,40 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedMatrixElement>
using namespace osgAnimation;
StackedMatrixElement::StackedMatrixElement() {}
StackedMatrixElement::StackedMatrixElement(const std::string& name, const osg::Matrix& matrix) : StackedTransformElement(), _matrix(matrix) { setName(name); }
StackedMatrixElement::StackedMatrixElement(const osg::Matrix& matrix) : _matrix(matrix) { setName("matrix"); }
StackedMatrixElement::StackedMatrixElement(const StackedMatrixElement& rhs, const osg::CopyOp& c) : StackedTransformElement(rhs, c), _matrix(rhs._matrix)
{
if (rhs._target.valid())
_target = new MatrixTarget(*rhs._target);
}
Target* StackedMatrixElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new MatrixTarget(_matrix);
return _target.get();
}
void StackedMatrixElement::update()
{
if (_target.valid())
_matrix = _target->getValue();
}

View File

@@ -0,0 +1,53 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedQuaternionElement>
using namespace osgAnimation;
StackedQuaternionElement::StackedQuaternionElement(const std::string& name, const osg::Quat& quaternion) : _quaternion(quaternion) { setName(name); }
StackedQuaternionElement::StackedQuaternionElement(const StackedQuaternionElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _quaternion(rhs._quaternion)
{
if (rhs._target.valid())
_target = new QuatTarget(*rhs._target);
}
StackedQuaternionElement::StackedQuaternionElement(const osg::Quat& quat) : _quaternion(quat) { setName("quaternion"); }
StackedQuaternionElement::StackedQuaternionElement()
{
}
const osg::Quat& StackedQuaternionElement::getQuaternion() const { return _quaternion; }
void StackedQuaternionElement::setQuaternion(const osg::Quat& q) { _quaternion = q; }
void StackedQuaternionElement::applyToMatrix(osg::Matrix& matrix) const {matrix.preMultRotate(_quaternion);}
osg::Matrix StackedQuaternionElement::getAsMatrix() const { return osg::Matrix(_quaternion); }
bool StackedQuaternionElement::isIdentity() const { return (_quaternion[0] == 0 && _quaternion[1] == 0 && _quaternion[2] == 0 && _quaternion[3] == 1.0); }
void StackedQuaternionElement::update()
{
if (_target.valid())
_quaternion = _target->getValue();
}
Target* StackedQuaternionElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new QuatTarget(_quaternion);
return _target.get();
}
Target* StackedQuaternionElement::getTarget() {return _target.get();}
const Target* StackedQuaternionElement::getTarget() const {return _target.get();}

View File

@@ -0,0 +1,55 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedRotateAxisElement>
using namespace osgAnimation;
StackedRotateAxisElement::StackedRotateAxisElement(const std::string& name, const osg::Vec3& axis, double angle) : StackedTransformElement(), _axis(axis), _angle(angle) { setName(name); }
StackedRotateAxisElement::StackedRotateAxisElement(const osg::Vec3& axis, double angle) : _axis(axis), _angle(angle) { setName("rotateaxis"); }
StackedRotateAxisElement::StackedRotateAxisElement() {}
StackedRotateAxisElement::StackedRotateAxisElement(const StackedRotateAxisElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _axis(rhs._axis), _angle(rhs._angle)
{
if (rhs._target.valid())
_target = new FloatTarget(*rhs._target);
}
osg::Matrix StackedRotateAxisElement::getAsMatrix() const { return osg::Matrix::rotate(osg::Quat(_angle, _axis)); }
void StackedRotateAxisElement::update()
{
if (_target.valid())
_angle = _target->getValue();
}
const osg::Vec3& StackedRotateAxisElement::getAxis() const { return _axis; }
const double StackedRotateAxisElement::getAngle() const { return _angle; }
void StackedRotateAxisElement::setAxis(const osg::Vec3& axis)
{
_axis = axis;
}
void StackedRotateAxisElement::setAngle(const double& angle)
{
_angle = angle;
}
Target* StackedRotateAxisElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new FloatTarget(_angle);
return _target.get();
}
void StackedRotateAxisElement::applyToMatrix(osg::Matrix& matrix) const { matrix.preMultRotate(osg::Quat(_angle, _axis)); }

View File

@@ -0,0 +1,56 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedScaleElement>
using namespace osgAnimation;
StackedScaleElement::StackedScaleElement(const std::string& name, const osg::Vec3& scale) : _scale(scale) { setName(name); }
StackedScaleElement::StackedScaleElement(const osg::Vec3& scale) : _scale(scale) { setName("scale"); }
StackedScaleElement::StackedScaleElement(const StackedScaleElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _scale(rhs._scale)
{
if (rhs._target.valid())
_target = new Vec3Target(*rhs._target);
}
const osg::Vec3& StackedScaleElement::getScale() const { return _scale; }
void StackedScaleElement::setScale(const osg::Vec3& scale) { _scale = scale; }
Target* StackedScaleElement::getTarget() {return _target.get();}
const Target* StackedScaleElement::getTarget() const {return _target.get();}
bool StackedScaleElement::isIdentity() const { return (_scale.x() == 1 && _scale.y() == 1 && _scale.z() == 1); }
osg::Matrix StackedScaleElement::getAsMatrix() const { return osg::Matrix::scale(_scale); }
void StackedScaleElement::applyToMatrix(osg::Matrix& matrix) const { matrix.preMultScale(_scale); }
StackedScaleElement::StackedScaleElement()
{
_scale = osg::Vec3(1,1,1);
}
void StackedScaleElement::update()
{
if (_target.valid())
_scale = _target->getValue();
}
Target* StackedScaleElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new Vec3Target(_scale);
return _target.get();
}

View File

@@ -0,0 +1,66 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedTransform>
using namespace osgAnimation;
StackedTransform::StackedTransform() {}
StackedTransform::StackedTransform(const StackedTransform& rhs, const osg::CopyOp& co)
{
reserve(rhs.size());
for (StackedTransform::const_iterator it = rhs.begin(); it != rhs.end(); ++it)
{
const StackedTransformElement* element = it->get();
if (element)
push_back(osg::clone(element,co));
}
}
void StackedTransform::update()
{
int dirty = 0;
for (StackedTransform::iterator it = begin(); it != end(); ++it)
{
StackedTransformElement* element = it->get();
if (!element)
continue;
// update and check if there are changes
element->update();
if (element->isIdentity())
continue;
dirty++;
}
if (!dirty)
return;
// dirty update matrix
_matrix.makeIdentity();
for (StackedTransform::iterator it = begin(); it != end(); ++it)
{
StackedTransformElement* element = it->get();
if (!element || element->isIdentity())
continue;
element->applyToMatrix(_matrix);
}
}
const osg::Matrix& StackedTransform::getMatrix() const
{
return _matrix;
}

View File

@@ -0,0 +1,50 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedTranslateElement>
using namespace osgAnimation;
StackedTranslateElement::StackedTranslateElement(const std::string& name, const osg::Vec3& translate) : _translate(translate) { setName(name); }
StackedTranslateElement::StackedTranslateElement(const osg::Vec3& translate) : _translate(translate) { setName("translate"); }
StackedTranslateElement::StackedTranslateElement() {}
StackedTranslateElement::StackedTranslateElement(const StackedTranslateElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _translate(rhs._translate)
{
if (rhs._target.valid())
_target = new Vec3Target(*rhs._target);
}
void StackedTranslateElement::applyToMatrix(osg::Matrix& matrix) const {matrix.preMultTranslate(_translate);}
osg::Matrix StackedTranslateElement::getAsMatrix() const { return osg::Matrix::translate(_translate); }
bool StackedTranslateElement::isIdentity() const { return (_translate[0] == 0 && _translate[1] == 0 && _translate[2] == 0); }
const osg::Vec3& StackedTranslateElement::getTranslate() const { return _translate; }
void StackedTranslateElement::setTranslate(const osg::Vec3& value) { _translate = value; }
Target* StackedTranslateElement::getOrCreateTarget()
{
if (!_target.valid())
_target = new Vec3Target(_translate);
return _target.get();
}
Target* StackedTranslateElement::getTarget() {return _target.get();}
const Target* StackedTranslateElement::getTarget() const {return _target.get();}
void StackedTranslateElement::update()
{
if (_target.valid())
_translate = _target->getValue();
}

View File

@@ -0,0 +1,722 @@
/* -*-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.
*/
#include <sstream>
#include <iomanip>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <osg/io_utils>
#include <osg/NodeVisitor>
#include <osg/MatrixTransform>
#include <osgViewer/Renderer>
#include <osgAnimation/StatsHandler>
#include <osgAnimation/EaseMotion>
#include <osgAnimation/StatsVisitor>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Renderer>
#include <osgAnimation/TimelineAnimationManager>
#include <osg/PolygonMode>
#include <osg/Geometry>
#include <iostream>
#include <cstdlib>
static unsigned int getRandomValueinRange(unsigned int v)
{
return static_cast<unsigned int>((rand() * 1.0 * v)/(RAND_MAX-1));
}
namespace osgAnimation
{
osg::Geometry* createBackgroundRectangle(const osg::Vec3& pos, const float width, const float height, osg::Vec4& color)
{
osg::StateSet *ss = new osg::StateSet;
osg::Geometry* geometry = new osg::Geometry;
geometry->setUseDisplayList(false);
geometry->setStateSet(ss);
osg::Vec3Array* vertices = new osg::Vec3Array;
geometry->setVertexArray(vertices);
vertices->push_back(osg::Vec3(pos.x(), pos.y(), 0));
vertices->push_back(osg::Vec3(pos.x(), pos.y()-height,0));
vertices->push_back(osg::Vec3(pos.x()+width, pos.y()-height,0));
vertices->push_back(osg::Vec3(pos.x()+width, pos.y(),0));
osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(color);
geometry->setColorArray(colors);
geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
osg::DrawElementsUInt *base = new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS,0);
base->push_back(0);
base->push_back(1);
base->push_back(2);
base->push_back(3);
geometry->addPrimitiveSet(base);
return geometry;
}
struct StatsGraph : public osg::MatrixTransform
{
StatsGraph(osg::Vec3 pos, float width, float height)
: _pos(pos), _width(width), _height(height),
_statsGraphGeode(new osg::Geode)
{
_pos = pos - osg::Vec3(0, _height, 0.1);
setMatrix(osg::Matrix::translate(_pos));
setDataVariance(osg::Object::DYNAMIC);
addChild(_statsGraphGeode.get());
_statsGraphGeode->setCullingActive(false);
}
void changeYposition(float y)
{
osg::Vec3 _pos = getMatrix().getTrans();
_pos[1] = y - _height;
setMatrix(osg::Matrix::translate(_pos));
}
void addStatGraph(osg::Stats* viewerStats, osg::Stats* stats, const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
{
_statsGraphGeode->addDrawable(new Graph(_width, _height, viewerStats, stats, color, max, nameBegin, nameEnd));
}
osg::Vec3 _pos;
float _width;
float _height;
osg::ref_ptr<osg::Geode> _statsGraphGeode;
struct NeverCull : public osg::Drawable::CullCallback
{
NeverCull() {}
bool cull(osg::NodeVisitor* nv, osg::Drawable* drawable, osg::RenderInfo* renderInfo) const { return false;}
};
struct Graph : public osg::Geometry
{
Graph(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
const osg::Vec4& color, float max, const std::string& nameBegin, const std::string& nameEnd = "")
{
setDataVariance(osg::Object::DYNAMIC);
setUseDisplayList(false);
setVertexArray(new osg::Vec3Array);
getVertexArray()->setDataVariance(osg::Object::DYNAMIC);
setColor(color);
setUpdateCallback(new GraphUpdateCallback(width, height, viewerStats, stats, max, nameBegin, nameEnd));
setCullCallback(new NeverCull);
}
void setColor(const osg::Vec4& color) {
osg::Vec4Array* colors = new osg::Vec4Array;
colors->push_back(color);
setColorArray(colors);
setColorBinding(osg::Geometry::BIND_OVERALL);
}
};
struct GraphUpdateCallback : public osg::Drawable::UpdateCallback
{
const unsigned int _width;
const unsigned int _height;
mutable unsigned int _curX;
osg::Stats* _viewerStats;
osg::Stats* _stats;
const float _max;
const std::string _nameBegin;
const std::string _nameEnd;
mutable int _frameNumber;
GraphUpdateCallback(float width, float height, osg::Stats* viewerStats, osg::Stats* stats,
float max, const std::string& nameBegin, const std::string& nameEnd = "")
: _width((unsigned int)width), _height((unsigned int)height), _curX(0),
_viewerStats(viewerStats), _stats(stats), _max(max), _nameBegin(nameBegin), _nameEnd(nameEnd), _frameNumber(0)
{
}
virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable)
{
if (nv->getVisitorType() != osg::NodeVisitor::UPDATE_VISITOR)
return;
osg::Geometry* geometry = const_cast<osg::Geometry*>(drawable->asGeometry());
if (!geometry) return;
osg::Vec3Array* vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());
if (!vertices) return;
int frameNumber = nv->getFrameStamp()->getFrameNumber();
if (frameNumber == _frameNumber)
return;
// Get stats
double value;
if (_nameEnd.empty())
{
if (!_stats->getAttribute(_stats->getLatestFrameNumber(), _nameBegin, value ))
{
value = 0.0;
}
}
else
{
double beginValue, endValue;
if (_stats->getAttribute( frameNumber, _nameBegin, beginValue) &&
_stats->getAttribute( frameNumber, _nameEnd, endValue) )
{
value = endValue - beginValue;
}
else
{
value = 0.0;
}
}
// Add new vertex for this frame.
value = osg::clampTo(value, 0.0, double(_max));
if (!vertices->size()) {
for (int i = 0; i < (int)_width; i++)
vertices->push_back(osg::Vec3(float(_curX++), 0, 0));
// Create primitive set if none exists.
if (geometry->getNumPrimitiveSets() == 0)
geometry->addPrimitiveSet(new osg::DrawArrays(GL_LINE_STRIP, 0, 0));
osg::DrawArrays* drawArrays = dynamic_cast<osg::DrawArrays*>(geometry->getPrimitiveSet(0));
drawArrays->setFirst(0);
drawArrays->setCount(vertices->size());
}
vertices->push_back(osg::Vec3(float(_curX), float(_height) / _max * value, 0));
unsigned int excedent = vertices->size() - _width;
vertices->erase(vertices->begin(), vertices->begin() + excedent);
// Make the graph scroll when there is enough data.
// Note: We check the frame number so that even if we have
// many graphs, the transform is translated only once per
// frame.
static const float increment = -1.0;
if (_frameNumber != frameNumber)
{
// We know the exact layout of this part of the scene
// graph, so this is OK...
osg::MatrixTransform* transform =
geometry->getParent(0)->getParent(0)->asTransform()->asMatrixTransform();
if (transform)
{
transform->setMatrix(transform->getMatrix() * osg::Matrix::translate(osg::Vec3(increment, 0, 0)));
}
}
_curX++;
_frameNumber = frameNumber;
geometry->dirtyBound();
}
};
};
// Drawcallback to draw averaged attribute
struct ValueTextDrawCallback : public virtual osg::Drawable::DrawCallback
{
ValueTextDrawCallback(osg::Stats* stats, const std::string& name):
_stats(stats),
_attributeName(name),
_frameNumber(0)
{
}
/** do customized draw code.*/
virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const
{
osgText::Text* text = (osgText::Text*)drawable;
int frameNumber = renderInfo.getState()->getFrameStamp()->getFrameNumber();
if (frameNumber == _frameNumber) {
text->drawImplementation(renderInfo);
return;
}
double value;
if (_stats->getAttribute(_stats->getLatestFrameNumber(), _attributeName, value))
{
sprintf(_tmpText,"%4.2f",value);
text->setText(_tmpText);
}
else
{
text->setText("");
}
_frameNumber = frameNumber;
text->drawImplementation(renderInfo);
}
osg::ref_ptr<osg::Stats> _stats;
std::string _attributeName;
mutable char _tmpText[128];
mutable int _frameNumber;
};
struct StatAction
{
double _lastTime;
std::string _name;
osg::ref_ptr<osg::Group> _group;
osg::ref_ptr<osg::Geode> _label;
osg::ref_ptr<osg::MatrixTransform> _graph;
osg::ref_ptr<osgText::Text> _textLabel;
osgAnimation::OutCubicMotion _fade;
StatAction() { _lastTime = 0; _fade = osgAnimation::OutCubicMotion(0,5); }
void init(osg::Stats* stats, const std::string& name, const osg::Vec3& pos, float width, float heigh, const osg::Vec4& color);
void setPosition(const osg::Vec3& pos);
#if 0
void touch()
{
_lastTime = osg::Timer::instance()->time_s();
float a = 1.0 - _fade.getValueAt(0.0);
setAlpha(a);
}
bool update() {
double t = osg::Timer::instance()->time_s();
float alpha = 1.0 - _fade.getValueAt(t-_lastTime);
if (t - _lastTime > _fade.getDuration())
return true;
setAlpha(alpha);
return false;
}
#endif
void setAlpha(float v);
};
struct StatsTimeline : public osg::NodeCallback
{
static float _statsHeight;
static float _statsWidth;
osg::ref_ptr<osg::Geometry> _background;
osg::ref_ptr<osgAnimation::Timeline> _timeline;
osg::ref_ptr<osg::MatrixTransform> _group;
std::map<std::string, StatAction > _actions;
StatsTimeline()
{
_statsHeight = 1024;
_statsWidth = 1280;
}
osg::MatrixTransform* createStatsForTimeline(osgAnimation::Timeline* timeline)
{
_timeline = timeline;
std::string font("fonts/arial.ttf");
float leftPos = 10.0f;
float startBlocks = 150.0f;
float characterSize = 20.0f;
osg::Vec4 backgroundColor(0.0, 0.0, 0.0f, 0.3);
float backgroundMargin = 5;
//float backgroundSpacing = 3;
osg::Vec4 color(1.0, 1.0, 1.0, 1.0);
_group = new osg::MatrixTransform;
_group->setDataVariance(osg::Object::DYNAMIC);
{
osg::Vec3 pos(leftPos, _statsHeight-24.0f,0.0f);
//float topOfViewerStats = pos.y() + characterSize;
osg::ref_ptr<osg::Stats> stats = _timeline->getStats();
pos.y() -= characterSize + backgroundMargin;
{
osg::Geode* geode = new osg::Geode();
_group->addChild(geode);
osg::ref_ptr<osgText::Text> timeLabel = new osgText::Text;
geode->addDrawable( timeLabel.get() );
timeLabel->setColor(color);
timeLabel->setFont(font);
timeLabel->setCharacterSize(characterSize);
timeLabel->setPosition(pos);
timeLabel->setText("Time: ");
osg::ref_ptr<osgText::Text> timeLabelValue = new osgText::Text;
geode->addDrawable( timeLabelValue.get() );
timeLabelValue->setColor(color);
timeLabelValue->setFont(font);
timeLabelValue->setCharacterSize(characterSize);
timeLabelValue->setPosition(pos + osg::Vec3(startBlocks, 0,0));
timeLabelValue->setText("0.0");
timeLabelValue->setDrawCallback(new ValueTextDrawCallback(stats.get(),"Timeline"));
}
}
{
osg::Vec3 pos(leftPos, _statsHeight - 24.0f ,0.0f);
//float topOfViewerStats = pos.y();
osg::Geode* geode = new osg::Geode;
_background = createBackgroundRectangle(
pos + osg::Vec3(-backgroundMargin, backgroundMargin, 0),
_statsWidth - 2 * backgroundMargin,
(3 + 4.5 * 1) * characterSize + 2 * backgroundMargin,
backgroundColor);
geode->addDrawable(_background.get());
_group->addChild(geode);
}
return _group.get();
}
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) {
updateGraph();
}
traverse(node,nv);
}
void updateGraph()
{
osgAnimation::StatsActionVisitor* visitor = _timeline->getStatsVisitor();
if (!visitor)
return;
std::string font("fonts/arial.ttf");
float leftPos = 10.0f;
float characterSize = 20.0f;
float backgroundMargin = 5;
//float backgroundSpacing = 3;
float graphSpacing = 5;
float width = _statsWidth - 4 * backgroundMargin;
float height = characterSize;
osg::Vec3 pos(leftPos, _statsHeight-24.0f,0.0f);
pos.y() -= characterSize *2 + backgroundMargin;
for (std::map<std::string, StatAction >::iterator it = _actions.begin(); it != _actions.end(); ++it) {
(*it).second._group->setNodeMask(~osg::Node::NodeMask(1));
}
const std::vector<std::string>& channels = visitor->getChannels();
std::map<std::string,int> size;
for (int i = 0; i < (int)channels.size(); i++) {
std::string name = channels[i];
if (_actions.find(name) == _actions.end()) {
osg::Vec4 color(getRandomValueinRange(255)/255.0, getRandomValueinRange(255)/255.0, getRandomValueinRange(255)/255.0, 1.0);
_actions[name].init(visitor->getStats(), name, pos, width, height, color);
_group->addChild(_actions[name]._group.get());
//_actions[name].touch();
} else {
_actions[name].setPosition(pos);
//_actions[name].touch();
}
_actions[name]._group->setNodeMask(~osg::Node::NodeMask(0x0));
size[name] = 0;
pos.y() -= characterSize + graphSpacing;
}
pos.y() -= backgroundMargin;
osg::Vec3Array* array = dynamic_cast<osg::Vec3Array*>(_background->getVertexArray());
float y = (*array)[0][1];
y = y - (pos.y() + backgroundMargin); //(2 * backgroundMargin + (size.size() * (characterSize + graphSpacing)));
(*array)[1][1] = pos.y();
(*array)[2][1] = pos.y();
array->dirty();
_background->dirtyBound();
}
};
float StatsTimeline::_statsHeight;
float StatsTimeline::_statsWidth;
struct FindTimelineStats : public osg::NodeVisitor
{
std::vector<osg::ref_ptr<osgAnimation::Timeline> > _timelines;
FindTimelineStats() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
void apply(osg::Node& node) {
osg::NodeCallback* cb = node.getUpdateCallback();
while (cb) {
osgAnimation::TimelineAnimationManager* tam = dynamic_cast<osgAnimation::TimelineAnimationManager*>(cb);
if (tam)
_timelines.push_back(tam->getTimeline());
cb = cb->getNestedCallback();
}
traverse(node);
}
};
StatsHandler::StatsHandler():
_keyEventTogglesOnScreenStats('a'),
_keyEventPrintsOutStats('A'),
_statsType(NO_STATS),
_initialized(false),
_statsWidth(1280.0f),
_statsHeight(1024.0f)
{
_camera = new osg::Camera;
_camera->setRenderer(new osgViewer::Renderer(_camera.get()));
_camera->setProjectionResizePolicy(osg::Camera::FIXED);
}
bool StatsHandler::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
osgViewer::View* myview = dynamic_cast<osgViewer::View*>(&aa);
if (!myview) return false;
osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(myview->getViewerBase());
if (!viewer->getSceneData())
return false;
if (ea.getHandled()) return false;
switch(ea.getEventType())
{
case(osgGA::GUIEventAdapter::KEYDOWN):
{
if (ea.getKey()==_keyEventTogglesOnScreenStats)
{
if (viewer->getViewerStats())
{
if (!_switch.get()) {
FindTimelineStats finder;
viewer->getSceneData()->accept(finder);
if (finder._timelines.empty())
return false;
}
if (!_initialized)
{
setUpHUDCamera(viewer);
setUpScene(dynamic_cast<osgViewer::Viewer*>(viewer));
}
++_statsType;
if (_statsType==LAST) _statsType = NO_STATS;
switch(_statsType)
{
case(NO_STATS):
{
_camera->setNodeMask(0x0);
_switch->setAllChildrenOff();
break;
}
case(FRAME_RATE):
{
_camera->setNodeMask(0xffffffff);
_switch->setAllChildrenOn();
break;
}
default:
break;
}
}
return true;
}
if (ea.getKey()==_keyEventPrintsOutStats)
{
FindTimelineStats finder;
viewer->getSceneData()->accept(finder);
if (!finder._timelines.empty()) {
osg::notify(osg::NOTICE)<<std::endl<<"Stats report:"<<std::endl;
typedef std::vector<osg::Stats*> StatsList;
StatsList statsList;
for (int i = 0; i < (int)finder._timelines.size(); i++)
statsList.push_back(finder._timelines[i]->getStats());
for(int i = statsList[0]->getEarliestFrameNumber(); i<= statsList[0]->getLatestFrameNumber()-1; ++i)
{
for(StatsList::iterator itr = statsList.begin();
itr != statsList.end();
++itr)
{
if (itr==statsList.begin()) (*itr)->report(osg::notify(osg::NOTICE), i);
else (*itr)->report(osg::notify(osg::NOTICE), i, " ");
}
osg::notify(osg::NOTICE)<<std::endl;
}
}
return true;
}
}
default: break;
}
return false;
}
void StatsHandler::reset()
{
_initialized = false;
_camera->setGraphicsContext(0);
_camera->removeChildren( 0, _camera->getNumChildren() );
}
void StatsHandler::setUpHUDCamera(osgViewer::ViewerBase* viewer)
{
osgViewer::GraphicsWindow* window = dynamic_cast<osgViewer::GraphicsWindow*>(_camera->getGraphicsContext());
if (!window)
{
osgViewer::Viewer::Windows windows;
viewer->getWindows(windows);
if (windows.empty()) return;
window = windows.front();
}
_camera->setGraphicsContext(window);
_camera->setViewport(0, 0, window->getTraits()->width, window->getTraits()->height);
_camera->setRenderOrder(osg::Camera::POST_RENDER, 10);
_camera->setProjectionMatrix(osg::Matrix::ortho2D(0.0,_statsWidth,0.0,_statsHeight));
_camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
_camera->setViewMatrix(osg::Matrix::identity());
// only clear the depth buffer
_camera->setClearMask(0); //GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //-1);
_camera->setAllowEventFocus(false);
_camera->setCullMask(0x1);
osgViewer::Viewer* v = dynamic_cast<osgViewer::Viewer*>(viewer);
v->getSceneData()->asGroup()->addChild(_camera.get());
_initialized = true;
}
void StatsHandler::setUpScene(osgViewer::Viewer* viewer)
{
if (!viewer->getSceneData())
return;
FindTimelineStats finder;
viewer->getSceneData()->accept(finder);
if (finder._timelines.empty())
return;
_switch = new osg::Switch;
osg::StateSet* stateset = _switch->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
stateset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED);
_group = new osg::Group;
_camera->addChild(_switch.get());
_switch->addChild(_group.get());
for (int i = 0; i < (int)finder._timelines.size(); i++) {
StatsTimeline* s = new StatsTimeline;
osg::MatrixTransform* m = s->createStatsForTimeline(finder._timelines[i].get());
m->setUpdateCallback(s);
m->setMatrix(osg::Matrix::translate(0, -i * 100, 0));
_group->addChild(m);
}
}
void StatAction::init(osg::Stats* stats, const std::string& name, const osg::Vec3& pos, float width, float height, const osg::Vec4& color)
{
std::string font("fonts/arial.ttf");
float characterSize = 20.0f;
float startBlocks = 150.0f;
_name = name;
_group = new osg::Group;
_label = new osg::Geode;
_textLabel = new osgText::Text;
_label->addDrawable(_textLabel.get());
_textLabel->setDataVariance(osg::Object::DYNAMIC);
_textLabel->setColor(color);
_textLabel->setFont(font);
_textLabel->setCharacterSize(characterSize);
_textLabel->setPosition(pos - osg::Vec3(0, height, 0));
_textLabel->setText(name);
StatsGraph* graph = new StatsGraph(pos + osg::Vec3(startBlocks, 0,0) , width-startBlocks, height);
graph->setCullingActive(false);
graph->addStatGraph(stats, stats, color, 1.0, name);
_graph = graph;
_group->addChild(_label.get());
_group->addChild(_graph.get());
}
void StatAction::setAlpha(float v)
{
std::cout << this << " color alpha " << v << std::endl;
StatsGraph* gfx = dynamic_cast<StatsGraph*>(_graph.get());
osg::Vec4 color = _textLabel->getColor();
color[3] = v;
_textLabel->setColor(color);
for (int i = 0; i < (int) gfx->_statsGraphGeode->getNumDrawables(); i++) {
StatsGraph::Graph* g = dynamic_cast<StatsGraph::Graph*>(gfx->_statsGraphGeode->getDrawable(0));
g->setColor(color);
}
}
void StatAction::setPosition(const osg::Vec3& pos)
{
float characterSize = 20.0f;
StatsGraph* gfx = dynamic_cast<StatsGraph*>(_graph.get());
gfx->changeYposition(pos[1]);
_textLabel->setPosition(pos - osg::Vec3(0, characterSize,0));
}
void StatsHandler::getUsage(osg::ApplicationUsage& usage) const
{
usage.addKeyboardMouseBinding("s","On screen stats.");
usage.addKeyboardMouseBinding("S","Output stats to console.");
}
}

View File

@@ -0,0 +1,86 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StatsVisitor>
#include <osgAnimation/Timeline>
#include <osgAnimation/ActionBlendIn>
#include <osgAnimation/ActionBlendOut>
#include <osgAnimation/ActionStripAnimation>
#include <osgAnimation/ActionAnimation>
using namespace osgAnimation;
StatsActionVisitor::StatsActionVisitor() {}
void StatsActionVisitor::reset() { _channels.clear(); }
StatsActionVisitor::StatsActionVisitor(osg::Stats* stats,unsigned int frame)
{
_frame = frame;
_stats = stats;
}
void StatsActionVisitor::apply(Timeline& tm)
{
_stats->setAttribute(_frame,"Timeline", tm.getCurrentTime());
tm.traverse(*this);
}
void StatsActionVisitor::apply(Action& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(),1);
}
}
void StatsActionVisitor::apply(ActionBlendIn& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getWeight());
}
}
void StatsActionVisitor::apply(ActionBlendOut& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getWeight());
}
}
void StatsActionVisitor::apply(ActionAnimation& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getAnimation()->getWeight());
}
}
void StatsActionVisitor::apply(ActionStripAnimation& action)
{
if (isActive(action))
{
_channels.push_back(action.getName());
double value;
std::string name = action.getName();
if (_stats->getAttribute(_frame, name, value))
name += "+";
_stats->setAttribute(_frame, action.getName(), action.getAnimation()->getAnimation()->getWeight());
}
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -18,5 +18,4 @@
using namespace osgAnimation;
Target::Target() { reset();}
Target::~Target() {}
Target::Target() : _weight(0), _priorityWeight(0), _lastPriority(0) {}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -13,6 +13,7 @@
*/
#include <osgAnimation/Timeline>
#include <osgAnimation/StatsVisitor>
#include <limits.h>
using namespace osgAnimation;
@@ -29,11 +30,14 @@ Timeline::Timeline()
_previousFrameEvaluated = 0;
_evaluating = 0;
_numberFrame = UINT_MAX; // something like infinity
_collectStats = false;
_stats = new osg::Stats("Timeline");
setName("Timeline");
}
Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, op),
_actions(nc._actions)
Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op)
: Action(nc, op),
_actions(nc._actions)
{
_lastUpdate = 0;
_currentFrame = 0;
@@ -44,5 +48,204 @@ Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, o
_previousFrameEvaluated = 0;
_evaluating = 0;
_numberFrame = UINT_MAX; // something like infinity
_collectStats = false;
_stats = new osg::Stats("Timeline");
setName("Timeline");
}
void Timeline::setAnimationManager(AnimationManagerBase* manager)
{
_animationManager = manager;
}
void Timeline::traverse(ActionVisitor& visitor)
{
int layer = visitor.getCurrentLayer();
visitor.pushTimelineOnStack(this);
// update from high priority to low priority
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
{
visitor.setCurrentLayer(iterAnim->first);
ActionList& list = iterAnim->second;
for (unsigned int i = 0; i < list.size(); i++)
{
visitor.pushFrameActionOnStack(list[i]);
if (list[i].second) list[i].second->accept(visitor);
visitor.popFrameAction();
}
}
visitor.popTimeline();
visitor.setCurrentLayer(layer);
}
void Timeline::setStats(osg::Stats* stats) { _stats = stats;}
osg::Stats* Timeline::getStats() { return _stats.get();}
void Timeline::collectStats(bool state) { _collectStats = state;}
StatsActionVisitor* Timeline::getStatsVisitor() { return _statsVisitor.get(); }
void Timeline::clearActions()
{
_actions.clear();
_addActionOperations.clear();
_removeActionOperations.clear();
}
void Timeline::update(double simulationTime)
{
// first time we call update we generate one frame
UpdateActionVisitor updateTimeline;
if (!_initFirstFrame)
{
_lastUpdate = simulationTime;
_initFirstFrame = true;
_animationManager->clearTargets();
updateTimeline.setFrame(_currentFrame);
accept(updateTimeline);
if (_collectStats)
{
if (!_statsVisitor)
_statsVisitor = new StatsActionVisitor();
_statsVisitor->setStats(_stats.get());
_statsVisitor->setFrame(_currentFrame);
_statsVisitor->reset();
accept(*_statsVisitor);
}
processPendingOperation();
}
// 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++;
_animationManager->clearTargets();
updateTimeline.setFrame(_currentFrame);
accept(updateTimeline);
if (_collectStats)
{
if (!_statsVisitor)
_statsVisitor = new StatsActionVisitor;
_statsVisitor->setStats(_stats.get());
_statsVisitor->setFrame(_currentFrame);
_statsVisitor->reset();
accept(*_statsVisitor);
}
processPendingOperation();
}
if (nb)
{
_lastUpdate += ((double)nb) / _fps;
}
}
void Timeline::removeAction(Action* action)
{
if (getEvaluating())
_removeActionOperations.push_back(FrameAction(0, action));
else
internalRemoveAction(action);
}
void Timeline::addActionAt(unsigned int frame, Action* action, int priority)
{
// skip if this action has already been added this frame
for (CommandList::iterator it = _addActionOperations.begin(); it != _addActionOperations.end(); ++it)
{
Command& command = *it;
if (command._action.second.get() == action) {
osg::notify(osg::INFO) << "Timeline::addActionAt command " << action->getName() << " already added this frame, declined" << std::endl;
return;
}
}
if (isActive(action))
{
osg::notify(osg::INFO) << "Timeline::addActionAt command " << action->getName() << " already active, remove the old" << std::endl;
removeAction(action);
}
if (getEvaluating())
_addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
else
internalAddAction(priority, FrameAction(frame, action));
}
void Timeline::addActionAt(double t, Action* action, int priority)
{
unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
addActionAt(frame, action, priority);
}
void Timeline::addActionNow(Action* action, int priority)
{
addActionAt(getCurrentFrame()+1, action, priority);
}
void Timeline::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.get());
_removeActionOperations.pop_back();
}
}
void Timeline::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 Timeline::internalAddAction(int priority, const FrameAction& ftl)
{
_actions[priority].insert(_actions[priority].begin(), ftl);
}
bool Timeline::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;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -34,7 +34,7 @@ TimelineAnimationManager::TimelineAnimationManager(const TimelineAnimationManage
void TimelineAnimationManager::update(double time)
{
clearTargets();
// clearTargets();
_timeline->setAnimationManager(this);
_timeline->update(time);
normalizeTargets();
}

View File

@@ -0,0 +1,54 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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 <osg/NodeVisitor>
#include <osgAnimation/Bone>
#include <osgAnimation/UpdateBone>
using namespace osgAnimation;
UpdateBone::UpdateBone(const std::string& name) : UpdateMatrixTransform(name)
{
}
UpdateBone::UpdateBone(const UpdateBone& apc,const osg::CopyOp& copyop) : osg::Object(apc,copyop), UpdateMatrixTransform(apc, copyop)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateBone::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
Bone* b = dynamic_cast<Bone*>(node);
if (!b)
{
osg::notify(osg::WARN) << "Warning: UpdateBone set on non-Bone object." << std::endl;
return;
}
// here we would prefer to have a flag inside transform stack in order to avoid update and a dirty state in matrixTransform if it's not require.
_transforms.update();
const osg::Matrix& matrix = _transforms.getMatrix();
b->setMatrix(matrix);
Bone* parent = b->getBoneParent();
if (parent)
b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace());
else
b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace());
}
traverse(node,nv);
}

View File

@@ -0,0 +1,63 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/UpdateMaterial>
#include <osg/NodeVisitor>
using namespace osgAnimation;
UpdateMaterial::UpdateMaterial(const UpdateMaterial& apc,const osg::CopyOp& copyop)
: osg::Object(apc, copyop),
AnimationUpdateCallback<osg::StateAttributeCallback>(apc, copyop)
{
_diffuse = new osgAnimation::Vec4Target(apc._diffuse->getValue());
}
UpdateMaterial::UpdateMaterial(const std::string& name):
AnimationUpdateCallback<osg::StateAttributeCallback>(name)
{
_diffuse = new osgAnimation::Vec4Target(osg::Vec4(1,0,1,1));
}
/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateMaterial::operator()(osg::StateAttribute* sa, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
osg::Material* material = dynamic_cast<osg::Material*>(sa);
if (material)
update(*material);
}
}
osgAnimation::Vec4Target* UpdateMaterial::getDiffuse() { return _diffuse.get(); }
void UpdateMaterial::update(osg::Material& material)
{
osg::Vec4 diffuse = _diffuse->getValue();
material.setDiffuse(osg::Material::FRONT_AND_BACK, diffuse);
}
bool UpdateMaterial::link(osgAnimation::Channel* channel)
{
if (channel->getName().find("diffuse") != std::string::npos)
{
return channel->setTarget(_diffuse.get());
}
else
{
osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class " << className() << std::endl;
}
return false;
}

View File

@@ -0,0 +1,67 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/UpdateMatrixTransform>
#include <osg/NodeVisitor>
#include <osg/MatrixTransform>
using namespace osgAnimation;
UpdateMatrixTransform::UpdateMatrixTransform( const UpdateMatrixTransform& apc,const osg::CopyOp& copyop) : osg::Object(apc,copyop), AnimationUpdateCallback<osg::NodeCallback>(apc, copyop)
{
_transforms = StackedTransform(apc.getStackedTransforms(), copyop);
}
UpdateMatrixTransform::UpdateMatrixTransform(const std::string& name) : AnimationUpdateCallback<osg::NodeCallback>(name)
{
}
/** Callback method called by the NodeVisitor when visiting a node.*/
void UpdateMatrixTransform::operator()(osg::Node* node, osg::NodeVisitor* nv)
{
if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
osg::MatrixTransform* matrixTransform = dynamic_cast<osg::MatrixTransform*>(node);
if (matrixTransform)
{
// here we would prefer to have a flag inside transform stack in order to avoid update and a dirty state in matrixTransform if it's not require.
_transforms.update();
const osg::Matrix& matrix = _transforms.getMatrix();
matrixTransform->setMatrix(matrix);
}
}
traverse(node,nv);
}
bool UpdateMatrixTransform::link(osgAnimation::Channel* channel)
{
const std::string& channelName = channel->getName();
// check if we can link a StackedTransformElement to the current Channel
for (StackedTransform::iterator it = _transforms.begin(); it != _transforms.end(); ++it)
{
StackedTransformElement* element = it->get();
if (element && !element->getName().empty() && channelName == element->getName())
{
Target* target = element->getOrCreateTarget();
if (target && channel->setTarget(target))
return true;
}
}
osg::notify(osg::INFO) << "UpdateMatrixTransform::link Channel " << channel->getName() << " does not contain a symbolic name that can be linked to a StackedTransformElement." << std::endl;
return false;
}

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,20 +10,23 @@
* 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 <osg/Notify>
#include <iostream>
#include <algorithm>
using namespace osgAnimation;
void VertexInfluenceSet::addVertexInfluence(const VertexInfluence& v) { _bone2Vertexes.push_back(v); }
const VertexInfluenceSet::VertexIndexToBoneWeightMap& VertexInfluenceSet::getVertexToBoneList() const { return _vertex2Bones;}
// this class manage VertexInfluence database by mesh
// reference bones per vertex ...
void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
void VertexInfluenceSet::buildVertex2BoneList()
{
_vertex2Bones.clear();
for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); it++)
for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); ++it)
{
const VertexInfluence& vi = (*it);
int size = vi.size();
@@ -33,13 +36,13 @@ void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
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;
osg::notify(osg::WARN) << "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++)
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it)
{
BoneWeightList& bones = it->second;
int size = bones.size();
@@ -48,7 +51,7 @@ void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
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;
osg::notify(osg::WARN) << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << it->first << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
}
else
{
@@ -62,10 +65,10 @@ void osgAnimation::VertexInfluenceSet::buildVertex2BoneList()
// sort by name and weight
struct SortByNameAndWeight : public std::less<osgAnimation::VertexInfluenceSet::BoneWeight>
struct SortByNameAndWeight : public std::less<VertexInfluenceSet::BoneWeight>
{
bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeight& b0,
const osgAnimation::VertexInfluenceSet::BoneWeight& b1) const
bool operator()(const VertexInfluenceSet::BoneWeight& b0,
const VertexInfluenceSet::BoneWeight& b1) const
{
if (b0.getBoneName() < b1.getBoneName())
return true;
@@ -77,10 +80,10 @@ struct SortByNameAndWeight : public std::less<osgAnimation::VertexInfluenceSet::
}
};
struct SortByBoneWeightList : public std::less<osgAnimation::VertexInfluenceSet::BoneWeightList>
struct SortByBoneWeightList : public std::less<VertexInfluenceSet::BoneWeightList>
{
bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeightList& b0,
const osgAnimation::VertexInfluenceSet::BoneWeightList& b1) const
bool operator()(const VertexInfluenceSet::BoneWeightList& b0,
const VertexInfluenceSet::BoneWeightList& b1) const
{
if (b0.size() < b1.size())
return true;
@@ -100,14 +103,20 @@ struct SortByBoneWeightList : public std::less<osgAnimation::VertexInfluenceSet:
}
};
void osgAnimation::VertexInfluenceSet::buildUniqVertexSetToBoneSetList()
void VertexInfluenceSet::clear()
{
_bone2Vertexes.clear();
_uniqVertexSetToBoneSet.clear();
}
void VertexInfluenceSet::buildUniqVertexSetToBoneSetList()
{
_uniqVertexSetToBoneSet.clear();
typedef std::map<BoneWeightList,UniqVertexSetToBoneSet, SortByBoneWeightList> UnifyBoneGroup;
UnifyBoneGroup unifyBuffer;
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); it++)
for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it)
{
BoneWeightList bones = it->second;
int vertexIndex = it->first;
@@ -123,8 +132,9 @@ void osgAnimation::VertexInfluenceSet::buildUniqVertexSetToBoneSetList()
}
_uniqVertexSetToBoneSet.reserve(unifyBuffer.size());
for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); it++)
for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
{
_uniqVertexSetToBoneSet.push_back(it->second);
}
}

View File

@@ -1,9 +1,7 @@
SET(TARGET_SRC
ReaderWriter.cpp
)
FILE(GLOB TARGET_SRC *.cpp)
FILE(GLOB TARGET_H *.h)
SET(TARGET_ADDED_LIBRARIES osgAnimation )
#### end var setup ###
SETUP_PLUGIN(osganimation)

View File

@@ -0,0 +1,51 @@
#include "Matrix.h"
bool readMatrix(osg::Matrix& matrix, osgDB::Input& fr, const char* keyword)
{
bool iteratorAdvanced = false;
if (fr[0].matchWord(keyword) && fr[1].isOpenBracket())
{
int entry = fr[0].getNoNestedBrackets();
fr += 2;
int row=0;
int col=0;
double v;
while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
{
if (fr[0].getFloat(v))
{
matrix(row,col)=v;
++col;
if (col>=4)
{
col = 0;
++row;
}
++fr;
}
else fr.advanceOverCurrentFieldOrBlock();
}
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool writeMatrix(const osg::Matrix& matrix, osgDB::Output& fw, const char* keyword)
{
fw.indent() << keyword <<" {" << std::endl;
fw.moveIn();
fw.indent() << matrix(0,0) << " " << matrix(0,1) << " " << matrix(0,2) << " " << matrix(0,3) << std::endl;
fw.indent() << matrix(1,0) << " " << matrix(1,1) << " " << matrix(1,2) << " " << matrix(1,3) << std::endl;
fw.indent() << matrix(2,0) << " " << matrix(2,1) << " " << matrix(2,2) << " " << matrix(2,3) << std::endl;
fw.indent() << matrix(3,0) << " " << matrix(3,1) << " " << matrix(3,2) << " " << matrix(3,3) << std::endl;
fw.moveOut();
fw.indent() << "}"<< std::endl;
return true;
}

View File

@@ -0,0 +1,13 @@
#ifndef DOTOSG_MATRIX
#define DOTOSG_MATRIX
#include <osg/Matrix>
#include <osgDB/Input>
#include <osgDB/Output>
extern bool readMatrix(osg::Matrix& matrix, osgDB::Input& fr, const char* keyword="Matrix");
extern bool writeMatrix(const osg::Matrix& matrix, osgDB::Output& fw, const char* keyword="Matrix");
#endif

View File

@@ -1,5 +1,5 @@
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@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
@@ -10,23 +10,30 @@
* 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 <osg/io_utils>
#include <osgAnimation/AnimationManagerBase>
#include <osgAnimation/BasicAnimationManager>
#include <osgAnimation/TimelineAnimationManager>
#include <osgAnimation/VertexInfluence>
#include <osgAnimation/Animation>
#include <osgAnimation/Bone>
#include <osgAnimation/UpdateBone>
#include <osgAnimation/UpdateMatrixTransform>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/UpdateCallback>
#include <osgAnimation/MorphGeometry>
#include <osgAnimation/StackedTransform>
#include <osgAnimation/StackedTranslateElement>
#include <osgAnimation/StackedRotateAxisElement>
#include <osgAnimation/StackedMatrixElement>
#include <osgAnimation/StackedScaleElement>
#include "Matrix.h"
#include <osgDB/Registry>
#include <osgDB/Input>
@@ -41,7 +48,7 @@ bool Bone_readLocalData(Object& obj, Input& fr)
osg::Quat att;
bool iteratorAdvanced = false;
if (fr.matchSequence("bindQuaternion %f %f %f %f"))
if (fr.matchSequence("bindQuaternion %f %f %f %f"))
{
fr[1].getFloat(att[0]);
fr[2].getFloat(att[1]);
@@ -50,10 +57,11 @@ bool Bone_readLocalData(Object& obj, Input& fr)
fr += 5;
iteratorAdvanced = true;
osg::notify(osg::WARN) << "Old osgAnimation file format update your data file" << std::endl;
}
osg::Vec3d pos(0,0,0);
if (fr.matchSequence("bindPosition %f %f %f"))
if (fr.matchSequence("bindPosition %f %f %f"))
{
fr[1].getFloat(pos[0]);
fr[2].getFloat(pos[1]);
@@ -61,10 +69,11 @@ bool Bone_readLocalData(Object& obj, Input& fr)
fr += 4;
iteratorAdvanced = true;
osg::notify(osg::WARN) << "Old osgAnimation file format update your data file" << std::endl;
}
osg::Vec3d scale(1,1,1);
if (fr.matchSequence("bindScale %f %f %f"))
if (fr.matchSequence("bindScale %f %f %f"))
{
fr[1].getFloat(scale[0]);
fr[2].getFloat(scale[1]);
@@ -72,31 +81,45 @@ bool Bone_readLocalData(Object& obj, Input& fr)
fr += 4;
iteratorAdvanced = true;
osg::notify(osg::WARN) << "Old osgAnimation file format update your data file" << std::endl;
}
bone.setBindMatrixInBoneSpace( osg::Matrix(att) * osg::Matrix::translate(pos));
if (fr.matchSequence("InvBindMatrixInSkeletonSpace {"))
{
Matrix matrix;
if (readMatrix(matrix,fr, "InvBindMatrixInSkeletonSpace"))
{
bone.setInvBindMatrixInSkeletonSpace(matrix);
iteratorAdvanced = true;
}
}
if (fr.matchSequence("MatrixInSkeletonSpace {"))
{
Matrix matrix;
if (readMatrix(matrix,fr, "MatrixInSkeletonSpace"))
{
bone.setMatrixInSkeletonSpace(matrix);
iteratorAdvanced = true;
}
}
return iteratorAdvanced;
}
bool Bone_writeLocalData(const Object& obj, Output& fw)
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;
bool res1 = writeMatrix(bone.getInvBindMatrixInSkeletonSpace(), fw, "InvBindMatrixInSkeletonSpace");
// write this field for debug only
// because it's recompute at each update
bool res2 = writeMatrix(bone.getMatrixInSkeletonSpace(), fw, "MatrixInSkeletonSpace");
return (res1 || res2);
}
RegisterDotOsgWrapperProxy g_atkBoneProxy
RegisterDotOsgWrapperProxy g_BoneProxy
(
new osgAnimation::Bone,
"osgAnimation::Bone",
"Object Node Transform osgAnimation::Bone Group",
"Object Node MatrixTransform osgAnimation::Bone Group",
&Bone_readLocalData,
&Bone_writeLocalData
);
@@ -111,23 +134,94 @@ bool Skeleton_writeLocalData(const Object& obj, Output& fr)
{
return true;
}
RegisterDotOsgWrapperProxy g_atkRootSkeletonProxy
RegisterDotOsgWrapperProxy g_SkeletonProxy
(
new osgAnimation::Skeleton,
"osgAnimation::Skeleton",
"Object Node Transform osgAnimation::Bone osgAnimation::Skeleton Group",
"Object Node MatrixTransform osgAnimation::Skeleton Group",
&Skeleton_readLocalData,
&Skeleton_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
// Helper method for reading channels
bool Animation_readChannel(osgAnimation::Channel* pChannel, Input& fr)
{
bool iteratorAdvanced = false;
std::string name = "unknown";
if (fr.matchSequence("name %s"))
{
if (fr[1].getStr())
name = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
pChannel->setName(name);
std::string target = "unknown";
if (fr.matchSequence("target %s"))
{
if (fr[1].getStr())
target = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
pChannel->setTargetName(target);
// we dont need this info
float weight = 1.0;
if (fr.matchSequence("weight %f"))
{
fr[1].getFloat(weight);
fr += 2;
iteratorAdvanced = true;
}
// pChannel->setWeight(weight);
return iteratorAdvanced;
}
bool Animation_readLocalData(Object& obj, Input& fr)
bool Animation_readLocalData(Object& obj, Input& fr)
{
osgAnimation::Animation& anim = dynamic_cast<osgAnimation::Animation&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("playmode %w"))
{
if (fr[1].matchWord("ONCE")) anim.setPlaymode(osgAnimation::Animation::ONCE);
else if (fr[1].matchWord("STAY")) anim.setPlaymode(osgAnimation::Animation::STAY);
else if (fr[1].matchWord("LOOP")) anim.setPlaymode(osgAnimation::Animation::LOOP);
else if (fr[1].matchWord("PPONG")) anim.setPlaymode(osgAnimation::Animation::PPONG);
fr += 2;
iteratorAdvanced = true;
}
if (fr.matchSequence("weight %f"))
{
float weight;
fr[1].getFloat(weight);
fr += 2;
iteratorAdvanced = true;
anim.setWeight(weight);
}
if (fr.matchSequence("duration %f"))
{
float duration;
fr[1].getFloat(duration);
fr += 2;
iteratorAdvanced = true;
anim.setDuration(duration);
}
if (fr.matchSequence("starttime %f"))
{
float starttime;
fr[1].getFloat(starttime);
fr += 2;
iteratorAdvanced = true;
anim.setStartTime(starttime);
}
int nbChannels = 0;
if (fr.matchSequence("num_channels %i"))
{
@@ -138,30 +232,267 @@ bool Animation_readLocalData(Object& obj, Input& fr)
for (int i = 0; i < nbChannels; i++)
{
if (fr.matchSequence("Channel {"))
if (fr.matchSequence("DoubleLinearChannel {"))
{
fr += 2;
osgAnimation::DoubleLinearChannel* channel = new osgAnimation::DoubleLinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
double v;
float time;
if (fr.matchSequence("key %f %f"))
{
fr[1].getFloat(time);
fr[2].getFloat(v);
fr += 3;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::DoubleKeyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("FloatLinearChannel {"))
{
fr += 2;
osgAnimation::FloatLinearChannel* channel = new osgAnimation::FloatLinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
float v;
float time;
if (fr.matchSequence("key %f %f"))
{
fr[1].getFloat(time);
fr[2].getFloat(v);
fr += 3;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::FloatKeyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("Vec2LinearChannel {"))
{
fr += 2;
osgAnimation::Vec2LinearChannel* channel = new osgAnimation::Vec2LinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
osg::Vec2 v;
float time;
if (fr.matchSequence("key %f %f %f"))
{
fr[1].getFloat(time);
fr[2].getFloat(v[0]);
fr[3].getFloat(v[1]);
fr += 4;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec2Keyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("Vec3LinearChannel {"))
{
fr += 2;
osgAnimation::Vec3LinearChannel* channel = new osgAnimation::Vec3LinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
osg::Vec3 v;
float time;
if (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;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec3Keyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("Vec4LinearChannel {"))
{
fr += 2;
osgAnimation::Vec4LinearChannel* channel = new osgAnimation::Vec4LinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
osg::Vec4 v;
float time;
if (fr.matchSequence("key %f %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].getFloat(v[3]);
fr += 6;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec4Keyframe(time, v));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
else if (fr.matchSequence("QuatSphericalLinearChannel {"))
{
fr += 2;
osgAnimation::QuatSphericalLinearChannel* channel = new osgAnimation::QuatSphericalLinearChannel;
if (Animation_readChannel(channel, fr))
iteratorAdvanced = true;
int nbKeys;
if (fr.matchSequence("Keyframes %i {"))
{
fr[1].getInt(nbKeys);
fr += 3;
iteratorAdvanced = true;
for (int k = 0; k < nbKeys; k++)
{
osg::Quat q;
float time;
if (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;
channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::QuatKeyframe(time, q));
iteratorAdvanced = true;
}
}
anim.addChannel(channel);
if (fr.matchSequence("}")) // keyframes
fr += 1;
}
if (fr.matchSequence("}")) // channel
fr += 1;
}
// Deprecated
// Reading of old channel info
// Kept here for easy conversion of old .osg data to new format
else if (fr.matchSequence("Channel {"))
{
fr += 2;
std::string name = "unknown";
if (fr.matchSequence("name %s"))
{
name = fr[1].getStr();
if (fr[1].getStr())
name = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
std::string target = "unknown";
if (fr.matchSequence("target %s"))
{
target = fr[1].getStr();
if (fr[1].getStr())
target = fr[1].getStr();
fr += 2;
iteratorAdvanced = true;
}
std::string type;
std::string type = "unknown";
int nbKeys;
if (fr.matchSequence("Keyframes %s %i {"))
{
type = fr[1].getStr();
if (fr[1].getStr())
type = fr[1].getStr();
fr[2].getInt(nbKeys);
fr += 4;
iteratorAdvanced = true;
@@ -175,11 +506,11 @@ bool Animation_readLocalData(Object& obj, Input& fr)
}
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++)
@@ -229,60 +560,130 @@ bool Animation_readLocalData(Object& obj, Input& fr)
return iteratorAdvanced;
}
// Helper method for writing channels
template <typename ChannelType, typename ContainerType>
void Animation_writeChannel(const std::string& channelString, ChannelType* pChannel, Output& fw)
{
fw.indent() << channelString.c_str() << " {" << std::endl;
fw.moveIn();
fw.indent() << "name \"" << pChannel->getName() << "\"" << std::endl;
fw.indent() << "target \"" << pChannel->getTargetName() << "\"" << std::endl;
// fw.indent() << "weight " << pChannel->getWeight() << std::endl;
ContainerType* kfc = pChannel->getSamplerTyped()->getKeyframeContainerTyped();
if (kfc)
{
fw.indent() << "Keyframes " << kfc->size() << " {" << std::endl;
fw.moveIn();
for (unsigned int k = 0; k < kfc->size(); k++)
{
fw.indent() << "key " << (*kfc)[k].getTime() << " " << (*kfc)[k].getValue() << std::endl;
}
fw.moveOut();
fw.indent() << "}" << std::endl;
fw.moveOut();
fw.indent() << "}" << std::endl;
}
}
bool Animation_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::Animation& anim = dynamic_cast<const osgAnimation::Animation&>(obj);
switch (anim.getPlayMode())
{
case osgAnimation::Animation::ONCE:
fw.indent() << "playmode ONCE" << std::endl;
break;
case osgAnimation::Animation::STAY:
fw.indent() << "playmode STAY" << std::endl;
break;
case osgAnimation::Animation::LOOP:
fw.indent() << "playmode LOOP" << std::endl;
break;
case osgAnimation::Animation::PPONG:
fw.indent() << "playmode PPONG" << std::endl;
break;
default:
break;
}
fw.indent() << "weight " << anim.getWeight() << std::endl;
fw.indent() << "duration " << anim.getDuration() << std::endl;
fw.indent() << "starttime " << anim.getStartTime() << std::endl;
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;
osgAnimation::Channel* pChannel = anim.getChannels()[i].get();
std::string type = "unknown";
if (anim.getChannels()[i]->getName() == std::string("quaternion"))
osgAnimation::DoubleLinearChannel* pDlc = dynamic_cast<osgAnimation::DoubleLinearChannel*>(pChannel);
if (pDlc)
{
type = "Quat";
Animation_writeChannel<osgAnimation::DoubleLinearChannel, osgAnimation::DoubleKeyframeContainer>("DoubleLinearChannel", pDlc, fw);
continue;
}
else if (anim.getChannels()[i]->getName() == std::string("rotation"))
osgAnimation::FloatLinearChannel* pFlc = dynamic_cast<osgAnimation::FloatLinearChannel*>(pChannel);
if (pFlc)
{
type = "Quat";
Animation_writeChannel<osgAnimation::FloatLinearChannel, osgAnimation::FloatKeyframeContainer>("FloatLinearChannel", pFlc, fw);
continue;
}
else if (anim.getChannels()[i]->getName() == std::string("euler"))
osgAnimation::Vec2LinearChannel* pV2lc = dynamic_cast<osgAnimation::Vec2LinearChannel*>(pChannel);
if (pV2lc)
{
type = "Vec3";
Animation_writeChannel<osgAnimation::Vec2LinearChannel, osgAnimation::Vec2KeyframeContainer>("Vec2LinearChannel", pV2lc, fw);
continue;
}
else if (anim.getChannels()[i]->getName() == std::string("scale"))
osgAnimation::Vec3LinearChannel* pV3lc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(pChannel);
if (pV3lc)
{
type = "Vec3";
Animation_writeChannel<osgAnimation::Vec3LinearChannel, osgAnimation::Vec3KeyframeContainer>("Vec3LinearChannel", pV3lc, fw);
continue;
}
else if (anim.getChannels()[i]->getName() == std::string("position"))
osgAnimation::Vec4LinearChannel* pV4lc = dynamic_cast<osgAnimation::Vec4LinearChannel*>(pChannel);
if (pV4lc)
{
type = "Vec3";
Animation_writeChannel<osgAnimation::Vec4LinearChannel, osgAnimation::Vec4KeyframeContainer>("Vec4LinearChannel", pV4lc, fw);
continue;
}
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++)
osgAnimation::QuatSphericalLinearChannel* pQslc = dynamic_cast<osgAnimation::QuatSphericalLinearChannel*>(pChannel);
if (pQslc)
{
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;
}
Animation_writeChannel<osgAnimation::QuatSphericalLinearChannel, osgAnimation::QuatKeyframeContainer>("QuatSphericalLinearChannel", pQslc, fw);
continue;
}
osgAnimation::FloatCubicBezierChannel* pFcbc = dynamic_cast<osgAnimation::FloatCubicBezierChannel*>(pChannel);
if (pFcbc)
{
Animation_writeChannel<osgAnimation::FloatCubicBezierChannel, osgAnimation::FloatCubicBezierKeyframeContainer>("FloatCubicBezierChannel", pFcbc, fw);
continue;
}
osgAnimation::DoubleCubicBezierChannel* pDcbc = dynamic_cast<osgAnimation::DoubleCubicBezierChannel*>(pChannel);
if (pDcbc)
{
Animation_writeChannel<osgAnimation::DoubleCubicBezierChannel, osgAnimation::DoubleCubicBezierKeyframeContainer>("DoubleCubicBezierChannel", pDcbc, fw);
continue;
}
osgAnimation::Vec2CubicBezierChannel* pV2cbc = dynamic_cast<osgAnimation::Vec2CubicBezierChannel*>(pChannel);
if (pV2cbc)
{
Animation_writeChannel<osgAnimation::Vec2CubicBezierChannel, osgAnimation::Vec2CubicBezierKeyframeContainer>("Vec2CubicBezierChannel", pV2cbc, fw);
continue;
}
osgAnimation::Vec3CubicBezierChannel* pV3cbc = dynamic_cast<osgAnimation::Vec3CubicBezierChannel*>(pChannel);
if (pV3cbc)
{
Animation_writeChannel<osgAnimation::Vec3CubicBezierChannel, osgAnimation::Vec3CubicBezierKeyframeContainer>("Vec3CubicBezierChannel", pV3cbc, fw);
continue;
}
osgAnimation::Vec4CubicBezierChannel* pV4cbc = dynamic_cast<osgAnimation::Vec4CubicBezierChannel*>(pChannel);
if (pV4cbc)
{
Animation_writeChannel<osgAnimation::Vec4CubicBezierChannel, osgAnimation::Vec4CubicBezierKeyframeContainer>("Vec4CubicBezierChannel", pV4cbc, fw);
continue;
}
fw.moveOut();
fw.indent() << "}" << std::endl;
fw.moveOut();
fw.indent() << "}" << std::endl;
}
return true;
}
@@ -344,7 +745,7 @@ bool AnimationManagerBase_writeLocalData(const osgAnimation::AnimationManagerBas
const osgAnimation::AnimationList& animList = manager.getAnimationList();
fw.indent() << "num_animations " << animList.size() << std::endl;
for (osgAnimation::AnimationList::const_iterator it = animList.begin(); it != animList.end(); it++)
for (osgAnimation::AnimationList::const_iterator it = animList.begin(); it != animList.end(); ++it)
{
if (!fw.writeObject(**it))
osg::notify(osg::WARN)<<"Warning: can't write an animation object"<< std::endl;
@@ -437,6 +838,13 @@ bool RigGeometry_readLocalData(Object& obj, Input& fr)
if (!vmap->empty())
geom.setInfluenceMap(vmap.get());
if (fr.matchSequence("Geometry {"))
{
osg::Geometry* source = dynamic_cast<osg::Geometry*>(fr.readObject());
geom.setSourceGeometry(source);
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
@@ -448,7 +856,7 @@ bool RigGeometry_writeLocalData(const Object& obj, Output& fw)
return true;
fw.indent() << "num_influences " << vm->size() << std::endl;
fw.moveIn();
for (osgAnimation::VertexInfluenceMap::const_iterator it = vm->begin(); it != vm->end(); it++)
for (osgAnimation::VertexInfluenceMap::const_iterator it = vm->begin(); it != vm->end(); ++it)
{
std::string name = it->first;
if (name.empty())
@@ -464,6 +872,8 @@ bool RigGeometry_writeLocalData(const Object& obj, Output& fw)
fw.indent() << "}" << std::endl;
}
fw.moveOut();
fw.writeObject(*geom.getSourceGeometry());
return true;
}
@@ -471,15 +881,135 @@ RegisterDotOsgWrapperProxy g_atkRigGeometryProxy
(
new osgAnimation::RigGeometry,
"osgAnimation::RigGeometry",
"Object Drawable osgAnimation::RigGeometry Geometry",
"Object osgAnimation::RigGeometry Drawable Geometry",
&RigGeometry_readLocalData,
&RigGeometry_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
bool MorphGeometry_readLocalData(Object& obj, Input& fr)
{
osgAnimation::MorphGeometry& geom = dynamic_cast<osgAnimation::MorphGeometry&>(obj);
bool UpdateBone_readLocalData(Object& obj, Input& fr)
bool iteratorAdvanced = false;
if (fr[0].matchWord("method"))
{
if (fr[1].matchWord("NORMALIZED"))
{
geom.setMethod(osgAnimation::MorphGeometry::NORMALIZED);
fr+=2;
iteratorAdvanced = true;
}
else if (fr[1].matchWord("RELATIVE"))
{
geom.setMethod(osgAnimation::MorphGeometry::RELATIVE);
fr+=2;
iteratorAdvanced = true;
}
}
if (fr[0].matchWord("morphNormals"))
{
if (fr[1].matchWord("TRUE"))
{
geom.setMorphNormals(true);
fr+=2;
iteratorAdvanced = true;
}
else if (fr[1].matchWord("FALSE"))
{
geom.setMorphNormals(false);
fr+=2;
iteratorAdvanced = true;
}
}
int num_morphTargets = 0;
if (fr.matchSequence("num_morphTargets %i"))
{
fr[1].getInt(num_morphTargets);
fr += 2;
iteratorAdvanced = true;
}
for (int i = 0; i < num_morphTargets; i++)
{
if (fr.matchSequence("MorphTarget {"))
{
int entry = fr[0].getNoNestedBrackets();
fr += 2;
iteratorAdvanced = true;
while (!fr.eof() && fr[0].getNoNestedBrackets()>entry)
{
float weight = 1.0;
if (fr.matchSequence("weight %f"))
{
fr[1].getFloat(weight);
fr += 2;
}
osg::Drawable* drawable = NULL;
drawable = fr.readDrawable();
osg::Geometry* geometry = dynamic_cast<osg::Geometry*>(drawable);
if (geometry)
geom.addMorphTarget(geometry, weight);
}
if (fr.matchSequence("}"))
fr += 1;
}
}
return iteratorAdvanced;
}
bool MorphGeometry_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::MorphGeometry& geom = dynamic_cast<const osgAnimation::MorphGeometry&>(obj);
switch(geom.getMethod())
{
case(osgAnimation::MorphGeometry::NORMALIZED): fw.indent() << "method NORMALIZED"<<std::endl; break;
case(osgAnimation::MorphGeometry::RELATIVE): fw.indent() << "method RELATIVE"<<std::endl; break;
}
fw.indent() << "morphNormals ";
if (geom.getMorphNormals())
fw << "TRUE" << std::endl;
else
fw << "FALSE" << std::endl;
const osgAnimation::MorphGeometry::MorphTargetList& morphTargets = geom.getMorphTargetList();
fw.indent() << "num_morphTargets " << morphTargets.size() << std::endl;
for (unsigned int i = 0; i < morphTargets.size(); i++)
{
fw.indent() << "MorphTarget {" << std::endl;
fw.moveIn();
fw.indent() << "weight " << morphTargets[i].getWeight() <<std::endl;
fw.writeObject(*morphTargets[i].getGeometry());
fw.moveOut();
fw.indent() << "}" << std::endl;
}
return true;
}
RegisterDotOsgWrapperProxy g_osgAnimationMorphGeometryProxy
(
new osgAnimation::MorphGeometry,
"osgAnimation::MorphGeometry",
"Object Drawable osgAnimation::MorphGeometry Geometry",
&MorphGeometry_readLocalData,
&MorphGeometry_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);
bool UpdateBone_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
return iteratorAdvanced;
@@ -490,11 +1020,11 @@ bool UpdateBone_writeLocalData(const Object& obj, Output& fw)
return true;
}
RegisterDotOsgWrapperProxy g_atkUpdateBoneProxy
RegisterDotOsgWrapperProxy g_UpdateBoneProxy
(
new osgAnimation::Bone::UpdateBone,
new osgAnimation::UpdateBone,
"osgAnimation::UpdateBone",
"Object NodeCallback osgAnimation::UpdateBone",
"Object NodeCallback osgAnimation::UpdateMatrixTransform osgAnimation::UpdateBone",
&UpdateBone_readLocalData,
&UpdateBone_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
@@ -513,7 +1043,7 @@ bool UpdateSkeleton_writeLocalData(const Object& obj, Output& fw)
return true;
}
RegisterDotOsgWrapperProxy g_atkUpdateSkeletonProxy
RegisterDotOsgWrapperProxy g_UpdateSkeletonProxy
(
new osgAnimation::Skeleton::UpdateSkeleton,
"osgAnimation::UpdateSkeleton",
@@ -524,25 +1054,24 @@ RegisterDotOsgWrapperProxy g_atkUpdateSkeletonProxy
);
bool UpdateTransform_readLocalData(Object& obj, Input& fr)
bool UpdateMorph_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
return iteratorAdvanced;
}
bool UpdateTransform_writeLocalData(const Object& obj, Output& fw)
bool UpdateMorph_writeLocalData(const Object& obj, Output& fw)
{
return true;
}
RegisterDotOsgWrapperProxy g_atkUpdateTransformProxy
RegisterDotOsgWrapperProxy g_UpdateMorphProxy
(
new osgAnimation::UpdateTransform,
"osgAnimation::UpdateTransform",
"Object NodeCallback osgAnimation::UpdateTransform",
&UpdateTransform_readLocalData,
&UpdateTransform_writeLocalData,
new osgAnimation::UpdateMorph,
"osgAnimation::UpdateMorph",
"Object NodeCallback osgAnimation::UpdateMorph",
&UpdateMorph_readLocalData,
&UpdateMorph_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);

View File

@@ -0,0 +1,228 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/StackedTranslateElement>
#include <osgAnimation/StackedMatrixElement>
#include <osgAnimation/StackedScaleElement>
#include <osgAnimation/StackedRotateAxisElement>
#include <osgAnimation/StackedQuaternionElement>
#include <osgDB/Input>
#include <osgDB/Output>
#include <osgDB/Registry>
#include <osgDB/ReaderWriter>
#include <osg/io_utils>
#include "Matrix.h"
using namespace osgDB;
using namespace osg;
bool readStackedTranslateElement(Object& obj, Input& fr)
{
osgAnimation::StackedTranslateElement& element = dynamic_cast<osgAnimation::StackedTranslateElement&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("translate %f %f %f"))
{
++fr;
osg::Vec3 translate;
fr[0].getFloat(translate.x());
fr[1].getFloat(translate.y());
fr[2].getFloat(translate.z());
element.setTranslate(translate);
fr += 3;
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool writeStackedTranslateElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedTranslateElement& element = dynamic_cast<const osgAnimation::StackedTranslateElement&>(obj);
fw.indent() << "translate " << element.getTranslate() << std::endl;
return true;
}
RegisterDotOsgWrapperProxy g_StackedTranslateElementProxy
(
new osgAnimation::StackedTranslateElement,
"osgAnimation::StackedTranslateElement",
"Object osgAnimation::StackedTranslateElement",
&readStackedTranslateElement,
&writeStackedTranslateElement,
DotOsgWrapper::READ_AND_WRITE
);
bool readStackedScaleElement(Object& obj, Input& fr)
{
osgAnimation::StackedScaleElement& element = dynamic_cast<osgAnimation::StackedScaleElement&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("scale %f %f %f"))
{
++fr;
osg::Vec3 scale;
fr[0].getFloat(scale.x());
fr[1].getFloat(scale.y());
fr[2].getFloat(scale.z());
element.setScale(scale);
fr += 3;
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool writeStackedScaleElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedScaleElement& element = dynamic_cast<const osgAnimation::StackedScaleElement&>(obj);
fw.indent() << "scale " << element.getScale() << std::endl;
return true;
}
RegisterDotOsgWrapperProxy g_StackedScaleElementProxy
(
new osgAnimation::StackedScaleElement,
"osgAnimation::StackedScaleElement",
"Object osgAnimation::StackedScaleElement",
&readStackedScaleElement,
&writeStackedScaleElement,
DotOsgWrapper::READ_AND_WRITE
);
bool readStackedMatrixElement(Object& obj, Input& fr)
{
osgAnimation::StackedMatrixElement& element = dynamic_cast<osgAnimation::StackedMatrixElement&>(obj);
bool iteratorAdvanced = false;
if (fr[0].matchWord("Matrix"))
{
osg::Matrix matrix;
matrix.makeIdentity();
iteratorAdvanced = readMatrix(matrix, fr);
element.setMatrix(matrix);
}
return iteratorAdvanced;
}
bool writeStackedMatrixElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedMatrixElement& element = dynamic_cast<const osgAnimation::StackedMatrixElement&>(obj);
writeMatrix(element.getMatrix(), fw);
return true;
}
RegisterDotOsgWrapperProxy g_StackedMatrixElementProxy
(
new osgAnimation::StackedMatrixElement,
"osgAnimation::StackedMatrixElement",
"Object osgAnimation::StackedMatrixElement",
&readStackedMatrixElement,
&writeStackedMatrixElement,
DotOsgWrapper::READ_AND_WRITE
);
bool writeStackedRotateAxisElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedRotateAxisElement& element = dynamic_cast<const osgAnimation::StackedRotateAxisElement&>(obj);
fw.indent() << "axis " << element.getAxis() << std::endl;
fw.indent() << "angle " << element.getAngle() << std::endl;
return true;
}
bool readStackedRotateAxisElement(Object& obj, Input& fr)
{
osgAnimation::StackedRotateAxisElement& element = dynamic_cast<osgAnimation::StackedRotateAxisElement&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("axis %f %f %f"))
{
++fr;
osg::Vec3 axis;
fr[0].getFloat(axis.x());
fr[1].getFloat(axis.y());
fr[2].getFloat(axis.z());
element.setAxis(axis);
fr += 3;
iteratorAdvanced = true;
}
if (fr.matchSequence("angle %f"))
{
++fr;
double angle = 0;
fr[0].getFloat(angle);
++fr;
element.setAngle(angle);
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
RegisterDotOsgWrapperProxy g_StackedRotateAxisElementProxy
(
new osgAnimation::StackedRotateAxisElement,
"osgAnimation::StackedRotateAxisElement",
"Object osgAnimation::StackedRotateAxisElement",
&readStackedRotateAxisElement,
&writeStackedRotateAxisElement,
DotOsgWrapper::READ_AND_WRITE
);
bool readStackedQuaternionElement(Object& obj, Input& fr)
{
osgAnimation::StackedQuaternionElement& element = dynamic_cast<osgAnimation::StackedQuaternionElement&>(obj);
bool iteratorAdvanced = false;
if (fr.matchSequence("quaternion %f %f %f %f"))
{
++fr;
osg::Quat quaternion;
fr[0].getFloat(quaternion[0]);
fr[1].getFloat(quaternion[1]);
fr[2].getFloat(quaternion[2]);
fr[3].getFloat(quaternion[3]);
element.setQuaternion(quaternion);
fr += 4;
iteratorAdvanced = true;
}
return iteratorAdvanced;
}
bool writeStackedQuaternionElement(const Object& obj, Output& fw)
{
const osgAnimation::StackedQuaternionElement& element = dynamic_cast<const osgAnimation::StackedQuaternionElement&>(obj);
fw.indent() << "quaternion " << element.getQuaternion() << std::endl;
return true;
}
RegisterDotOsgWrapperProxy g_StackedQuaternionElementProxy
(
new osgAnimation::StackedQuaternionElement,
"osgAnimation::StackedQuaternionElement",
"Object osgAnimation::StackedQuaternionElement",
&readStackedQuaternionElement,
&writeStackedQuaternionElement,
DotOsgWrapper::READ_AND_WRITE
);

View File

@@ -0,0 +1,47 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/Input>
#include <osgDB/Output>
#include <osgDB/Registry>
#include <osgDB/ReaderWriter>
#include <osg/io_utils>
#include <osgAnimation/UpdateMaterial>
using namespace osg;
using namespace osgDB;
bool UpdateMaterial_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
return iteratorAdvanced;
}
bool UpdateMaterial_writeLocalData(const Object& obj, Output& fw)
{
return true;
}
RegisterDotOsgWrapperProxy g_UpdateMaterialProxy
(
new osgAnimation::UpdateMaterial,
"osgAnimation::UpdateMaterial",
"Object StateAttribute::Callback osgAnimation::UpdateMaterial",
&UpdateMaterial_readLocalData,
&UpdateMaterial_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);

View File

@@ -0,0 +1,70 @@
/* -*-c++-*-
* Copyright (C) 2009 Cedric Pinson <cedric.pinson@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/Input>
#include <osgDB/Output>
#include <osgDB/Registry>
#include <osgDB/ReaderWriter>
#include <osg/io_utils>
#include <osgAnimation/StackedTransformElement>
#include <osgAnimation/UpdateMatrixTransform>
using namespace osg;
using namespace osgDB;
bool UpdateMatrixTransform_readLocalData(Object& obj, Input& fr)
{
bool iteratorAdvanced = false;
osgAnimation::UpdateMatrixTransform& updateCallback = dynamic_cast<osgAnimation::UpdateMatrixTransform&>(obj);
osgAnimation::StackedTransform& stackedTransform = updateCallback.getStackedTransforms();
int entry = fr[0].getNoNestedBrackets();
while (!fr.eof() && fr[0].getNoNestedBrackets() == entry && fr.matchSequence("%w {"))
{
osgAnimation::StackedTransformElement* element = dynamic_cast<osgAnimation::StackedTransformElement*>(fr.readObject());
if (element)
stackedTransform.push_back(element);
}
return iteratorAdvanced;
}
bool UpdateMatrixTransform_writeLocalData(const Object& obj, Output& fw)
{
const osgAnimation::UpdateMatrixTransform* uc = dynamic_cast<const osgAnimation::UpdateMatrixTransform*>(&obj);
const osgAnimation::StackedTransform& transforms = uc->getStackedTransforms();
for (osgAnimation::StackedTransform::const_iterator it = transforms.begin(); it != transforms.end(); ++it)
{
osgAnimation::StackedTransformElement* element = it->get();
if (element)
fw.writeObject(*element);
}
return true;
}
RegisterDotOsgWrapperProxy g_UpdateMatrixTransformProxy
(
new osgAnimation::UpdateMatrixTransform,
"osgAnimation::UpdateMatrixTransform",
"Object NodeCallback osgAnimation::UpdateMatrixTransform",
&UpdateMatrixTransform_readLocalData,
&UpdateMatrixTransform_writeLocalData,
DotOsgWrapper::READ_AND_WRITE
);