From Cedric Pinson, split timeline classes in differents files, cleanup and add a statshandler to visualize current action in timeline

This commit is contained in:
Cedric Pinson
2009-06-15 14:48:37 +00:00
parent b2943aa50a
commit c4c5ca7566
18 changed files with 2000 additions and 465 deletions

208
include/osgAnimation/Action Normal file
View File

@@ -0,0 +1,208 @@
/* -*-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 (_nestedCallback.valid())
_nestedCallback->addNestedCallback(callback);
else
_nestedCallback = callback;
}
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();
}
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;
};
// blend in from 0 to weight in duration
class BlendIn : public Action
{
double _weight;
osg::ref_ptr<Animation> _animation;
public:
META_Action(osgAnimation, BlendIn);
BlendIn() : _weight(0) {}
BlendIn(const BlendIn& a, const osg::CopyOp& c) : Action(a,c) { _weight = a._weight; _animation = a._animation;}
BlendIn(Animation* animation, double duration, double weight);
double getWeight() const { return _weight;}
Animation* getAnimation() { return _animation.get(); }
void computeWeight(unsigned int frame);
};
// blend in from 0 to weight in duration
class BlendOut : public Action
{
double _weight;
osg::ref_ptr<Animation> _animation;
public:
META_Action(osgAnimation, BlendOut);
BlendOut() : _weight(0) {}
BlendOut(const BlendOut& a, const osg::CopyOp& c) : Action(a,c) { _weight = a._weight; _animation = a._animation;}
BlendOut(Animation* animation, double duration);
Animation* getAnimation() { return _animation.get(); }
double getWeight() const { return _weight;}
void computeWeight(unsigned int frame);
};
class ActionAnimation : public Action
{
public:
META_Action(osgAnimation, ActionAnimation);
ActionAnimation() {}
ActionAnimation(const ActionAnimation& a, const osg::CopyOp& c) : Action(a,c) { _animation = a._animation;}
ActionAnimation(Animation* animation);
void updateAnimation(unsigned int frame);
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
{
public:
META_Action(osgAnimation, StripAnimation);
StripAnimation() {}
StripAnimation(const StripAnimation& a, const osg::CopyOp& c);
StripAnimation(Animation* animation, double blendInDuration = 0.0, double blendOutDuration = 0.0, double blendInWeightTarget = 1.0 );
ActionAnimation* getActionAnimation() { return _animation.get(); }
BlendIn* getBlendIn() { return _blendIn.get(); }
BlendOut* getBlendOut() { return _blendOut.second.get(); }
const ActionAnimation* getActionAnimation() const { return _animation.get(); }
const BlendIn* getBlendIn() const { return _blendIn.get(); }
const BlendOut* getBlendOut() const { return _blendOut.second.get(); }
unsigned int getBlendOutStartFrame() const { return _blendOut.first; }
unsigned int getLoop() const { return _animation->getLoop(); }
void setLoop(unsigned int loop);
void computeWeightAndUpdateAnimation(unsigned int frame);
protected:
typedef std::pair<unsigned int, osg::ref_ptr<BlendOut> > FrameBlendOut;
osg::ref_ptr<BlendIn> _blendIn;
FrameBlendOut _blendOut;
osg::ref_ptr<ActionAnimation> _animation;
};
}
#endif

View File

@@ -0,0 +1,37 @@
/* -*-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/Action>
namespace osgAnimation
{
/** Callback used to run new action on the timeline.*/
class RunAction : public Action::Callback
{
public:
RunAction(Action* a) : _action(a) {}
virtual void operator()(Action* action, ActionVisitor* visitor);
protected:
osg::ref_ptr<Action> _action;
};
}
#endif

View File

