OpenSceneGraph/include/osg/AnimationPath
2007-06-13 19:54:00 +00:00

311 lines
11 KiB
C++

/* -*-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.
*/
#ifndef OSG_ANIMATIONPATH
#define OSG_ANIMATIONPATH 1
#include <map>
#include <istream>
#include <float.h>
#include <osg/Matrixf>
#include <osg/Matrixd>
#include <osg/Quat>
#include <osg/NodeCallback>
namespace osg {
/** AnimationPath encapsulates a time varying transformation pathway. Can be
* used for updating camera position and model object position.
* AnimationPathCallback can be attached directly to Transform nodes to
* move subgraphs around the scene.
*/
class OSG_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);
class ControlPoint
{
public:
ControlPoint():
_scale(1.0,1.0,1.0) {}
ControlPoint(const osg::Vec3d& position):
_position(position),
_rotation(),
_scale(1.0,1.0,1.0) {}
ControlPoint(const osg::Vec3d& position, const osg::Quat& rotation):
_position(position),
_rotation(rotation),
_scale(1.0,1.0,1.0) {}
ControlPoint(const osg::Vec3d& position, const osg::Quat& rotation, const osg::Vec3d& scale):
_position(position),
_rotation(rotation),
_scale(scale) {}
void setPosition(const osg::Vec3d& position) { _position = position; }
const osg::Vec3d& getPosition() const { return _position; }
void setRotation(const osg::Quat& rotation) { _rotation = rotation; }
const osg::Quat& getRotation() const { return _rotation; }
void setScale(const osg::Vec3d& scale) { _scale = scale; }
const osg::Vec3d& getScale() const { return _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 interpolate(double ratio,const ControlPoint& first, const ControlPoint& second)
{
double 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.0/_scale.x(),1.0/_scale.y(),1.0/_scale.z());
matrix.preMult(osg::Matrixf::rotate(_rotation.inverse()));
matrix.preMult(osg::Matrixf::translate(-_position));
}
inline void getInverse(Matrixd& matrix) const
{
matrix.makeScale(1.0/_scale.x(),1.0/_scale.y(),1.0/_scale.z());
matrix.preMult(osg::Matrixd::rotate(_rotation.inverse()));
matrix.preMult(osg::Matrixd::translate(-_position));
}
protected:
osg::Vec3d _position;
osg::Quat _rotation;
osg::Vec3d _scale;
};
/** Given a specific time, return the transformation matrix for a point. */
bool getMatrix(double time,Matrixf& matrix) const
{
ControlPoint cp;
if (!getInterpolatedControlPoint(time,cp)) return false;
cp.getMatrix(matrix);
return true;
}
/** Given a specific time, return the transformation matrix for a point..*/
bool getMatrix(double time,Matrixd& matrix) const
{
ControlPoint cp;
if (!getInterpolatedControlPoint(time,cp)) return false;
cp.getMatrix(matrix);
return true;
}
/** Given a specific time, return the inverse transformation matrix for a point. */
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;
}
/** Given a specific time, return the local ControlPoint frame for a point. */
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<double,ControlPoint> TimeControlPointMap;
void setTimeControlPointMap(TimeControlPointMap& tcpm) { _timeControlPointMap=tcpm; }
TimeControlPointMap& getTimeControlPointMap() { return _timeControlPointMap; }
const TimeControlPointMap& getTimeControlPointMap() const { return _timeControlPointMap; }
bool empty() const { return _timeControlPointMap.empty(); }
void clear() { _timeControlPointMap.clear(); }
/** Read the animation path from a flat ASCII file stream. */
void read(std::istream& in);
/** Write the animation path to a flat ASCII file stream. */
void write(std::ostream& out) const;
protected:
virtual ~AnimationPath() {}
TimeControlPointMap _timeControlPointMap;
LoopMode _loopMode;
};
class OSG_EXPORT AnimationPathCallback : public NodeCallback
{
public:
AnimationPathCallback():
_pivotPoint(0.0,0.0,0.0),
_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);
/** Construct an AnimationPathCallback with a specified animation path.*/
AnimationPathCallback(AnimationPath* ap,double timeOffset=0.0,double timeMultiplier=1.0):
_animationPath(ap),
_pivotPoint(0.0,0.0,0.0),
_useInverseMatrix(false),
_timeOffset(timeOffset),
_timeMultiplier(timeMultiplier),
_firstTime(DBL_MAX),
_latestTime(0.0),
_pause(false),
_pauseTime(0.0) {}
/** Construct an AnimationPathCallback and automatical create an animation path to produce a rotation about a point.*/
AnimationPathCallback(const osg::Vec3d& pivot,const osg::Vec3d& axis,float angularVelocity);
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);
bool getPause() const { return _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> _animationPath;
osg::Vec3d _pivotPoint;
bool _useInverseMatrix;
double _timeOffset;
double _timeMultiplier;
double _firstTime;
double _latestTime;
bool _pause;
double _pauseTime;
protected:
~AnimationPathCallback(){}
};
}
#endif