/* * Copyright (C) 2017 Christopher J. Howard * * This file is part of Antkeeper Source Code. * * Antkeeper Source Code is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Antkeeper Source Code 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 * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Antkeeper Source Code. If not, see . */ #ifndef TWEEN_HPP #define TWEEN_HPP #include #include #include #include #include using namespace Emergent; /// @see http://easings.net/ /// @see http://wiki.unity3d.com/index.php?title=Tween enum class EaseFunction { LINEAR, IN_SINE, OUT_SINE, IN_OUT_SINE, IN_QUAD, OUT_QUAD, IN_OUT_QUAD, IN_CUBIC, OUT_CUBIC, IN_OUT_CUBIC, IN_QUART, OUT_QUART, IN_OUT_QUART, IN_QUINT, OUT_QUINT, IN_OUT_QUINT, IN_EXPO, OUT_EXPO, IN_OUT_EXPO, IN_CIRC, OUT_CIRC, IN_OUT_CIRC, IN_BACK, OUT_BACK, IN_OUT_BACK, IN_BOUNCE, OUT_BOUNCE, IN_OUT_BOUNCE }; class TweenBase { public: TweenBase(EaseFunction function, float time, float duration); TweenBase(); virtual ~TweenBase(); void start(); void stop(); void pause(); void reset(); void setEaseFunction(EaseFunction function); void setTime(float time); void setDuration(float duration); EaseFunction getEaseFunction() const; float getTime() const; float getDuration() const; bool isStopped() const; bool wasStopped() const; bool isPaused() const; protected: typedef float (*EaseFunctionPointer)(float, float, float, float); EaseFunction easeFunction; EaseFunctionPointer easeFunctionPointer; float time; float duration; bool stopped; bool oldStopped; bool paused; private: friend class Tweener; static const EaseFunctionPointer easeFunctionPointers[28]; virtual void update(float dt) = 0; static float easeLinear(float t, float b, float c, float d); static float easeInSine(float t, float b, float c, float d); static float easeOutSine(float t, float b, float c, float d); static float easeInOutSine(float t, float b, float c, float d); static float easeInQuad(float t, float b, float c, float d); static float easeOutQuad(float t, float b, float c, float d); static float easeInOutQuad(float t, float b, float c, float d); static float easeInCubic(float t, float b, float c, float d); static float easeOutCubic(float t, float b, float c, float d); static float easeInOutCubic(float t, float b, float c, float d); static float easeInQuart(float t, float b, float c, float d); static float easeOutQuart(float t, float b, float c, float d); static float easeInOutQuart(float t, float b, float c, float d); static float easeInQuint(float t, float b, float c, float d); static float easeOutQuint(float t, float b, float c, float d); static float easeInOutQuint(float t, float b, float c, float d); static float easeInExpo(float t, float b, float c, float d); static float easeOutExpo(float t, float b, float c, float d); static float easeInOutExpo(float t, float b, float c, float d); static float easeInCirc(float t, float b, float c, float d); static float easeOutCirc(float t, float b, float c, float d); static float easeInOutCirc(float t, float b, float c, float d); static float easeInBack(float t, float b, float c, float d); static float easeOutBack(float t, float b, float c, float d); static float easeInOutBack(float t, float b, float c, float d); static float easeInBounce(float t, float b, float c, float d); static float easeOutBounce(float t, float b, float c, float d); static float easeInOutBounce(float t, float b, float c, float d); }; inline EaseFunction TweenBase::getEaseFunction() const { return easeFunction; } inline float TweenBase::getTime() const { return time; } inline float TweenBase::getDuration() const { return duration; } inline bool TweenBase::isStopped() const { return stopped; } inline bool TweenBase::wasStopped() const { return oldStopped; } inline bool TweenBase::isPaused() const { return paused; } template class Tween: public TweenBase { public: Tween(EaseFunction function, float time, float duration, const T& startValue, const T& deltaValue); Tween(); virtual ~Tween(); void setStartValue(const T& startValue); void setDeltaValue(const T& deltaValue); void setStartCallback(std::function callback); void setUpdateCallback(std::function callback); void setEndCallback(std::function callback); const T& getStartValue() const; const T& getDeltaValue() const; const T& getTweenValue() const; std::function getStartCallback() const; std::function getUpdateCallback() const; std::function getEndCallback() const; private: virtual void update(float dt); void calculateTweenValue(); T startValue; T deltaValue; T tweenValue; std::function startCallback; std::function updateCallback; std::function endCallback; }; template Tween::Tween(EaseFunction function, float time, float duration, const T& startValue, const T& deltaValue): TweenBase(function, time, duration), startValue(startValue), deltaValue(deltaValue), tweenValue(startValue), startCallback(nullptr), updateCallback(nullptr), endCallback(nullptr) {} template Tween::Tween(): startCallback(nullptr), updateCallback(nullptr), endCallback(nullptr) {} template Tween::~Tween() {} template void Tween::update(float dt) { if (isStopped() || isPaused()) { return; } // Check if tween was just started if (!isStopped() && wasStopped()) { // Execute start callback if (startCallback != nullptr) { startCallback(startValue); } } oldStopped = stopped; // Add delta time to time and calculate tween value time = std::min(duration, time + dt); calculateTweenValue(); // Execute update callback if (updateCallback != nullptr) { updateCallback(tweenValue); } // Check if tween has ended if (time >= duration) { if (!isStopped()) { // Stop tween stop(); // Execute end callback if (endCallback != nullptr) { endCallback(tweenValue); } } } } template inline void Tween::setStartValue(const T& startValue) { this->startValue = startValue; } template inline void Tween::setDeltaValue(const T& deltaValue) { this->deltaValue = deltaValue; } template inline void Tween::setStartCallback(std::function callback) { this->startCallback = callback; } template inline void Tween::setUpdateCallback(std::function callback) { this->updateCallback = callback; } template inline void Tween::setEndCallback(std::function callback) { this->endCallback = callback; } template inline const T& Tween::getStartValue() const { return startValue; } template inline const T& Tween::getDeltaValue() const { return deltaValue; } template inline const T& Tween::getTweenValue() const { return tweenValue; } template inline std::function Tween::getStartCallback() const { return startCallback; } template inline std::function Tween::getUpdateCallback() const { return updateCallback; } template inline std::function Tween::getEndCallback() const { return endCallback; } template inline void Tween::calculateTweenValue() { tweenValue = easeFunctionPointer(time, startValue, deltaValue, duration); } template <> inline void Tween::calculateTweenValue() { tweenValue.x = easeFunctionPointer(time, startValue.x, deltaValue.x, duration); tweenValue.y = easeFunctionPointer(time, startValue.y, deltaValue.y, duration); } template <> inline void Tween::calculateTweenValue() { tweenValue.x = easeFunctionPointer(time, startValue.x, deltaValue.x, duration); tweenValue.y = easeFunctionPointer(time, startValue.y, deltaValue.y, duration); tweenValue.z = easeFunctionPointer(time, startValue.z, deltaValue.z, duration); } template <> inline void Tween::calculateTweenValue() { tweenValue.x = easeFunctionPointer(time, startValue.x, deltaValue.x, duration); tweenValue.y = easeFunctionPointer(time, startValue.y, deltaValue.y, duration); tweenValue.z = easeFunctionPointer(time, startValue.z, deltaValue.z, duration); tweenValue.w = easeFunctionPointer(time, startValue.w, deltaValue.w, duration); } class Tweener { public: void update(float dt); void addTween(TweenBase* tween); void removeTween(TweenBase* tween); void removeTweens(); private: std::list tweens; }; #endif // TWEEN_HPP