Browse Source

Bootstrap the Animation library with keyframe interpolation functions.

Yay!
pull/191/head
Vladimír Vondruš 8 years ago
parent
commit
9a8f88d59e
  1. 5
      doc/changelog.dox
  2. 12
      doc/namespaces.dox
  3. 46
      src/Magnum/Animation/Animation.h
  4. 38
      src/Magnum/Animation/CMakeLists.txt
  5. 46
      src/Magnum/Animation/Interpolation.cpp
  6. 201
      src/Magnum/Animation/Interpolation.h
  7. 34
      src/Magnum/Animation/Test/CMakeLists.txt
  8. 252
      src/Magnum/Animation/Test/InterpolationTest.cpp
  9. 5
      src/Magnum/CMakeLists.txt

5
doc/changelog.dox

@ -40,6 +40,11 @@ See also:
@subsection changelog-latest-new New features
@subsubsection changelog-latest-new-animation Animation library
- New experimental @ref Animation library for keyframe-based animation
playback
@subsubsection changelog-latest-new-math Math library
- Added @ref Math::Intersection::rangeFrustum(),

12
doc/namespaces.dox

@ -178,6 +178,18 @@ target_link_libraries(your-app Magnum::Magnum)
See @ref building and @ref cmake for more information.
*/
/** @dir Magnum/Animation
* @brief Namespace @ref Magnum::Animation
*/
/** @namespace Magnum::Animation
@brief Keyframe-based animation
This library is built as part of Magnum by default. To use it, you need to
find `Magnum` package and link to `Magnum::Magnum` target. See @ref building
and @ref cmake for more information.
@experimental
*/
/** @dir Magnum/Audio
* @brief Namespace @ref Magnum::Audio, @ref Magnum::Audio::Extensions
*/

46
src/Magnum/Animation/Animation.h

@ -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

38
src/Magnum/Animation/CMakeLists.txt

@ -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()

46
src/Magnum/Animation/Interpolation.cpp

@ -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
}}

201
src/Magnum/Animation/Interpolation.h

@ -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

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

@ -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")

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

@ -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)

5
src/Magnum/CMakeLists.txt

@ -32,7 +32,9 @@ set(Magnum_SRCS
PixelStorage.cpp
Resource.cpp
Sampler.cpp
Timeline.cpp)
Timeline.cpp
Animation/Interpolation.cpp)
set(Magnum_GracefulAssert_SRCS
Image.cpp
@ -199,6 +201,7 @@ install(TARGETS Magnum
install(FILES ${Magnum_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/configure.h DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR})
add_subdirectory(Animation)
add_subdirectory(Math)
add_subdirectory(Platform)

Loading…
Cancel
Save