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