You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

981 lines
28 KiB

#ifndef Magnum_Animation_Easing_h
#define Magnum_Animation_Easing_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022, 2023 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
/** @file
* @brief Struct @ref Magnum::Animation::BasicEasing, typedef @ref Magnum::Animation::Easing, @ref Magnum::Animation::Easingd
*/
#include "Magnum/Magnum.h"
#include "Magnum/Math/Constants.h"
#include "Magnum/Animation/Animation.h"
namespace Magnum { namespace Animation {
/**
@brief Easing functions
@m_since_latest
@m_keywords{Tweening Inbetweening}
A collection of predefined [easing / tweening](https://en.wikipedia.org/wiki/Inbetweening)
functions for adding life to animation interpolation. Meant to be used through
the @ref Easing and @ref Easingd typedefs.
This library is built as part of Magnum by default. To use this library with
CMake, find the `Magnum` package and link to the `Magnum::Magnum` target:
@code{.cmake}
find_package(Magnum REQUIRED)
# ...
target_link_libraries(your-app PRIVATE Magnum::Magnum)
@endcode
See @ref building, @ref cmake and @ref animation for more information.
@m_class{m-row m-container-inflate}
@parblock
@m_div{m-col-l-2 m-push-l-2 m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-linear-thumb.svg
@ref linear() @m_class{m-label m-primary} **B** @m_class{m-label m-success} **E**
@m_enddiv
@m_div{m-col-l-2 m-push-l-2 m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-step-thumb.svg
@ref step() @m_class{m-label m-success} **E**
@m_enddiv
@m_div{m-col-l-2 m-push-l-2 m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-smoothstep-thumb.svg
@ref smoothstep() @m_class{m-label m-primary} **B** @m_class{m-label m-success} **E**
@m_enddiv
@m_div{m-col-l-2 m-push-l-2 m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-smootherstep-thumb.svg
@ref smootherstep() @m_class{m-label m-success} **E**
@m_enddiv
@endparblock
@m_class{m-row m-container-inflate}
@parblock
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-quadraticin-thumb.svg
@ref quadraticIn() @m_class{m-label m-primary} **B** @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-quadraticout-thumb.svg
@ref quadraticOut() @m_class{m-label m-primary} **B** @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-quadraticinout-thumb.svg
@ref quadraticInOut() @m_class{m-label m-info} **B** @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-cubicin-thumb.svg
@ref cubicIn() @m_class{m-label m-primary} **B** @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-cubicout-thumb.svg
@ref cubicOut() @m_class{m-label m-primary} **B** @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-cubicinout-thumb.svg
@ref cubicInOut() @m_class{m-label m-info} **B** @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-quarticin-thumb.svg
@ref quarticIn() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-quarticout-thumb.svg
@ref quarticOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-quarticinout-thumb.svg
@ref quarticInOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-quinticin-thumb.svg
@ref quinticIn() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-quinticout-thumb.svg
@ref quinticOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-quinticinout-thumb.svg
@ref quinticInOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-sinein-thumb.svg
@ref sineIn() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-sineout-thumb.svg
@ref sineOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-sineinout-thumb.svg
@ref sineInOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-circularin-thumb.svg
@ref circularIn()
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-circularout-thumb.svg
@ref circularOut()
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-circularinout-thumb.svg
@ref circularInOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-exponentialin-thumb.svg
@ref exponentialIn() @m_class{m-label m-success} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-exponentialout-thumb.svg
@ref exponentialOut() @m_class{m-label m-success} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-exponentialinout-thumb.svg
@ref exponentialInOut() @m_class{m-label m-success} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-elasticin-thumb.svg
@ref elasticIn() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-elasticout-thumb.svg
@ref elasticOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-elasticinout-thumb.svg
@ref elasticInOut() @m_class{m-label m-success} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-backin-thumb.svg
@ref backIn() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-backout-thumb.svg
@ref backOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-backinout-thumb.svg
@ref backInOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-bouncein-thumb.svg
@ref bounceIn() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-bounceout-thumb.svg
@ref bounceOut() @m_class{m-label m-danger} **E**
@m_enddiv
@m_div{m-col-l-2 m-col-t-4 m-text-center m-nopadt m-nopadx}
@htmlinclude easings-bounceinout-thumb.svg
@ref bounceInOut() @m_class{m-label m-danger} **E**
@m_enddiv
@endparblock
The easing function is meant to be used to modify the interpolation factor, such as:
@snippet MagnumAnimation.cpp Easing-factor
The @ref Animation library also provides the @ref ease() utility that combines
the interpolator together with the easing function:
@snippet MagnumAnimation.cpp Easing-ease
@section Animation-Easing-equations Equations
Every function documentation shows a plot of its behavior, together with a
direction in which it extrapolates. Green color means the extrapolation goes in
a reasonable monotonic direction outside of the range (also denoted by
@m_class{m-label m-success} **E** in the above list), red color means the
extrapolation is defined, but behaves in a probably unwanted or non-monotonic
way (denoted by @m_class{m-label m-danger} **E** in the above list). If neither
is present, it means the function is not defined outside of the @f$ [ 0; 1 ] @f$
range and produces a NaN. You may want to ensure the factor stays in bounds,
using either @ref Math::clamp() or the @ref easeClamped() function --- the
following two expressions are equivalent:
@snippet MagnumAnimation.cpp Easing-clamp
Out-function @f$ f_\text{out} @f$ for a corresponding in-function @f$ f_\text{in} @f$
is defined as the following, the equations in the docs usually just show the
final derived form. Similarly goes for combined in-/out-function
@f$ f_\text{inout} @f$: @f[
\begin{array}{rcl}
f_\text{out}(x) & = & 1 - f_\text{in}(1 - x) \\[5pt]
f_\text{inout}(x) & = & \left. \begin{cases}
\frac{1}{2} f_\text{in}(2x), & x < 0.5 \\
\frac{1}{2} (1 + f_\text{out}(2x - 1)), & x \ge 0.5
\end{cases} \right\} = \begin{cases}
\frac{1}{2} f_\text{in}(2x), & x < 0.5 \\
1 - \frac{1}{2} f_\text{in}(2 - 2x), & x \ge 0.5
\end{cases}
\end{array}
@f]
Easing functions defined by simple polynomials can have an *exact* (denoted
by @m_class{m-label m-primary} **B** in the above list) or approximate (denoted
by @m_class{m-label m-info} **B** in the above list) cubic @ref Math::Bezier
curve representation (and thus, in turn, convertible to Cubic Hermite splines
using @ref Math::CubicHermite::fromBezier()). If that's the case, given
function documentation also lists the corresponding Bézier representation and
plots it with a thin blue line. The curve is always normalized to go from
@f$ (0, 0)^T @f$ to @f$ (1, 1)^T @f$, apply arbitrary transformation to each
point as needed:
@snippet MagnumAnimation.cpp Easing-bezier-transform
@section Animation-Easing-references References
Functions follow the common naming from Robert Penner's Easing functions,
http://robertpenner.com/easing/. Implementation based on and inspired by
https://easings.net/,
[https://github.com/warrenm/AHEasing](https://github.com/warrenm/AHEasing/blob/master/AHEasing/easing.c),
[https://github.com/bkaradzic/bx](https://github.com/bkaradzic/bx/blob/master/include/bx/inline/easing.inl),
https://blog.demofox.org/2014/08/28/one-dimensional-bezier-curves/.
*/
template<class T> struct BasicEasing {
/**
* @brief Linear
*
* @htmlinclude easings-linear.svg
*
* @f[
* y = x
* @f]
*
* One possible *exact* Bézier representation:
*
* @snippet easings.cpp linear
*/
static T linear(T t) { return t; }
/**
* @brief Step
*
* Similar to @ref Math::select(), but does the step in the middle of the
* range instead of at the end. Implementation matching the GLSL
* @glsl step() @ce function with @cpp edge = T(0.5) @ce.
*
* @htmlinclude easings-step.svg
*
* @f[
* y = \begin{cases}
* 0, & x < 0.5 \\
* 1, & x \ge 0.5
* \end{cases}
* @f]
*
* @m_keyword{step(),GLSL step(),}
* @see @ref smoothstep(), @ref smootherstep()
*/
static T step(T t) { return t < T(0.5) ? T(0.0) : T(1.0); }
/**
* @brief [Smoothstep](https://en.wikipedia.org/wiki/Smoothstep).
*
* Implementation matching the GLSL @glsl smoothstep() @ce function.
* Combine with @ref Math::lerp() to get the equivalent result:
*
* @snippet MagnumAnimation.cpp Easing-smoothstep
*
* @htmlinclude easings-smoothstep.svg
*
* @f[
* y = \begin{cases}
* 0, & x < 0 \\
* 3x^2 - 2x^3, & x \in [0, 1] \\
* 1, & x > 1
* \end{cases}
* @f]
*
* *Exact* Bézier representation:
*
* @snippet easings.cpp smoothstep
*
* @m_keyword{smoothstep(),GLSL smoothstep(),}
* @see @ref smootherstep(), @ref Math::clamp()
*/
static T smoothstep(T t) {
/* Deliberately *not* using Math::clamp() because that would drag in
unneeded vector headers */
if(t <= T(0.0)) return T(0.0);
if(t >= T(1.0)) return T(1.0);
return (T(3.0) - T(2.0)*t)*t*t;
}
/**
* @brief [Smootherstep](https://en.wikipedia.org/wiki/Smoothstep#Variations).
*
* Improved version of @ref smoothstep() by [Ken Perlin](https://en.wikipedia.org/wiki/Ken_Perlin).
*
* @htmlinclude easings-smootherstep.svg
*
* @f[
* y = \begin{cases}
* 0, & x < 0 \\
* 6x^5 - 15x^4 + 10x^3, & x \in [0, 1] \\
* 1, & x > 1
* \end{cases}
* @f]
*
* @see @ref Math::clamp()
*/
static T smootherstep(T t) {
/* Deliberately *not* using Math::clamp() because that would drag in
unneeded vector headers */
if(t <= T(0.0)) return T(0.0);
if(t >= T(1.0)) return T(1.0);
return t*t*t*(t*(t*T(6.0) - T(15.0)) + T(10.0));
}
/**
* @brief Quadratic in
*
* @htmlinclude easings-quadraticin.svg
*
* @f[
* y = x^2
* @f]
*
* *Exact* Bézier representation:
*
* @snippet easings.cpp quadraticIn
*
* @see @ref cubicIn(), @ref quarticIn(), @ref quinticIn()
*/
static T quadraticIn(T t) { return t*t; }
/**
* @brief Quadratic out
*
* @htmlinclude easings-quadraticout.svg
*
* @f[
* y = 1 - (1 - x)^2 = (2 - x) x
* @f]
*
* *Exact* Bézier representation:
*
* @snippet easings.cpp quadraticOut
*
* @see @ref cubicOut(), @ref quarticOut(), @ref quinticOut()
*/
static T quadraticOut(T t) { return -t*(t - T(2.0)); }
/**
* @brief Quadratic in and out
*
* Combination of @ref quadraticIn() and @ref quadraticOut().
*
* @htmlinclude easings-quadraticinout.svg
*
* @f[
* y = \begin{cases}
* 2 x^2, & x < 0.5 \\
* 1 - 2 (1 - x)^2, & x \ge 0.5
* \end{cases}
* @f]
*
* Approximate Bézier representation:
*
* @snippet easings.cpp quadraticInOut
*
* @see @ref cubicInOut(), @ref quarticInOut(), @ref quinticInOut()
*/
static T quadraticInOut(T t) {
if(t < T(0.5)) return T(2.0)*t*t;
const T inv = T(1.0) - t;
return T(1.0) - T(2.0)*inv*inv;
}
/**
* @brief Cubic in
*
* @htmlinclude easings-cubicin.svg
*
* @f[
* y = x^3
* @f]
*
* *Exact* Bézier representation:
*
* @snippet easings.cpp cubicIn
*
* @see @ref quadraticIn(), @ref quarticIn(), @ref quinticIn()
*/
static T cubicIn(T t) { return t*t*t; }
/**
* @brief Cubic out
*
* @htmlinclude easings-cubicout.svg
*
* @f[
* y = 1 - (1 - x)^3
* @f]
*
* *Exact* Bézier representation:
*
* @snippet easings.cpp cubicOut
*
* @see @ref quadraticOut(), @ref quarticOut(), @ref quinticOut()
*/
static T cubicOut(T t) {
const T inv = t - T(1.0);
return inv*inv*inv + T(1.0);
}
/**
* @brief Cubic in and out
*
* Combination of @ref cubicIn() and @ref cubicOut().
*
* @htmlinclude easings-cubicinout.svg
*
* @f[
* y = \begin{cases}
* 4 x^3, & x < 0.5 \\
* 1 - 4 (1 - x)^3, & x \ge 0.5
* \end{cases}
* @f]
*
* Approximate Bézier representation:
*
* @snippet easings.cpp cubicInOut
*
* @see @ref quadraticInOut(), @ref quarticInOut(), @ref quinticInOut()
*/
static T cubicInOut(T t) {
if(t < T(0.5)) return T(4.0)*t*t*t;
const T inv = T(1.0) - t;
return T(1.0) - T(4.0)*inv*inv*inv;
}
/**
* @brief Quartic in
*
* @htmlinclude easings-quarticin.svg
*
* @f[
* y = x^4
* @f]
*
* @see @ref quadraticIn(), @ref cubicIn(), @ref quinticIn()
*/
static T quarticIn(T t) {
/* Not just t*t*t*t, since compile can't optimize it on its own to just
two multiplication without breaking precision. So doing that
explicitly. */
const T tt = t*t;
return tt*tt;
}
/**
* @brief Quartic out
*
* @htmlinclude easings-quarticout.svg
*
* @f[
* y = 1 - (1 - x)^4
* @f]
*
* @see @ref quadraticOut(), @ref cubicOut(), @ref quinticOut()
*/
static T quarticOut(T t) {
/* Instead of t*t*t*t suggesting the optimization as described above */
const T inv = T(1.0) - t;
const T quad = inv*inv;
return T(1.0) - quad*quad;
}
/**
* @brief Quartic in and out
*
* Combination of @ref quarticIn() and @ref quarticOut().
*
* @htmlinclude easings-quarticinout.svg
*
* @f[
* y = \begin{cases}
* 8 x^4, & x < 0.5 \\
* 1 - 8 (1 - x)^4, & x \ge 0.5
* \end{cases}
* @f]
*
* @see @ref quadraticInOut(), @ref cubicInOut(), @ref quinticInOut()
*/
static T quarticInOut(T t) {
/* Instead of t*t*t*t suggesting the optimization as described above */
if(t < T(0.5)) {
const T tt = t*t;
return 8*tt*tt;
}
const T inv = T(1.0) - t;
const T quad = inv*inv;
return T(1.0) - T(8.0)*quad*quad;
}
/**
* @brief Quintic in
*
* @htmlinclude easings-quinticin.svg
*
* @f[
* y = x^5
* @f]
*
* @see @ref quadraticIn(), @ref cubicIn(), @ref quarticIn()
*/
static T quinticIn(T t) {
/* Instead of t*t*t*t*t suggesting the optimization as described
above */
const T tt = t*t;
return tt*t*tt;
}
/**
* @brief Quintic out
*
* @htmlinclude easings-quinticout.svg
*
* @f[
* y = 1 - (1 - x)^5
* @f]
*
* @see @ref quadraticOut(), @ref cubicOut(), @ref quarticOut()
*/
static T quinticOut(T t) {
/* Instead of t*t*t*t*t suggesting the optimization as described
above */
const T inv = t - T(1.0);
const T quad = inv*inv;
return T(1.0) + quad*inv*quad;
}
/**
* @brief Quintic in and out
*
* Combination of @ref quinticIn() and @ref quinticOut().
*
* @htmlinclude easings-quinticinout.svg
*
* @f[
* y = \begin{cases}
* 16 x^5, & x < 0.5 \\
* 1 - 16 (1 - x)^5, & x \ge 0.5
* \end{cases}
* @f]
*
* @see @ref quadraticInOut(), @ref cubicInOut(), @ref quarticInOut()
*/
static T quinticInOut(T t) {
/* Instead of t*t*t*t*t suggesting the optimization as described
above */
if(t < T(0.5)) {
const T tt = t*t;
return T(16.0)*tt*t*tt;
}
const T inv = T(1.0) - t;
const T quad = inv*inv;
return T(1.0) - T(16.0)*quad*inv*quad;
}
/**
* @brief Sine in
*
* @htmlinclude easings-sinein.svg
*
* @f[
* y = 1 + \sin(\frac{\pi}{2} (x - 1))
* @f]
*
* @see @ref circularIn()
*/
static T sineIn(T t) {
return T(1.0) + std::sin(Math::Constants<T>::piHalf()*(t - T(1.0)));
}
/**
* @brief Sine out
*
* @htmlinclude easings-sineout.svg
*
* @f[
* y = \sin(\frac{\pi}{2} x)
* @f]
*
* @see @ref circularOut()
*/
static T sineOut(T t) {
return std::sin(Math::Constants<T>::piHalf()*t);
}
/**
* @brief Sine in and out
*
* Combination of @ref sineIn() and @ref sineOut().
*
* @htmlinclude easings-sineinout.svg
*
* @f[
* y = \frac{1}{2} (1 - \cos(\pi x))
* @f]
*
* @see @ref circularInOut()
*/
static T sineInOut(T t) {
return T(0.5)*(T(1.0) - std::cos(t*Math::Constants<T>::pi()));
}
/**
* @brief Circular in
*
* @htmlinclude easings-circularin.svg
*
* @f[
* y = 1 - \sqrt{1 - x^2}
* @f]
*
* @see @ref sineIn()
*/
static T circularIn(T t) {
return T(1.0) - std::sqrt(T(1.0) - t*t);
}
/**
* @brief Circular out
*
* @htmlinclude easings-circularout.svg
*
* @f[
* y = \sqrt{(2 - x) x}
* @f]
*
* @see @ref sineOut()
*/
static T circularOut(T t) {
return std::sqrt((T(2.0) - t)*t);
}
/**
* @brief Circular in and out
*
* Combination of @ref circularIn() and @ref circularOut().
*
* @htmlinclude easings-circularinout.svg
*
* @f[
* y = \begin{cases}
* \frac{1}{2} (1 - \sqrt{1 - (2x)^2}), & x < 0.5 \\
* \frac{1}{2} (1 + \sqrt{1 - (2x - 2)^2}), & x \ge 0.5
* \end{cases}
* @f]
*
* @see @ref sineInOut()
*/
static T circularInOut(T t) {
if(t < T(0.5)) return T(0.5)*(T(1.0) - std::sqrt(T(1.0) - T(4.0)*t*t));
return T(0.5)*(T(1.0) + std::sqrt(T(-4.0)*t*t + T(8.0)*t - T(3.0)));
}
/**
* @brief Exponential in
*
* Contrary to Robert Penner's book but consistently with other
* implementations has a special case for @f$ x \le 0 @f$, because
* @f$ 2^{-10} = 0.0009765625 @f$ otherwise.
*
* @htmlinclude easings-exponentialin.svg
*
* @f[
* y = \begin{cases}
* 0, & x \le 0 \\
* 2^{10(x - 1)}, & x \ne 0
* \end{cases}
* @f]
*
* @todo could be done better like with the sRGB curve, but should I
* bother?
*/
static T exponentialIn(T t) {
return t <= T(0.0) ? T(0.0) : std::pow(T(2.0), T(10.0)*(t - T(1.0)));
}
/**
* @brief Exponential out
*
* Contrary to Robert Penner's book but consistently with other
* implementations has a special case for @f$ x \ge 1 @f$, because
* @f$ 2^{-10} = 0.0009765625 @f$ otherwise.
*
* @htmlinclude easings-exponentialout.svg
*
* @f[
* y = \begin{cases}
* 2^{-10 x}, & x < 1 \\
* 1, & x \ge 1
* \end{cases}
* @f]
*
* @todo could be done better like with the sRGB curve, but should I
* bother?
*/
static T exponentialOut(T t) {
return t >= T(1.0) ? T(1.0) : T(1.0) - std::pow(T(2.0), -T(10.0)*t);
}
/**
* @brief Exponential in and out
*
* Combination of @ref exponentialIn() and @ref exponentialOut(). Contrary
* to Robert Penner's book but consistently with other implementations has
* a special case for @f$ x \notin \{0, 1\} @f$, because
* @f$ 2^{-10} = 0.0009765625 @f$ otherwise.
*
* @htmlinclude easings-exponentialinout.svg
*
* @f[
* y = \begin{cases}
* 0, & x \le 0 \\
* \frac{1}{2} 2^{20 x - 10}, & x \in (0, 0.5) \\
* 1 - \frac{1}{2} 2^{10 - 20 x}, & x \in [0.5, 1) \\
* 1, & x \ge 1
* \end{cases}
* @f]
*/
static T exponentialInOut(T t) {
if(t <= T(0.0)) return T(0.0);
if(t < T(0.5)) return T(0.5)*std::pow(T(2.0), T(20.0)*t - T(10.0));
if(t < T(1.0)) return T(1.0) - T(0.5)*std::pow(T(2.0), T(10.0) -T(20.0)*t);
return T(1.0);
}
/**
* @brief Elastic in
*
* Combines @ref sineIn() and @ref exponentialIn().
*
* @htmlinclude easings-elasticin.svg
*
* @f[
* y = 2^{10 (p - 1)} \sin(13 \frac{\pi}{2} x)
* @f]
*/
static T elasticIn(T t) {
return std::pow(T(2.0), T(10.0)*(t - T(1.0)))*std::sin(T(13.0)*Math::Constants<T>::piHalf()*t);
}
/**
* @brief Elastic out
*
* Combines @ref sineOut() and @ref exponentialOut().
*
* @htmlinclude easings-elasticout.svg
*
* @f[
* y = 1 - 2^{-10 x} \sin(13 \frac{\pi}{2} (x + 1))
* @f]
*/
static T elasticOut(T t) {
return T(1.0) - std::pow(T(2.0), T(-10.0)*t)*std::sin(T(13.0)*Math::Constants<T>::piHalf()*(t + T(1.0)));
}
/**
* @brief Elastic in and out
*
* Combination of @ref elasticIn() and @ref elasticOut() (or
* @ref sineInOut() and @ref exponentialInOut()).
*
* @htmlinclude easings-elasticinout.svg
*
* @f[
* y = \begin{cases}
* \frac{1}{2} 2^{10 (2x - 1)} \sin(13 \pi x), & x < 0.5 \\
* 1 - \frac{1}{2} 2^{10 (1 - 2x)} \sin(13 \pi x), & x \ge 0.5
* \end{cases}
* @f]
*/
static T elasticInOut(T t) {
if(t < T(0.5))
return T(0.5)*std::pow(T(2.0), T(10.0)*(T(2.0)*t - T(1.0)))*std::sin(T(13.0)*Math::Constants<T>::pi()*t);
return T(1.0) - T(0.5)*std::pow(T(2.0), T(10.0)*(T(1.0) - T(2.0)*t))*std::sin(T(13.0)*Math::Constants<T>::pi()*t);
}
/**
* @brief Back in
*
* @htmlinclude easings-backin.svg
*
* @f[
* y = x^3 - x \sin(\pi x)
* @f]
*/
static T backIn(T t) {
return t*(t*t - std::sin(Math::Constants<T>::pi()*t));
}
/**
* @brief Back out
*
* @htmlinclude easings-backout.svg
*
* @f[
* y = 1 - ((1 - x)^3 - (1 - x) \sin(\pi (1 - x)))
* @f]
*/
static T backOut(T t) {
const T inv = T(1.0) - t;
return 1 - inv*(inv*inv - std::sin(Math::Constants<T>::pi()*inv));
}
/**
* @brief Back in and out
*
* Combination of @ref backIn() and @ref backOut().
*
* @htmlinclude easings-backinout.svg
*
* @f[
* y = \begin{cases}
* \frac{1}{2} ((2x)^3 - 2x \sin(2 \pi x)),
* & x < 0.5 \\
* 1 - \frac{1}{2} ((2 - 2x)^3 - (2 - 2x) \sin(\pi (2 - 2x)),
* & x \ge 0.5
* \end{cases}
* @f]
*/
static T backInOut(T t) {
if(t < T(0.5)) {
const T t2 = T(2.0)*t;
return T(0.5)*t2*(t2*t2 - std::sin(Math::Constants<T>::pi()*t2));
}
const T inv = T(2.0) - T(2.0)*t;
return T(1.0) - T(0.5)*inv*(inv*inv - std::sin(Math::Constants<T>::pi()*inv));
}
/**
* @brief Bounce in
*
* @htmlinclude easings-bouncein.svg
*/
static T bounceIn(T t) {
return T(1.0) - bounceOut(T(1.0) - t);
}
/**
* @brief Bounce out
*
* @htmlinclude easings-bounceout.svg
*/
static T bounceOut(T t) {
if(t < T(4.0)/T(11.0)) return (T(121.0)*t*t)/T(16.0);
if(t < T(8.0)/T(11.0)) return T(363.0)/T(40.0)*t*t - T(99.0)/T(10.0)*t + T(17.0)/T(5.0);
if(t < T(9.0)/T(10.0)) return T(4356.0)/T(361.0)*t*t - T(35442.0)/T(1805.0)*t + T(16061.0)/T(1805.0);
return T(54.0)/T(5.0)*t*t - T(513.0)/T(25.0)*t + T(268.0)/T(25.0);
}
/**
* @brief Bounce in and out
*
* Combination of @ref bounceIn() and @ref bounceOut().
*
* @htmlinclude easings-bounceinout.svg
*/
static T bounceInOut(T t) {
if(t < T(0.5)) return T(0.5)*bounceIn(T(2.0)*t);
return T(0.5)*bounceOut(T(2.0)*t - T(1.0)) + T(0.5);
}
};
/**
@brief Float easing functions
@see @ref Easingd
*/
typedef BasicEasing<Float> Easing;
/**
@brief Double easing functions
@m_since_latest
@see @ref Easing
*/
typedef BasicEasing<Double> Easingd;
}}
#endif