From 38e68ed7f101145ecac3e14d77301411a7754ff1 Mon Sep 17 00:00:00 2001 From: Paul MARTZ Date: Sat, 13 Mar 2010 20:55:16 +0000 Subject: [PATCH] 2.8 branch: backport of osgAnimation from svn head 11026. --- include/osgAnimation/Action | 147 ++++ include/osgAnimation/ActionAnimation | 41 + include/osgAnimation/ActionBlendIn | 44 ++ include/osgAnimation/ActionBlendOut | 45 ++ include/osgAnimation/ActionCallback | 41 + include/osgAnimation/ActionStripAnimation | 57 ++ include/osgAnimation/ActionVisitor | 117 +++ include/osgAnimation/Animation | 8 +- include/osgAnimation/AnimationManagerBase | 24 +- include/osgAnimation/AnimationUpdateCallback | 72 ++ include/osgAnimation/Bone | 247 +----- include/osgAnimation/BoneMapVisitor | 42 + include/osgAnimation/Channel | 76 +- include/osgAnimation/CubicBezier | 63 +- include/osgAnimation/EaseMotion | 250 +++++- include/osgAnimation/FrameAction | 26 + include/osgAnimation/Interpolator | 52 +- include/osgAnimation/Keyframe | 11 + include/osgAnimation/LinkVisitor | 50 +- include/osgAnimation/MorphGeometry | 154 ++++ include/osgAnimation/RigGeometry | 92 ++- include/osgAnimation/RigTransform | 36 + include/osgAnimation/RigTransformHardware | 85 +++ include/osgAnimation/RigTransformSoftware | 172 +++++ include/osgAnimation/Sampler | 17 +- include/osgAnimation/Skeleton | 27 +- include/osgAnimation/StackedMatrixElement | 54 ++ include/osgAnimation/StackedQuaternionElement | 54 ++ include/osgAnimation/StackedRotateAxisElement | 59 ++ include/osgAnimation/StackedScaleElement | 56 ++ include/osgAnimation/StackedTransform | 42 + include/osgAnimation/StackedTransformElement | 42 + include/osgAnimation/StackedTranslateElement | 54 ++ include/osgAnimation/StatsHandler | 113 +++ include/osgAnimation/StatsVisitor | 53 ++ include/osgAnimation/Target | 114 +-- include/osgAnimation/Timeline | 526 ++----------- include/osgAnimation/TimelineAnimationManager | 34 +- include/osgAnimation/UpdateBone | 36 + include/osgAnimation/UpdateMaterial | 46 ++ include/osgAnimation/UpdateMatrixTransform | 48 ++ include/osgAnimation/VertexInfluence | 22 +- src/osgAnimation/Action.cpp | 83 ++ src/osgAnimation/ActionAnimation.cpp | 32 + src/osgAnimation/ActionBlendIn.cpp | 45 ++ src/osgAnimation/ActionBlendOut.cpp | 41 + src/osgAnimation/ActionCallback.cpp | 23 + src/osgAnimation/ActionStripAnimation.cpp | 88 +++ src/osgAnimation/ActionVisitor.cpp | 184 +++++ src/osgAnimation/Animation.cpp | 28 +- src/osgAnimation/AnimationManagerBase.cpp | 69 +- src/osgAnimation/BasicAnimationManager.cpp | 35 +- src/osgAnimation/Bone.cpp | 87 +-- src/osgAnimation/BoneMapVisitor.cpp | 42 + src/osgAnimation/CMakeLists.txt | 108 ++- src/osgAnimation/Channel.cpp | 13 +- src/osgAnimation/LinkVisitor.cpp | 87 +++ src/osgAnimation/MorphGeometry.cpp | 277 +++++++ src/osgAnimation/RigGeometry.cpp | 228 ++++-- src/osgAnimation/RigTransformHardware.cpp | 272 +++++++ src/osgAnimation/RigTransformSoftware.cpp | 144 ++++ src/osgAnimation/Skeleton.cpp | 91 +-- src/osgAnimation/StackedMatrixElement.cpp | 40 + src/osgAnimation/StackedQuaternionElement.cpp | 53 ++ src/osgAnimation/StackedRotateAxisElement.cpp | 55 ++ src/osgAnimation/StackedScaleElement.cpp | 56 ++ src/osgAnimation/StackedTransform.cpp | 66 ++ src/osgAnimation/StackedTranslateElement.cpp | 50 ++ src/osgAnimation/StatsHandler.cpp | 722 ++++++++++++++++++ src/osgAnimation/StatsVisitor.cpp | 86 +++ src/osgAnimation/Target.cpp | 5 +- src/osgAnimation/Timeline.cpp | 209 ++++- src/osgAnimation/TimelineAnimationManager.cpp | 6 +- src/osgAnimation/UpdateBone.cpp | 54 ++ src/osgAnimation/UpdateMaterial.cpp | 63 ++ src/osgAnimation/UpdateMatrixTransform.cpp | 67 ++ src/osgAnimation/VertexInfluence.cpp | 42 +- src/osgPlugins/osgAnimation/CMakeLists.txt | 8 +- src/osgPlugins/osgAnimation/Matrix.cpp | 51 ++ src/osgPlugins/osgAnimation/Matrix.h | 13 + src/osgPlugins/osgAnimation/ReaderWriter.cpp | 691 +++++++++++++++-- .../osgAnimation/StackedTransform.cpp | 228 ++++++ .../osgAnimation/UpdateMaterial.cpp | 47 ++ .../osgAnimation/UpdateMatrixTransform.cpp | 70 ++ 84 files changed, 6677 insertions(+), 1331 deletions(-) create mode 100644 include/osgAnimation/Action create mode 100644 include/osgAnimation/ActionAnimation create mode 100644 include/osgAnimation/ActionBlendIn create mode 100644 include/osgAnimation/ActionBlendOut create mode 100644 include/osgAnimation/ActionCallback create mode 100644 include/osgAnimation/ActionStripAnimation create mode 100644 include/osgAnimation/ActionVisitor create mode 100644 include/osgAnimation/AnimationUpdateCallback create mode 100644 include/osgAnimation/BoneMapVisitor create mode 100644 include/osgAnimation/FrameAction create mode 100644 include/osgAnimation/MorphGeometry create mode 100644 include/osgAnimation/RigTransform create mode 100644 include/osgAnimation/RigTransformHardware create mode 100644 include/osgAnimation/RigTransformSoftware create mode 100644 include/osgAnimation/StackedMatrixElement create mode 100644 include/osgAnimation/StackedQuaternionElement create mode 100644 include/osgAnimation/StackedRotateAxisElement create mode 100644 include/osgAnimation/StackedScaleElement create mode 100644 include/osgAnimation/StackedTransform create mode 100644 include/osgAnimation/StackedTransformElement create mode 100644 include/osgAnimation/StackedTranslateElement create mode 100644 include/osgAnimation/StatsHandler create mode 100644 include/osgAnimation/StatsVisitor create mode 100644 include/osgAnimation/UpdateBone create mode 100644 include/osgAnimation/UpdateMaterial create mode 100644 include/osgAnimation/UpdateMatrixTransform create mode 100644 src/osgAnimation/Action.cpp create mode 100644 src/osgAnimation/ActionAnimation.cpp create mode 100644 src/osgAnimation/ActionBlendIn.cpp create mode 100644 src/osgAnimation/ActionBlendOut.cpp create mode 100644 src/osgAnimation/ActionCallback.cpp create mode 100644 src/osgAnimation/ActionStripAnimation.cpp create mode 100644 src/osgAnimation/ActionVisitor.cpp create mode 100644 src/osgAnimation/BoneMapVisitor.cpp create mode 100644 src/osgAnimation/LinkVisitor.cpp create mode 100644 src/osgAnimation/MorphGeometry.cpp create mode 100644 src/osgAnimation/RigTransformHardware.cpp create mode 100644 src/osgAnimation/RigTransformSoftware.cpp create mode 100644 src/osgAnimation/StackedMatrixElement.cpp create mode 100644 src/osgAnimation/StackedQuaternionElement.cpp create mode 100644 src/osgAnimation/StackedRotateAxisElement.cpp create mode 100644 src/osgAnimation/StackedScaleElement.cpp create mode 100644 src/osgAnimation/StackedTransform.cpp create mode 100644 src/osgAnimation/StackedTranslateElement.cpp create mode 100644 src/osgAnimation/StatsHandler.cpp create mode 100644 src/osgAnimation/StatsVisitor.cpp create mode 100644 src/osgAnimation/UpdateBone.cpp create mode 100644 src/osgAnimation/UpdateMaterial.cpp create mode 100644 src/osgAnimation/UpdateMatrixTransform.cpp create mode 100644 src/osgPlugins/osgAnimation/Matrix.cpp create mode 100644 src/osgPlugins/osgAnimation/Matrix.h create mode 100644 src/osgPlugins/osgAnimation/StackedTransform.cpp create mode 100644 src/osgPlugins/osgAnimation/UpdateMaterial.cpp create mode 100644 src/osgPlugins/osgAnimation/UpdateMatrixTransform.cpp diff --git a/include/osgAnimation/Action b/include/osgAnimation/Action new file mode 100644 index 000000000..b61e45c39 --- /dev/null +++ b/include/osgAnimation/Action @@ -0,0 +1,147 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include +#include + +#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(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 (callback) { + if (_nestedCallback.valid()) + _nestedCallback->addNestedCallback(callback); + else + _nestedCallback = callback; + } + } + + void removeCallback(Callback* cb) + { + if (!cb) + return; + + if (_nestedCallback.get() == cb) + _nestedCallback = _nestedCallback->getNestedCallback(); + else if (_nestedCallback.valid()) + _nestedCallback->removeCallback(cb); + } + + protected: + osg::ref_ptr _nestedCallback; + }; + + + typedef std::map > FrameCallback; + + META_Action(osgAnimation, Action); + + Action(); + Action(const Action&,const osg::CopyOp&); + + void setCallback(double when, Callback* callback) + { + setCallback(static_cast(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 removeCallback(Callback*); + + 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(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; + }; + + + + +} + +#endif diff --git a/include/osgAnimation/ActionAnimation b/include/osgAnimation/ActionAnimation new file mode 100644 index 000000000..ed4d8982e --- /dev/null +++ b/include/osgAnimation/ActionAnimation @@ -0,0 +1,41 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_ANIMATION_H +#define OSGANIMATION_ACTION_ANIMATION_H + +#include +#include + + +namespace osgAnimation { + + + class OSGANIMATION_EXPORT ActionAnimation : public Action + { + public: + META_Action(osgAnimation, ActionAnimation); + ActionAnimation(); + ActionAnimation(const ActionAnimation& a, const osg::CopyOp& c); + ActionAnimation(Animation* animation); + void updateAnimation(unsigned int frame, int priority); + Animation* getAnimation() { return _animation.get(); } + + protected: + osg::ref_ptr _animation; + }; + +} + +#endif diff --git a/include/osgAnimation/ActionBlendIn b/include/osgAnimation/ActionBlendIn new file mode 100644 index 000000000..5789a2c51 --- /dev/null +++ b/include/osgAnimation/ActionBlendIn @@ -0,0 +1,44 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_BLENDIN_H +#define OSGANIMATION_ACTION_BLENDIN_H + +#include +#include + + +namespace osgAnimation { + + + /// blend in from 0 to weight in duration + class OSGANIMATION_EXPORT ActionBlendIn : public Action + { + public: + META_Action(osgAnimation, ActionBlendIn); + ActionBlendIn(); + ActionBlendIn(const ActionBlendIn& a, const osg::CopyOp& c); + ActionBlendIn(Animation* animation, double duration, double weight); + double getWeight() const { return _weight;} + Animation* getAnimation() { return _animation.get(); } + void computeWeight(unsigned int frame); + + protected: + double _weight; + osg::ref_ptr _animation; + }; + +} + +#endif diff --git a/include/osgAnimation/ActionBlendOut b/include/osgAnimation/ActionBlendOut new file mode 100644 index 000000000..cc391739e --- /dev/null +++ b/include/osgAnimation/ActionBlendOut @@ -0,0 +1,45 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_BLENDOUT_H +#define OSGANIMATION_ACTION_BLENDOUT_H + +#include +#include + + +namespace osgAnimation { + + + /// blend out from weight to 0 in duration + class OSGANIMATION_EXPORT ActionBlendOut : public Action + { + public: + META_Action(osgAnimation, ActionBlendOut); + ActionBlendOut(); + ActionBlendOut(const ActionBlendOut& a, const osg::CopyOp& c); + ActionBlendOut(Animation* animation, double duration); + Animation* getAnimation() { return _animation.get(); } + double getWeight() const { return _weight;} + void computeWeight(unsigned int frame); + + protected: + double _weight; + osg::ref_ptr _animation; + + }; + +} + +#endif diff --git a/include/osgAnimation/ActionCallback b/include/osgAnimation/ActionCallback new file mode 100644 index 000000000..0f589d5a9 --- /dev/null +++ b/include/osgAnimation/ActionCallback @@ -0,0 +1,41 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include + +namespace osgAnimation +{ + + /** Callback used to run new action on the timeline.*/ + class OSGANIMATION_EXPORT RunAction : public Action::Callback + { + public: + RunAction(Action* a, int priority = 0) : _action(a), _priority(priority) {} + virtual void operator()(Action* action, ActionVisitor* visitor); + + Action* getAction() const { return _action.get(); } + int getPriority() const { return _priority; } + protected: + osg::ref_ptr _action; + int _priority; + + }; + +} + +#endif diff --git a/include/osgAnimation/ActionStripAnimation b/include/osgAnimation/ActionStripAnimation new file mode 100644 index 000000000..7ede4ae08 --- /dev/null +++ b/include/osgAnimation/ActionStripAnimation @@ -0,0 +1,57 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_STRIPANIMATION_H +#define OSGANIMATION_ACTION_STRIPANIMATION_H + +#include +#include +#include +#include +#include +#include + +namespace osgAnimation +{ + + // encapsulate animation with blend in blend out for classic usage + class OSGANIMATION_EXPORT ActionStripAnimation : public Action + { + public: + META_Action(osgAnimation, ActionStripAnimation); + ActionStripAnimation() {} + ActionStripAnimation(const ActionStripAnimation& a, const osg::CopyOp& c); + ActionStripAnimation(Animation* animation, double blendInDuration = 0.0, double blendOutDuration = 0.0, double blendInWeightTarget = 1.0 ); + ActionAnimation* getAnimation(); + ActionBlendIn* getBlendIn(); + ActionBlendOut* getBlendOut(); + const ActionAnimation* getAnimation() const; + const ActionBlendIn* getBlendIn() const; + const ActionBlendOut* getBlendOut() const; + unsigned int getBlendOutStartFrame() const; + + unsigned int getLoop() const; + void setLoop(unsigned int loop); + void traverse(ActionVisitor& visitor); + + protected: + typedef std::pair > FrameBlendOut; + osg::ref_ptr _blendIn; + FrameBlendOut _blendOut; + osg::ref_ptr _animation; + }; + +} + +#endif diff --git a/include/osgAnimation/ActionVisitor b/include/osgAnimation/ActionVisitor new file mode 100644 index 000000000..cc1f542f5 --- /dev/null +++ b/include/osgAnimation/ActionVisitor @@ -0,0 +1,117 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include + +namespace osgAnimation +{ + + class Timeline; + class Action; + class ActionBlendIn; + class ActionBlendOut; + class ActionAnimation; + class ActionStripAnimation; + +#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: + META_ActionVisitor(osgAnimation, ActionVisitor); + ActionVisitor(); + void traverse(Action& visitor); + + void pushFrameActionOnStack(const FrameAction& fa); + void popFrameAction(); + + void pushTimelineOnStack(Timeline* tm); + void popTimeline(); + + Timeline* getCurrentTimeline(); + void setCurrentLayer(int layer) { _currentLayer = layer;} + int getCurrentLayer() const { return _currentLayer; } + + const std::vector& getStackedFrameAction() const { return _stackFrameAction; } + + virtual void apply(Action& action); + virtual void apply(Timeline& tm); + virtual void apply(ActionBlendIn& action); + virtual void apply(ActionBlendOut& action); + virtual void apply(ActionAnimation& action); + virtual void apply(ActionStripAnimation& action); + + protected: + std::vector _stackFrameAction; + std::vector _stackTimeline; + int _currentLayer; + }; + + + class OSGANIMATION_EXPORT UpdateActionVisitor : public osgAnimation::ActionVisitor + { + protected: + unsigned int _frame; + unsigned int _currentAnimationPriority; + public: + META_ActionVisitor(osgAnimation, UpdateActionVisitor); + UpdateActionVisitor(); + void setFrame(unsigned int frame) { _frame = frame;} + + bool isActive(Action& action) const; + unsigned int getLocalFrame() const; + + void apply(Timeline& action); + void apply(Action& action); + void apply(ActionBlendIn& action); + void apply(ActionBlendOut& action); + void apply(ActionAnimation& action); + void apply(ActionStripAnimation& 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 > _remove; + ClearType _clearType; + }; + +} + +#endif diff --git a/include/osgAnimation/Animation b/include/osgAnimation/Animation index 550c8de23..2d50372b8 100644 --- a/include/osgAnimation/Animation +++ b/include/osgAnimation/Animation @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -31,7 +31,7 @@ namespace osgAnimation META_Object(osgAnimation, Animation) Animation() : _duration(0), _weight(0), _startTime(0), _playmode(LOOP) {} - Animation(const osgAnimation::Animation& anim, const osg::CopyOp&); + Animation(const osgAnimation::Animation&, const osg::CopyOp&); enum PlayMode { @@ -71,10 +71,12 @@ namespace osgAnimation void setWeight (float weight); float getWeight() const; - bool update (float time); + bool update (float time, int priority = 0); void resetTargets(); void setPlaymode (PlayMode mode) { _playmode = mode; } + PlayMode getPlayMode() const { return _playmode; } + void setStartTime(float time) { _startTime = time;} float getStartTime() const { return _startTime;} diff --git a/include/osgAnimation/AnimationManagerBase b/include/osgAnimation/AnimationManagerBase index e5b900204..b501b626d 100644 --- a/include/osgAnimation/AnimationManagerBase +++ b/include/osgAnimation/AnimationManagerBase @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -12,9 +12,10 @@ * OpenSceneGraph Public License for more details. */ -#ifndef OSGANIMATION_ANIMATION_MANAGER_BASE_H -#define OSGANIMATION_ANIMATION_MANAGER_BASE_H +#ifndef OSGANIMATION_ANIMATION_MANAGER_BASE +#define OSGANIMATION_ANIMATION_MANAGER_BASE 1 +#include #include #include #include @@ -33,7 +34,8 @@ namespace osgAnimation AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY); virtual ~AnimationManagerBase(); virtual void buildTargetReference(); - virtual void registerAnimation (Animation* animation); + virtual void registerAnimation (Animation*); + virtual void unregisterAnimation (Animation*); virtual void link(osg::Node* subgraph); virtual void update(double t) = 0; virtual bool needToLink() const; @@ -42,16 +44,26 @@ namespace osgAnimation /** Callback method called by the NodeVisitor when visiting a node.*/ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); - /// Operation that must be done each frame + /** Reset the value of targets + this Operation must be done each frame */ void clearTargets(); - void normalizeTargets(); + + LinkVisitor* getOrCreateLinkVisitor(); + void setLinkVisitor(LinkVisitor*); + + /// set a flag to define the behaviour + void setAutomaticLink(bool); + bool isAutomaticLink() const; + void dirty(); protected: + osg::ref_ptr _linker; AnimationList _animations; TargetSet _targets; bool _needToLink; + bool _automaticLink; }; } #endif diff --git a/include/osgAnimation/AnimationUpdateCallback b/include/osgAnimation/AnimationUpdateCallback new file mode 100644 index 000000000..9cb526773 --- /dev/null +++ b/include/osgAnimation/AnimationUpdateCallback @@ -0,0 +1,72 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_ANIMATION_UPDATE_CALLBACK +#define OSGANIMATION_ANIMATION_UPDATE_CALLBACK 1 + +#include +#include +#include +#include + +namespace osgAnimation +{ + + class AnimationUpdateCallbackBase : public virtual osg::Object + { + public: + virtual bool link(Channel* channel) = 0; + virtual int link(Animation* animation) = 0; + }; + + + template + class AnimationUpdateCallback : public AnimationUpdateCallbackBase, public T + { + public: + AnimationUpdateCallback() {} + AnimationUpdateCallback(const std::string& name) { T::setName(name);} + AnimationUpdateCallback(const AnimationUpdateCallback& apc,const osg::CopyOp& copyop): T(apc, copyop) {} + + META_Object(osgAnimation, AnimationUpdateCallback); + + const std::string& getName() const { return T::getName(); } + bool link(Channel* channel) { return 0; } + int link(Animation* animation) + { + if (T::getName().empty()) + { + osg::notify(osg::WARN) << "An update callback has no name, it means it could link only with \"\" named Target, often an error, discard" << std::endl; + return 0; + } + int nbLinks = 0; + for (ChannelList::iterator it = animation->getChannels().begin(); + it != animation->getChannels().end(); + ++it) + { + std::string targetName = (*it)->getTargetName(); + if (targetName == T::getName()) + { + AnimationUpdateCallbackBase* a = this; + a->link((*it).get()); + nbLinks++; + } + } + return nbLinks; + } + }; + +} + +#endif diff --git a/include/osgAnimation/Bone b/include/osgAnimation/Bone index 6fac97db2..43e01d78c 100644 --- a/include/osgAnimation/Bone +++ b/include/osgAnimation/Bone @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -10,39 +10,26 @@ * 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. -*/ + * + * Authors: + * Cedric Pinson + * Michael Platings + */ -#ifndef OSGANIMATION_BONE_H -#define OSGANIMATION_BONE_H +#ifndef OSGANIMATION_BONE +#define OSGANIMATION_BONE 1 -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include namespace osgAnimation { // A bone can't have more than one parent Bone, so sharing a part of Bone's hierarchy - // has not sense. You can share the entire hierarchie but not only a part of - class OSGANIMATION_EXPORT Bone : public osg::Transform + // makes no sense. You can share the entire hierarchy but not only a part of it. + class OSGANIMATION_EXPORT Bone : public osg::MatrixTransform { public: - typedef osg::ref_ptr PointerType; - typedef std::map BoneMap; typedef osg::Matrix MatrixType; META_Node(osgAnimation, Bone); @@ -51,230 +38,24 @@ namespace osgAnimation void setDefaultUpdateCallback(const std::string& name = ""); - struct BoneMapVisitor : public osg::NodeVisitor - { - BoneMap _map; - BoneMapVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - - META_NodeVisitor("osgAnimation","BoneMapVisitor") - - void apply(osg::Node&) { return; } - void apply(osg::Transform& node) - { - Bone* bone = dynamic_cast(&node); - if (bone) - { - _map[bone->getName()] = bone; - traverse(node); - } - } - }; - - struct FindNearestParentAnimationManager : public osg::NodeVisitor - { - osg::ref_ptr _manager; - FindNearestParentAnimationManager() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} - void apply(osg::Node& node) - { - if (_manager.valid()) - return; - osg::NodeCallback* callback = node.getUpdateCallback(); - while (callback) - { - _manager = dynamic_cast(callback); - if (_manager.valid()) - return; - callback = callback->getNestedCallback(); - } - traverse(node); - } - }; - - - class OSGANIMATION_EXPORT UpdateBone : public AnimationUpdateCallback - { - public: - osg::ref_ptr _position; - osg::ref_ptr _quaternion; - osg::ref_ptr _scale; - - public: - META_Object(osgAnimation, UpdateBone); - UpdateBone(const UpdateBone& apc,const osg::CopyOp& copyop); - - UpdateBone(const std::string& name = "") - { - setName(name); - _quaternion = new osgAnimation::QuatTarget; - _position = new osgAnimation::Vec3Target; - _scale = new osgAnimation::Vec3Target; - } - - void update(osgAnimation::Bone& bone) - { - bone.setTranslation(_position->getValue()); - bone.setRotation(_quaternion->getValue()); - bone.setScale(_scale->getValue()); - bone.dirtyBound(); - } - - bool needLink() const - { - // the idea is to return true if nothing is linked - return !((_position->getCount() + _quaternion->getCount() + _scale->getCount()) > 3); - } - - bool link(osgAnimation::Channel* channel) - { - if (channel->getName().find("quaternion") != std::string::npos) - { - osgAnimation::QuatSphericalLinearChannel* qc = dynamic_cast(channel); - if (qc) - { - qc->setTarget(_quaternion.get()); - return true; - } - } - else if (channel->getName().find("position") != std::string::npos) - { - osgAnimation::Vec3LinearChannel* vc = dynamic_cast(channel); - if (vc) - { - vc->setTarget(_position.get()); - return true; - } - } - else if (channel->getName().find("scale") != std::string::npos) - { - osgAnimation::Vec3LinearChannel* vc = dynamic_cast(channel); - if (vc) - { - vc->setTarget(_scale.get()); - return true; - } - } - else - { - std::cerr << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl; - } - return false; - } - - /** Callback method called by the NodeVisitor when visiting a node.*/ - virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) - { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) - { - Bone* b = dynamic_cast(node); - if (b && !_manager.valid()) - { - FindNearestParentAnimationManager finder; - - if (b->getParents().size() > 1) - { - osg::notify(osg::WARN) << "A Bone should not have multi parent ( " << b->getName() << " ) has parents "; - osg::notify(osg::WARN) << "( " << b->getParents()[0]->getName(); - for (int i = 1; i < (int)b->getParents().size(); i++) - osg::notify(osg::WARN) << ", " << b->getParents()[i]->getName(); - osg::notify(osg::WARN) << ")" << std::endl; - return; - } - b->getParents()[0]->accept(finder); - - if (!finder._manager.valid()) - { - osg::notify(osg::WARN) << "Warning can't update Bone, path to parent AnimationManagerBase not found" << std::endl; - return; - } - - _manager = finder._manager.get(); - } - - updateLink(); - update(*b); - } - traverse(node,nv); - } - }; - - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const; - virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const; - Bone* getBoneParent(); const Bone* getBoneParent() const; - void setTranslation(const osg::Vec3& trans) { _position = trans;} - void setRotation(const osg::Quat& quat) { _rotation = quat;} - void setScale(const osg::Vec3& scale) { _scale = scale;} - - const osg::Vec3& getTranslation() const { return _position;} - const osg::Quat& getRotation() const { return _rotation;} - osg::Matrix getMatrixInBoneSpace() const { return (osg::Matrix(getRotation())) * osg::Matrix::translate(getTranslation()) * _bindInBoneSpace;} - const osg::Matrix& getBindMatrixInBoneSpace() const { return _bindInBoneSpace; } + const osg::Matrix& getMatrixInBoneSpace() const { return getMatrix();} const osg::Matrix& getMatrixInSkeletonSpace() const { return _boneInSkeletonSpace; } const osg::Matrix& getInvBindMatrixInSkeletonSpace() const { return _invBindInSkeletonSpace;} void setMatrixInSkeletonSpace(const osg::Matrix& matrix) { _boneInSkeletonSpace = matrix; } - void setBindMatrixInBoneSpace(const osg::Matrix& matrix) - { - _bindInBoneSpace = matrix; - _needToRecomputeBindMatrix = true; - } - - inline bool needToComputeBindMatrix() { return _needToRecomputeBindMatrix;} - virtual void computeBindMatrix(); - - bool needLink() const; - - void setNeedToComputeBindMatrix(bool state) { _needToRecomputeBindMatrix = state; } - - /** Add Node to Group. - * If node is not NULL and is not contained in Group then increment its - * reference count, add it to the child list and dirty the bounding - * sphere to force it to recompute on next getBound() and return true for success. - * Otherwise return false. Scene nodes can't be added as child nodes. - */ - virtual bool addChild( Node *child ); - BoneMap getBoneMap(); - + void setInvBindMatrixInSkeletonSpace(const osg::Matrix& matrix) { _invBindInSkeletonSpace = matrix; } protected: - osg::Vec3 _position; - osg::Quat _rotation; - osg::Vec3 _scale; - - - // flag to recompute bind pose - bool _needToRecomputeBindMatrix; - // bind data - osg::Matrix _bindInBoneSpace; osg::Matrix _invBindInSkeletonSpace; // bone updated osg::Matrix _boneInSkeletonSpace; - }; - - inline bool Bone::computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const - { - if (_referenceFrame==RELATIVE_RF) - matrix.preMult(getMatrixInBoneSpace()); - else - matrix = getMatrixInBoneSpace(); - return true; - } - - - inline bool Bone::computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor*) const - { - if (_referenceFrame==RELATIVE_RF) - matrix.postMult(osg::Matrix::inverse(getMatrixInBoneSpace())); - else - matrix = osg::Matrix::inverse(getMatrixInBoneSpace()); - return true; - } - + typedef std::map > BoneMap; } #endif diff --git a/include/osgAnimation/BoneMapVisitor b/include/osgAnimation/BoneMapVisitor new file mode 100644 index 000000000..d41538493 --- /dev/null +++ b/include/osgAnimation/BoneMapVisitor @@ -0,0 +1,42 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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. + * + * Authors: + * Cedric Pinson + */ + +#ifndef OSGANIMATION_BONEMAP_VISITOR +#define OSGANIMATION_BONEMAP_VISITOR 1 + +#include +#include +#include + +namespace osgAnimation +{ + class OSGANIMATION_EXPORT BoneMapVisitor : public osg::NodeVisitor + { + public: + META_NodeVisitor("osgAnimation","BoneMapVisitor") + BoneMapVisitor(); + + void apply(osg::Node&); + void apply(osg::Transform& node); + const BoneMap& getBoneMap() const; + + protected: + BoneMap _map; + }; +} + +#endif diff --git a/include/osgAnimation/Channel b/include/osgAnimation/Channel index c2ebf79d4..a91316406 100644 --- a/include/osgAnimation/Channel +++ b/include/osgAnimation/Channel @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -10,7 +10,11 @@ * 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. -*/ + * + * Authors: + * Cedric Pinson + * Michael Platings + */ #ifndef OSGANIMATION_CHANNEL_H #define OSGANIMATION_CHANNEL_H @@ -29,11 +33,14 @@ namespace osgAnimation public: Channel(); + Channel(const Channel& channel); virtual ~Channel(); + virtual Channel* clone() const = 0; - virtual void update(float time) = 0; + virtual void update(float time, float weight, int priority) = 0; virtual void reset() = 0; virtual Target* getTarget() = 0; + virtual bool setTarget(Target*) = 0; const std::string& getName() const; void setName(const std::string& name); @@ -44,17 +51,18 @@ namespace osgAnimation const std::string& getTargetName() const; void setTargetName(const std::string& name); - float getWeight() const; - void setWeight(float w); - virtual Sampler* getSampler() = 0; virtual const Sampler* getSampler() const = 0; + // create a keyframe container from current target value + // with one key only, can be used for debug or to create + // easily a default channel from an existing one + virtual bool createKeyframeContainerFromTargetValue() = 0; + protected: std::string _targetName; std::string _name; - float _weight; }; @@ -66,8 +74,19 @@ namespace osgAnimation typedef typename SamplerType::UsingType UsingType; typedef TemplateTarget TargetType; typedef TemplateKeyframeContainer KeyframeContainerType; + Channel* clone() const { return new TemplateChannel(*this); } - TemplateChannel (SamplerType* s = 0,TargetType* target = 0) + TemplateChannel (const TemplateChannel& channel) : + Channel(channel) + { + if (channel.getTargetTyped()) + _target = new TargetType(*channel.getTargetTyped()); + + if (channel.getSamplerTyped()) + _sampler = new SamplerType(*channel.getSamplerTyped()); + } + + TemplateChannel (SamplerType* s = 0,TargetType* target = 0) { if (target) _target = target; @@ -76,20 +95,42 @@ namespace osgAnimation _sampler = s; } + virtual bool createKeyframeContainerFromTargetValue() + { + if (!_target.valid()) // no target it does not make sense to do it + { + return false; + } + + // create a key from current target value + typename KeyframeContainerType::KeyType key(0, _target->getValue()); + // recreate the keyframe container + getOrCreateSampler()->setKeyframeContainer(0); + getOrCreateSampler()->getOrCreateKeyframeContainer(); + // add the key + _sampler->getKeyframeContainerTyped()->push_back(key); + return true; + } + virtual ~TemplateChannel() {} - virtual void update(float time) + virtual void update(float time, float weight, int priority) { // skip if weight == 0 - if (_weight < 1e-4) + if (weight < 1e-4) return; typename SamplerType::UsingType value; _sampler->getValueAt(time, value); - _target->update(_weight, value); + _target->update(weight, value, priority); } virtual void reset() { _target->reset(); } virtual Target* getTarget() { return _target.get();} + virtual bool setTarget(Target* target) + { + _target = dynamic_cast(target); + return _target.get() == target; + } - SamplerType* getOrCreateSampler() + SamplerType* getOrCreateSampler() { if (!_sampler.valid()) _sampler = new SamplerType; @@ -104,6 +145,7 @@ namespace osgAnimation void setSampler(SamplerType* sampler) { _sampler = sampler; } TargetType* getTargetTyped() { return _target.get(); } + const TargetType* getTargetTyped() const { return _target.get(); } void setTarget(TargetType* target) { _target = target; } virtual float getStartTime() const { return _sampler->getStartTime(); } @@ -116,13 +158,21 @@ namespace osgAnimation typedef std::vector > ChannelList; + + typedef TemplateChannel DoubleStepChannel; + typedef TemplateChannel FloatStepChannel; + typedef TemplateChannel Vec2StepChannel; + typedef TemplateChannel Vec3StepChannel; + typedef TemplateChannel Vec4StepChannel; + typedef TemplateChannel QuatStepChannel; + typedef TemplateChannel DoubleLinearChannel; typedef TemplateChannel FloatLinearChannel; - typedef TemplateChannel Vec2LinearChannel; typedef TemplateChannel Vec3LinearChannel; typedef TemplateChannel Vec4LinearChannel; typedef TemplateChannel QuatSphericalLinearChannel; + typedef TemplateChannel MatrixLinearChannel; typedef TemplateChannel FloatCubicBezierChannel; typedef TemplateChannel DoubleCubicBezierChannel; diff --git a/include/osgAnimation/CubicBezier b/include/osgAnimation/CubicBezier index bd6da32b0..2bb514d7f 100644 --- a/include/osgAnimation/CubicBezier +++ b/include/osgAnimation/CubicBezier @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -12,38 +12,61 @@ * OpenSceneGraph Public License for more details. */ -#ifndef OSGANIMATION_CUBIC_BEZIER_H -#define OSGANIMATION_CUBIC_BEZIER_H +#ifndef OSGANIMATION_CUBIC_BEZIER +#define OSGANIMATION_CUBIC_BEZIER 1 #include #include #include -#include namespace osgAnimation { template - struct TemplateCubicBezier + class TemplateCubicBezier { - T mPoint[3]; - const T& getP0() const { return mPoint[0];} - const T& getP1() const { return mPoint[1];} - const T& getP2() const { return mPoint[2];} - TemplateCubicBezier(const T& v0, const T& v1, const T& v2) - { - mPoint[0] = v0; - mPoint[1] = v1; - mPoint[2] = v2; - } - + public: TemplateCubicBezier() {} - const T& getPosition() const { return mPoint[0];} - const T& getTangentPoint1() const { return mPoint[1];} - const T& getTangentPoint2() const { return mPoint[2];} - }; + TemplateCubicBezier(const T& p, const T& i, const T& o) : _position(p), _controlPointIn(i), _controlPointOut(o) + { + } + // Constructor with value only + TemplateCubicBezier(const T& p) : _position(p), _controlPointIn(p), _controlPointOut(p) + { + } + + const T& getPosition() const { return _position;} + const T& getControlPointIn() const { return _controlPointIn;} + const T& getControlPointOut() const { return _controlPointOut;} + + T& getPosition() { return _position;} + T& getControlPointIn() { return _controlPointIn;} + T& getControlPointOut() { return _controlPointOut;} + + void setPosition(const T& v) {_position = v;} + void setControlPointIn(const T& v) {_controlPointIn = v;} + void setControlPointOut(const T& v) {_controlPointOut = v;} + + // steaming operators. + friend std::ostream& operator << (std::ostream& output, const TemplateCubicBezier& tcb) + { + output << tcb._position << " " + << tcb._controlPointIn << " " + << tcb._controlPointOut; + return output; // to enable cascading + } + + friend std::istream& operator >> (std::istream& input, TemplateCubicBezier& tcb) + { + input >> tcb._position >> tcb._controlPointIn >> tcb._controlPointOut; + return input; + } + + protected: + T _position, _controlPointIn, _controlPointOut; + }; typedef TemplateCubicBezier FloatCubicBezier; typedef TemplateCubicBezier DoubleCubicBezier; diff --git a/include/osgAnimation/EaseMotion b/include/osgAnimation/EaseMotion index df3ae8d7f..3c55851e6 100644 --- a/include/osgAnimation/EaseMotion +++ b/include/osgAnimation/EaseMotion @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -10,10 +10,10 @@ * 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_EASE_MOTION_H -#define OSGANIMATION_EASE_MOTION_H +#ifndef OSGANIMATION_EASE_MOTION +#define OSGANIMATION_EASE_MOTION 1 #include #include @@ -21,9 +21,8 @@ #include #include -namespace osgAnimation { - - +namespace osgAnimation +{ struct OutBounceFunction { inline static void getValueAt(float t, float& result) @@ -76,14 +75,12 @@ namespace osgAnimation { } }; - /// Linear function struct LinearFunction { inline static void getValueAt(float t, float& result) { result = t;} }; - /// Quad function struct OutQuadFunction { @@ -94,46 +91,47 @@ namespace osgAnimation { { inline static void getValueAt(float t, float& result) { result = t*t;} }; + struct InOutQuadFunction { inline static void getValueAt(float t, float& result) - { - t = t * 2.0; - if (t < 1.0) + { + t *= 2.0; + if (t < 1.0) result = 0.5 * t * t; else { - t = t - 1.0; - result = - 0.5 * t * ( t - 2) - 1; + t -= 1.0; + result = - 0.5 * (t * ( t - 2) - 1); } } }; - /// Cubic function struct OutCubicFunction { inline static void getValueAt(float t, float& result) { t = t-1.0; result = t*t*t + 1;} }; + struct InCubicFunction { inline static void getValueAt(float t, float& result) { result = t*t*t;} }; + struct InOutCubicFunction { inline static void getValueAt(float t, float& result) { - t = t * 2; - if (t < 1.0) - result = 0.5 * t * t * t; + t *= 2.0f; + if (t < 1.0f) + result = 0.5f * t * t * t; else { - t = t - 2; - result = 0.5 * t * t * t + 2; + t -= 2.0f; + result = 0.5 * (t * t * t + 2.0f); } } }; - /// Quart function struct InQuartFunction { @@ -160,7 +158,191 @@ namespace osgAnimation { } }; + /// Elastic function + struct OutElasticFunction + { + inline static void getValueAt(float t, float& result) + { + result = pow(2.0f, -10.0f * t) * sinf((t - 0.3f / 4.0f) * (2.0f * osg::PI) / 0.3f) + 1.0f; + } + }; + struct InElasticFunction + { + inline static void getValueAt(float t, float& result) + { + OutElasticFunction::getValueAt(1.0f - t, result); + result = 1.0f - result; + } + }; + + struct InOutElasticFunction + { + inline static void getValueAt(float t, float& result) + { + t *= 2.0f; + if (t < 1.0f) + { + t -= 1.0f; + result = -0.5 * (1.0f * pow(2.0f, 10.0f * t) * sinf((t - 0.45f / 4.0f) * (2.0f * osg::PI) / 0.45f)); + } + else + { + t -= 1.0f; + result = pow(2.0f, -10.0f * t) * sinf((t - 0.45f / 4.0f) * (2.0f * osg::PI) / 0.45f) * 0.5f + 1.0f; + } + } + }; + + // Sine function + struct OutSineFunction + { + inline static void getValueAt(float t, float& result) + { + result = sinf(t * (osg::PI / 2.0f)); + } + }; + + struct InSineFunction + { + inline static void getValueAt(float t, float& result) + { + result = -cosf(t * (osg::PI / 2.0f)) + 1.0f; + } + }; + + struct InOutSineFunction + { + inline static void getValueAt(float t, float& result) + { + result = -0.5f * (cosf((osg::PI * t)) - 1.0f); + } + }; + + // Back function + struct OutBackFunction + { + inline static void getValueAt(float t, float& result) + { + t -= 1.0f; + result = t * t * ((1.70158 + 1.0f) * t + 1.70158) + 1.0f; + } + }; + + struct InBackFunction + { + inline static void getValueAt(float t, float& result) + { + result = t * t * ((1.70158 + 1.0f) * t - 1.70158); + } + }; + + struct InOutBackFunction + { + inline static void getValueAt(float t, float& result) + { + float s = 1.70158 * 1.525f; + t *= 2.0f; + if (t < 1.0f) + { + result = 0.5f * (t * t * ((s + 1.0f) * t - s)); + } + else + { + float p = t -= 2.0f; + result = 0.5f * ((p) * t * ((s + 1.0f) * t + s) + 2.0f); + } + } + }; + + // Circ function + struct OutCircFunction + { + inline static void getValueAt(float t, float& result) + { + t -= 1.0f; + result = sqrt(1.0f - t * t); + } + }; + + struct InCircFunction + { + inline static void getValueAt(float t, float& result) + { + result = -(sqrt(1.0f - (t * t)) - 1.0f); + } + }; + + struct InOutCircFunction + { + inline static void getValueAt(float t, float& result) + { + t *= 2.0f; + if (t < 1.0f) + { + result = -0.5f * (sqrt(1.0f - t * t) - 1.0f); + } + else + { + t -= 2.0f; + result = 0.5f * (sqrt(1 - t * t) + 1.0f); + } + } + }; + + // Expo function + struct OutExpoFunction + { + inline static void getValueAt(float t, float& result) + { + if(t == 1.0f) + { + result = 0.0f; + } + else + { + result = -powf(2.0f, -10.0f * t) + 1.0f; + } + } + }; + + struct InExpoFunction + { + inline static void getValueAt(float t, float& result) + { + if(t == 0.0f) + { + result = 0.0f; + } + else + { + result = powf(2.0f, 10.0f * (t - 1.0f)); + } + } + }; + + struct InOutExpoFunction + { + inline static void getValueAt(float t, float& result) + { + if(t == 0.0f || t == 1.0f) + { + result = 0.0f; + } + else + { + t *= 2.0f; + if(t < 1.0f) + { + result = 0.5f * powf(2.0f, 10.0f * (t - 1.0f)); + } + else + { + result = 0.5f * (-powf(2.0f, -10.0f * (t - 1.0f)) + 2.0f); + } + } + } + }; class Motion : public osg::Referenced { @@ -278,7 +460,7 @@ namespace osgAnimation { osg::notify(osg::WARN) << "CompositeMotion::getValueInNormalizedRange no Motion in the CompositeMotion, add motion to have result" << std::endl; return; } - for (MotionList::const_iterator it = _motions.begin(); it != _motions.end(); it++) + for (MotionList::const_iterator it = _motions.begin(); it != _motions.end(); ++it) { const Motion* motion = static_cast(it->get()); float durationInRange = motion->getDuration() / getDuration(); @@ -314,13 +496,35 @@ namespace osgAnimation { typedef MathMotionTemplate InQuartMotion; typedef MathMotionTemplate InOutQuartMotion; - // bounce typedef MathMotionTemplate OutBounceMotion; typedef MathMotionTemplate InBounceMotion; typedef MathMotionTemplate InOutBounceMotion; + // elastic + typedef MathMotionTemplate OutElasticMotion; + typedef MathMotionTemplate InElasticMotion; + typedef MathMotionTemplate InOutElasticMotion; + // sine + typedef MathMotionTemplate OutSineMotion; + typedef MathMotionTemplate InSineMotion; + typedef MathMotionTemplate InOutSineMotion; + + // back + typedef MathMotionTemplate OutBackMotion; + typedef MathMotionTemplate InBackMotion; + typedef MathMotionTemplate InOutBackMotion; + + // circ + typedef MathMotionTemplate OutCircMotion; + typedef MathMotionTemplate InCircMotion; + typedef MathMotionTemplate InOutCircMotion; + + // expo + typedef MathMotionTemplate OutExpoMotion; + typedef MathMotionTemplate InExpoMotion; + typedef MathMotionTemplate InOutExpoMotion; } #endif diff --git a/include/osgAnimation/FrameAction b/include/osgAnimation/FrameAction new file mode 100644 index 000000000..ae3595354 --- /dev/null +++ b/include/osgAnimation/FrameAction @@ -0,0 +1,26 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include + +namespace osgAnimation +{ + class Action; + typedef std::pair > FrameAction; +} +#endif diff --git a/include/osgAnimation/Interpolator b/include/osgAnimation/Interpolator index f50310818..a5bda3b0e 100644 --- a/include/osgAnimation/Interpolator +++ b/include/osgAnimation/Interpolator @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -10,13 +10,16 @@ * 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. -*/ + * + * Authors: + * Cedric Pinson + * Michael Platings + */ -#ifndef OSGANIMATION_INTERPOLATOR_H -#define OSGANIMATION_INTERPOLATOR_H +#ifndef OSGANIMATION_INTERPOLATOR +#define OSGANIMATION_INTERPOLATOR 1 #include -#include #include namespace osgAnimation @@ -61,6 +64,32 @@ namespace osgAnimation }; + template + class TemplateStepInterpolator : public TemplateInterpolatorBase + { + public: + + TemplateStepInterpolator() {} + void getValue(const TemplateKeyframeContainer& keyframes, float time, TYPE& result) const + { + + if (time >= keyframes.back().getTime()) + { + result = keyframes.back().getValue(); + return; + } + else if (time <= keyframes.front().getTime()) + { + result = keyframes.front().getValue(); + return; + } + + int i = getKeyIndexFromTime(keyframes,time); + result = keyframes[i].getValue(); + } + }; + + template class TemplateLinearInterpolator : public TemplateInterpolatorBase { @@ -176,14 +205,22 @@ namespace osgAnimation float t2 = t * t; TYPE v0 = keyframes[i].getValue().getPosition() * one_minus_t3; - TYPE v1 = keyframes[i].getValue().getTangentPoint1() * (3.0 * t * one_minus_t2); - TYPE v2 = keyframes[i].getValue().getTangentPoint2() * (3.0 * t2 * one_minus_t); + TYPE v1 = keyframes[i].getValue().getControlPointIn() * (3.0 * t * one_minus_t2); + TYPE v2 = keyframes[i].getValue().getControlPointOut() * (3.0 * t2 * one_minus_t); TYPE v3 = keyframes[i+1].getValue().getPosition() * (t2 * t); result = v0 + v1 + v2 + v3; } }; + typedef TemplateStepInterpolator DoubleStepInterpolator; + typedef TemplateStepInterpolator FloatStepInterpolator; + typedef TemplateStepInterpolator Vec2StepInterpolator; + typedef TemplateStepInterpolator Vec3StepInterpolator; + typedef TemplateStepInterpolator Vec3PackedStepInterpolator; + typedef TemplateStepInterpolator Vec4StepInterpolator; + typedef TemplateStepInterpolator QuatStepInterpolator; + typedef TemplateLinearInterpolator DoubleLinearInterpolator; typedef TemplateLinearInterpolator FloatLinearInterpolator; typedef TemplateLinearInterpolator Vec2LinearInterpolator; @@ -191,6 +228,7 @@ namespace osgAnimation typedef TemplateLinearInterpolator Vec3PackedLinearInterpolator; typedef TemplateLinearInterpolator Vec4LinearInterpolator; typedef TemplateSphericalLinearInterpolator QuatSphericalLinearInterpolator; + typedef TemplateLinearInterpolator MatrixLinearInterpolator; typedef TemplateCubicBezierInterpolator FloatCubicBezierInterpolator; typedef TemplateCubicBezierInterpolator DoubleCubicBezierInterpolator; diff --git a/include/osgAnimation/Keyframe b/include/osgAnimation/Keyframe index f1b57323f..c83c31746 100644 --- a/include/osgAnimation/Keyframe +++ b/include/osgAnimation/Keyframe @@ -23,6 +23,7 @@ #include #include #include +#include namespace osgAnimation { @@ -98,6 +99,9 @@ namespace osgAnimation typedef TemplateKeyframe FloatKeyframe; typedef TemplateKeyframeContainer FloatKeyframeContainer; + + typedef TemplateKeyframe DoubleKeyframe; + typedef TemplateKeyframeContainer DoubleKeyframeContainer; typedef TemplateKeyframe Vec2Keyframe; typedef TemplateKeyframeContainer Vec2KeyframeContainer; @@ -111,17 +115,24 @@ namespace osgAnimation typedef TemplateKeyframe QuatKeyframe; typedef TemplateKeyframeContainer QuatKeyframeContainer; + typedef TemplateKeyframe MatrixKeyframe; + typedef TemplateKeyframeContainer MatrixKeyframeContainer; + typedef TemplateKeyframe Vec3PackedKeyframe; typedef TemplateKeyframeContainer Vec3PackedKeyframeContainer; typedef TemplateKeyframe FloatCubicBezierKeyframe; typedef TemplateKeyframeContainer FloatCubicBezierKeyframeContainer; + typedef TemplateKeyframe DoubleCubicBezierKeyframe; typedef TemplateKeyframeContainer DoubleCubicBezierKeyframeContainer; + typedef TemplateKeyframe Vec2CubicBezierKeyframe; typedef TemplateKeyframeContainer Vec2CubicBezierKeyframeContainer; + typedef TemplateKeyframe Vec3CubicBezierKeyframe; typedef TemplateKeyframeContainer Vec3CubicBezierKeyframeContainer; + typedef TemplateKeyframe Vec4CubicBezierKeyframe; typedef TemplateKeyframeContainer Vec4CubicBezierKeyframeContainer; diff --git a/include/osgAnimation/LinkVisitor b/include/osgAnimation/LinkVisitor index 0492a4d65..de61a229f 100644 --- a/include/osgAnimation/LinkVisitor +++ b/include/osgAnimation/LinkVisitor @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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,37 +16,39 @@ #define OSGANIMATION_NODE_VISITOR_H #include +#include #include -#include namespace osgAnimation { + class AnimationUpdateCallbackBase; - struct LinkVisitor : public osg::NodeVisitor + /** This class is instancied by the AnimationManagerBase, it will link animation target to updatecallback that have the same name + */ + class OSGANIMATION_EXPORT LinkVisitor : public osg::NodeVisitor { + public: + LinkVisitor(); + + META_NodeVisitor("osgAnimation","LinkVisitor"); + + void apply(osg::Node& node); + void apply(osg::Geode& node); + + AnimationList& getAnimationList(); + void reset(); + unsigned int getNbLinkedTarget() const { return _nbLinkedTarget; } + + protected: + + void handle_stateset(osg::StateSet* stateset); + void link(osgAnimation::AnimationUpdateCallbackBase* cb); + + // animation list to link AnimationList _animations; + + // number of success link done unsigned int _nbLinkedTarget; - - LinkVisitor(Animation* animation) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _animations.push_back(animation); _nbLinkedTarget = 0;} - LinkVisitor(const AnimationList& animations) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { _animations = animations; _nbLinkedTarget = 0;} - - META_NodeVisitor("osgAnimation","LinkVisitor") - - void apply(osg::Node& node) - { - osgAnimation::AnimationUpdateCallback* cb = dynamic_cast(node.getUpdateCallback()); - if (cb) - { - int result = 0; - for (int i = 0; i < (int)_animations.size(); i++) - { - result += cb->link(_animations[i].get()); - _nbLinkedTarget += result; - } - std::cout << "LinkVisitor links " << result << " for \"" << cb->getName() << '"' << std::endl; - } - traverse(node); - } }; } diff --git a/include/osgAnimation/MorphGeometry b/include/osgAnimation/MorphGeometry new file mode 100644 index 000000000..2e350abca --- /dev/null +++ b/include/osgAnimation/MorphGeometry @@ -0,0 +1,154 @@ +/* -*-c++-*- + * Copyright (C) 2008 Cedric Pinson + * + * 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_MORPHGEOMETRY_H +#define OSGANIMATION_MORPHGEOMETRY_H + +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT MorphGeometry : public osg::Geometry + { + + public: + + enum Method { + NORMALIZED, + RELATIVE + }; + + class MorphTarget + { + protected: + osg::ref_ptr _geom; + float _weight; + public: + MorphTarget(osg::Geometry* geom, float w = 1.0) : _geom(geom), _weight(w) {} + void setWeight(float weight) { _weight = weight; } + const float getWeight() const { return _weight; } + osg::Geometry* getGeometry() { return _geom.get(); } + const osg::Geometry* getGeometry() const { return _geom.get(); } + void setGeometry(osg::Geometry* geom) { _geom = geom; } + }; + + typedef std::vector MorphTargetList; + + struct UpdateVertex : public osg::Drawable::UpdateCallback + { + virtual void update(osg::NodeVisitor*, osg::Drawable* drw) + { + MorphGeometry* geom = dynamic_cast(drw); + if (!geom) + return; + + geom->transformSoftwareMethod(); + } + }; + + MorphGeometry(); + MorphGeometry(const osg::Geometry& b); + MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + virtual osg::Object* cloneType() const { return new MorphGeometry(); } + virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MorphGeometry(*this,copyop); } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* libraryName() const { return "osgAnimation"; } + virtual const char* className() const { return "MorphGeometry"; } + + virtual void transformSoftwareMethod(); + + /** Set the morphing method. */ + void setMethod(Method method) { _method = method; } + /** Get the morphing method. */ + inline Method getMethod() const { return _method; } + + /** Set flag for morphing normals. */ + void setMorphNormals(bool morphNormals) { _morphNormals = morphNormals; } + /** Get the flag for morphing normals. */ + inline bool getMorphNormals() const { return _morphNormals; } + + /** Add a \c MorphTarget to the \c MorphGeometry. + * If \c MorphTarget is not \c NULL and is not contained in the \c MorphGeometry + * then increment its reference count, add it to the MorphTargets list and + * dirty the bounding sphere to force it to be recomputed on the next + * call to \c getBound(). + * @param morphTarget The \c MorphTarget to be added to the \c MorphGeometry. + * @param weight The weight to be added to the \c MorphGeometry. + * @return \c true for success; \c false otherwise. + */ + virtual void addMorphTarget( osg::Geometry *morphTarget, float weight = 1.0 ) { _morphTargets.push_back(MorphTarget(morphTarget, weight)); _dirty = true; } + + void setWeight(unsigned int index, float morphWeight) + { + if (index < _morphTargets.size()) + { + _morphTargets[index].setWeight(morphWeight); + dirty(); + } + } + + /** Set the MorphGeometry dirty.*/ + void dirty() { _dirty = true; } + + /** Get the list of MorphTargets.*/ + const MorphTargetList& getMorphTargetList() const { return _morphTargets; } + + /** Get the list of MorphTargets. Warning if you modify this array you will have to call dirty() */ + MorphTargetList& getMorphTargetList() { return _morphTargets; } + + /** Return the \c MorphTarget at position \c i.*/ + inline const MorphTarget& getMorphTarget( unsigned int i ) const { return _morphTargets[i]; } + + /** Return the \c MorphTarget at position \c i.*/ + inline MorphTarget& getMorphTarget( unsigned int i ) { return _morphTargets[i]; } + + protected: + /// Do we need to recalculate the morphed geometry? + bool _dirty; + + Method _method; + MorphTargetList _morphTargets; + + std::vector _positionSource; + std::vector _normalSource; + + /// Do we also morph between normals? + bool _morphNormals; + }; + + class OSGANIMATION_EXPORT UpdateMorph : public AnimationUpdateCallback + { + protected: + std::map > _weightTargets; + + public: + + META_Object(osgAnimation, UpdateMorph); + + UpdateMorph(const std::string& name = ""); + UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop); + + /** Callback method called by the NodeVisitor when visiting a node.*/ + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + bool needLink() const; + bool link(osgAnimation::Channel* channel); + }; + +} + +#endif diff --git a/include/osgAnimation/RigGeometry b/include/osgAnimation/RigGeometry index d939d81c2..ac0deea8a 100644 --- a/include/osgAnimation/RigGeometry +++ b/include/osgAnimation/RigGeometry @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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,8 +16,9 @@ #define OSGANIMATION_RIGGEOMETRY_H #include -#include #include +#include +#include #include namespace osgAnimation @@ -28,49 +29,63 @@ namespace osgAnimation public: RigGeometry(); - RigGeometry(const osg::Geometry& b); +// 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();} + void setInfluenceMap(VertexInfluenceMap* vertexInfluenceMap) { _vertexInfluenceMap = vertexInfluenceMap; } + const VertexInfluenceMap* getInfluenceMap() const { return _vertexInfluenceMap.get();} + VertexInfluenceMap* getInfluenceMap() { return _vertexInfluenceMap.get();} const Skeleton* getSkeleton() const; Skeleton* getSkeleton(); + // will be used by the update callback to init correctly the rig mesh + void setSkeleton(Skeleton*); void setNeedToComputeMatrix(bool state) { _needToComputeMatrix = state;} bool getNeedToComputeMatrix() const { return _needToComputeMatrix;} - void buildVertexSet(); - void buildTransformer(Skeleton* root); + + // this build the internal database about vertex influence and bones + void buildVertexInfluenceSet(); + const VertexInfluenceSet& getVertexInfluenceSet() const; + void computeMatrixFromRootSkeleton(); - virtual void transformSoftwareMethod(); - const osgAnimation::VertexInfluenceSet& getVertexInfluenceSet() const { return _vertexInfluenceSet;} - const std::vector& getPositionSource() const { return _positionSource;} - const std::vector& getNormalSource() const { return _normalSource;} + // set implementation of rig method + void setRigTransformImplementation(RigTransform*); + RigTransform* getRigTransformImplementation(); + + virtual void drawImplementation(osg::RenderInfo& renderInfo) const; + void update(); + + const osg::Matrix& getMatrixFromSkeletonToGeometry() const; + const osg::Matrix& getInvMatrixFromSkeletonToGeometry() const; + + osg::Geometry* getSourceGeometry(); + const osg::Geometry* getSourceGeometry() const; + void setSourceGeometry(osg::Geometry* geometry); + + void copyFrom(osg::Geometry& from); protected: + + osg::ref_ptr _geometry; + osg::ref_ptr _rigTransformImplementation; - std::vector _positionSource; - std::vector _normalSource; - - osgAnimation::VertexInfluenceSet _vertexInfluenceSet; - osg::ref_ptr _vertexInfluenceMap; - osgAnimation::TransformVertexFunctor _transformVertexes; + VertexInfluenceSet _vertexInfluenceSet; + osg::ref_ptr _vertexInfluenceMap; osg::Matrix _matrixFromSkeletonToGeometry; osg::Matrix _invMatrixFromSkeletonToGeometry; osg::observer_ptr _root; bool _needToComputeMatrix; - struct FindNearestParentSkeleton : public osg::NodeVisitor { - osg::ref_ptr _root; + osg::ref_ptr _root; FindNearestParentSkeleton() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) {} void apply(osg::Transform& node) { @@ -89,7 +104,7 @@ namespace osgAnimation RigGeometry* geom = dynamic_cast(drw); if (!geom) return; - if (!geom->getSkeleton() && !geom->getParents().empty()) + if (!geom->getSkeleton() && !geom->getParents().empty()) { FindNearestParentSkeleton finder; if (geom->getParents().size() > 1) @@ -97,9 +112,12 @@ namespace osgAnimation geom->getParents()[0]->accept(finder); if (!finder._root.valid()) + { + osg::notify(osg::WARN) << "A RigGeometry did not find a parent skeleton for RigGeomtry ( " << geom->getName() << " )" << std::endl; return; - geom->buildVertexSet(); - geom->buildTransformer(finder._root.get()); + } + geom->buildVertexInfluenceSet(); + geom->setSkeleton(finder._root.get()); } if (!geom->getSkeleton()) @@ -107,34 +125,10 @@ namespace osgAnimation if (geom->getNeedToComputeMatrix()) geom->computeMatrixFromRootSkeleton(); - geom->transformSoftwareMethod(); + + geom->update(); } }; - - /** BuildVertexTransformerVisitor is used to setup RigGeometry drawable - * throw a subgraph. - */ - struct BuildVertexTransformerVisitor : public osg::NodeVisitor - { - osg::ref_ptr _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(node.getDrawable(i)); - if (geom) - { - geom->buildVertexSet(); - geom->buildTransformer(_root.get()); - } - } - } - }; - }; } diff --git a/include/osgAnimation/RigTransform b/include/osgAnimation/RigTransform new file mode 100644 index 000000000..3c97f7e8c --- /dev/null +++ b/include/osgAnimation/RigTransform @@ -0,0 +1,36 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_RIGTRANSFORM +#define OSGANIMATION_RIGTRANSFORM 1 + +#include + +namespace osgAnimation +{ + + class RigGeometry; + + class RigTransform : public osg::Referenced + { + public: + RigTransform() {} + virtual ~RigTransform() {} + virtual void operator()(RigGeometry& geometry) {} + + }; + +} + +#endif diff --git a/include/osgAnimation/RigTransformHardware b/include/osgAnimation/RigTransformHardware new file mode 100644 index 000000000..53a0c8c92 --- /dev/null +++ b/include/osgAnimation/RigTransformHardware @@ -0,0 +1,85 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_RIG_TRANSFORM_HARDWARE +#define OSGANIMATION_RIG_TRANSFORM_HARDWARE 1 + +#include +#include +#include +#include +#include +#include + +namespace osgAnimation +{ + class RigGeometry; + + /// This class manage format for hardware skinning + class OSGANIMATION_EXPORT RigTransformHardware : public RigTransform + { + public: + typedef osg::Matrix MatrixType; + typedef osgAnimation::Bone BoneType; + typedef std::vector > BoneWeightAttribList; + typedef std::vector > BonePalette; + + typedef std::vector MatrixPalette; + struct IndexWeightEntry + { + int _boneIndex; + float _boneWeight; + IndexWeightEntry() { _boneIndex = 0; _boneWeight = 0;} + IndexWeightEntry(int index, float weight) { _boneIndex = index; _boneWeight = weight;} + int getIndex() const { return _boneIndex; } + float getWeight() const { return _boneWeight; } + }; + typedef std::vector > VertexIndexWeightList; + + RigTransformHardware(); + + osg::Vec4Array* getVertexAttrib(int index); + int getNumVertexAttrib(); + + osg::Uniform* getMatrixPaletteUniform(); + void computeMatrixPaletteUniform(const osg::Matrix& transformFromSkeletonToGeometry, const osg::Matrix& invTransformFromSkeletonToGeometry); + + int getNumBonesPerVertex() const; + int getNumVertexes() const; + + bool createPalette(int nbVertexes, BoneMap boneMap, const VertexInfluenceSet::VertexIndexToBoneWeightMap& vertexIndexToBoneWeightMap); + + virtual void operator()(RigGeometry&); + void setShader(osg::Shader*); + + protected: + + bool init(RigGeometry&); + + BoneWeightAttribList createVertexAttribList(); + osg::Uniform* createVertexUniform(); + + int _bonesPerVertex; + int _nbVertexes; + VertexIndexWeightList _vertexIndexMatrixWeightList; + BonePalette _bonePalette; + BoneWeightAttribList _boneWeightAttribArrays; + osg::ref_ptr _uniformMatrixPalette; + osg::ref_ptr _shader; + + bool _needInit; + }; +} + +#endif diff --git a/include/osgAnimation/RigTransformSoftware b/include/osgAnimation/RigTransformSoftware new file mode 100644 index 000000000..16c06c619 --- /dev/null +++ b/include/osgAnimation/RigTransformSoftware @@ -0,0 +1,172 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_RIGTRANSFORM_SOFTWARE +#define OSGANIMATION_RIGTRANSFORM_SOFTWARE 1 + +#include +#include +#include +#include +#include + +namespace osgAnimation +{ + + class RigGeometry; + + /// This class manage format for hardware skinning + class OSGANIMATION_EXPORT RigTransformSoftware : public RigTransform + { + public: + + RigTransformSoftware(); + virtual void operator()(RigGeometry&); + + + class BoneWeight + { + public: + BoneWeight(Bone* bone, float weight) : _bone(bone), _weight(weight) {} + const Bone* getBone() const { return _bone.get(); } + float getWeight() const { return _weight; } + void setWeight(float w) { _weight = w; } + protected: + osg::observer_ptr _bone; + float _weight; + }; + + typedef std::vector BoneWeightList; + typedef std::vector VertexList; + + class UniqBoneSetVertexSet + { + public: + BoneWeightList& getBones() { return _bones; } + VertexList& getVertexes() { return _vertexes; } + + void resetMatrix() + { + _result.set(0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1); + } + void accummulateMatrix(const osg::Matrix& invBindMatrix, const osg::Matrix& matrix, osg::Matrix::value_type weight) + { + osg::Matrix m = invBindMatrix * matrix; + osg::Matrix::value_type* ptr = m.ptr(); + osg::Matrix::value_type* ptrresult = _result.ptr(); + ptrresult[0] += ptr[0] * weight; + ptrresult[1] += ptr[1] * weight; + ptrresult[2] += ptr[2] * weight; + + ptrresult[4] += ptr[4] * weight; + ptrresult[5] += ptr[5] * weight; + ptrresult[6] += ptr[6] * weight; + + ptrresult[8] += ptr[8] * weight; + ptrresult[9] += ptr[9] * weight; + ptrresult[10] += ptr[10] * weight; + + ptrresult[12] += ptr[12] * weight; + ptrresult[13] += ptr[13] * weight; + ptrresult[14] += ptr[14] * weight; + } + void computeMatrixForVertexSet() + { + if (_bones.empty()) + { + osg::notify(osg::WARN) << this << " RigTransformSoftware::UniqBoneSetVertexSet no bones found" << std::endl; + _result = osg::Matrix::identity(); + return; + } + resetMatrix(); + + int size = _bones.size(); + for (int i = 0; i < size; i++) + { + const Bone* bone = _bones[i].getBone(); + if (!bone) + { + osg::notify(osg::WARN) << this << " RigTransformSoftware::computeMatrixForVertexSet Warning a bone is null, skip it" << std::endl; + continue; + } + const osg::Matrix& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace(); + const osg::Matrix& matrix = bone->getMatrixInSkeletonSpace(); + osg::Matrix::value_type w = _bones[i].getWeight(); + accummulateMatrix(invBindMatrix, matrix, w); + } + } + const osg::Matrix& getMatrix() const { return _result;} + protected: + BoneWeightList _bones; + VertexList _vertexes; + osg::Matrix _result; + }; + + + + template void compute(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst) + { + // the result of matrix mult should be cached to be used for vertexes transform and normal transform and maybe other computation + int size = _boneSetVertexSet.size(); + for (int i = 0; i < size; i++) + { + UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i]; + uniq.computeMatrixForVertexSet(); + osg::Matrix matrix = transform * uniq.getMatrix() * invTransform; + + const VertexList& vertexes = uniq.getVertexes(); + int vertexSize = vertexes.size(); + for (int j = 0; j < vertexSize; j++) + { + int idx = vertexes[j]; + dst[idx] = src[idx] * matrix; + } + } + } + + + template void computeNormal(const osg::Matrix& transform, const osg::Matrix& invTransform, const V* src, V* dst) + { + int size = _boneSetVertexSet.size(); + for (int i = 0; i < size; i++) + { + UniqBoneSetVertexSet& uniq = _boneSetVertexSet[i]; + uniq.computeMatrixForVertexSet(); + osg::Matrix matrix = transform * uniq.getMatrix() * invTransform; + + const VertexList& vertexes = uniq.getVertexes(); + int vertexSize = vertexes.size(); + for (int j = 0; j < vertexSize; j++) + { + int idx = vertexes[j]; + dst[idx] = osg::Matrix::transform3x3(src[idx],matrix); + } + } + } + + protected: + + bool init(RigGeometry&); + void initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexSetToBoneSetList& influence); + std::vector _boneSetVertexSet; + + bool _needInit; + + }; +} + +#endif diff --git a/include/osgAnimation/Sampler b/include/osgAnimation/Sampler index 1f5a66c1b..cda31b982 100644 --- a/include/osgAnimation/Sampler +++ b/include/osgAnimation/Sampler @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -10,7 +10,11 @@ * 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. -*/ + * + * Authors: + * Cedric Pinson + * Michael Platings + */ #ifndef OSGANIMATION_SAMPLER_H #define OSGANIMATION_SAMPLER_H @@ -108,12 +112,21 @@ namespace osgAnimation }; + typedef TemplateSampler DoubleStepSampler; + typedef TemplateSampler FloatStepSampler; + typedef TemplateSampler Vec2StepSampler; + typedef TemplateSampler Vec3StepSampler; + typedef TemplateSampler Vec4StepSampler; + typedef TemplateSampler QuatStepSampler; + typedef TemplateSampler DoubleLinearSampler; typedef TemplateSampler FloatLinearSampler; typedef TemplateSampler Vec2LinearSampler; typedef TemplateSampler Vec3LinearSampler; typedef TemplateSampler Vec4LinearSampler; typedef TemplateSampler QuatSphericalLinearSampler; + typedef TemplateSampler MatrixLinearSampler; + typedef TemplateSampler FloatCubicBezierSampler; typedef TemplateSampler DoubleCubicBezierSampler; typedef TemplateSampler Vec2CubicBezierSampler; diff --git a/include/osgAnimation/Skeleton b/include/osgAnimation/Skeleton index b1e69b1a5..c476e6e2c 100644 --- a/include/osgAnimation/Skeleton +++ b/include/osgAnimation/Skeleton @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -12,33 +12,36 @@ * OpenSceneGraph Public License for more details. */ -#ifndef OSGANIMATION_SKELETON_H -#define OSGANIMATION_SKELETON_H +#ifndef OSGANIMATION_SKELETON +#define OSGANIMATION_SKELETON 1 -#include -#include #include +#include namespace osgAnimation { - class OSGANIMATION_EXPORT Skeleton : public Bone + class OSGANIMATION_EXPORT Skeleton : public osg::MatrixTransform { public: META_Node(osgAnimation, Skeleton); - struct OSGANIMATION_EXPORT UpdateSkeleton : public osg::NodeCallback + class OSGANIMATION_EXPORT UpdateSkeleton : public osg::NodeCallback { + public: META_Object(osgAnimation, UpdateSkeleton); - UpdateSkeleton() {} - UpdateSkeleton(const UpdateSkeleton& us, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : osg::NodeCallback(us, copyop) {} + UpdateSkeleton(); + UpdateSkeleton(const UpdateSkeleton&, const osg::CopyOp&); virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + bool needToValidate() const; + protected: + bool _needValidate; }; - Skeleton(const Skeleton& b, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : Bone(b,copyop) {} Skeleton(); - void setDefaultUpdateCallback(void); - void computeBindMatrix() { _invBindInSkeletonSpace = osg::Matrix::inverse(_bindInBoneSpace); } + Skeleton(const Skeleton&, const osg::CopyOp&); + void setDefaultUpdateCallback(); + }; } diff --git a/include/osgAnimation/StackedMatrixElement b/include/osgAnimation/StackedMatrixElement new file mode 100644 index 000000000..1a33c7ccb --- /dev/null +++ b/include/osgAnimation/StackedMatrixElement @@ -0,0 +1,54 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_STACKED_MATRIX_ELEMENT +#define OSGANIMATION_STACKED_MATRIX_ELEMENT 1 + +#include +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT StackedMatrixElement : public StackedTransformElement + { + public: + META_Object(osgAnimation, StackedMatrixElement); + + StackedMatrixElement(); + StackedMatrixElement(const StackedMatrixElement&, const osg::CopyOp&); + StackedMatrixElement(const std::string& name, const osg::Matrix& matrix); + StackedMatrixElement(const osg::Matrix& matrix); + + void applyToMatrix(osg::Matrix& matrix) const { matrix = _matrix * matrix; } + osg::Matrix getAsMatrix() const { return _matrix; } + const osg::Matrix& getMatrix() const { return _matrix;} + void setMatrix(const osg::Matrix& matrix) { _matrix = matrix;} + bool isIdentity() const { return _matrix.isIdentity(); } + void update(); + virtual Target* getOrCreateTarget(); + virtual Target* getTarget() {return _target.get();} + virtual const Target* getTarget() const {return _target.get();} + + protected: + osg::Matrix _matrix; + osg::ref_ptr _target; + }; + +} + +#endif diff --git a/include/osgAnimation/StackedQuaternionElement b/include/osgAnimation/StackedQuaternionElement new file mode 100644 index 000000000..1384950c1 --- /dev/null +++ b/include/osgAnimation/StackedQuaternionElement @@ -0,0 +1,54 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_STACKED_QUATERNION_ELEMENT +#define OSGANIMATION_STACKED_QUATERNION_ELEMENT 1 + +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT StackedQuaternionElement : public StackedTransformElement + { + public: + META_Object(osgAnimation, StackedQuaternionElement); + + StackedQuaternionElement(); + StackedQuaternionElement(const StackedQuaternionElement&, const osg::CopyOp&); + StackedQuaternionElement(const std::string&, const osg::Quat& q = osg::Quat(0,0,0,1)); + StackedQuaternionElement(const osg::Quat&); + + void applyToMatrix(osg::Matrix& matrix) const; + osg::Matrix getAsMatrix() const; + bool isIdentity() const; + void update(); + + const osg::Quat& getQuaternion() const; + void setQuaternion(const osg::Quat&); + virtual Target* getOrCreateTarget(); + virtual Target* getTarget(); + virtual const Target* getTarget() const; + + protected: + osg::Quat _quaternion; + osg::ref_ptr _target; + }; + +} + +#endif diff --git a/include/osgAnimation/StackedRotateAxisElement b/include/osgAnimation/StackedRotateAxisElement new file mode 100644 index 000000000..d5a160869 --- /dev/null +++ b/include/osgAnimation/StackedRotateAxisElement @@ -0,0 +1,59 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_STACKED_ROTATE_AXIS_ELEMENT +#define OSGANIMATION_STACKED_ROTATE_AXIS_ELEMENT 1 + +#include +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT StackedRotateAxisElement : public StackedTransformElement + { + public: + META_Object(osgAnimation, StackedRotateAxisElement); + + StackedRotateAxisElement(); + StackedRotateAxisElement(const StackedRotateAxisElement&, const osg::CopyOp&); + StackedRotateAxisElement(const std::string& name, const osg::Vec3& axis, double angle); + StackedRotateAxisElement(const osg::Vec3& axis, double angle); + + void applyToMatrix(osg::Matrix& matrix) const; + osg::Matrix getAsMatrix() const; + bool isIdentity() const { return (_angle == 0); } + void update(); + + const osg::Vec3& getAxis() const; + const double getAngle() const; + void setAxis(const osg::Vec3&); + void setAngle(const double&); + + virtual Target* getOrCreateTarget(); + virtual Target* getTarget() {return _target.get();} + virtual const Target* getTarget() const {return _target.get();} + + protected: + osg::Vec3 _axis; + double _angle; + osg::ref_ptr _target; + }; + +} + +#endif + diff --git a/include/osgAnimation/StackedScaleElement b/include/osgAnimation/StackedScaleElement new file mode 100644 index 000000000..a36cc5be3 --- /dev/null +++ b/include/osgAnimation/StackedScaleElement @@ -0,0 +1,56 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_STACKED_SCALE_ELEMENT +#define OSGANIMATION_STACKED_SCALE_ELEMENT 1 + +#include +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT StackedScaleElement : public StackedTransformElement + { + public: + META_Object(osgAnimation, StackedScaleElement) + + StackedScaleElement(); + StackedScaleElement(const StackedScaleElement&, const osg::CopyOp&); + StackedScaleElement(const std::string& name, const osg::Vec3& scale = osg::Vec3(1,1,1)); + StackedScaleElement(const osg::Vec3& scale); + + void applyToMatrix(osg::Matrix& matrix) const; + osg::Matrix getAsMatrix() const; + bool isIdentity() const; + void update(); + const osg::Vec3& getScale() const; + void setScale(const osg::Vec3& scale); + + virtual Target* getOrCreateTarget(); + virtual Target* getTarget(); + virtual const Target* getTarget() const; + + protected: + osg::Vec3 _scale; + osg::ref_ptr _target; + }; + + +} + +#endif + diff --git a/include/osgAnimation/StackedTransform b/include/osgAnimation/StackedTransform new file mode 100644 index 000000000..59c1eed4f --- /dev/null +++ b/include/osgAnimation/StackedTransform @@ -0,0 +1,42 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_STACKED_TRANSFORM +#define OSGANIMATION_STACKED_TRANSFORM 1 + +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT StackedTransform : public osg::MixinVector > + { + public: + StackedTransform(); + StackedTransform(const StackedTransform&, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + void update(); + const osg::Matrix& getMatrix() const; + + protected: + osg::Matrix _matrix; + }; + + + +} + +#endif diff --git a/include/osgAnimation/StackedTransformElement b/include/osgAnimation/StackedTransformElement new file mode 100644 index 000000000..3a6628ff1 --- /dev/null +++ b/include/osgAnimation/StackedTransformElement @@ -0,0 +1,42 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_STACKED_TRANSFORM_ELEMENT +#define OSGANIMATION_STACKED_TRANSFORM_ELEMENT 1 + +#include +#include +#include + +namespace osgAnimation +{ + class Target; + class OSGANIMATION_EXPORT StackedTransformElement : public osg::Object + { + public: + StackedTransformElement() {} + StackedTransformElement(const StackedTransformElement& rhs, const osg::CopyOp& c) : osg::Object(rhs, c) {} + virtual void applyToMatrix(osg::Matrix& matrix) const = 0; + virtual osg::Matrix getAsMatrix() const = 0; + virtual bool isIdentity() const = 0; + virtual void update() = 0; + virtual Target* getOrCreateTarget() {return 0;} + virtual Target* getTarget() {return 0;} + virtual const Target* getTarget() const {return 0;} + }; + +} + +#endif diff --git a/include/osgAnimation/StackedTranslateElement b/include/osgAnimation/StackedTranslateElement new file mode 100644 index 000000000..9728d0bee --- /dev/null +++ b/include/osgAnimation/StackedTranslateElement @@ -0,0 +1,54 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_STACKED_TRANSLATE_ELEMENT +#define OSGANIMATION_STACKED_TRANSLATE_ELEMENT 1 + +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT StackedTranslateElement : public StackedTransformElement + { + public: + META_Object(osgAnimation, StackedTranslateElement); + + StackedTranslateElement(); + StackedTranslateElement(const StackedTranslateElement&, const osg::CopyOp&); + StackedTranslateElement(const std::string&, const osg::Vec3& translate = osg::Vec3(0,0,0)); + StackedTranslateElement(const osg::Vec3& translate); + + void applyToMatrix(osg::Matrix& matrix) const; + osg::Matrix getAsMatrix() const; + bool isIdentity() const; + void update(); + + const osg::Vec3& getTranslate() const; + void setTranslate(const osg::Vec3& ); + virtual Target* getOrCreateTarget(); + virtual Target* getTarget(); + virtual const Target* getTarget() const; + + protected: + osg::Vec3 _translate; + osg::ref_ptr _target; + }; + +} + +#endif diff --git a/include/osgAnimation/StatsHandler b/include/osgAnimation/StatsHandler new file mode 100644 index 000000000..1fc26b03b --- /dev/null +++ b/include/osgAnimation/StatsHandler @@ -0,0 +1,113 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include +#include + +namespace osgAnimation +{ +#if 0 + struct StatAction + { + + std::string _name; + osg::ref_ptr _group; + osg::ref_ptr _label; + osg::ref_ptr _graph; + osg::ref_ptr _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; + + 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 _camera; + + osg::ref_ptr _switch; + osg::ref_ptr _group; + + unsigned int _frameRateChildNum; + unsigned int _numBlocks; + double _blockMultiplier; + + float _statsWidth; + float _statsHeight; + +// std::map _actions; + }; + +} +#endif diff --git a/include/osgAnimation/StatsVisitor b/include/osgAnimation/StatsVisitor new file mode 100644 index 000000000..8b3656265 --- /dev/null +++ b/include/osgAnimation/StatsVisitor @@ -0,0 +1,53 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT StatsActionVisitor : public osgAnimation::UpdateActionVisitor + { + protected: + osg::ref_ptr _stats; + std::vector _channels; + + public: + META_ActionVisitor(osgAnimation, StatsActionVisitor); + + StatsActionVisitor(); + StatsActionVisitor(osg::Stats* stats, unsigned int frame); + void reset(); + const std::vector& getChannels() const { return _channels; } + osg::Stats* getStats() { return _stats.get(); } + void setStats(osg::Stats* stats) { _stats = stats; } + void setFrame(unsigned int frame) { _frame = frame; } + void apply(Timeline& action); + void apply(Action& action); + void apply(ActionBlendIn& action); + void apply(ActionBlendOut& action); + void apply(ActionAnimation& action); + void apply(ActionStripAnimation& action); + + }; + +} + +#endif diff --git a/include/osgAnimation/Target b/include/osgAnimation/Target index bbb40df14..4e519c01e 100644 --- a/include/osgAnimation/Target +++ b/include/osgAnimation/Target @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -34,15 +34,14 @@ namespace osgAnimation public: Target(); - virtual ~Target(); - virtual void normalize() = 0; - float getWeight() const { return _weight; } - void reset() { _weight = 0;} + virtual ~Target() {} + void reset() { _weight = 0; _priorityWeight = 0; } int getCount() const { return referenceCount(); } + float getWeight() const { return _weight; } protected: - - void addWeight(float w) { _weight += w; } float _weight; + float _priorityWeight; + int _lastPriority; }; @@ -51,75 +50,78 @@ namespace osgAnimation { public: - TemplateTarget() {} + TemplateTarget() : _target() {} TemplateTarget(const T& v) { setValue(v); } + TemplateTarget(const TemplateTarget& v) { setValue(v.getValue()); } - void update(float weight, const T& val) + inline void lerp(float t, const T& a, const T& b); + + /** + * The priority is used to detect a change of priority + * It's important to update animation target in priority + * order. eg: + * all animation with priority 1 + * all animation with priority 0 + * all animation with priority -1 + * ... + */ + void update(float weight, const T& val, int priority) { - if (!_weight) - _target = val * weight; + if (_weight || _priorityWeight) + { + if (_lastPriority != priority) + { + // change in priority + // add to weight with the same previous priority cumulated weight + _weight += _priorityWeight * (1.0 - _weight); + _priorityWeight = 0; + _lastPriority = priority; + } + + _priorityWeight += weight; + float t = (1.0 - _weight) * weight / _priorityWeight; + lerp(t, _target, val); + } else { - weight = (1.0 - _weight) * weight; - _target += val * weight; + _priorityWeight = weight; + _lastPriority = priority; + _target = val; } - addWeight(weight); } - const T& getValue() const { return _target;} + const T& getValue() const { return _target; } - void normalize() - { - float weightSummed = getWeight(); - if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1) < 1e-4) - return; - (_target) /= weightSummed; - } - - void setValue(const T& value) { _target = value;} + void setValue(const T& value) { _target = value; } protected: T _target; }; - - // Target Specialisation for Quaternions - template <> - class TemplateTarget< osg::Quat > : public Target + template + inline void TemplateTarget::lerp(float t, const T& a, const T& b) { - public: - - TemplateTarget () {} + _target = a * (1.0f - t) + b * t; + } - const osg::Quat& getValue() const { return _target;} - void update(float weight, const osg::Quat& val) - { - if (!_weight) - _target = val * weight; - else - { - weight = (1.0 - _weight) * weight; - _target += val * weight; - } - addWeight(weight); - } - - // maybe normalize could be non virtual and put on ITarget - void normalize() + template <> + inline void TemplateTarget::lerp(float t, const osg::Quat& a, const osg::Quat& b) + { + if (a.asVec4() * b.asVec4() < 0.0) { - float weightSummed = getWeight(); - if (fabs(weightSummed) < 1e-4 || fabs(weightSummed-1.0) < 1e-4) - return; - (_target) /= weightSummed; + _target = a * (1.0f - t) + b * -t; + } + else + { + _target = a * (1.0f - t) + b * t; } - void setValue(const osg::Quat& value) { _target = value;} - - protected: + osg::Quat::value_type len2 = _target.length2(); + if ( len2 != 1.0 && len2 != 0.0) + _target *= 1.0/sqrt(len2); + } - osg::Quat _target; - }; - + typedef TemplateTarget MatrixTarget; typedef TemplateTarget QuatTarget; typedef TemplateTarget Vec3Target; typedef TemplateTarget Vec4Target; diff --git a/include/osgAnimation/Timeline b/include/osgAnimation/Timeline index 51ed1fb3c..e578f2430 100644 --- a/include/osgAnimation/Timeline +++ b/include/osgAnimation/Timeline @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -12,180 +12,88 @@ * OpenSceneGraph Public License for more details. */ -#ifndef OSGANIMATION_TIMELINE_H -#define OSGANIMATION_TIMELINE_H +#ifndef OSGANIMATION_TIMELINE +#define OSGANIMATION_TIMELINE 1 #include -#include #include #include +#include #include -#include -#include +#include +#include +#include #include +#include namespace osgAnimation { - - class Action : public osg::Object + class OSGANIMATION_EXPORT Timeline : public Action { public: - class Callback : public osg::Object - { - public: - Callback(){} - Callback(const Callback&,const osg::CopyOp&) {} + Timeline(); + Timeline(const Timeline& nc,const osg::CopyOp& op = osg::CopyOp::SHALLOW_COPY); - META_Object(osgAnimation,Callback); - - virtual void operator()(Action* /*action*/) {} - - void addNestedCallback(Callback* callback) - { - if (_nested.valid()) - _nested->addNestedCallback(callback); - else - _nested = callback; - } + META_Action(osgAnimation, Timeline); - protected: - osg::ref_ptr _nested; - }; - - - typedef std::map > 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(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(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 + enum TimelineStatus { Play, Stop }; - - State _state; - }; + TimelineStatus getStatus() const { return _state; } - class Timeline : public osg::Object - { - protected: - typedef std::pair > FrameAction; typedef std::vector ActionList; typedef std::map ActionLayers; - enum State - { - Play, - Stop - }; - + 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); + + 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); + + void clearActions(); + + virtual void update(double simulationTime); + void setLastFrameEvaluated(unsigned int frame) { _previousFrameEvaluated = frame; } + + void setEvaluating(bool state) { _evaluating = state;} + void traverse(ActionVisitor& visitor); + + void setStats(osg::Stats* stats); + osg::Stats* getStats(); + void collectStats(bool state); + osgAnimation::StatsActionVisitor* getStatsVisitor(); + + const ActionLayers& getActionLayers() const { return _actions; } + + void processPendingOperation(); + void setAnimationManager(AnimationManagerBase*); + protected: + osg::observer_ptr _animationManager; ActionLayers _actions; double _lastUpdate; double _speed; unsigned int _currentFrame; - unsigned int _fps; - unsigned int _numberFrame; unsigned int _previousFrameEvaluated; - bool _loop; bool _initFirstFrame; - - State _state; + TimelineStatus _state; + + bool _collectStats; + osg::ref_ptr _stats; + osg::ref_ptr _statsVisitor; // to manage pending operation bool _evaluating; @@ -202,331 +110,9 @@ 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); - 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(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(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; - - public: - BlendIn(Animation* animation, double duration, double weight) - { - _animation = animation; - _weight = weight; - float d = duration * _fps; - setNumFrames(static_cast(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; - public: - BlendOut(Animation* animation, double duration) - { - _animation = animation; - float d = duration * _fps; - setNumFrames(static_cast(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; - }; - - - // encapsulate animation with blend in blend out for classic usage - class StripAnimation : public Action - { - protected: - typedef std::pair > 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(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.second.get()); } - const ActionAnimation* getActionAnimation() const { return _animation.get(); } - const BlendIn* getBlendIn() const { return _blendIn.get(); } - const BlendOut* getBlendOut() const { return dynamic_cast(_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(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; - FrameAction _blendOut; - osg::ref_ptr _animation; - }; - - - class RunAction : public Action::Callback - { - protected: - osg::ref_ptr _tm; - osg::ref_ptr _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 - } }; diff --git a/include/osgAnimation/TimelineAnimationManager b/include/osgAnimation/TimelineAnimationManager index 329ab9a17..68574ec5e 100644 --- a/include/osgAnimation/TimelineAnimationManager +++ b/include/osgAnimation/TimelineAnimationManager @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -10,10 +10,10 @@ * 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_ANIMATION_MANAGER_H -#define OSGANIMATION_TIMELINE_ANIMATION_MANAGER_H +#ifndef OSGANIMATION_TIMELINE_ANIMATION_MANAGER +#define OSGANIMATION_TIMELINE_ANIMATION_MANAGER 1 #include #include @@ -23,21 +23,21 @@ namespace osgAnimation { -class OSGANIMATION_EXPORT TimelineAnimationManager : public AnimationManagerBase -{ -protected: - osg::ref_ptr _timeline; + class OSGANIMATION_EXPORT TimelineAnimationManager : public AnimationManagerBase + { + protected: + osg::ref_ptr _timeline; -public: - META_Object(osgAnimation, TimelineAnimationManager); - TimelineAnimationManager(); - TimelineAnimationManager(const AnimationManagerBase& manager); - TimelineAnimationManager(const TimelineAnimationManager& nc,const osg::CopyOp&); + public: + META_Object(osgAnimation, TimelineAnimationManager); + TimelineAnimationManager(); + TimelineAnimationManager(const AnimationManagerBase& manager); + TimelineAnimationManager(const TimelineAnimationManager& nc,const osg::CopyOp&); - Timeline* getTimeline() { return _timeline.get(); } - const Timeline* getTimeline() const { return _timeline.get(); } - void update(double time); -}; + Timeline* getTimeline() { return _timeline.get(); } + const Timeline* getTimeline() const { return _timeline.get(); } + void update(double time); + }; } diff --git a/include/osgAnimation/UpdateBone b/include/osgAnimation/UpdateBone new file mode 100644 index 000000000..916b2b912 --- /dev/null +++ b/include/osgAnimation/UpdateBone @@ -0,0 +1,36 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_UPDATE_BONE +#define OSGANIMATION_UPDATE_BONE 1 + +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT UpdateBone : public UpdateMatrixTransform + { + public: + META_Object(osgAnimation, UpdateBone); + + UpdateBone(const std::string& name = ""); + UpdateBone(const UpdateBone&,const osg::CopyOp&); + void operator()(osg::Node* node, osg::NodeVisitor* nv); + }; + +} + +#endif diff --git a/include/osgAnimation/UpdateMaterial b/include/osgAnimation/UpdateMaterial new file mode 100644 index 000000000..8d9fe6a53 --- /dev/null +++ b/include/osgAnimation/UpdateMaterial @@ -0,0 +1,46 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_UPDATE_MATERIAL +#define OSGANIMATION_UPDATE_MATERIAL 1 + +#include +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT UpdateMaterial : public AnimationUpdateCallback + { + protected: + osg::ref_ptr _diffuse; + + public: + + META_Object(osgAnimation, UpdateMaterial); + + UpdateMaterial(const std::string& name = ""); + UpdateMaterial(const UpdateMaterial& apc,const osg::CopyOp& copyop); + + /** Callback method called by the NodeVisitor when visiting a node.*/ + virtual void operator () (osg::StateAttribute*, osg::NodeVisitor*); + void update(osg::Material& material); + bool link(Channel* channel); + Vec4Target* getDiffuse(); + }; +} + +#endif diff --git a/include/osgAnimation/UpdateMatrixTransform b/include/osgAnimation/UpdateMatrixTransform new file mode 100644 index 000000000..94be6b689 --- /dev/null +++ b/include/osgAnimation/UpdateMatrixTransform @@ -0,0 +1,48 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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_UPDATE_MATRIX_TRANSFORM +#define OSGANIMATION_UPDATE_MATRIX_TRANSFORM 1 + +#include +#include +#include +#include + +namespace osgAnimation +{ + + class OSGANIMATION_EXPORT UpdateMatrixTransform : public AnimationUpdateCallback + { + public: + META_Object(osgAnimation, UpdateMatrixTransform); + + UpdateMatrixTransform(const std::string& name = ""); + UpdateMatrixTransform(const UpdateMatrixTransform& apc,const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); + + // Callback method called by the NodeVisitor when visiting a node. + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + virtual bool link(osgAnimation::Channel* channel); + + StackedTransform& getStackedTransforms() { return _transforms;} + const StackedTransform& getStackedTransforms() const { return _transforms;} + + protected: + StackedTransform _transforms; + }; + +} + +#endif diff --git a/include/osgAnimation/VertexInfluence b/include/osgAnimation/VertexInfluence index 337e0d792..813cddb44 100644 --- a/include/osgAnimation/VertexInfluence +++ b/include/osgAnimation/VertexInfluence @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -12,8 +12,8 @@ * OpenSceneGraph Public License for more details. */ -#ifndef OSGANIMATION_VERTEX_INFLUENCES_H -#define OSGANIMATION_VERTEX_INFLUENCES_H +#ifndef OSGANIMATION_VERTEX_INFLUENCE +#define OSGANIMATION_VERTEX_INFLUENCE 1 #include #include @@ -38,8 +38,6 @@ namespace osgAnimation std::string _name; }; - // typedef std::map VertexInfluenceMap; - class VertexInfluenceMap : public std::map , public osg::Object { public: @@ -52,7 +50,7 @@ namespace osgAnimation // this class manage VertexInfluence database by mesh // reference bones per vertex ... - class VertexInfluenceSet + class OSGANIMATION_EXPORT VertexInfluenceSet { public: typedef std::vector BoneToVertexList; @@ -73,7 +71,7 @@ namespace osgAnimation typedef std::vector BoneWeightList; typedef std::map VertexIndexToBoneWeightMap; - class UniqVertexSetToBoneSet + class UniqVertexSetToBoneSet { public: void setBones(BoneWeightList& bones) { _bones = bones;} @@ -88,14 +86,12 @@ namespace osgAnimation typedef std::vector UniqVertexSetToBoneSetList; const UniqVertexSetToBoneSetList& getUniqVertexSetToBoneSetList() const { return _uniqVertexSetToBoneSet;} - void addVertexInfluence(const VertexInfluence& v) { _bone2Vertexes.push_back(v); } + void addVertexInfluence(const VertexInfluence& v); void buildVertex2BoneList(); void buildUniqVertexSetToBoneSetList(); - void clear() - { - _bone2Vertexes.clear(); - _uniqVertexSetToBoneSet.clear(); - } + void clear(); + + const VertexIndexToBoneWeightMap& getVertexToBoneList() const; protected: BoneToVertexList _bone2Vertexes; VertexIndexToBoneWeightMap _vertex2Bones; diff --git a/src/osgAnimation/Action.cpp b/src/osgAnimation/Action.cpp new file mode 100644 index 000000000..0c4648d8a --- /dev/null +++ b/src/osgAnimation/Action.cpp @@ -0,0 +1,83 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +Action::Action() +{ + _numberFrame = 25; + _fps = 25; + _speed = 1.0; + _loop = 1; +} +Action::Action(const Action&,const osg::CopyOp&) {} +Action::Callback* Action::getFrameCallback(unsigned int frame) +{ + if (_framesCallback.find(frame) != _framesCallback.end()) + { + return _framesCallback[frame].get(); + } + return 0; +} + +void Action::removeCallback(Callback* cb) +{ + std::vector keyToRemove; + for (FrameCallback::iterator it = _framesCallback.begin(); it != _framesCallback.end(); ++it) + { + if (it->second.get()) + { + if (it->second.get() == cb) + { + it->second = it->second->getNestedCallback(); + if (!it->second.valid()) + keyToRemove.push_back(it->first); + } + else + { + it->second->removeCallback(cb); + } + } + } + for (std::vector::iterator it = keyToRemove.begin(); it != keyToRemove.end(); ++it) + _framesCallback.erase(*it); +} + +Action::Callback* Action::getFrameCallback(double time) +{ + unsigned int frame = static_cast(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; +} diff --git a/src/osgAnimation/ActionAnimation.cpp b/src/osgAnimation/ActionAnimation.cpp new file mode 100644 index 000000000..a57a073a0 --- /dev/null +++ b/src/osgAnimation/ActionAnimation.cpp @@ -0,0 +1,32 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +ActionAnimation::ActionAnimation() {} + +ActionAnimation::ActionAnimation(const ActionAnimation& a, const osg::CopyOp& c) : Action(a,c) { _animation = a._animation;} + +ActionAnimation::ActionAnimation(Animation* animation) : _animation(animation) +{ + Action::setDuration(animation->getDuration()); + setName(animation->getName()); +} + +void ActionAnimation::updateAnimation(unsigned int frame, int priority) +{ + _animation->update(frame * 1.0/_fps, priority); +} diff --git a/src/osgAnimation/ActionBlendIn.cpp b/src/osgAnimation/ActionBlendIn.cpp new file mode 100644 index 000000000..74a532789 --- /dev/null +++ b/src/osgAnimation/ActionBlendIn.cpp @@ -0,0 +1,45 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +ActionBlendIn::ActionBlendIn() : _weight(0) {} +ActionBlendIn::ActionBlendIn(const ActionBlendIn& a, const osg::CopyOp& c) : Action(a,c) +{ + _weight = a._weight; + _animation = a._animation; +} + +ActionBlendIn::ActionBlendIn(Animation* animation, double duration, double weight) +{ + _animation = animation; + _weight = weight; + float d = duration * _fps; + setNumFrames(static_cast(floor(d)) + 1); + setName("BlendIn"); +} + +void ActionBlendIn::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; + + osg::notify(osg::DEBUG_INFO) << getName() << " BlendIn frame " << frame << " weight " << w << std::endl; + _animation->setWeight(w); +} diff --git a/src/osgAnimation/ActionBlendOut.cpp b/src/osgAnimation/ActionBlendOut.cpp new file mode 100644 index 000000000..beabcf632 --- /dev/null +++ b/src/osgAnimation/ActionBlendOut.cpp @@ -0,0 +1,41 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +ActionBlendOut::ActionBlendOut() : _weight(0) {} +ActionBlendOut::ActionBlendOut(const ActionBlendOut& a, const osg::CopyOp& c) : Action(a,c) +{ + _weight = a._weight; + _animation = a._animation; +} + +ActionBlendOut::ActionBlendOut(Animation* animation, double duration) +{ + _animation = animation; + float d = duration * _fps; + setNumFrames(static_cast(floor(d) + 1)); + _weight = 1.0; + setName("BlendOut"); +} + +void ActionBlendOut::computeWeight(unsigned int frame) +{ + double ratio = ( (frame+1) * 1.0 / (getNumFrames()) ); + double w = _weight * (1.0-ratio); + osg::notify(osg::DEBUG_INFO) << getName() << " BlendOut frame " << frame << " weight " << w << std::endl; + _animation->setWeight(w); +} diff --git a/src/osgAnimation/ActionCallback.cpp b/src/osgAnimation/ActionCallback.cpp new file mode 100644 index 000000000..2e4f2a23e --- /dev/null +++ b/src/osgAnimation/ActionCallback.cpp @@ -0,0 +1,23 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include + +void osgAnimation::RunAction::operator()(Action* action, ActionVisitor* visitor) +{ + Timeline* tm = visitor->getCurrentTimeline(); + tm->addActionNow(_action.get(), _priority); +} + diff --git a/src/osgAnimation/ActionStripAnimation.cpp b/src/osgAnimation/ActionStripAnimation.cpp new file mode 100644 index 000000000..fa2c7c448 --- /dev/null +++ b/src/osgAnimation/ActionStripAnimation.cpp @@ -0,0 +1,88 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +ActionAnimation* ActionStripAnimation::getAnimation() { return _animation.get(); } +ActionBlendIn* ActionStripAnimation::getBlendIn() { return _blendIn.get(); } +ActionBlendOut* ActionStripAnimation::getBlendOut() { return _blendOut.second.get(); } +const ActionAnimation* ActionStripAnimation::getAnimation() const { return _animation.get(); } +const ActionBlendIn* ActionStripAnimation::getBlendIn() const { return _blendIn.get(); } +const ActionBlendOut* ActionStripAnimation::getBlendOut() const { return _blendOut.second.get(); } +unsigned int ActionStripAnimation::getBlendOutStartFrame() const { return _blendOut.first; } + +unsigned int ActionStripAnimation::getLoop() const { return _animation->getLoop(); } + + +ActionStripAnimation::ActionStripAnimation(const ActionStripAnimation& a, const osg::CopyOp& c) : Action(a,c) +{ + _animation = a._animation; + _blendIn = a._blendIn; + _blendOut = a._blendOut; +} + +ActionStripAnimation::ActionStripAnimation(Animation* animation, double blendInDuration, double blendOutDuration, double blendInWeightTarget) +{ + _blendIn = new ActionBlendIn(animation, blendInDuration, blendInWeightTarget); + _animation = new ActionAnimation(animation); + unsigned int start = static_cast(floor((_animation->getDuration() - blendOutDuration) * _fps)); + _blendOut = FrameBlendOut(start, new ActionBlendOut(animation, blendOutDuration)); + setName(animation->getName() + "_Strip"); + _blendIn->setName(_animation->getName() + "_" + _blendIn->getName()); + _blendOut.second->setName(_animation->getName() + "_" + _blendOut.second->getName()); + setDuration(animation->getDuration()); +} + + +void ActionStripAnimation::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(floor((getDuration() - _blendOut.second->getDuration()) * _fps)); + _blendOut = FrameBlendOut(start, _blendOut.second); +} + +void ActionStripAnimation::traverse(ActionVisitor& visitor) +{ + if (_blendIn.valid()) + { + unsigned int f = visitor.getStackedFrameAction().back().first; + visitor.pushFrameActionOnStack(FrameAction(f,_blendIn.get())); + _blendIn->accept(visitor); + visitor.popFrameAction(); + } + if (_blendOut.second.valid()) + { + unsigned int f = visitor.getStackedFrameAction().back().first; + visitor.pushFrameActionOnStack(FrameAction(f + _blendOut.first,_blendOut.second.get())); + _blendOut.second.get()->accept(visitor); + visitor.popFrameAction(); + } + + if (_animation.valid()) + { + unsigned int f = visitor.getStackedFrameAction().back().first; + visitor.pushFrameActionOnStack(FrameAction(f,_animation.get())); + _animation->accept(visitor); + visitor.popFrameAction(); + } +} diff --git a/src/osgAnimation/ActionVisitor.cpp b/src/osgAnimation/ActionVisitor.cpp new file mode 100644 index 000000000..32f6d9002 --- /dev/null +++ b/src/osgAnimation/ActionVisitor.cpp @@ -0,0 +1,184 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include +#include +#include +#include + +using namespace osgAnimation; + +ActionVisitor::ActionVisitor() +{ + _currentLayer = 0; +} +void ActionVisitor::pushFrameActionOnStack(const FrameAction& fa) { _stackFrameAction.push_back(fa); } +void ActionVisitor::popFrameAction() { _stackFrameAction.pop_back(); } +void ActionVisitor::pushTimelineOnStack(Timeline* tm) { _stackTimeline.push_back(tm); } +void ActionVisitor::popTimeline() { _stackTimeline.pop_back(); } +void ActionVisitor::apply(Action& action) { traverse(action); } +void ActionVisitor::apply(Timeline& tm) { tm.traverse(*this); } +void ActionVisitor::apply(ActionBlendIn& action) { apply(static_cast(action));} +void ActionVisitor::apply(ActionBlendOut& action) { apply(static_cast(action)); } +void ActionVisitor::apply(ActionAnimation& action) { apply(static_cast(action)); } +void ActionVisitor::apply(ActionStripAnimation& action) { apply(static_cast(action)); } +void ActionVisitor::traverse(Action& action) +{ + action.traverse(*this); +} + +Timeline* ActionVisitor::getCurrentTimeline() +{ + if (_stackTimeline.empty()) + return 0; + return _stackTimeline.back(); +} + +UpdateActionVisitor::UpdateActionVisitor() +{ + _frame = 0; + _currentAnimationPriority = 0; +} + + +void UpdateActionVisitor::apply(Timeline& tm) +{ + _currentAnimationPriority = 0; + + tm.setEvaluating(true); + + tm.traverse(*this); + + tm.setEvaluating(false); + + tm.setLastFrameEvaluated(_frame); +} + +bool UpdateActionVisitor::isActive(Action& action) const +{ + FrameAction fa = _stackFrameAction.back(); + if (_frame < fa.first) + return false; + if (!fa.second.valid()) + return false; + + unsigned int f = getLocalFrame(); + unsigned int frameInAction; + unsigned int loopDone; + return action.evaluateFrame(f, frameInAction, loopDone); +} + +unsigned int UpdateActionVisitor::getLocalFrame() const +{ + return _frame - _stackFrameAction.back().first; +} + +void UpdateActionVisitor::apply(Action& action) +{ + if (isActive(action)) + { + 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 UpdateActionVisitor::apply(ActionBlendIn& action) +{ + if (isActive(action)) + { + unsigned int frame = getLocalFrame(); + apply(static_cast(action)); + action.computeWeight(frame); + } +} + +void UpdateActionVisitor::apply(ActionBlendOut& action) +{ + if (isActive(action)) + { + unsigned int frame = getLocalFrame(); + apply(static_cast(action)); + action.computeWeight(frame); + } +} + +void UpdateActionVisitor::apply(ActionAnimation& action) +{ + if (isActive(action)) + { + unsigned int frame = getLocalFrame(); + apply(static_cast(action)); + int pri = static_cast(_currentAnimationPriority); + _currentAnimationPriority++; + action.updateAnimation(frame, -pri); + } +} + +void UpdateActionVisitor::apply(ActionStripAnimation& action) +{ + if (isActive(action)) + { + apply(static_cast(action)); + action.traverse(*this); + } +} + + + +ClearActionVisitor::ClearActionVisitor(ClearType type) : _clearType(type) +{ +} + +void ClearActionVisitor::apply(Timeline& tm) +{ + _remove.clear(); + tm.traverse(*this); + for (int i = 0; i < (int)_remove.size(); i++) + tm.removeAction(_remove[i].get()); +} +void 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; + } +} diff --git a/src/osgAnimation/Animation.cpp b/src/osgAnimation/Animation.cpp index 5ac0c9ea4..948d94c36 100644 --- a/src/osgAnimation/Animation.cpp +++ b/src/osgAnimation/Animation.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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,13 +16,18 @@ using namespace osgAnimation; -Animation::Animation(const osgAnimation::Animation& anim, const osg::CopyOp& c) +Animation::Animation(const osgAnimation::Animation& anim, const osg::CopyOp& copyop): osg::Object(anim, copyop), + _duration(anim._duration), + _originalDuration(anim._originalDuration), + _weight(anim._weight), + _startTime(anim._startTime), + _playmode(anim._playmode) { - _duration = anim._duration; - _originalDuration = anim._originalDuration; - _weight = anim._weight; - _startTime = anim._startTime; - _playmode = anim._playmode; + const ChannelList& cl = anim.getChannels(); + for (ChannelList::const_iterator it = cl.begin(); it != cl.end(); ++it) + { + addChannel(it->get()->clone()); + } } @@ -90,7 +95,7 @@ void Animation::setWeight (float weight) _weight = weight; } -bool Animation::update (float time) +bool Animation::update (float time, int priority) { if (!_duration) // if not initialized then do it computeDuration(); @@ -128,13 +133,10 @@ bool Animation::update (float time) break; } - // 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); + (*chan)->update(t, _weight, priority); } return true; } diff --git a/src/osgAnimation/AnimationManagerBase.cpp b/src/osgAnimation/AnimationManagerBase.cpp index 6bb3f5443..166165380 100644 --- a/src/osgAnimation/AnimationManagerBase.cpp +++ b/src/osgAnimation/AnimationManagerBase.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -14,6 +14,7 @@ #include #include +#include using namespace osgAnimation; @@ -21,23 +22,27 @@ AnimationManagerBase::~AnimationManagerBase() {} AnimationManagerBase::AnimationManagerBase() { - _needToLink = false; + _needToLink = false; + _automaticLink = true; } void AnimationManagerBase::clearTargets() { - for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++) + for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); ++it) (*it).get()->reset(); } -void AnimationManagerBase::normalizeTargets() + +void AnimationManagerBase::dirty() { - for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++) - (*it).get()->normalize(); + _needToLink = true; } +void AnimationManagerBase::setAutomaticLink(bool state) { _automaticLink = state; } +bool AnimationManagerBase::isAutomaticLink() const { return _automaticLink; } + void AnimationManagerBase::operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) { if (needToLink()) { @@ -57,22 +62,30 @@ void AnimationManagerBase::operator()(osg::Node* node, osg::NodeVisitor* nv) } -AnimationManagerBase::AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop) : osg::NodeCallback(b,copyop) +AnimationManagerBase::AnimationManagerBase(const AnimationManagerBase& b, const osg::CopyOp& copyop) : osg::NodeCallback(b,copyop) { - _animations = b._animations; - _targets = b._targets; - _needToLink = b._needToLink; + const AnimationList& animationList = b.getAnimationList(); + for (AnimationList::const_iterator it = animationList.begin(); + it != animationList.end(); + ++it) + { + Animation* animation = dynamic_cast(it->get()->clone(copyop)); + _animations.push_back(animation); + } + _needToLink = true; + _automaticLink = b._automaticLink; + buildTargetReference(); } void AnimationManagerBase::buildTargetReference() { _targets.clear(); - for( AnimationList::iterator iterAnim = _animations.begin(); iterAnim != _animations.end(); ++iterAnim ) + for( AnimationList::iterator iterAnim = _animations.begin(); iterAnim != _animations.end(); ++iterAnim ) { Animation* anim = (*iterAnim).get(); for (ChannelList::iterator it = anim->getChannels().begin(); it != anim->getChannels().end(); - it++) + ++it) _targets.insert((*it)->getTarget()); } } @@ -85,14 +98,38 @@ void AnimationManagerBase::registerAnimation (Animation* animation) buildTargetReference(); } -bool AnimationManagerBase::needToLink() const { return _needToLink; } +void AnimationManagerBase::unregisterAnimation (Animation* animation) +{ + AnimationList::iterator it = std::find(_animations.begin(), _animations.end(), animation); + if (it != _animations.end()) + { + _animations.erase(it); + } + buildTargetReference(); +} + +bool AnimationManagerBase::needToLink() const { return _needToLink && isAutomaticLink(); } +void AnimationManagerBase::setLinkVisitor(LinkVisitor* visitor) +{ + _linker = visitor; +} + +LinkVisitor* AnimationManagerBase::getOrCreateLinkVisitor() +{ + if (!_linker.valid()) + _linker = new LinkVisitor; + return _linker.get(); +} void AnimationManagerBase::link(osg::Node* subgraph) { - LinkVisitor linker(_animations); - subgraph->accept(linker); + LinkVisitor* linker = getOrCreateLinkVisitor(); + linker->getAnimationList().clear(); + linker->getAnimationList() = _animations; + + subgraph->accept(*linker); _needToLink = false; buildTargetReference(); } diff --git a/src/osgAnimation/BasicAnimationManager.cpp b/src/osgAnimation/BasicAnimationManager.cpp index df438fa36..53788ab2c 100644 --- a/src/osgAnimation/BasicAnimationManager.cpp +++ b/src/osgAnimation/BasicAnimationManager.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -38,7 +38,7 @@ void BasicAnimationManager::stopAll() for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim ) { AnimationList& list = iterAnim->second; - for (AnimationList::iterator it = list.begin(); it != list.end(); it++) + for (AnimationList::iterator it = list.begin(); it != list.end(); ++it) (*it)->resetTargets(); } _animationsPlaying.clear(); @@ -47,14 +47,14 @@ void BasicAnimationManager::stopAll() void BasicAnimationManager::playAnimation(Animation* pAnimation, int priority, float weight) { if (!findAnimation(pAnimation)) - { return; - } if ( isPlaying(pAnimation) ) stopAnimation(pAnimation); _animationsPlaying[priority].push_back(pAnimation); + // for debug + //std::cout << "player Animation " << pAnimation->getName() << " at " << _lastUpdate << std::endl; pAnimation->setStartTime(_lastUpdate); pAnimation->setWeight(weight); } @@ -62,10 +62,10 @@ void BasicAnimationManager::playAnimation(Animation* pAnimation, int priority, f bool BasicAnimationManager::stopAnimation(Animation* pAnimation) { // search though the layer and remove animation - for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim ) + for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim ) { AnimationList& list = iterAnim->second; - for (AnimationList::iterator it = list.begin(); it != list.end(); it++) + for (AnimationList::iterator it = list.begin(); it != list.end(); ++it) if( (*it) == pAnimation ) { (*it)->resetTargets(); @@ -79,11 +79,10 @@ bool BasicAnimationManager::stopAnimation(Animation* pAnimation) void BasicAnimationManager::update (double time) { - if (!_lastUpdate) - _lastUpdate = time; + _lastUpdate = time; // keep time of last update // could filtered with an active flag - for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++) + for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); ++it) (*it).get()->reset(); // update from high priority to low priority @@ -91,11 +90,20 @@ void BasicAnimationManager::update (double time) { // update all animation std::vector toremove; + int priority = iterAnim->first; AnimationList& list = iterAnim->second; for (unsigned int i = 0; i < list.size(); i++) { - if (! list[i]->update(time)) + if (! list[i]->update(time, priority)) + { + // debug + // std::cout << list[i]->getName() << " finished at " << time << std::endl; toremove.push_back(i); + } else + { + // debug + //std::cout << list[i]->getName() << " updated" << std::endl; + } } // remove finished animation @@ -105,9 +113,6 @@ void BasicAnimationManager::update (double time) toremove.pop_back(); } } - - for (TargetSet::iterator it = _targets.begin(); it != _targets.end(); it++) - (*it).get()->normalize(); } @@ -127,7 +132,7 @@ bool BasicAnimationManager::isPlaying(Animation* pAnimation) for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim ) { AnimationList& list = iterAnim->second; - for (AnimationList::iterator it = list.begin(); it != list.end(); it++) + for (AnimationList::iterator it = list.begin(); it != list.end(); ++it) if ( (*it) == pAnimation ) return true; } @@ -140,7 +145,7 @@ bool BasicAnimationManager::isPlaying(const std::string& name) for( AnimationLayers::iterator iterAnim = _animationsPlaying.begin(); iterAnim != _animationsPlaying.end(); ++iterAnim ) { AnimationList& list = iterAnim->second; - for (AnimationList::iterator it = list.begin(); it != list.end(); it++) + for (AnimationList::iterator it = list.begin(); it != list.end(); ++it) if ( (*it)->getName() == name ) return true; } diff --git a/src/osgAnimation/Bone.cpp b/src/osgAnimation/Bone.cpp index 8f75a5ea1..ec50b2fa7 100644 --- a/src/osgAnimation/Bone.cpp +++ b/src/osgAnimation/Bone.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -12,36 +12,25 @@ * OpenSceneGraph Public License for more details. */ -#include #include #include +#include +#include -osgAnimation::Bone::UpdateBone::UpdateBone(const osgAnimation::Bone::UpdateBone& apc,const osg::CopyOp& copyop): - osgAnimation::AnimationUpdateCallback(apc, copyop), - _position(apc._position), - _quaternion(apc._quaternion), - _scale(apc._scale) +using namespace osgAnimation; + +Bone::Bone(const Bone& b, const osg::CopyOp& copyop) : osg::MatrixTransform(b,copyop), _invBindInSkeletonSpace(b._invBindInSkeletonSpace), _boneInSkeletonSpace(b._boneInSkeletonSpace) { } - -osgAnimation::Bone::Bone(const Bone& b, const osg::CopyOp& copyop) - : osg::Transform(b,copyop), - _position(b._position), - _rotation(b._rotation), - _scale(b._scale) -{ -} - -osgAnimation::Bone::Bone(const std::string& name) +Bone::Bone(const std::string& name) { if (!name.empty()) setName(name); - _needToRecomputeBindMatrix = false; } -void osgAnimation::Bone::setDefaultUpdateCallback(const std::string& name) +void Bone::setDefaultUpdateCallback(const std::string& name) { std::string cbName = name; if (cbName.empty()) @@ -49,42 +38,12 @@ void osgAnimation::Bone::setDefaultUpdateCallback(const std::string& name) setUpdateCallback(new UpdateBone(cbName)); } -void osgAnimation::Bone::computeBindMatrix() -{ - _invBindInSkeletonSpace = osg::Matrix::inverse(_bindInBoneSpace); - const Bone* parent = getBoneParent(); - _needToRecomputeBindMatrix = false; - if (!parent) - { -#if 0 - // no more parent means, we get the skeleton - if (getParents().empty()) { - osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl; - return; - } else if (getParents().size() > 1) { - osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you have more than one parent in a skeleton structure (" << getName() <<") unknown behaviour" << std::endl; - return; - } - osgAnimation::Skeleton* skel = dynamic_cast(getParents()[0]); - if (!skel) { - osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl; - return; - } - _invBindInSkeletonSpace = osg::Matrix::inverse(skel->getMatrix()) * _invBindInSkeletonSpace; -#else - osg::notify(osg::WARN) << "Warning " << className() <<"::computeBindMatrix you should not have this message, it means you miss to attach this bone(" << getName() <<") to a Skeleton node" << std::endl; -#endif - return; - } - _invBindInSkeletonSpace = parent->getInvBindMatrixInSkeletonSpace() * _invBindInSkeletonSpace; -} - -osgAnimation::Bone* osgAnimation::Bone::getBoneParent() +Bone* Bone::getBoneParent() { if (getParents().empty()) return 0; osg::Node::ParentList parents = getParents(); - for (osg::Node::ParentList::iterator it = parents.begin(); it != parents.end(); it++) + for (osg::Node::ParentList::iterator it = parents.begin(); it != parents.end(); ++it) { Bone* pb = dynamic_cast(*it); if (pb) @@ -92,12 +51,12 @@ osgAnimation::Bone* osgAnimation::Bone::getBoneParent() } return 0; } -const osgAnimation::Bone* osgAnimation::Bone::getBoneParent() const +const Bone* Bone::getBoneParent() const { if (getParents().empty()) return 0; const osg::Node::ParentList& parents = getParents(); - for (osg::Node::ParentList::const_iterator it = parents.begin(); it != parents.end(); it++) + for (osg::Node::ParentList::const_iterator it = parents.begin(); it != parents.end(); ++it) { const Bone* pb = dynamic_cast(*it); if (pb) @@ -105,25 +64,3 @@ const osgAnimation::Bone* osgAnimation::Bone::getBoneParent() const } return 0; } - - -/** Add Node to Group. - * If node is not NULL and is not contained in Group then increment its - * reference count, add it to the child list and dirty the bounding - * sphere to force it to recompute on next getBound() and return true for success. - * Otherwise return false. Scene nodes can't be added as child nodes. - */ -bool osgAnimation::Bone::addChild( Node *child ) -{ - Bone* bone = dynamic_cast(child); - if (bone) - bone->setNeedToComputeBindMatrix(true); - return osg::Group::addChild(child); -} - -osgAnimation::Bone::BoneMap osgAnimation::Bone::getBoneMap() -{ - BoneMapVisitor mapVisitor; - this->accept(mapVisitor); - return mapVisitor._map; -} diff --git a/src/osgAnimation/BoneMapVisitor.cpp b/src/osgAnimation/BoneMapVisitor.cpp new file mode 100644 index 000000000..befa9297f --- /dev/null +++ b/src/osgAnimation/BoneMapVisitor.cpp @@ -0,0 +1,42 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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. + * + * Authors: + * Cedric Pinson + */ + +#include +#include + +using namespace osgAnimation; + +BoneMapVisitor::BoneMapVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + +void BoneMapVisitor::apply(osg::Node&) { return; } +void BoneMapVisitor::apply(osg::Transform& node) +{ + Bone* bone = dynamic_cast(&node); + if (bone) + { + _map[bone->getName()] = bone; + traverse(node); + } + Skeleton* skeleton = dynamic_cast(&node); + if (skeleton) + traverse(node); +} + +const BoneMap& BoneMapVisitor::getBoneMap() const +{ + return _map; +} diff --git a/src/osgAnimation/CMakeLists.txt b/src/osgAnimation/CMakeLists.txt index 0c27201b0..d6315bd70 100644 --- a/src/osgAnimation/CMakeLists.txt +++ b/src/osgAnimation/CMakeLists.txt @@ -1,60 +1,108 @@ -IF (DYNAMIC_OPENSCENEGRAPH) +IF(DYNAMIC_OPENSCENEGRAPH) ADD_DEFINITIONS(-DOSGANIMATION_LIBRARY) -ELSE (DYNAMIC_OPENSCENEGRAPH) +ELSE() ADD_DEFINITIONS(-DOSG_LIBRARY_STATIC) -ENDIF(DYNAMIC_OPENSCENEGRAPH) +ENDIF() SET(LIB_NAME osgAnimation) SET(HEADER_PATH ${OpenSceneGraph_SOURCE_DIR}/include/${LIB_NAME}) SET(LIB_PUBLIC_HEADERS - ${HEADER_PATH}/Export - ${HEADER_PATH}/Bone - ${HEADER_PATH}/Skeleton - ${HEADER_PATH}/Channel - ${HEADER_PATH}/Sampler - ${HEADER_PATH}/Interpolator - ${HEADER_PATH}/Target + ${HEADER_PATH}/Action + ${HEADER_PATH}/ActionAnimation + ${HEADER_PATH}/ActionBlendIn + ${HEADER_PATH}/ActionBlendOut + ${HEADER_PATH}/ActionCallback + ${HEADER_PATH}/ActionStripAnimation + ${HEADER_PATH}/ActionVisitor ${HEADER_PATH}/Animation - ${HEADER_PATH}/Keyframe - ${HEADER_PATH}/Skinning - ${HEADER_PATH}/CubicBezier - ${HEADER_PATH}/Vec3Packed - ${HEADER_PATH}/BasicAnimationManager - ${HEADER_PATH}/TimelineAnimationManager ${HEADER_PATH}/AnimationManagerBase - ${HEADER_PATH}/UpdateCallback - ${HEADER_PATH}/LinkVisitor - ${HEADER_PATH}/VertexInfluence + ${HEADER_PATH}/AnimationUpdateCallback + ${HEADER_PATH}/BasicAnimationManager + ${HEADER_PATH}/Bone + ${HEADER_PATH}/BoneMapVisitor + ${HEADER_PATH}/Channel + ${HEADER_PATH}/CubicBezier ${HEADER_PATH}/EaseMotion - ${HEADER_PATH}/Assert - ${HEADER_PATH}/Timeline + ${HEADER_PATH}/Export + ${HEADER_PATH}/FrameAction + ${HEADER_PATH}/Interpolator + ${HEADER_PATH}/Keyframe + ${HEADER_PATH}/LinkVisitor + ${HEADER_PATH}/MorphGeometry ${HEADER_PATH}/RigGeometry + ${HEADER_PATH}/RigTransform + ${HEADER_PATH}/RigTransformHardware + ${HEADER_PATH}/RigTransformSoftware + ${HEADER_PATH}/Sampler + ${HEADER_PATH}/Skeleton + ${HEADER_PATH}/StackedMatrixElement + ${HEADER_PATH}/StackedQuaternionElement + ${HEADER_PATH}/StackedRotateAxisElement + ${HEADER_PATH}/StackedScaleElement + ${HEADER_PATH}/StackedTransformElement + ${HEADER_PATH}/StackedTranslateElement + ${HEADER_PATH}/StackedTransform + ${HEADER_PATH}/StatsVisitor + ${HEADER_PATH}/StatsHandler + ${HEADER_PATH}/Target + ${HEADER_PATH}/Timeline + ${HEADER_PATH}/TimelineAnimationManager + ${HEADER_PATH}/UpdateBone + ${HEADER_PATH}/UpdateMaterial + ${HEADER_PATH}/UpdateMatrixTransform + ${HEADER_PATH}/Vec3Packed + ${HEADER_PATH}/VertexInfluence ) ADD_LIBRARY(${LIB_NAME} ${OPENSCENEGRAPH_USER_DEFINED_DYNAMIC_OR_STATIC} ${LIB_PUBLIC_HEADERS} - Channel.cpp - Target.cpp + Action.cpp + ActionAnimation.cpp + ActionBlendIn.cpp + ActionBlendOut.cpp + ActionCallback.cpp + ActionStripAnimation.cpp + ActionVisitor.cpp Animation.cpp - Bone.cpp - RigGeometry.cpp - AnimationManager.cpp - BasicAnimationManager.cpp - TimelineAnimationManager.cpp AnimationManagerBase.cpp + BasicAnimationManager.cpp + Bone.cpp + BoneMapVisitor.cpp + Channel.cpp + LinkVisitor.cpp + MorphGeometry.cpp + RigGeometry.cpp + RigTransformHardware.cpp + RigTransformSoftware.cpp Skeleton.cpp - VertexInfluence.cpp - UpdateCallback.cpp + StackedMatrixElement.cpp + StackedQuaternionElement.cpp + StackedRotateAxisElement.cpp + StackedScaleElement.cpp + StackedTransform.cpp + StackedTranslateElement.cpp + StatsVisitor.cpp + StatsHandler.cpp + Target.cpp + TimelineAnimationManager.cpp Timeline.cpp + UpdateBone.cpp + UpdateMaterial.cpp + UpdateMatrixTransform.cpp + VertexInfluence.cpp + ${OPENSCENEGRAPH_VERSIONINFO_RC} ) LINK_INTERNAL(${LIB_NAME} osg + osgText + osgGA + osgViewer OpenThreads ) diff --git a/src/osgAnimation/Channel.cpp b/src/osgAnimation/Channel.cpp index 559d83573..ad2de93f4 100644 --- a/src/osgAnimation/Channel.cpp +++ b/src/osgAnimation/Channel.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -15,15 +15,16 @@ #include using namespace osgAnimation; -Channel::Channel() { _weight=1; } +Channel::Channel() {} Channel::~Channel() {} +Channel::Channel(const Channel& channel) : osg::Referenced(channel), + _targetName(channel._targetName), + _name(channel._name) +{ +} const std::string& Channel::getName() const { return _name; } void Channel::setName (const std::string& name) { _name = name; } const std::string& Channel::getTargetName() const { return _targetName;} void Channel::setTargetName (const std::string& name) { _targetName = name; } - -float Channel::getWeight() const { return _weight;} -void Channel::setWeight(float w) { _weight = w;} - diff --git a/src/osgAnimation/LinkVisitor.cpp b/src/osgAnimation/LinkVisitor.cpp new file mode 100644 index 000000000..1a3065dbe --- /dev/null +++ b/src/osgAnimation/LinkVisitor.cpp @@ -0,0 +1,87 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include + +using namespace osgAnimation; + +LinkVisitor::LinkVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) +{ + _nbLinkedTarget = 0; +} + +void LinkVisitor::reset() +{ + _nbLinkedTarget = 0; +} + +AnimationList& LinkVisitor::getAnimationList() +{ + return _animations; +} +void LinkVisitor::link(AnimationUpdateCallbackBase* cb) +{ + int result = 0; + for (int i = 0; i < (int)_animations.size(); i++) + { + result += cb->link(_animations[i].get()); + _nbLinkedTarget += result; + } + osg::notify(osg::NOTICE) << "LinkVisitor links " << result << " for \"" << cb->getName() << '"' << std::endl; +} + +void LinkVisitor::handle_stateset(osg::StateSet* stateset) +{ + if (!stateset) + return; + osg::StateSet::AttributeList& attr = stateset->getAttributeList(); + for (osg::StateSet::AttributeList::iterator it = attr.begin(); it != attr.end(); ++it) + { + osg::StateAttribute* sattr = it->second.first.get(); + osgAnimation::AnimationUpdateCallbackBase* cb = dynamic_cast(sattr->getUpdateCallback()); + if (cb) + link(cb); + } +} + +void LinkVisitor::apply(osg::Node& node) +{ + osg::StateSet* st = node.getStateSet(); + if (st) + handle_stateset(st); + + osg::NodeCallback* cb = node.getUpdateCallback(); + while (cb) + { + osgAnimation::AnimationUpdateCallbackBase* cba = dynamic_cast(cb); + if (cba) + link(cba); + cb = cb->getNestedCallback(); + } + traverse(node); +} + +void LinkVisitor::apply(osg::Geode& node) +{ + for (unsigned int i = 0; i < node.getNumDrawables(); i++) + { + osg::Drawable* drawable = node.getDrawable(i); + if (drawable && drawable->getStateSet()) + handle_stateset(drawable->getStateSet()); + } + apply(static_cast(node)); +} diff --git a/src/osgAnimation/MorphGeometry.cpp b/src/osgAnimation/MorphGeometry.cpp new file mode 100644 index 000000000..0961520b1 --- /dev/null +++ b/src/osgAnimation/MorphGeometry.cpp @@ -0,0 +1,277 @@ +/* -*-c++-*- + * Copyright (C) 2008 Cedric Pinson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Authors: + * + * Roland Smeenk + * Cedric Pinson + * + */ +#include +#include + +#include + +using namespace osgAnimation; + +MorphGeometry::MorphGeometry() : + _dirty(false), + _method(NORMALIZED), + _morphNormals(true) +{ + setUseDisplayList(false); + setUpdateCallback(new UpdateVertex); + setDataVariance(osg::Object::DYNAMIC); + setUseVertexBufferObjects(true); +} + +MorphGeometry::MorphGeometry(const osg::Geometry& b) : + osg::Geometry(b, osg::CopyOp::DEEP_COPY_ARRAYS), + _dirty(false), + _method(NORMALIZED), + _morphNormals(true) +{ + setUseDisplayList(false); + setUpdateCallback(new UpdateVertex); + setDataVariance(osg::Object::DYNAMIC); + setUseVertexBufferObjects(true); + if (b.getInternalOptimizedGeometry()) + computeInternalOptimizedGeometry(); +} + +MorphGeometry::MorphGeometry(const MorphGeometry& b, const osg::CopyOp& copyop) : + osg::Geometry(b,copyop), + _dirty(b._dirty), + _method(b._method), + _morphTargets(b._morphTargets), + _positionSource(b._positionSource), + _normalSource(b._normalSource), + _morphNormals(b._morphNormals) +{ + setUseDisplayList(false); + setUseVertexBufferObjects(true); + if (b.getInternalOptimizedGeometry()) + computeInternalOptimizedGeometry(); +} + +void MorphGeometry::transformSoftwareMethod() +{ + if (_dirty) + { + // See if we have an internal optimized geometry + osg::Geometry* morphGeometry = this; + if (_internalOptimizedGeometry.valid()) + morphGeometry = _internalOptimizedGeometry.get(); + + osg::Vec3Array* pos = dynamic_cast(morphGeometry->getVertexArray()); + if (pos && _positionSource.size() != pos->size()) + { + _positionSource = std::vector(pos->begin(),pos->end()); + pos->setDataVariance(osg::Object::DYNAMIC); + } + + osg::Vec3Array* normal = dynamic_cast(morphGeometry->getNormalArray()); + if (normal && _normalSource.size() != normal->size()) + { + _normalSource = std::vector(normal->begin(),normal->end()); + normal->setDataVariance(osg::Object::DYNAMIC); + } + + + if (!_positionSource.empty()) + { + bool initialized = false; + if (_method == NORMALIZED) + { + // base * 1 - (sum of weights) + sum of (weight * target) + float baseWeight = 0; + for (unsigned int i=0; i < _morphTargets.size(); i++) + { + baseWeight += _morphTargets[i].getWeight(); + } + baseWeight = 1 - baseWeight; + + if (baseWeight != 0) + { + initialized = true; + for (unsigned int i=0; i < pos->size(); i++) + { + (*pos)[i] = _positionSource[i] * baseWeight; + } + if (_morphNormals) + { + for (unsigned int i=0; i < normal->size(); i++) + { + (*normal)[i] = _normalSource[i] * baseWeight; + } + } + } + } + else //if (_method == RELATIVE) + { + // base + sum of (weight * target) + initialized = true; + for (unsigned int i=0; i < pos->size(); i++) + { + (*pos)[i] = _positionSource[i]; + } + if (_morphNormals) + { + for (unsigned int i=0; i < normal->size(); i++) + { + (*normal)[i] = _normalSource[i]; + } + } + } + + for (unsigned int i=0; i < _morphTargets.size(); i++) + { + if (_morphTargets[i].getWeight() > 0) + { + // See if any the targets use the internal optimized geometry + osg::Geometry* targetGeometry = _morphTargets[i].getGeometry()->getInternalOptimizedGeometry(); + if (!targetGeometry) + targetGeometry = _morphTargets[i].getGeometry(); + + osg::Vec3Array* targetPos = dynamic_cast(targetGeometry->getVertexArray()); + osg::Vec3Array* targetNormals = dynamic_cast(targetGeometry->getNormalArray()); + + if (initialized) + { + // If vertices are initialized, add the morphtargets + for (unsigned int j=0; j < pos->size(); j++) + { + (*pos)[j] += (*targetPos)[j] * _morphTargets[i].getWeight(); + } + + if (_morphNormals) + { + for (unsigned int j=0; j < normal->size(); j++) + { + (*normal)[j] += (*targetNormals)[j] * _morphTargets[i].getWeight(); + } + } + } + else + { + // If not initialized, initialize with this morph target + initialized = true; + for (unsigned int j=0; j < pos->size(); j++) + { + (*pos)[j] = (*targetPos)[j] * _morphTargets[i].getWeight(); + } + + if (_morphNormals) + { + for (unsigned int j=0; j < normal->size(); j++) + { + (*normal)[j] = (*targetNormals)[j] * _morphTargets[i].getWeight(); + } + } + } + } + } + + pos->dirty(); + if (_morphNormals) + { + for (unsigned int j=0; j < normal->size(); j++) + { + (*normal)[j].normalize(); + } + normal->dirty(); + } + } + + dirtyBound(); + _dirty = false; + } +} + +UpdateMorph::UpdateMorph(const UpdateMorph& apc,const osg::CopyOp& copyop) : + osg::Object(apc, copyop), + AnimationUpdateCallback(apc, copyop) +{ +} + +UpdateMorph::UpdateMorph(const std::string& name) : AnimationUpdateCallback(name) +{ +} + +/** Callback method called by the NodeVisitor when visiting a node.*/ +void UpdateMorph::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::Geode* geode = dynamic_cast(node); + if (geode) + { + unsigned int numDrawables = geode->getNumDrawables(); + for (unsigned int i = 0; i != numDrawables; ++i) + { + osgAnimation::MorphGeometry* morph = dynamic_cast(geode->getDrawable(i)); + if (morph) + { + // Update morph weights + std::map >::iterator iter = _weightTargets.begin(); + while (iter != _weightTargets.end()) + { + if (iter->second->getValue() >= 0) + { + morph->setWeight(iter->first, iter->second->getValue()); + } + ++iter; + } + } + } + } + } + traverse(node,nv); +} + + + +bool UpdateMorph::needLink() const +{ + // the idea is to return true if nothing is linked + return (_weightTargets.size() == 0); +} + +bool UpdateMorph::link(osgAnimation::Channel* channel) +{ + // Typically morph geometries only have the weights for morph targets animated + + // Expect a weight value + // TODO Should we make this more generic to handle other things than single values? + int weightIndex = atoi(channel->getName().c_str()); + + if (weightIndex >= 0) + { + osgAnimation::FloatTarget* ft = _weightTargets[weightIndex].get(); + if (!ft) + { + ft = new osgAnimation::FloatTarget; + _weightTargets[weightIndex] = ft; + } + return channel->setTarget(ft); + } + else + { + osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class" << std::endl; + } + return false; +} diff --git a/src/osgAnimation/RigGeometry.cpp b/src/osgAnimation/RigGeometry.cpp index 293ab5e52..39b4cc879 100644 --- a/src/osgAnimation/RigGeometry.cpp +++ b/src/osgAnimation/RigGeometry.cpp @@ -1,129 +1,209 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Authors: + * 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. * - * Cedric Pinson - * + * 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 #include +#include +#include +#include using namespace osgAnimation; +// The idea is to compute a bounding box with a factor x of the first step we compute the bounding box +class RigComputeBoundingBoxCallback : public osg::Drawable::ComputeBoundingBoxCallback +{ +public: + RigComputeBoundingBoxCallback(double factor = 2.0) : _computed(false), _factor(factor) {} + void reset() { _computed = false; } + virtual osg::BoundingBox computeBound(const osg::Drawable& drawable) const + { + const osgAnimation::RigGeometry& rig = dynamic_cast(drawable); + + // if a valid inital bounding box is set we use it without asking more + if (rig.getInitialBound().valid()) + return rig.getInitialBound(); + + if (_computed) + return _boundingBox; + + // if the computing of bb is invalid (like no geometry inside) + // then dont tag the bounding box as computed + osg::BoundingBox bb = rig.computeBound(); + if (!bb.valid()) + return bb; + + + _boundingBox.expandBy(bb); + osg::Vec3 center = _boundingBox.center(); + osg::Vec3 vec = (_boundingBox._max-center)*_factor; + _boundingBox.expandBy(center + vec); + _boundingBox.expandBy(center - vec); + _computed = true; +// osg::notify(osg::NOTICE) << "build the bounding box for RigGeometry " << rig.getName() << " " << _boundingBox._min << " " << _boundingBox._max << std::endl; + return _boundingBox; + } +protected: + mutable bool _computed; + double _factor; + mutable osg::BoundingBox _boundingBox; +}; + RigGeometry::RigGeometry() { - setUseDisplayList(false); + _supportsDisplayList = false; + setUseVertexBufferObjects(true); setUpdateCallback(new UpdateVertex); setDataVariance(osg::Object::DYNAMIC); _needToComputeMatrix = true; _matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity(); + + // disable the computation of boundingbox for the rig mesh + setComputeBoundingBoxCallback(new RigComputeBoundingBoxCallback); } -RigGeometry::RigGeometry(const osg::Geometry& b) : osg::Geometry(b, osg::CopyOp::SHALLOW_COPY) -{ - setUseDisplayList(false); - setUpdateCallback(new UpdateVertex); - setDataVariance(osg::Object::DYNAMIC); - _needToComputeMatrix = true; - _matrixFromSkeletonToGeometry = _invMatrixFromSkeletonToGeometry = osg::Matrix::identity(); -} -RigGeometry::RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop) : +RigGeometry::RigGeometry(const RigGeometry& b, const osg::CopyOp& copyop) : osg::Geometry(b,copyop), - _positionSource(b._positionSource), - _normalSource(b._normalSource), + _geometry(b._geometry), _vertexInfluenceSet(b._vertexInfluenceSet), _vertexInfluenceMap(b._vertexInfluenceMap), - _transformVertexes(b._transformVertexes), - _needToComputeMatrix(b._needToComputeMatrix) + _needToComputeMatrix(b._needToComputeMatrix) { + // we dont copy the RigImplementation yet. because the RigImplementation need to be initialized in a valid graph, with a skeleton ... + // dont know yet what to do with a clone of a RigGeometry } -void RigGeometry::buildTransformer(Skeleton* root) + +const osg::Matrix& RigGeometry::getMatrixFromSkeletonToGeometry() const { return _matrixFromSkeletonToGeometry; } +const osg::Matrix& RigGeometry::getInvMatrixFromSkeletonToGeometry() const { return _invMatrixFromSkeletonToGeometry;} + + +void RigGeometry::drawImplementation(osg::RenderInfo& renderInfo) const { - Bone::BoneMap bm = root->getBoneMap(); - _transformVertexes.init(bm, _vertexInfluenceSet.getUniqVertexSetToBoneSetList()); - _root = root; + osg::Geometry::drawImplementation(renderInfo); } -void RigGeometry::buildVertexSet() +void RigGeometry::buildVertexInfluenceSet() { - if (!_vertexInfluenceMap.valid()) + if (!_vertexInfluenceMap.valid()) { - osg::notify(osg::WARN) << "buildVertexSet can't be called without VertexInfluence already set to the RigGeometry ( " << getName() << " ) " << std::endl; + osg::notify(osg::WARN) << "buildVertexInfluenceSet can't be called without VertexInfluence already set to the RigGeometry ( " << getName() << " ) " << std::endl; return; } _vertexInfluenceSet.clear(); for (osgAnimation::VertexInfluenceMap::iterator it = _vertexInfluenceMap->begin(); it != _vertexInfluenceMap->end(); - it++) + ++it) _vertexInfluenceSet.addVertexInfluence(it->second); _vertexInfluenceSet.buildVertex2BoneList(); _vertexInfluenceSet.buildUniqVertexSetToBoneSetList(); - std::cout << "uniq groups " << _vertexInfluenceSet.getUniqVertexSetToBoneSetList().size() << " for " << getName() << std::endl; + osg::notify(osg::NOTICE) << "uniq groups " << _vertexInfluenceSet.getUniqVertexSetToBoneSetList().size() << " for " << getName() << std::endl; } -void RigGeometry::computeMatrixFromRootSkeleton() +void RigGeometry::computeMatrixFromRootSkeleton() { - if (!_root.valid()) + if (!_root.valid()) { osg::notify(osg::WARN) << "Warning " << className() <<"::computeMatrixFromRootSkeleton if you have this message it means you miss to call buildTransformer(Skeleton* root), or your RigGeometry (" << getName() <<") is not attached to a Skeleton subgraph" << std::endl; return; } osg::MatrixList mtxList = getParent(0)->getWorldMatrices(_root.get()); - _matrixFromSkeletonToGeometry = mtxList[0]; + osg::Matrix notRoot = _root->getMatrix(); + _matrixFromSkeletonToGeometry = mtxList[0] * osg::Matrix::inverse(notRoot); _invMatrixFromSkeletonToGeometry = osg::Matrix::inverse(_matrixFromSkeletonToGeometry); _needToComputeMatrix = false; } -void RigGeometry::transformSoftwareMethod() +void RigGeometry::update() { - setUseDisplayList(false); - setUseVertexBufferObjects(true); - - // std::cout << getName() << " _matrixFromSkeletonToGeometry" << _matrixFromSkeletonToGeometry << std::endl; - osg::Vec3Array* pos = dynamic_cast(getVertexArray()); - if (pos && _positionSource.size() != pos->size()) + if (!getRigTransformImplementation()) { - _positionSource = std::vector(pos->begin(),pos->end()); - getVertexArray()->setDataVariance(osg::Object::DYNAMIC); - } - osg::Vec3Array* normal = dynamic_cast(getNormalArray()); - if (normal && _normalSource.size() != normal->size()) - { - _normalSource = std::vector(normal->begin(),normal->end()); - getNormalArray()->setDataVariance(osg::Object::DYNAMIC); + _rigTransformImplementation = new RigTransformSoftware; } - if (!_positionSource.empty()) - { - _transformVertexes.compute(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_positionSource.front(), &pos->front()); - pos->dirty(); - } - if (!_normalSource.empty()) - { - _transformVertexes.computeNormal(_matrixFromSkeletonToGeometry, _invMatrixFromSkeletonToGeometry, &_normalSource.front(), &normal->front()); - normal->dirty(); - } - if (getUseDisplayList()) - dirtyDisplayList(); - dirtyBound(); + RigTransform& implementation = *getRigTransformImplementation(); + (implementation)(*this); } -const osgAnimation::Skeleton* RigGeometry::getSkeleton() const { return _root.get(); } -osgAnimation::Skeleton* RigGeometry::getSkeleton() { return _root.get(); } +void RigGeometry::copyFrom(osg::Geometry& from) +{ + bool copyToSelf = (this==&from); + + osg::Geometry& target = *this; + + if (!copyToSelf) target.setStateSet(from.getStateSet()); + + // copy over primitive sets. + if (!copyToSelf) target.getPrimitiveSetList() = from.getPrimitiveSetList(); + + if (from.getVertexArray()) + { + if (!copyToSelf) target.setVertexArray(from.getVertexArray()); + } + + target.setNormalBinding(from.getNormalBinding()); + if (from.getNormalArray()) + { + if (!copyToSelf) target.setNormalArray(from.getNormalArray()); + } + + target.setColorBinding(from.getColorBinding()); + if (from.getColorArray()) + { + if (!copyToSelf) target.setColorArray(from.getColorArray()); + } + + target.setSecondaryColorBinding(from.getSecondaryColorBinding()); + if (from.getSecondaryColorArray()) + { + if (!copyToSelf) target.setSecondaryColorArray(from.getSecondaryColorArray()); + } + + target.setFogCoordBinding(from.getFogCoordBinding()); + if (from.getFogCoordArray()) + { + if (!copyToSelf) target.setFogCoordArray(from.getFogCoordArray()); + } + + for(unsigned int ti=0;ti + * + * 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 +#include +#include +#include + +using namespace osgAnimation; + + +RigTransformHardware::RigTransformHardware() +{ + _needInit = true; + _bonesPerVertex = 0; + _nbVertexes = 0; +} + +osg::Vec4Array* RigTransformHardware::getVertexAttrib(int index) +{ + if (index >= (int)_boneWeightAttribArrays.size()) + return 0; + return _boneWeightAttribArrays[index].get(); +} + +int RigTransformHardware::getNumVertexAttrib() +{ + return _boneWeightAttribArrays.size(); +} + +osg::Uniform* RigTransformHardware::getMatrixPaletteUniform() +{ + return _uniformMatrixPalette.get(); +} + + +void RigTransformHardware::computeMatrixPaletteUniform(const osg::Matrix& transformFromSkeletonToGeometry, const osg::Matrix& invTransformFromSkeletonToGeometry) +{ + for (int i = 0; i < (int)_bonePalette.size(); i++) + { + osg::ref_ptr bone = _bonePalette[i].get(); + const osg::Matrix& invBindMatrix = bone->getInvBindMatrixInSkeletonSpace(); + const osg::Matrix& boneMatrix = bone->getMatrixInSkeletonSpace(); + osg::Matrix resultBoneMatrix = invBindMatrix * boneMatrix; + osg::Matrix result = transformFromSkeletonToGeometry * resultBoneMatrix * invTransformFromSkeletonToGeometry; + if (!_uniformMatrixPalette->setElement(i, result)) + osg::notify(osg::WARN) << "RigTransformHardware::computeUniformMatrixPalette can't set uniform at " << i << " elements" << std::endl; + } +} + + +int RigTransformHardware::getNumBonesPerVertex() const { return _bonesPerVertex;} +int RigTransformHardware::getNumVertexes() const { return _nbVertexes;} + +bool RigTransformHardware::createPalette(int nbVertexes, BoneMap boneMap, const VertexInfluenceSet::VertexIndexToBoneWeightMap& vertexIndexToBoneWeightMap) +{ + typedef std::map BoneNameCountMap; + typedef std::map BoneNamePaletteIndex; + BoneNamePaletteIndex bname2palette; + BonePalette palette; + BoneNameCountMap boneNameCountMap; + + // init vertex attribute data + VertexIndexWeightList vertexIndexWeight; + vertexIndexWeight.resize(nbVertexes); + + int maxBonePerVertex = 0; + for (VertexInfluenceSet::VertexIndexToBoneWeightMap::const_iterator it = vertexIndexToBoneWeightMap.begin(); it != vertexIndexToBoneWeightMap.end(); ++it) + { + int vertexIndex = it->first; + const VertexInfluenceSet::BoneWeightList& boneWeightList = it->second; + int bonesForThisVertex = 0; + for (VertexInfluenceSet::BoneWeightList::const_iterator it = boneWeightList.begin(); it != boneWeightList.end(); ++it) + { + const VertexInfluenceSet::BoneWeight& bw = *it; + if (boneNameCountMap.find(bw.getBoneName()) != boneNameCountMap.end()) + { + boneNameCountMap[bw.getBoneName()]++; + bonesForThisVertex++; // count max number of bones per vertexes + vertexIndexWeight[vertexIndex].push_back(IndexWeightEntry(bname2palette[bw.getBoneName()],bw.getWeight())); + } + else if (fabs(bw.getWeight()) > 1e-2) // dont use bone with weight too small + { + if (boneMap.find(bw.getBoneName()) == boneMap.end()) + { + osg::notify(osg::INFO) << "RigTransformHardware::createPalette can't find bone " << bw.getBoneName() << " skip this influence" << std::endl; + continue; + } + boneNameCountMap[bw.getBoneName()] = 1; // for stats + bonesForThisVertex++; + palette.push_back(boneMap[bw.getBoneName()]); + bname2palette[bw.getBoneName()] = palette.size()-1; + vertexIndexWeight[vertexIndex].push_back(IndexWeightEntry(bname2palette[bw.getBoneName()],bw.getWeight())); + } + else + { + osg::notify(osg::WARN) << "RigTransformHardware::createPalette Bone " << bw.getBoneName() << " has a weight " << bw.getWeight() << " for vertex " << vertexIndex << " this bone will not be in the palette" << std::endl; + } + } + maxBonePerVertex = osg::maximum(maxBonePerVertex, bonesForThisVertex); + } + osg::notify(osg::INFO) << "RigTransformHardware::createPalette maximum number of bone per vertex is " << maxBonePerVertex << std::endl; + osg::notify(osg::INFO) << "RigTransformHardware::createPalette matrix palette has " << boneNameCountMap.size() << " entries" << std::endl; + + for (BoneNameCountMap::iterator it = boneNameCountMap.begin(); it != boneNameCountMap.end(); ++it) + { + osg::notify(osg::INFO) << "RigTransformHardware::createPalette Bone " << it->first << " is used " << it->second << " times" << std::endl; + } + + osg::notify(osg::INFO) << "RigTransformHardware::createPalette will use " << boneNameCountMap.size() * 4 << " uniforms" << std::endl; + + + for (int i = 0 ; i < (int)vertexIndexWeight.size(); i++) + vertexIndexWeight[i].resize(maxBonePerVertex); + + _nbVertexes = nbVertexes; + _bonesPerVertex = maxBonePerVertex; + _bonePalette = palette; + _vertexIndexMatrixWeightList = vertexIndexWeight; + _uniformMatrixPalette = createVertexUniform(); + _boneWeightAttribArrays = createVertexAttribList(); + return true; +} + + +// +// create vertex attribute by 2 bones +// vec4(boneIndex0, weight0, boneIndex1, weight1) +// if more bones are needed then other attributes are created +// vec4(boneIndex2, weight2, boneIndex3, weight3) +// the idea is to use this format to have a granularity smaller +// than the 4 bones using two vertex attributes +// +RigTransformHardware::BoneWeightAttribList RigTransformHardware::createVertexAttribList() +{ + BoneWeightAttribList arrayList; + int nbArray = static_cast(ceilf(getNumBonesPerVertex() * 0.5)); + if (!nbArray) + return arrayList; + + arrayList.resize(nbArray); + for (int i = 0; i < nbArray; i++) + { + osg::ref_ptr array = new osg::Vec4Array; + arrayList[i] = array; + int nbVertexes = getNumVertexes(); + array->resize(nbVertexes); + for (int j = 0; j < nbVertexes; j++) + { + for (int b = 0; b < 2; b++) + { + // the granularity is 2 so if we have only one bone + // it's convenient to init the second with a weight 0 + int boneIndexInList = i*2 + b; + int boneIndexInVec4 = b*2; + (*array)[j][0 + boneIndexInVec4] = 0; + (*array)[j][1 + boneIndexInVec4] = 0; + if (boneIndexInList < getNumBonesPerVertex()) + { + float boneIndex = static_cast(_vertexIndexMatrixWeightList[j][boneIndexInList].getIndex()); + float boneWeight = _vertexIndexMatrixWeightList[j][boneIndexInList].getWeight(); + // fill the vec4 + (*array)[j][0 + boneIndexInVec4] = boneIndex; + (*array)[j][1 + boneIndexInVec4] = boneWeight; + } + } + } + } + return arrayList; +} + + +osg::Uniform* RigTransformHardware::createVertexUniform() +{ + osg::Uniform* uniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "matrixPalette", _bonePalette.size()); + return uniform; +} + + +void RigTransformHardware::setShader(osg::Shader* shader) +{ + _shader = shader; +} + +bool RigTransformHardware::init(RigGeometry& geom) +{ + osg::Geometry& source = *geom.getSourceGeometry(); + osg::Vec3Array* positionSrc = dynamic_cast(source.getVertexArray()); + if (!positionSrc) + { + osg::notify(osg::WARN) << "RigTransformHardware no vertex array in the geometry " << geom.getName() << std::endl; + return false; + } + + if (!geom.getSkeleton()) + { + osg::notify(osg::WARN) << "RigTransformHardware no skeleton set in geometry " << geom.getName() << std::endl; + return false; + } + + + // copy shallow from source geometry to rig + geom.copyFrom(source); + + + BoneMapVisitor mapVisitor; + geom.getSkeleton()->accept(mapVisitor); + BoneMap bm = mapVisitor.getBoneMap(); + + if (!createPalette(positionSrc->size(),bm, geom.getVertexInfluenceSet().getVertexToBoneList())) + return false; + + osg::ref_ptr program = new osg::Program; + program->setName("HardwareSkinning"); + if (!_shader.valid()) + _shader = osg::Shader::readShaderFile(osg::Shader::VERTEX,"skinning.vert"); + + if (!_shader.valid()) { + osg::notify(osg::WARN) << "RigTransformHardware can't load VertexShader" << std::endl; + return false; + } + + // replace max matrix by the value from uniform + { + std::string str = _shader->getShaderSource(); + std::string toreplace = std::string("MAX_MATRIX"); + std::size_t start = str.find(toreplace); + std::stringstream ss; + ss << getMatrixPaletteUniform()->getNumElements(); + str.replace(start, toreplace.size(), ss.str()); + _shader->setShaderSource(str); + osg::notify(osg::INFO) << "Shader " << str << std::endl; + } + + int attribIndex = 11; + int nbAttribs = getNumVertexAttrib(); + for (int i = 0; i < nbAttribs; i++) + { + std::stringstream ss; + ss << "boneWeight" << i; + program->addBindAttribLocation(ss.str(), attribIndex + i); + geom.setVertexAttribData(attribIndex + i, osg::Geometry::ArrayData(getVertexAttrib(i),osg::Geometry::BIND_PER_VERTEX)); + osg::notify(osg::INFO) << "set vertex attrib " << ss.str() << std::endl; + } + program->addShader(_shader.get()); + + osg::ref_ptr ss = new osg::StateSet; + ss->addUniform(getMatrixPaletteUniform()); + ss->addUniform(new osg::Uniform("nbBonesPerVertex", getNumBonesPerVertex())); + ss->setAttributeAndModes(program.get()); + geom.setStateSet(ss.get()); + _needInit = false; + return true; +} +void RigTransformHardware::operator()(RigGeometry& geom) +{ + if (_needInit) + if (!init(geom)) + return; + computeMatrixPaletteUniform(geom.getMatrixFromSkeletonToGeometry(), geom.getInvMatrixFromSkeletonToGeometry()); +} diff --git a/src/osgAnimation/RigTransformSoftware.cpp b/src/osgAnimation/RigTransformSoftware.cpp new file mode 100644 index 000000000..ab5566fd6 --- /dev/null +++ b/src/osgAnimation/RigTransformSoftware.cpp @@ -0,0 +1,144 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include + +using namespace osgAnimation; + +RigTransformSoftware::RigTransformSoftware() +{ + _needInit = true; +} + +bool RigTransformSoftware::init(RigGeometry& geom) +{ + if (!geom.getSkeleton()) + return false; + + BoneMapVisitor mapVisitor; + geom.getSkeleton()->accept(mapVisitor); + BoneMap bm = mapVisitor.getBoneMap(); + initVertexSetFromBones(bm, geom.getVertexInfluenceSet().getUniqVertexSetToBoneSetList()); + + if (geom.getSourceGeometry()) + geom.copyFrom(*geom.getSourceGeometry()); + geom.setVertexArray(0); + geom.setNormalArray(0); + + _needInit = false; + return true; +} + +void RigTransformSoftware::operator()(RigGeometry& geom) +{ + if (_needInit) + if (!init(geom)) + return; + + if (!geom.getSourceGeometry()) { + osg::notify(osg::WARN) << this << " RigTransformSoftware no source geometry found on RigGeometry" << std::endl; + return; + } + osg::Geometry& source = *geom.getSourceGeometry(); + osg::Geometry& destination = geom; + + osg::Vec3Array* positionSrc = dynamic_cast(source.getVertexArray()); + osg::Vec3Array* positionDst = dynamic_cast(destination.getVertexArray()); + if (positionSrc && (!positionDst || (positionDst->size() != positionSrc->size()) ) ) + { + if (!positionDst) + { + positionDst = new osg::Vec3Array; + positionDst->setDataVariance(osg::Object::DYNAMIC); + destination.setVertexArray(positionDst); + } + *positionDst = *positionSrc; + } + + osg::Vec3Array* normalSrc = dynamic_cast(source.getNormalArray()); + osg::Vec3Array* normalDst = dynamic_cast(destination.getNormalArray()); + if (normalSrc && (!normalDst || (normalDst->size() != normalSrc->size()) ) ) + { + if (!normalDst) + { + normalDst = new osg::Vec3Array; + normalDst->setDataVariance(osg::Object::DYNAMIC); + destination.setNormalArray(normalDst); + destination.setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + } + *normalDst = *normalSrc; + } + + if (positionDst && !positionDst->empty()) + { + compute(geom.getMatrixFromSkeletonToGeometry(), + geom.getInvMatrixFromSkeletonToGeometry(), + &positionSrc->front(), + &positionDst->front()); + positionDst->dirty(); + } + + if (normalDst && !normalDst->empty()) + { + computeNormal(geom.getMatrixFromSkeletonToGeometry(), + geom.getInvMatrixFromSkeletonToGeometry(), + &normalSrc->front(), + &normalDst->front()); + normalDst->dirty(); + } +} + +void RigTransformSoftware::initVertexSetFromBones(const BoneMap& map, const VertexInfluenceSet::UniqVertexSetToBoneSetList& influence) +{ + _boneSetVertexSet.clear(); + + int size = influence.size(); + _boneSetVertexSet.resize(size); + for (int i = 0; i < size; i++) + { + const VertexInfluenceSet::UniqVertexSetToBoneSet& inf = influence[i]; + int nbBones = inf.getBones().size(); + BoneWeightList& boneList = _boneSetVertexSet[i].getBones(); + + double sumOfWeight = 0; + for (int b = 0; b < nbBones; b++) + { + const std::string& bname = inf.getBones()[b].getBoneName(); + float weight = inf.getBones()[b].getWeight(); + BoneMap::const_iterator it = map.find(bname); + if (it == map.end()) + { + osg::notify(osg::WARN) << "RigTransformSoftware Bone " << bname << " not found, skip the influence group " <second.get(); + boneList.push_back(BoneWeight(bone, weight)); + sumOfWeight += weight; + } + // if a bone referenced by a vertexinfluence is missed it can make the sum less than 1.0 + // so we check it and renormalize the all weight bone + const double threshold = 1e-4; + if (!_boneSetVertexSet[i].getBones().empty() && + (sumOfWeight < 1.0 - threshold || sumOfWeight > 1.0 + threshold)) + { + for (int b = 0; b < (int)boneList.size(); b++) + boneList[b].setWeight(boneList[b].getWeight() / sumOfWeight); + } + _boneSetVertexSet[i].getVertexes() = inf.getVertexes(); + } +} diff --git a/src/osgAnimation/Skeleton.cpp b/src/osgAnimation/Skeleton.cpp index 62db25588..f08f17292 100644 --- a/src/osgAnimation/Skeleton.cpp +++ b/src/osgAnimation/Skeleton.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -14,29 +14,29 @@ #include #include +#include using namespace osgAnimation; -struct computeBindMatrixVisitor : public osg::NodeVisitor -{ - osg::Matrix _skeleton; - computeBindMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - void apply(osg::Node& node) { return ;} - void apply(osg::Transform& node) - { - Bone* bone = dynamic_cast(&node); - if (!bone) - return; - bone->computeBindMatrix(); - traverse(node); - } -}; +Skeleton::Skeleton() {} +Skeleton::Skeleton(const Skeleton& b, const osg::CopyOp& copyop) : osg::MatrixTransform(b,copyop) {} -struct updateMatrixVisitor : public osg::NodeVisitor +Skeleton::UpdateSkeleton::UpdateSkeleton() : _needValidate(true) {} +Skeleton::UpdateSkeleton::UpdateSkeleton(const UpdateSkeleton& us, const osg::CopyOp& copyop= osg::CopyOp::SHALLOW_COPY) : osg::Object(us, copyop), osg::NodeCallback(us, copyop) { - osg::Matrix _skeleton; - updateMatrixVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - void apply(osg::Node& node) { return ;} + _needValidate = true; +} +bool Skeleton::UpdateSkeleton::needToValidate() const +{ + return _needValidate; +} + + +class ValidateSkeletonVisitor : public osg::NodeVisitor +{ +public: + ValidateSkeletonVisitor(): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + void apply(osg::Node& node) { return; } void apply(osg::Transform& node) { // the idea is to traverse the skeleton or bone but to stop if other node is found @@ -44,45 +44,50 @@ struct updateMatrixVisitor : public osg::NodeVisitor if (!bone) return; - Bone* parent = bone->getBoneParent(); - if (bone->needToComputeBindMatrix()) + bool foundNonBone = false; + + for (unsigned int i = 0; i < bone->getNumChildren(); ++i) { - computeBindMatrixVisitor visitor; - bone->accept(visitor); + if (dynamic_cast(bone->getChild(i))) + { + if (foundNonBone) + { + osg::notify(osg::WARN) << + "Warning: a Bone was found after a non-Bone child " + "within a Skeleton. Children of a Bone must be ordered " + "with all child Bones first for correct update order." << std::endl; + setTraversalMode(TRAVERSE_NONE); + return; + } + } + else + { + foundNonBone = true; + } } - - if (parent) - bone->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace() * bone->getBoneParent()->getMatrixInSkeletonSpace()); - else - bone->setMatrixInSkeletonSpace(bone->getMatrixInBoneSpace()); - traverse(node); } }; void Skeleton::UpdateSkeleton::operator()(osg::Node* node, osg::NodeVisitor* nv) { - if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + if (nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) { - Skeleton* b = dynamic_cast(node); - if (b) + Skeleton* skeleton = dynamic_cast(node); + if (_needValidate && skeleton) { - // apply the updater only on the root bone, The udpateMatrixVisitor will - // traverse only bone and will update only bone. Then we continu on the classic - // process. It's important to update Bone before other things because the update - // of RigGeometry need it - updateMatrixVisitor visitor; - b->accept(visitor); + ValidateSkeletonVisitor visitor; + for (unsigned int i = 0; i < skeleton->getNumChildren(); ++i) + { + osg::Node* child = skeleton->getChild(i); + child->accept(visitor); + } + _needValidate = false; } } traverse(node,nv); } - -Skeleton::Skeleton() -{ -} - void Skeleton::setDefaultUpdateCallback() { setUpdateCallback(new Skeleton::UpdateSkeleton ); diff --git a/src/osgAnimation/StackedMatrixElement.cpp b/src/osgAnimation/StackedMatrixElement.cpp new file mode 100644 index 000000000..909ac26aa --- /dev/null +++ b/src/osgAnimation/StackedMatrixElement.cpp @@ -0,0 +1,40 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +StackedMatrixElement::StackedMatrixElement() {} +StackedMatrixElement::StackedMatrixElement(const std::string& name, const osg::Matrix& matrix) : StackedTransformElement(), _matrix(matrix) { setName(name); } +StackedMatrixElement::StackedMatrixElement(const osg::Matrix& matrix) : _matrix(matrix) { setName("matrix"); } + +StackedMatrixElement::StackedMatrixElement(const StackedMatrixElement& rhs, const osg::CopyOp& c) : StackedTransformElement(rhs, c), _matrix(rhs._matrix) +{ + if (rhs._target.valid()) + _target = new MatrixTarget(*rhs._target); +} + +Target* StackedMatrixElement::getOrCreateTarget() +{ + if (!_target.valid()) + _target = new MatrixTarget(_matrix); + return _target.get(); +} + +void StackedMatrixElement::update() +{ + if (_target.valid()) + _matrix = _target->getValue(); +} diff --git a/src/osgAnimation/StackedQuaternionElement.cpp b/src/osgAnimation/StackedQuaternionElement.cpp new file mode 100644 index 000000000..c0fb89e24 --- /dev/null +++ b/src/osgAnimation/StackedQuaternionElement.cpp @@ -0,0 +1,53 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +StackedQuaternionElement::StackedQuaternionElement(const std::string& name, const osg::Quat& quaternion) : _quaternion(quaternion) { setName(name); } + +StackedQuaternionElement::StackedQuaternionElement(const StackedQuaternionElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _quaternion(rhs._quaternion) +{ + if (rhs._target.valid()) + _target = new QuatTarget(*rhs._target); +} + + +StackedQuaternionElement::StackedQuaternionElement(const osg::Quat& quat) : _quaternion(quat) { setName("quaternion"); } + +StackedQuaternionElement::StackedQuaternionElement() +{ +} +const osg::Quat& StackedQuaternionElement::getQuaternion() const { return _quaternion; } +void StackedQuaternionElement::setQuaternion(const osg::Quat& q) { _quaternion = q; } + +void StackedQuaternionElement::applyToMatrix(osg::Matrix& matrix) const {matrix.preMultRotate(_quaternion);} +osg::Matrix StackedQuaternionElement::getAsMatrix() const { return osg::Matrix(_quaternion); } +bool StackedQuaternionElement::isIdentity() const { return (_quaternion[0] == 0 && _quaternion[1] == 0 && _quaternion[2] == 0 && _quaternion[3] == 1.0); } + +void StackedQuaternionElement::update() +{ + if (_target.valid()) + _quaternion = _target->getValue(); +} + +Target* StackedQuaternionElement::getOrCreateTarget() +{ + if (!_target.valid()) + _target = new QuatTarget(_quaternion); + return _target.get(); +} +Target* StackedQuaternionElement::getTarget() {return _target.get();} +const Target* StackedQuaternionElement::getTarget() const {return _target.get();} diff --git a/src/osgAnimation/StackedRotateAxisElement.cpp b/src/osgAnimation/StackedRotateAxisElement.cpp new file mode 100644 index 000000000..a6188601a --- /dev/null +++ b/src/osgAnimation/StackedRotateAxisElement.cpp @@ -0,0 +1,55 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +StackedRotateAxisElement::StackedRotateAxisElement(const std::string& name, const osg::Vec3& axis, double angle) : StackedTransformElement(), _axis(axis), _angle(angle) { setName(name); } +StackedRotateAxisElement::StackedRotateAxisElement(const osg::Vec3& axis, double angle) : _axis(axis), _angle(angle) { setName("rotateaxis"); } +StackedRotateAxisElement::StackedRotateAxisElement() {} +StackedRotateAxisElement::StackedRotateAxisElement(const StackedRotateAxisElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _axis(rhs._axis), _angle(rhs._angle) +{ + if (rhs._target.valid()) + _target = new FloatTarget(*rhs._target); +} + + +osg::Matrix StackedRotateAxisElement::getAsMatrix() const { return osg::Matrix::rotate(osg::Quat(_angle, _axis)); } +void StackedRotateAxisElement::update() +{ + if (_target.valid()) + _angle = _target->getValue(); +} + +const osg::Vec3& StackedRotateAxisElement::getAxis() const { return _axis; } +const double StackedRotateAxisElement::getAngle() const { return _angle; } +void StackedRotateAxisElement::setAxis(const osg::Vec3& axis) +{ + _axis = axis; +} + +void StackedRotateAxisElement::setAngle(const double& angle) +{ + _angle = angle; +} + +Target* StackedRotateAxisElement::getOrCreateTarget() +{ + if (!_target.valid()) + _target = new FloatTarget(_angle); + return _target.get(); +} + +void StackedRotateAxisElement::applyToMatrix(osg::Matrix& matrix) const { matrix.preMultRotate(osg::Quat(_angle, _axis)); } diff --git a/src/osgAnimation/StackedScaleElement.cpp b/src/osgAnimation/StackedScaleElement.cpp new file mode 100644 index 000000000..41b4dd837 --- /dev/null +++ b/src/osgAnimation/StackedScaleElement.cpp @@ -0,0 +1,56 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +StackedScaleElement::StackedScaleElement(const std::string& name, const osg::Vec3& scale) : _scale(scale) { setName(name); } +StackedScaleElement::StackedScaleElement(const osg::Vec3& scale) : _scale(scale) { setName("scale"); } + +StackedScaleElement::StackedScaleElement(const StackedScaleElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _scale(rhs._scale) +{ + if (rhs._target.valid()) + _target = new Vec3Target(*rhs._target); +} + +const osg::Vec3& StackedScaleElement::getScale() const { return _scale; } +void StackedScaleElement::setScale(const osg::Vec3& scale) { _scale = scale; } + +Target* StackedScaleElement::getTarget() {return _target.get();} +const Target* StackedScaleElement::getTarget() const {return _target.get();} + +bool StackedScaleElement::isIdentity() const { return (_scale.x() == 1 && _scale.y() == 1 && _scale.z() == 1); } + +osg::Matrix StackedScaleElement::getAsMatrix() const { return osg::Matrix::scale(_scale); } + +void StackedScaleElement::applyToMatrix(osg::Matrix& matrix) const { matrix.preMultScale(_scale); } + +StackedScaleElement::StackedScaleElement() +{ + _scale = osg::Vec3(1,1,1); +} + +void StackedScaleElement::update() +{ + if (_target.valid()) + _scale = _target->getValue(); +} + +Target* StackedScaleElement::getOrCreateTarget() +{ + if (!_target.valid()) + _target = new Vec3Target(_scale); + return _target.get(); +} diff --git a/src/osgAnimation/StackedTransform.cpp b/src/osgAnimation/StackedTransform.cpp new file mode 100644 index 000000000..eda4d7d5c --- /dev/null +++ b/src/osgAnimation/StackedTransform.cpp @@ -0,0 +1,66 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + +StackedTransform::StackedTransform() {} + +StackedTransform::StackedTransform(const StackedTransform& rhs, const osg::CopyOp& co) +{ + reserve(rhs.size()); + for (StackedTransform::const_iterator it = rhs.begin(); it != rhs.end(); ++it) + { + const StackedTransformElement* element = it->get(); + if (element) + push_back(osg::clone(element,co)); + } +} + + +void StackedTransform::update() +{ + int dirty = 0; + for (StackedTransform::iterator it = begin(); it != end(); ++it) + { + + StackedTransformElement* element = it->get(); + if (!element) + continue; + // update and check if there are changes + element->update(); + if (element->isIdentity()) + continue; + dirty++; + } + if (!dirty) + return; + + + // dirty update matrix + _matrix.makeIdentity(); + for (StackedTransform::iterator it = begin(); it != end(); ++it) + { + StackedTransformElement* element = it->get(); + if (!element || element->isIdentity()) + continue; + element->applyToMatrix(_matrix); + } +} + +const osg::Matrix& StackedTransform::getMatrix() const +{ + return _matrix; +} diff --git a/src/osgAnimation/StackedTranslateElement.cpp b/src/osgAnimation/StackedTranslateElement.cpp new file mode 100644 index 000000000..f88710e11 --- /dev/null +++ b/src/osgAnimation/StackedTranslateElement.cpp @@ -0,0 +1,50 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 + +using namespace osgAnimation; + + +StackedTranslateElement::StackedTranslateElement(const std::string& name, const osg::Vec3& translate) : _translate(translate) { setName(name); } +StackedTranslateElement::StackedTranslateElement(const osg::Vec3& translate) : _translate(translate) { setName("translate"); } + + +StackedTranslateElement::StackedTranslateElement() {} +StackedTranslateElement::StackedTranslateElement(const StackedTranslateElement& rhs, const osg::CopyOp&) : StackedTransformElement(rhs), _translate(rhs._translate) +{ + if (rhs._target.valid()) + _target = new Vec3Target(*rhs._target); +} + +void StackedTranslateElement::applyToMatrix(osg::Matrix& matrix) const {matrix.preMultTranslate(_translate);} +osg::Matrix StackedTranslateElement::getAsMatrix() const { return osg::Matrix::translate(_translate); } +bool StackedTranslateElement::isIdentity() const { return (_translate[0] == 0 && _translate[1] == 0 && _translate[2] == 0); } +const osg::Vec3& StackedTranslateElement::getTranslate() const { return _translate; } +void StackedTranslateElement::setTranslate(const osg::Vec3& value) { _translate = value; } + +Target* StackedTranslateElement::getOrCreateTarget() +{ + if (!_target.valid()) + _target = new Vec3Target(_translate); + return _target.get(); +} +Target* StackedTranslateElement::getTarget() {return _target.get();} +const Target* StackedTranslateElement::getTarget() const {return _target.get();} + +void StackedTranslateElement::update() +{ + if (_target.valid()) + _translate = _target->getValue(); +} diff --git a/src/osgAnimation/StatsHandler.cpp b/src/osgAnimation/StatsHandler.cpp new file mode 100644 index 000000000..60093b12c --- /dev/null +++ b/src/osgAnimation/StatsHandler.cpp @@ -0,0 +1,722 @@ +/* -*-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 +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static unsigned int getRandomValueinRange(unsigned int v) +{ + return static_cast((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 _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(drawable->asGeometry()); + if (!geometry) return; + osg::Vec3Array* vertices = dynamic_cast(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(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 _stats; + std::string _attributeName; + mutable char _tmpText[128]; + mutable int _frameNumber; +}; + + + + + + struct StatAction + { + double _lastTime; + std::string _name; + osg::ref_ptr _group; + osg::ref_ptr _label; + osg::ref_ptr _graph; + osg::ref_ptr _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 _background; + osg::ref_ptr _timeline; + osg::ref_ptr _group; + std::map _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 stats = _timeline->getStats(); + pos.y() -= characterSize + backgroundMargin; + + { + osg::Geode* geode = new osg::Geode(); + _group->addChild(geode); + osg::ref_ptr 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 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.get(),"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.get()); + _group->addChild(geode); + } + + return _group.get(); + } + + 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::iterator it = _actions.begin(); it != _actions.end(); ++it) { + (*it).second._group->setNodeMask(~osg::Node::NodeMask(1)); + } + + const std::vector& channels = visitor->getChannels(); + std::map 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.get()); + //_actions[name].touch(); + } else { + _actions[name].setPosition(pos); + //_actions[name].touch(); + } + _actions[name]._group->setNodeMask(~osg::Node::NodeMask(0x0)); + size[name] = 0; + pos.y() -= characterSize + graphSpacing; + } + + pos.y() -= backgroundMargin; + osg::Vec3Array* array = dynamic_cast(_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 > _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(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(&aa); + if (!myview) return false; + + osgViewer::Viewer* viewer = dynamic_cast(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(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)< StatsList; + StatsList statsList; + + for (int i = 0; i < (int)finder._timelines.size(); i++) + statsList.push_back(finder._timelines[i]->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)<setGraphicsContext(0); + _camera->removeChildren( 0, _camera->getNumChildren() ); +} + +void StatsHandler::setUpHUDCamera(osgViewer::ViewerBase* viewer) +{ + osgViewer::GraphicsWindow* window = dynamic_cast(_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(viewer); + v->getSceneData()->asGroup()->addChild(_camera.get()); + _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.get()); + + for (int i = 0; i < (int)finder._timelines.size(); i++) { + StatsTimeline* s = new StatsTimeline; + osg::MatrixTransform* m = s->createStatsForTimeline(finder._timelines[i].get()); + m->setUpdateCallback(s); + m->setMatrix(osg::Matrix::translate(0, -i * 100, 0)); + _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.get()); + _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.get()); + _group->addChild(_graph.get()); +} +void StatAction::setAlpha(float v) +{ + std::cout << this << " color alpha " << v << std::endl; + StatsGraph* gfx = dynamic_cast(_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(gfx->_statsGraphGeode->getDrawable(0)); + g->setColor(color); + } +} + +void StatAction::setPosition(const osg::Vec3& pos) +{ + float characterSize = 20.0f; + StatsGraph* gfx = dynamic_cast(_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."); +} + +} diff --git a/src/osgAnimation/StatsVisitor.cpp b/src/osgAnimation/StatsVisitor.cpp new file mode 100644 index 000000000..8106ca708 --- /dev/null +++ b/src/osgAnimation/StatsVisitor.cpp @@ -0,0 +1,86 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include +#include +#include + +using namespace osgAnimation; + +StatsActionVisitor::StatsActionVisitor() {} +void StatsActionVisitor::reset() { _channels.clear(); } + +StatsActionVisitor::StatsActionVisitor(osg::Stats* stats,unsigned int frame) +{ + _frame = frame; + _stats = stats; +} + +void StatsActionVisitor::apply(Timeline& tm) +{ + _stats->setAttribute(_frame,"Timeline", tm.getCurrentTime()); + tm.traverse(*this); +} + +void StatsActionVisitor::apply(Action& action) +{ + if (isActive(action)) + { + _channels.push_back(action.getName()); + _stats->setAttribute(_frame,action.getName(),1); + } +} + +void StatsActionVisitor::apply(ActionBlendIn& action) +{ + if (isActive(action)) + { + _channels.push_back(action.getName()); + _stats->setAttribute(_frame,action.getName(), action.getWeight()); + } +} + +void StatsActionVisitor::apply(ActionBlendOut& action) +{ + if (isActive(action)) + { + _channels.push_back(action.getName()); + _stats->setAttribute(_frame,action.getName(), action.getWeight()); + } +} + +void StatsActionVisitor::apply(ActionAnimation& action) +{ + if (isActive(action)) + { + _channels.push_back(action.getName()); + _stats->setAttribute(_frame,action.getName(), action.getAnimation()->getWeight()); + } +} + +void StatsActionVisitor::apply(ActionStripAnimation& action) +{ + if (isActive(action)) + { + _channels.push_back(action.getName()); + double value; + std::string name = action.getName(); + if (_stats->getAttribute(_frame, name, value)) + name += "+"; + _stats->setAttribute(_frame, action.getName(), action.getAnimation()->getAnimation()->getWeight()); + } +} diff --git a/src/osgAnimation/Target.cpp b/src/osgAnimation/Target.cpp index 7bb2da215..b05775611 100644 --- a/src/osgAnimation/Target.cpp +++ b/src/osgAnimation/Target.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -18,5 +18,4 @@ using namespace osgAnimation; -Target::Target() { reset();} -Target::~Target() {} +Target::Target() : _weight(0), _priorityWeight(0), _lastPriority(0) {} diff --git a/src/osgAnimation/Timeline.cpp b/src/osgAnimation/Timeline.cpp index 2d6097f2a..1bb137e52 100644 --- a/src/osgAnimation/Timeline.cpp +++ b/src/osgAnimation/Timeline.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -13,6 +13,7 @@ */ #include +#include #include using namespace osgAnimation; @@ -29,11 +30,14 @@ Timeline::Timeline() _previousFrameEvaluated = 0; _evaluating = 0; _numberFrame = UINT_MAX; // something like infinity + _collectStats = false; + _stats = new osg::Stats("Timeline"); setName("Timeline"); } -Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, op), - _actions(nc._actions) +Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) + : Action(nc, op), + _actions(nc._actions) { _lastUpdate = 0; _currentFrame = 0; @@ -44,5 +48,204 @@ Timeline::Timeline(const Timeline& nc,const osg::CopyOp& op) : osg::Object(nc, o _previousFrameEvaluated = 0; _evaluating = 0; _numberFrame = UINT_MAX; // something like infinity + _collectStats = false; + _stats = new osg::Stats("Timeline"); setName("Timeline"); } + +void Timeline::setAnimationManager(AnimationManagerBase* manager) +{ + _animationManager = manager; +} + +void Timeline::traverse(ActionVisitor& visitor) +{ + int layer = visitor.getCurrentLayer(); + visitor.pushTimelineOnStack(this); + // update from high priority to low priority + for( ActionLayers::reverse_iterator iterAnim = _actions.rbegin(); iterAnim != _actions.rend(); ++iterAnim ) + { + visitor.setCurrentLayer(iterAnim->first); + 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(); + visitor.setCurrentLayer(layer); +} + + +void Timeline::setStats(osg::Stats* stats) { _stats = stats;} +osg::Stats* Timeline::getStats() { return _stats.get();} +void Timeline::collectStats(bool state) { _collectStats = state;} +StatsActionVisitor* Timeline::getStatsVisitor() { return _statsVisitor.get(); } + +void Timeline::clearActions() +{ + _actions.clear(); + _addActionOperations.clear(); + _removeActionOperations.clear(); +} + +void Timeline::update(double simulationTime) +{ + // first time we call update we generate one frame + UpdateActionVisitor updateTimeline; + if (!_initFirstFrame) + { + _lastUpdate = simulationTime; + _initFirstFrame = true; + + + _animationManager->clearTargets(); + updateTimeline.setFrame(_currentFrame); + accept(updateTimeline); + + if (_collectStats) + { + if (!_statsVisitor) + _statsVisitor = new StatsActionVisitor(); + _statsVisitor->setStats(_stats.get()); + _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(floor(nbframes)); + + for (unsigned int i = 0; i < nb; i++) + { + if (_state == Play) + _currentFrame++; + + _animationManager->clearTargets(); + updateTimeline.setFrame(_currentFrame); + accept(updateTimeline); + if (_collectStats) + { + if (!_statsVisitor) + _statsVisitor = new StatsActionVisitor; + _statsVisitor->setStats(_stats.get()); + _statsVisitor->setFrame(_currentFrame); + _statsVisitor->reset(); + accept(*_statsVisitor); + } + + processPendingOperation(); + } + if (nb) + { + _lastUpdate += ((double)nb) / _fps; + } +} + +void Timeline::removeAction(Action* action) +{ + if (getEvaluating()) + _removeActionOperations.push_back(FrameAction(0, action)); + else + internalRemoveAction(action); +} + +void Timeline::addActionAt(unsigned int frame, Action* action, int priority) +{ + // skip if this action has already been added this frame + for (CommandList::iterator it = _addActionOperations.begin(); it != _addActionOperations.end(); ++it) + { + Command& command = *it; + if (command._action.second.get() == action) { + osg::notify(osg::INFO) << "Timeline::addActionAt command " << action->getName() << " already added this frame, declined" << std::endl; + return; + } + } + + if (isActive(action)) + { + osg::notify(osg::INFO) << "Timeline::addActionAt command " << action->getName() << " already active, remove the old" << std::endl; + removeAction(action); + } + + if (getEvaluating()) + _addActionOperations.push_back(Command(priority,FrameAction(frame, action))); + else + internalAddAction(priority, FrameAction(frame, action)); +} +void Timeline::addActionAt(double t, Action* action, int priority) +{ + unsigned int frame = static_cast(floor(t * _fps)); + addActionAt(frame, action, priority); +} + +void Timeline::addActionNow(Action* action, int priority) +{ + addActionAt(getCurrentFrame()+1, action, priority); +} + +void 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 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 Timeline::internalAddAction(int priority, const FrameAction& ftl) +{ + _actions[priority].insert(_actions[priority].begin(), ftl); +} + +bool 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; +} diff --git a/src/osgAnimation/TimelineAnimationManager.cpp b/src/osgAnimation/TimelineAnimationManager.cpp index 3fcc827e8..97a7cd8f6 100644 --- a/src/osgAnimation/TimelineAnimationManager.cpp +++ b/src/osgAnimation/TimelineAnimationManager.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -34,7 +34,7 @@ TimelineAnimationManager::TimelineAnimationManager(const TimelineAnimationManage void TimelineAnimationManager::update(double time) { - clearTargets(); + // clearTargets(); + _timeline->setAnimationManager(this); _timeline->update(time); - normalizeTargets(); } diff --git a/src/osgAnimation/UpdateBone.cpp b/src/osgAnimation/UpdateBone.cpp new file mode 100644 index 000000000..c3e7d67ce --- /dev/null +++ b/src/osgAnimation/UpdateBone.cpp @@ -0,0 +1,54 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include + +using namespace osgAnimation; + + +UpdateBone::UpdateBone(const std::string& name) : UpdateMatrixTransform(name) +{ +} + +UpdateBone::UpdateBone(const UpdateBone& apc,const osg::CopyOp& copyop) : osg::Object(apc,copyop), UpdateMatrixTransform(apc, copyop) +{ +} + +/** Callback method called by the NodeVisitor when visiting a node.*/ +void UpdateBone::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + Bone* b = dynamic_cast(node); + if (!b) + { + osg::notify(osg::WARN) << "Warning: UpdateBone set on non-Bone object." << std::endl; + return; + } + + // here we would prefer to have a flag inside transform stack in order to avoid update and a dirty state in matrixTransform if it's not require. + _transforms.update(); + const osg::Matrix& matrix = _transforms.getMatrix(); + b->setMatrix(matrix); + + Bone* parent = b->getBoneParent(); + if (parent) + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace() * parent->getMatrixInSkeletonSpace()); + else + b->setMatrixInSkeletonSpace(b->getMatrixInBoneSpace()); + } + traverse(node,nv); +} diff --git a/src/osgAnimation/UpdateMaterial.cpp b/src/osgAnimation/UpdateMaterial.cpp new file mode 100644 index 000000000..4f2a8dd51 --- /dev/null +++ b/src/osgAnimation/UpdateMaterial.cpp @@ -0,0 +1,63 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include + +using namespace osgAnimation; + +UpdateMaterial::UpdateMaterial(const UpdateMaterial& apc,const osg::CopyOp& copyop) + : osg::Object(apc, copyop), + AnimationUpdateCallback(apc, copyop) +{ + _diffuse = new osgAnimation::Vec4Target(apc._diffuse->getValue()); +} + +UpdateMaterial::UpdateMaterial(const std::string& name): + AnimationUpdateCallback(name) +{ + _diffuse = new osgAnimation::Vec4Target(osg::Vec4(1,0,1,1)); +} + +/** Callback method called by the NodeVisitor when visiting a node.*/ +void UpdateMaterial::operator()(osg::StateAttribute* sa, osg::NodeVisitor* nv) +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::Material* material = dynamic_cast(sa); + if (material) + update(*material); + } +} + + +osgAnimation::Vec4Target* UpdateMaterial::getDiffuse() { return _diffuse.get(); } +void UpdateMaterial::update(osg::Material& material) +{ + osg::Vec4 diffuse = _diffuse->getValue(); + material.setDiffuse(osg::Material::FRONT_AND_BACK, diffuse); +} + +bool UpdateMaterial::link(osgAnimation::Channel* channel) +{ + if (channel->getName().find("diffuse") != std::string::npos) + { + return channel->setTarget(_diffuse.get()); + } + else + { + osg::notify(osg::WARN) << "Channel " << channel->getName() << " does not contain a valid symbolic name for this class " << className() << std::endl; + } + return false; +} diff --git a/src/osgAnimation/UpdateMatrixTransform.cpp b/src/osgAnimation/UpdateMatrixTransform.cpp new file mode 100644 index 000000000..64a4bc99c --- /dev/null +++ b/src/osgAnimation/UpdateMatrixTransform.cpp @@ -0,0 +1,67 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include + +using namespace osgAnimation; + +UpdateMatrixTransform::UpdateMatrixTransform( const UpdateMatrixTransform& apc,const osg::CopyOp& copyop) : osg::Object(apc,copyop), AnimationUpdateCallback(apc, copyop) +{ + _transforms = StackedTransform(apc.getStackedTransforms(), copyop); +} + +UpdateMatrixTransform::UpdateMatrixTransform(const std::string& name) : AnimationUpdateCallback(name) +{ +} + +/** Callback method called by the NodeVisitor when visiting a node.*/ +void UpdateMatrixTransform::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + if (nv && nv->getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR) + { + osg::MatrixTransform* matrixTransform = dynamic_cast(node); + if (matrixTransform) + { + // here we would prefer to have a flag inside transform stack in order to avoid update and a dirty state in matrixTransform if it's not require. + _transforms.update(); + const osg::Matrix& matrix = _transforms.getMatrix(); + matrixTransform->setMatrix(matrix); + } + } + traverse(node,nv); +} + + +bool UpdateMatrixTransform::link(osgAnimation::Channel* channel) +{ + const std::string& channelName = channel->getName(); + + // check if we can link a StackedTransformElement to the current Channel + for (StackedTransform::iterator it = _transforms.begin(); it != _transforms.end(); ++it) + { + StackedTransformElement* element = it->get(); + if (element && !element->getName().empty() && channelName == element->getName()) + { + Target* target = element->getOrCreateTarget(); + if (target && channel->setTarget(target)) + return true; + } + } + + osg::notify(osg::INFO) << "UpdateMatrixTransform::link Channel " << channel->getName() << " does not contain a symbolic name that can be linked to a StackedTransformElement." << std::endl; + + return false; +} diff --git a/src/osgAnimation/VertexInfluence.cpp b/src/osgAnimation/VertexInfluence.cpp index 3ef29f0db..e605d4574 100644 --- a/src/osgAnimation/VertexInfluence.cpp +++ b/src/osgAnimation/VertexInfluence.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -10,20 +10,23 @@ * 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 +#include #include #include using namespace osgAnimation; +void VertexInfluenceSet::addVertexInfluence(const VertexInfluence& v) { _bone2Vertexes.push_back(v); } +const VertexInfluenceSet::VertexIndexToBoneWeightMap& VertexInfluenceSet::getVertexToBoneList() const { return _vertex2Bones;} // this class manage VertexInfluence database by mesh // reference bones per vertex ... -void osgAnimation::VertexInfluenceSet::buildVertex2BoneList() +void VertexInfluenceSet::buildVertex2BoneList() { _vertex2Bones.clear(); - for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); it++) + for (BoneToVertexList::const_iterator it = _bone2Vertexes.begin(); it != _bone2Vertexes.end(); ++it) { const VertexInfluence& vi = (*it); int size = vi.size(); @@ -33,13 +36,13 @@ void osgAnimation::VertexInfluenceSet::buildVertex2BoneList() int index = viw.first; float weight = viw.second; if (vi.getName().empty()) - std::cout << "osgAnimation::VertexInfluenceSet::buildVertex2BoneList warning vertex " << index << " is not assigned to a bone" << std::endl; + osg::notify(osg::WARN) << "VertexInfluenceSet::buildVertex2BoneList warning vertex " << index << " is not assigned to a bone" << std::endl; _vertex2Bones[index].push_back(BoneWeight(vi.getName(), weight)); } } // normalize weight per vertex - for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); it++) + for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it) { BoneWeightList& bones = it->second; int size = bones.size(); @@ -48,7 +51,7 @@ void osgAnimation::VertexInfluenceSet::buildVertex2BoneList() sum += bones[i].getWeight(); if (sum < 1e-4) { - std::cerr << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << it->first << " seems to have 0 weight, skip normalize for this vertex" << std::endl; + osg::notify(osg::WARN) << "VertexInfluenceSet::buildVertex2BoneList warning the vertex " << it->first << " seems to have 0 weight, skip normalize for this vertex" << std::endl; } else { @@ -62,10 +65,10 @@ void osgAnimation::VertexInfluenceSet::buildVertex2BoneList() // sort by name and weight -struct SortByNameAndWeight : public std::less +struct SortByNameAndWeight : public std::less { - bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeight& b0, - const osgAnimation::VertexInfluenceSet::BoneWeight& b1) const + bool operator()(const VertexInfluenceSet::BoneWeight& b0, + const VertexInfluenceSet::BoneWeight& b1) const { if (b0.getBoneName() < b1.getBoneName()) return true; @@ -77,10 +80,10 @@ struct SortByNameAndWeight : public std::less +struct SortByBoneWeightList : public std::less { - bool operator()(const osgAnimation::VertexInfluenceSet::BoneWeightList& b0, - const osgAnimation::VertexInfluenceSet::BoneWeightList& b1) const + bool operator()(const VertexInfluenceSet::BoneWeightList& b0, + const VertexInfluenceSet::BoneWeightList& b1) const { if (b0.size() < b1.size()) return true; @@ -100,14 +103,20 @@ struct SortByBoneWeightList : public std::less UnifyBoneGroup; UnifyBoneGroup unifyBuffer; - for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); it++) + for (VertexIndexToBoneWeightMap::iterator it = _vertex2Bones.begin(); it != _vertex2Bones.end(); ++it) { BoneWeightList bones = it->second; int vertexIndex = it->first; @@ -123,8 +132,9 @@ void osgAnimation::VertexInfluenceSet::buildUniqVertexSetToBoneSetList() } _uniqVertexSetToBoneSet.reserve(unifyBuffer.size()); - for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); it++) + for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it) { _uniqVertexSetToBoneSet.push_back(it->second); } } + diff --git a/src/osgPlugins/osgAnimation/CMakeLists.txt b/src/osgPlugins/osgAnimation/CMakeLists.txt index 993bd6b7b..a4f50231d 100644 --- a/src/osgPlugins/osgAnimation/CMakeLists.txt +++ b/src/osgPlugins/osgAnimation/CMakeLists.txt @@ -1,9 +1,7 @@ -SET(TARGET_SRC - ReaderWriter.cpp -) +FILE(GLOB TARGET_SRC *.cpp) +FILE(GLOB TARGET_H *.h) + SET(TARGET_ADDED_LIBRARIES osgAnimation ) #### end var setup ### SETUP_PLUGIN(osganimation) - - diff --git a/src/osgPlugins/osgAnimation/Matrix.cpp b/src/osgPlugins/osgAnimation/Matrix.cpp new file mode 100644 index 000000000..bb36713a9 --- /dev/null +++ b/src/osgPlugins/osgAnimation/Matrix.cpp @@ -0,0 +1,51 @@ +#include "Matrix.h" + + +bool readMatrix(osg::Matrix& matrix, osgDB::Input& fr, const char* keyword) +{ + bool iteratorAdvanced = false; + + if (fr[0].matchWord(keyword) && fr[1].isOpenBracket()) + { + int entry = fr[0].getNoNestedBrackets(); + + fr += 2; + + int row=0; + int col=0; + double v; + while (!fr.eof() && fr[0].getNoNestedBrackets()>entry) + { + if (fr[0].getFloat(v)) + { + matrix(row,col)=v; + ++col; + if (col>=4) + { + col = 0; + ++row; + } + ++fr; + } + else fr.advanceOverCurrentFieldOrBlock(); + } + iteratorAdvanced = true; + } + + return iteratorAdvanced; +} + + +bool writeMatrix(const osg::Matrix& matrix, osgDB::Output& fw, const char* keyword) +{ + fw.indent() << keyword <<" {" << std::endl; + fw.moveIn(); + fw.indent() << matrix(0,0) << " " << matrix(0,1) << " " << matrix(0,2) << " " << matrix(0,3) << std::endl; + fw.indent() << matrix(1,0) << " " << matrix(1,1) << " " << matrix(1,2) << " " << matrix(1,3) << std::endl; + fw.indent() << matrix(2,0) << " " << matrix(2,1) << " " << matrix(2,2) << " " << matrix(2,3) << std::endl; + fw.indent() << matrix(3,0) << " " << matrix(3,1) << " " << matrix(3,2) << " " << matrix(3,3) << std::endl; + fw.moveOut(); + fw.indent() << "}"<< std::endl; + return true; +} + diff --git a/src/osgPlugins/osgAnimation/Matrix.h b/src/osgPlugins/osgAnimation/Matrix.h new file mode 100644 index 000000000..e5fa46724 --- /dev/null +++ b/src/osgPlugins/osgAnimation/Matrix.h @@ -0,0 +1,13 @@ +#ifndef DOTOSG_MATRIX +#define DOTOSG_MATRIX + +#include + +#include +#include + +extern bool readMatrix(osg::Matrix& matrix, osgDB::Input& fr, const char* keyword="Matrix"); + +extern bool writeMatrix(const osg::Matrix& matrix, osgDB::Output& fw, const char* keyword="Matrix"); + +#endif diff --git a/src/osgPlugins/osgAnimation/ReaderWriter.cpp b/src/osgPlugins/osgAnimation/ReaderWriter.cpp index 192a8002b..5a91eb2f6 100644 --- a/src/osgPlugins/osgAnimation/ReaderWriter.cpp +++ b/src/osgPlugins/osgAnimation/ReaderWriter.cpp @@ -1,5 +1,5 @@ /* -*-c++-*- - * Copyright (C) 2008 Cedric Pinson + * Copyright (C) 2008 Cedric Pinson * * 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 @@ -10,23 +10,30 @@ * 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 #include #include #include - +#include #include #include #include #include #include #include +#include +#include #include #include -#include +#include +#include +#include +#include +#include +#include +#include "Matrix.h" #include #include @@ -41,7 +48,7 @@ bool Bone_readLocalData(Object& obj, Input& fr) osg::Quat att; bool iteratorAdvanced = false; - if (fr.matchSequence("bindQuaternion %f %f %f %f")) + if (fr.matchSequence("bindQuaternion %f %f %f %f")) { fr[1].getFloat(att[0]); fr[2].getFloat(att[1]); @@ -50,10 +57,11 @@ bool Bone_readLocalData(Object& obj, Input& fr) fr += 5; iteratorAdvanced = true; + osg::notify(osg::WARN) << "Old osgAnimation file format update your data file" << std::endl; } osg::Vec3d pos(0,0,0); - if (fr.matchSequence("bindPosition %f %f %f")) + if (fr.matchSequence("bindPosition %f %f %f")) { fr[1].getFloat(pos[0]); fr[2].getFloat(pos[1]); @@ -61,10 +69,11 @@ bool Bone_readLocalData(Object& obj, Input& fr) fr += 4; iteratorAdvanced = true; + osg::notify(osg::WARN) << "Old osgAnimation file format update your data file" << std::endl; } osg::Vec3d scale(1,1,1); - if (fr.matchSequence("bindScale %f %f %f")) + if (fr.matchSequence("bindScale %f %f %f")) { fr[1].getFloat(scale[0]); fr[2].getFloat(scale[1]); @@ -72,31 +81,45 @@ bool Bone_readLocalData(Object& obj, Input& fr) fr += 4; iteratorAdvanced = true; + osg::notify(osg::WARN) << "Old osgAnimation file format update your data file" << std::endl; } - bone.setBindMatrixInBoneSpace( osg::Matrix(att) * osg::Matrix::translate(pos)); + if (fr.matchSequence("InvBindMatrixInSkeletonSpace {")) + { + Matrix matrix; + if (readMatrix(matrix,fr, "InvBindMatrixInSkeletonSpace")) + { + bone.setInvBindMatrixInSkeletonSpace(matrix); + iteratorAdvanced = true; + } + } + if (fr.matchSequence("MatrixInSkeletonSpace {")) + { + Matrix matrix; + if (readMatrix(matrix,fr, "MatrixInSkeletonSpace")) + { + bone.setMatrixInSkeletonSpace(matrix); + iteratorAdvanced = true; + } + } return iteratorAdvanced; } -bool Bone_writeLocalData(const Object& obj, Output& fw) +bool Bone_writeLocalData(const Object& obj, Output& fw) { const osgAnimation::Bone& bone = dynamic_cast(obj); - osg::Vec3 t; - osg::Quat r; - osg::Vec3 s; - osg::Quat rs; - bone.getBindMatrixInBoneSpace().decompose(t,r,s,rs); - fw.indent() << "bindQuaternion " << r << std::endl; - fw.indent() << "bindPosition " << t << std::endl; - fw.indent() << "bindScale " << s << std::endl; - return true; + bool res1 = writeMatrix(bone.getInvBindMatrixInSkeletonSpace(), fw, "InvBindMatrixInSkeletonSpace"); + // write this field for debug only + // because it's recompute at each update + bool res2 = writeMatrix(bone.getMatrixInSkeletonSpace(), fw, "MatrixInSkeletonSpace"); + return (res1 || res2); } -RegisterDotOsgWrapperProxy g_atkBoneProxy +RegisterDotOsgWrapperProxy g_BoneProxy ( new osgAnimation::Bone, "osgAnimation::Bone", - "Object Node Transform osgAnimation::Bone Group", + "Object Node MatrixTransform osgAnimation::Bone Group", &Bone_readLocalData, &Bone_writeLocalData ); @@ -111,23 +134,94 @@ bool Skeleton_writeLocalData(const Object& obj, Output& fr) { return true; } -RegisterDotOsgWrapperProxy g_atkRootSkeletonProxy +RegisterDotOsgWrapperProxy g_SkeletonProxy ( new osgAnimation::Skeleton, "osgAnimation::Skeleton", - "Object Node Transform osgAnimation::Bone osgAnimation::Skeleton Group", + "Object Node MatrixTransform osgAnimation::Skeleton Group", &Skeleton_readLocalData, &Skeleton_writeLocalData, DotOsgWrapper::READ_AND_WRITE ); +// Helper method for reading channels +bool Animation_readChannel(osgAnimation::Channel* pChannel, Input& fr) +{ + bool iteratorAdvanced = false; + std::string name = "unknown"; + if (fr.matchSequence("name %s")) + { + if (fr[1].getStr()) + name = fr[1].getStr(); + fr += 2; + iteratorAdvanced = true; + } + pChannel->setName(name); + std::string target = "unknown"; + if (fr.matchSequence("target %s")) + { + if (fr[1].getStr()) + target = fr[1].getStr(); + fr += 2; + iteratorAdvanced = true; + } + pChannel->setTargetName(target); +// we dont need this info + float weight = 1.0; + if (fr.matchSequence("weight %f")) + { + fr[1].getFloat(weight); + fr += 2; + iteratorAdvanced = true; + } +// pChannel->setWeight(weight); + return iteratorAdvanced; +} -bool Animation_readLocalData(Object& obj, Input& fr) +bool Animation_readLocalData(Object& obj, Input& fr) { osgAnimation::Animation& anim = dynamic_cast(obj); bool iteratorAdvanced = false; + + if (fr.matchSequence("playmode %w")) + { + if (fr[1].matchWord("ONCE")) anim.setPlaymode(osgAnimation::Animation::ONCE); + else if (fr[1].matchWord("STAY")) anim.setPlaymode(osgAnimation::Animation::STAY); + else if (fr[1].matchWord("LOOP")) anim.setPlaymode(osgAnimation::Animation::LOOP); + else if (fr[1].matchWord("PPONG")) anim.setPlaymode(osgAnimation::Animation::PPONG); + fr += 2; + iteratorAdvanced = true; + } + + if (fr.matchSequence("weight %f")) + { + float weight; + fr[1].getFloat(weight); + fr += 2; + iteratorAdvanced = true; + anim.setWeight(weight); + } + + if (fr.matchSequence("duration %f")) + { + float duration; + fr[1].getFloat(duration); + fr += 2; + iteratorAdvanced = true; + anim.setDuration(duration); + } + + if (fr.matchSequence("starttime %f")) + { + float starttime; + fr[1].getFloat(starttime); + fr += 2; + iteratorAdvanced = true; + anim.setStartTime(starttime); + } + int nbChannels = 0; if (fr.matchSequence("num_channels %i")) { @@ -138,30 +232,267 @@ bool Animation_readLocalData(Object& obj, Input& fr) for (int i = 0; i < nbChannels; i++) { - if (fr.matchSequence("Channel {")) + if (fr.matchSequence("DoubleLinearChannel {")) + { + fr += 2; + + osgAnimation::DoubleLinearChannel* channel = new osgAnimation::DoubleLinearChannel; + + if (Animation_readChannel(channel, fr)) + iteratorAdvanced = true; + + int nbKeys; + if (fr.matchSequence("Keyframes %i {")) + { + fr[1].getInt(nbKeys); + fr += 3; + iteratorAdvanced = true; + + for (int k = 0; k < nbKeys; k++) + { + double v; + float time; + if (fr.matchSequence("key %f %f")) + { + fr[1].getFloat(time); + fr[2].getFloat(v); + fr += 3; + channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::DoubleKeyframe(time, v)); + iteratorAdvanced = true; + } + } + anim.addChannel(channel); + + if (fr.matchSequence("}")) // keyframes + fr += 1; + } + if (fr.matchSequence("}")) // channel + fr += 1; + } + else if (fr.matchSequence("FloatLinearChannel {")) + { + fr += 2; + + osgAnimation::FloatLinearChannel* channel = new osgAnimation::FloatLinearChannel; + + if (Animation_readChannel(channel, fr)) + iteratorAdvanced = true; + + int nbKeys; + if (fr.matchSequence("Keyframes %i {")) + { + fr[1].getInt(nbKeys); + fr += 3; + iteratorAdvanced = true; + + for (int k = 0; k < nbKeys; k++) + { + float v; + float time; + if (fr.matchSequence("key %f %f")) + { + fr[1].getFloat(time); + fr[2].getFloat(v); + fr += 3; + channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::FloatKeyframe(time, v)); + iteratorAdvanced = true; + } + } + anim.addChannel(channel); + + if (fr.matchSequence("}")) // keyframes + fr += 1; + } + if (fr.matchSequence("}")) // channel + fr += 1; + } + else if (fr.matchSequence("Vec2LinearChannel {")) + { + fr += 2; + + osgAnimation::Vec2LinearChannel* channel = new osgAnimation::Vec2LinearChannel; + + if (Animation_readChannel(channel, fr)) + iteratorAdvanced = true; + + int nbKeys; + if (fr.matchSequence("Keyframes %i {")) + { + fr[1].getInt(nbKeys); + fr += 3; + iteratorAdvanced = true; + + for (int k = 0; k < nbKeys; k++) + { + osg::Vec2 v; + float time; + if (fr.matchSequence("key %f %f %f")) + { + fr[1].getFloat(time); + fr[2].getFloat(v[0]); + fr[3].getFloat(v[1]); + fr += 4; + channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec2Keyframe(time, v)); + iteratorAdvanced = true; + } + } + anim.addChannel(channel); + + if (fr.matchSequence("}")) // keyframes + fr += 1; + } + if (fr.matchSequence("}")) // channel + fr += 1; + } + else if (fr.matchSequence("Vec3LinearChannel {")) + { + fr += 2; + + osgAnimation::Vec3LinearChannel* channel = new osgAnimation::Vec3LinearChannel; + + if (Animation_readChannel(channel, fr)) + iteratorAdvanced = true; + + int nbKeys; + if (fr.matchSequence("Keyframes %i {")) + { + fr[1].getInt(nbKeys); + fr += 3; + iteratorAdvanced = true; + + for (int k = 0; k < nbKeys; k++) + { + osg::Vec3 v; + float time; + if (fr.matchSequence("key %f %f %f %f")) + { + fr[1].getFloat(time); + fr[2].getFloat(v[0]); + fr[3].getFloat(v[1]); + fr[4].getFloat(v[2]); + fr += 5; + channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec3Keyframe(time, v)); + iteratorAdvanced = true; + } + } + anim.addChannel(channel); + + if (fr.matchSequence("}")) // keyframes + fr += 1; + } + if (fr.matchSequence("}")) // channel + fr += 1; + } + else if (fr.matchSequence("Vec4LinearChannel {")) + { + fr += 2; + + osgAnimation::Vec4LinearChannel* channel = new osgAnimation::Vec4LinearChannel; + + if (Animation_readChannel(channel, fr)) + iteratorAdvanced = true; + + int nbKeys; + if (fr.matchSequence("Keyframes %i {")) + { + fr[1].getInt(nbKeys); + fr += 3; + iteratorAdvanced = true; + + for (int k = 0; k < nbKeys; k++) + { + osg::Vec4 v; + float time; + if (fr.matchSequence("key %f %f %f %f %f")) + { + fr[1].getFloat(time); + fr[2].getFloat(v[0]); + fr[3].getFloat(v[1]); + fr[4].getFloat(v[2]); + fr[5].getFloat(v[3]); + fr += 6; + channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::Vec4Keyframe(time, v)); + iteratorAdvanced = true; + } + } + anim.addChannel(channel); + + if (fr.matchSequence("}")) // keyframes + fr += 1; + } + if (fr.matchSequence("}")) // channel + fr += 1; + } + else if (fr.matchSequence("QuatSphericalLinearChannel {")) + { + fr += 2; + + osgAnimation::QuatSphericalLinearChannel* channel = new osgAnimation::QuatSphericalLinearChannel; + + if (Animation_readChannel(channel, fr)) + iteratorAdvanced = true; + + int nbKeys; + if (fr.matchSequence("Keyframes %i {")) + { + fr[1].getInt(nbKeys); + fr += 3; + iteratorAdvanced = true; + + for (int k = 0; k < nbKeys; k++) + { + osg::Quat q; + float time; + if (fr.matchSequence("key %f %f %f %f %f")) + { + fr[1].getFloat(time); + fr[2].getFloat(q[0]); + fr[3].getFloat(q[1]); + fr[4].getFloat(q[2]); + fr[5].getFloat(q[3]); + fr += 6; + channel->getOrCreateSampler()->getOrCreateKeyframeContainer()->push_back(osgAnimation::QuatKeyframe(time, q)); + iteratorAdvanced = true; + } + } + anim.addChannel(channel); + + if (fr.matchSequence("}")) // keyframes + fr += 1; + } + if (fr.matchSequence("}")) // channel + fr += 1; + } + // Deprecated + // Reading of old channel info + // Kept here for easy conversion of old .osg data to new format + else if (fr.matchSequence("Channel {")) { fr += 2; std::string name = "unknown"; if (fr.matchSequence("name %s")) { - name = fr[1].getStr(); + if (fr[1].getStr()) + name = fr[1].getStr(); fr += 2; iteratorAdvanced = true; } std::string target = "unknown"; if (fr.matchSequence("target %s")) { - target = fr[1].getStr(); + if (fr[1].getStr()) + target = fr[1].getStr(); fr += 2; iteratorAdvanced = true; } - std::string type; + std::string type = "unknown"; int nbKeys; if (fr.matchSequence("Keyframes %s %i {")) { - type = fr[1].getStr(); + if (fr[1].getStr()) + type = fr[1].getStr(); fr[2].getInt(nbKeys); fr += 4; iteratorAdvanced = true; @@ -175,11 +506,11 @@ bool Animation_readLocalData(Object& obj, Input& fr) } else if (type == "Vec3") { - channel = new osgAnimation::Vec3LinearChannel; osgAnimation::Vec3LinearChannel* c = new osgAnimation::Vec3LinearChannel; c->getOrCreateSampler()->getOrCreateKeyframeContainer(); channel = c; } + if (channel) { for (int k = 0; k < nbKeys; k++) @@ -229,60 +560,130 @@ bool Animation_readLocalData(Object& obj, Input& fr) return iteratorAdvanced; } +// Helper method for writing channels +template +void Animation_writeChannel(const std::string& channelString, ChannelType* pChannel, Output& fw) +{ + fw.indent() << channelString.c_str() << " {" << std::endl; + fw.moveIn(); + fw.indent() << "name \"" << pChannel->getName() << "\"" << std::endl; + fw.indent() << "target \"" << pChannel->getTargetName() << "\"" << std::endl; + +// fw.indent() << "weight " << pChannel->getWeight() << std::endl; + + ContainerType* kfc = pChannel->getSamplerTyped()->getKeyframeContainerTyped(); + if (kfc) + { + fw.indent() << "Keyframes " << kfc->size() << " {" << std::endl; + fw.moveIn(); + for (unsigned int k = 0; k < kfc->size(); k++) + { + fw.indent() << "key " << (*kfc)[k].getTime() << " " << (*kfc)[k].getValue() << std::endl; + } + fw.moveOut(); + fw.indent() << "}" << std::endl; + fw.moveOut(); + fw.indent() << "}" << std::endl; + } +} + bool Animation_writeLocalData(const Object& obj, Output& fw) { const osgAnimation::Animation& anim = dynamic_cast(obj); + switch (anim.getPlayMode()) + { + case osgAnimation::Animation::ONCE: + fw.indent() << "playmode ONCE" << std::endl; + break; + case osgAnimation::Animation::STAY: + fw.indent() << "playmode STAY" << std::endl; + break; + case osgAnimation::Animation::LOOP: + fw.indent() << "playmode LOOP" << std::endl; + break; + case osgAnimation::Animation::PPONG: + fw.indent() << "playmode PPONG" << std::endl; + break; + default: + break; + } + + fw.indent() << "weight " << anim.getWeight() << std::endl; + fw.indent() << "duration " << anim.getDuration() << std::endl; + fw.indent() << "starttime " << anim.getStartTime() << std::endl; + fw.indent() << "num_channels " << anim.getChannels().size() << std::endl; for (unsigned int i = 0; i < anim.getChannels().size(); i++) { - fw.indent() << "Channel {" << std::endl; - fw.moveIn(); - fw.indent() << "name \"" << anim.getChannels()[i]->getName() << "\"" << std::endl; - fw.indent() << "target \"" << anim.getChannels()[i]->getTargetName() << "\"" << std::endl; + osgAnimation::Channel* pChannel = anim.getChannels()[i].get(); - std::string type = "unknown"; - if (anim.getChannels()[i]->getName() == std::string("quaternion")) + osgAnimation::DoubleLinearChannel* pDlc = dynamic_cast(pChannel); + if (pDlc) { - type = "Quat"; + Animation_writeChannel("DoubleLinearChannel", pDlc, fw); + continue; } - else if (anim.getChannels()[i]->getName() == std::string("rotation")) + osgAnimation::FloatLinearChannel* pFlc = dynamic_cast(pChannel); + if (pFlc) { - type = "Quat"; + Animation_writeChannel("FloatLinearChannel", pFlc, fw); + continue; } - else if (anim.getChannels()[i]->getName() == std::string("euler")) + osgAnimation::Vec2LinearChannel* pV2lc = dynamic_cast(pChannel); + if (pV2lc) { - type = "Vec3"; + Animation_writeChannel("Vec2LinearChannel", pV2lc, fw); + continue; } - else if (anim.getChannels()[i]->getName() == std::string("scale")) + osgAnimation::Vec3LinearChannel* pV3lc = dynamic_cast(pChannel); + if (pV3lc) { - type = "Vec3"; + Animation_writeChannel("Vec3LinearChannel", pV3lc, fw); + continue; } - else if (anim.getChannels()[i]->getName() == std::string("position")) + osgAnimation::Vec4LinearChannel* pV4lc = dynamic_cast(pChannel); + if (pV4lc) { - type = "Vec3"; + Animation_writeChannel("Vec4LinearChannel", pV4lc, fw); + continue; } - - osgAnimation::KeyframeContainer* kf = anim.getChannels()[i]->getSampler()->getKeyframeContainer(); - fw.indent() << "Keyframes \"" << type << "\" " << kf->size() << " {" << std::endl; - fw.moveIn(); - for (unsigned int k = 0; k < kf->size(); k++) + osgAnimation::QuatSphericalLinearChannel* pQslc = dynamic_cast(pChannel); + if (pQslc) { - if (type == "Vec3") - { - osgAnimation::Vec3KeyframeContainer* kk = dynamic_cast(kf); - fw.indent() << "key " << (*kk)[k].getTime() << " " << (*kk)[k].getValue() << std::endl; - } - else if ( type == "Quat") - { - osgAnimation::QuatKeyframeContainer* kk = dynamic_cast(kf); - fw.indent() << "key " << (*kk)[k].getTime() << " " << (*kk)[k].getValue() << std::endl; - } + Animation_writeChannel("QuatSphericalLinearChannel", pQslc, fw); + continue; + } + osgAnimation::FloatCubicBezierChannel* pFcbc = dynamic_cast(pChannel); + if (pFcbc) + { + Animation_writeChannel("FloatCubicBezierChannel", pFcbc, fw); + continue; + } + osgAnimation::DoubleCubicBezierChannel* pDcbc = dynamic_cast(pChannel); + if (pDcbc) + { + Animation_writeChannel("DoubleCubicBezierChannel", pDcbc, fw); + continue; + } + osgAnimation::Vec2CubicBezierChannel* pV2cbc = dynamic_cast(pChannel); + if (pV2cbc) + { + Animation_writeChannel("Vec2CubicBezierChannel", pV2cbc, fw); + continue; + } + osgAnimation::Vec3CubicBezierChannel* pV3cbc = dynamic_cast(pChannel); + if (pV3cbc) + { + Animation_writeChannel("Vec3CubicBezierChannel", pV3cbc, fw); + continue; + } + osgAnimation::Vec4CubicBezierChannel* pV4cbc = dynamic_cast(pChannel); + if (pV4cbc) + { + Animation_writeChannel("Vec4CubicBezierChannel", pV4cbc, fw); + continue; } - fw.moveOut(); - fw.indent() << "}" << std::endl; - fw.moveOut(); - fw.indent() << "}" << std::endl; } return true; } @@ -344,7 +745,7 @@ bool AnimationManagerBase_writeLocalData(const osgAnimation::AnimationManagerBas const osgAnimation::AnimationList& animList = manager.getAnimationList(); fw.indent() << "num_animations " << animList.size() << std::endl; - for (osgAnimation::AnimationList::const_iterator it = animList.begin(); it != animList.end(); it++) + for (osgAnimation::AnimationList::const_iterator it = animList.begin(); it != animList.end(); ++it) { if (!fw.writeObject(**it)) osg::notify(osg::WARN)<<"Warning: can't write an animation object"<< std::endl; @@ -437,6 +838,13 @@ bool RigGeometry_readLocalData(Object& obj, Input& fr) if (!vmap->empty()) geom.setInfluenceMap(vmap.get()); + if (fr.matchSequence("Geometry {")) + { + osg::Geometry* source = dynamic_cast(fr.readObject()); + geom.setSourceGeometry(source); + iteratorAdvanced = true; + } + return iteratorAdvanced; } @@ -448,7 +856,7 @@ bool RigGeometry_writeLocalData(const Object& obj, Output& fw) return true; fw.indent() << "num_influences " << vm->size() << std::endl; fw.moveIn(); - for (osgAnimation::VertexInfluenceMap::const_iterator it = vm->begin(); it != vm->end(); it++) + for (osgAnimation::VertexInfluenceMap::const_iterator it = vm->begin(); it != vm->end(); ++it) { std::string name = it->first; if (name.empty()) @@ -464,6 +872,8 @@ bool RigGeometry_writeLocalData(const Object& obj, Output& fw) fw.indent() << "}" << std::endl; } fw.moveOut(); + + fw.writeObject(*geom.getSourceGeometry()); return true; } @@ -471,15 +881,135 @@ RegisterDotOsgWrapperProxy g_atkRigGeometryProxy ( new osgAnimation::RigGeometry, "osgAnimation::RigGeometry", - "Object Drawable osgAnimation::RigGeometry Geometry", + "Object osgAnimation::RigGeometry Drawable Geometry", &RigGeometry_readLocalData, &RigGeometry_writeLocalData, DotOsgWrapper::READ_AND_WRITE ); +bool MorphGeometry_readLocalData(Object& obj, Input& fr) +{ + osgAnimation::MorphGeometry& geom = dynamic_cast(obj); -bool UpdateBone_readLocalData(Object& obj, Input& fr) + bool iteratorAdvanced = false; + + if (fr[0].matchWord("method")) + { + if (fr[1].matchWord("NORMALIZED")) + { + geom.setMethod(osgAnimation::MorphGeometry::NORMALIZED); + fr+=2; + iteratorAdvanced = true; + } + else if (fr[1].matchWord("RELATIVE")) + { + geom.setMethod(osgAnimation::MorphGeometry::RELATIVE); + fr+=2; + iteratorAdvanced = true; + } + } + + if (fr[0].matchWord("morphNormals")) + { + if (fr[1].matchWord("TRUE")) + { + geom.setMorphNormals(true); + fr+=2; + iteratorAdvanced = true; + } + else if (fr[1].matchWord("FALSE")) + { + geom.setMorphNormals(false); + fr+=2; + iteratorAdvanced = true; + } + } + + int num_morphTargets = 0; + if (fr.matchSequence("num_morphTargets %i")) + { + fr[1].getInt(num_morphTargets); + fr += 2; + iteratorAdvanced = true; + } + + for (int i = 0; i < num_morphTargets; i++) + { + if (fr.matchSequence("MorphTarget {")) + { + int entry = fr[0].getNoNestedBrackets(); + fr += 2; + iteratorAdvanced = true; + + while (!fr.eof() && fr[0].getNoNestedBrackets()>entry) + { + + float weight = 1.0; + if (fr.matchSequence("weight %f")) + { + fr[1].getFloat(weight); + fr += 2; + } + osg::Drawable* drawable = NULL; + drawable = fr.readDrawable(); + osg::Geometry* geometry = dynamic_cast(drawable); + if (geometry) + geom.addMorphTarget(geometry, weight); + } + if (fr.matchSequence("}")) + fr += 1; + } + } + + return iteratorAdvanced; +} + +bool MorphGeometry_writeLocalData(const Object& obj, Output& fw) +{ + const osgAnimation::MorphGeometry& geom = dynamic_cast(obj); + + switch(geom.getMethod()) + { + case(osgAnimation::MorphGeometry::NORMALIZED): fw.indent() << "method NORMALIZED"< + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Matrix.h" + +using namespace osgDB; +using namespace osg; + +bool readStackedTranslateElement(Object& obj, Input& fr) +{ + osgAnimation::StackedTranslateElement& element = dynamic_cast(obj); + bool iteratorAdvanced = false; + if (fr.matchSequence("translate %f %f %f")) + { + ++fr; + osg::Vec3 translate; + fr[0].getFloat(translate.x()); + fr[1].getFloat(translate.y()); + fr[2].getFloat(translate.z()); + element.setTranslate(translate); + fr += 3; + iteratorAdvanced = true; + } + return iteratorAdvanced; +} + +bool writeStackedTranslateElement(const Object& obj, Output& fw) +{ + const osgAnimation::StackedTranslateElement& element = dynamic_cast(obj); + fw.indent() << "translate " << element.getTranslate() << std::endl; + return true; +} + +RegisterDotOsgWrapperProxy g_StackedTranslateElementProxy +( + new osgAnimation::StackedTranslateElement, + "osgAnimation::StackedTranslateElement", + "Object osgAnimation::StackedTranslateElement", + &readStackedTranslateElement, + &writeStackedTranslateElement, + DotOsgWrapper::READ_AND_WRITE + ); + + +bool readStackedScaleElement(Object& obj, Input& fr) +{ + osgAnimation::StackedScaleElement& element = dynamic_cast(obj); + bool iteratorAdvanced = false; + if (fr.matchSequence("scale %f %f %f")) + { + ++fr; + osg::Vec3 scale; + fr[0].getFloat(scale.x()); + fr[1].getFloat(scale.y()); + fr[2].getFloat(scale.z()); + element.setScale(scale); + fr += 3; + iteratorAdvanced = true; + } + return iteratorAdvanced; +} + +bool writeStackedScaleElement(const Object& obj, Output& fw) +{ + const osgAnimation::StackedScaleElement& element = dynamic_cast(obj); + fw.indent() << "scale " << element.getScale() << std::endl; + return true; +} + + +RegisterDotOsgWrapperProxy g_StackedScaleElementProxy +( + new osgAnimation::StackedScaleElement, + "osgAnimation::StackedScaleElement", + "Object osgAnimation::StackedScaleElement", + &readStackedScaleElement, + &writeStackedScaleElement, + DotOsgWrapper::READ_AND_WRITE + ); + + + + + + + +bool readStackedMatrixElement(Object& obj, Input& fr) +{ + osgAnimation::StackedMatrixElement& element = dynamic_cast(obj); + bool iteratorAdvanced = false; + if (fr[0].matchWord("Matrix")) + { + osg::Matrix matrix; + matrix.makeIdentity(); + iteratorAdvanced = readMatrix(matrix, fr); + element.setMatrix(matrix); + } + + return iteratorAdvanced; +} + +bool writeStackedMatrixElement(const Object& obj, Output& fw) +{ + const osgAnimation::StackedMatrixElement& element = dynamic_cast(obj); + writeMatrix(element.getMatrix(), fw); + return true; +} + +RegisterDotOsgWrapperProxy g_StackedMatrixElementProxy +( + new osgAnimation::StackedMatrixElement, + "osgAnimation::StackedMatrixElement", + "Object osgAnimation::StackedMatrixElement", + &readStackedMatrixElement, + &writeStackedMatrixElement, + DotOsgWrapper::READ_AND_WRITE + ); + + + + +bool writeStackedRotateAxisElement(const Object& obj, Output& fw) +{ + const osgAnimation::StackedRotateAxisElement& element = dynamic_cast(obj); + fw.indent() << "axis " << element.getAxis() << std::endl; + fw.indent() << "angle " << element.getAngle() << std::endl; + return true; +} + +bool readStackedRotateAxisElement(Object& obj, Input& fr) +{ + osgAnimation::StackedRotateAxisElement& element = dynamic_cast(obj); + bool iteratorAdvanced = false; + if (fr.matchSequence("axis %f %f %f")) + { + ++fr; + osg::Vec3 axis; + fr[0].getFloat(axis.x()); + fr[1].getFloat(axis.y()); + fr[2].getFloat(axis.z()); + element.setAxis(axis); + fr += 3; + iteratorAdvanced = true; + } + + if (fr.matchSequence("angle %f")) + { + ++fr; + double angle = 0; + fr[0].getFloat(angle); + ++fr; + element.setAngle(angle); + iteratorAdvanced = true; + } + return iteratorAdvanced; +} + +RegisterDotOsgWrapperProxy g_StackedRotateAxisElementProxy +( + new osgAnimation::StackedRotateAxisElement, + "osgAnimation::StackedRotateAxisElement", + "Object osgAnimation::StackedRotateAxisElement", + &readStackedRotateAxisElement, + &writeStackedRotateAxisElement, + DotOsgWrapper::READ_AND_WRITE + ); + + + + + +bool readStackedQuaternionElement(Object& obj, Input& fr) +{ + osgAnimation::StackedQuaternionElement& element = dynamic_cast(obj); + bool iteratorAdvanced = false; + if (fr.matchSequence("quaternion %f %f %f %f")) + { + ++fr; + osg::Quat quaternion; + fr[0].getFloat(quaternion[0]); + fr[1].getFloat(quaternion[1]); + fr[2].getFloat(quaternion[2]); + fr[3].getFloat(quaternion[3]); + element.setQuaternion(quaternion); + fr += 4; + iteratorAdvanced = true; + } + return iteratorAdvanced; +} + +bool writeStackedQuaternionElement(const Object& obj, Output& fw) +{ + const osgAnimation::StackedQuaternionElement& element = dynamic_cast(obj); + fw.indent() << "quaternion " << element.getQuaternion() << std::endl; + return true; +} + +RegisterDotOsgWrapperProxy g_StackedQuaternionElementProxy +( + new osgAnimation::StackedQuaternionElement, + "osgAnimation::StackedQuaternionElement", + "Object osgAnimation::StackedQuaternionElement", + &readStackedQuaternionElement, + &writeStackedQuaternionElement, + DotOsgWrapper::READ_AND_WRITE + ); diff --git a/src/osgPlugins/osgAnimation/UpdateMaterial.cpp b/src/osgPlugins/osgAnimation/UpdateMaterial.cpp new file mode 100644 index 000000000..f7acb1250 --- /dev/null +++ b/src/osgPlugins/osgAnimation/UpdateMaterial.cpp @@ -0,0 +1,47 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include +#include +#include + + +using namespace osg; +using namespace osgDB; + + +bool UpdateMaterial_readLocalData(Object& obj, Input& fr) +{ + bool iteratorAdvanced = false; + return iteratorAdvanced; +} + +bool UpdateMaterial_writeLocalData(const Object& obj, Output& fw) +{ + return true; +} + +RegisterDotOsgWrapperProxy g_UpdateMaterialProxy +( + new osgAnimation::UpdateMaterial, + "osgAnimation::UpdateMaterial", + "Object StateAttribute::Callback osgAnimation::UpdateMaterial", + &UpdateMaterial_readLocalData, + &UpdateMaterial_writeLocalData, + DotOsgWrapper::READ_AND_WRITE +); diff --git a/src/osgPlugins/osgAnimation/UpdateMatrixTransform.cpp b/src/osgPlugins/osgAnimation/UpdateMatrixTransform.cpp new file mode 100644 index 000000000..2f8879197 --- /dev/null +++ b/src/osgPlugins/osgAnimation/UpdateMatrixTransform.cpp @@ -0,0 +1,70 @@ +/* -*-c++-*- + * Copyright (C) 2009 Cedric Pinson + * + * 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 +#include +#include +#include +#include +#include +#include + + +using namespace osg; +using namespace osgDB; + +bool UpdateMatrixTransform_readLocalData(Object& obj, Input& fr) +{ + bool iteratorAdvanced = false; + + osgAnimation::UpdateMatrixTransform& updateCallback = dynamic_cast(obj); + osgAnimation::StackedTransform& stackedTransform = updateCallback.getStackedTransforms(); + + int entry = fr[0].getNoNestedBrackets(); + while (!fr.eof() && fr[0].getNoNestedBrackets() == entry && fr.matchSequence("%w {")) + { + osgAnimation::StackedTransformElement* element = dynamic_cast(fr.readObject()); + if (element) + stackedTransform.push_back(element); + } + return iteratorAdvanced; +} + + + +bool UpdateMatrixTransform_writeLocalData(const Object& obj, Output& fw) +{ + const osgAnimation::UpdateMatrixTransform* uc = dynamic_cast(&obj); + const osgAnimation::StackedTransform& transforms = uc->getStackedTransforms(); + for (osgAnimation::StackedTransform::const_iterator it = transforms.begin(); it != transforms.end(); ++it) + { + osgAnimation::StackedTransformElement* element = it->get(); + if (element) + fw.writeObject(*element); + } + return true; +} + + +RegisterDotOsgWrapperProxy g_UpdateMatrixTransformProxy +( + new osgAnimation::UpdateMatrixTransform, + "osgAnimation::UpdateMatrixTransform", + "Object NodeCallback osgAnimation::UpdateMatrixTransform", + &UpdateMatrixTransform_readLocalData, + &UpdateMatrixTransform_writeLocalData, + DotOsgWrapper::READ_AND_WRITE + ); +