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++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
@ -110,7 +110,7 @@ namespace osgAnimation
|
||||
_scale = new osgAnimation::Vec3Target;
|
||||
}
|
||||
|
||||
void update(osgAnimation::Bone& bone)
|
||||
void update(osgAnimation::Bone& bone)
|
||||
{
|
||||
bone.setTranslation(_position->getValue());
|
||||
bone.setRotation(_quaternion->getValue());
|
||||
@ -126,25 +126,25 @@ namespace osgAnimation
|
||||
|
||||
bool link(osgAnimation::Channel* channel)
|
||||
{
|
||||
if (channel->getName().find("quaternion") != std::string::npos)
|
||||
if (channel->getName().find("quaternion") != std::string::npos)
|
||||
{
|
||||
osgAnimation::QuatSphericalLinearChannel* qc = dynamic_cast<osgAnimation::QuatSphericalLinearChannel*>(channel);
|
||||
if (qc)
|
||||
if (qc)
|
||||
{
|
||||
qc->setTarget(_quaternion.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (channel->getName().find("position") != std::string::npos)
|
||||
else if (channel->getName().find("position") != std::string::npos)
|
||||
{
|
||||
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
|
||||
if (vc)
|
||||
if (vc)
|
||||
{
|
||||
vc->setTarget(_position.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (channel->getName().find("scale") != std::string::npos)
|
||||
}
|
||||
else if (channel->getName().find("scale") != std::string::npos)
|
||||
{
|
||||
osgAnimation::Vec3LinearChannel* vc = dynamic_cast<osgAnimation::Vec3LinearChannel*>(channel);
|
||||
if (vc)
|
||||
@ -152,7 +152,7 @@ namespace osgAnimation
|
||||
vc->setTarget(_scale.get());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl;
|
||||
|
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);
|
||||
if (!geom)
|
||||
return;
|
||||
if (!geom->getSkeleton() && !geom->getParents().empty())
|
||||
if (!geom->getSkeleton() && !geom->getParents().empty())
|
||||
{
|
||||
FindNearestParentSkeleton finder;
|
||||
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++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
@ -67,7 +67,7 @@ namespace osgAnimation
|
||||
}
|
||||
const T& getValue() const { return _target;}
|
||||
|
||||
void normalize()
|
||||
void normalize()
|
||||
{
|
||||
float weightSummed = getWeight();
|
||||
if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1) < 1e-4)
|
||||
@ -91,6 +91,7 @@ namespace osgAnimation
|
||||
|
||||
TemplateTarget () {}
|
||||
TemplateTarget (const osg::Quat& q) { setValue(q); }
|
||||
|
||||
const osg::Quat& getValue() const { return _target;}
|
||||
void update(float weight, const osg::Quat& val)
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* -*-c++-*-
|
||||
* Copyright (C) 2008 Cedric Pinson <mornifle@plopbyte.net>
|
||||
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
@ -16,161 +16,27 @@
|
||||
#define OSGANIMATION_TIMELINE_H
|
||||
|
||||
#include <osgAnimation/Export>
|
||||
#include <osg/Object>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <osg/Notify>
|
||||
#include <osg/Group>
|
||||
#include <osgAnimation/Animation>
|
||||
#include <osg/Stats>
|
||||
#include <osgAnimation/Action>
|
||||
#include <osgAnimation/FrameAction>
|
||||
#include <osgAnimation/AnimationManagerBase>
|
||||
|
||||
namespace osgAnimation
|
||||
{
|
||||
class StatsActionVisitor;
|
||||
|
||||
class Action : public osg::Object
|
||||
class OSGANIMATION_EXPORT Timeline : public Action //osg::Object
|
||||
{
|
||||
public:
|
||||
|
||||
class Callback : public osg::Object
|
||||
{
|
||||
public:
|
||||
Callback(){}
|
||||
Callback(const Callback&,const osg::CopyOp&) {}
|
||||
|
||||
META_Object(osgAnimation,Callback);
|
||||
|
||||
virtual void operator()(Action* /*action*/) {}
|
||||
|
||||
void addNestedCallback(Callback* callback)
|
||||
{
|
||||
if (_nested.valid())
|
||||
_nested->addNestedCallback(callback);
|
||||
else
|
||||
_nested = callback;
|
||||
}
|
||||
|
||||
protected:
|
||||
osg::ref_ptr<Callback> _nested;
|
||||
};
|
||||
|
||||
|
||||
typedef std::map<unsigned int, osg::ref_ptr<Callback> > FrameCallback;
|
||||
|
||||
META_Object(osgAnimation, Action);
|
||||
|
||||
Action()
|
||||
{
|
||||
_numberFrame = 25;
|
||||
_fps = 25;
|
||||
_speed = 1.0;
|
||||
_loop = 1;
|
||||
}
|
||||
|
||||
Action(const Action&,const osg::CopyOp&) {}
|
||||
|
||||
void setCallback(double when, Callback* callback)
|
||||
{
|
||||
setCallback(static_cast<unsigned int>(floor(when*_fps)), callback);
|
||||
}
|
||||
|
||||
void setCallback(unsigned int frame, Callback* callback)
|
||||
{
|
||||
if (_framesCallback[frame].valid())
|
||||
_framesCallback[frame]->addNestedCallback(callback);
|
||||
else
|
||||
_framesCallback[frame] = callback;
|
||||
}
|
||||
Callback* getCallback(unsigned int frame)
|
||||
{
|
||||
if (_framesCallback.find(frame) == _framesCallback.end())
|
||||
return 0;
|
||||
return _framesCallback[frame].get();
|
||||
}
|
||||
|
||||
void setNumFrames(unsigned int numFrames) { _numberFrame = numFrames;}
|
||||
void setDuration(double duration) { _numberFrame = static_cast<unsigned int>(floor(duration * _fps)); }
|
||||
|
||||
unsigned int getNumFrames() const { return _numberFrame;}
|
||||
double getDuration() const { return _numberFrame * 1.0 / _fps; }
|
||||
|
||||
// 0 means infini else it's the number of loop
|
||||
virtual void setLoop(int nb) { _loop = nb; }
|
||||
virtual unsigned int getLoop() const { return _loop;}
|
||||
|
||||
// get the number of loop, the frame relative to loop.
|
||||
// return true if in range, and false if out of range.
|
||||
bool evaluateFrame(unsigned int frame, unsigned int& resultframe, unsigned int& nbloop )
|
||||
{
|
||||
nbloop = frame / getNumFrames();
|
||||
resultframe = frame;
|
||||
|
||||
if (frame > getNumFrames()-1)
|
||||
{
|
||||
if (!getLoop())
|
||||
resultframe = frame % getNumFrames();
|
||||
else
|
||||
{
|
||||
if (nbloop >= getLoop())
|
||||
return false;
|
||||
else
|
||||
resultframe = frame % getNumFrames();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void evaluate(unsigned int frame)
|
||||
{
|
||||
unsigned int frameInAction;
|
||||
unsigned int loopDone;
|
||||
if (!evaluateFrame(frame, frameInAction, loopDone))
|
||||
osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " << frameInAction << " finished" << std::endl;
|
||||
else
|
||||
osg::notify(osg::DEBUG_INFO) << getName() << " Action frame " << frame << " relative to loop " << frameInAction << " no loop " << loopDone<< std::endl;
|
||||
}
|
||||
|
||||
virtual void evaluateCallback(unsigned int frame)
|
||||
{
|
||||
unsigned int frameInAction;
|
||||
unsigned int loopDone;
|
||||
if (!evaluateFrame(frame, frameInAction, loopDone))
|
||||
return;
|
||||
|
||||
frame = frameInAction;
|
||||
if (_framesCallback.find(frame) != _framesCallback.end())
|
||||
{
|
||||
std::cout << getName() << " evaluate callback " << _framesCallback[frame]->getName() << " at " << frame << std::endl;
|
||||
(*_framesCallback[frame])(this);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
FrameCallback _framesCallback;
|
||||
|
||||
double _speed;
|
||||
unsigned int _fps;
|
||||
unsigned int _numberFrame;
|
||||
unsigned int _loop;
|
||||
|
||||
enum ActionStatus
|
||||
{
|
||||
Play,
|
||||
Stop
|
||||
};
|
||||
|
||||
ActionStatus _state;
|
||||
};
|
||||
|
||||
|
||||
class OSGANIMATION_EXPORT Timeline : public osg::Object
|
||||
{
|
||||
public:
|
||||
|
||||
META_Object(osgAnimation, Timeline);
|
||||
|
||||
Timeline();
|
||||
Timeline(const Timeline& nc,const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY);
|
||||
|
||||
META_Action(osgAnimation, Timeline);
|
||||
|
||||
enum TimelineStatus
|
||||
{
|
||||
Play,
|
||||
@ -179,14 +45,10 @@ namespace osgAnimation
|
||||
|
||||
TimelineStatus getStatus() const { return _state; }
|
||||
|
||||
typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
|
||||
typedef std::vector<FrameAction> ActionList;
|
||||
typedef std::map<int, ActionList> ActionLayers;
|
||||
|
||||
const ActionList& getActionLayer(int i)
|
||||
{
|
||||
return _actions[i];
|
||||
}
|
||||
const ActionList& getActionLayer(int i) { return _actions[i];}
|
||||
unsigned int getCurrentFrame() const { return _currentFrame;}
|
||||
double getCurrentTime() const { return _currentFrame * 1.0 / _fps;}
|
||||
|
||||
@ -195,139 +57,44 @@ namespace osgAnimation
|
||||
void stop() { _state = Stop; }
|
||||
bool getEvaluating() const { return _evaluating;}
|
||||
|
||||
bool isActive(Action* activeAction)
|
||||
{
|
||||
// update from high priority to low priority
|
||||
for( ActionLayers::iterator iterAnim = _actions.begin(); iterAnim != _actions.end(); ++iterAnim )
|
||||
{
|
||||
// update all animation
|
||||
ActionList& list = iterAnim->second;
|
||||
for (unsigned int i = 0; i < list.size(); i++)
|
||||
{
|
||||
Action* action = list[i].second.get();
|
||||
if (action == activeAction)
|
||||
{
|
||||
unsigned int firstFrame = list[i].first;
|
||||
// check if current frame of timeline hit an action interval
|
||||
if (_currentFrame >= firstFrame &&
|
||||
_currentFrame < (firstFrame + action->getNumFrames()) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool isActive(Action* activeAction);
|
||||
|
||||
void removeAction(Action* action)
|
||||
{
|
||||
if (getEvaluating())
|
||||
_removeActionOperations.push_back(FrameAction(0, action));
|
||||
else
|
||||
internalRemoveAction(action);
|
||||
}
|
||||
void removeAction(Action* action);
|
||||
virtual void addActionAt(unsigned int frame, Action* action, int priority = 0);
|
||||
virtual void addActionAt(double t, Action* action, int priority = 0);
|
||||
void addActionNow(Action* action, int priority = 0);
|
||||
|
||||
virtual void addActionAt(unsigned int frame, Action* action, int priority = 0)
|
||||
{
|
||||
if (getEvaluating())
|
||||
_addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
|
||||
else
|
||||
internalAddAction(priority, FrameAction(frame, action));
|
||||
}
|
||||
virtual void addActionAt(double t, Action* action, int priority = 0)
|
||||
{
|
||||
unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
|
||||
addActionAt(frame, action, priority);
|
||||
}
|
||||
void clearActions();
|
||||
|
||||
virtual void evaluate(unsigned int frame)
|
||||
{
|
||||
setEvaluating(true);
|
||||
osg::notify(osg::DEBUG_INFO) << getName() << " evaluate frame " << _currentFrame << std::endl;
|
||||
virtual void update(double simulationTime);
|
||||
void setLastFrameEvaluated(unsigned int frame) { _previousFrameEvaluated = frame; }
|
||||
|
||||
// update from high priority to low priority
|
||||
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
|
||||
{
|
||||
// update all animation
|
||||
ActionList& list = iterAnim->second;
|
||||
for (unsigned int i = 0; i < list.size(); i++)
|
||||
{
|
||||
unsigned int firstFrame = list[i].first;
|
||||
Action* action = list[i].second.get();
|
||||
// check if current frame of timeline hit an action interval
|
||||
if (frame >= firstFrame &&
|
||||
frame < (firstFrame + action->getNumFrames()) )
|
||||
action->evaluate(frame - firstFrame);
|
||||
}
|
||||
}
|
||||
setEvaluating(false);
|
||||
void setEvaluating(bool state) { _evaluating = state;}
|
||||
void traverse(ActionVisitor& visitor);
|
||||
|
||||
// evaluate callback after updating all animation
|
||||
evaluateCallback(frame);
|
||||
_previousFrameEvaluated = frame;
|
||||
}
|
||||
void setStats(osg::Stats* stats);
|
||||
osg::Stats* getStats();
|
||||
void collectStats(bool state);
|
||||
osgAnimation::StatsActionVisitor* getStatsVisitor();
|
||||
|
||||
virtual void evaluateCallback(unsigned int frame)
|
||||
{
|
||||
// update from high priority to low priority
|
||||
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
|
||||
{
|
||||
// update all animation
|
||||
ActionList& list = iterAnim->second;
|
||||
for (unsigned int i = 0; i < list.size(); i++)
|
||||
{
|
||||
unsigned int firstFrame = list[i].first;
|
||||
Action* action = list[i].second.get();
|
||||
// check if current frame of timeline hit an action interval
|
||||
if (frame >= firstFrame &&
|
||||
frame < (firstFrame + action->getNumFrames()) )
|
||||
action->evaluateCallback(frame - firstFrame);
|
||||
}
|
||||
}
|
||||
processPendingOperation();
|
||||
}
|
||||
const ActionLayers& getActionLayers() const { return _actions; }
|
||||
|
||||
virtual void update(double simulationTime)
|
||||
{
|
||||
// first time we call update we generate one frame
|
||||
if (!_initFirstFrame)
|
||||
{
|
||||
_lastUpdate = simulationTime;
|
||||
_initFirstFrame = true;
|
||||
evaluate(_currentFrame);
|
||||
}
|
||||
|
||||
// find the number of frame pass since the last update
|
||||
double delta = (simulationTime - _lastUpdate);
|
||||
double nbframes = delta * _fps * _speed;
|
||||
unsigned int nb = static_cast<unsigned int>(floor(nbframes));
|
||||
|
||||
for (unsigned int i = 0; i < nb; i++)
|
||||
{
|
||||
if (_state == Play)
|
||||
_currentFrame++;
|
||||
evaluate(_currentFrame);
|
||||
}
|
||||
if (nb)
|
||||
{
|
||||
_lastUpdate += ((double)nb) / _fps;
|
||||
}
|
||||
}
|
||||
void processPendingOperation();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
ActionLayers _actions;
|
||||
double _lastUpdate;
|
||||
double _speed;
|
||||
unsigned int _currentFrame;
|
||||
unsigned int _fps;
|
||||
unsigned int _numberFrame;
|
||||
unsigned int _previousFrameEvaluated;
|
||||
bool _loop;
|
||||
bool _initFirstFrame;
|
||||
|
||||
TimelineStatus _state;
|
||||
|
||||
bool _collectStats;
|
||||
osg::ref_ptr<osg::Stats> _stats;
|
||||
osg::ref_ptr<osgAnimation::StatsActionVisitor> _statsVisitor;
|
||||
|
||||
// to manage pending operation
|
||||
bool _evaluating;
|
||||
|
||||
@ -343,199 +110,13 @@ namespace osgAnimation
|
||||
CommandList _addActionOperations;
|
||||
ActionList _removeActionOperations;
|
||||
|
||||
void setEvaluating(bool state) { _evaluating = state;}
|
||||
void processPendingOperation()
|
||||
{
|
||||
// process all pending add action operation
|
||||
while( !_addActionOperations.empty())
|
||||
{
|
||||
internalAddAction(_addActionOperations.back()._priority, _addActionOperations.back()._action);
|
||||
_addActionOperations.pop_back();
|
||||
}
|
||||
|
||||
// process all pending remove action operation
|
||||
while( !_removeActionOperations.empty())
|
||||
{
|
||||
internalRemoveAction(_removeActionOperations.back().second.get());
|
||||
_removeActionOperations.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void internalRemoveAction(Action* action)
|
||||
{
|
||||
for (ActionLayers::iterator it = _actions.begin(); it != _actions.end(); it++)
|
||||
{
|
||||
ActionList& fa = it->second;
|
||||
for (unsigned int i = 0; i < fa.size(); i++)
|
||||
if (fa[i].second.get() == action)
|
||||
{
|
||||
fa.erase(fa.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
void internalAddAction(int priority, const FrameAction& ftl)
|
||||
{
|
||||
_actions[priority].push_back(ftl);
|
||||
}
|
||||
void internalRemoveAction(Action* action);
|
||||
void internalAddAction(int priority, const FrameAction& ftl);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// blend in from 0 to weight in duration
|
||||
class BlendIn : public Action
|
||||
{
|
||||
double _weight;
|
||||
osg::ref_ptr<Animation> _animation;
|
||||
|
||||
public:
|
||||
BlendIn(Animation* animation, double duration, double weight)
|
||||
{
|
||||
_animation = animation;
|
||||
_weight = weight;
|
||||
float d = duration * _fps;
|
||||
setNumFrames(static_cast<unsigned int>(floor(d)) + 1);
|
||||
setName("BlendIn");
|
||||
}
|
||||
double getWeight() const { return _weight;}
|
||||
virtual void evaluate(unsigned int frame)
|
||||
{
|
||||
Action::evaluate(frame);
|
||||
// frame + 1 because the start is 0 and we want to start the blend in at the first
|
||||
// frame.
|
||||
double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
|
||||
double w = _weight;
|
||||
if (frame < getNumFrames() -1 ) // the last frame we set the target weight the user asked
|
||||
w = _weight * ratio;
|
||||
_animation->setWeight(w);
|
||||
}
|
||||
};
|
||||
|
||||
// blend in from 0 to weight in duration
|
||||
class BlendOut : public Action
|
||||
{
|
||||
double _weight;
|
||||
osg::ref_ptr<Animation> _animation;
|
||||
public:
|
||||
BlendOut(Animation* animation, double duration)
|
||||
{
|
||||
_animation = animation;
|
||||
float d = duration * _fps;
|
||||
setNumFrames(static_cast<unsigned int>(floor(d) + 1));
|
||||
_weight = 1.0;
|
||||
setName("BlendOut");
|
||||
}
|
||||
double getWeight() const { return _weight;}
|
||||
virtual void evaluate(unsigned int frame)
|
||||
{
|
||||
Action::evaluate(frame);
|
||||
// frame + 1 because the start is 0 and we want to start the blend in at the first
|
||||
// frame.
|
||||
double ratio = ( (frame+1) * 1.0 / (getNumFrames()) );
|
||||
double w = 0.0;
|
||||
if (frame < getNumFrames() -1 ) // the last frame we set the target weight the user asked
|
||||
w = _weight * (1.0-ratio);
|
||||
_animation->setWeight(w);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ActionAnimation : public Action
|
||||
{
|
||||
public:
|
||||
ActionAnimation(Animation* animation) : _animation(animation)
|
||||
{
|
||||
setDuration(animation->getDuration());
|
||||
setName(animation->getName());
|
||||
}
|
||||
virtual void evaluate(unsigned int frame)
|
||||
{
|
||||
Action::evaluate(frame);
|
||||
_animation->update(frame * 1.0/_fps);
|
||||
}
|
||||
Animation* getAnimation() { return _animation.get(); }
|
||||
protected:
|
||||
osg::ref_ptr<Animation> _animation;
|
||||
};
|
||||
|
||||
|
||||
// encapsulate animation with blend in blend out for classic usage
|
||||
class StripAnimation : public Action
|
||||
{
|
||||
protected:
|
||||
typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
|
||||
|
||||
public:
|
||||
StripAnimation(Animation* animation, double blendInDuration, double blendOutDuration, double blendInWeightTarget = 1.0 )
|
||||
{
|
||||
_blendIn = new BlendIn(animation, blendInDuration, blendInWeightTarget);
|
||||
_animation = new ActionAnimation(animation);
|
||||
unsigned int start = static_cast<unsigned int>(floor((_animation->getDuration() - blendOutDuration) * _fps));
|
||||
_blendOut = FrameAction(start, new BlendOut(animation, blendOutDuration));
|
||||
setName(animation->getName() + "_Strip");
|
||||
_blendIn->setName(_animation->getName() + "_" + _blendIn->getName());
|
||||
_blendOut.second->setName(_animation->getName() + "_" + _blendOut.second->getName());
|
||||
setDuration(animation->getDuration());
|
||||
}
|
||||
|
||||
ActionAnimation* getActionAnimation() { return _animation.get(); }
|
||||
BlendIn* getBlendIn() { return _blendIn.get(); }
|
||||
BlendOut* getBlendOut() { return dynamic_cast<BlendOut*>(_blendOut.second.get()); }
|
||||
const ActionAnimation* getActionAnimation() const { return _animation.get(); }
|
||||
const BlendIn* getBlendIn() const { return _blendIn.get(); }
|
||||
const BlendOut* getBlendOut() const { return dynamic_cast<BlendOut*>(_blendOut.second.get()); }
|
||||
|
||||
unsigned int getLoop() const { return _animation->getLoop(); }
|
||||
void setLoop(unsigned int loop)
|
||||
{
|
||||
_animation->setLoop(loop);
|
||||
if (!loop)
|
||||
setDuration(-1);
|
||||
else
|
||||
setDuration(loop * _animation->getDuration());
|
||||
|
||||
// duration changed re evaluate the blendout duration
|
||||
unsigned int start = static_cast<unsigned int>(floor((getDuration() - _blendOut.second->getDuration()) * _fps));
|
||||
_blendOut = FrameAction(start, _blendOut.second);
|
||||
}
|
||||
|
||||
virtual void evaluate(unsigned int frame)
|
||||
{
|
||||
if (frame > getNumFrames() - 1)
|
||||
return;
|
||||
|
||||
Action::evaluate(frame);
|
||||
if (frame < _blendIn->getNumFrames())
|
||||
_blendIn->evaluate(frame);
|
||||
if (frame >= _blendOut.first)
|
||||
_blendOut.second->evaluate(frame - _blendOut.first);
|
||||
_animation->evaluate(frame);
|
||||
}
|
||||
|
||||
protected:
|
||||
osg::ref_ptr<BlendIn> _blendIn;
|
||||
FrameAction _blendOut;
|
||||
osg::ref_ptr<ActionAnimation> _animation;
|
||||
};
|
||||
|
||||
|
||||
class RunAction : public Action::Callback
|
||||
{
|
||||
protected:
|
||||
osg::ref_ptr<Timeline> _tm;
|
||||
osg::ref_ptr<Action> _action;
|
||||
|
||||
public:
|
||||
RunAction(Timeline* tm, Action* a) : _tm(tm), _action(a) {}
|
||||
virtual void operator()(Action* /*action*/)
|
||||
{
|
||||
_tm->addActionAt(_tm->getCurrentFrame(), _action.get()); // warning we are trsversing the vector
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
201
src/osgAnimation/Action.cpp
Normal file
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;
|
||||
|
||||
ChannelList::const_iterator chan;
|
||||
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
|
||||
for( chan=_channels.begin(); chan!=_channels.end(); ++chan)
|
||||
{
|
||||
(*chan)->setWeight(_weight);
|
||||
(*chan)->update(t);
|
||||
|
@ -10,6 +10,9 @@ SET(LIB_NAME osgAnimation)
|
||||
|
||||
SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME})
|
||||
SET(LIB_PUBLIC_HEADERS
|
||||
${HEADER_PATH}/Action
|
||||
${HEADER_PATH}/ActionCallback
|
||||
${HEADER_PATH}/ActionVisitor
|
||||
${HEADER_PATH}/Animation
|
||||
${HEADER_PATH}/AnimationManagerBase
|
||||
${HEADER_PATH}/Assert
|
||||
@ -19,6 +22,7 @@ SET(LIB_PUBLIC_HEADERS
|
||||
${HEADER_PATH}/CubicBezier
|
||||
${HEADER_PATH}/EaseMotion
|
||||
${HEADER_PATH}/Export
|
||||
${HEADER_PATH}/FrameAction
|
||||
${HEADER_PATH}/Interpolator
|
||||
${HEADER_PATH}/Keyframe
|
||||
${HEADER_PATH}/LinkVisitor
|
||||
@ -27,6 +31,8 @@ SET(LIB_PUBLIC_HEADERS
|
||||
${HEADER_PATH}/Sampler
|
||||
${HEADER_PATH}/Skeleton
|
||||
${HEADER_PATH}/Skinning
|
||||
${HEADER_PATH}/StatsVisitor
|
||||
${HEADER_PATH}/StatsHandler
|
||||
${HEADER_PATH}/Target
|
||||
${HEADER_PATH}/Timeline
|
||||
${HEADER_PATH}/TimelineAnimationManager
|
||||
@ -39,6 +45,9 @@ SET(LIB_PUBLIC_HEADERS
|
||||
ADD_LIBRARY(${LIB_NAME}
|
||||
${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC}
|
||||
${LIB_PUBLIC_HEADERS}
|
||||
Action.cpp
|
||||
ActionCallback.cpp
|
||||
ActionVisitor.cpp
|
||||
Animation.cpp
|
||||
AnimationManagerBase.cpp
|
||||
AnimationManager.cpp
|
||||
@ -48,6 +57,8 @@ ADD_LIBRARY(${LIB_NAME}
|
||||
MorphGeometry.cpp
|
||||
RigGeometry.cpp
|
||||
Skeleton.cpp
|
||||
StatsVisitor.cpp
|
||||
StatsHandler.cpp
|
||||
Target.cpp
|
||||
TimelineAnimationManager.cpp
|
||||
Timeline.cpp
|
||||
|
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/StatsVisitor>
|
||||
#include <limits.h>
|
||||
|
||||
using namespace osgAnimation;
|
||||
@ -29,11 +30,13 @@ osgAnimation::Timeline::Timeline()
|
||||
_previousFrameEvaluated = 0;
|
||||
_evaluating = 0;
|
||||
_numberFrame = UINT_MAX; // something like infinity
|
||||
_collectStats = false;
|
||||
_stats = new osg::Stats("Timeline");
|
||||
setName("Timeline");
|
||||
}
|
||||
|
||||
osgAnimation::Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, op),
|
||||
_actions(nc._actions)
|
||||
osgAnimation::Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : Action(nc, op),
|
||||
_actions(nc._actions)
|
||||
{
|
||||
_lastUpdate = 0;
|
||||
_currentFrame = 0;
|
||||
@ -44,5 +47,200 @@ osgAnimation::Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg
|
||||
_previousFrameEvaluated = 0;
|
||||
_evaluating = 0;
|
||||
_numberFrame = UINT_MAX; // something like infinity
|
||||
_collectStats = false;
|
||||
_stats = new osg::Stats("Timeline");
|
||||
setName("Timeline");
|
||||
}
|
||||
|
||||
void osgAnimation::Timeline::traverse(ActionVisitor& visitor)
|
||||
{
|
||||
visitor.pushTimelineOnStack(this);
|
||||
// update from high priority to low priority
|
||||
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
|
||||
{
|
||||
ActionList& list = iterAnim->second;
|
||||
for (unsigned int i = 0; i < list.size(); i++)
|
||||
{
|
||||
visitor.pushFrameActionOnStack(list[i]);
|
||||
if (list[i].second) list[i].second->accept(visitor);
|
||||
visitor.popFrameAction();
|
||||
}
|
||||
}
|
||||
visitor.popTimeline();
|
||||
}
|
||||
|
||||
|
||||
void osgAnimation::Timeline::setStats(osg::Stats* stats) { _stats = stats;}
|
||||
osg::Stats* osgAnimation::Timeline::getStats() { return _stats;}
|
||||
void osgAnimation::Timeline::collectStats(bool state) { _collectStats = state;}
|
||||
osgAnimation::StatsActionVisitor* osgAnimation::Timeline::getStatsVisitor() { return _statsVisitor; }
|
||||
|
||||
void osgAnimation::Timeline::clearActions()
|
||||
{
|
||||
_actions.clear();
|
||||
_addActionOperations.clear();
|
||||
_removeActionOperations.clear();
|
||||
}
|
||||
|
||||
void osgAnimation::Timeline::update(double simulationTime)
|
||||
{
|
||||
// first time we call update we generate one frame
|
||||
UpdateActionVisitor updateTimeline;
|
||||
if (!_initFirstFrame)
|
||||
{
|
||||
_lastUpdate = simulationTime;
|
||||
_initFirstFrame = true;
|
||||
|
||||
updateTimeline.setFrame(_currentFrame);
|
||||
accept(updateTimeline);
|
||||
|
||||
if (_collectStats)
|
||||
{
|
||||
if (!_statsVisitor)
|
||||
_statsVisitor = new osgAnimation::StatsActionVisitor();
|
||||
_statsVisitor->setStats(_stats);
|
||||
_statsVisitor->setFrame(_currentFrame);
|
||||
_statsVisitor->reset();
|
||||
accept(*_statsVisitor);
|
||||
}
|
||||
|
||||
processPendingOperation();
|
||||
}
|
||||
|
||||
// find the number of frame pass since the last update
|
||||
double delta = (simulationTime - _lastUpdate);
|
||||
double nbframes = delta * _fps * _speed;
|
||||
unsigned int nb = static_cast<unsigned int>(floor(nbframes));
|
||||
|
||||
for (unsigned int i = 0; i < nb; i++)
|
||||
{
|
||||
if (_state == Play)
|
||||
_currentFrame++;
|
||||
|
||||
updateTimeline.setFrame(_currentFrame);
|
||||
accept(updateTimeline);
|
||||
if (_collectStats)
|
||||
{
|
||||
if (!_statsVisitor)
|
||||
_statsVisitor = new StatsActionVisitor;
|
||||
_statsVisitor->setStats(_stats);
|
||||
_statsVisitor->setFrame(_currentFrame);
|
||||
_statsVisitor->reset();
|
||||
accept(*_statsVisitor);
|
||||
}
|
||||
|
||||
processPendingOperation();
|
||||
}
|
||||
if (nb)
|
||||
{
|
||||
_lastUpdate += ((double)nb) / _fps;
|
||||
}
|
||||
}
|
||||
|
||||
void osgAnimation::Timeline::removeAction(Action* action)
|
||||
{
|
||||
if (getEvaluating())
|
||||
_removeActionOperations.push_back(FrameAction(0, action));
|
||||
else
|
||||
internalRemoveAction(action);
|
||||
}
|
||||
|
||||
void osgAnimation::Timeline::addActionAt(unsigned int frame, Action* action, int priority)
|
||||
{
|
||||
if (getEvaluating())
|
||||
_addActionOperations.push_back(Command(priority,FrameAction(frame, action)));
|
||||
else
|
||||
internalAddAction(priority, FrameAction(frame, action));
|
||||
}
|
||||
void osgAnimation::Timeline::addActionAt(double t, Action* action, int priority)
|
||||
{
|
||||
unsigned int frame = static_cast<unsigned int>(floor(t * _fps));
|
||||
addActionAt(frame, action, priority);
|
||||
}
|
||||
|
||||
void osgAnimation::Timeline::addActionNow(Action* action, int priority)
|
||||
{
|
||||
addActionAt(getCurrentFrame(), action, priority);
|
||||
}
|
||||
|
||||
void osgAnimation::Timeline::processPendingOperation()
|
||||
{
|
||||
// process all pending add action operation
|
||||
while( !_addActionOperations.empty())
|
||||
{
|
||||
internalAddAction(_addActionOperations.back()._priority, _addActionOperations.back()._action);
|
||||
_addActionOperations.pop_back();
|
||||
}
|
||||
|
||||
// process all pending remove action operation
|
||||
while( !_removeActionOperations.empty())
|
||||
{
|
||||
internalRemoveAction(_removeActionOperations.back().second.get());
|
||||
_removeActionOperations.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void osgAnimation::Timeline::internalRemoveAction(Action* action)
|
||||
{
|
||||
for (ActionLayers::iterator it = _actions.begin(); it != _actions.end(); it++)
|
||||
{
|
||||
ActionList& fa = it->second;
|
||||
for (unsigned int i = 0; i < fa.size(); i++)
|
||||
if (fa[i].second.get() == action)
|
||||
{
|
||||
fa.erase(fa.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void osgAnimation::Timeline::internalAddAction(int priority, const FrameAction& ftl)
|
||||
{
|
||||
_actions[priority].insert(_actions[priority].begin(), ftl);
|
||||
// _actions[priority].push_back(ftl);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void osgAnimation::Timeline::evaluateCallback(unsigned int frame)
|
||||
{
|
||||
// update from high priority to low priority
|
||||
for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim )
|
||||
{
|
||||
// update all animation
|
||||
ActionList& list = iterAnim->second;
|
||||
for (unsigned int i = 0; i < list.size(); i++)
|
||||
{
|
||||
unsigned int firstFrame = list[i].first;
|
||||
Action* action = list[i].second.get();
|
||||
// check if current frame of timeline hit an action interval
|
||||
if (frame >= firstFrame &&
|
||||
frame < (firstFrame + action->getNumFrames()) )
|
||||
action->evaluateCallback(frame - firstFrame);
|
||||
}
|
||||
}
|
||||
processPendingOperation();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool osgAnimation::Timeline::isActive(Action* activeAction)
|
||||
{
|
||||
// update from high priority to low priority
|
||||
for( ActionLayers::iterator iterAnim = _actions.begin(); iterAnim != _actions.end(); ++iterAnim )
|
||||
{
|
||||
// update all animation
|
||||
ActionList& list = iterAnim->second;
|
||||
for (unsigned int i = 0; i < list.size(); i++)
|
||||
{
|
||||
Action* action = list[i].second.get();
|
||||
if (action == activeAction)
|
||||
{
|
||||
unsigned int firstFrame = list[i].first;
|
||||
// check if current frame of timeline hit an action interval
|
||||
if (_currentFrame >= firstFrame &&
|
||||
_currentFrame < (firstFrame + action->getNumFrames()) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user