template<class K, class V, class R = ResultOf<V>>
Magnum::Animation::Track class

Animation track.

Template parameters
K Key type
V Value type
R Result type

Immutable storage of keyframe + value pairs. Usually used in combination with the Player class, but it's possible to use it separately as well.

Basic usage

Animation track is defined by a list of keyframes (time+value pairs), interpolator function and extrapolation behavior.

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

Types and interpolators

The track supports arbitrary types for keys, values and interpolators. See Transformation interpolation for an overview of builtin interpolation functions.

Besides directly specifying an interpolator function as shown in the above snippet, it's also possible to supply a generic interpolation behavior by passing the Interpolation enum to the constructor. In case the interpolator function is not passed in as well, it's autodetected using interpolatorFor(). See its documentation for more information. The Interpolation enum is then stored in interpolation() and acts as a hint for desired interpolation behavior for users who might want to use their own interpolator.

Performance tuning

The snippet shown above is convenience-oriented at a cost of sacrificing some performance. You have the following options:

Keyframe hinting

The Track and TrackView classes are fully stateless and the at(K) const function performs a linear search for matching keyframe from the beginning every time. You can use at(K, std::size_t&) const to remember last used keyframe index and pass it in the next iteration as a hint:

std::size_t hint = 0;
Vector2 position = jump.at(2.2f, hint);         // y = 0.775, hint = 2

Strict interpolation

While it's possible to have different 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 atStrict() has implicit 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 at():

std::size_t hint = 0;
Vector2 position = jump.atStrict(2.2f, hint);   // y = 0.775, hint = 2

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 Corrade::Containers::StridedArrayView to multiple TrackView instead of having data duplicated scattered across disjoint allocations of Track instances:

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<const Float, const Vector2> positions{
    {data, &data[0].time, Containers::arraySize(data), sizeof(Keyframe)},
    {data, &data[0].position, Containers::arraySize(data), sizeof(Keyframe)},
    Math::lerp};
