Files
wagic/projects/mtg/include/Easing.h
2013-12-09 22:20:43 +01:00

246 lines
6.9 KiB
C++

#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_