diff --git a/include/osg/AnimationPath b/include/osg/AnimationPath index c7a600678..d83e1a6da 100644 --- a/include/osg/AnimationPath +++ b/include/osg/AnimationPath @@ -7,7 +7,6 @@ #include #include -#include #include @@ -17,29 +16,27 @@ namespace osg { * Subclassed from Transform::ComputeTransformCallback allows AnimationPath to * be attached directly to Transform nodes to move subgraphs around the scene. */ -class SG_EXPORT AnimationPath : public Transform::ComputeTransformCallback +class SG_EXPORT AnimationPath : public osg::Referenced { public: - AnimationPath() {} + AnimationPath():_loopMode(LOOP) {} - /** get the local transformation matrix for a point in time.*/ - virtual bool getMatrix(double time,Matrix& matrix) const; - - /** get the local inverse transformation matrix for a point in time.*/ - virtual bool getInverse(double time,Matrix& matrix) const; - - /** Get the transformation matrix which moves from local coords to world coords.*/ - virtual const bool computeLocalToWorldMatrix(Matrix& matrix,const Transform* transform, NodeVisitor* nv) const; - - /** Get the transformation matrix which moves from world coords to local coords.*/ - virtual const bool computeWorldToLocalMatrix(Matrix& matrix,const Transform* transform, NodeVisitor* nv) const; - - struct Key + struct ControlPoint { - Key() {} + ControlPoint() {} - Key(const osg::Vec3& position, const osg::Quat& rotation, const osg::Vec3& scale): + ControlPoint(const osg::Vec3& position): + _position(position), + _rotation(), + _scale() {} + + ControlPoint(const osg::Vec3& position, const osg::Quat& rotation): + _position(position), + _rotation(rotation), + _scale() {} + + ControlPoint(const osg::Vec3& position, const osg::Quat& rotation, const osg::Vec3& scale): _position(position), _rotation(rotation), _scale(scale) {} @@ -48,7 +45,7 @@ class SG_EXPORT AnimationPath : public Transform::ComputeTransformCallback osg::Quat _rotation; osg::Vec3 _scale; - inline void interpolate(const float ratio,const Key& first, const Key& second) + inline void interpolate(const float ratio,const ControlPoint& first, const ControlPoint& second) { float one_minus_ratio = 1.0f-ratio; _position = first._position*one_minus_ratio + second._position*ratio; @@ -71,16 +68,53 @@ class SG_EXPORT AnimationPath : public Transform::ComputeTransformCallback } }; + + /** get the transformation matrix for a point in time.*/ + bool getMatrix(double time,Matrix& 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,Matrix& matrix) const + { + ControlPoint cp; + if (!getInterpolatedControlPoint(time,cp)) return false; + cp.getInverse(matrix); + return true; + } - void insert(double time,const Key& key); + /** 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; } protected: virtual ~AnimationPath() {} - typedef std::map TimeKeyMap; + typedef std::map TimeControlPointMap; - TimeKeyMap _timeKeyMap; + TimeControlPointMap _timeControlPointMap; + LoopMode _loopMode; }; diff --git a/include/osg/Billboard b/include/osg/Billboard index 20980e55f..eb2aabd02 100644 --- a/include/osg/Billboard +++ b/include/osg/Billboard @@ -84,30 +84,11 @@ class SG_EXPORT Billboard : public Geode virtual const bool removeDrawable( Drawable *gset ); - /** Callback attached to an Billboard which allows the users to customize the billboard orientation calculation during cull traversal.*/ - struct ComputeBillboardCallback : public osg::Referenced - { - /** Get the transformation matrix which moves from local coords to world coords.*/ - virtual const bool computeMatrix(Matrix& modelview, const Billboard* billboard, const Vec3& eye_local, const Vec3& pos_local) const = 0; - }; - - /** Set the ComputeBillboardCallback which allows users to attach custom computation of the local transformation as - * seen by cull traversers and alike.*/ - void setComputeBillboardCallback(ComputeBillboardCallback* ctc) { _computeBillboardCallback=ctc; } - - /** Get the non const ComputeBillboardCallback.*/ - ComputeBillboardCallback* getComputeBillboardCallback() { return _computeBillboardCallback.get(); } - - /** Get the const ComputeBillboardCallback.*/ - const ComputeBillboardCallback* getComputeBillboardCallback() const { return _computeBillboardCallback.get(); } inline const bool getMatrix(Matrix& modelview, const Vec3& eye_local, const Vec3& pos_local) const { - if (_computeBillboardCallback.valid()) - return _computeBillboardCallback->computeMatrix(modelview,this,eye_local,pos_local); - else - return computeMatrix(modelview,eye_local,pos_local); + return computeMatrix(modelview,eye_local,pos_local); } virtual const bool computeMatrix(Matrix& modelview, const Vec3& eye_local, const Vec3& pos_local) const; @@ -131,7 +112,6 @@ class SG_EXPORT Billboard : public Geode Vec3 _axis; Vec3 _normal; PositionList _positionList; - ref_ptr _computeBillboardCallback; // used internally as cache of which what _axis is aligned to help // deicde which method of rotation to use. diff --git a/include/osg/MatrixTransform b/include/osg/MatrixTransform index 52b951a68..0764ad856 100644 --- a/include/osg/MatrixTransform +++ b/include/osg/MatrixTransform @@ -6,6 +6,7 @@ #define OSG_MATRIXTRANSFORM 1 #include +#include namespace osg { @@ -78,6 +79,23 @@ class SG_EXPORT MatrixTransform : public Transform return true; } + /** Callback which can be attached to a MatrixTransform as an app + * callback to allow it to follow the path defined by a AnimationPath.*/ + class AnimationPathCallback : public NodeCallback + { + public: + + AnimationPathCallback(AnimationPath* ap): + _animationPath(ap), + _firstTime(0.0) {} + + /** implements the callback*/ + virtual void operator()(Node* node, NodeVisitor* nv); + + ref_ptr _animationPath; + double _firstTime; + }; + protected : virtual ~MatrixTransform(); diff --git a/include/osg/PositionAttitudeTransform b/include/osg/PositionAttitudeTransform index 16303b67c..53725d595 100644 --- a/include/osg/PositionAttitudeTransform +++ b/include/osg/PositionAttitudeTransform @@ -7,11 +7,12 @@ #include #include +#include #include namespace osg { -/** PositionAttitideTransform - is Transfrom the set the coordinates transform +/** PositionAttitideTransform - is Transform the set the coordinates transform up via a Vec3 position and Quat attitude. */ class SG_EXPORT PositionAttitudeTransform : public Transform @@ -48,6 +49,26 @@ class SG_EXPORT PositionAttitudeTransform : public Transform virtual const bool computeWorldToLocalMatrix(Matrix& matrix,NodeVisitor* nv) const; + + /** Callback which can be attached to a PositionAttitudeTransform + * as an app callback to allow it to follow the path defined by a + * AnimationPath.*/ + class AnimationPathCallback : public NodeCallback + { + public: + + AnimationPathCallback(AnimationPath* ap): + _animationPath(ap), + _firstTime(0.0) {} + + /** implements the callback*/ + virtual void operator()(Node* node, NodeVisitor* nv); + + ref_ptr _animationPath; + double _firstTime; + }; + + protected : diff --git a/src/Demos/osgcallback/osgcallback.cpp b/src/Demos/osgcallback/osgcallback.cpp index 5016bc66d..0dff60474 100644 --- a/src/Demos/osgcallback/osgcallback.cpp +++ b/src/Demos/osgcallback/osgcallback.cpp @@ -113,19 +113,6 @@ struct TransformCallback : public osg::Transform::ComputeTransformCallback } }; - -struct BillboardCallback : public osg::Billboard::ComputeBillboardCallback -{ - /** Get the transformation matrix which moves from local coords to world coords.*/ - virtual const bool computeMatrix(osg::Matrix& modelview, const osg::Billboard* billboard, const osg::Vec3& eye_local, const osg::Vec3& pos_local) const - { - std::cout<<"ComputeBillboardCallback - pre billboard->computeMatrix"<computeMatrix(modelview,eye_local,pos_local); - std::cout<<"ComputeBillboardCallback - post billboard->computeMatrix"<setStateSetModes(*rootStateSet,osg::StateAttribute::ON); - osg::PositionAttitudeTransform* pat = new osg::PositionAttitudeTransform(); + osg::MatrixTransform* mt = new osg::MatrixTransform(); { // set up the animation path osg::AnimationPath* animationPath = new osg::AnimationPath; - animationPath->insert(0.0,osg::AnimationPath::Key(bb.corner(0))); - animationPath->insert(1.0,osg::AnimationPath::Key(bb.corner(1))); - animationPath->insert(2.0,osg::AnimationPath::Key(bb.corner(2))); - animationPath->insert(3.0,osg::AnimationPath::Key(bb.corner(3))); - animationPath->insert(4.0,osg::AnimationPath::Key(bb.corner(4))); - animationPath->insert(5.0,osg::AnimationPath::Key(bb.corner(5))); - animationPath->insert(6.0,osg::AnimationPath::Key(bb.corner(6))); - animationPath->insert(7.0,osg::AnimationPath::Key(bb.corner(7))); - animationPath->insert(8.0,osg::AnimationPath::Key(bb.corner(0))); + animationPath->insert(0.0,osg::AnimationPath::ControlPoint(bb.corner(0))); + animationPath->insert(1.0,osg::AnimationPath::ControlPoint(bb.corner(1))); + animationPath->insert(2.0,osg::AnimationPath::ControlPoint(bb.corner(2))); + animationPath->insert(3.0,osg::AnimationPath::ControlPoint(bb.corner(3))); + animationPath->insert(4.0,osg::AnimationPath::ControlPoint(bb.corner(4))); + animationPath->insert(5.0,osg::AnimationPath::ControlPoint(bb.corner(5))); + animationPath->insert(6.0,osg::AnimationPath::ControlPoint(bb.corner(6))); + animationPath->insert(7.0,osg::AnimationPath::ControlPoint(bb.corner(7))); + animationPath->insert(8.0,osg::AnimationPath::ControlPoint(bb.corner(0))); + animationPath->setLoopMode(osg::AnimationPath::SWING); - // attach it to the transform as an app callback. - pat->setAppCallback(new osg::PositionAttitudeTransform::AnimationPathCallback(animationPath)); + mt->setAppCallback(new osg::MatrixTransform::AnimationPathCallback(animationPath)); } // create marker for point light. @@ -144,12 +144,12 @@ osg::Node* createLights(osg::BoundingBox& bb,osg::StateSet* rootStateSet) osg::Geode* markerGeode = new osg::Geode; markerGeode->addDrawable(marker); - pat->addChild(lightS2); - pat->addChild(markerGeode); + mt->addChild(lightS2); + mt->addChild(markerGeode); lightGroup->addChild(lightS2); - lightGroup->addChild(pat); + lightGroup->addChild(mt); return lightGroup; } diff --git a/src/osg/AnimationPath.cpp b/src/osg/AnimationPath.cpp index f9b83b2ad..f1521e557 100644 --- a/src/osg/AnimationPath.cpp +++ b/src/osg/AnimationPath.cpp @@ -3,23 +3,50 @@ using namespace osg; -void AnimationPath::insert(double time,const Key& key) +void AnimationPath::insert(double time,const ControlPoint& ControlPoint) { - _timeKeyMap[time] = key; + _timeControlPointMap[time] = ControlPoint; } -bool AnimationPath::getMatrix(double time,Matrix& matrix) const +bool AnimationPath::getInterpolatedControlPoint(double time,ControlPoint& controlPoint) const { - if (_timeKeyMap.empty()) return false; - - TimeKeyMap::const_iterator second = _timeKeyMap.lower_bound(time); - if (second==_timeKeyMap.begin()) + if (_timeControlPointMap.empty()) return false; + + + + switch(_loopMode) { - second->second.getMatrix(matrix); + case(SWING): + { + double modulated_time = (time - getFirstTime())/(getPeriod()*2.0); + double fraction_part = modulated_time - floor(modulated_time); + if (fraction_part>0.5) fraction_part = 1.0-fraction_part; + + time = (fraction_part*2.0) * getPeriod(); + break; + } + case(LOOP): + { + double modulated_time = (time - getFirstTime())/getPeriod(); + double fraction_part = modulated_time - floor(modulated_time); + time = fraction_part * getPeriod(); + break; + } + case(NO_LOOPING): + // no need to modulate the time. + break; } - else if (second!=_timeKeyMap.end()) + + + + TimeControlPointMap::const_iterator second = _timeControlPointMap.lower_bound(time); + if (second==_timeControlPointMap.begin()) { - TimeKeyMap::const_iterator first = second; + controlPoint = second->second; + } + else if (second!=_timeControlPointMap.end()) + { + TimeControlPointMap::const_iterator first = second; --first; // we have both a lower bound and the next item. @@ -28,92 +55,17 @@ bool AnimationPath::getMatrix(double time,Matrix& matrix) const double delta_time = second->first - first->first; if (delta_time==0.0) - first->second.getMatrix(matrix); + controlPoint = first->second; else { - Key key; - key.interpolate((time - first->first)/delta_time, - first->second, - second->second); - key.getMatrix(matrix); - } - } - else // (second==_timeKeyMap.end()) - { - _timeKeyMap.rbegin().base()->second.getMatrix(matrix); - } - return true; -} - -bool AnimationPath::getInverse(double time,Matrix& matrix) const -{ - if (_timeKeyMap.empty()) return false; - - TimeKeyMap::const_iterator second = _timeKeyMap.lower_bound(time); - if (second==_timeKeyMap.begin()) - { - second->second.getInverse(matrix); - } - else if (second!=_timeKeyMap.end()) - { - TimeKeyMap::const_iterator first = second; - --first; - - // we have both a lower bound and the next item. - - // deta_time = second.time - first.time - double delta_time = second->first - first->first; - - if (delta_time==0.0) - first->second.getInverse(matrix); - else - { - Key key; - key.interpolate((time - first->first)/delta_time, - first->second, - second->second); - key.getInverse(matrix); - } - } - else // (second==_timeKeyMap.end()) - { - _timeKeyMap.rbegin().base()->second.getInverse(matrix); - } - return true; -} - - -bool AnimationPath::getKeyFrame(double time,Key& key) const -{ - if (_timeKeyMap.empty()) return false; - - TimeKeyMap::const_iterator second = _timeKeyMap.lower_bound(time); - if (second==_timeKeyMap.begin()) - { - key = second->second; - } - else if (second!=_timeKeyMap.end()) - { - TimeKeyMap::const_iterator first = second; - --first; - - // we have both a lower bound and the next item. - - // deta_time = second.time - first.time - double delta_time = second->first - first->first; - - if (delta_time==0.0) - key = first->second; - else - { - key.interpolate((time - first->first)/delta_time, + controlPoint.interpolate((time - first->first)/delta_time, first->second, second->second); } } - else // (second==_timeKeyMap.end()) + else // (second==_timeControlPointMap.end()) { - key = _timeKeyMap.rbegin().base()->second; + controlPoint = _timeControlPointMap.rbegin()->second; } return true; } diff --git a/src/osg/Billboard.cpp b/src/osg/Billboard.cpp index 8f3909957..267766274 100644 --- a/src/osg/Billboard.cpp +++ b/src/osg/Billboard.cpp @@ -21,7 +21,6 @@ Billboard::Billboard(const Billboard& billboard,const CopyOp& copyop): _axis(billboard._axis), _normal(billboard._normal), _positionList(billboard._positionList), - _computeBillboardCallback(_computeBillboardCallback), _cachedMode(billboard._cachedMode), _side(billboard._side) {} diff --git a/src/osg/MatrixTransform.cpp b/src/osg/MatrixTransform.cpp index 8b542f89a..3d41f709c 100644 --- a/src/osg/MatrixTransform.cpp +++ b/src/osg/MatrixTransform.cpp @@ -30,3 +30,21 @@ MatrixTransform::MatrixTransform(const Matrix& mat ) MatrixTransform::~MatrixTransform() { } + +void MatrixTransform::AnimationPathCallback::operator()(Node* node, NodeVisitor* nv) +{ + MatrixTransform* mt = dynamic_cast(node); + if (mt && + _animationPath.valid() && + nv->getVisitorType()==NodeVisitor::APP_VISITOR && + nv->getFrameStamp()) + { + double time = nv->getFrameStamp()->getReferenceTime(); + if (_firstTime==0.0) _firstTime = time; + Matrix matrix; + if (_animationPath->getMatrix(time-_firstTime,matrix)) + { + mt->setMatrix(matrix); + } + } +} diff --git a/src/osg/PositionAttitudeTransform.cpp b/src/osg/PositionAttitudeTransform.cpp index 840d61e81..3a6806dce 100644 --- a/src/osg/PositionAttitudeTransform.cpp +++ b/src/osg/PositionAttitudeTransform.cpp @@ -51,11 +51,11 @@ void PositionAttitudeTransform::AnimationPathCallback::operator()(Node* node, No { double time = nv->getFrameStamp()->getReferenceTime(); if (_firstTime==0.0) _firstTime = time; - AnimationPath::Key key; - if (_animationPath->getKeyFrame(time-_firstTime,key)) + AnimationPath::ControlPoint cp; + if (_animationPath->getInterpolatedControlPoint(time-_firstTime,cp)) { - pat->setPosition(key._position); - pat->setAttitude(key._rotation); + pat->setPosition(cp._position); + pat->setAttitude(cp._rotation); } } }