/* -*-c++-*- * Copyright (C) 2008 Cedric Pinson * * 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 #include #include #include #include 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); } } }; /// Elastic function struct OutElasticFunction { inline static void getValueAt(float t, float& result) { result = pow(2.0f, -10.0f * t) * sinf((t - 0.3f / 4.0f) * (2.0f * osg::PI) / 0.3f) + 1.0f; } }; struct InElasticFunction { inline static void getValueAt(float t, float& result) { OutElasticFunction::getValueAt(1.0f - t, result); result = 1.0f - result; } }; struct InOutElasticFunction { inline static void getValueAt(float t, float& result) { t *= 2.0f; if (t < 1.0f) { t -= 1.0f; result = -0.5 * (1.0f * pow(2.0f, 10.0f * t) * sinf((t - 0.45f / 4.0f) * (2.0f * osg::PI) / 0.45f)); } else { t -= 1.0f; result = pow(2.0f, -10.0f * t) * sinf((t - 0.45f / 4.0f) * (2.0f * osg::PI) / 0.45f) * 0.5f + 1.0f; } } }; 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 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 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 > 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(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 LinearMotion; // quad typedef MathMotionTemplate OutQuadMotion; typedef MathMotionTemplate InQuadMotion; typedef MathMotionTemplate InOutQuadMotion; // cubic typedef MathMotionTemplate OutCubicMotion; typedef MathMotionTemplate InCubicMotion; typedef MathMotionTemplate InOutCubicMotion; // quart typedef MathMotionTemplate OutQuartMotion; typedef MathMotionTemplate InQuartMotion; typedef MathMotionTemplate InOutQuartMotion; // bounce typedef MathMotionTemplate OutBounceMotion; typedef MathMotionTemplate InBounceMotion; typedef MathMotionTemplate InOutBounceMotion; // elastic typedef MathMotionTemplate OutElasticMotion; typedef MathMotionTemplate InElasticMotion; typedef MathMotionTemplate InOutElasticMotion; } #endif