Hi Robert,
I just sent you the files by mail, here again on the mailing. Those
changes are not critical, so it's not a problem if not for the 2.8
Cheers,
Cedric
Robert Osfield wrote:
Hi Guys,
If we have a quicker turn around on review on these changes I would
have considered them for the 2.8.0 release, but given that lots of
people are now testing the 2.8 branch as is, without these changes I
feel it'd be best to just apply these changes to svn/trunk. None of
these changes address bugs so there shouldn't be a risk in not merging
for 2.8.
Robert.
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
--
+33 (0) 6 63 20 03 56 Cedric Pinson mailto:[email protected]
http://www.plopbyte.net
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <[email protected]>
*
* 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 <iostream>
#include <osg/Geometry>
#include <osg/MatrixTransform>
#include <osg/Geode>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osgUtil/SmoothingVisitor>
#include <osg/io_utils>
#include <osgAnimation/Bone>
#include <osgAnimation/Skeleton>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/Skinning>
#include <osgAnimation/BasicAnimationManager>
osg::Geode* createAxis()
{
osg::Geode* geode (new osg::Geode());
osg::Geometry* geometry (new osg::Geometry());
osg::Vec3Array* vertices (new osg::Vec3Array());
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 1.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 1.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 0.0));
vertices->push_back (osg::Vec3 ( 0.0, 0.0, 1.0));
geometry->setVertexArray (vertices);
osg::Vec4Array* colors (new osg::Vec4Array());
colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (1.0f, 0.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 1.0f, 0.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
colors->push_back (osg::Vec4 (0.0f, 0.0f, 1.0f, 1.0f));
geometry->setColorArray (colors);
geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,0,6));
geode->addDrawable( geometry );
return geode;
}
osgAnimation::RigGeometry* createTesselatedBox(int nsplit, float size)
{
osgAnimation::RigGeometry* geometry = new osgAnimation::RigGeometry;
osg::ref_ptr<osg::Vec3Array> vertices (new osg::Vec3Array());
osg::ref_ptr<osg::Vec3Array> colors (new osg::Vec3Array());
geometry->setVertexArray (vertices.get());
geometry->setColorArray (colors.get());
geometry->setColorBinding (osg::Geometry::BIND_PER_VERTEX);
float step = size / nsplit;
float s = 0.5/4.0;
for (int i = 0; i < nsplit; i++)
{
float x = -1 + i * step;
std::cout << x << std::endl;
vertices->push_back (osg::Vec3 ( x, s, s));
vertices->push_back (osg::Vec3 ( x, -s, s));
vertices->push_back (osg::Vec3 ( x, -s, -s));
vertices->push_back (osg::Vec3 ( x, s, -s));
osg::Vec3 c (0,0,0);
c[i%3] = 1;
colors->push_back (c);
colors->push_back (c);
colors->push_back (c);
colors->push_back (c);
}
osg::ref_ptr<osg::UIntArray> array = new osg::UIntArray;
for (int i = 0; i < nsplit - 1; i++)
{
int base = i * 4;
array->push_back(base);
array->push_back(base+1);
array->push_back(base+4);
array->push_back(base+1);
array->push_back(base+5);
array->push_back(base+4);
array->push_back(base+3);
array->push_back(base);
array->push_back(base+4);
array->push_back(base+7);
array->push_back(base+3);
array->push_back(base+4);
array->push_back(base+5);
array->push_back(base+1);
array->push_back(base+2);
array->push_back(base+2);
array->push_back(base+6);
array->push_back(base+5);
array->push_back(base+2);
array->push_back(base+3);
array->push_back(base+7);
array->push_back(base+6);
array->push_back(base+2);
array->push_back(base+7);
}
geometry->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES, array->size(), &array->front()));
geometry->setUseDisplayList( false );
return geometry;
}
void initVertexMap(osgAnimation::Bone* b0,
osgAnimation::Bone* b1,
osgAnimation::Bone* b2,
osgAnimation::RigGeometry* geom,
osg::Vec3Array* array)
{
osgAnimation::VertexInfluenceSet vertexesInfluences;
osgAnimation::VertexInfluenceMap* vim = new osgAnimation::VertexInfluenceMap;
(*vim)[b0->getName()].setName(b0->getName());
(*vim)[b1->getName()].setName(b1->getName());
(*vim)[b2->getName()].setName(b2->getName());
for (int i = 0; i < (int)array->size(); i++)
{
float val = (*array)[i][0];
std::cout << val << std::endl;
if (val >= -1 && val <= 0)
(*vim)[b0->getName()].push_back(osgAnimation::VertexIndexWeight(i,1));
else if ( val > 0 && val <= 1)
(*vim)[b1->getName()].push_back(osgAnimation::VertexIndexWeight(i,1));
else if ( val > 1)
(*vim)[b2->getName()].push_back(osgAnimation::VertexIndexWeight(i,1));
}
geom->setInfluenceMap(vim);
}
int main (int argc, char* argv[])
{
osg::ArgumentParser arguments(&argc, argv);
osgViewer::Viewer viewer(arguments);
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
osg::ref_ptr<osgAnimation::Skeleton> skelroot = new osgAnimation::Skeleton;
skelroot->setDefaultUpdateCallback();
osg::ref_ptr<osgAnimation::Bone> root = new osgAnimation::Bone;
{
root->setBindMatrixInBoneSpace(osg::Matrix::identity());
root->setBindMatrixInBoneSpace(osg::Matrix::translate(-1,0,0));
root->setName("root");
root->setDefaultUpdateCallback();
}
osg::ref_ptr<osgAnimation::Bone> right0 = new osgAnimation::Bone;
right0->setBindMatrixInBoneSpace(osg::Matrix::translate(1,0,0));
right0->setName("right0");
right0->setDefaultUpdateCallback("right0");
osg::ref_ptr<osgAnimation::Bone> right1 = new osgAnimation::Bone;
right1->setBindMatrixInBoneSpace(osg::Matrix::translate(1,0,0));
right1->setName("right1");
right1->setDefaultUpdateCallback("right1");
root->addChild(right0.get());
right0->addChild(right1.get());
skelroot->addChild(root.get());
osg::Group* scene = new osg::Group;
osg::ref_ptr<osgAnimation::BasicAnimationManager> manager = new osgAnimation::BasicAnimationManager;
scene->setUpdateCallback(manager.get());
osgAnimation::Animation* anim = new osgAnimation::Animation;
{
osgAnimation::QuatKeyframeContainer* keys0 = new osgAnimation::QuatKeyframeContainer;
osg::Quat rotate;
rotate.makeRotate(osg::PI_2, osg::Vec3(0,0,1));
keys0->push_back(osgAnimation::QuatKeyframe(0,osg::Quat(0,0,0,1)));
keys0->push_back(osgAnimation::QuatKeyframe(3,rotate));
keys0->push_back(osgAnimation::QuatKeyframe(6,rotate));
osgAnimation::QuatSphericalLinearSampler* sampler = new osgAnimation::QuatSphericalLinearSampler;
sampler->setKeyframeContainer(keys0);
// osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(right0->getUpdateCallback());
osgAnimation::QuatSphericalLinearChannel* channel = new osgAnimation::QuatSphericalLinearChannel(sampler);
channel->setName("quaternion");
channel->setTargetName("right0");
anim->addChannel(channel);
}
{
osgAnimation::QuatKeyframeContainer* keys1 = new osgAnimation::QuatKeyframeContainer;
osg::Quat rotate;
rotate.makeRotate(osg::PI_2, osg::Vec3(0,0,1));
keys1->push_back(osgAnimation::QuatKeyframe(0,osg::Quat(0,0,0,1)));
keys1->push_back(osgAnimation::QuatKeyframe(3,osg::Quat(0,0,0,1)));
keys1->push_back(osgAnimation::QuatKeyframe(6,rotate));
osgAnimation::QuatSphericalLinearSampler* sampler = new osgAnimation::QuatSphericalLinearSampler;
sampler->setKeyframeContainer(keys1);
osgAnimation::QuatSphericalLinearChannel* channel = new osgAnimation::QuatSphericalLinearChannel(sampler);
//osgAnimation::AnimationUpdateCallback* cb = dynamic_cast<osgAnimation::AnimationUpdateCallback*>(right1->getUpdateCallback());
channel->setName("quaternion");
channel->setTargetName("right1");
anim->addChannel(channel);
}
manager->registerAnimation(anim);
manager->buildTargetReference();
// let's start !
manager->playAnimation(anim);
// we will use local data from the skeleton
osg::MatrixTransform* rootTransform = new osg::MatrixTransform;
rootTransform->setMatrix(osg::Matrix::rotate(osg::PI_2,osg::Vec3(1,0,0)));
right0->addChild(createAxis());
right0->setDataVariance(osg::Object::DYNAMIC);
right1->addChild(createAxis());
right1->setDataVariance(osg::Object::DYNAMIC);
osg::MatrixTransform* trueroot = new osg::MatrixTransform;
trueroot->setMatrix(osg::Matrix(root->getMatrixInBoneSpace().ptr()));
trueroot->addChild(createAxis());
trueroot->addChild(skelroot.get());
trueroot->setDataVariance(osg::Object::DYNAMIC);
rootTransform->addChild(trueroot);
scene->addChild(rootTransform);
osgAnimation::RigGeometry* geom = createTesselatedBox(4, 4.0);
osg::Geode* geode = new osg::Geode;
geode->addDrawable(geom);
skelroot->addChild(geode);
osg::ref_ptr<osg::Vec3Array> src = dynamic_cast<osg::Vec3Array*>(geom->getVertexArray());
geom->getOrCreateStateSet()->setMode(GL_LIGHTING, false);
geom->setDataVariance(osg::Object::DYNAMIC);
initVertexMap(root.get(), right0.get(), right1.get(), geom, src.get());
// let's run !
viewer.setSceneData( scene );
viewer.realize();
while (!viewer.done())
{
viewer.frame();
}
return 0;
}
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <[email protected]>
*
* 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_RIGGEOMETRY_H
#define OSGANIMATION_RIGGEOMETRY_H
#include <osgAnimation/Export>
#include <osgAnimation/Skinning>
#include <osgAnimation/Skeleton>
#include <osg/Geometry>
namespace osgAnimation
{
class OSGANIMATION_EXPORT RigGeometry : public osg::Geometry
{
public:
RigGeometry();
RigGeometry(const osg::Geometry& b);
RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop =
osg::CopyOp::SHALLOW_COPY);
META_Object(osgAnimation, RigGeometry);
void setInfluenceMap(osgAnimation::VertexInfluenceMap*
vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; }
const osgAnimation::VertexInfluenceMap* getInfluenceMap() const {
return _vertexInfluenceMap.get();}
osgAnimation::VertexInfluenceMap* getInfluenceMap() { return
_vertexInfluenceMap.get();}
const Skeleton* getSkeleton() const;
Skeleton* getSkeleton();
void setNeedToComputeMatrix(bool state) { _needToComputeMatrix = state;}
bool getNeedToComputeMatrix() const { return _needToComputeMatrix;}
void buildVertexSet();
void buildTransformer(Skeleton* root);
void computeMatrixFromRootSkeleton();
virtual void transformSoftwareMethod();
const osgAnimation::VertexInfluenceSet& getVertexInfluenceSet() const {
return _vertexInfluenceSet;}
const std::vector<osg::Vec3>& getPositionSource() const { return
_positionSource;}
const std::vector<osg::Vec3>& getNormalSource() const { return
_normalSource;}
protected:
std::vector<osg::Vec3> _positionSource;
std::vector<osg::Vec3> _normalSource;
osgAnimation::VertexInfluenceSet _vertexInfluenceSet;
osg::ref_ptr<osgAnimation::VertexInfluenceMap> _vertexInfluenceMap;
osgAnimation::TransformVertexFunctor _transformVertexes;
osg::Matrix _matrixFromSkeletonToGeometry;
osg::Matrix _invMatrixFromSkeletonToGeometry;
osg::observer_ptr<Skeleton> _root;
bool _needToComputeMatrix;
struct FindNearestParentSkeleton : public osg::NodeVisitor
{
osg::ref_ptr<osgAnimation::Skeleton> _root;
FindNearestParentSkeleton() :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {}
void apply(osg::Transform& node)
{
if (_root.valid())
return;
_root = dynamic_cast<osgAnimation::Skeleton*>(&node);
traverse(node);
}
};
struct UpdateVertex : public osg::Drawable::UpdateCallback
{
virtual void update(osg::NodeVisitor*, osg::Drawable* drw)
{
RigGeometry* geom = dynamic_cast<RigGeometry*>(drw);
if (!geom)
return;
if (!geom->getSkeleton() && !geom->getParents().empty())
{
FindNearestParentSkeleton finder;
if (geom->getParents().size() > 1)
osg::notify(osg::WARN) << "A RigGeometry should not
have multi parent ( " << geom->getName() << " )" << std::endl;
geom->getParents()[0]->accept(finder);
if (!finder._root.valid())
return;
geom->buildVertexSet();
geom->buildTransformer(finder._root.get());
}
if (!geom->getSkeleton())
return;
if (geom->getNeedToComputeMatrix())
geom->computeMatrixFromRootSkeleton();
geom->transformSoftwareMethod();
}
};
/** BuildVertexTransformerVisitor is used to setup RigGeometry drawable
* throw a subgraph.
*/
struct BuildVertexTransformerVisitor : public osg::NodeVisitor
{
osg::ref_ptr<Skeleton> _root;
BuildVertexTransformerVisitor(Skeleton* root):
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _root = root;}
META_NodeVisitor("osgAnimation","BuildVertexTransformerVisitor")
void apply(osg::Geode& node)
{
int num = node.getNumDrawables();
for (int i = 0; i < num; i++) {
RigGeometry* geom =
dynamic_cast<RigGeometry*>(node.getDrawable(i));
if (geom)
{
geom->buildVertexSet();
geom->buildTransformer(_root.get());
}
}
}
};
};
}
#endif
/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <[email protected]>
*
* 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_TIMELINE_H
#define OSGANIMATION_TIMELINE_H
#include <osgAnimation/Export>
#include <osg/Object>
#include <map>
#include <vector>
#include <osg/Notify>
#include <osg/Group>
#include <osgAnimation/Animation>
#include <osgAnimation/AnimationManagerBase>
namespace osgAnimation
{
class Action : public 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 State
{
Play,
Stop
};
State _state;
};
class Timeline : public osg::Object
{
protected:
typedef std::pair<unsigned int, osg::ref_ptr<Action> > FrameAction;
typedef std::vector<FrameAction> ActionList;
typedef std::map<int, ActionList> ActionLayers;
enum State
{
Play,
Stop
};
ActionLayers _actions;
double _lastUpdate;
double _speed;
unsigned int _currentFrame;
unsigned int _fps;
unsigned int _numberFrame;
unsigned int _previousFrameEvaluated;
bool _loop;
bool _initFirstFrame;
State _state;
// to manage pending operation
bool _evaluating;
struct Command
{
Command():_priority(0) {}
Command(int priority, const FrameAction& action) :
_priority(priority), _action(action) {}
int _priority;
FrameAction _action;
};
typedef std::vector<Command> CommandList;
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);
}
public:
META_Object(osgAnimation, Timeline);
Timeline();
Timeline(const Timeline& nc,const osg::CopyOp& op =
osg::CopyOp::SHALLOW_COPY);
State getStatus() const { return _state; }
const ActionList& getActionLayer(int i)
{
return _actions[i];
}
unsigned int getCurrentFrame() const { return _currentFrame;}
double getCurrentTime() const { return _currentFrame * 1.0 / _fps;}
void play() { _state = Play; }
void gotoFrame(unsigned int frame) { _currentFrame = frame; }
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;
}
void removeAction(Action* action)
{
if (getEvaluating())
_removeActionOperations.push_back(FrameAction(0, action));
else
internalRemoveAction(action);
}
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);
}
virtual void evaluate(unsigned int frame)
{
setEvaluating(true);
osg::notify(osg::DEBUG_INFO) << getName() << " evaluate frame " <<
_currentFrame << std::endl;
// 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);
// evaluate callback after updating all animation
evaluateCallback(frame);
_previousFrameEvaluated = frame;
}
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();
}
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;
}
}
};
// 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
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org