mirror of https://github.com/mosra/magnum.git
9 changed files with 928 additions and 2 deletions
@ -0,0 +1,102 @@
|
||||
/*
|
||||
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 "Magnum/Math/Quaternion.h" |
||||
#include "Magnum/Animation/Track.h" |
||||
|
||||
using namespace Magnum; |
||||
using namespace Magnum::Math::Literals; |
||||
|
||||
int main() { |
||||
{ |
||||
/* [Track-usage] */ |
||||
const Animation::Track<Float, Vector2> jump{{ |
||||
{0.0f, Vector2::yAxis(0.0f)}, |
||||
{1.0f, Vector2::yAxis(0.5f)}, |
||||
{2.0f, Vector2::yAxis(0.75f)}, |
||||
{3.0f, Vector2::yAxis(0.875f)}, |
||||
{4.0f, Vector2::yAxis(0.75f)}, |
||||
{5.0f, Vector2::yAxis(0.5f)}, |
||||
{6.0f, Vector2::yAxis(0.0f)} |
||||
}, Math::lerp, Animation::Extrapolation::Constant}; |
||||
|
||||
Vector2 position = jump.at(2.2f); // y = 0.775
|
||||
/* [Track-usage] */ |
||||
|
||||
{ |
||||
/* [Track-performance-hint] */ |
||||
std::size_t hint = 0; |
||||
Vector2 position = jump.at(2.2f, hint); // y = 0.775, hint = 2
|
||||
/* [Track-performance-hint] */ |
||||
static_cast<void>(position); |
||||
} |
||||
|
||||
{ |
||||
/* [Track-performance-strict] */ |
||||
std::size_t hint = 0; |
||||
Vector2 position = jump.atStrict(2.2f, hint); // y = 0.775, hint = 2
|
||||
/* [Track-performance-strict] */ |
||||
static_cast<void>(position); |
||||
} |
||||
|
||||
static_cast<void>(position); |
||||
} |
||||
|
||||
{ |
||||
/* [Track-performance-cache] */ |
||||
struct Keyframe { |
||||
Float time; |
||||
Vector2 position; |
||||
Deg rotation; |
||||
}; |
||||
const Keyframe data[]{ |
||||
{0.0f, Vector2::yAxis(0.0f), 0.0_degf}, |
||||
{1.0f, Vector2::yAxis(0.5f), 60.0_degf}, |
||||
{2.0f, Vector2::yAxis(0.75f), 80.0_degf}, |
||||
{3.0f, Vector2::yAxis(0.875f), 90.0_degf}, |
||||
{4.0f, Vector2::yAxis(0.75f), 100.0_degf}, |
||||
{5.0f, Vector2::yAxis(0.5f), 120.0_degf}, |
||||
{6.0f, Vector2::yAxis(0.0f), 180.0_degf} |
||||
}; |
||||
|
||||
Animation::TrackView<Float, Vector2> positions{ |
||||
{&data[0].time, Containers::arraySize(data), sizeof(Keyframe)}, |
||||
{&data[0].position, Containers::arraySize(data), sizeof(Keyframe)}, |
||||
Math::lerp}; |
||||
Animation::TrackView<Float, Deg> rotations{ |
||||
{&data[0].time, Containers::arraySize(data), sizeof(Keyframe)}, |
||||
{&data[0].rotation, Containers::arraySize(data), sizeof(Keyframe)}, |
||||
Math::lerp}; |
||||
|
||||
Float time = 2.2f; |
||||
std::size_t hint = 0; |
||||
Vector2 position = positions.atStrict(time, hint); // y = 0.775f
|
||||
Deg rotation = rotations.atStrict(time, hint); // φ = 82°
|
||||
/* [Track-performance-cache] */ |
||||
static_cast<void>(position); |
||||
static_cast<void>(rotation); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,223 @@
|
||||
/*
|
||||
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 <Corrade/TestSuite/Tester.h> |
||||
|
||||
#include "Magnum/Animation/Track.h" |
||||
#include "Magnum/Math/Vector3.h" |
||||
|
||||
namespace Magnum { namespace Animation { namespace Test { |
||||
|
||||
struct TrackTest: TestSuite::Tester { |
||||
explicit TrackTest(); |
||||
|
||||
void constructArray(); |
||||
void constructArrayDefaults(); |
||||
void constructInitializerList(); |
||||
void constructInitializerListDefaults(); |
||||
|
||||
void convertView(); |
||||
|
||||
void at(); |
||||
void atStrict(); |
||||
}; |
||||
|
||||
namespace { |
||||
|
||||
/* Reduced version from InterpolateTest, keep in sync with TrackViewTest */ |
||||
const struct { |
||||
const char* name; |
||||
Extrapolation extrapolationBefore; |
||||
Extrapolation extrapolationAfter; |
||||
Float time; |
||||
Float expectedValue, expectedValueStrict; |
||||
std::size_t expectedHint; |
||||
} AtData[] { |
||||
{"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} |
||||
}; |
||||
|
||||
} |
||||
|
||||
TrackTest::TrackTest() { |
||||
addTests({&TrackTest::constructArray, |
||||
&TrackTest::constructArrayDefaults, |
||||
&TrackTest::constructInitializerList, |
||||
&TrackTest::constructInitializerListDefaults, |
||||
|
||||
&TrackTest::convertView}); |
||||
|
||||
addInstancedTests({&TrackTest::at, |
||||
&TrackTest::atStrict}, Containers::arraySize(AtData)); |
||||
} |
||||
|
||||
using namespace Math::Literals; |
||||
|
||||
void TrackTest::constructArray() { |
||||
const Track<Float, Vector3> a{ |
||||
Containers::Array<std::pair<Float, Vector3>>{Containers::InPlaceInit, |
||||
{{0.0f, {3.0f, 1.0f, 0.1f}}, |
||||
{5.0f, {0.3f, 0.6f, 1.0f}}}}, |
||||
Math::select, Extrapolation::Extrapolated, Extrapolation::Constant}; |
||||
|
||||
CORRADE_COMPARE(a.interpolator(), Math::select); |
||||
CORRADE_COMPARE(a.before(), Extrapolation::Extrapolated); |
||||
CORRADE_COMPARE(a.after(), Extrapolation::Constant); |
||||
CORRADE_COMPARE(a.data().size(), 2); |
||||
CORRADE_COMPARE(a.keys().size(), 2); |
||||
CORRADE_COMPARE(a.values().size(), 2); |
||||
CORRADE_COMPARE(a[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}})); |
||||
CORRADE_COMPARE(a.data()[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}})); |
||||
CORRADE_COMPARE(a.keys()[1], 5.0f); |
||||
CORRADE_COMPARE(a.values()[0], (Vector3{3.0f, 1.0f, 0.1f})); |
||||
} |
||||
|
||||
void TrackTest::constructArrayDefaults() { |
||||
const Track<Float, Vector3> a{ |
||||
Containers::Array<std::pair<Float, Vector3>>{Containers::InPlaceInit, |
||||
{{0.0f, {3.0f, 1.0f, 0.1f}}}}, |
||||
Math::lerp, Extrapolation::DefaultConstructed}; |
||||
|
||||
CORRADE_COMPARE(a.interpolator(), Math::lerp); |
||||
CORRADE_COMPARE(a.before(), Extrapolation::DefaultConstructed); |
||||
CORRADE_COMPARE(a.after(), Extrapolation::DefaultConstructed); |
||||
CORRADE_COMPARE(a.data().size(), 1); |
||||
CORRADE_COMPARE(a.keys().size(), 1); |
||||
CORRADE_COMPARE(a.values().size(), 1); |
||||
CORRADE_COMPARE(a[0], (std::pair<Float, Vector3>{0.0f, {3.0f, 1.0f, 0.1f}})); |
||||
CORRADE_COMPARE(a.data()[0], (std::pair<Float, Vector3>{0.0f, {3.0f, 1.0f, 0.1f}})); |
||||
CORRADE_COMPARE(a.keys()[0], 0.0f); |
||||
CORRADE_COMPARE(a.values()[0], (Vector3{3.0f, 1.0f, 0.1f})); |
||||
} |
||||
|
||||
void TrackTest::constructInitializerList() { |
||||
const Track<Float, Vector3> a{ |
||||
{{0.0f, {3.0f, 1.0f, 0.1f}}, |
||||
{5.0f, {0.3f, 0.6f, 1.0f}}}, |
||||
Math::select, Extrapolation::Extrapolated, Extrapolation::DefaultConstructed}; |
||||
|
||||
CORRADE_COMPARE(a.interpolator(), Math::select); |
||||
CORRADE_COMPARE(a.before(), Extrapolation::Extrapolated); |
||||
CORRADE_COMPARE(a.after(), Extrapolation::DefaultConstructed); |
||||
CORRADE_COMPARE(a.data().size(), 2); |
||||
CORRADE_COMPARE(a.keys().size(), 2); |
||||
CORRADE_COMPARE(a.values().size(), 2); |
||||
CORRADE_COMPARE(a[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}})); |
||||
CORRADE_COMPARE(a.data()[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}})); |
||||
CORRADE_COMPARE(a.keys()[1], 5.0f); |
||||
CORRADE_COMPARE(a.values()[0], (Vector3{3.0f, 1.0f, 0.1f})); |
||||
} |
||||
|
||||
void TrackTest::constructInitializerListDefaults() { |
||||
const Track<Float, Vector3> a{{{0.0f, {3.0f, 1.0f, 0.1f}}}, |
||||
Math::lerp, Extrapolation::Constant}; |
||||
|
||||
CORRADE_COMPARE(a.interpolator(), Math::lerp); |
||||
CORRADE_COMPARE(a.before(), Extrapolation::Constant); |
||||
CORRADE_COMPARE(a.after(), Extrapolation::Constant); |
||||
CORRADE_COMPARE(a.data().size(), 1); |
||||
CORRADE_COMPARE(a.keys().size(), 1); |
||||
CORRADE_COMPARE(a.values().size(), 1); |
||||
CORRADE_COMPARE(a[0], (std::pair<Float, Vector3>{0.0f, {3.0f, 1.0f, 0.1f}})); |
||||
CORRADE_COMPARE(a.data()[0], (std::pair<Float, Vector3>{0.0f, {3.0f, 1.0f, 0.1f}})); |
||||
CORRADE_COMPARE(a.keys()[0], 0.0f); |
||||
CORRADE_COMPARE(a.values()[0], (Vector3{3.0f, 1.0f, 0.1f})); |
||||
} |
||||
|
||||
void TrackTest::convertView() { |
||||
const Track<Float, Vector3> a{ |
||||
{{0.0f, {3.0f, 1.0f, 0.1f}}, |
||||
{5.0f, {0.3f, 0.6f, 1.0f}}}, |
||||
Math::select, Extrapolation::Extrapolated, Extrapolation::DefaultConstructed}; |
||||
const TrackView<Float, Vector3> av = a; |
||||
|
||||
CORRADE_COMPARE(av.interpolator(), Math::select); |
||||
CORRADE_COMPARE(av.before(), Extrapolation::Extrapolated); |
||||
CORRADE_COMPARE(av.after(), Extrapolation::DefaultConstructed); |
||||
CORRADE_COMPARE(av.keys().size(), 2); |
||||
CORRADE_COMPARE(av.values().size(), 2); |
||||
CORRADE_COMPARE(av[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}})); |
||||
CORRADE_COMPARE(av.keys()[1], 5.0f); |
||||
CORRADE_COMPARE(av.values()[0], (Vector3{3.0f, 1.0f, 0.1f})); |
||||
} |
||||
|
||||
void TrackTest::at() { |
||||
const auto& data = AtData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
const Track<Float, Float> a{ |
||||
{{0.0f, 3.0f}, |
||||
{2.0f, 1.0f}, |
||||
{4.0f, 2.5f}, |
||||
{5.0f, 0.5f}}, Math::lerp, |
||||
data.extrapolationBefore, data.extrapolationAfter}; |
||||
|
||||
std::size_t hint{}; |
||||
CORRADE_COMPARE(a.at(data.time, hint), data.expectedValue); |
||||
CORRADE_COMPARE(a.at(data.time), data.expectedValue); |
||||
CORRADE_COMPARE(hint, data.expectedHint); |
||||
} |
||||
|
||||
void TrackTest::atStrict() { |
||||
const auto& data = AtData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
const Track<Float, Float> a{ |
||||
{{0.0f, 3.0f}, |
||||
{2.0f, 1.0f}, |
||||
{4.0f, 2.5f}, |
||||
{5.0f, 0.5f}}, Math::lerp, |
||||
data.extrapolationBefore, data.extrapolationAfter}; |
||||
|
||||
std::size_t hint{}; |
||||
CORRADE_COMPARE(a.atStrict(data.time, hint), data.expectedValueStrict); |
||||
CORRADE_COMPARE(hint, data.expectedHint); |
||||
} |
||||
|
||||
}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Animation::Test::TrackTest) |
||||
@ -0,0 +1,193 @@
|
||||
/*
|
||||
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 <Corrade/TestSuite/Tester.h> |
||||
|
||||
#include "Magnum/Animation/Track.h" |
||||
#include "Magnum/Math/Vector3.h" |
||||
|
||||
namespace Magnum { namespace Animation { namespace Test { |
||||
|
||||
struct TrackViewTest: TestSuite::Tester { |
||||
explicit TrackViewTest(); |
||||
|
||||
void construct(); |
||||
void constructDefaults(); |
||||
void constructSingleArray(); |
||||
void constructSingleArrayDefaults(); |
||||
|
||||
void at(); |
||||
void atStrict(); |
||||
}; |
||||
|
||||
namespace { |
||||
|
||||
/* Reduced version from InterpolateTest, keep in sync with TrackTest */ |
||||
const struct { |
||||
const char* name; |
||||
Extrapolation extrapolationBefore; |
||||
Extrapolation extrapolationAfter; |
||||
Float time; |
||||
Float expectedValue, expectedValueStrict; |
||||
std::size_t expectedHint; |
||||
} AtData[] { |
||||
{"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} |
||||
}; |
||||
|
||||
} |
||||
|
||||
TrackViewTest::TrackViewTest() { |
||||
addTests({&TrackViewTest::construct, |
||||
&TrackViewTest::constructDefaults, |
||||
&TrackViewTest::constructSingleArray, |
||||
&TrackViewTest::constructSingleArrayDefaults}); |
||||
|
||||
addInstancedTests({&TrackViewTest::at, |
||||
&TrackViewTest::atStrict}, Containers::arraySize(AtData)); |
||||
} |
||||
|
||||
using namespace Math::Literals; |
||||
|
||||
void TrackViewTest::construct() { |
||||
constexpr Float keys[]{0.0f, 5.0f}; |
||||
constexpr Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}}; |
||||
|
||||
const TrackView<Float, Vector3> a{keys, values, Math::lerp, |
||||
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed}; |
||||
|
||||
CORRADE_COMPARE(a.interpolator(), Math::lerp); |
||||
CORRADE_COMPARE(a.before(), Extrapolation::Extrapolated); |
||||
CORRADE_COMPARE(a.after(), Extrapolation::DefaultConstructed); |
||||
CORRADE_COMPARE(a.keys().size(), 2); |
||||
CORRADE_COMPARE(a.values().size(), 2); |
||||
CORRADE_COMPARE(a[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}})); |
||||
} |
||||
|
||||
void TrackViewTest::constructDefaults() { |
||||
constexpr Float keys[]{0.0f, 5.0f}; |
||||
constexpr Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}}; |
||||
|
||||
const TrackView<Float, Vector3> a{keys, values, Math::lerp, |
||||
Extrapolation::Constant}; |
||||
|
||||
CORRADE_COMPARE(a.interpolator(), Math::lerp); |
||||
CORRADE_COMPARE(a.before(), Extrapolation::Constant); |
||||
CORRADE_COMPARE(a.after(), Extrapolation::Constant); |
||||
CORRADE_COMPARE(a.keys().size(), 2); |
||||
CORRADE_COMPARE(a.values().size(), 2); |
||||
CORRADE_COMPARE(a[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}})); |
||||
} |
||||
|
||||
void TrackViewTest::constructSingleArray() { |
||||
const std::pair<Float, Vector3> data[]{ |
||||
{0.0f, {3.0f, 1.0f, 0.1f}}, |
||||
{5.0f, {0.3f, 0.6f, 1.0f}}}; |
||||
|
||||
const TrackView<Float, Vector3> a{data, Math::lerp, |
||||
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed}; |
||||
|
||||
CORRADE_COMPARE(a.interpolator(), Math::lerp); |
||||
CORRADE_COMPARE(a.before(), Extrapolation::Extrapolated); |
||||
CORRADE_COMPARE(a.after(), Extrapolation::DefaultConstructed); |
||||
CORRADE_COMPARE(a.keys().size(), 2); |
||||
CORRADE_COMPARE(a.values().size(), 2); |
||||
CORRADE_COMPARE(a[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}})); |
||||
} |
||||
|
||||
void TrackViewTest::constructSingleArrayDefaults() { |
||||
const std::pair<Float, Vector3> data[]{ |
||||
{0.0f, {3.0f, 1.0f, 0.1f}}, |
||||
{5.0f, {0.3f, 0.6f, 1.0f}}}; |
||||
|
||||
const TrackView<Float, Vector3> a{data, Math::lerp, |
||||
Extrapolation::Constant}; |
||||
|
||||
CORRADE_COMPARE(a.interpolator(), Math::lerp); |
||||
CORRADE_COMPARE(a.before(), Extrapolation::Constant); |
||||
CORRADE_COMPARE(a.after(), Extrapolation::Constant); |
||||
CORRADE_COMPARE(a.keys().size(), 2); |
||||
CORRADE_COMPARE(a.values().size(), 2); |
||||
CORRADE_COMPARE(a[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}})); |
||||
} |
||||
|
||||
namespace { |
||||
const std::pair<Float, Float> Keyframes[]{ |
||||
{0.0f, 3.0f}, |
||||
{2.0f, 1.0f}, |
||||
{4.0f, 2.5f}, |
||||
{5.0f, 0.5f}}; |
||||
} |
||||
|
||||
void TrackViewTest::at() { |
||||
const auto& data = AtData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
const TrackView<Float, Float> a{Keyframes, Math::lerp, |
||||
data.extrapolationBefore, data.extrapolationAfter}; |
||||
|
||||
std::size_t hint{}; |
||||
CORRADE_COMPARE(a.at(data.time, hint), data.expectedValue); |
||||
CORRADE_COMPARE(a.at(data.time), data.expectedValue); |
||||
CORRADE_COMPARE(hint, data.expectedHint); |
||||
} |
||||
|
||||
void TrackViewTest::atStrict() { |
||||
const auto& data = AtData[testCaseInstanceId()]; |
||||
setTestCaseDescription(data.name); |
||||
|
||||
const TrackView<Float, Float> a{Keyframes, Math::lerp, |
||||
data.extrapolationBefore, data.extrapolationAfter}; |
||||
|
||||
std::size_t hint{}; |
||||
CORRADE_COMPARE(a.atStrict(data.time, hint), data.expectedValueStrict); |
||||
CORRADE_COMPARE(hint, data.expectedHint); |
||||
} |
||||
|
||||
}}} |
||||
|
||||
CORRADE_TEST_MAIN(Magnum::Animation::Test::TrackViewTest) |
||||
@ -0,0 +1,390 @@
|
||||
#ifndef Magnum_Animation_Track_h |
||||
#define Magnum_Animation_Track_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 Class @ref Magnum::Animation::Track, @ref Magnum::Animation::TrackView |
||||
*/ |
||||
|
||||
#include <Corrade/Containers/Array.h> |
||||
|
||||
#include "Magnum/Animation/Animation.h" |
||||
#include "Magnum/Animation/Interpolation.h" |
||||
|
||||
namespace Magnum { namespace Animation { |
||||
|
||||
/**
|
||||
@brief Animation track |
||||
@tparam K Key type |
||||
@tparam V Value type |
||||
|
||||
Immutable storage of keyframe + value pairs. |
||||
|
||||
@section Animation-Track-usage Basic usage |
||||
|
||||
Animation track is defined by a list of keyframes (time+value pairs), |
||||
interpolator function and extrapolation behavior. |
||||
|
||||
@snippet MagnumAnimation.cpp Track-usage |
||||
|
||||
@section Animation-Track-interpolators Types and interpolators |
||||
|
||||
The track supports arbitrary types for keys, values and interpolators. These |
||||
are common combinations: |
||||
|
||||
@m_class{m-fullwidth} |
||||
|
||||
Interpolation type | Value type | Result type | Interpolator |
||||
------------------- | ----------------- | ------------- | ------------ |
||||
Constant | any `V` | `V` | @ref Math::select() |
||||
Linear | @cpp bool @ce <b></b> | @cpp bool @ce <b></b> | @ref Math::select() |
||||
Linear | @ref Math::BoolVector | @ref Math::BoolVector | @ref Math::select() |
||||
Linear | any scalar `V` | `V` | @ref Math::lerp() |
||||
Linear | any vector `V` | `V` | @ref Math::lerp() |
||||
Linear | @ref Math::Quaternion | @ref Math::Quaternion | @ref Math::lerp(const Quaternion<T>&, const Quaternion<T>&, T) "Math::lerp()" |
||||
Spherical linear | @ref Math::Quaternion | @ref Math::Quaternion | @ref Math::slerp(const Quaternion<T>&, const Quaternion<T>&, T) "Math::slerp()" |
||||
Screw linear | @ref Math::DualQuaternion | @ref Math::DualQuaternion | @ref Math::sclerp(const DualQuaternion<T>&, const DualQuaternion<T>&, T) "Math::sclerp()" |
||||
|
||||
@section Animation-Track-performance Performance tuning |
||||
|
||||
The snippet shown above is convenience-oriented at a cost of sacrificing some |
||||
performance. You have the following options: |
||||
|
||||
@subsection Animation-Track-performance-hint Keyframe hinting |
||||
|
||||
The @ref Track and @ref TrackView classes are fully stateless and the |
||||
@ref at(K) const function performs a linear search for matching keyframe from |
||||
the beginning every time. You can use @ref at(K, std::size_t&) const to |
||||
remember last used keyframe index and pass it in the next iteration as a hint: |
||||
|
||||
@snippet MagnumAnimation.cpp Track-performance-hint |
||||
|
||||
@subsection Animation-Track-performance-strict Strict interpolation |
||||
|
||||
While it's possible to have different @ref Extrapolation modes for frames |
||||
outside of the track range with graceful handling of single- or zero-frame |
||||
animations, the additional checks have some impact. The @ref atStrict() has |
||||
implicit @ref Extrapolation::Extrapolated behavior and assumes there are always |
||||
at least two keyframes, resulting in more compact interpolation code. If your |
||||
animation data satisfy the prerequisites, simply use it in place of @ref at(): |
||||
|
||||
@snippet MagnumAnimation.cpp Track-performance-strict |
||||
|
||||
@subsection Animation-Track-performance-cache Cache-efficient data layout |
||||
|
||||
Usually multiple tracks (translation, rotation, scaling) are combined together |
||||
to form a single animation. In order to achieve better data layout, consider |
||||
interleaving the data and passing them using |
||||
@ref Corrade::Containers::StridedArrayView to multiple @ref TrackView |
||||
instead of having data duplicated scattered across disjoint allocations of |
||||
@ref Track instances: |
||||
|
||||
@snippet MagnumAnimation.cpp Track-performance-cache |
||||
|
||||
@experimental |
||||
*/ |
||||
template<class K, class V> class Track { |
||||
public: |
||||
/** @brief Key type */ |
||||
typedef K KeyType; |
||||
|
||||
/** @brief Value type */ |
||||
typedef V ValueType; |
||||
|
||||
/** @brief Animation result type */ |
||||
typedef ResultOf<V> ResultType; |
||||
|
||||
/** @brief Interpolation function */ |
||||
typedef ResultType(*Interpolator)(const ValueType&, const ValueType&, Float); |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* @param data Keyframe data |
||||
* @param interpolator Interpolator function |
||||
* @param before Extrapolation behavior |
||||
* @param after Extrapolation behavior after |
||||
* |
||||
* The keyframe data are assumed to be stored in sorted order. It's not |
||||
* an error to have two successive keyframes with the same frame value. |
||||
*/ |
||||
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} {} |
||||
|
||||
/** @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} {} |
||||
|
||||
/** @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} {} |
||||
|
||||
/** @brief Copying is not allowed */ |
||||
Track(const Track<K, V>&) = delete; |
||||
|
||||
/** @brief Move constructor */ |
||||
Track(Track<K, V>&&) = default; |
||||
|
||||
/** @brief Copying is not allowed */ |
||||
Track<K, V>& operator=(const Track<K, V>&) = delete; |
||||
|
||||
/** @brief Move constructor */ |
||||
Track<K, V>& operator=(Track<K, V>&&) = default; |
||||
|
||||
/** @brief Conversion to a view */ |
||||
operator TrackView<K, V>() const noexcept { |
||||
return TrackView<K, V>{_data, _interpolator, _before, _after}; |
||||
} |
||||
|
||||
/** @brief Interpolation function */ |
||||
Interpolator interpolator() const { return _interpolator; } |
||||
|
||||
/**
|
||||
* @brief Extrapolation behavior before first keyframe |
||||
* |
||||
* @see @ref after(), @ref at() |
||||
*/ |
||||
Extrapolation before() const { return _before; } |
||||
|
||||
/**
|
||||
* @brief Extrapolation behavior after last keyframe |
||||
* |
||||
* @see @ref before(), @ref at() |
||||
*/ |
||||
Extrapolation after() const { return _after; } |
||||
|
||||
/**
|
||||
* @brief Keyframe data |
||||
* |
||||
* @see @ref keys(), @ref values(), @ref operator[]() |
||||
*/ |
||||
Containers::ArrayView<const std::pair<K, V>> data() const { return _data; } |
||||
|
||||
/**
|
||||
* @brief Key data |
||||
* |
||||
* @see @ref data(), @ref values(), @ref operator[]() |
||||
*/ |
||||
Containers::StridedArrayView<const K> keys() const { |
||||
return _data ? Containers::StridedArrayView<const K>{&_data[0].first, _data.size(), sizeof(std::pair<K, V>)} : nullptr; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Value data |
||||
* |
||||
* @see @ref data(), @ref keys(), @ref operator[]() |
||||
*/ |
||||
Containers::StridedArrayView<const V> values() const { |
||||
return _data ? Containers::StridedArrayView<const V>{&_data[0].second, _data.size(), sizeof(std::pair<K, V>)} : nullptr; |
||||
} |
||||
|
||||
/** @brief Keyframe access */ |
||||
const std::pair<K, V>& operator[](std::size_t i) const { return _data[i]; } |
||||
|
||||
/**
|
||||
* @brief Animated value at a given time |
||||
* |
||||
* Calls @ref interpolate(), see its documentation for more |
||||
* information. Note that this function performs a linear search every |
||||
* time, use @ref at(K, std::size_t&) const to supply a search hint. |
||||
* @see @ref atStrict() |
||||
*/ |
||||
ResultOf<V> at(K frame) const { |
||||
std::size_t hint{}; |
||||
return at(frame, hint); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Animated value at a given time |
||||
* |
||||
* Calls @ref interpolate(), see its documentation for more |
||||
* information. |
||||
* @see @ref at(K) const, @ref atStrict(K, std::size_t&) const |
||||
*/ |
||||
ResultOf<V> at(K frame, std::size_t& hint) const { |
||||
return interpolate(keys(), values(), _before, _after, _interpolator, frame, hint); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Animated value at a given time |
||||
* |
||||
* A faster version of @ref at(K, std::size_t&) const with some |
||||
* restrictions. Calls @ref interpolateStrict(), see its documentation |
||||
* for more information. |
||||
*/ |
||||
ResultOf<V> atStrict(K frame, std::size_t& hint) const { |
||||
return interpolateStrict(keys(), values(), _interpolator, frame, hint); |
||||
} |
||||
|
||||
private: |
||||
Containers::Array<std::pair<K, V>> _data; |
||||
Interpolator _interpolator; |
||||
Extrapolation _before, _after; |
||||
}; |
||||
|
||||
/**
|
||||
@brief Animation track view |
||||
@tparam K Key type |
||||
@tparam V Value 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 { |
||||
public: |
||||
/** @brief Key type */ |
||||
typedef K KeyType; |
||||
|
||||
/** @brief Value type */ |
||||
typedef V ValueType; |
||||
|
||||
/** @brief Animation result type */ |
||||
typedef ResultOf<V> ResultType; |
||||
|
||||
/** @brief Interpolation function */ |
||||
typedef ResultType(*Interpolator)(const ValueType&, const ValueType&, Float); |
||||
|
||||
/**
|
||||
* @brief Constructor |
||||
* @param keys Frame keys |
||||
* @param values Frame values |
||||
* @param interpolator Interpolation function |
||||
* @param before Extrapolation behavior before |
||||
* @param after Extrapolation behavior after |
||||
* |
||||
* The keyframe data are assumed to be stored in sorted order. It's not |
||||
* an error to have two successive keyframes with the same frame value. |
||||
*/ |
||||
constexpr explicit TrackView(const Containers::StridedArrayView<const K>& keys, const Containers::StridedArrayView<const V>& values, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: _keys{keys}, _values{values}, _interpolator{interpolator}, _before{before}, _after{after} {} |
||||
|
||||
/** @overload
|
||||
* 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} {} |
||||
|
||||
/**
|
||||
* @brief Construct from an interleaved array |
||||
* @param data Keyframe data |
||||
* @param interpolator Interpolation function |
||||
* @param before Extrapolation behavior before |
||||
* @param after Extrapolation behavior after |
||||
* |
||||
* Converts @p data to a pair of strided array views and calls |
||||
* @ref TrackView(const Containers::StridedArrayView<const K>&, const Containers::StridedArrayView<const V>&, Interpolator, Extrapolation, Extrapolation). |
||||
*/ |
||||
constexpr explicit TrackView(Containers::ArrayView<const std::pair<K, V>> data, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: _keys{data ? &data[0].first : nullptr, data.size(), sizeof(std::pair<K, V>)}, _values{data ? &data[0].second : nullptr, data.size(), sizeof(std::pair<K, V>)}, _interpolator{interpolator}, _before{before}, _after{after} {} |
||||
|
||||
/** @overload
|
||||
* 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} {} |
||||
|
||||
/**
|
||||
* @brief Extrapolation behavior before first keyframe |
||||
* |
||||
* @see @ref after(), @ref at(), @ref atStrict() |
||||
*/ |
||||
Extrapolation before() const { return _before; } |
||||
|
||||
/**
|
||||
* @brief Extrapolation behavior after last keyframe |
||||
* |
||||
* @see @ref before(), @ref at(), @ref atStrict() |
||||
*/ |
||||
Extrapolation after() const { return _after; } |
||||
|
||||
/** @brief Interpolation function */ |
||||
Interpolator interpolator() const { return _interpolator; } |
||||
|
||||
/**
|
||||
* @brief Key data |
||||
* |
||||
* @see @ref values(), @ref operator[]() |
||||
*/ |
||||
Containers::StridedArrayView<const K> keys() const { return _keys; } |
||||
|
||||
/**
|
||||
* @brief Value data |
||||
* |
||||
* @see @ref keys(), @ref operator[]() |
||||
*/ |
||||
Containers::StridedArrayView<const V> values() const { return _values; } |
||||
|
||||
/** @brief Keyframe access */ |
||||
std::pair<K, V> operator[](std::size_t i) const { |
||||
return {_keys[i], _values[i]}; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Animated value at a given time |
||||
* |
||||
* Calls @ref interpolate(), see its documentation for more |
||||
* information. Note that this function performs a linear search every |
||||
* 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 { |
||||
std::size_t hint{}; |
||||
return at(frame, hint); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Animated value at a given time |
||||
* |
||||
* Calls @ref interpolate(), see its documentation for more |
||||
* information. |
||||
* @see @ref at(K) const, @ref atStrict(K, std::size_t&) const |
||||
*/ |
||||
ResultOf<V> at(K frame, std::size_t& hint) const { |
||||
return interpolate(_keys, _values, _before, _after, _interpolator, frame, hint); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Animated value at a given time |
||||
* |
||||
* A faster version of @ref at(K, std::size_t&) const with some |
||||
* restrictions. Calls @ref interpolateStrict(), see its documentation |
||||
* for more information. |
||||
*/ |
||||
ResultOf<V> atStrict(K frame, std::size_t& hint) const { |
||||
return interpolateStrict(_keys, _values, _interpolator, frame, hint); |
||||
} |
||||
|
||||
private: |
||||
Containers::StridedArrayView<const K> _keys; |
||||
Containers::StridedArrayView<const V> _values; |
||||
Interpolator _interpolator; |
||||
Extrapolation _before, _after; |
||||
}; |
||||
|
||||
}} |
||||
|
||||
#endif |
||||
Loading…
Reference in new issue