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:
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user