2006-07-18 23:21:48 +08:00
|
|
|
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
2003-01-22 00:45:36 +08:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2002-02-27 08:58:54 +08:00
|
|
|
#include <osg/AnimationPath>
|
2003-01-03 04:10:04 +08:00
|
|
|
#include <osg/MatrixTransform>
|
|
|
|
#include <osg/PositionAttitudeTransform>
|
2006-11-27 22:52:07 +08:00
|
|
|
#include <osg/Camera>
|
2005-10-05 17:48:53 +08:00
|
|
|
#include <osg/CameraView>
|
2005-04-08 17:01:23 +08:00
|
|
|
#include <osg/io_utils>
|
2002-02-27 08:58:54 +08:00
|
|
|
|
|
|
|
using namespace osg;
|
|
|
|
|
2002-10-10 22:58:44 +08:00
|
|
|
void AnimationPath::insert(double time,const ControlPoint& controlPoint)
|
2002-02-27 08:58:54 +08:00
|
|
|
{
|
2002-10-10 22:58:44 +08:00
|
|
|
_timeControlPointMap[time] = controlPoint;
|
2002-02-27 08:58:54 +08:00
|
|
|
}
|
|
|
|
|
2002-08-13 23:31:10 +08:00
|
|
|
bool AnimationPath::getInterpolatedControlPoint(double time,ControlPoint& controlPoint) const
|
2002-02-27 08:58:54 +08:00
|
|
|
{
|
2002-08-13 23:31:10 +08:00
|
|
|
if (_timeControlPointMap.empty()) return false;
|
|
|
|
|
|
|
|
switch(_loopMode)
|
2002-02-27 08:58:54 +08:00
|
|
|
{
|
2002-08-13 23:31:10 +08:00
|
|
|
case(SWING):
|
2002-02-27 08:58:54 +08:00
|
|
|
{
|
2002-08-13 23:31:10 +08:00
|
|
|
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;
|
|
|
|
|
2002-11-06 18:24:33 +08:00
|
|
|
time = getFirstTime()+(fraction_part*2.0) * getPeriod();
|
2002-08-13 23:31:10 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(LOOP):
|
2002-03-01 17:29:56 +08:00
|
|
|
{
|
2002-08-13 23:31:10 +08:00
|
|
|
double modulated_time = (time - getFirstTime())/getPeriod();
|
|
|
|
double fraction_part = modulated_time - floor(modulated_time);
|
2002-11-06 18:24:33 +08:00
|
|
|
time = getFirstTime()+fraction_part * getPeriod();
|
2002-08-13 23:31:10 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case(NO_LOOPING):
|
|
|
|
// no need to modulate the time.
|
|
|
|
break;
|
2002-03-01 17:29:56 +08:00
|
|
|
}
|
2002-08-13 23:31:10 +08:00
|
|
|
|
|
|
|
|
2002-08-13 21:22:46 +08:00
|
|
|
|
2002-08-13 23:31:10 +08:00
|
|
|
TimeControlPointMap::const_iterator second = _timeControlPointMap.lower_bound(time);
|
|
|
|
if (second==_timeControlPointMap.begin())
|
2002-04-22 06:05:26 +08:00
|
|
|
{
|
2002-08-13 23:31:10 +08:00
|
|
|
controlPoint = second->second;
|
2002-04-22 06:05:26 +08:00
|
|
|
}
|
2002-08-13 23:31:10 +08:00
|
|
|
else if (second!=_timeControlPointMap.end())
|
2002-04-22 06:05:26 +08:00
|
|
|
{
|
2002-08-13 23:31:10 +08:00
|
|
|
TimeControlPointMap::const_iterator first = second;
|
2002-08-13 21:22:46 +08:00
|
|
|
--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)
|
2002-08-13 23:31:10 +08:00
|
|
|
controlPoint = first->second;
|
2002-08-13 21:22:46 +08:00
|
|
|
else
|
2002-04-22 06:05:26 +08:00
|
|
|
{
|
2002-08-13 23:31:10 +08:00
|
|
|
controlPoint.interpolate((time - first->first)/delta_time,
|
2002-08-13 21:22:46 +08:00
|
|
|
first->second,
|
|
|
|
second->second);
|
|
|
|
}
|
2002-04-22 06:05:26 +08:00
|
|
|
}
|
2002-08-13 23:31:10 +08:00
|
|
|
else // (second==_timeControlPointMap.end())
|
2002-08-13 21:22:46 +08:00
|
|
|
{
|
2002-08-13 23:31:10 +08:00
|
|
|
controlPoint = _timeControlPointMap.rbegin()->second;
|
2002-08-13 21:22:46 +08:00
|
|
|
}
|
|
|
|
return true;
|
2002-04-22 06:05:26 +08:00
|
|
|
}
|
2003-01-03 04:10:04 +08:00
|
|
|
|
|
|
|
|
2003-11-04 07:13:31 +08:00
|
|
|
void AnimationPath::read(std::istream& in)
|
|
|
|
{
|
|
|
|
while (!in.eof())
|
|
|
|
{
|
|
|
|
double time;
|
2004-06-08 22:30:48 +08:00
|
|
|
osg::Vec3d position;
|
2003-11-04 07:13:31 +08:00
|
|
|
osg::Quat rotation;
|
|
|
|
in >> time >> position.x() >> position.y() >> position.z() >> rotation.x() >> rotation.y() >> rotation.z() >> rotation.w();
|
|
|
|
if(!in.eof())
|
|
|
|
insert(time,osg::AnimationPath::ControlPoint(position,rotation));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-02-21 04:10:51 +08:00
|
|
|
void AnimationPath::write(std::ostream& fout) const
|
2003-11-04 07:13:31 +08:00
|
|
|
{
|
2004-06-08 22:30:48 +08:00
|
|
|
int prec = fout.precision();
|
|
|
|
fout.precision(15);
|
|
|
|
|
2003-11-04 07:13:31 +08:00
|
|
|
const TimeControlPointMap& tcpm = getTimeControlPointMap();
|
|
|
|
for(TimeControlPointMap::const_iterator tcpmitr=tcpm.begin();
|
|
|
|
tcpmitr!=tcpm.end();
|
|
|
|
++tcpmitr)
|
|
|
|
{
|
|
|
|
const ControlPoint& cp = tcpmitr->second;
|
2004-12-17 09:06:33 +08:00
|
|
|
fout<<tcpmitr->first<<" "<<cp.getPosition()<<" "<<cp.getRotation()<<std::endl;
|
2003-11-04 07:13:31 +08:00
|
|
|
}
|
2004-06-08 22:30:48 +08:00
|
|
|
|
|
|
|
fout.precision(prec);
|
2003-11-04 07:13:31 +08:00
|
|
|
}
|
|
|
|
|
2005-11-09 23:11:22 +08:00
|
|
|
AnimationPathCallback::AnimationPathCallback(const osg::Vec3d& pivot,const osg::Vec3d& axis,float angularVelocity):
|
|
|
|
_pivotPoint(pivot),
|
|
|
|
_useInverseMatrix(false),
|
|
|
|
_timeOffset(0.0),
|
|
|
|
_timeMultiplier(1.0),
|
|
|
|
_firstTime(DBL_MAX),
|
|
|
|
_latestTime(0.0),
|
|
|
|
_pause(false),
|
|
|
|
_pauseTime(0.0)
|
|
|
|
{
|
|
|
|
_animationPath = new AnimationPath;
|
|
|
|
_animationPath->setLoopMode(osg::AnimationPath::LOOP);
|
|
|
|
|
|
|
|
double time0 = 0.0;
|
|
|
|
double time1 = osg::PI*0.5/angularVelocity;
|
|
|
|
double time2 = osg::PI*1.0/angularVelocity;
|
|
|
|
double time3 = osg::PI*1.5/angularVelocity;
|
|
|
|
double time4 = osg::PI*2.0/angularVelocity;
|
|
|
|
|
|
|
|
osg::Quat rotation0(0.0, axis);
|
|
|
|
osg::Quat rotation1(osg::PI*0.5, axis);
|
|
|
|
osg::Quat rotation2(osg::PI*1.0, axis);
|
|
|
|
osg::Quat rotation3(osg::PI*1.5, axis);
|
|
|
|
|
|
|
|
|
|
|
|
_animationPath->insert(time0,osg::AnimationPath::ControlPoint(pivot,rotation0));
|
|
|
|
_animationPath->insert(time1,osg::AnimationPath::ControlPoint(pivot,rotation1));
|
|
|
|
_animationPath->insert(time2,osg::AnimationPath::ControlPoint(pivot,rotation2));
|
|
|
|
_animationPath->insert(time3,osg::AnimationPath::ControlPoint(pivot,rotation3));
|
|
|
|
_animationPath->insert(time4,osg::AnimationPath::ControlPoint(pivot,rotation0));
|
|
|
|
}
|
|
|
|
|
2003-01-04 05:42:02 +08:00
|
|
|
class AnimationPathCallbackVisitor : public NodeVisitor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
2004-05-20 18:15:48 +08:00
|
|
|
AnimationPathCallbackVisitor(const AnimationPath::ControlPoint& cp, const osg::Vec3d& pivotPoint, bool useInverseMatrix):
|
2003-11-04 07:13:31 +08:00
|
|
|
_cp(cp),
|
2004-02-22 19:58:44 +08:00
|
|
|
_pivotPoint(pivotPoint),
|
2003-11-04 07:13:31 +08:00
|
|
|
_useInverseMatrix(useInverseMatrix) {}
|
2003-01-04 05:42:02 +08:00
|
|
|
|
2006-11-27 22:52:07 +08:00
|
|
|
virtual void apply(Camera& camera)
|
2005-10-05 17:48:53 +08:00
|
|
|
{
|
|
|
|
Matrix matrix;
|
|
|
|
if (_useInverseMatrix)
|
|
|
|
_cp.getInverse(matrix);
|
|
|
|
else
|
|
|
|
_cp.getMatrix(matrix);
|
|
|
|
|
|
|
|
camera.setViewMatrix(osg::Matrix::translate(-_pivotPoint)*matrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual void apply(CameraView& cv)
|
|
|
|
{
|
|
|
|
if (_useInverseMatrix)
|
|
|
|
{
|
|
|
|
Matrix matrix;
|
|
|
|
_cp.getInverse(matrix);
|
|
|
|
cv.setPosition(matrix.getTrans());
|
|
|
|
cv.setAttitude(_cp.getRotation().inverse());
|
|
|
|
cv.setFocalLength(1.0f/_cp.getScale().x());
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cv.setPosition(_cp.getPosition());
|
|
|
|
cv.setAttitude(_cp.getRotation());
|
|
|
|
cv.setFocalLength(_cp.getScale().x());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-04 05:42:02 +08:00
|
|
|
virtual void apply(MatrixTransform& mt)
|
|
|
|
{
|
|
|
|
Matrix matrix;
|
2003-11-04 07:13:31 +08:00
|
|
|
if (_useInverseMatrix)
|
|
|
|
_cp.getInverse(matrix);
|
|
|
|
else
|
|
|
|
_cp.getMatrix(matrix);
|
|
|
|
|
2004-02-22 19:58:44 +08:00
|
|
|
mt.setMatrix(osg::Matrix::translate(-_pivotPoint)*matrix);
|
2003-01-04 05:42:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void apply(PositionAttitudeTransform& pat)
|
|
|
|
{
|
2003-11-04 07:13:31 +08:00
|
|
|
if (_useInverseMatrix)
|
|
|
|
{
|
|
|
|
Matrix matrix;
|
|
|
|
_cp.getInverse(matrix);
|
|
|
|
pat.setPosition(matrix.getTrans());
|
2004-12-17 09:06:33 +08:00
|
|
|
pat.setAttitude(_cp.getRotation().inverse());
|
|
|
|
pat.setScale(osg::Vec3(1.0f/_cp.getScale().x(),1.0f/_cp.getScale().y(),1.0f/_cp.getScale().z()));
|
2004-02-22 19:58:44 +08:00
|
|
|
pat.setPivotPoint(_pivotPoint);
|
2003-11-04 07:13:31 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-12-17 09:06:33 +08:00
|
|
|
pat.setPosition(_cp.getPosition());
|
|
|
|
pat.setAttitude(_cp.getRotation());
|
|
|
|
pat.setScale(_cp.getScale());
|
2004-02-22 19:58:44 +08:00
|
|
|
pat.setPivotPoint(_pivotPoint);
|
2003-11-04 07:13:31 +08:00
|
|
|
}
|
2003-01-04 05:42:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
AnimationPath::ControlPoint _cp;
|
2004-05-20 18:15:48 +08:00
|
|
|
osg::Vec3d _pivotPoint;
|
2003-11-04 07:13:31 +08:00
|
|
|
bool _useInverseMatrix;
|
2003-01-04 05:42:02 +08:00
|
|
|
};
|
|
|
|
|
2003-01-03 04:10:04 +08:00
|
|
|
void AnimationPathCallback::operator()(Node* node, NodeVisitor* nv)
|
|
|
|
{
|
|
|
|
if (_animationPath.valid() &&
|
|
|
|
nv->getVisitorType()==NodeVisitor::UPDATE_VISITOR &&
|
|
|
|
nv->getFrameStamp())
|
|
|
|
{
|
|
|
|
double time = nv->getFrameStamp()->getReferenceTime();
|
2003-11-04 07:13:31 +08:00
|
|
|
_latestTime = time;
|
|
|
|
|
|
|
|
if (!_pause)
|
2003-01-04 05:42:02 +08:00
|
|
|
{
|
2004-01-12 21:53:04 +08:00
|
|
|
// Only update _firstTime the first time, when its value is still DBL_MAX
|
|
|
|
if (_firstTime==DBL_MAX) _firstTime = time;
|
2003-11-04 07:13:31 +08:00
|
|
|
update(*node);
|
2003-01-04 05:42:02 +08:00
|
|
|
}
|
2003-01-03 04:10:04 +08:00
|
|
|
}
|
2003-11-04 07:13:31 +08:00
|
|
|
|
2003-01-03 04:10:04 +08:00
|
|
|
// must call any nested node callbacks and continue subgraph traversal.
|
|
|
|
NodeCallback::traverse(node,nv);
|
|
|
|
}
|
2003-11-04 07:13:31 +08:00
|
|
|
|
2004-01-31 19:34:28 +08:00
|
|
|
double AnimationPathCallback::getAnimationTime() const
|
2003-11-04 07:13:31 +08:00
|
|
|
{
|
2004-01-31 19:34:28 +08:00
|
|
|
return ((_latestTime-_firstTime)-_timeOffset)*_timeMultiplier;
|
|
|
|
}
|
2003-11-04 07:13:31 +08:00
|
|
|
|
2004-01-31 19:34:28 +08:00
|
|
|
void AnimationPathCallback::update(osg::Node& node)
|
|
|
|
{
|
2003-11-04 07:13:31 +08:00
|
|
|
AnimationPath::ControlPoint cp;
|
2004-01-31 19:34:28 +08:00
|
|
|
if (_animationPath->getInterpolatedControlPoint(getAnimationTime(),cp))
|
2003-11-04 07:13:31 +08:00
|
|
|
{
|
2004-02-22 19:58:44 +08:00
|
|
|
AnimationPathCallbackVisitor apcv(cp,_pivotPoint,_useInverseMatrix);
|
2003-11-04 07:13:31 +08:00
|
|
|
node.accept(apcv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AnimationPathCallback::reset()
|
|
|
|
{
|
2004-08-25 02:23:53 +08:00
|
|
|
#if 1
|
|
|
|
_firstTime = DBL_MAX;
|
|
|
|
_pauseTime = DBL_MAX;
|
|
|
|
#else
|
2003-11-04 07:13:31 +08:00
|
|
|
_firstTime = _latestTime;
|
|
|
|
_pauseTime = _latestTime;
|
2004-08-25 02:23:53 +08:00
|
|
|
#endif
|
2003-11-04 07:13:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void AnimationPathCallback::setPause(bool pause)
|
|
|
|
{
|
|
|
|
if (_pause==pause)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_pause = pause;
|
2004-08-25 02:23:53 +08:00
|
|
|
|
|
|
|
if (_firstTime==DBL_MAX) return;
|
|
|
|
|
2003-11-04 07:13:31 +08:00
|
|
|
if (_pause)
|
|
|
|
{
|
|
|
|
_pauseTime = _latestTime;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_firstTime += (_latestTime-_pauseTime);
|
|
|
|
}
|
|
|
|
}
|