OpenSceneGraph/include/osgAnimation/EaseMotion
2008-12-18 11:06:57 +00:00

327 lines
9.7 KiB
C++

/* -*-c++-*-
* Copyright (C) 2008 Cedric Pinson <mornifle@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.
*/
#ifndef OSGANIMATION_EASE_MOTION_H
#define OSGANIMATION_EASE_MOTION_H
#include <osg/Referenced>
#include <osg/ref_ptr>
#include <osg/Notify>
#include <osg/Math>
#include <vector>
namespace osgAnimation {
struct OutBounceFunction
{
inline static void getValueAt(float t, float& result)
{
if ((t) < (1/2.75))
{
result = 7.5625 * t * t;
}
else if (t < (2/2.75))
{
t = t - (1.5/2.75);
result = 7.5625* t * t + .75;
}
else if (t < (2.5/2.75))
{
t = t - (2.25/2.75);
result = 7.5625 * t * t + .9375;
}
else
{
t = t - (2.625/2.75);
result = 7.5625* t * t + .984375;
}
}
};
struct InBounceFunction
{
inline static void getValueAt(float t, float& result)
{
OutBounceFunction::getValueAt(1-t, result);
result = 1 - result;
}
};
struct InOutBounceFunction
{
inline static void getValueAt(float t, float& result)
{
if (t < 0.5)
{
InBounceFunction::getValueAt(t * 2, result);
result *= 0.5;
}
else
{
OutBounceFunction::getValueAt(t * 2 - 1 , result);
result = result * 0.5 + 0.5;
}
}
};
/// Linear function
struct LinearFunction
{
inline static void getValueAt(float t, float& result) { result = t;}
};
/// Quad function
struct OutQuadFunction
{
inline static void getValueAt(float t, float& result) { result = - (t * (t -2.0));}
};
struct InQuadFunction
{
inline static void getValueAt(float t, float& result) { result = t*t;}
};
struct InOutQuadFunction
{
inline static void getValueAt(float t, float& result)
{
t = t * 2.0;
if (t < 1.0)
result = 0.5 * t * t;
else
{
t = t - 1.0;
result = - 0.5 * t * ( t - 2) - 1;
}
}
};
/// Cubic function
struct OutCubicFunction
{
inline static void getValueAt(float t, float& result) { t = t-1.0; result = t*t*t + 1;}
};
struct InCubicFunction
{
inline static void getValueAt(float t, float& result) { result = t*t*t;}
};
struct InOutCubicFunction
{
inline static void getValueAt(float t, float& result)
{
t = t * 2;
if (t < 1.0)
result = 0.5 * t * t * t;
else {
t = t - 2;
result = 0.5 * t * t * t + 2;
}
}
};
/// Quart function
struct InQuartFunction
{
inline static void getValueAt(float t, float& result) { result = t*t*t*t*t;}
};
struct OutQuartFunction
{
inline static void getValueAt(float t, float& result) { t = t - 1; result = - (t*t*t*t -1); }
};
struct InOutQuartFunction
{
inline static void getValueAt(float t, float& result)
{
t = t * 2.0;
if ( t < 1)
result = 0.5*t*t*t*t;
else
{
t -= 2.0;
result = -0.5 * (t*t*t*t -2);
}
}
};
class Motion : public osg::Referenced
{
public:
typedef float value_type;
enum TimeBehaviour
{
CLAMP,
LOOP
};
Motion(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : _time(0), _startValue(startValue), _changeValue(changeValue), _duration(duration), _behaviour(tb) {}
virtual ~Motion() {}
void reset() { setTime(0);}
float getTime() const { return _time; }
float evaluateTime(float time) const
{
switch (_behaviour)
{
case CLAMP:
if (time > _duration)
time = _duration;
else if (time < 0.0)
time = 0.0;
break;
case LOOP:
if (time <= 0)
time = 0;
else
time = fmodf(time, _duration);
break;
}
return time;
}
void update(float dt)
{
_time = evaluateTime(_time + dt);
}
void setTime(float time) { _time = evaluateTime(time);}
void getValue(value_type& result) const { getValueAt(_time, result); }
value_type getValue() const
{
value_type result;
getValueAt(_time, result);
return result;
}
void getValueAt(float time, value_type& result) const
{
getValueInNormalizedRange(evaluateTime(time)/_duration, result);
result = result * _changeValue + _startValue;
}
value_type getValueAt(float time) const
{
value_type result;
getValueAt(evaluateTime(time), result);
return result;
}
virtual void getValueInNormalizedRange(float t, value_type& result) const = 0;
float getDuration() const { return _duration;}
protected:
float _time;
float _startValue;
float _changeValue;
float _duration;
TimeBehaviour _behaviour;
};
template <typename T>
struct MathMotionTemplate : public Motion
{
MathMotionTemplate(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : Motion(startValue, duration, changeValue, tb) {}
virtual void getValueInNormalizedRange(float t, value_type& result) const { T::getValueAt(t, result); }
};
template <class T>
struct SamplerMotionTemplate : public Motion
{
T _sampler;
SamplerMotionTemplate(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : Motion(startValue, duration, changeValue, tb) {}
T& getSampler() { return _sampler;}
const T& getSampler() const { return _sampler;}
virtual void getValueInNormalizedRange(float t, value_type& result) const
{
if (!_sampler.getKeyframeContainer())
{
result = 0;
return;
}
float size = _sampler.getEndTime() - _sampler.getStartTime();
t = t * size + _sampler.getStartTime();
_sampler.getValueAt(t, result);
}
};
struct CompositeMotion : public Motion
{
typedef std::vector<osg::ref_ptr<Motion> > MotionList;
MotionList _motions;
MotionList& getMotionList() { return _motions; }
const MotionList& getMotionList() const { return _motions; }
CompositeMotion(float startValue = 0, float duration = 1, float changeValue = 1, TimeBehaviour tb = CLAMP) : Motion(startValue, duration, changeValue, tb) {}
virtual void getValueInNormalizedRange(float t, value_type& result) const
{
if (_motions.empty())
{
result = 0;
osg::notify(osg::WARN) << "CompositeMotion::getValueInNormalizedRange no Motion in the CompositeMotion, add motion to have result" << std::endl;
return;
}
for (MotionList::const_iterator it = _motions.begin(); it != _motions.end(); it++)
{
const Motion* motion = static_cast<const Motion*>(it->get());
float durationInRange = motion->getDuration() / getDuration();
if (t < durationInRange)
{
float tInRange = t/durationInRange * motion->getDuration();
motion->getValueAt( tInRange, result);
return;
} else
t = t - durationInRange;
}
osg::notify(osg::WARN) << "CompositeMotion::getValueInNormalizedRange did find the value in range, something wrong" << std::endl;
result = 0;
}
};
// linear
typedef MathMotionTemplate<LinearFunction > LinearMotion;
// quad
typedef MathMotionTemplate<OutQuadFunction > OutQuadMotion;
typedef MathMotionTemplate<InQuadFunction> InQuadMotion;
typedef MathMotionTemplate<InOutQuadFunction> InOutQuadMotion;
// cubic
typedef MathMotionTemplate<OutCubicFunction > OutCubicMotion;
typedef MathMotionTemplate<InCubicFunction> InCubicMotion;
typedef MathMotionTemplate<InOutCubicFunction> InOutCubicMotion;
// quart
typedef MathMotionTemplate<OutQuartFunction > OutQuartMotion;
typedef MathMotionTemplate<InQuartFunction> InQuartMotion;
typedef MathMotionTemplate<InOutQuartFunction> InOutQuartMotion;
// bounce
typedef MathMotionTemplate<OutBounceFunction > OutBounceMotion;
typedef MathMotionTemplate<InBounceFunction> InBounceMotion;
typedef MathMotionTemplate<InOutBounceFunction> InOutBounceMotion;
}
#endif