Browse Source

Animation: added Interpolation enum and interpolatorFor() helper.

Will be used to supply general desired interpolation method to tracks to
make it possible for the user to decide about a particular interpolator
function for given type.
pull/191/head
Vladimír Vondruš 8 years ago
parent
commit
844b42f5e9
  1. 6
      src/Magnum/Animation/Animation.h
  2. 45
      src/Magnum/Animation/Interpolation.cpp
  3. 129
      src/Magnum/Animation/Interpolation.h
  4. 2
      src/Magnum/Animation/Test/CMakeLists.txt
  5. 112
      src/Magnum/Animation/Test/InterpolationTest.cpp
  6. 8
      src/Magnum/CMakeLists.txt

6
src/Magnum/Animation/Animation.h

@ -34,11 +34,13 @@
namespace Magnum { namespace Animation {
namespace Implementation {
template<class> struct TypeTraits;
template<class V> struct ResultTraits;
template<class, class> struct TypeTraits;
}
template<class V> using ResultOf = typename Implementation::TypeTraits<V>::ResultType;
template<class V> using ResultOf = typename Implementation::ResultTraits<V>::Type;
enum class Interpolation: UnsignedByte;
enum class Extrapolation: UnsignedByte;
template<class K, class V, class R = ResultOf<V>> class Track;

45
src/Magnum/Animation/Interpolation.cpp

@ -25,9 +25,25 @@
#include "Interpolation.h"
#include "Magnum/Math/DualQuaternion.h"
namespace Magnum { namespace Animation {
#ifndef DOXYGEN_GENERATING_OUTPUT
Debug& operator<<(Debug& debug, const Interpolation value) {
switch(value) {
/* LCOV_EXCL_START */
#define _c(value) case Interpolation::value: return debug << "Animation::Interpolation::" #value;
_c(Constant)
_c(Linear)
_c(Custom)
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "Animation::Interpolation(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const Extrapolation value) {
switch(value) {
/* LCOV_EXCL_START */
@ -43,4 +59,33 @@ Debug& operator<<(Debug& debug, const Extrapolation value) {
}
#endif
namespace Implementation {
template<class T> auto TypeTraits<Math::Quaternion<T>, Math::Quaternion<T>>::interpolator(Interpolation interpolation) -> Interpolator {
switch(interpolation) {
case Interpolation::Constant: return Math::select;
case Interpolation::Linear: return Math::slerp;
case Interpolation::Custom: ; /* nope */
}
CORRADE_ASSERT(false, "Animation::interpolatorFor(): can't deduce interpolator function for" << interpolation, {});
}
template<class T> auto TypeTraits<Math::DualQuaternion<T>, Math::DualQuaternion<T>>::interpolator(Interpolation interpolation) -> Interpolator {
switch(interpolation) {
case Interpolation::Constant: return Math::select;
case Interpolation::Linear: return Math::sclerp;
case Interpolation::Custom: ; /* nope */
}
CORRADE_ASSERT(false, "Animation::interpolatorFor(): can't deduce interpolator function for" << interpolation, {});
}
template struct MAGNUM_EXPORT TypeTraits<Math::Quaternion<Float>, Math::Quaternion<Float>>;
template struct MAGNUM_EXPORT TypeTraits<Math::DualQuaternion<Float>, Math::DualQuaternion<Float>>;
}
}}

129
src/Magnum/Animation/Interpolation.h

@ -33,17 +33,42 @@
#include "Magnum/Magnum.h"
#include "Magnum/Math/Functions.h"
#ifdef CORRADE_MSVC2015_COMPATIBILITY
#include "Magnum/Animation/Animation.h" /* ResultOf alias on MSVC 2015 */
#endif
#include "Magnum/Animation/Animation.h"
namespace Magnum { namespace Animation {
namespace Implementation {
template<class T> struct TypeTraits {
typedef T ResultType;
};
}
/**
@brief Animation interpolation
Describes the general desired way to interpolate animation keyframes. The
concrete choice of interpolator function is in user's hands.
@see @ref interpolatorFor()
@experimental
*/
enum class Interpolation: UnsignedByte {
/**
* Constant interpolation.
*
* @see @ref Math::select()
*/
Constant,
/**
* Linear interpolation.
*
* @see @ref Math::lerp(), @ref Math::slerp(), @ref Math::sclerp()
*/
Linear,
/**
* Custom interpolation. An user-supplied interpolation function should be
* used.
*/
Custom
};
/** @debugoperatorenum{Interpolation} */
MAGNUM_EXPORT Debug& operator<<(Debug& debug, Interpolation value);
/**
@brief Animation result type for given value type
@ -54,9 +79,35 @@ does not result in a spline).
@experimental
*/
#ifndef CORRADE_MSVC2015_COMPATIBILITY /* Multiple definitions still broken */
template<class V> using ResultOf = typename Implementation::TypeTraits<V>::ResultType;
template<class V> using ResultOf = typename Implementation::ResultTraits<V>::Type;
#endif
/**
@brief Interpolator function for given type
@tparam V Value type
@tparam R Result type
Expects that @p interpolation is not @ref Interpolation::Custom. Favors
output correctness over performance, supply custom interpolator functions for
faster but less precise results.
@m_class{m-fullwidth}
Interpolation type | Value type | Result type | Interpolator
------------------- | ----------------- | ------------- | ------------
@ref Interpolation::Constant | any `V` | `V` | @ref Math::select()
@ref Interpolation::Linear | @cpp bool @ce <b></b> | @cpp bool @ce <b></b> | @ref Math::select()
@ref Interpolation::Linear | @ref Math::BoolVector | @ref Math::BoolVector | @ref Math::select()
@ref Interpolation::Linear | any scalar `V` | `V` | @ref Math::lerp()
@ref Interpolation::Linear | any vector `V` | `V` | @ref Math::lerp()
@ref Interpolation::Linear | @ref Math::Quaternion | @ref Math::Quaternion | @ref Math::slerp(const Quaternion<T>&, const Quaternion<T>&, T) "Math::slerp()"
@ref Interpolation::Linear | @ref Math::DualQuaternion | @ref Math::DualQuaternion | @ref Math::sclerp(const DualQuaternion<T>&, const DualQuaternion<T>&, T) "Math::sclerp()"
@see @ref interpolate(), @ref interpolateStrict()
@experimental
*/
template<class V, class R = ResultOf<V>> auto interpolatorFor(Interpolation interpolation) -> R(*)(const V&, const V&, Float);
/**
@brief Animation extrapolation behavior
@ -155,6 +206,66 @@ Used internally from @ref Track::atStrict() / @ref TrackView::atStrict(), see
*/
template<class K, class V, class R = ResultOf<V>> R interpolateStrict(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& values, R(*interpolator)(const V&, const V&, Float), K frame, std::size_t& hint);
namespace Implementation {
/* Generic types where result type is the same as value type */
template<class V> struct ResultTraits {
typedef V Type;
};
template<class V> struct TypeTraits<V, V> {
typedef V(*Interpolator)(const V&, const V&, Float);
static Interpolator interpolator(Interpolation interpolation);
};
template<class V> auto TypeTraits<V, V>::interpolator(Interpolation interpolation) -> Interpolator {
switch(interpolation) {
case Interpolation::Constant: return Math::select;
case Interpolation::Linear: return Math::lerp;
case Interpolation::Custom: ; /* nope */
}
CORRADE_ASSERT(false, "Animation::interpolatorFor(): can't deduce interpolator function for" << interpolation, {});
}
/* Specialization for booleans (no linear interpolation) */
template<class T> struct TypeTraitsBool {
typedef T(*Interpolator)(const T&, const T&, Float);
static Interpolator interpolator(Interpolation interpolation);
};
template<class T> auto TypeTraitsBool<T>::interpolator(Interpolation interpolation) -> Interpolator {
switch(interpolation) {
case Interpolation::Constant:
case Interpolation::Linear: return Math::select;
case Interpolation::Custom: ; /* nope */
}
CORRADE_ASSERT(false, "Animation::interpolatorFor(): can't deduce interpolator function for" << interpolation, {});
}
template<> struct TypeTraits<bool, bool>: TypeTraitsBool<bool> {};
template<std::size_t size> struct TypeTraits<Math::BoolVector<size>, Math::BoolVector<size>>: TypeTraitsBool<Math::BoolVector<size>> {};
/* Quaternions and dual quaternions, preferring slerp() as it is more precise */
template<class T> struct MAGNUM_EXPORT TypeTraits<Math::Quaternion<T>, Math::Quaternion<T>> {
typedef Math::Quaternion<T>(*Interpolator)(const Math::Quaternion<T>&, const Math::Quaternion<T>&, Float);
static Interpolator interpolator(Interpolation interpolation);
};
template<class T> struct MAGNUM_EXPORT TypeTraits<Math::DualQuaternion<T>, Math::DualQuaternion<T>> {
typedef Math::DualQuaternion<T>(*Interpolator)(const Math::DualQuaternion<T>&, const Math::DualQuaternion<T>&, Float);
static Interpolator interpolator(Interpolation interpolation);
};
}
/* Needs to be defined later so it can pick up the TypeTraits definitions */
template<class V, class R> auto interpolatorFor(Interpolation interpolation) -> R(*)(const V&, const V&, Float) {
return Implementation::TypeTraits<V, R>::interpolator(interpolation);
}
template<class K, class V, class R> R interpolate(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& values, const Extrapolation before, const Extrapolation after, R(*const interpolator)(const V&, const V&, Float), K frame, std::size_t& hint) {
CORRADE_ASSERT(keys.size() == values.size(), "Animation::interpolate(): keys and values don't have the same size", {});

2
src/Magnum/Animation/Test/CMakeLists.txt

@ -23,7 +23,7 @@
# DEALINGS IN THE SOFTWARE.
#
corrade_add_test(AnimationInterpolationTest InterpolationTest.cpp LIBRARIES Magnum)
corrade_add_test(AnimationInterpolationTest InterpolationTest.cpp LIBRARIES MagnumTestLib)
corrade_add_test(AnimationTrackTest TrackTest.cpp LIBRARIES Magnum)
corrade_add_test(AnimationTrackViewTest TrackViewTest.cpp LIBRARIES Magnum)

112
src/Magnum/Animation/Test/InterpolationTest.cpp

@ -27,6 +27,7 @@
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Animation/Interpolation.h"
#include "Magnum/Math/DualQuaternion.h"
#include "Magnum/Math/Half.h"
namespace Magnum { namespace Animation { namespace Test {
@ -34,6 +35,12 @@ namespace Magnum { namespace Animation { namespace Test {
struct InterpolationTest: TestSuite::Tester {
explicit InterpolationTest();
void interpolatorFor();
void interpolatorForBool();
void interpolatorForBoolVector();
void interpolatorForQuaternion();
void interpolatorForDualQuaternion();
void interpolate();
void interpolateStrict();
void interpolateSingleKeyframe();
@ -51,11 +58,14 @@ struct InterpolationTest: TestSuite::Tester {
void interpolateIntegerKey();
void interpolateStrictIntegerKey();
void debugInterpolation();
void debugExtrapolation();
};
namespace {
using namespace Math::Literals;
const struct {
const char* name;
Extrapolation extrapolationBefore;
@ -125,6 +135,12 @@ const struct {
}
InterpolationTest::InterpolationTest() {
addTests({&InterpolationTest::interpolatorFor,
&InterpolationTest::interpolatorForBool,
&InterpolationTest::interpolatorForBoolVector,
&InterpolationTest::interpolatorForQuaternion,
&InterpolationTest::interpolatorForDualQuaternion});
addInstancedTests({&InterpolationTest::interpolate,
&InterpolationTest::interpolateStrict},
Containers::arraySize(Data));
@ -147,9 +163,98 @@ InterpolationTest::InterpolationTest() {
&InterpolationTest::interpolateIntegerKey,
&InterpolationTest::interpolateStrictIntegerKey,
&InterpolationTest::debugInterpolation,
&InterpolationTest::debugExtrapolation});
}
void InterpolationTest::interpolatorFor() {
CORRADE_COMPARE(Animation::interpolatorFor<Vector2>(Interpolation::Constant)(
Vector2{0.3f, 0.5f}, Vector2{-0.3f, -1.5f}, 0.5f), (Vector2{0.3f, 0.5f}));
CORRADE_COMPARE(Animation::interpolatorFor<Vector2>(Interpolation::Linear)(
Vector2{0.3f, 0.5f}, Vector2{-0.3f, -1.5f}, 0.5f), (Vector2{0.0f, -0.5f}));
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<Float>(Interpolation::Custom);
Animation::interpolatorFor<Float>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
void InterpolationTest::interpolatorForBool() {
CORRADE_COMPARE(Animation::interpolatorFor<bool>(Interpolation::Constant)(
true, false, 0.5f), true);
CORRADE_COMPARE(Animation::interpolatorFor<bool>(Interpolation::Linear)(
true, false, 0.5f), true);
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<bool>(Interpolation::Custom);
Animation::interpolatorFor<bool>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
void InterpolationTest::interpolatorForBoolVector() {
CORRADE_COMPARE(Animation::interpolatorFor<Math::BoolVector<4>>(Interpolation::Constant)(
Math::BoolVector<4>{0xa}, Math::BoolVector<4>{0x5}, 0.5f), (Math::BoolVector<4>{0xa}));
CORRADE_COMPARE(Animation::interpolatorFor<Math::BoolVector<4>>(Interpolation::Linear)(
Math::BoolVector<4>{0xa}, Math::BoolVector<4>{0x5}, 0.5f), (Math::BoolVector<4>{0xa}));
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<Math::BoolVector<4>>(Interpolation::Custom);
Animation::interpolatorFor<Math::BoolVector<4>>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
void InterpolationTest::interpolatorForQuaternion() {
CORRADE_COMPARE(Animation::interpolatorFor<Quaternion>(Interpolation::Constant)(
Quaternion::rotation(25.0_degf, Vector3::xAxis()),
Quaternion::rotation(75.0_degf, Vector3::xAxis()), 0.5f),
Quaternion::rotation(25.0_degf, Vector3::xAxis()));
CORRADE_COMPARE(Animation::interpolatorFor<Quaternion>(Interpolation::Linear)(
Quaternion::rotation(25.0_degf, Vector3::xAxis()),
Quaternion::rotation(75.0_degf, Vector3::xAxis()), 0.5f),
Quaternion::rotation(50.0_degf, Vector3::xAxis()));
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<Quaternion>(Interpolation::Custom);
Animation::interpolatorFor<Quaternion>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
void InterpolationTest::interpolatorForDualQuaternion() {
CORRADE_COMPARE(Animation::interpolatorFor<DualQuaternion>(Interpolation::Constant)(
DualQuaternion::translation(Vector3::xAxis(2.5f)),
DualQuaternion::translation(Vector3::xAxis(7.5f)), 0.5f),
DualQuaternion::translation(Vector3::xAxis(2.5f)));
CORRADE_COMPARE(Animation::interpolatorFor<DualQuaternion>(Interpolation::Linear)(
DualQuaternion::translation(Vector3::xAxis(2.5f)),
DualQuaternion::translation(Vector3::xAxis(7.5f)), 0.5f),
DualQuaternion::translation(Vector3::xAxis(5.0f)));
std::ostringstream out;
Error redirectError{&out};
Animation::interpolatorFor<DualQuaternion>(Interpolation::Custom);
Animation::interpolatorFor<DualQuaternion>(Interpolation(0xde));
CORRADE_COMPARE(out.str(),
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation::Custom\n"
"Animation::interpolatorFor(): can't deduce interpolator function for Animation::Interpolation(0xde)\n");
}
namespace {
constexpr Float Keys[]{0.0f, 2.0f, 4.0f, 5.0f};
constexpr Float Values[]{3.0f, 1.0f, 2.5f, 0.5f};
@ -295,6 +400,13 @@ void InterpolationTest::interpolateStrictError() {
"Animation::interpolateStrict(): keys and values don't have the same size\n");
}
void InterpolationTest::debugInterpolation() {
std::ostringstream out;
Debug{&out} << Interpolation::Custom << Interpolation(0xde);
CORRADE_COMPARE(out.str(), "Animation::Interpolation::Custom Animation::Interpolation(0xde)\n");
}
void InterpolationTest::debugExtrapolation() {
std::ostringstream out;

8
src/Magnum/CMakeLists.txt

@ -32,14 +32,14 @@ set(Magnum_SRCS
PixelStorage.cpp
Resource.cpp
Sampler.cpp
Timeline.cpp
Animation/Interpolation.cpp)
Timeline.cpp)
set(Magnum_GracefulAssert_SRCS
Image.cpp
ImageView.cpp
PixelFormat.cpp)
PixelFormat.cpp
Animation/Interpolation.cpp)
set(Magnum_HEADERS
AbstractResourceLoader.h

Loading…
Cancel
Save