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:
parent
b2943aa50a
commit
c4c5ca7566
208
include/osgAnimation/Action
Normal file
208
include/osgAnimation/Action
Normal 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
|
37
include/osgAnimation/ActionCallback
Normal file
37
include/osgAnimation/ActionCallback
Normal 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
|
110
include/osgAnimation/ActionVisitor
Normal file
110
include/osgAnimation/ActionVisitor
Normal 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
|
@ -1,5 +1,5 @@
|
|||||||
/* -*-c++-*-
|
/* -*-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
|
* 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
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||||
@ -110,7 +110,7 @@ namespace osgAnimation
|
|||||||
_scale = new osgAnimation::Vec3Target;
|
_scale = new osgAnimation::Vec3Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(osgAnimation::Bone& bone)
|
void update(osgAnimation::Bone& bone)
|
||||||
{
|
{
|
||||||
bone.setTranslation(_position->getValue());
|
bone.setTranslation(_position->getValue());
|
||||||
bone.setRotation(_quaternion->getValue());
|
bone.setRotation(_quaternion->getValue());
|
||||||
@ -126,25 +126,25 @@ namespace osgAnimation
|
|||||||
|
|
||||||
bool link(osgAnimation::Channel* channel)
|
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);
|
osgAnimation::QuatSphericalLinearChannel* qc = dynamic_cast<osgAnimation::QuatSphericalLinearChannel*>(channel);
|
||||||
if (qc)
|
if (qc)
|
||||||
{
|
{
|
||||||
qc->setTarget(_quaternion.get());
|
qc->setTarget(_quaternion.get());
|
||||||
return true;
|
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);
|
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
|
||||||
if (vc)
|
if (vc)
|
||||||
{
|
{
|
||||||
vc->setTarget(_position.get());
|
vc->setTarget(_position.get());
|
||||||
return true;
|
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);
|
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
|
||||||
if (vc)
|
if (vc)
|
||||||
@ -152,7 +152,7 @@ namespace osgAnimation
|
|||||||
vc->setTarget(_scale.get());
|
vc->setTarget(_scale.get());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
|
std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
|
||||||
|
26
include/osgAnimation/FrameAction
Normal file
26
include/osgAnimation/FrameAction
Normal 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
|
@ -89,7 +89,7 @@ namespace osgAnimation
|
|||||||
RigGeometry* geom = dynamic_cast<RigGeometry*>(drw);
|
RigGeometry* geom = dynamic_cast<RigGeometry*>(drw);
|
||||||
if (!geom)
|
if (!geom)
|
||||||
return;
|
return;
|
||||||
if (!geom->getSkeleton() && !geom->getParents().empty())
|
if (!geom->getSkeleton() && !geom->getParents().empty())
|
||||||
{
|
{
|
||||||
FindNearestParentSkeleton finder;
|
FindNearestParentSkeleton finder;
|
||||||
if (geom->getParents().size() > 1)
|
if (geom->getParents().size() > 1)
|
||||||
|
115
include/osgAnimation/StatsHandler
Normal file
115
include/osgAnimation/StatsHandler
Normal 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
|
53
include/osgAnimation/StatsVisitor
Normal file
53
include/osgAnimation/StatsVisitor
Normal 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
|
@ -1,5 +1,5 @@
|
|||||||
/* -*-c++-*-
|
/* -*-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
|
* 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
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||||
@ -67,7 +67,7 @@ namespace osgAnimation
|
|||||||
}
|
}
|
||||||
const T& getValue() const { return _target;}
|
const T& getValue() const { return _target;}
|
||||||
|
|
||||||
void normalize()
|
void normalize()
|
||||||
{
|
{
|
||||||
float weightSummed = getWeight();
|
float weightSummed = getWeight();
|
||||||
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1) < 1e-4)
|
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1) < 1e-4)
|
||||||
@ -91,6 +91,7 @@ namespace osgAnimation
|
|||||||
|
|
||||||
TemplateTarget () {}
|
TemplateTarget () {}
|
||||||
TemplateTarget (const osg::Quat& q) { setValue(q); }
|
TemplateTarget (const osg::Quat& q) { setValue(q); }
|
||||||
|
|
||||||
const osg::Quat& getValue() const { return _target;}
|
const osg::Quat& getValue() const { return _target;}
|
||||||
void update(float weight, const osg::Quat& val)
|
void update(float weight, const osg::Quat& val)
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* -*-c++-*-
|
/* -*-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
|
* 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
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||||
@ -16,161 +16,27 @@
|
|||||||
#define OSGANIMATION_TIMELINE_H
|
#define OSGANIMATION_TIMELINE_H
|
||||||
|
|
||||||
#include <osgAnimation/Export>
|
#include <osgAnimation/Export>
|
||||||
#include <osg/Object>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <osg/Notify>
|
#include <osg/Notify>
|
||||||
#include <osg/Group>
|
#include <osg/Stats>
|
||||||
#include <osgAnimation/Animation>
|
#include <osgAnimation/Action>
|
||||||
|
#include <osgAnimation/FrameAction>
|
||||||
#include <osgAnimation/AnimationManagerBase>
|
#include <osgAnimation/AnimationManagerBase>
|
||||||
|
|
||||||
namespace osgAnimation
|
namespace osgAnimation
|
||||||
{
|
{
|
||||||
|
class StatsActionVisitor;
|
||||||
|
|
||||||
class Action : public osg::Object
|
class OSGANIMATION_EXPORT Timeline : public Action //osg::Object
|
||||||
{
|
{
|
||||||
public:
|
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();
|
||||||
Timeline(const Timeline& nc,const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY);
|
Timeline(const Timeline& nc,const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY);
|
||||||
|
|
||||||
|
META_Action(osgAnimation, Timeline);
|
||||||
|
|
||||||
enum TimelineStatus
|
enum TimelineStatus
|
||||||
{
|
{
|
||||||
Play,
|
Play,
|
||||||
@ -179,14 +45,10 @@ namespace osgAnimation
|
|||||||
|
|
||||||
TimelineStatus getStatus() const { return _state; }
|
TimelineStatus getStatus() const { return _state; }
|
||||||
|
|
||||||
typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
|
|
||||||
typedef std::vector<FrameAction> ActionList;
|
typedef std::vector<FrameAction> ActionList;
|
||||||
typedef std::map<int, ActionList> ActionLayers;
|
typedef std::map<int, ActionList> ActionLayers;
|
||||||
|
|
||||||
const ActionList& getActionLayer(int i)
|
const ActionList& getActionLayer(int i) { return _actions[i];}
|
||||||
{
|
|
||||||
return _actions[i];
|
|
||||||
}
|
|
||||||
unsigned int getCurrentFrame() const { return _currentFrame;}
|
unsigned int getCurrentFrame() const { return _currentFrame;}
|
||||||
double getCurrentTime() const { return _currentFrame * 1.0 / _fps;}
|
double getCurrentTime() const { return _currentFrame * 1.0 / _fps;}
|
||||||
|
|
||||||
@ -195,139 +57,44 @@ namespace osgAnimation
|
|||||||
void stop() { _state = Stop; }
|
void stop() { _state = Stop; }
|
||||||
bool getEvaluating() const { return _evaluating;}
|
bool getEvaluating() const { return _evaluating;}
|
||||||
|
|
||||||
bool isActive(Action* activeAction)
|
bool isActive(Action* activeAction);
|
||||||
{
|
|
||||||
// update from high priority to low priority
|
|
||||||
for( ActionLayers::iterator iterAnim = _actions.begin(); iterAnim != _actions.end(); ++iterAnim )
|
|
||||||
{
|
|
||||||
// update all animation
|
|
||||||
ActionList& list = iterAnim->second;
|
|
||||||
for (unsigned int i = 0; i < list.size(); i++)
|
|
||||||
{
|
|
||||||
Action* action = list[i].second.get();
|
|
||||||
if (action == activeAction)
|
|
||||||
{
|
|
||||||
unsigned int firstFrame = list[i].first;
|
|
||||||
// check if current frame of timeline hit an action interval
|
|
||||||
if (_currentFrame >= firstFrame &&
|
|
||||||
_currentFrame < (firstFrame + action->getNumFrames()) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeAction(Action* action)
|
void removeAction(Action* action);
|
||||||
{
|
virtual void addActionAt(unsigned int frame, Action* action, int priority = 0);
|
||||||
if (getEvaluating())
|
virtual void addActionAt(double t, Action* action, int priority = 0);
|
||||||
_removeActionOperations.push_back(FrameAction(0, action));
|
void addActionNow(Action* action, int priority = 0);
|
||||||
else
|
|
||||||
internalRemoveAction(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void addActionAt(unsigned int frame, Action* action, int priority = 0)
|
void clearActions();
|
||||||
{
|
|
||||||
if (getEvaluating())
|
|
||||||
_addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
|
|
||||||
else
|
|
||||||
internalAddAction(priority, FrameAction(frame, action));
|
|
||||||
}
|
|
||||||
virtual void addActionAt(double t, Action* action, int priority = 0)
|
|
||||||
{
|
|
||||||
unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
|
|
||||||
addActionAt(frame, action, priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void evaluate(unsigned int frame)
|
virtual void update(double simulationTime);
|
||||||
{
|
void setLastFrameEvaluated(unsigned int frame) { _previousFrameEvaluated = frame; }
|
||||||
setEvaluating(true);
|
|
||||||
osg::notify(osg::DEBUG_INFO) << getName() << " evaluate frame " << _currentFrame << std::endl;
|
|
||||||
|
|
||||||
// update from high priority to low priority
|
void setEvaluating(bool state) { _evaluating = state;}
|
||||||
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
|
void traverse(ActionVisitor& visitor);
|
||||||
{
|
|
||||||
// update all animation
|
|
||||||
ActionList& list = iterAnim->second;
|
|
||||||
for (unsigned int i = 0; i < list.size(); i++)
|
|
||||||
{
|
|
||||||
unsigned int firstFrame = list[i].first;
|
|
||||||
Action* action = list[i].second.get();
|
|
||||||
// check if current frame of timeline hit an action interval
|
|
||||||
if (frame >= firstFrame &&
|
|
||||||
frame < (firstFrame + action->getNumFrames()) )
|
|
||||||
action->evaluate(frame - firstFrame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setEvaluating(false);
|
|
||||||
|
|
||||||
// evaluate callback after updating all animation
|
void setStats(osg::Stats* stats);
|
||||||
evaluateCallback(frame);
|
osg::Stats* getStats();
|
||||||
_previousFrameEvaluated = frame;
|
void collectStats(bool state);
|
||||||
}
|
osgAnimation::StatsActionVisitor* getStatsVisitor();
|
||||||
|
|
||||||
virtual void evaluateCallback(unsigned int frame)
|
const ActionLayers& getActionLayers() const { return _actions; }
|
||||||
{
|
|
||||||
// update from high priority to low priority
|
|
||||||
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
|
|
||||||
{
|
|
||||||
// update all animation
|
|
||||||
ActionList& list = iterAnim->second;
|
|
||||||
for (unsigned int i = 0; i < list.size(); i++)
|
|
||||||
{
|
|
||||||
unsigned int firstFrame = list[i].first;
|
|
||||||
Action* action = list[i].second.get();
|
|
||||||
// check if current frame of timeline hit an action interval
|
|
||||||
if (frame >= firstFrame &&
|
|
||||||
frame < (firstFrame + action->getNumFrames()) )
|
|
||||||
action->evaluateCallback(frame - firstFrame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
processPendingOperation();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void update(double simulationTime)
|
void processPendingOperation();
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
||||||
ActionLayers _actions;
|
ActionLayers _actions;
|
||||||
double _lastUpdate;
|
double _lastUpdate;
|
||||||
double _speed;
|
double _speed;
|
||||||
unsigned int _currentFrame;
|
unsigned int _currentFrame;
|
||||||
unsigned int _fps;
|
|
||||||
unsigned int _numberFrame;
|
|
||||||
unsigned int _previousFrameEvaluated;
|
unsigned int _previousFrameEvaluated;
|
||||||
bool _loop;
|
|
||||||
bool _initFirstFrame;
|
bool _initFirstFrame;
|
||||||
|
|
||||||
TimelineStatus _state;
|
TimelineStatus _state;
|
||||||
|
|
||||||
|
bool _collectStats;
|
||||||
|
osg::ref_ptr<osg::Stats> _stats;
|
||||||
|
osg::ref_ptr<osgAnimation::StatsActionVisitor> _statsVisitor;
|
||||||
|
|
||||||
// to manage pending operation
|
// to manage pending operation
|
||||||
bool _evaluating;
|
bool _evaluating;
|
||||||
|
|
||||||
@ -343,199 +110,13 @@ namespace osgAnimation
|
|||||||
CommandList _addActionOperations;
|
CommandList _addActionOperations;
|
||||||
ActionList _removeActionOperations;
|
ActionList _removeActionOperations;
|
||||||
|
|
||||||
void setEvaluating(bool state) { _evaluating = state;}
|
void internalRemoveAction(Action* action);
|
||||||
void processPendingOperation()
|
void internalAddAction(int priority, const FrameAction& ftl);
|
||||||
{
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 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
|
#endif
|
||||||
|
201
src/osgAnimation/Action.cpp
Normal file
201
src/osgAnimation/Action.cpp
Normal 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);
|
||||||
|
}
|
23
src/osgAnimation/ActionCallback.cpp
Normal file
23
src/osgAnimation/ActionCallback.cpp
Normal 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());
|
||||||
|
}
|
||||||
|
|
164
src/osgAnimation/ActionVisitor.cpp
Normal file
164
src/osgAnimation/ActionVisitor.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -131,7 +131,7 @@ bool Animation::update (float time)
|
|||||||
// std::cout << "t " << t << " / " << _duration << std::endl;
|
// std::cout << "t " << t << " / " << _duration << std::endl;
|
||||||
|
|
||||||
ChannelList::const_iterator chan;
|
ChannelList::const_iterator chan;
|
||||||
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
|
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
|
||||||
{
|
{
|
||||||
(*chan)->setWeight(_weight);
|
(*chan)->setWeight(_weight);
|
||||||
(*chan)->update(t);
|
(*chan)->update(t);
|
||||||
|
@ -10,6 +10,9 @@ SET(LIB_NAME osgAnimation)
|
|||||||
|
|
||||||
SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME})
|
SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME})
|
||||||
SET(LIB_PUBLIC_HEADERS
|
SET(LIB_PUBLIC_HEADERS
|
||||||
|
${HEADER_PATH}/Action
|
||||||
|
${HEADER_PATH}/ActionCallback
|
||||||
|
${HEADER_PATH}/ActionVisitor
|
||||||
${HEADER_PATH}/Animation
|
${HEADER_PATH}/Animation
|
||||||
${HEADER_PATH}/AnimationManagerBase
|
${HEADER_PATH}/AnimationManagerBase
|
||||||
${HEADER_PATH}/Assert
|
${HEADER_PATH}/Assert
|
||||||
@ -19,6 +22,7 @@ SET(LIB_PUBLIC_HEADERS
|
|||||||
${HEADER_PATH}/CubicBezier
|
${HEADER_PATH}/CubicBezier
|
||||||
${HEADER_PATH}/EaseMotion
|
${HEADER_PATH}/EaseMotion
|
||||||
${HEADER_PATH}/Export
|
${HEADER_PATH}/Export
|
||||||
|
${HEADER_PATH}/FrameAction
|
||||||
${HEADER_PATH}/Interpolator
|
${HEADER_PATH}/Interpolator
|
||||||
${HEADER_PATH}/Keyframe
|
${HEADER_PATH}/Keyframe
|
||||||
${HEADER_PATH}/LinkVisitor
|
${HEADER_PATH}/LinkVisitor
|
||||||
@ -27,6 +31,8 @@ SET(LIB_PUBLIC_HEADERS
|
|||||||
${HEADER_PATH}/Sampler
|
${HEADER_PATH}/Sampler
|
||||||
${HEADER_PATH}/Skeleton
|
${HEADER_PATH}/Skeleton
|
||||||
${HEADER_PATH}/Skinning
|
${HEADER_PATH}/Skinning
|
||||||
|
${HEADER_PATH}/StatsVisitor
|
||||||
|
${HEADER_PATH}/StatsHandler
|
||||||
${HEADER_PATH}/Target
|
${HEADER_PATH}/Target
|
||||||
${HEADER_PATH}/Timeline
|
${HEADER_PATH}/Timeline
|
||||||
${HEADER_PATH}/TimelineAnimationManager
|
${HEADER_PATH}/TimelineAnimationManager
|
||||||
@ -39,6 +45,9 @@ SET(LIB_PUBLIC_HEADERS
|
|||||||
ADD_LIBRARY(${LIB_NAME}
|
ADD_LIBRARY(${LIB_NAME}
|
||||||
${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC}
|
${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC}
|
||||||
${LIB_PUBLIC_HEADERS}
|
${LIB_PUBLIC_HEADERS}
|
||||||
|
Action.cpp
|
||||||
|
ActionCallback.cpp
|
||||||
|
ActionVisitor.cpp
|
||||||
Animation.cpp
|
Animation.cpp
|
||||||
AnimationManagerBase.cpp
|
AnimationManagerBase.cpp
|
||||||
AnimationManager.cpp
|
AnimationManager.cpp
|
||||||
@ -48,6 +57,8 @@ ADD_LIBRARY(${LIB_NAME}
|
|||||||
MorphGeometry.cpp
|
MorphGeometry.cpp
|
||||||
RigGeometry.cpp
|
RigGeometry.cpp
|
||||||
Skeleton.cpp
|
Skeleton.cpp
|
||||||
|
StatsVisitor.cpp
|
||||||
|
StatsHandler.cpp
|
||||||
Target.cpp
|
Target.cpp
|
||||||
TimelineAnimationManager.cpp
|
TimelineAnimationManager.cpp
|
||||||
Timeline.cpp
|
Timeline.cpp
|
||||||
|
721
src/osgAnimation/StatsHandler.cpp
Normal file
721
src/osgAnimation/StatsHandler.cpp
Normal 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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
86
src/osgAnimation/StatsVisitor.cpp
Normal file
86
src/osgAnimation/StatsVisitor.cpp
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
@ -13,6 +13,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <osgAnimation/Timeline>
|
#include <osgAnimation/Timeline>
|
||||||
|
#include <osgAnimation/StatsVisitor>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
using namespace osgAnimation;
|
using namespace osgAnimation;
|
||||||
@ -29,11 +30,13 @@ osgAnimation::Timeline::Timeline()
|
|||||||
_previousFrameEvaluated = 0;
|
_previousFrameEvaluated = 0;
|
||||||
_evaluating = 0;
|
_evaluating = 0;
|
||||||
_numberFrame = UINT_MAX; // something like infinity
|
_numberFrame = UINT_MAX; // something like infinity
|
||||||
|
_collectStats = false;
|
||||||
|
_stats = new osg::Stats("Timeline");
|
||||||
setName("Timeline");
|
setName("Timeline");
|
||||||
}
|
}
|
||||||
|
|
||||||
osgAnimation::Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, op),
|
osgAnimation::Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : Action(nc, op),
|
||||||
_actions(nc._actions)
|
_actions(nc._actions)
|
||||||
{
|
{
|
||||||
_lastUpdate = 0;
|
_lastUpdate = 0;
|
||||||
_currentFrame = 0;
|
_currentFrame = 0;
|
||||||
@ -44,5 +47,200 @@ osgAnimation::Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg
|
|||||||
_previousFrameEvaluated = 0;
|
_previousFrameEvaluated = 0;
|
||||||
_evaluating = 0;
|
_evaluating = 0;
|
||||||
_numberFrame = UINT_MAX; // something like infinity
|
_numberFrame = UINT_MAX; // something like infinity
|
||||||
|
_collectStats = false;
|
||||||
|
_stats = new osg::Stats("Timeline");
|
||||||
setName("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;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user