4354c0180c
1) some time values were passed as floats, reducing accuracy. 2) comparisons done between doubles and floats gave different results so time < endtime evaluated to false the first time it was checked (with doubles), and true the second time it was checked (with time having been converted to a float). This consequently resulted in an array-out-of-bounds crash
241 lines
9.2 KiB
C++
241 lines
9.2 KiB
C++
/* -*-c++-*-
|
|
* Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
|
|
*
|
|
* 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 <cedric.pinson@plopbyte.net>
|
|
* Michael Platings <mplatings@pixelpower.com>
|
|
*/
|
|
|
|
#ifndef OSGANIMATION_INTERPOLATOR
|
|
#define OSGANIMATION_INTERPOLATOR 1
|
|
|
|
#include <osg/Notify>
|
|
#include <osgAnimation/Keyframe>
|
|
|
|
namespace osgAnimation
|
|
{
|
|
|
|
template <class TYPE, class KEY>
|
|
class TemplateInterpolatorBase
|
|
{
|
|
public:
|
|
typedef KEY KeyframeType;
|
|
typedef TYPE UsingType;
|
|
|
|
public:
|
|
mutable int _lastKeyAccess;
|
|
|
|
TemplateInterpolatorBase() : _lastKeyAccess(-1) {}
|
|
|
|
void reset() { _lastKeyAccess = -1; }
|
|
int getKeyIndexFromTime(const TemplateKeyframeContainer<KEY>& keys, double time) const
|
|
{
|
|
// todo use a cache
|
|
int key_size = keys.size();
|
|
if (!key_size) {
|
|
osg::notify(osg::WARN) << "TemplateInterpolatorBase::getKeyIndexFromTime the container is empty, impossible to get key index from time" << std::endl;;
|
|
return -1;
|
|
}
|
|
const TemplateKeyframe<KeyframeType>* keysVector = &keys.front();
|
|
for (int i = 0; i < key_size-1; i++)
|
|
{
|
|
double time0 = keysVector[i].getTime();
|
|
double time1 = keysVector[i+1].getTime();
|
|
|
|
if ( time >= time0 && time < time1 )
|
|
{
|
|
_lastKeyAccess = i;
|
|
return i;
|
|
}
|
|
}
|
|
osg::notify(osg::WARN) << time << " first key " << keysVector[0].getTime() << " last key " << keysVector[key_size-1].getTime() << std::endl;
|
|
return -1;
|
|
}
|
|
};
|
|
|
|
|
|
template <class TYPE, class KEY=TYPE>
|
|
class TemplateStepInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
|
|
{
|
|
public:
|
|
|
|
TemplateStepInterpolator() {}
|
|
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, double 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 TYPE, class KEY=TYPE>
|
|
class TemplateLinearInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
|
|
{
|
|
public:
|
|
|
|
TemplateLinearInterpolator() {}
|
|
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, double 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);
|
|
float blend = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
|
|
const TYPE& v1 = keyframes[i].getValue();
|
|
const TYPE& v2 = keyframes[i+1].getValue();
|
|
result = v1*(1-blend) + v2*blend;
|
|
}
|
|
};
|
|
|
|
|
|
template <class TYPE, class KEY=TYPE>
|
|
class TemplateSphericalLinearInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
|
|
{
|
|
public:
|
|
TemplateSphericalLinearInterpolator() {}
|
|
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, double 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);
|
|
float blend = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
|
|
const TYPE& q1 = keyframes[i].getValue();
|
|
const TYPE& q2 = keyframes[i+1].getValue();
|
|
result.slerp(blend,q1,q2);
|
|
}
|
|
};
|
|
|
|
|
|
template <class TYPE, class KEY>
|
|
class TemplateLinearPackedInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
|
|
{
|
|
public:
|
|
|
|
TemplateLinearPackedInterpolator() {}
|
|
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, double time, TYPE& result) const
|
|
{
|
|
if (time >= keyframes.back().getTime())
|
|
{
|
|
keyframes.back().getValue().uncompress(keyframes.mScale, keyframes.mMin, result);
|
|
return;
|
|
}
|
|
else if (time <= keyframes.front().getTime())
|
|
{
|
|
keyframes.front().getValue().uncompress(keyframes.mScale, keyframes.mMin, result);
|
|
return;
|
|
}
|
|
|
|
int i = getKeyIndexFromTime(keyframes,time);
|
|
float blend = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
|
|
TYPE v1,v2;
|
|
keyframes[i].getValue().uncompress(keyframes.mScale, keyframes.mMin, v1);
|
|
keyframes[i+1].getValue().uncompress(keyframes.mScale, keyframes.mMin, v2);
|
|
result = v1*(1-blend) + v2*blend;
|
|
}
|
|
};
|
|
|
|
|
|
// http://en.wikipedia.org/wiki/B%C3%A9zier_curve
|
|
template <class TYPE, class KEY=TYPE>
|
|
class TemplateCubicBezierInterpolator : public TemplateInterpolatorBase<TYPE,KEY>
|
|
{
|
|
public:
|
|
|
|
TemplateCubicBezierInterpolator() {}
|
|
void getValue(const TemplateKeyframeContainer<KEY>& keyframes, double time, TYPE& result) const
|
|
{
|
|
|
|
if (time >= keyframes.back().getTime())
|
|
{
|
|
result = keyframes.back().getValue().getPosition();
|
|
return;
|
|
}
|
|
else if (time <= keyframes.front().getTime())
|
|
{
|
|
result = keyframes.front().getValue().getPosition();
|
|
return;
|
|
}
|
|
|
|
int i = getKeyIndexFromTime(keyframes,time);
|
|
|
|
float t = (time - keyframes[i].getTime()) / ( keyframes[i+1].getTime() - keyframes[i].getTime());
|
|
float one_minus_t = 1.0-t;
|
|
float one_minus_t2 = one_minus_t * one_minus_t;
|
|
float one_minus_t3 = one_minus_t2 * one_minus_t;
|
|
float t2 = t * t;
|
|
|
|
TYPE v0 = keyframes[i].getValue().getPosition() * one_minus_t3;
|
|
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<double, double> DoubleStepInterpolator;
|
|
typedef TemplateStepInterpolator<float, float> FloatStepInterpolator;
|
|
typedef TemplateStepInterpolator<osg::Vec2, osg::Vec2> Vec2StepInterpolator;
|
|
typedef TemplateStepInterpolator<osg::Vec3, osg::Vec3> Vec3StepInterpolator;
|
|
typedef TemplateStepInterpolator<osg::Vec3, Vec3Packed> Vec3PackedStepInterpolator;
|
|
typedef TemplateStepInterpolator<osg::Vec4, osg::Vec4> Vec4StepInterpolator;
|
|
typedef TemplateStepInterpolator<osg::Quat, osg::Quat> QuatStepInterpolator;
|
|
|
|
typedef TemplateLinearInterpolator<double, double> DoubleLinearInterpolator;
|
|
typedef TemplateLinearInterpolator<float, float> FloatLinearInterpolator;
|
|
typedef TemplateLinearInterpolator<osg::Vec2, osg::Vec2> Vec2LinearInterpolator;
|
|
typedef TemplateLinearInterpolator<osg::Vec3, osg::Vec3> Vec3LinearInterpolator;
|
|
typedef TemplateLinearInterpolator<osg::Vec3, Vec3Packed> Vec3PackedLinearInterpolator;
|
|
typedef TemplateLinearInterpolator<osg::Vec4, osg::Vec4> Vec4LinearInterpolator;
|
|
typedef TemplateSphericalLinearInterpolator<osg::Quat, osg::Quat> QuatSphericalLinearInterpolator;
|
|
typedef TemplateLinearInterpolator<osg::Matrixf, osg::Matrixf> MatrixLinearInterpolator;
|
|
|
|
typedef TemplateCubicBezierInterpolator<float, FloatCubicBezier > FloatCubicBezierInterpolator;
|
|
typedef TemplateCubicBezierInterpolator<double, DoubleCubicBezier> DoubleCubicBezierInterpolator;
|
|
typedef TemplateCubicBezierInterpolator<osg::Vec2, Vec2CubicBezier> Vec2CubicBezierInterpolator;
|
|
typedef TemplateCubicBezierInterpolator<osg::Vec3, Vec3CubicBezier> Vec3CubicBezierInterpolator;
|
|
typedef TemplateCubicBezierInterpolator<osg::Vec4, Vec4CubicBezier> Vec4CubicBezierInterpolator;
|
|
|
|
}
|
|
#endif
|