mirror of https://github.com/mosra/magnum.git
9 changed files with 638 additions and 1 deletions
@ -0,0 +1,46 @@
|
||||
#ifndef Magnum_Animation_Animation_h |
||||
#define Magnum_Animation_Animation_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
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 Forward declarations for @ref Magnum::Animation namespace |
||||
*/ |
||||
|
||||
#include "Magnum/Types.h" |
||||
|
||||
namespace Magnum { namespace Animation { |
||||
|
||||
namespace Implementation { |
||||
template<class> struct TypeTraits; |
||||
} |
||||
|
||||
template<class V> using ResultOf = typename Implementation::TypeTraits<V>::ResultType; |
||||
|
||||
enum class Extrapolation: UnsignedByte; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,38 @@
|
||||
# |
||||
# This file is part of Magnum. |
||||
# |
||||
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
# 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. |
||||
# |
||||
|
||||
set(MagnumAnimation_HEADERS |
||||
Animation.h |
||||
Interpolation.h) |
||||
|
||||
# Force IDEs to display all header files in project view |
||||
add_custom_target(MagnumAnimation SOURCES ${MagnumAnimation_HEADERS}) |
||||
set_target_properties(MagnumAnimation PROPERTIES FOLDER "Magnum/Animation") |
||||
|
||||
install(FILES ${MagnumAnimation_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Animation) |
||||
|
||||
if(BUILD_TESTS) |
||||
add_subdirectory(Test) |
||||
endif() |
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
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. |
||||
*/ |
||||
|
||||
#include "Interpolation.h" |
||||
|
||||
namespace Magnum { namespace Animation { |
||||
|
||||
#ifndef DOXYGEN_GENERATING_OUTPUT |
||||
Debug& operator<<(Debug& debug, const Extrapolation value) { |
||||
switch(value) { |
||||
/* LCOV_EXCL_START */ |
||||
#define _c(value) case Extrapolation::value: return debug << "Animation::Extrapolation::" #value; |
||||
_c(DefaultConstructed) |
||||
_c(Constant) |
||||
_c(Extrapolated) |
||||
#undef _c |
||||
/* LCOV_EXCL_STOP */ |
||||
} |
||||
|
||||
return debug << "Animation::Extrapolation(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")"; |
||||
} |
||||
#endif |
||||
|
||||
}} |
||||
@ -0,0 +1,201 @@
|
||||
#ifndef Magnum_Animation_Interpolation_h |
||||
#define Magnum_Animation_Interpolation_h |
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
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 Alias @ref Magnum::Animation::ResultOf, enum @ref Magnum::Animation::Extrapolation, function @ref Magnum::Animation::interpolate(), @ref Magnum::Animation::interpolateStrict() |
||||
*/ |
||||
|
||||
#include <Corrade/Containers/StridedArrayView.h> |
||||
|
||||
#include "Magnum/Magnum.h" |
||||
#include "Magnum/Math/Functions.h" |
||||
#ifdef CORRADE_MSVC2015_COMPATIBILITY |
||||
#include "Magnum/Animation/Animation.h" /* ResultOf alias on MSVC 2015 */ |
||||
#endif |
||||
|
||||
namespace Magnum { namespace Animation { |
||||
|
||||
namespace Implementation { |
||||
template<class T> struct TypeTraits { |
||||
typedef T ResultType; |
||||
}; |
||||
} |
||||
|
||||
/**
|
||||
@brief Animation result type for given value type |
||||
|
||||
Result of interpolating two `V` values (for example interpolating two |
||||
@ref Color3 values gives back a @ref Color3 again, but interpolating a spline |
||||
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; |
||||
#endif |
||||
|
||||
/**
|
||||
@brief Animation extrapolation behavior |
||||
|
||||
Describes what value is returned for frames outside of keyframe range for given |
||||
track (frame lower than first keyframe or frame larger or equal to last |
||||
keyframe). |
||||
@see @ref interpolate() |
||||
@experimental |
||||
*/ |
||||
enum class Extrapolation: UnsignedByte { |
||||
/**
|
||||
* Values of first two / last two keyframes are extrapolated. In case |
||||
* there is only one keyframe, it's passed to both inputs of the |
||||
* interpolator. Implicit behavior in @ref interpolateStrict(). |
||||
*/ |
||||
Extrapolated, |
||||
|
||||
/**
|
||||
* Value of first/last keyframe is used. In other words, for the first |
||||
* keyframe the interpolator is called with first two keyframes and |
||||
* interpolation factor set to `0.0f`; for the last keyframe the |
||||
* interpolator is called with last two keyframes and interpolation factor |
||||
* set to `1.0f`. In case there is only one keyframe, it's passed to both |
||||
* inputs of the interpolator. |
||||
*/ |
||||
Constant, |
||||
|
||||
/** Default-constructed value is returned. */ |
||||
DefaultConstructed, |
||||
|
||||
/** @todo repeat? that would duplicate the play count feature though */ |
||||
}; |
||||
|
||||
/** @debugoperatorenum{Extrapolation} */ |
||||
MAGNUM_EXPORT Debug& operator<<(Debug& debug, Extrapolation value); |
||||
|
||||
/**
|
||||
@brief Interpolate animation value |
||||
@tparam K Key type |
||||
@tparam V Value type |
||||
@param keys Keys |
||||
@param values Values |
||||
@param before Extrapolation mode before first keyframe |
||||
@param after Extrapolation mode after last keyframe |
||||
@param interpolator Interpolator function |
||||
@param frame Frame at which to interpolate |
||||
@param hint Hint for keyframe search |
||||
|
||||
Does a linear search over the keyframes until it finds last keyframe which is |
||||
not larger than @p frame. Once the keyframe is found, reference to it and the immediately following keyframe is passed to @p interpolator along with |
||||
calculated interpolation factor, returning the interpolated value. |
||||
|
||||
- In case the first keyframe is already larger than @p frame or @p frame is |
||||
larger or equal to the last keyframe, either the first two or last two |
||||
keyframes are used and value is extrapolated according to @p before / |
||||
@p after. |
||||
- In case only one keyframe is present, its value is used for both sides of |
||||
the interpolator. |
||||
- In case no keyframes are present, default-constructed value is returned. |
||||
|
||||
The @p hint parameter hints where to start the linear search and is updated |
||||
with keyframe index matching @p frame. If @p frame is earlier than @p hint, the |
||||
search is restarted from the beginning. |
||||
@see @ref interpolateStrict(), @ref Math::select(), @ref Math::lerp(), |
||||
@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); |
||||
|
||||
/**
|
||||
@brief Interpolate animation value with strict constraints |
||||
|
||||
Does a linear search over the keyframes until it finds last keyframe which is |
||||
not larger than @p frame. Once the keyframe is found, reference to it and the immediately following keyframe is passed to @p interpolator along with |
||||
calculated interpolation factor, returning the interpolated value. The @p hint |
||||
parameter hints where to start the linear search and is updated with keyframe |
||||
index matching @p frame. If @p frame is earlier than @p hint, the search is |
||||
restarted from the beginning. |
||||
|
||||
This is a stricter but more performant version of @ref interpolate() with |
||||
implicit @ref Extrapolation::Extrapolated behavior. Expects that there are |
||||
always at least two keyframes. |
||||
@see @ref Math::select(), @ref Math::lerp(), @ref Math::slerp(), |
||||
@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> 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) { |
||||
CORRADE_ASSERT(keys.size() == values.size(), "Animation::interpolate(): keys and values don't have the same size", {}); |
||||
|
||||
/* No data, return default-constructed value */ |
||||
if(!keys.size()) return {}; |
||||
|
||||
/* Only one frame, return it verbatim (or default-constructed, if desired) */ |
||||
if(keys.size() == 1) { |
||||
if((frame < keys[0] && before == Extrapolation::DefaultConstructed) || |
||||
(frame > keys[0] && after == Extrapolation::DefaultConstructed)) |
||||
return {}; |
||||
|
||||
return interpolator(values[0], values[0], 0.0f); |
||||
} |
||||
|
||||
/* Rewind from the beginning if hint is too late */ |
||||
if(hint >= keys.size() || frame < keys[hint]) hint = 0; |
||||
|
||||
/* Go through the keys until we find a pair that is around given time */ |
||||
while(hint + 2 < keys.size() && frame >= keys[hint + 1]) |
||||
++hint; |
||||
|
||||
/* Special extrapolation outside of range. Usual extrapolation is handled
|
||||
below. */ |
||||
if(frame < keys[hint]) { |
||||
if(before == Extrapolation::DefaultConstructed) return {}; |
||||
if(before == Extrapolation::Constant) frame = keys[hint]; |
||||
} else if(frame >= keys[hint + 1]) { |
||||
if(after == Extrapolation::DefaultConstructed) return {}; |
||||
if(after == Extrapolation::Constant) frame = keys[hint + 1]; |
||||
} |
||||
|
||||
return interpolator(values[hint], values[hint + 1], |
||||
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) { |
||||
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", {}); |
||||
|
||||
/* Rewind from the beginning if hint is too late */ |
||||
if(hint >= keys.size() || frame < keys[hint]) hint = 0; |
||||
|
||||
/* Go through the keys until we find a pair that is around given time */ |
||||
while(hint + 2 < keys.size() && frame >= keys[hint + 1]) |
||||
++hint; |
||||
|
||||
return interpolator(values[hint], values[hint + 1], |
||||
Math::lerpInverted(keys[hint], keys[hint + 1], frame)); |
||||
} |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
@ -0,0 +1,34 @@
|
||||
# |
||||
# This file is part of Magnum. |
||||
# |
||||
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
# 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. |
||||
# |
||||
|
||||
corrade_add_test(AnimationInterpolationTest InterpolationTest.cpp LIBRARIES Magnum) |
||||
|
||||
set_property(TARGET |
||||
AnimationInterpolationTest |
||||
APPEND PROPERTY COMPILE_DEFINITIONS "CORRADE_GRACEFUL_ASSERT") |
||||
|
||||
set_target_properties( |
||||
AnimationInterpolationTest |
||||
PROPERTIES FOLDER "Magnum/Animation/Test") |
||||
@ -0,0 +1,252 @@
|
||||
/*
|
||||
This file is part of Magnum. |
||||
|
||||
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 |
||||
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. |
||||
*/ |
||||
|
||||
#include <sstream> |
||||
#include <Corrade/TestSuite/Tester.h> |
||||
|
||||
#include "Magnum/Animation/Interpolation.h" |
||||
|
||||
namespace Magnum { namespace Animation { namespace Test { |
||||
|
||||
struct InterpolationTest: TestSuite::Tester { |
||||
explicit InterpolationTest(); |
||||
|
||||
void interpolate(); |
||||
void interpolateStrict(); |
||||
void interpolateSingleKeyframe(); |
||||
void interpolateNoKeyframe(); |
||||
|
||||
void interpolateHint(); |
||||
void interpolateStrictHint(); |
||||
|
||||
void interpolateError(); |
||||
void interpolateStrictError(); |
||||
|
||||
void debugExtrapolation(); |
||||
}; |
||||
|
||||
namespace { |
||||
|
||||
const struct { |
||||
const char* name; |
||||
Extrapolation extrapolationBefore; |
||||
Extrapolation extrapolationAfter; |
||||
Float time; |
||||
Float expectedValue, expectedValueStrict; |
||||
std::size_t expectedHint; |
||||
} Data[] { |
||||
{"before default-constructed", |
||||
Extrapolation::DefaultConstructed, Extrapolation::Extrapolated, |
||||
-1.0f, 0.0f, 4.0f, 0}, |
||||
{"before constant", |
||||
Extrapolation::Constant, Extrapolation::Extrapolated, |
||||
-1.0f, 3.0f, 4.0f, 0}, |
||||
{"before extrapolated", |
||||
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed, |
||||
-1.0f, 4.0f, 4.0f, 0}, |
||||
{"during first", |
||||
Extrapolation::DefaultConstructed, Extrapolation::DefaultConstructed, |
||||
1.5f, 1.5f, 1.5f, 0}, |
||||
{"during second", |
||||
Extrapolation::DefaultConstructed, Extrapolation::DefaultConstructed, |
||||
4.75f, 1.0f, 1.0f, 2}, |
||||
{"after default-constructed", |
||||
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed, |
||||
6.0f, 0.0f, -1.5f, 2}, |
||||
{"after constant", |
||||
Extrapolation::Extrapolated, Extrapolation::Constant, |
||||
6.0f, 0.5f, -1.5f, 2}, |
||||
{"after extrapolated", |
||||
Extrapolation::DefaultConstructed, Extrapolation::Extrapolated, |
||||
6.0f, -1.5f, -1.5f, 2} |
||||
}; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
Extrapolation extrapolation; |
||||
Float time; |
||||
Float expectedValue; |
||||
} SingleKeyframeData[] { |
||||
{"before default-constructed", |
||||
Extrapolation::DefaultConstructed, -1.0f, 0.0f}, |
||||
{"before constant", |
||||
Extrapolation::Constant, -1.0f, 3.0f}, |
||||
{"before extrapolated", |
||||
Extrapolation::Extrapolated, -1.0f, 3.0f}, |
||||
{"at", |
||||
Extrapolation::DefaultConstructed, 0.0f, 3.0f}, |
||||
{"after default-constructed", |
||||
Extrapolation::DefaultConstructed, 1.0f, 0.0f}, |
||||
{"after constant", |
||||
Extrapolation::Constant, 1.0f, 3.0f}, |
||||
{"after extrapolated", |
||||
Extrapolation::Extrapolated, 1.0f, 3.0f} |
||||
}; |
||||
|
||||
const struct { |
||||
const char* name; |
||||
std::size_t hint; |
||||
} HintData[] { |
||||
{"before", 1}, |
||||
{"at", 2}, |
||||
{"after", 3}, |
||||
{"out of bounds", 405780454} |
||||
}; |
||||
|
||||
} |
||||
|
||||
InterpolationTest::InterpolationTest() { |
||||
addInstancedTests({&InterpolationTest::interpolate, |
||||
&InterpolationTest::interpolateStrict}, |
||||
Containers::arraySize(Data)); |
||||
|
||||
addInstancedTests({&InterpolationTest::interpolateSingleKeyframe}, |
||||
Containers::arraySize(SingleKeyframeData)); |
||||
|
||||
addTests({&InterpolationTest::interpolateNoKeyframe}); |
||||
|
||||
addInstancedTests({&InterpolationTest::interpolateHint, |
||||
&InterpolationTest::interpolateStrictHint}, |
||||
Containers::arraySize(HintData)); |
||||
|
||||
addTests({&InterpolationTest::interpolateError, |
||||
&InterpolationTest::interpolateStrictError, |
||||
|
||||
&InterpolationTest::debugExtrapolation}); |
||||
} |
||||
|
||||
namespace { |
||||
constexpr Float Keys[]{0.0f, 2.0f, 4.0f, 5.0f}; |
||||
constexpr Float Values[]{3.0f, 1.0f, 2.5f, 0.5f}; |
||||
} |
||||
|
||||
void InterpolationTest::interpolate() { |
||||
const auto& data = Data[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
std::size_t hint{}; |
||||
CORRADE_COMPARE((Animation::interpolate<Float, Float>( |
||||
Keys, Values, data.extrapolationBefore, data.extrapolationAfter, |
||||
Math::lerp, data.time, hint)), data.expectedValue); |
||||
CORRADE_COMPARE(hint, data.expectedHint); |
||||
} |
||||
|
||||
void InterpolationTest::interpolateStrict() { |
||||
const auto& data = Data[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
std::size_t hint{}; |
||||
CORRADE_COMPARE((Animation::interpolateStrict<Float, Float>( |
||||
Keys, Values, Math::lerp, data.time, hint)), data.expectedValueStrict); |
||||
CORRADE_COMPARE(hint, data.expectedHint); |
||||
} |
||||
|
||||
void InterpolationTest::interpolateSingleKeyframe() { |
||||
const auto& data = SingleKeyframeData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
std::size_t hint{}; |
||||
CORRADE_COMPARE((Animation::interpolate<Float, Float>( |
||||
Containers::arrayView(Keys).prefix(1), |
||||
Containers::arrayView(Values).prefix(1), |
||||
data.extrapolation, data.extrapolation, |
||||
Math::lerp, data.time, hint)), data.expectedValue); |
||||
CORRADE_COMPARE(hint, 0); |
||||
} |
||||
|
||||
void InterpolationTest::interpolateNoKeyframe() { |
||||
std::size_t hint{}; |
||||
CORRADE_COMPARE((Animation::interpolate<Float, Float>( |
||||
nullptr, nullptr, Extrapolation::Extrapolated, |
||||
Extrapolation::Extrapolated, Math::lerp, 3.5f, hint)), Float{}); |
||||
CORRADE_COMPARE(hint, 0); |
||||
} |
||||
|
||||
void InterpolationTest::interpolateHint() { |
||||
const auto& data = HintData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
std::size_t hint = data.hint; |
||||
CORRADE_COMPARE((Animation::interpolate<Float, Float>( |
||||
Keys, Values, Extrapolation::Extrapolated, Extrapolation::Extrapolated, |
||||
Math::lerp, 4.75f, hint)), 1.0f); |
||||
CORRADE_COMPARE(hint, 2); |
||||
} |
||||
|
||||
void InterpolationTest::interpolateStrictHint() { |
||||
const auto& data = HintData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
std::size_t hint = data.hint; |
||||
CORRADE_COMPARE((Animation::interpolateStrict<Float, Float>( |
||||
Keys, Values, Math::lerp, 4.75f, hint)), 1.0f); |
||||
CORRADE_COMPARE(hint, 2); |
||||
} |
||||
|
||||
void InterpolationTest::interpolateError() { |
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
|
||||
{ |
||||
std::size_t hint{}; |
||||
Animation::interpolate<Float, Float>(Keys, nullptr, Extrapolation::Extrapolated, Extrapolation::Extrapolated, Math::lerp, 0.0f, hint); |
||||
} |
||||
|
||||
CORRADE_COMPARE(out.str(), |
||||
"Animation::interpolate(): keys and values don't have the same size\n"); |
||||
} |
||||
|
||||
void InterpolationTest::interpolateStrictError() { |
||||
std::ostringstream out; |
||||
Error redirectError{&out}; |
||||
|
||||
{ |
||||
std::size_t hint{}; |
||||
Animation::interpolateStrict<Float, Float>( |
||||
Containers::arrayView(Keys).prefix(1), |
||||
Containers::arrayView(Values).prefix(1), |
||||
Math::lerp, 0.0f, hint); |
||||
} { |
||||
std::size_t hint{}; |
||||
Animation::interpolateStrict<Float, Float>( |
||||
Containers::arrayView(Keys).prefix(3), Values, |
||||
Math::lerp, 0.0f, hint); |
||||
} |
||||
|
||||
CORRADE_COMPARE(out.str(), |
||||
"Animation::interpolateStrict(): at least two keyframes required\n" |
||||
"Animation::interpolateStrict(): keys and values don't have the same size\n"); |
||||
} |
||||
|
||||
void InterpolationTest::debugExtrapolation() { |
||||
std::ostringstream out; |
||||
|
||||
Debug{&out} << Extrapolation::DefaultConstructed << Extrapolation(0xde); |
||||
CORRADE_COMPARE(out.str(), "Animation::Extrapolation::DefaultConstructed Animation::Extrapolation(0xde)\n"); |
||||
} |
||||
|
||||
}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Animation::Test::InterpolationTest) |
||||
Loading…
Reference in new issue