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

201
src/osgAnimation/Action.cpp Normal file
View File

@ -0,0 +1,201 @@
/* -*-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>
osgAnimation::Action::Action()
{
_numberFrame = 25;
_fps = 25;
_speed = 1.0;
_loop = 1;
}
osgAnimation::Action::Action(const Action&,const osg::CopyOp&) {}
osgAnimation::Action::Callback* osgAnimation::Action::getFrameCallback(unsigned int frame)
{
if (_framesCallback.find(frame) != _framesCallback.end())
{
return _framesCallback[frame];
}
return 0;
}
osgAnimation::Action::Callback* osgAnimation::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;
}
#if 0
void osgAnimation::Action::evaluate(unsigned int frame)
{
unsigned int frameInAction;
unsigned int loopDone;
bool result = evaluateFrame(frame, frameInAction, loopDone);
if (!result)
{
osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " << frameInAction << " finished" << std::endl;
return;
}
osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " << frame << " relative to loop " << frameInAction << " no loop " << loopDone<< std::endl;
frame = frameInAction;
if (_framesCallback.find(frame) != _framesCallback.end())
{
osg::notify(osg::DEBUG_INFO) << getName() << " evaluate callback " << _framesCallback[frame]->getName() << " at " << frame << std::endl;
(*_framesCallback[frame])(this, visitor);
}
}
#endif
osgAnimation::BlendIn::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");
}
void osgAnimation::BlendIn::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;
_animation->setWeight(w);
}
#if 0
void osgAnimation::BlendIn::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);
}
#endif
osgAnimation::BlendOut::BlendOut(Animation* animation, double duration)
{
_animation = animation;
float d = duration * _fps;
setNumFrames(static_cast<unsigned int>(floor(d) + 1));
_weight = 1.0;
setName("BlendOut");
}
void osgAnimation::BlendOut::computeWeight(unsigned int frame)
{
double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
double w = _weight * (1.0-ratio);
_animation->setWeight(w);
}
#if 0
void osgAnimation::BlendOut::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);
}
#endif
osgAnimation::ActionAnimation::ActionAnimation(Animation* animation) : _animation(animation)
{
Action::setDuration(animation->getDuration());
setName(animation->getName());
}
void osgAnimation::ActionAnimation::updateAnimation(unsigned int frame)
{
_animation->update(frame * 1.0/_fps);
}
osgAnimation::StripAnimation::StripAnimation(const StripAnimation& a, const osg::CopyOp& c) : Action(a,c)
{
_animation = a._animation;
_blendIn = a._blendIn;
_blendOut = a._blendOut;
}
osgAnimation::StripAnimation::StripAnimation(Animation* animation, double blendInDuration, double blendOutDuration, double blendInWeightTarget)
{
_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());
}
void osgAnimation::StripAnimation::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);
}
void osgAnimation::StripAnimation::computeWeightAndUpdateAnimation(unsigned int frame)
{
if (frame < _blendIn->getNumFrames())
_blendIn->computeWeight(frame);
if (frame >= _blendOut.first)
_blendOut.second->computeWeight(frame - _blendOut.first);
_animation->updateAnimation(frame);
}

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());
}

View File

@ -0,0 +1,164 @@
/* -*-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/ActionVisitor>
#include <osgAnimation/Timeline>
void osgAnimation::ActionVisitor::pushFrameActionOnStack(FrameAction& fa) { _stackFrameAction.push_back(fa); }
void osgAnimation::ActionVisitor::popFrameAction() { _stackFrameAction.pop_back(); }
void osgAnimation::ActionVisitor::pushTimelineOnStack(Timeline* tm) { _stackTimeline.push_back(tm); }
void osgAnimation::ActionVisitor::popTimeline() { _stackTimeline.pop_back(); }
void osgAnimation::ActionVisitor::apply(Action& action) { traverse(action); }
void osgAnimation::ActionVisitor::apply(Timeline& tm) { tm.traverse(*this); }
void osgAnimation::ActionVisitor::apply(BlendIn& action) { apply(static_cast<Action&>(action));}
void osgAnimation::ActionVisitor::apply(BlendOut& action) { apply(static_cast<Action&>(action)); }
void osgAnimation::ActionVisitor::apply(ActionAnimation& action) { apply(static_cast<Action&>(action)); }
void osgAnimation::ActionVisitor::apply(StripAnimation& action) { apply(static_cast<Action&>(action)); }
void osgAnimation::ActionVisitor::traverse(Action& action)
{
action.traverse(*this);
}
osgAnimation::Timeline* osgAnimation::ActionVisitor::getCurrentTimeline()
{
if (_stackTimeline.empty())
return 0;
return _stackTimeline.back().get();
}
osgAnimation::UpdateActionVisitor::UpdateActionVisitor() { _frame = 0; }
void osgAnimation::UpdateActionVisitor::apply(Timeline& tm)
{
tm.setEvaluating(true);
tm.traverse(*this);
tm.setEvaluating(false);
tm.setLastFrameEvaluated(_frame);
}
bool osgAnimation::UpdateActionVisitor::isActive() const
{
FrameAction fa = _stackFrameAction.back();
if (_frame < fa.first)
return false;
if (!fa.second.valid())
return false;
if (getLocalFrame() >= fa.second->getNumFrames())
return false;
return true;
}
unsigned int osgAnimation::UpdateActionVisitor::getLocalFrame() const
{
return _frame - _stackFrameAction.back().first;
}
void osgAnimation::UpdateActionVisitor::apply(Action& action)
{
if (isActive())
{
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 osgAnimation::UpdateActionVisitor::apply(BlendIn& action)
{
if (isActive())
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
action.computeWeight(frame);
}
}
void osgAnimation::UpdateActionVisitor::apply(BlendOut& action)
{
if (isActive())
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
action.computeWeight(frame);
}
}
void osgAnimation::UpdateActionVisitor::apply(ActionAnimation& action)
{
if (isActive())
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
action.updateAnimation(frame);
}
}
void osgAnimation::UpdateActionVisitor::apply(StripAnimation& action)
{
if (isActive())
{
unsigned int frame = getLocalFrame();
apply(static_cast<Action&>(action));
action.computeWeightAndUpdateAnimation(frame);
}
}
osgAnimation::ClearActionVisitor::ClearActionVisitor(ClearType type) : _clearType(type)
{
}
void osgAnimation::ClearActionVisitor::apply(Timeline& tm)
{
_remove.clear();
tm.traverse(*this);
for (int i = 0; i < (int)_remove.size(); i++)
tm.removeAction(_remove[i]);
}
void osgAnimation::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

@ -131,7 +131,7 @@ bool Animation::update (float time)
// 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);

View File

@ -10,6 +10,9 @@ SET(LIB_NAME osgAnimation)
SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME})
SET(LIB_PUBLIC_HEADERS
${HEADER_PATH}/Action
${HEADER_PATH}/ActionCallback
${HEADER_PATH}/ActionVisitor
${HEADER_PATH}/Animation
${HEADER_PATH}/AnimationManagerBase
${HEADER_PATH}/Assert
@ -19,6 +22,7 @@ SET(LIB_PUBLIC_HEADERS
${HEADER_PATH}/CubicBezier
${HEADER_PATH}/EaseMotion
${HEADER_PATH}/Export
${HEADER_PATH}/FrameAction
${HEADER_PATH}/Interpolator
${HEADER_PATH}/Keyframe
${HEADER_PATH}/LinkVisitor
@ -27,6 +31,8 @@ SET(LIB_PUBLIC_HEADERS
${HEADER_PATH}/Sampler
${HEADER_PATH}/Skeleton
${HEADER_PATH}/Skinning
${HEADER_PATH}/StatsVisitor
${HEADER_PATH}/StatsHandler
${HEADER_PATH}/Target
${HEADER_PATH}/Timeline
${HEADER_PATH}/TimelineAnimationManager
@ -39,6 +45,9 @@ SET(LIB_PUBLIC_HEADERS
ADD_LIBRARY(${LIB_NAME}
${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC}
${LIB_PUBLIC_HEADERS}
Action.cpp
ActionCallback.cpp
ActionVisitor.cpp
Animation.cpp
AnimationManagerBase.cpp
AnimationManager.cpp
@ -48,6 +57,8 @@ ADD_LIBRARY(${LIB_NAME}
MorphGeometry.cpp
RigGeometry.cpp
Skeleton.cpp
StatsVisitor.cpp
StatsHandler.cpp
Target.cpp
TimelineAnimationManager.cpp
Timeline.cpp

View File

@ -0,0 +1,721 @@
/* -*-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 <cmath>
#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,"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);
_group->addChild(geode);
}
return _group;
}
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++) {
//if ((*it).second.update())
(*it).second._group->setNodeMask(~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);
//_actions[name].touch();
} else {
_actions[name].setPosition(pos);
//_actions[name].touch();
}
_actions[name]._group->setNodeMask(-1);
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[0]->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);
_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);
for (int i = 0; i < (int)finder._timelines.size(); i++) {
StatsTimeline* s = new StatsTimeline;
osg::MatrixTransform* m = s->createStatsForTimeline(finder._timelines[i]);
m->setUpdateCallback(s);
_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);
_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);
_group->addChild(_graph);
}
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>
osgAnimation::StatsActionVisitor::StatsActionVisitor() {}
void osgAnimation::StatsActionVisitor::reset() { _channels.clear(); }
osgAnimation::StatsActionVisitor::StatsActionVisitor(osg::Stats* stats,unsigned int frame)
{
_frame = frame;
_stats = stats;
}
void osgAnimation::StatsActionVisitor::apply(Timeline& tm)
{
_stats->setAttribute(_frame,"Timeline", tm.getCurrentTime());
tm.traverse(*this);
}
void osgAnimation::StatsActionVisitor::apply(Action& action)
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(),0);
if (isActive())
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(),1);
}
}
void osgAnimation::StatsActionVisitor::apply(BlendIn& action)
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(),0);
if (isActive())
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getWeight());
}
}
void osgAnimation::StatsActionVisitor::apply(BlendOut& action)
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(),0);
if (isActive())
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getWeight());
}
}
void osgAnimation::StatsActionVisitor::apply(ActionAnimation& action)
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(),0);
if (isActive())
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getAnimation()->getWeight());
}
}
void osgAnimation::StatsActionVisitor::apply(StripAnimation& action)
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(),0);
if (isActive())
{
_channels.push_back(action.getName());
_stats->setAttribute(_frame,action.getName(), action.getActionAnimation()->getAnimation()->getWeight());
}
}

View File

@ -13,6 +13,7 @@
*/
#include <osgAnimation/Timeline>
#include <osgAnimation/StatsVisitor>
#include <limits.h>
using namespace osgAnimation;
@ -29,11 +30,13 @@ osgAnimation::Timeline::Timeline()
_previousFrameEvaluated = 0;
_evaluating = 0;
_numberFrame = UINT_MAX; // something like infinity
_collectStats = false;
_stats = new osg::Stats("Timeline");
setName("Timeline");
}
osgAnimation::Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, op),
_actions(nc._actions)
osgAnimation::Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : Action(nc, op),
_actions(nc._actions)
{
_lastUpdate = 0;
_currentFrame = 0;
@ -44,5 +47,200 @@ osgAnimation::Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg
_previousFrameEvaluated = 0;
_evaluating = 0;
_numberFrame = UINT_MAX; // something like infinity
_collectStats = false;
_stats = new osg::Stats("Timeline");
setName("Timeline");
}
void osgAnimation::Timeline::traverse(ActionVisitor& visitor)
{
visitor.pushTimelineOnStack(this);
// update from high priority to low priority
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
{
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();
}
void osgAnimation::Timeline::setStats(osg::Stats* stats) { _stats = stats;}
osg::Stats* osgAnimation::Timeline::getStats() { return _stats;}
void osgAnimation::Timeline::collectStats(bool state) { _collectStats = state;}
osgAnimation::StatsActionVisitor* osgAnimation::Timeline::getStatsVisitor() { return _statsVisitor; }
void osgAnimation::Timeline::clearActions()
{
_actions.clear();
_addActionOperations.clear();
_removeActionOperations.clear();
}
void osgAnimation::Timeline::update(double simulationTime)
{
// first time we call update we generate one frame
UpdateActionVisitor updateTimeline;
if (!_initFirstFrame)
{
_lastUpdate = simulationTime;
_initFirstFrame = true;
updateTimeline.setFrame(_currentFrame);
accept(updateTimeline);
if (_collectStats)
{
if (!_statsVisitor)
_statsVisitor = new osgAnimation::StatsActionVisitor();
_statsVisitor->setStats(_stats);
_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++;
updateTimeline.setFrame(_currentFrame);
accept(updateTimeline);
if (_collectStats)
{
if (!_statsVisitor)
_statsVisitor = new StatsActionVisitor;
_statsVisitor->setStats(_stats);
_statsVisitor->setFrame(_currentFrame);
_statsVisitor->reset();
accept(*_statsVisitor);
}
processPendingOperation();
}
if (nb)
{
_lastUpdate += ((double)nb) / _fps;
}
}
void osgAnimation::Timeline::removeAction(Action* action)
{
if (getEvaluating())
_removeActionOperations.push_back(FrameAction(0, action));
else
internalRemoveAction(action);
}
void osgAnimation::Timeline::addActionAt(unsigned int frame, Action* action, int priority)
{
if (getEvaluating())
_addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
else
internalAddAction(priority, FrameAction(frame, action));
}
void osgAnimation::Timeline::addActionAt(double t, Action* action, int priority)
{
unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
addActionAt(frame, action, priority);
}
void osgAnimation::Timeline::addActionNow(Action* action, int priority)
{
addActionAt(getCurrentFrame(), action, priority);
}
void osgAnimation::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 osgAnimation::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 osgAnimation::Timeline::internalAddAction(int priority, const FrameAction& ftl)
{
_actions[priority].insert(_actions[priority].begin(), ftl);
// _actions[priority].push_back(ftl);
}
#if 0
void osgAnimation::Timeline::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();
}
#endif
bool osgAnimation::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;
}