Browse Source

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.
pull/191/head
Vladimír Vondruš 8 years ago
parent
commit
4d4b299740
  1. 4
      src/Magnum/Animation/Animation.h
  2. 9
      src/Magnum/Animation/Interpolation.h
  3. 33
      src/Magnum/Animation/Test/InterpolationTest.cpp
  4. 41
      src/Magnum/Animation/Test/TrackTest.cpp
  5. 37
      src/Magnum/Animation/Test/TrackViewTest.cpp
  6. 52
      src/Magnum/Animation/Track.h

4
src/Magnum/Animation/Animation.h

@ -41,8 +41,8 @@ template<class V> using ResultOf = typename Implementation::TypeTraits<V>::Resul
enum class Extrapolation: UnsignedByte;
template<class, class> class Track;
template<class, class> class TrackView;
template<class K, class V, class R = ResultOf<V>> class Track;
template<class K, class V, class R = ResultOf<V>> class TrackView;
}}

9
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<class K, class V> ResultOf<V> interpolate(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& values, Extrapolation before, Extrapolation after, ResultOf<V>(*interpolator)(const V&, const V&, Float), K frame, std::size_t& hint);
template<class K, class V, class R = ResultOf<V>> R interpolate(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& 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<class K, class V> ResultOf<V> interpolateStrict(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& values, ResultOf<V>(*interpolator)(const V&, const V&, Float), K frame, std::size_t& hint);
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);
template<class K, class V> ResultOf<V> interpolate(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& values, const Extrapolation before, const Extrapolation after, ResultOf<V>(*const interpolator)(const V&, const V&, Float), K frame, std::size_t& hint) {
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", {});
/* No data, return default-constructed value */
@ -190,7 +191,7 @@ template<class K, class V> ResultOf<V> interpolate(const Containers::StridedArra
Math::lerpInverted(keys[hint], keys[hint + 1], frame));
}
template<class K, class V> ResultOf<V> interpolateStrict(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& values, ResultOf<V>(*const interpolator)(const V&, const V&, Float), const K frame, std::size_t& hint) {
template<class K, class V, class R> R interpolateStrict(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& 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", {});

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

@ -27,6 +27,7 @@
#include <Corrade/TestSuite/Tester.h>
#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<Float, Half, Float>(
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<Float, Half, Float>(
Keys, HalfValues, lerpHalf, 4.75f, hint)), 1.0f);
CORRADE_COMPARE(hint, 2);
}
void InterpolationTest::interpolateError() {
std::ostringstream out;
Error redirectError{&out};

41
src/Magnum/Animation/Test/TrackTest.cpp

@ -26,6 +26,7 @@
#include <Corrade/TestSuite/Tester.h>
#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<Float, Half, Float> 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<Float, Half, Float> 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)

37
src/Magnum/Animation/Test/TrackViewTest.cpp

@ -26,6 +26,7 @@
#include <Corrade/TestSuite/Tester.h>
#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<Float, Half, Float> 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<Float, Half, Float> 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)

52
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 K, class V> class Track {
template<class K, class V, class R
#ifdef DOXYGEN_GENERATING_OUTPUT
= ResultOf<V>
#endif
> class Track {
public:
/** @brief Key type */
typedef K KeyType;
@ -115,7 +120,7 @@ template<class K, class V> class Track {
typedef V ValueType;
/** @brief Animation result type */
typedef ResultOf<V> ResultType;
typedef R ResultType;
/** @brief Interpolation function */
typedef ResultType(*Interpolator)(const ValueType&, const ValueType&, Float);
@ -133,32 +138,32 @@ template<class K, class V> class Track {
explicit Track(Containers::Array<std::pair<K, V>>&& data, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: _data{std::move(data)}, _interpolator{interpolator}, _before{before}, _after{after} {}
/** @overload */
explicit Track(std::initializer_list<std::pair<K, V>> data, Interpolator interpolator, Extrapolation before, Extrapolation after): Track<K, V>{Containers::Array<std::pair<K, V>>{Containers::InPlaceInit, data}, interpolator, before, after} {}
explicit Track(std::initializer_list<std::pair<K, V>> data, Interpolator interpolator, Extrapolation before, Extrapolation after): Track<K, V, R>{Containers::Array<std::pair<K, V>>{Containers::InPlaceInit, data}, interpolator, before, after} {}
/** @overload
* Equivalent to calling @ref Track(Containers::Array<std::pair<K, V>>&&, Interpolator, Extrapolation, Extrapolation)
* with both @p before and @p after set to @p extrapolation.
*/
explicit Track(Containers::Array<std::pair<K, V>>&& data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: Track<K, V>{std::move(data), interpolator, extrapolation, extrapolation} {}
explicit Track(Containers::Array<std::pair<K, V>>&& data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: Track<K, V, R>{std::move(data), interpolator, extrapolation, extrapolation} {}
/** @overload */
explicit Track(std::initializer_list<std::pair<K, V>> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant): Track<K, V>{Containers::Array<std::pair<K, V>>{Containers::InPlaceInit, data}, interpolator, extrapolation} {}
explicit Track(std::initializer_list<std::pair<K, V>> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant): Track<K, V, R>{Containers::Array<std::pair<K, V>>{Containers::InPlaceInit, data}, interpolator, extrapolation, extrapolation} {}
/** @brief Copying is not allowed */
Track(const Track<K, V>&) = delete;
Track(const Track<K, V, R>&) = delete;
/** @brief Move constructor */
Track(Track<K, V>&&) = default;
Track(Track<K, V, R>&&) = default;
/** @brief Copying is not allowed */
Track<K, V>& operator=(const Track<K, V>&) = delete;
Track<K, V, R>& operator=(const Track<K, V, R>&) = delete;
/** @brief Move constructor */
Track<K, V>& operator=(Track<K, V>&&) = default;
Track<K, V, R>& operator=(Track<K, V, R>&&) = default;
/** @brief Conversion to a view */
operator TrackView<K, V>() const noexcept {
return TrackView<K, V>{_data, _interpolator, _before, _after};
operator TrackView<K, V, R>() const noexcept {
return TrackView<K, V, R>{_data, _interpolator, _before, _after};
}
/** @brief Interpolation function */
@ -214,7 +219,7 @@ template<class K, class V> class Track {
* time, use @ref at(K, std::size_t&) const to supply a search hint.
* @see @ref atStrict()
*/
ResultOf<V> at(K frame) const {
R at(K frame) const {
std::size_t hint{};
return at(frame, hint);
}
@ -226,7 +231,7 @@ template<class K, class V> class Track {
* information.
* @see @ref at(K) const, @ref atStrict(K, std::size_t&) const
*/
ResultOf<V> 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 K, class V> class Track {
* restrictions. Calls @ref interpolateStrict(), see its documentation
* for more information.
*/
ResultOf<V> 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 K, class V> 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 K, class V> class TrackView {
template<class K, class V, class R
#ifdef DOXYGEN_GENERATING_OUTPUT
= ResultOf<V>
#endif
> class TrackView {
public:
/** @brief Key type */
typedef K KeyType;
@ -265,7 +275,7 @@ template<class K, class V> class TrackView {
typedef V ValueType;
/** @brief Animation result type */
typedef ResultOf<V> ResultType;
typedef R ResultType;
/** @brief Interpolation function */
typedef ResultType(*Interpolator)(const ValueType&, const ValueType&, Float);
@ -287,7 +297,7 @@ template<class K, class V> class TrackView {
* Equivalent to calling @ref TrackView(const Containers::StridedArrayView<const K>&, const Containers::StridedArrayView<const V>&, Interpolator, Extrapolation, Extrapolation)
* with both @p before and @p after set to @p extrapolation.
*/
constexpr explicit TrackView(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& values, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Extrapolated) noexcept: TrackView<K, V>{keys, values, interpolator, extrapolation, extrapolation} {}
constexpr explicit TrackView(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& values, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Extrapolated) noexcept: TrackView<K, V, R>{keys, values, interpolator, extrapolation, extrapolation} {}
/**
* @brief Construct from an interleaved array
@ -305,7 +315,7 @@ template<class K, class V> class TrackView {
* Equivalent to calling @ref TrackView(Containers::ArrayView<const std::pair<K, V>>, Interpolator, Extrapolation, Extrapolation)
* with both @p before and @p after set to @p extrapolation.
*/
constexpr explicit TrackView(Containers::ArrayView<const std::pair<K, V>> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Extrapolated) noexcept: TrackView<K, V>{data, interpolator, extrapolation, extrapolation} {}
constexpr explicit TrackView(Containers::ArrayView<const std::pair<K, V>> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Extrapolated) noexcept: TrackView<K, V, R>{data, interpolator, extrapolation, extrapolation} {}
/**
* @brief Extrapolation behavior before first keyframe
@ -351,7 +361,7 @@ template<class K, class V> 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<V> at(K frame) const {
R at(K frame) const {
std::size_t hint{};
return at(frame, hint);
}
@ -363,7 +373,7 @@ template<class K, class V> class TrackView {
* information.
* @see @ref at(K) const, @ref atStrict(K, std::size_t&) const
*/
ResultOf<V> 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 K, class V> class TrackView {
* restrictions. Calls @ref interpolateStrict(), see its documentation
* for more information.
*/
ResultOf<V> atStrict(K frame, std::size_t& hint) const {
R atStrict(K frame, std::size_t& hint) const {
return interpolateStrict(_keys, _values, _interpolator, frame, hint);
}

Loading…
Cancel
Save