From 4d4b299740e370742f6325ea3cbf1b0f6c451d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 10 Jul 2018 13:10:59 +0200 Subject: [PATCH] Animation: make interpolation result type non-implicit. TrackView can, for example, have quaternions encoded as a 10-10-10-2 integer, but the result should still be a Quaternion. --- src/Magnum/Animation/Animation.h | 4 +- src/Magnum/Animation/Interpolation.h | 9 ++-- .../Animation/Test/InterpolationTest.cpp | 33 +++++++++++- src/Magnum/Animation/Test/TrackTest.cpp | 41 +++++++++++++++ src/Magnum/Animation/Test/TrackViewTest.cpp | 37 +++++++++++++ src/Magnum/Animation/Track.h | 52 +++++++++++-------- 6 files changed, 148 insertions(+), 28 deletions(-) diff --git a/src/Magnum/Animation/Animation.h b/src/Magnum/Animation/Animation.h index dd580cbb4..57852e7c3 100644 --- a/src/Magnum/Animation/Animation.h +++ b/src/Magnum/Animation/Animation.h @@ -41,8 +41,8 @@ template using ResultOf = typename Implementation::TypeTraits::Resul enum class Extrapolation: UnsignedByte; -template class Track; -template class TrackView; +template> class Track; +template> class TrackView; }} diff --git a/src/Magnum/Animation/Interpolation.h b/src/Magnum/Animation/Interpolation.h index d9f09345d..1d946cb87 100644 --- a/src/Magnum/Animation/Interpolation.h +++ b/src/Magnum/Animation/Interpolation.h @@ -98,6 +98,7 @@ MAGNUM_EXPORT Debug& operator<<(Debug& debug, Extrapolation value); @brief Interpolate animation value @tparam K Key type @tparam V Value type +@tparam R Result type @param keys Keys @param values Values @param before Extrapolation mode before first keyframe @@ -129,7 +130,7 @@ documentation for more information. @ref Math::slerp(), @ref Math::sclerp() @experimental */ -template ResultOf interpolate(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& values, Extrapolation before, Extrapolation after, ResultOf(*interpolator)(const V&, const V&, Float), K frame, std::size_t& hint); +template> R interpolate(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& values, Extrapolation before, Extrapolation after, R(*interpolator)(const V&, const V&, Float), K frame, std::size_t& hint); /** @brief Interpolate animation value with strict constraints @@ -152,9 +153,9 @@ Used internally from @ref Track::atStrict() / @ref TrackView::atStrict(), see @ref Math::sclerp() @experimental */ -template ResultOf interpolateStrict(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& values, ResultOf(*interpolator)(const V&, const V&, Float), K frame, std::size_t& hint); +template> R interpolateStrict(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& values, R(*interpolator)(const V&, const V&, Float), K frame, std::size_t& hint); -template ResultOf interpolate(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& values, const Extrapolation before, const Extrapolation after, ResultOf(*const interpolator)(const V&, const V&, Float), K frame, std::size_t& hint) { +template R interpolate(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& 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", {}); /* No data, return default-constructed value */ @@ -190,7 +191,7 @@ template ResultOf interpolate(const Containers::StridedArra Math::lerpInverted(keys[hint], keys[hint + 1], frame)); } -template ResultOf interpolateStrict(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& values, ResultOf(*const interpolator)(const V&, const V&, Float), const K frame, std::size_t& hint) { +template R interpolateStrict(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& values, R(*const interpolator)(const V&, const V&, Float), const K frame, std::size_t& hint) { CORRADE_ASSERT(keys.size() >= 2, "Animation::interpolateStrict(): at least two keyframes required", {}); CORRADE_ASSERT(keys.size() == values.size(), "Animation::interpolateStrict(): keys and values don't have the same size", {}); diff --git a/src/Magnum/Animation/Test/InterpolationTest.cpp b/src/Magnum/Animation/Test/InterpolationTest.cpp index fb100ba89..453627cda 100644 --- a/src/Magnum/Animation/Test/InterpolationTest.cpp +++ b/src/Magnum/Animation/Test/InterpolationTest.cpp @@ -27,6 +27,7 @@ #include #include "Magnum/Animation/Interpolation.h" +#include "Magnum/Math/Half.h" namespace Magnum { namespace Animation { namespace Test { @@ -41,6 +42,9 @@ struct InterpolationTest: TestSuite::Tester { void interpolateHint(); void interpolateStrictHint(); + void interpolateDifferentResultType(); + void interpolateStrictDifferentResultType(); + void interpolateError(); void interpolateStrictError(); @@ -131,7 +135,10 @@ InterpolationTest::InterpolationTest() { &InterpolationTest::interpolateStrictHint}, Containers::arraySize(HintData)); - addTests({&InterpolationTest::interpolateError, + addTests({&InterpolationTest::interpolateDifferentResultType, + &InterpolationTest::interpolateStrictDifferentResultType, + + &InterpolationTest::interpolateError, &InterpolationTest::interpolateStrictError, &InterpolationTest::debugExtrapolation}); @@ -205,6 +212,30 @@ void InterpolationTest::interpolateStrictHint() { CORRADE_COMPARE(hint, 2); } +namespace { + using namespace Math::Literals; + + const Half HalfValues[]{3.0_h, 1.0_h, 2.5_h, 0.5_h}; + + Float lerpHalf(const Half& a, const Half& b, Float t) { + return Math::lerp(Float(a), Float(b), t); + } +} + +void InterpolationTest::interpolateDifferentResultType() { + std::size_t hint{}; + CORRADE_COMPARE((Animation::interpolate( + Keys, HalfValues, Extrapolation::Extrapolated, Extrapolation::Extrapolated, lerpHalf, 4.75f, hint)), 1.0f); + CORRADE_COMPARE(hint, 2); +} + +void InterpolationTest::interpolateStrictDifferentResultType() { + std::size_t hint{}; + CORRADE_COMPARE((Animation::interpolateStrict( + Keys, HalfValues, lerpHalf, 4.75f, hint)), 1.0f); + CORRADE_COMPARE(hint, 2); +} + void InterpolationTest::interpolateError() { std::ostringstream out; Error redirectError{&out}; diff --git a/src/Magnum/Animation/Test/TrackTest.cpp b/src/Magnum/Animation/Test/TrackTest.cpp index d511dcb8d..fe03d775c 100644 --- a/src/Magnum/Animation/Test/TrackTest.cpp +++ b/src/Magnum/Animation/Test/TrackTest.cpp @@ -26,6 +26,7 @@ #include #include "Magnum/Animation/Track.h" +#include "Magnum/Math/Half.h" #include "Magnum/Math/Vector3.h" namespace Magnum { namespace Animation { namespace Test { @@ -42,6 +43,8 @@ struct TrackTest: TestSuite::Tester { void at(); void atStrict(); + void atDifferentResultType(); + void atDifferentResultTypeStrict(); }; namespace { @@ -93,6 +96,9 @@ TrackTest::TrackTest() { addInstancedTests({&TrackTest::at, &TrackTest::atStrict}, Containers::arraySize(AtData)); + + addTests({&TrackTest::atDifferentResultType, + &TrackTest::atDifferentResultTypeStrict}); } using namespace Math::Literals; @@ -218,6 +224,41 @@ void TrackTest::atStrict() { CORRADE_COMPARE(hint, data.expectedHint); } +namespace { + Float lerpHalf(const Half& a, const Half& b, Float t) { + return Math::lerp(Float(a), Float(b), t); + } +} + +void TrackTest::atDifferentResultType() { + using namespace Math::Literals; + + const Track a{ + {{0.0f, 3.0_h}, + {2.0f, 1.0_h}, + {4.0f, 2.5_h}, + {5.0f, 0.5_h}}, lerpHalf}; + + std::size_t hint{}; + CORRADE_COMPARE(a.at(4.75f, hint), 1.0f); + CORRADE_COMPARE(a.at(4.75f), 1.0f); + CORRADE_COMPARE(hint, 2); +} + +void TrackTest::atDifferentResultTypeStrict() { + using namespace Math::Literals; + + const Track a{ + {{0.0f, 3.0_h}, + {2.0f, 1.0_h}, + {4.0f, 2.5_h}, + {5.0f, 0.5_h}}, lerpHalf}; + + std::size_t hint{}; + CORRADE_COMPARE(a.atStrict(4.75f, hint), 1.0f); + CORRADE_COMPARE(hint, 2); +} + }}} CORRADE_TEST_MAIN(Magnum::Animation::Test::TrackTest) diff --git a/src/Magnum/Animation/Test/TrackViewTest.cpp b/src/Magnum/Animation/Test/TrackViewTest.cpp index 4c2de191d..4706cc284 100644 --- a/src/Magnum/Animation/Test/TrackViewTest.cpp +++ b/src/Magnum/Animation/Test/TrackViewTest.cpp @@ -26,6 +26,7 @@ #include #include "Magnum/Animation/Track.h" +#include "Magnum/Math/Half.h" #include "Magnum/Math/Vector3.h" namespace Magnum { namespace Animation { namespace Test { @@ -40,6 +41,8 @@ struct TrackViewTest: TestSuite::Tester { void at(); void atStrict(); + void atDifferentResultType(); + void atDifferentResultTypeStrict(); }; namespace { @@ -89,6 +92,9 @@ TrackViewTest::TrackViewTest() { addInstancedTests({&TrackViewTest::at, &TrackViewTest::atStrict}, Containers::arraySize(AtData)); + + addTests({&TrackViewTest::atDifferentResultType, + &TrackViewTest::atDifferentResultTypeStrict}); } using namespace Math::Literals; @@ -188,6 +194,37 @@ void TrackViewTest::atStrict() { CORRADE_COMPARE(hint, data.expectedHint); } +namespace { + using namespace Math::Literals; + + const Half HalfValues[]{3.0_h, 1.0_h, 2.5_h, 0.5_h}; + + Float lerpHalf(const Half& a, const Half& b, Float t) { + return Math::lerp(Float(a), Float(b), t); + } +} + +void TrackViewTest::atDifferentResultType() { + const TrackView a{ + {&Keyframes[0].first, Containers::arraySize(Keyframes), sizeof(Keyframes[0])}, + HalfValues, lerpHalf}; + + std::size_t hint{}; + CORRADE_COMPARE(a.at(4.75f, hint), 1.0f); + CORRADE_COMPARE(a.at(4.75f), 1.0f); + CORRADE_COMPARE(hint, 2); +} + +void TrackViewTest::atDifferentResultTypeStrict() { + const TrackView a{ + {&Keyframes[0].first, Containers::arraySize(Keyframes), sizeof(Keyframes[0])}, + HalfValues, lerpHalf}; + + std::size_t hint{}; + CORRADE_COMPARE(a.atStrict(4.75f, hint), 1.0f); + CORRADE_COMPARE(hint, 2); +} + }}} CORRADE_TEST_MAIN(Magnum::Animation::Test::TrackViewTest) diff --git a/src/Magnum/Animation/Track.h b/src/Magnum/Animation/Track.h index 2e9d6e197..a7cb88023 100644 --- a/src/Magnum/Animation/Track.h +++ b/src/Magnum/Animation/Track.h @@ -40,6 +40,7 @@ namespace Magnum { namespace Animation { @brief Animation track @tparam K Key type @tparam V Value type +@tparam R Result type Immutable storage of keyframe + value pairs. @@ -106,7 +107,11 @@ instead of having data duplicated scattered across disjoint allocations of @experimental */ -template class Track { +template + #endif +> class Track { public: /** @brief Key type */ typedef K KeyType; @@ -115,7 +120,7 @@ template class Track { typedef V ValueType; /** @brief Animation result type */ - typedef ResultOf ResultType; + typedef R ResultType; /** @brief Interpolation function */ typedef ResultType(*Interpolator)(const ValueType&, const ValueType&, Float); @@ -133,32 +138,32 @@ template class Track { explicit Track(Containers::Array>&& data, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: _data{std::move(data)}, _interpolator{interpolator}, _before{before}, _after{after} {} /** @overload */ - explicit Track(std::initializer_list> data, Interpolator interpolator, Extrapolation before, Extrapolation after): Track{Containers::Array>{Containers::InPlaceInit, data}, interpolator, before, after} {} + explicit Track(std::initializer_list> data, Interpolator interpolator, Extrapolation before, Extrapolation after): Track{Containers::Array>{Containers::InPlaceInit, data}, interpolator, before, after} {} /** @overload * Equivalent to calling @ref Track(Containers::Array>&&, Interpolator, Extrapolation, Extrapolation) * with both @p before and @p after set to @p extrapolation. */ - explicit Track(Containers::Array>&& data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: Track{std::move(data), interpolator, extrapolation, extrapolation} {} + explicit Track(Containers::Array>&& data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: Track{std::move(data), interpolator, extrapolation, extrapolation} {} /** @overload */ - explicit Track(std::initializer_list> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant): Track{Containers::Array>{Containers::InPlaceInit, data}, interpolator, extrapolation} {} + explicit Track(std::initializer_list> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant): Track{Containers::Array>{Containers::InPlaceInit, data}, interpolator, extrapolation, extrapolation} {} /** @brief Copying is not allowed */ - Track(const Track&) = delete; + Track(const Track&) = delete; /** @brief Move constructor */ - Track(Track&&) = default; + Track(Track&&) = default; /** @brief Copying is not allowed */ - Track& operator=(const Track&) = delete; + Track& operator=(const Track&) = delete; /** @brief Move constructor */ - Track& operator=(Track&&) = default; + Track& operator=(Track&&) = default; /** @brief Conversion to a view */ - operator TrackView() const noexcept { - return TrackView{_data, _interpolator, _before, _after}; + operator TrackView() const noexcept { + return TrackView{_data, _interpolator, _before, _after}; } /** @brief Interpolation function */ @@ -214,7 +219,7 @@ template class Track { * time, use @ref at(K, std::size_t&) const to supply a search hint. * @see @ref atStrict() */ - ResultOf at(K frame) const { + R at(K frame) const { std::size_t hint{}; return at(frame, hint); } @@ -226,7 +231,7 @@ template class Track { * information. * @see @ref at(K) const, @ref atStrict(K, std::size_t&) const */ - ResultOf at(K frame, std::size_t& hint) const { + R at(K frame, std::size_t& hint) const { return interpolate(keys(), values(), _before, _after, _interpolator, frame, hint); } @@ -237,7 +242,7 @@ template class Track { * restrictions. Calls @ref interpolateStrict(), see its documentation * for more information. */ - ResultOf atStrict(K frame, std::size_t& hint) const { + R atStrict(K frame, std::size_t& hint) const { return interpolateStrict(keys(), values(), _interpolator, frame, hint); } @@ -251,12 +256,17 @@ template class Track { @brief Animation track view @tparam K Key type @tparam V Value type +@tparam R Result type Unlike @ref Track this is a non-owning view onto keyframe + value pairs. See its documentation for more information. @experimental */ -template class TrackView { +template + #endif +> class TrackView { public: /** @brief Key type */ typedef K KeyType; @@ -265,7 +275,7 @@ template class TrackView { typedef V ValueType; /** @brief Animation result type */ - typedef ResultOf ResultType; + typedef R ResultType; /** @brief Interpolation function */ typedef ResultType(*Interpolator)(const ValueType&, const ValueType&, Float); @@ -287,7 +297,7 @@ template class TrackView { * Equivalent to calling @ref TrackView(const Containers::StridedArrayView&, const Containers::StridedArrayView&, Interpolator, Extrapolation, Extrapolation) * with both @p before and @p after set to @p extrapolation. */ - constexpr explicit TrackView(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& values, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Extrapolated) noexcept: TrackView{keys, values, interpolator, extrapolation, extrapolation} {} + constexpr explicit TrackView(const Containers::StridedArrayView& keys, const Containers::StridedArrayView& values, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Extrapolated) noexcept: TrackView{keys, values, interpolator, extrapolation, extrapolation} {} /** * @brief Construct from an interleaved array @@ -305,7 +315,7 @@ template class TrackView { * Equivalent to calling @ref TrackView(Containers::ArrayView>, Interpolator, Extrapolation, Extrapolation) * with both @p before and @p after set to @p extrapolation. */ - constexpr explicit TrackView(Containers::ArrayView> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Extrapolated) noexcept: TrackView{data, interpolator, extrapolation, extrapolation} {} + constexpr explicit TrackView(Containers::ArrayView> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Extrapolated) noexcept: TrackView{data, interpolator, extrapolation, extrapolation} {} /** * @brief Extrapolation behavior before first keyframe @@ -351,7 +361,7 @@ template class TrackView { * time, use @ref at(K, std::size_t&) const to supply a search hint. * @see @ref atStrict(K, std::size_t&) const */ - ResultOf at(K frame) const { + R at(K frame) const { std::size_t hint{}; return at(frame, hint); } @@ -363,7 +373,7 @@ template class TrackView { * information. * @see @ref at(K) const, @ref atStrict(K, std::size_t&) const */ - ResultOf at(K frame, std::size_t& hint) const { + R at(K frame, std::size_t& hint) const { return interpolate(_keys, _values, _before, _after, _interpolator, frame, hint); } @@ -374,7 +384,7 @@ template class TrackView { * restrictions. Calls @ref interpolateStrict(), see its documentation * for more information. */ - ResultOf atStrict(K frame, std::size_t& hint) const { + R atStrict(K frame, std::size_t& hint) const { return interpolateStrict(_keys, _values, _interpolator, frame, hint); }