#ifndef _EASING_H_ #define _EASING_H_ /*! \brief A class for eased floats for use in animations * * Animations often defines values a floating point variable * should have at given times and interpolates between them to * calculate the value of that variable at any given intermediate * time step. * * The simplest case would be linear interpolation: * Suppose a float "position" should be a at time = 0 and * b at time = x. If the current time is y, the value of * "position" is then a + (b-a)*y/x. * * This class defines the interface needed to implement different * kind of interpolations with a common interface. See * http://www.gizma.com/easing/ for more information for a few * examples. */ class Easing { public: /*! \brief The value at the start of an animation. * * start_value is undefined if no animation is running. */ float start_value; /*! \brief The amount the value should change during the animation. * * delta_value is undefined if no animation is running. */ float delta_value; /*! \brief The current value. * * Use this member to read the value or to write the value without * to animate intermediate values and. Make sure that the easing * is not used once value is deleted. */ float& value; /*! \brief The duration the animation should take * * It is not relevant which unit is used. This value is undefined * if no animation is running. */ float duration; /*! \brief The accumulated time the animation did run until now. * * It is not relevant which unit is used. This values is undefined * if no animation is running. */ float time_acc; /*! \brief Sets Easing::float to val and sets the animation as not running. * * Make sure that the easing is not used once value is deleted. * * \param val The value to ease */ Easing(float& val): start_value(val), delta_value(0), value(val), duration(0), time_acc(0) { } /*! \brief Resets the animation to its initial value * * This method does set the value to the start value and sets the passed time to 0. * If there is no animation animation running, the resulting value is undefined. */ void reset() { value = start_value; time_acc = 0; } /*! \brief Finishes the animation immediately * * Sets the value to the animations target value and the passed time to the * animations duration. If there is no animation running, the behaviour is undefined. */ void finish() { value = start_value + delta_value; time_acc = duration; } /*! \brief Lets dt time pass * * Advances the animation by dt time units and updates the value accordingly. * * \val dt The amount of time to jump forward */ void update(float dt) { if(time_acc < duration) { time_acc += dt; if(time_acc > duration) { time_acc = duration; value = start_value + delta_value; } else { updateValue(); } } } /*! \brief Calculates the value from all other members. * * This method gets implemented by all specific easing classes. */ virtual void updateValue() = 0; /*! \brief Starts the animation. * * Starts the interpolation from the current value (now) to * targetValue (in now + _duration). * * If the animation is currently running, it gets replaced. * * \param targetValue The value to interpolate to * \param _duration The duration the interpolation should take */ void start(float targetValue, float _duration) { start_value = value; delta_value = targetValue - start_value; time_acc = 0; duration = _duration; } /*! \brief Translates the current value and the target value by delta_value * * This method is mainly used for trickery. Suppose there is one object in the * middle of the screen that should move to the top until it is outside of the * screen and gets replaced by a second one entering the screen from the lower * side once the first one disappeared. This method can be used to simulate this * effect with one animation by translating (i.e. moving) the animation from the * top to the bottom: * * Object1 and object2 are the same object: object1 whose y position is bound to value * To start the transition, use start(SCREEN_HEIGHT, desired time); Once the first * object left the screen (i.e. object.y < 0), change objects appearance to object2 * and translate the easing by (SCREEN_HEIGHT). * * \param delta_value The change in start_value and value */ void translate(float delta_value) { start_value += delta_value; value += delta_value; } /*! \brief Returns if the passed time exceeds duration. * * If ther is no animation running, it is ensured that this is true. */ bool finished() { return time_acc >= duration; } }; /*! \brief This class defines an easing with quadratic acceleration */ class InQuadEasing : public Easing { public: /*! \brief Calls Easing::Easing(val). * * \see Easing::Easing(float& val) */ InQuadEasing(float& val): Easing(val) {} /*! \brief Implements the value calculation. * * \see Easing::updateValue() */ void updateValue() { float time_tmp = time_acc / duration; value = delta_value * time_tmp * time_tmp + start_value; } }; /*! \brief This class defines an easing with quadratic decceleration */ class OutQuadEasing : public Easing { public: /*! \brief Calls Easing::Easing(val). * * \see Easing::Easing(float& val) */ OutQuadEasing(float& val): Easing(val) {} /*! \brief Implements the value calculation. * * \see Easing::updateValue() */ void updateValue() { float time_tmp = time_acc / duration; value = (-delta_value) * time_tmp * (time_tmp - 2.0f) + start_value; } }; /*! \brief This class defines an easing with quadratic acceleration and decceleration. */ class InOutQuadEasing : public Easing { public: /*! \brief Calls Easing::Easing(val). * * \see Easing::Easing(float& val) */ InOutQuadEasing(float& val): Easing(val) {} /*! \brief Implements the value calculation. * * \see Easing::updateValue() */ void updateValue() { float time_tmp = (time_acc * 2) / duration; if (time_tmp < 1) { value = (float)(delta_value * 0.5 * time_tmp * time_tmp + start_value); } else { time_tmp -= 1; value = (float)(- delta_value * 0.5 * (time_tmp * (time_tmp - 2) - 1) + start_value); } } }; #endif //_EASING_H_