/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 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. */ #ifndef OSG_ANIMATIONPATH #define OSG_ANIMATIONPATH 1 #include #include #include #include #include #include #include namespace osg { /** AnimationPath for specify the time varying transformation pathway to use when update camera and model objects. * Subclassed from Transform::ComputeTransformCallback allows AnimationPath to * be attached directly to Transform nodes to move subgraphs around the scene. */ class SG_EXPORT AnimationPath : public virtual osg::Object { public: AnimationPath():_loopMode(LOOP) {} AnimationPath(const AnimationPath& ap, const CopyOp& copyop=CopyOp::SHALLOW_COPY): Object(ap,copyop), _timeControlPointMap(ap._timeControlPointMap), _loopMode(ap._loopMode) {} META_Object(osg,AnimationPath); struct ControlPoint { ControlPoint(): _scale(1.0f,1.0f,1.0f) {} ControlPoint(const osg::Vec3d& position): _position(position), _rotation(), _scale(1.0f,1.0f,1.0f) {} ControlPoint(const osg::Vec3d& position, const osg::Quat& rotation): _position(position), _rotation(rotation), _scale(1.0f,1.0f,1.0f) {} ControlPoint(const osg::Vec3d& position, const osg::Quat& rotation, const osg::Vec3d& scale): _position(position), _rotation(rotation), _scale(scale) {} osg::Vec3d _position; osg::Quat _rotation; osg::Vec3d _scale; inline void interpolate(float ratio,const ControlPoint& first, const ControlPoint& second) { float one_minus_ratio = 1.0f-ratio; _position = first._position*one_minus_ratio + second._position*ratio; _rotation.slerp(ratio,first._rotation,second._rotation); _scale = first._scale*one_minus_ratio + second._scale*ratio; } inline void getMatrix(Matrixf& matrix) const { matrix.makeScale(_scale); matrix.postMult(osg::Matrixf::rotate(_rotation)); matrix.postMult(osg::Matrixf::translate(_position)); } inline void getMatrix(Matrixd& matrix) const { matrix.makeScale(_scale); matrix.postMult(osg::Matrixd::rotate(_rotation)); matrix.postMult(osg::Matrixd::translate(_position)); } inline void getInverse(Matrixf& matrix) const { matrix.makeScale(1.0f/_scale.x(),1.0f/_scale.y(),1.0f/_scale.y()); matrix.preMult(osg::Matrixf::rotate(_rotation.inverse())); matrix.preMult(osg::Matrixf::translate(-_position)); } inline void getInverse(Matrixd& matrix) const { matrix.makeScale(1.0f/_scale.x(),1.0f/_scale.y(),1.0f/_scale.y()); matrix.preMult(osg::Matrixd::rotate(_rotation.inverse())); matrix.preMult(osg::Matrixd::translate(-_position)); } }; /** get the transformation matrix for a point in time.*/ bool getMatrix(double time,Matrixf& matrix) const { ControlPoint cp; if (!getInterpolatedControlPoint(time,cp)) return false; cp.getMatrix(matrix); return true; } /** get the transformation matrix for a point in time.*/ bool getMatrix(double time,Matrixd& matrix) const { ControlPoint cp; if (!getInterpolatedControlPoint(time,cp)) return false; cp.getMatrix(matrix); return true; } /** get the inverse transformation matrix for a point in time.*/ bool getInverse(double time,Matrixf& matrix) const { ControlPoint cp; if (!getInterpolatedControlPoint(time,cp)) return false; cp.getInverse(matrix); return true; } bool getInverse(double time,Matrixd& matrix) const { ControlPoint cp; if (!getInterpolatedControlPoint(time,cp)) return false; cp.getInverse(matrix); return true; } /** get the local ControlPoint frame for a point in time.*/ virtual bool getInterpolatedControlPoint(double time,ControlPoint& controlPoint) const; void insert(double time,const ControlPoint& controlPoint); double getFirstTime() const { if (!_timeControlPointMap.empty()) return _timeControlPointMap.begin()->first; else return 0.0;} double getLastTime() const { if (!_timeControlPointMap.empty()) return _timeControlPointMap.rbegin()->first; else return 0.0;} double getPeriod() const { return getLastTime()-getFirstTime();} enum LoopMode { SWING, LOOP, NO_LOOPING }; void setLoopMode(LoopMode lm) { _loopMode = lm; } LoopMode getLoopMode() const { return _loopMode; } typedef std::map TimeControlPointMap; TimeControlPointMap& getTimeControlPointMap() { return _timeControlPointMap; } const TimeControlPointMap& getTimeControlPointMap() const { return _timeControlPointMap; } bool empty() const { return _timeControlPointMap.empty(); } /** read the anumation path from a flat ascii file stream.*/ void read(std::istream& in); /** write the anumation path to a flat ascii file stream.*/ void write(std::ostream& out) const; protected: virtual ~AnimationPath() {} TimeControlPointMap _timeControlPointMap; LoopMode _loopMode; }; class SG_EXPORT AnimationPathCallback : public NodeCallback { public: AnimationPathCallback(): _pivotPoint(0.0f,0.0f,0.0f), _useInverseMatrix(false), _timeOffset(0.0), _timeMultiplier(1.0), _firstTime(DBL_MAX), _latestTime(0.0), _pause(false), _pauseTime(0.0) {} AnimationPathCallback(const AnimationPathCallback& apc,const CopyOp& copyop): NodeCallback(apc,copyop), _animationPath(apc._animationPath), _pivotPoint(apc._pivotPoint), _useInverseMatrix(apc._useInverseMatrix), _timeOffset(apc._timeOffset), _timeMultiplier(apc._timeMultiplier), _firstTime(apc._firstTime), _latestTime(apc._latestTime), _pause(apc._pause), _pauseTime(apc._pauseTime) {} META_Object(osg,AnimationPathCallback); AnimationPathCallback(AnimationPath* ap,double timeOffset=0.0f,double timeMultiplier=1.0f): _animationPath(ap), _pivotPoint(0.0f,0.0f,0.0f), _useInverseMatrix(false), _timeOffset(timeOffset), _timeMultiplier(timeMultiplier), _firstTime(DBL_MAX), _latestTime(0.0), _pause(false), _pauseTime(0.0) {} void setAnimationPath(AnimationPath* path) { _animationPath = path; } AnimationPath* getAnimationPath() { return _animationPath.get(); } const AnimationPath* getAnimationPath() const { return _animationPath.get(); } inline void setPivotPoint(const Vec3d& pivot) { _pivotPoint = pivot; } inline const Vec3d& getPivotPoint() const { return _pivotPoint; } void setUseInverseMatrix(bool useInverseMatrix) { _useInverseMatrix = useInverseMatrix; } bool getUseInverseMatrix() const { return _useInverseMatrix; } void setTimeOffset(double offset) { _timeOffset = offset; } double getTimeOffset() const { return _timeOffset; } void setTimeMultiplier(double multiplier) { _timeMultiplier = multiplier; } double getTimeMultiplier() const { return _timeMultiplier; } void reset(); void setPause(bool pause); /** get the animation time that is used to specify the position along the AnimationPath. * Animation time is computed from the formula ((_latestTime-_firstTime)-_timeOffset)*_timeMultiplier.*/ double getAnimationTime() const; /** implements the callback*/ virtual void operator()(Node* node, NodeVisitor* nv); void update(osg::Node& node); public: ref_ptr _animationPath; osg::Vec3d _pivotPoint; bool _useInverseMatrix; double _timeOffset; double _timeMultiplier; double _firstTime; double _latestTime; bool _pause; double _pauseTime; protected: ~AnimationPathCallback(){} }; } #endif