Animation::TrackView<const Float, const Deg> rotations{
    {data, &data[0].time, Containers::arraySize(data), sizeof(Keyframe)},
    {data, &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°

Interpolator function choice

The interpolator function has a direct effect on animation performance. You can choose a less complex interpolator (constant instead of linear or linear instead of spheric linear, for example) either during construction or passing it directly to at() / atStrict(). The interpolator() can act as a hint on what kind of function should be chosen. Depending on how the track was constructed, passing the interpolator directly to at() / atStrict() usually also results in it being inlined by the compiler and thus faster than an indirect function call.

Note that when constructing the track by just passing Interpolator to the constructor, the function is chosen by interpolatorFor(), which favors correctness over performance. See its documentation for more information.

Public types

using KeyType = K
Key type.
using ValueType = V
Value type.
using ResultType = R
Animation result type.
using Interpolator = ResultType(*)(const ValueType&, const ValueType&, Float)
Interpolation function.

Constructors, destructors, conversion operators

Track() explicit noexcept
Construct an empty track.
Track(Containers::Array<std::pair<K, V>>&& data, Interpolator interpolator, Extrapolation before, Extrapolation after) explicit noexcept
Construct with custom interpolator.
Track(std::initializer_list<std::pair<K, V>> data, Interpolator interpolator, Extrapolation before, Extrapolation after) explicit
Track(Containers::Array<std::pair<K, V>>&& data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) explicit noexcept
Track(std::initializer_list<std::pair<K, V>> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) explicit
Track(Containers::Array<std::pair<K, V>>&& data, Interpolation interpolation, Interpolator interpolator, Extrapolation before, Extrapolation after) explicit noexcept
Construct with both generic and custom interpolator.
Track(std::initializer_list<std::pair<K, V>> data, Interpolation interpolation, Interpolator interpolator, Extrapolation before, Extrapolation after) explicit
Track(Containers::Array<std::pair<K, V>>&& data, Interpolation interpolation, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) explicit noexcept
Track(std::initializer_list<std::pair<K, V>> data, Interpolation interpolation, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) explicit
Track(Containers::Array<std::pair<K, V>>&& data, Interpolation interpolation, Extrapolation before, Extrapolation after) explicit noexcept
Construct with generic interpolation behavior.
Track(std::initializer_list<std::pair<K, V>> data, Interpolation interpolation, Extrapolation before, Extrapolation after) explicit
Track(Containers::Array<std::pair<K, V>>&& data, Interpolation interpolation, Extrapolation extrapolation = Extrapolation::Constant) explicit noexcept
Track(std::initializer_list<std::pair<K, V>> data, Interpolation interpolation, Extrapolation extrapolation = Extrapolation::Constant) explicit
Track(const Track<K, V, R>&) deleted
Copying is not allowed.
Track(Track<K, V, R>&&) defaulted noexcept
Move constructor.
operator TrackView<const K, const V, R>() const noexcept
Conversion to a view.
operator TrackView<K, V, R>() noexcept

Public functions

auto operator=(const Track<K, V, R>&) -> Track<K, V, R>& deleted
Copying is not allowed.
auto operator=(Track<K, V, R>&&) -> Track<K, V, R>& defaulted noexcept
Move constructor.
auto interpolation() const -> Interpolation
Interpolation behavior.
auto interpolator() const -> Interpolator
Interpolation function.
auto before() const -> Extrapolation
Extrapolation behavior before first keyframe.
auto after() const -> Extrapolation
Extrapolation behavior after last keyframe.
auto duration() const -> Math::Range1D<K>
Duration of the track.
auto size() const -> std::size_t
Keyframe count.
auto data() const -> Containers::ArrayView<const std::pair<K, V>>
Keyframe data.
auto data() -> Containers::ArrayView<std::pair<K, V>>
auto keys() const -> Containers::StridedArrayView1D<const K>
Key data.
auto keys() -> Containers::StridedArrayView1D<K>
auto values() const -> Containers::StridedArrayView1D<const V>
Value data.
auto values() -> Containers::StridedArrayView1D<V>
auto operator[](std::size_t i) const -> const std::pair<K, V>&
Keyframe access.
auto operator[](std::size_t i) -> std::pair<K, V>&
auto at(K frame) const -> R
Animated value at a given time.
auto at(K frame, std::size_t& hint) const -> R
Animated value at a given time.
auto at(Interpolator interpolator, K frame) const -> R
Animated value at a given time.
auto at(Interpolator interpolator, K frame, std::size_t& hint) const -> R
Animated value at a given time.
auto atStrict(K frame, std::size_t& hint) const -> R
Animated value at a given time.
auto atStrict(Interpolator interpolator, K frame, std::size_t& hint) const -> R
Animated value at a given time.

Function documentation

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track() explicit noexcept

Construct an empty track.

The data(), keys(), values() and interpolator() functions return nullptr, at() always returns a default-constructed value.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(Containers::Array<std::pair<K, V>>&& data, Interpolator interpolator, Extrapolation before, Extrapolation after) explicit noexcept

Construct with custom interpolator.

Parameters
data Keyframe data
interpolator Interpolator function
before Extrapolation behavior
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. The interpolation() field is set to Interpolation::Custom. See Track(Containers::Array<std::pair<K, V>>&&, Interpolation, Interpolator, Extrapolation, Extrapolation) or Track(Containers::Array<std::pair<K, V>>&&, Interpolation, Extrapolation, Extrapolation) for an alternative.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(std::initializer_list<std::pair<K, V>> data, Interpolator interpolator, Extrapolation before, Extrapolation after) explicit

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(Containers::Array<std::pair<K, V>>&& data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) explicit noexcept

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. Equivalent to calling Track(Containers::Array<std::pair<K, V>>&&, Interpolator, Extrapolation, Extrapolation) with both before and after set to extrapolation.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(std::initializer_list<std::pair<K, V>> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) explicit

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(Containers::Array<std::pair<K, V>>&& data, Interpolation interpolation, Interpolator interpolator, Extrapolation before, Extrapolation after) explicit noexcept

Construct with both generic and custom interpolator.

Parameters
data Keyframe data
interpolation Interpolation behavior
interpolator Interpolator function
before Extrapolation behavior
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. interpolation acts as a behavior hint to users that might want to supply their own interpolator function to at() or atStrict().

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(std::initializer_list<std::pair<K, V>> data, Interpolation interpolation, Interpolator interpolator, Extrapolation before, Extrapolation after) explicit

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(Containers::Array<std::pair<K, V>>&& data, Interpolation interpolation, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) explicit noexcept

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. Equivalent to calling Track(Containers::Array<std::pair<K, V>>&&, Interpolation, Interpolator, Extrapolation, Extrapolation) with both before and after set to extrapolation.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(std::initializer_list<std::pair<K, V>> data, Interpolation interpolation, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) explicit

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(Containers::Array<std::pair<K, V>>&& data, Interpolation interpolation, Extrapolation before, Extrapolation after) explicit noexcept

Construct with generic interpolation behavior.

Parameters
data Keyframe data
interpolation Interpolation behavior
before Extrapolation behavior
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. The interpolator() function is autodetected from interpolation using interpolatorFor(). See its documentation for more information.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(std::initializer_list<std::pair<K, V>> data, Interpolation interpolation, Extrapolation before, Extrapolation after) explicit

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(Containers::Array<std::pair<K, V>>&& data, Interpolation interpolation, Extrapolation extrapolation = Extrapolation::Constant) explicit noexcept

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts. Equivalent to calling Track(Containers::Array<std::pair<K, V>>&&, Interpolation, Extrapolation, Extrapolation) with both before and after set to extrapolation.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::Track(std::initializer_list<std::pair<K, V>> data, Interpolation interpolation, Extrapolation extrapolation = Extrapolation::Constant) explicit

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
Magnum::Animation::Track<K, V, R>::operator TrackView<K, V, R>() noexcept

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
Interpolation Magnum::Animation::Track<K, V, R>::interpolation() const

Interpolation behavior.

Acts as a behavior hint to users that might want to supply their own interpolator function to at() or atStrict().

template<class K, class V, class R>
Interpolator Magnum::Animation::Track<K, V, R>::interpolator() const

Interpolation function.

template<class K, class V, class R>
Extrapolation Magnum::Animation::Track<K, V, R>::before() const

Extrapolation behavior before first keyframe.

template<class K, class V, class R>
Extrapolation Magnum::Animation::Track<K, V, R>::after() const

Extrapolation behavior after last keyframe.

template<class K, class V, class R>
Math::Range1D<K> Magnum::Animation::Track<K, V, R>::duration() const

Duration of the track.

Calculated from first and last keyframe. If there are no keyframes, a default-constructed value is returned. Use Math::join() to calculate combined duration for a set of tracks.

template<class K, class V, class R>
Containers::ArrayView<const std::pair<K, V>> Magnum::Animation::Track<K, V, R>::data() const

Keyframe data.

template<class K, class V, class R>
Containers::ArrayView<std::pair<K, V>> Magnum::Animation::Track<K, V, R>::data()

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
Containers::StridedArrayView1D<const K> Magnum::Animation::Track<K, V, R>::keys() const

Key data.

template<class K, class V, class R>
Containers::StridedArrayView1D<K> Magnum::Animation::Track<K, V, R>::keys()

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
Containers::StridedArrayView1D<const V> Magnum::Animation::Track<K, V, R>::values() const

Value data.

template<class K, class V, class R>
Containers::StridedArrayView1D<V> Magnum::Animation::Track<K, V, R>::values()

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
const std::pair<K, V>& Magnum::Animation::Track<K, V, R>::operator[](std::size_t i) const

Keyframe access.

template<class K, class V, class R>
std::pair<K, V>& Magnum::Animation::Track<K, V, R>::operator[](std::size_t i)

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

template<class K, class V, class R>
R Magnum::Animation::Track<K, V, R>::at(K frame) const

Animated value at a given time.

Calls interpolate(), see its documentation for more information. Note that this function performs a linear search every time, use at(K, std::size_t&) const to supply a search hint.

template<class K, class V, class R>
R Magnum::Animation::Track<K, V, R>::at(K frame, std::size_t& hint) const

Animated value at a given time.

Calls interpolate(), see its documentation for more information.

template<class K, class V, class R>
R Magnum::Animation::Track<K, V, R>::at(Interpolator interpolator, K frame) const

Animated value at a given time.

Unlike at(K) const calls interpolate() with interpolator, overriding the interpolator function set in constructor. See its documentation for more information.

template<class K, class V, class R>
R Magnum::Animation::Track<K, V, R>::at(Interpolator interpolator, K frame, std::size_t& hint) const

Animated value at a given time.

Unlike at(K, std::size_t&) const calls interpolate() with interpolator, overriding the interpolator function set in constructor. See its documentation for more information.

template<class K, class V, class R>
R Magnum::Animation::Track<K, V, R>::atStrict(K frame, std::size_t& hint) const

Animated value at a given time.

A faster version of at(K, std::size_t&) const with some restrictions. Calls interpolateStrict(), see its documentation for more information.

template<class K, class V, class R>
R Magnum::Animation::Track<K, V, R>::atStrict(Interpolator interpolator, K frame, std::size_t& hint) const

Animated value at a given time.

Unlike atStrict(K, std::size_t&) const calls interpolate() with interpolator, overriding the interpolator function set in constructor. See its documentation for more information.