@@ -0,0 +1,110 @@
/* -*-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 BlendIn;
class BlendOut;
class ActionAnimation;
class StripAnimation;
#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:
std::vector<FrameAction> _stackFrameAction;
std::vector<osg::ref_ptr<Timeline> > _stackTimeline;
META_ActionVisitor(osgAnimation, ActionVisitor);
void traverse(Action& visitor);
void pushFrameActionOnStack(FrameAction& fa);
void popFrameAction();
void pushTimelineOnStack(Timeline* tm);
void popTimeline();
Timeline* getCurrentTimeline();
virtual void apply(Action& action);
virtual void apply(Timeline& tm);
virtual void apply(BlendIn& action);
virtual void apply(BlendOut& action);
virtual void apply(ActionAnimation& action);
virtual void apply(StripAnimation& action);
};
class OSGANIMATION_EXPORT UpdateActionVisitor : public osgAnimation::ActionVisitor
{
protected:
unsigned int _frame;
public:
META_ActionVisitor(osgAnimation, UpdateActionVisitor);
UpdateActionVisitor();
void setFrame(unsigned int frame) { _frame = frame;}
bool isActive() const;
unsigned int getLocalFrame() const;
void apply(Timeline& action);
void apply(Action& action);
void apply(BlendIn& action);
void apply(BlendOut& action);
void apply(ActionAnimation& action);
void apply(StripAnimation& 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
@@ -110,7 +110,7 @@ namespace osgAnimation
_scale = new osgAnimation::Vec3Target;
}
void update(osgAnimation::Bone& bone)
void update(osgAnimation::Bone& bone)
{
bone.setTranslation(_position->getValue());
bone.setRotation(_quaternion->getValue());
@@ -126,25 +126,25 @@ namespace osgAnimation
bool link(osgAnimation::Channel* channel)
{
if (channel->getName().find("quaternion") != std::string::npos)
if (channel->getName().find("quaternion") != std::string::npos)
{
osgAnimation::QuatSphericalLinearChannel* qc = dynamic_cast<osgAnimation::QuatSphericalLinearChannel*>(channel);
if (qc)
if (qc)
{
qc->setTarget(_quaternion.get());
return true;
}
}
else if (channel->getName().find("position") != std::string::npos)
else if (channel->getName().find("position") != std::string::npos)
{
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
if (vc)
if (vc)
{
vc->setTarget(_position.get());
return true;
}
}
else if (channel->getName().find("scale") != std::string::npos)
}
else if (channel->getName().find("scale") != std::string::npos)
{
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
if (vc)
@@ -152,7 +152,7 @@ namespace osgAnimation
vc->setTarget(_scale.get());
return true;
}
}
}
else
{
std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;

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

@@ -89,7 +89,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)

View File

@@ -0,0 +1,115 @@
/* -*-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;
void updateGraph(osgAnimation::StatsActionVisitor* visitor); //, float width, float height, float ystart);
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; }
void setStats(osg::Stats* stats) { _stats = stats; }
void setFrame(unsigned int frame) { _frame = frame; }
void apply(Timeline& action);
void apply(Action& action);
void apply(BlendIn& action);
void apply(BlendOut& action);
void apply(ActionAnimation& action);
void apply(StripAnimation& 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
@@ -67,7 +67,7 @@ namespace osgAnimation
}
const T& getValue() const { return _target;}
void normalize()
void normalize()
{
float weightSummed = getWeight();
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1) < 1e-4)
@@ -91,6 +91,7 @@ namespace osgAnimation
TemplateTarget () {}
TemplateTarget (const osg::Quat& q) { setValue(q); }
const osg::Quat& getValue() const { return _target;}
void update(float weight, const osg::Quat& val)
{

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,161 +16,27 @@
#define OSGANIMATION_TIMELINE_H
#include <osgAnimation/Export>
#include <osg/Object>
#include <map>
#include <vector>
#include <osg/Notify>
#include <osg/Group>
#include <osgAnimation/Animation>
#include <osg/Stats>
#include <osgAnimation/Action>
#include <osgAnimation/FrameAction>
#include <osgAnimation/AnimationManagerBase>
namespace osgAnimation
{
class StatsActionVisitor;
class Action : public osg::Object
class OSGANIMATION_EXPORT Timeline : public Action //osg::Object
{
public:
class Callback : public osg::Object
{
public:
Callback(){}
Callback(const Callback&,const osg::CopyOp&) {}
META_Object(osgAnimation,Callback);
virtual void operator()(Action* /*action*/) {}
void addNestedCallback(Callback* callback)
{
if (_nested.valid())
_nested->addNestedCallback(callback);
else
_nested = callback;
}
protected:
osg::ref_ptr<Callback> _nested;
};
typedef std::map<unsigned int, osg::ref_ptr<Callback> > FrameCallback;
META_Object(osgAnimation, Action);
Action()
{
_numberFrame = 25;
_fps = 25;
_speed = 1.0;
_loop = 1;
}
Action(const Action&,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 ActionStatus
{
Play,
Stop
};
ActionStatus _state;
};
class OSGANIMATION_EXPORT Timeline : public osg::Object
{
public:
META_Object(osgAnimation, Timeline);
Timeline();
Timeline(const Timeline& nc,const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY);
META_Action(osgAnimation, Timeline);
enum TimelineStatus
{
Play,
@@ -179,14 +45,10 @@ namespace osgAnimation
TimelineStatus getStatus() const { return _state; }
typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
typedef std::vector<FrameAction> ActionList;
typedef std::map<int, ActionList> ActionLayers;
const ActionList& getActionLayer(int i)
{
return _actions[i];
}
const ActionList& getActionLayer(int i) { return _actions[i];}
unsigned int getCurrentFrame() const { return _currentFrame;}
double getCurrentTime() const { return _currentFrame * 1.0 / _fps;}
@@ -195,139 +57,44 @@ namespace osgAnimation
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;
}
bool isActive(Action* activeAction);
void removeAction(Action* action)
{
if (getEvaluating())
_removeActionOperations.push_back(FrameAction(0, action));
else
internalRemoveAction(action);
}
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);
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);
}
void clearActions();
virtual void evaluate(unsigned int frame)
{
setEvaluating(true);
osg::notify(osg::DEBUG_INFO) << getName() << " evaluate frame " << _currentFrame << std::endl;
virtual void update(double simulationTime);
void setLastFrameEvaluated(unsigned int frame) { _previousFrameEvaluated = 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->evaluate(frame - firstFrame);
}
}
setEvaluating(false);
void setEvaluating(bool state) { _evaluating = state;}
void traverse(ActionVisitor& visitor);
// evaluate callback after updating all animation
evaluateCallback(frame);
_previousFrameEvaluated = frame;
}
void setStats(osg::Stats* stats);
osg::Stats* getStats();
void collectStats(bool state);
osgAnimation::StatsActionVisitor* getStatsVisitor();
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();
}
const ActionLayers& getActionLayers() const { return _actions; }
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;
}
}
void processPendingOperation();
protected:
ActionLayers _actions;
double _lastUpdate;
double _speed;
unsigned int _currentFrame;
unsigned int _fps;
unsigned int _numberFrame;
unsigned int _previousFrameEvaluated;
bool _loop;
bool _initFirstFrame;
TimelineStatus _state;
bool _collectStats;
osg::ref_ptr<osg::Stats> _stats;
osg::ref_ptr<osgAnimation::StatsActionVisitor> _statsVisitor;
// to manage pending operation
bool _evaluating;
@@ -343,199 +110,13 @@ 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);
};
// 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
}
};
}
#endif