Browse Source

Animation: make Easing a template struct, add an Easingd typedef.

Similarly to how Constants and Constantsd are made.
pull/601/head
Vladimír Vondruš 3 years ago
parent
commit
3c8fd70c12
  1. 13
      doc/changelog.dox
  2. 44
      doc/generated/easings.cpp
  3. 231
      src/Magnum/Animation/Easing.h
  4. 135
      src/Magnum/Animation/Test/EasingTest.cpp

13
doc/changelog.dox

@ -393,6 +393,13 @@ See also:
@relativeref{Timeline,previousFrameDuration()} (see @relativeref{Timeline,previousFrameDuration()} (see
[mosra/magnum#604](https://github.com/mosra/magnum/pull/604)) [mosra/magnum#604](https://github.com/mosra/magnum/pull/604))
@subsubsection changelog-latest-changes-animation Animation library
- Added a @ref Animation::Easingd typedef with
@ref Animation::BasicEasing "easing functions" implemented with
double precision, in addition to single-precision @ref Animation::Easing,
and similar in spirit to the @ref Constants and @ref Constantsd typedefs.
@subsubsection changelog-latest-changes-debugtools DebugTools library @subsubsection changelog-latest-changes-debugtools DebugTools library
- @ref DebugTools::bufferData() and @ref DebugTools::bufferSubData() now - @ref DebugTools::bufferData() and @ref DebugTools::bufferSubData() now
@ -1146,6 +1153,12 @@ See also:
@ref Corrade::Containers::ArrayView are now removed. This should have a @ref Corrade::Containers::ArrayView are now removed. This should have a
significant positive effect on compile times of code using the @ref GL, significant positive effect on compile times of code using the @ref GL,
@ref Audio, @ref Trade and @ref Text libraries @ref Audio, @ref Trade and @ref Text libraries
- @ref Animation::Easing is now a typedef to a new
@ref Animation::BasicEasing struct instead of being a namespace in order to
expose the easing functions in double precision as @ref Animation::Easingd.
The change is API-compatible and shouldn't require any changes from user
side, however existing code that contained
@cpp using namespace Animation::Easing @ce will break.
- As part of the ongoing STL header dependency cleanup, the following - As part of the ongoing STL header dependency cleanup, the following
breaking changes related to @ref std::string, @ref std::vector and breaking changes related to @ref std::string, @ref std::vector and
@ref std::pair are done: @ref std::pair are done:

44
doc/generated/easings.cpp

@ -202,9 +202,7 @@ const Color3 success = 0x3bd267_srgbf;
/** @todo better bezier approximations for more complex curves, easings.net has it awful */ /** @todo better bezier approximations for more complex curves, easings.net has it awful */
int main() { int main() {
using namespace Animation::Easing; #define _c(name) Utility::String::lowercase(std::string{#name}), Animation::Easing::name
#define _c(name) Utility::String::lowercase(std::string{#name}), name
generate(_c(linear), {}, generate(_c(linear), {},
/* [linear] */ /* [linear] */
CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f}, CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f},
@ -212,127 +210,127 @@ CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f},
/* [linear] */ /* [linear] */
, success, success); , success, success);
generate(_c(step), {}, {}, success, success); generate(_c(step), {}, {}, success, success);
generate(_c(smoothstep), {smootherstep}, generate(_c(smoothstep), {Animation::Easing::smootherstep},
/* [smoothstep] */ /* [smoothstep] */
CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 0.0f}, CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 0.0f},
Vector2{2.0f/3.0f, 1.0f}, Vector2{1.0f}} Vector2{2.0f/3.0f, 1.0f}, Vector2{1.0f}}
/* [smoothstep] */ /* [smoothstep] */
, success, success); , success, success);
generate(_c(smootherstep), {smoothstep}, {}, success, success); generate(_c(smootherstep), {Animation::Easing::smoothstep}, {}, success, success);
generate(_c(quadraticIn), {cubicIn, quarticIn, quinticIn}, generate(_c(quadraticIn), {Animation::Easing::cubicIn, Animation::Easing::quarticIn, Animation::Easing::quinticIn},
/* [quadraticIn] */ /* [quadraticIn] */
CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 0.0f}, CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 0.0f},
Vector2{2.0f/3.0f, 1.0f/3.0f}, Vector2{1.0f}} Vector2{2.0f/3.0f, 1.0f/3.0f}, Vector2{1.0f}}
/* [quadraticIn] */ /* [quadraticIn] */
, danger, success); , danger, success);
generate(_c(quadraticOut), {cubicOut, quarticOut, quinticOut}, generate(_c(quadraticOut), {Animation::Easing::cubicOut, Animation::Easing::quarticOut, Animation::Easing::quinticOut},
/* [quadraticOut] */ /* [quadraticOut] */
CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 2.0f/3.0f}, CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 2.0f/3.0f},
Vector2{2.0f/3.0f, 1.0f}, Vector2{1.0f}} Vector2{2.0f/3.0f, 1.0f}, Vector2{1.0f}}
/* [quadraticOut] */ /* [quadraticOut] */
, success, danger); , success, danger);
generate(_c(quadraticInOut), {cubicInOut, quarticInOut, quinticInOut}, generate(_c(quadraticInOut), {Animation::Easing::cubicInOut, Animation::Easing::quarticInOut, Animation::Easing::quinticInOut},
/* [quadraticInOut] */ /* [quadraticInOut] */
CubicBezier2D{Vector2{0.0f}, Vector2{0.455f, 0.0f}, CubicBezier2D{Vector2{0.0f}, Vector2{0.455f, 0.0f},
Vector2{0.545f, 1.0f}, Vector2{1.0f}} Vector2{0.545f, 1.0f}, Vector2{1.0f}}
/* [quadraticInOut] */ /* [quadraticInOut] */
); );
generate(_c(cubicIn), {quadraticIn, quarticIn, quinticIn}, generate(_c(cubicIn), {Animation::Easing::quadraticIn, Animation::Easing::quarticIn, Animation::Easing::quinticIn},
/* [cubicIn] */ /* [cubicIn] */
CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 0.0f}, CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 0.0f},
Vector2{2.0f/3.0f, 0.0f}, Vector2{1.0f}} Vector2{2.0f/3.0f, 0.0f}, Vector2{1.0f}}
/* [cubicIn] */ /* [cubicIn] */
, danger, success); , danger, success);
generate(_c(cubicOut), {quadraticOut, quarticOut, quinticOut}, generate(_c(cubicOut), {Animation::Easing::quadraticOut, Animation::Easing::quarticOut, Animation::Easing::quinticOut},
/* [cubicOut] */ /* [cubicOut] */
CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 1.0f}, CubicBezier2D{Vector2{0.0f}, Vector2{1.0f/3.0f, 1.0f},
Vector2{2.0f/3.0f, 1.0f}, Vector2{1.0f}} Vector2{2.0f/3.0f, 1.0f}, Vector2{1.0f}}
/* [cubicOut] */ /* [cubicOut] */
, success, danger); , success, danger);
generate(_c(cubicInOut), {quadraticInOut, quarticInOut, quinticInOut}, generate(_c(cubicInOut), {Animation::Easing::quadraticInOut, Animation::Easing::quarticInOut, Animation::Easing::quinticInOut},
/* [cubicInOut] */ /* [cubicInOut] */
CubicBezier2D{Vector2{0.0f}, Vector2{0.645f, 0.0f}, CubicBezier2D{Vector2{0.0f}, Vector2{0.645f, 0.0f},
Vector2{0.355f, 1.0f}, Vector2{1.0f}} Vector2{0.355f, 1.0f}, Vector2{1.0f}}
/* [cubicInOut] */ /* [cubicInOut] */
); );
generate(_c(quarticIn), {quadraticIn, cubicIn, quinticIn}, {} generate(_c(quarticIn), {Animation::Easing::quadraticIn, Animation::Easing::cubicIn, Animation::Easing::quinticIn}, {}
// , // ,
// /* [quarticIn] */ // /* [quarticIn] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.895f, 0.03f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.895f, 0.03f},
// Vector2{0.685f, 0.22f}, Vector2{1.0f}} // Vector2{0.685f, 0.22f}, Vector2{1.0f}}
// /* [quarticIn] */ // /* [quarticIn] */
, danger, success); , danger, success);
generate(_c(quarticOut), {quadraticOut, cubicOut, quinticOut}, {} generate(_c(quarticOut), {Animation::Easing::quadraticOut, Animation::Easing::cubicOut, Animation::Easing::quinticOut}, {}
// , // ,
// /* [quarticOut] */ // /* [quarticOut] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.165f, 0.84f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.165f, 0.84f},
// Vector2{0.44f, 1.0f}, Vector2{1.0f}} // Vector2{0.44f, 1.0f}, Vector2{1.0f}}
// /* [quarticOut] */ // /* [quarticOut] */
, success, danger); , success, danger);
generate(_c(quarticInOut), {quadraticInOut, cubicInOut, quinticInOut} generate(_c(quarticInOut), {Animation::Easing::quadraticInOut, Animation::Easing::cubicInOut, Animation::Easing::quinticInOut}
// , // ,
// /* [quarticInOut] */ // /* [quarticInOut] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.77f, 0.0f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.77f, 0.0f},
// Vector2{0.175f, 1.0f}, Vector2{1.0f}} // Vector2{0.175f, 1.0f}, Vector2{1.0f}}
// /* [quarticInOut] */ // /* [quarticInOut] */
); );
generate(_c(quinticIn), {quadraticIn, cubicIn, quarticIn}, {} generate(_c(quinticIn), {Animation::Easing::quadraticIn, Animation::Easing::cubicIn, Animation::Easing::quarticIn}, {}
// , // ,
// /* [quinticIn] */ // /* [quinticIn] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.755f, 0.05f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.755f, 0.05f},
// Vector2{0.855f, 0.06f}, Vector2{1.0f}} // Vector2{0.855f, 0.06f}, Vector2{1.0f}}
// /* [quinticIn] */ // /* [quinticIn] */
, danger, success); , danger, success);
generate(_c(quinticOut), {quadraticOut, cubicOut, quarticOut}, {} generate(_c(quinticOut), {Animation::Easing::quadraticOut, Animation::Easing::cubicOut, Animation::Easing::quarticOut}, {}
// , // ,
// /* [quinticOut] */ // /* [quinticOut] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.23f, 1.0f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.23f, 1.0f},
// Vector2{0.32f, 1.0f}, Vector2{1.0f}} // Vector2{0.32f, 1.0f}, Vector2{1.0f}}
// /* [quinticOut] */ // /* [quinticOut] */
, success, danger); , success, danger);
generate(_c(quinticInOut), {quadraticInOut, cubicInOut, quarticInOut} generate(_c(quinticInOut), {Animation::Easing::quadraticInOut, Animation::Easing::cubicInOut, Animation::Easing::quarticInOut}
// , // ,
// /* [quinticInOut] */ // /* [quinticInOut] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.86f, 0.0f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.86f, 0.0f},
// Vector2{0.07f, 1.0f}, Vector2{1.0f}} // Vector2{0.07f, 1.0f}, Vector2{1.0f}}
// /* [quinticInOut] */ // /* [quinticInOut] */
); );
generate(_c(sineIn), {circularIn} generate(_c(sineIn), {Animation::Easing::circularIn}
// , // ,
// /* [sineIn] */ // /* [sineIn] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.47f, 0.0f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.47f, 0.0f},
// Vector2{0.745f, 0.715f}, Vector2{1.0f}} // Vector2{0.745f, 0.715f}, Vector2{1.0f}}
// /* [sineIn] */ // /* [sineIn] */
); );
generate(_c(sineOut), {circularOut} generate(_c(sineOut), {Animation::Easing::circularOut}
// , // ,
// /* [sineOut] */ // /* [sineOut] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.39f, 0.575f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.39f, 0.575f},
// Vector2{0.565f, 1.0f}, Vector2{1.0f}} // Vector2{0.565f, 1.0f}, Vector2{1.0f}}
// /* [sineOut] */ // /* [sineOut] */
); );
generate(_c(sineInOut), {circularInOut} generate(_c(sineInOut), {Animation::Easing::circularInOut}
// , // ,
// /* [sineInOut] */ // /* [sineInOut] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.445f, 0.05f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.445f, 0.05f},
// Vector2{0.55f, 0.95f}, Vector2{1.0f}} // Vector2{0.55f, 0.95f}, Vector2{1.0f}}
// /* [sineInOut] */ // /* [sineInOut] */
); );
generate(_c(circularIn), {sineIn} generate(_c(circularIn), {Animation::Easing::sineIn}
// , // ,
// /* [circularIn] */ // /* [circularIn] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.6f, 0.04f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.6f, 0.04f},
// Vector2{0.98f, 0.335f}, Vector2{1.0f}} // Vector2{0.98f, 0.335f}, Vector2{1.0f}}
// /* [circularIn] */ // /* [circularIn] */
); );
generate(_c(circularOut), {sineOut} generate(_c(circularOut), {Animation::Easing::sineOut}
// , // ,
// /* [circularOut] */ // /* [circularOut] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.075f, 0.085f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.075f, 0.085f},
// Vector2{0.165f, 1.0f}, Vector2{1.0f}} // Vector2{0.165f, 1.0f}, Vector2{1.0f}}
// /* [circularOut] */ // /* [circularOut] */
); );
generate(_c(circularInOut), {sineInOut} generate(_c(circularInOut), {Animation::Easing::sineInOut}
// , // ,
// /* [circularInOut] */ // /* [circularInOut] */
// CubicBezier2D{Vector2{0.0f}, Vector2{0.785f, 0.135f}, // CubicBezier2D{Vector2{0.0f}, Vector2{0.785f, 0.135f},

231
src/Magnum/Animation/Easing.h

@ -26,7 +26,7 @@
*/ */
/** @file /** @file
* @brief Namespace @ref Magnum::Animation::Easing * @brief Struct @ref Magnum::Animation::BasicEasing, typedef @ref Magnum::Animation::Easing, @ref Magnum::Animation::Easingd
*/ */
#include "Magnum/Magnum.h" #include "Magnum/Magnum.h"
@ -37,11 +37,13 @@ namespace Magnum { namespace Animation {
/** /**
@brief Easing functions @brief Easing functions
@m_since_latest
@m_keywords{Tweening Inbetweening} @m_keywords{Tweening Inbetweening}
A collection of predefined [easing / tweening](https://en.wikipedia.org/wiki/Inbetweening) A collection of predefined [easing / tweening](https://en.wikipedia.org/wiki/Inbetweening)
functions for adding life to animation interpolation. 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 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: CMake, find the `Magnum` package and link to the `Magnum::Magnum` target:
@ -298,7 +300,7 @@ https://easings.net/,
[https://github.com/bkaradzic/bx](https://github.com/bkaradzic/bx/blob/master/include/bx/inline/easing.inl), [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/. https://blog.demofox.org/2014/08/28/one-dimensional-bezier-curves/.
*/ */
namespace Easing { template<class T> struct BasicEasing {
/** /**
* @brief Linear * @brief Linear
* *
@ -312,14 +314,14 @@ namespace Easing {
* *
* @snippet easings.cpp linear * @snippet easings.cpp linear
*/ */
inline Float linear(Float t) { return t; } static T linear(T t) { return t; }
/** /**
* @brief Step * @brief Step
* *
* Similar to @ref Math::select(), but does the step in the middle of the * Similar to @ref Math::select(), but does the step in the middle of the
* range instead of at the end. Implementation matching the GLSL * range instead of at the end. Implementation matching the GLSL
* @glsl step() @ce function with @cpp edge = 0.5f @ce. * @glsl step() @ce function with @cpp edge = T(0.5) @ce.
* *
* @htmlinclude easings-step.svg * @htmlinclude easings-step.svg
* *
@ -333,7 +335,7 @@ namespace Easing {
* @m_keyword{step(),GLSL step(),} * @m_keyword{step(),GLSL step(),}
* @see @ref smoothstep(), @ref smootherstep() * @see @ref smoothstep(), @ref smootherstep()
*/ */
inline Float step(Float t) { return t < 0.5f ? 0.0f : 1.0f; } static T step(T t) { return t < T(0.5) ? T(0.0) : T(1.0); }
/** /**
* @brief [Smoothstep](https://en.wikipedia.org/wiki/Smoothstep). * @brief [Smoothstep](https://en.wikipedia.org/wiki/Smoothstep).
@ -360,12 +362,12 @@ namespace Easing {
* @m_keyword{smoothstep(),GLSL smoothstep(),} * @m_keyword{smoothstep(),GLSL smoothstep(),}
* @see @ref smootherstep(), @ref Math::clamp() * @see @ref smootherstep(), @ref Math::clamp()
*/ */
inline Float smoothstep(Float t) { static T smoothstep(T t) {
/* Deliberately *not* using Math::clamp() because that would drag in /* Deliberately *not* using Math::clamp() because that would drag in
unneeded vector headers */ unneeded vector headers */
if(t <= 0.0f) return 0.0f; if(t <= T(0.0)) return T(0.0);
if(t >= 1.0f) return 1.0f; if(t >= T(1.0)) return T(1.0);
return (3.0f - 2.0f*t)*t*t; return (T(3.0) - T(2.0)*t)*t*t;
} }
/** /**
@ -385,12 +387,12 @@ namespace Easing {
* *
* @see @ref Math::clamp() * @see @ref Math::clamp()
*/ */
inline Float smootherstep(Float t) { static T smootherstep(T t) {
/* Deliberately *not* using Math::clamp() because that would drag in /* Deliberately *not* using Math::clamp() because that would drag in
unneeded vector headers */ unneeded vector headers */
if(t <= 0.0f) return 0.0f; if(t <= T(0.0)) return T(0.0);
if(t >= 1.0f) return 1.0f; if(t >= T(1.0)) return T(1.0);
return t*t*t*(t*(t* 6.0f - 15.0f) + 10.0f); return t*t*t*(t*(t*T(6.0) - T(15.0)) + T(10.0));
} }
/** /**
@ -408,7 +410,7 @@ namespace Easing {
* *
* @see @ref cubicIn(), @ref quarticIn(), @ref quinticIn() * @see @ref cubicIn(), @ref quarticIn(), @ref quinticIn()
*/ */
inline Float quadraticIn(Float t) { return t*t; } static T quadraticIn(T t) { return t*t; }
/** /**
* @brief Quadratic out * @brief Quadratic out
@ -425,7 +427,7 @@ namespace Easing {
* *
* @see @ref cubicOut(), @ref quarticOut(), @ref quinticOut() * @see @ref cubicOut(), @ref quarticOut(), @ref quinticOut()
*/ */
inline Float quadraticOut(Float t) { return -t*(t - 2.0f); } static T quadraticOut(T t) { return -t*(t - T(2.0)); }
/** /**
* @brief Quadratic in and out * @brief Quadratic in and out
@ -447,11 +449,11 @@ namespace Easing {
* *
* @see @ref cubicInOut(), @ref quarticInOut(), @ref quinticInOut() * @see @ref cubicInOut(), @ref quarticInOut(), @ref quinticInOut()
*/ */
inline Float quadraticInOut(Float t) { static T quadraticInOut(T t) {
if(t < 0.5f) return 2.0f*t*t; if(t < T(0.5)) return T(2.0)*t*t;
const Float inv = 1.0f - t; const T inv = T(1.0) - t;
return 1.0f - 2.0f*inv*inv; return T(1.0) - T(2.0)*inv*inv;
} }
/** /**
@ -469,7 +471,7 @@ namespace Easing {
* *
* @see @ref quadraticIn(), @ref quarticIn(), @ref quinticIn() * @see @ref quadraticIn(), @ref quarticIn(), @ref quinticIn()
*/ */
inline Float cubicIn(Float t) { return t*t*t; } static T cubicIn(T t) { return t*t*t; }
/** /**
* @brief Cubic out * @brief Cubic out
@ -486,9 +488,9 @@ namespace Easing {
* *
* @see @ref quadraticOut(), @ref quarticOut(), @ref quinticOut() * @see @ref quadraticOut(), @ref quarticOut(), @ref quinticOut()
*/ */
inline Float cubicOut(Float t) { static T cubicOut(T t) {
const Float inv = t - 1.0f; const T inv = t - T(1.0);
return inv*inv*inv + 1.0f; return inv*inv*inv + T(1.0);
} }
/** /**
@ -511,11 +513,11 @@ namespace Easing {
* *
* @see @ref quadraticInOut(), @ref quarticInOut(), @ref quinticInOut() * @see @ref quadraticInOut(), @ref quarticInOut(), @ref quinticInOut()
*/ */
inline Float cubicInOut(Float t) { static T cubicInOut(T t) {
if(t < 0.5f) return 4.0f*t*t*t; if(t < T(0.5)) return T(4.0)*t*t*t;
const Float inv = 1.0f - t; const T inv = T(1.0) - t;
return 1.0f - 4.0f*inv*inv*inv; return T(1.0) - T(4.0)*inv*inv*inv;
} }
/** /**
@ -529,11 +531,11 @@ namespace Easing {
* *
* @see @ref quadraticIn(), @ref cubicIn(), @ref quinticIn() * @see @ref quadraticIn(), @ref cubicIn(), @ref quinticIn()
*/ */
inline Float quarticIn(Float t) { static T quarticIn(T t) {
/* Not just t*t*t*t, since compile can't optimize it on its own to just /* 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 two multiplication without breaking precision. So doing that
explicitly. */ explicitly. */
const Float tt = t*t; const T tt = t*t;
return tt*tt; return tt*tt;
} }
@ -548,11 +550,11 @@ namespace Easing {
* *
* @see @ref quadraticOut(), @ref cubicOut(), @ref quinticOut() * @see @ref quadraticOut(), @ref cubicOut(), @ref quinticOut()
*/ */
inline Float quarticOut(Float t) { static T quarticOut(T t) {
/* Instead of t*t*t*t suggesting the optimization as described above */ /* Instead of t*t*t*t suggesting the optimization as described above */
const Float inv = 1.0f - t; const T inv = T(1.0) - t;
const Float quad = inv*inv; const T quad = inv*inv;
return 1.0f - quad*quad; return T(1.0) - quad*quad;
} }
/** /**
@ -571,17 +573,17 @@ namespace Easing {
* *
* @see @ref quadraticInOut(), @ref cubicInOut(), @ref quinticInOut() * @see @ref quadraticInOut(), @ref cubicInOut(), @ref quinticInOut()
*/ */
inline Float quarticInOut(Float t) { static T quarticInOut(T t) {
/* Instead of t*t*t*t suggesting the optimization as described above */ /* Instead of t*t*t*t suggesting the optimization as described above */
if(t < 0.5f) { if(t < T(0.5)) {
const Float tt = t*t; const T tt = t*t;
return 8*tt*tt; return 8*tt*tt;
} }
const Float inv = 1.0f - t; const T inv = T(1.0) - t;
const Float quad = inv*inv; const T quad = inv*inv;
return 1.0f - 8.0f*quad*quad; return T(1.0) - T(8.0)*quad*quad;
} }
/** /**
@ -595,10 +597,10 @@ namespace Easing {
* *
* @see @ref quadraticIn(), @ref cubicIn(), @ref quarticIn() * @see @ref quadraticIn(), @ref cubicIn(), @ref quarticIn()
*/ */
inline Float quinticIn(Float t) { static T quinticIn(T t) {
/* Instead of t*t*t*t*t suggesting the optimization as described /* Instead of t*t*t*t*t suggesting the optimization as described
above */ above */
const Float tt = t*t; const T tt = t*t;
return tt*t*tt; return tt*t*tt;
} }
@ -613,12 +615,12 @@ namespace Easing {
* *
* @see @ref quadraticOut(), @ref cubicOut(), @ref quarticOut() * @see @ref quadraticOut(), @ref cubicOut(), @ref quarticOut()
*/ */
inline Float quinticOut(Float t) { static T quinticOut(T t) {
/* Instead of t*t*t*t*t suggesting the optimization as described /* Instead of t*t*t*t*t suggesting the optimization as described
above */ above */
const Float inv = t - 1.0f; const T inv = t - T(1.0);
const Float quad = inv*inv; const T quad = inv*inv;
return 1.0f + quad*inv*quad; return T(1.0) + quad*inv*quad;
} }
/** /**
@ -637,18 +639,18 @@ namespace Easing {
* *
* @see @ref quadraticInOut(), @ref cubicInOut(), @ref quarticInOut() * @see @ref quadraticInOut(), @ref cubicInOut(), @ref quarticInOut()
*/ */
inline Float quinticInOut(Float t) { static T quinticInOut(T t) {
/* Instead of t*t*t*t*t suggesting the optimization as described /* Instead of t*t*t*t*t suggesting the optimization as described
above */ above */
if(t < 0.5f) { if(t < T(0.5)) {
const Float tt = t*t; const T tt = t*t;
return 16.0f*tt*t*tt; return T(16.0)*tt*t*tt;
} }
const Float inv = 1.0f - t; const T inv = T(1.0) - t;
const Float quad = inv*inv; const T quad = inv*inv;
return 1.0f - 16.0f*quad*inv*quad; return T(1.0) - T(16.0)*quad*inv*quad;
} }
/** /**
@ -662,8 +664,8 @@ namespace Easing {
* *
* @see @ref circularIn() * @see @ref circularIn()
*/ */
inline Float sineIn(Float t) { static T sineIn(T t) {
return 1.0f + std::sin(Constants::piHalf()*(t - 1.0f)); return T(1.0) + std::sin(Math::Constants<T>::piHalf()*(t - T(1.0)));
} }
/** /**
@ -677,8 +679,8 @@ namespace Easing {
* *
* @see @ref circularOut() * @see @ref circularOut()
*/ */
inline Float sineOut(Float t) { static T sineOut(T t) {
return std::sin(Constants::piHalf()*t); return std::sin(Math::Constants<T>::piHalf()*t);
} }
/** /**
@ -694,8 +696,8 @@ namespace Easing {
* *
* @see @ref circularInOut() * @see @ref circularInOut()
*/ */
inline Float sineInOut(Float t) { static T sineInOut(T t) {
return 0.5f*(1.0f - std::cos(t*Constants::pi())); return T(0.5)*(T(1.0) - std::cos(t*Math::Constants<T>::pi()));
} }
/** /**
@ -709,8 +711,8 @@ namespace Easing {
* *
* @see @ref sineIn() * @see @ref sineIn()
*/ */
inline Float circularIn(Float t) { static T circularIn(T t) {
return 1.0f - std::sqrt(1.0f - t*t); return T(1.0) - std::sqrt(T(1.0) - t*t);
} }
/** /**
@ -724,8 +726,8 @@ namespace Easing {
* *
* @see @ref sineOut() * @see @ref sineOut()
*/ */
inline Float circularOut(Float t) { static T circularOut(T t) {
return std::sqrt((2.0f - t)*t); return std::sqrt((T(2.0) - t)*t);
} }
/** /**
@ -744,9 +746,9 @@ namespace Easing {
* *
* @see @ref sineInOut() * @see @ref sineInOut()
*/ */
inline Float circularInOut(Float t) { static T circularInOut(T t) {
if(t < 0.5f) return 0.5f*(1.0f - std::sqrt(1.0f - 4.0f*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 0.5f*(1.0f + std::sqrt(-4.0f*t*t + 8.0f*t - 3.0f)); return T(0.5)*(T(1.0) + std::sqrt(T(-4.0)*t*t + T(8.0)*t - T(3.0)));
} }
/** /**
@ -768,8 +770,8 @@ namespace Easing {
* @todo could be done better like with the sRGB curve, but should I * @todo could be done better like with the sRGB curve, but should I
* bother? * bother?
*/ */
inline Float exponentialIn(Float t) { static T exponentialIn(T t) {
return t <= 0.0f ? 0.0f : std::pow(2.0f, 10.0f * (t - 1.0f)); return t <= T(0.0) ? T(0.0) : std::pow(T(2.0), T(10.0)*(t - T(1.0)));
} }
/** /**
@ -791,8 +793,8 @@ namespace Easing {
* @todo could be done better like with the sRGB curve, but should I * @todo could be done better like with the sRGB curve, but should I
* bother? * bother?
*/ */
inline Float exponentialOut(Float t) { static T exponentialOut(T t) {
return t >= 1.0f ? 1.0f : 1.0f - std::pow(2.0f, -10.0f*t); return t >= T(1.0) ? T(1.0) : T(1.0) - std::pow(T(2.0), -T(10.0)*t);
} }
/** /**
@ -814,11 +816,11 @@ namespace Easing {
* \end{cases} * \end{cases}
* @f] * @f]
*/ */
inline Float exponentialInOut(Float t) { static T exponentialInOut(T t) {
if(t <= 0.0f) return 0.0f; if(t <= T(0.0)) return T(0.0);
if(t < 0.5f) return 0.5f*std::pow(2.0f, 20.0f*t - 10.0f); if(t < T(0.5)) return T(0.5)*std::pow(T(2.0), T(20.0)*t - T(10.0));
if(t < 1.0f) return 1.0f - 0.5f*std::pow(2.0f, 10.0f - 20.0f*t); 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 1.0f; return T(1.0);
} }
/** /**
@ -832,8 +834,8 @@ namespace Easing {
* y = 2^{10 (p - 1)} \sin(13 \frac{\pi}{2} x) * y = 2^{10 (p - 1)} \sin(13 \frac{\pi}{2} x)
* @f] * @f]
*/ */
inline Float elasticIn(Float t) { static T elasticIn(T t) {
return std::pow(2.0f, 10.0f*(t - 1.0f))*std::sin(13.0f*Constants::piHalf()*t); return std::pow(T(2.0), T(10.0)*(t - T(1.0)))*std::sin(T(13.0)*Math::Constants<T>::piHalf()*t);
} }
/** /**
@ -847,8 +849,8 @@ namespace Easing {
* y = 1 - 2^{-10 x} \sin(13 \frac{\pi}{2} (x + 1)) * y = 1 - 2^{-10 x} \sin(13 \frac{\pi}{2} (x + 1))
* @f] * @f]
*/ */
inline Float elasticOut(Float t) { static T elasticOut(T t) {
return 1.0f - std::pow(2.0f, -10.0f*t)*std::sin(13.0f*Constants::piHalf()*(t + 1.0f)); 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)));
} }
/** /**
@ -866,10 +868,10 @@ namespace Easing {
* \end{cases} * \end{cases}
* @f] * @f]
*/ */
inline Float elasticInOut(Float t) { static T elasticInOut(T t) {
if(t < 0.5f) if(t < T(0.5))
return 0.5f*std::pow(2.0f, 10.0f*(2.0f*t - 1.0f))*std::sin(13.0f*Constants::pi()*t); 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 1.0f - 0.5f*std::pow(2.0f, 10.0f*(1.0f - 2.0f*t))*std::sin(13.0f*Constants::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);
} }
/** /**
@ -881,8 +883,8 @@ namespace Easing {
* y = x^3 - x \sin(\pi x) * y = x^3 - x \sin(\pi x)
* @f] * @f]
*/ */
inline Float backIn(Float t) { static T backIn(T t) {
return t*(t*t - std::sin(Constants::pi()*t)); return t*(t*t - std::sin(Math::Constants<T>::pi()*t));
} }
/** /**
@ -894,9 +896,9 @@ namespace Easing {
* y = 1 - ((1 - x)^3 - (1 - x) \sin(\pi (1 - x))) * y = 1 - ((1 - x)^3 - (1 - x) \sin(\pi (1 - x)))
* @f] * @f]
*/ */
inline Float backOut(Float t) { static T backOut(T t) {
const Float inv = 1.0f - t; const T inv = T(1.0) - t;
return 1 - inv*(inv*inv - std::sin(Constants::pi()*inv)); return 1 - inv*(inv*inv - std::sin(Math::Constants<T>::pi()*inv));
} }
/** /**
@ -915,27 +917,23 @@ namespace Easing {
* \end{cases} * \end{cases}
* @f] * @f]
*/ */
inline Float backInOut(Float t) { static T backInOut(T t) {
if(t < 0.5f) { if(t < T(0.5)) {
const Float t2 = 2.0f*t; const T t2 = T(2.0)*t;
return 0.5f*t2*(t2*t2 - std::sin(Constants::pi()*t2)); return T(0.5)*t2*(t2*t2 - std::sin(Math::Constants<T>::pi()*t2));
} }
const Float inv = 2.0f - 2.0f*t; const T inv = T(2.0) - T(2.0)*t;
return 1.0f - 0.5f*inv*(inv*inv - std::sin(Constants::pi()*inv)); return T(1.0) - T(0.5)*inv*(inv*inv - std::sin(Math::Constants<T>::pi()*inv));
} }
#ifndef DOXYGEN_GENERATING_OUTPUT
Float bounceOut(Float);
#endif
/** /**
* @brief Bounce in * @brief Bounce in
* *
* @htmlinclude easings-bouncein.svg * @htmlinclude easings-bouncein.svg
*/ */
inline Float bounceIn(Float t) { static T bounceIn(T t) {
return 1.0f - bounceOut(1.0f - t); return T(1.0) - bounceOut(T(1.0) - t);
} }
/** /**
@ -943,11 +941,11 @@ namespace Easing {
* *
* @htmlinclude easings-bounceout.svg * @htmlinclude easings-bounceout.svg
*/ */
inline Float bounceOut(Float t) { static T bounceOut(T t) {
if(t < 4.0f/11.0f) return (121.0f*t*t)/16.0f; if(t < T(4.0)/T(11.0)) return (T(121.0)*t*t)/T(16.0);
if(t < 8.0f/11.0f) return 363.0f/40.0f*t*t - 99.0f/10.0f*t + 17.0f/5.0f; 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 < 9.0f/10.0f) return 4356.0f/361.0f*t*t - 35442.0f/1805.0f*t + 16061.0f/1805.0f; 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 54.0f/5.0f*t*t - 513.0f/25.0f*t + 268.0f/25.0f; return T(54.0)/T(5.0)*t*t - T(513.0)/T(25.0)*t + T(268.0)/T(25.0);
} }
/** /**
@ -957,11 +955,26 @@ namespace Easing {
* *
* @htmlinclude easings-bounceinout.svg * @htmlinclude easings-bounceinout.svg
*/ */
inline Float bounceInOut(Float t) { static T bounceInOut(T t) {
if(t < 0.5f) return 0.5f*bounceIn(2.0f*t); if(t < T(0.5)) return T(0.5)*bounceIn(T(2.0)*t);
return 0.5f*bounceOut(2.0f*t - 1.0f) + 0.5f; 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;
}} }}

135
src/Magnum/Animation/Test/EasingTest.cpp

@ -30,24 +30,26 @@
#include <Corrade/Utility/Format.h> #include <Corrade/Utility/Format.h>
#include "Magnum/Animation/Easing.h" #include "Magnum/Animation/Easing.h"
#include "Magnum/Math/TypeTraits.h"
namespace Magnum { namespace Animation { namespace Test { namespace { namespace Magnum { namespace Animation { namespace Test { namespace {
struct EasingTest: TestSuite::Tester { struct EasingTest: TestSuite::Tester {
explicit EasingTest(); explicit EasingTest();
void bounds(); template<class T> void bounds();
void monotonicity(); template<class T> void monotonicity();
void symmetry(); template<class T> void symmetry();
void values(); template<class T> void values();
void benchmark(); template<class T> void benchmark();
}; };
#define _c(name) #name, Easing::name #define _c(name) #name, Easing::name, Easingd::name
constexpr struct { constexpr struct Bounds {
const char* name; const char* name;
Float(*function)(Float); Float(*function)(Float);
Double(*functiond)(Double);
} BoundsData[] { } BoundsData[] {
{_c(linear)}, {_c(linear)},
{_c(step)}, {_c(step)},
@ -80,9 +82,10 @@ constexpr struct {
{_c(bounceInOut)} {_c(bounceInOut)}
}; };
constexpr struct { constexpr struct Monotonicity {
const char* name; const char* name;
Float(*function)(Float); Float(*function)(Float);
Double(*functiond)(Double);
} MonotonicityData[] { } MonotonicityData[] {
{_c(linear)}, {_c(linear)},
{_c(step)}, {_c(step)},
@ -112,11 +115,13 @@ constexpr struct {
/* elastic, back and bounce are not monotonic */ /* elastic, back and bounce are not monotonic */
}; };
constexpr struct { constexpr struct Symmetry {
const char* name; const char* name;
Float(*function)(Float); Float(*function)(Float);
Double(*functiond)(Double);
const char* symmetricName; const char* symmetricName;
Float(*symmetric)(Float); Float(*symmetric)(Float);
Double(*symmetricd)(Double);
} SymmetryData[] { } SymmetryData[] {
{_c(linear), _c(linear)}, {_c(linear), _c(linear)},
{_c(step), _c(step)}, {_c(step), _c(step)},
@ -144,9 +149,10 @@ constexpr struct {
{_c(bounceInOut), _c(bounceInOut)} {_c(bounceInOut), _c(bounceInOut)}
}; };
constexpr struct { constexpr struct Value {
const char* name; const char* name;
Float(*function)(Float); Float(*function)(Float);
Double(*functiond)(Double);
Float values[3]; Float values[3];
} ValueData[] { } ValueData[] {
{_c(linear), {0.25f, 0.5f, 0.75f}}, {_c(linear), {0.25f, 0.5f, 0.75f}},
@ -186,91 +192,142 @@ constexpr struct {
}; };
#undef _c #undef _c
template<class T> struct FunctionFor;
template<> struct FunctionFor<Float> {
static auto function(const Bounds& s) -> Float(*)(Float) {
return s.function;
}
static auto function(const Monotonicity& s) -> Float(*)(Float) {
return s.function;
}
static auto function(const Symmetry& s) -> Float(*)(Float) {
return s.function;
}
static auto symmetric(const Symmetry& s) -> Float(*)(Float) {
return s.symmetric;
}
static auto function(const Value& s) -> Float(*)(Float) {
return s.function;
}
};
template<> struct FunctionFor<Double> {
static auto function(const Bounds& s) -> Double(*)(Double) {
return s.functiond;
}
static auto function(const Monotonicity& s) -> Double(*)(Double) {
return s.functiond;
}
static auto function(const Symmetry& s) -> Double(*)(Double) {
return s.functiond;
}
static auto symmetric(const Symmetry& s) -> Double(*)(Double) {
return s.symmetricd;
}
static auto function(const Value& s) -> Double(*)(Double) {
return s.functiond;
}
};
EasingTest::EasingTest() { EasingTest::EasingTest() {
addInstancedTests({&EasingTest::bounds}, addInstancedTests<EasingTest>({
&EasingTest::bounds<Float>,
&EasingTest::bounds<Double>},
Containers::arraySize(BoundsData)); Containers::arraySize(BoundsData));
addInstancedTests({&EasingTest::monotonicity}, addInstancedTests<EasingTest>({
&EasingTest::monotonicity<Float>,
&EasingTest::monotonicity<Double>},
Containers::arraySize(MonotonicityData)); Containers::arraySize(MonotonicityData));
addInstancedTests({&EasingTest::symmetry}, addInstancedTests<EasingTest>({
&EasingTest::symmetry<Float>,
&EasingTest::symmetry<Double>},
Containers::arraySize(SymmetryData)); Containers::arraySize(SymmetryData));
addInstancedTests({&EasingTest::values}, addInstancedTests<EasingTest>({
&EasingTest::values<Float>,
&EasingTest::values<Double>},
Containers::arraySize(ValueData)); Containers::arraySize(ValueData));
addInstancedBenchmarks({&EasingTest::benchmark}, 100, addInstancedBenchmarks<EasingTest>({
&EasingTest::benchmark<Float>,
&EasingTest::benchmark<Double>}, 100,
Containers::arraySize(ValueData)); Containers::arraySize(ValueData));
} }
enum: std::size_t { PropertyVerificationStepCount = 50 }; enum: std::size_t { PropertyVerificationStepCount = 50 };
void EasingTest::bounds() { template<class T> void EasingTest::bounds() {
auto&& data = BoundsData[testCaseInstanceId()]; auto&& data = BoundsData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
setTestCaseTemplateName(Math::TypeTraits<T>::name());
Float scale = 1.0f/Float(PropertyVerificationStepCount - 1); T scale = T(1.0)/T(PropertyVerificationStepCount - 1);
for(std::size_t i = 0; i != PropertyVerificationStepCount; ++i) { for(std::size_t i = 0; i != PropertyVerificationStepCount; ++i) {
Float t = i*scale; T t = i*scale;
CORRADE_COMPARE_AS(data.function(t), 0.0f, TestSuite::Compare::GreaterOrEqual); CORRADE_COMPARE_AS(FunctionFor<T>::function(data)(t), T(0.0), TestSuite::Compare::GreaterOrEqual);
CORRADE_COMPARE_AS(data.function(t), 1.0f, TestSuite::Compare::LessOrEqual); CORRADE_COMPARE_AS(FunctionFor<T>::function(data)(t), T(1.0), TestSuite::Compare::LessOrEqual);
} }
} }
void EasingTest::monotonicity() { template<class T> void EasingTest::monotonicity() {
auto&& data = MonotonicityData[testCaseInstanceId()]; auto&& data = MonotonicityData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
setTestCaseTemplateName(Math::TypeTraits<T>::name());
Float scale = 1.0f/Float(PropertyVerificationStepCount - 1); T scale = T(1.0)/T(PropertyVerificationStepCount - 1);
Float prev = data.function(0); T prev = FunctionFor<T>::function(data)(0);
for(std::size_t i = 1; i != PropertyVerificationStepCount; ++i) { for(std::size_t i = 1; i != PropertyVerificationStepCount; ++i) {
Float cur = data.function(i*scale); T cur = FunctionFor<T>::function(data)(i*scale);
CORRADE_COMPARE_AS(cur, prev, TestSuite::Compare::GreaterOrEqual); CORRADE_COMPARE_AS(cur, prev, TestSuite::Compare::GreaterOrEqual);
prev = cur; prev = cur;
} }
} }
void EasingTest::symmetry() { template<class T> void EasingTest::symmetry() {
auto&& data = SymmetryData[testCaseInstanceId()]; auto&& data = SymmetryData[testCaseInstanceId()];
if(data.name == Containers::StringView{data.symmetricName}) if(data.name == Containers::StringView{data.symmetricName})
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
else else
setTestCaseDescription(Utility::format("{} : {}", data.name, data.symmetricName)); setTestCaseDescription(Utility::format("{} : {}", data.name, data.symmetricName));
setTestCaseTemplateName(Math::TypeTraits<T>::name());
/* Not testing the edges, as these are tested in values() anyway (and are /* Not testing the edges, as these are tested in values() anyway (and are
problematic in functions that have explicit handling for them) */ problematic in functions that have explicit handling for them) */
Float scale = 1.0f/Float(PropertyVerificationStepCount + 1); T scale = T(1.0)/T(PropertyVerificationStepCount + 1);
std::size_t max = PropertyVerificationStepCount/(data.function == data.symmetric ? 2 : 1); std::size_t max = PropertyVerificationStepCount/(FunctionFor<T>::function(data) == FunctionFor<T>::symmetric(data) ? 2 : 1);
for(std::size_t i = 1; i != max; ++i) { for(std::size_t i = 1; i != max; ++i) {
Float t = i*scale; T t = i*scale;
CORRADE_COMPARE(data.function(t), 1.0f - data.symmetric(1.0f - t)); CORRADE_COMPARE(FunctionFor<T>::function(data)(t), T(1.0) - FunctionFor<T>::symmetric(data)(T(1.0) - t));
} }
} }
void EasingTest::values() { template<class T> void EasingTest::values() {
auto&& data = ValueData[testCaseInstanceId()]; auto&& data = ValueData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
setTestCaseTemplateName(Math::TypeTraits<T>::name());
CORRADE_COMPARE(data.function(0.0f), 0.0f); CORRADE_COMPARE(FunctionFor<T>::function(data)(T(0.0)), T(0.0));
CORRADE_COMPARE(data.function(1.0f), 1.0f); CORRADE_COMPARE(FunctionFor<T>::function(data)(T(1.0)), T(1.0));
CORRADE_COMPARE(data.function(0.25f), data.values[0]); CORRADE_COMPARE(FunctionFor<T>::function(data)(T(0.25)), data.values[0]);
CORRADE_COMPARE(data.function(0.50f), data.values[1]); CORRADE_COMPARE(FunctionFor<T>::function(data)(T(0.50)), data.values[1]);
CORRADE_COMPARE(data.function(0.75f), data.values[2]); CORRADE_COMPARE(FunctionFor<T>::function(data)(T(0.75)), data.values[2]);
} }
enum: Int { BenchmarkStepCount = 5000 }; enum: Int { BenchmarkStepCount = 5000 };
void EasingTest::benchmark() { template<class T> void EasingTest::benchmark() {
auto&& data = ValueData[testCaseInstanceId()]; auto&& data = ValueData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
setTestCaseTemplateName(Math::TypeTraits<T>::name());
/* Skip edges because the cumulated number may exceed 1 (on asm.js /* Skip edges because the cumulated number may exceed 1 (on asm.js
Emscripten), producing NaN on some functions and failing the test */ Emscripten), producing NaN on some functions and failing the test */
Float scale = 1.0f/Float(BenchmarkStepCount + 1); T scale = T(1.0)/T(BenchmarkStepCount + 1);
Float result = 0.0f; T result = T(0.0);
std::size_t i = 0; std::size_t i = 0;
CORRADE_BENCHMARK(BenchmarkStepCount) CORRADE_BENCHMARK(BenchmarkStepCount)
result += data.function(++i*scale); result += FunctionFor<T>::function(data)(++i*scale);
/* backIn() has -340 */ /* backIn() has -340 */
CORRADE_COMPARE_AS(result, -350.0f, TestSuite::Compare::Greater); CORRADE_COMPARE_AS(result, -350.0f, TestSuite::Compare::Greater);

Loading…
Cancel
Save