Browse Source

Animation: allow mutable access to data referenced by TrackView.

This is a breaking change, sorry.
pull/381/merge
Vladimír Vondruš 7 years ago
parent
commit
954798a9ba
  1. 7
      doc/changelog.dox
  2. 8
      doc/snippets/MagnumAnimation.cpp
  3. 7
      src/Magnum/Animation/Interpolation.h
  4. 113
      src/Magnum/Animation/Player.h
  5. 10
      src/Magnum/Animation/Player.hpp
  6. 14
      src/Magnum/Animation/Test/Benchmark.cpp
  7. 94
      src/Magnum/Animation/Test/PlayerTest.cpp
  8. 55
      src/Magnum/Animation/Test/TrackTest.cpp
  9. 280
      src/Magnum/Animation/Test/TrackViewTest.cpp
  10. 112
      src/Magnum/Animation/Track.h

7
doc/changelog.dox

@ -105,6 +105,13 @@ See also:
deprecated in favor of the new @ref Platform::Sdl2Application::setCursor()
together with @ref Platform::Sdl2Application::Cursor::HiddenLocked
@subsection changelog-latest-compatibility Potential compatibility breakages, removed APIs
- @ref Animation::TrackView "TrackView" in the still-experimental
@ref Animation library was changed to allow mutable access to the keys &
values it references. Existing code needs to be changed to say
@cpp TrackView<const K, const V> @ce instead of @cpp TrackView<K, V> @ce.
@section changelog-2019-10 2019.10
Released 2019-10-24, tagged as

8
doc/snippets/MagnumAnimation.cpp

@ -276,9 +276,9 @@ auto callback = [](std::vector<Int>& data, Int value) {
Animation::Player<Float> player;
player.addRawCallback(track,
[](const Animation::TrackViewStorage<Float>& track, Float key,
[](const Animation::TrackViewStorage<const Float>& track, Float key,
std::size_t& hint, void* destination, void(*callback)(), void* userData) {
Int value = static_cast<const Animation::TrackView<Float, Int>&>(track)
Int value = static_cast<const Animation::TrackView<const Float, const Int>&>(track)
.atStrict(key, hint);
if(value == *static_cast<Int*>(destination)) return;
*static_cast<Int*>(destination) = value;
@ -341,11 +341,11 @@ const Keyframe data[]{
{6.0f, Vector2::yAxis(0.0f), 180.0_degf}
};
Animation::TrackView<Float, Vector2> positions{
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<Float, Deg> rotations{
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};

7
src/Magnum/Animation/Interpolation.h

@ -293,11 +293,14 @@ namespace Implementation {
/* Generic types where result type is the same as value type */
template<class V> struct ResultTraits {
typedef V Type;
typedef typename std::remove_const<V>::type Type;
};
template<class T> struct ResultTraits<Math::CubicHermite<T>> {
typedef T Type;
};
template<class T> struct ResultTraits<const Math::CubicHermite<T>> {
typedef T Type;
};
template<class V> struct TypeTraits<V, V> {
typedef V(*Interpolator)(const V&, const V&, Float);
@ -365,7 +368,7 @@ template<class T> struct MAGNUM_EXPORT TypeTraits<Math::CubicHermite<T>, T> {
/* Needs to be defined later so it can pick up the TypeTraits definitions */
template<class V, class R> auto interpolatorFor(Interpolation interpolation) -> R(*)(const V&, const V&, Float) {
return Implementation::TypeTraits<V, R>::interpolator(interpolation);
return Implementation::TypeTraits<typename std::remove_const<V>::type, R>::interpolator(interpolation);
}
template<class K, class V, class R> R interpolate(const Containers::StridedArrayView1D<const K>& keys, const Containers::StridedArrayView1D<const V>& values, const Extrapolation before, const Extrapolation after, R(*const interpolator)(const V&, const V&, Float), K frame, std::size_t& hint) {

113
src/Magnum/Animation/Player.h

@ -370,7 +370,7 @@ template<class T, class K
* Due to the type-erased nature of the player implementation, it's not
* possible to know the exact track type.
*/
const TrackViewStorage<K>& track(std::size_t i) const;
const TrackViewStorage<const K>& track(std::size_t i) const;
/**
* @brief Add a track with a result destination
@ -378,7 +378,12 @@ template<class T, class K
* The @p destination is updated with new value after each call to
* @ref advance() as long as the animation is playing.
*/
template<class V, class R> Player<T, K>& add(const TrackView<K, V, R>& track, R& destination);
template<class V, class R> Player<T, K>& add(const TrackView<const K, const V, R>& track, R& destination);
/** @overload */
template<class V, class R> Player<T, K>& add(const TrackView<K, V, R>& track, R& destination) {
return add(reinterpret_cast<const TrackView<const K, const V, R>&>(track), destination);
}
/** @overload
*
@ -388,7 +393,7 @@ template<class T, class K
*/
#ifndef CORRADE_MSVC2019_COMPATIBILITY
template<class V, class R> Player<T, K>& add(const Track<K, V, R>& track, R& destination) {
return add(TrackView<K, V, R>{track}, destination);
return add(TrackView<const K, const V, R>{track}, destination);
}
#else
/* MSVC 2015 and 2017 is clueless when it comes to trying to deduce the
@ -405,7 +410,7 @@ template<class T, class K
Intellisense freezing like hell and adding this overload fixes the
freezes. Three birds with one stone. */
template<class Track, class R> Player<T, K>& add(const Track& track, R& destination) {
return add<typename Track::ValueType, R>(static_cast<const TrackView<K, typename Track::ValueType, R>&>(track), destination);
return add<typename Track::ValueType, R>(static_cast<const TrackView<const K, const typename Track::ValueType, R>&>(track), destination);
}
#endif
@ -423,6 +428,9 @@ template<class T, class K
* @see @ref addRawCallback()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class V, class R> Player<T, K>& addWithCallback(const TrackView<const K, const V, R>& track, void(*callback)(K, const R&, void*), void* userData = nullptr);
/** @overload */
template<class V, class R> Player<T, K>& addWithCallback(const TrackView<K, V, R>& track, void(*callback)(K, const R&, void*), void* userData = nullptr);
#else
/* Otherwise the user would be forced to use the + operator to convert
@ -430,7 +438,10 @@ template<class T, class K
annoying) it's also not portable because it doesn't work on MSVC
2015 and older versions of MSVC 2017. OTOH, putting this in the docs
would say nothing about how the callback signature should look. */
template<class V, class R, class Callback> Player<T, K>& addWithCallback(const TrackView<K, V, R>& track, Callback callback, void* userData = nullptr);
template<class V, class R, class Callback> Player<T, K>& addWithCallback(const TrackView<const K, const V, R>& track, Callback callback, void* userData = nullptr);
template<class V, class R, class Callback> Player<T, K>& addWithCallback(const TrackView<K, V, R>& track, Callback callback, void* userData = nullptr) {
return addWithCallback(reinterpret_cast<const TrackView<const K, const V, R>&>(track), callback, userData);
}
#endif
/** @overload
@ -443,11 +454,11 @@ template<class T, class K
template<class V, class R> Player<T, K>& addWithCallback(const Track<K, V, R>& track, void(*callback)(K, const R&, void*), void* userData = nullptr);
#elif !defined(CORRADE_MSVC2019_COMPATIBILITY) /* See above why */
template<class V, class R, class Callback> Player<T, K>& addWithCallback(const Track<K, V, R>& track, Callback callback, void* userData = nullptr) {
return addWithCallback(TrackView<K, V, R>{track}, callback, userData);
return addWithCallback(TrackView<const K, const V, R>{track}, callback, userData);
}
#else /* see the add() function for explanation */
template<class Track, class Callback> Player<T, K>& addWithCallback(const Track& track, Callback callback, void* userData = nullptr) {
return addWithCallback<typename Track::ValueType, typename Track::ResultType, Callback>(static_cast<const TrackView<K, typename Track::ValueType, typename Track::ResultType>&>(track), callback, userData);
return addWithCallback<typename Track::ValueType, typename Track::ResultType, Callback>(static_cast<const TrackView<const K, const typename Track::ValueType, typename Track::ResultType>&>(track), callback, userData);
}
#endif
@ -461,9 +472,15 @@ template<class T, class K
* @ref addRawCallback() for optimization possibilities.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class V, class R, class U> Player<T, K>& addWithCallback(const TrackView<const K, const V, R>& track, void(*callback)(K, const R&, U&), U& userData);
/** @overload */
template<class V, class R, class U> Player<T, K>& addWithCallback(const TrackView<K, V, R>& track, void(*callback)(K, const R&, U&), U& userData);
#else /* See above why */
template<class V, class R, class U, class Callback> Player<T, K>& addWithCallback(const TrackView<K, V, R>& track, Callback callback, U& userData);
template<class V, class R, class U, class Callback> Player<T, K>& addWithCallback(const TrackView<const K, const V, R>& track, Callback callback, U& userData);
template<class V, class R, class U, class Callback> Player<T, K>& addWithCallback(const TrackView<K, V, R>& track, Callback callback, U& userData) {
return addWithCallback(reinterpret_cast<const TrackView<const K, const V, R>&>(track), callback, userData);
}
#endif
/** @overload
@ -476,11 +493,11 @@ template<class T, class K
template<class V, class R, class U> Player<T, K>& addWithCallback(const Track<K, V, R>& track, void(*callback)(K, const R&, U&), U& userData);
#elif !defined(CORRADE_MSVC2019_COMPATIBILITY) /* See above why */
template<class V, class R, class U, class Callback> Player<T, K>& addWithCallback(const Track<K, V, R>& track, Callback callback, U& userData) {
return addWithCallback(TrackView<K, V, R>{track}, callback, userData);
return addWithCallback(TrackView<const K, const V, R>{track}, callback, userData);
}
#else /* see the add() function for explanation */
template<class Track, class U, class Callback> Player<T, K>& addWithCallback(const Track& track, Callback callback, U& userData) {
return addWithCallback<typename Track::ValueType, typename Track::ResultType, U, Callback>(static_cast<const TrackView<K, typename Track::ValueType, typename Track::ResultType>&>(track), callback, userData);
return addWithCallback<typename Track::ValueType, typename Track::ResultType, U, Callback>(static_cast<const TrackView<const K, const typename Track::ValueType, typename Track::ResultType>&>(track), callback, userData);
}
#endif
@ -500,9 +517,15 @@ template<class T, class K
* @see @ref addRawCallback()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class V, class R> Player<T, K>& addWithCallbackOnChange(const TrackView<const K, const V, R>& track, void(*callback)(K, const R&, void*), R& destination, void* userData = nullptr);
/** @overload */
template<class V, class R> Player<T, K>& addWithCallbackOnChange(const TrackView<K, V, R>& track, void(*callback)(K, const R&, void*), R& destination, void* userData = nullptr);
#else /* See above why */
template<class V, class R, class Callback> Player<T, K>& addWithCallbackOnChange(const TrackView<K, V, R>& track, Callback callback, R& destination, void* userData = nullptr);
template<class V, class R, class Callback> Player<T, K>& addWithCallbackOnChange(const TrackView<const K, const V, R>& track, Callback callback, R& destination, void* userData = nullptr);
template<class V, class R, class Callback> Player<T, K>& addWithCallbackOnChange(const TrackView<K, V, R>& track, Callback callback, R& destination, void* userData = nullptr) {
return addWithCallbackOnChange(reinterpret_cast<const TrackView<const K, const V, R>&>(track), callback, destination, userData);
}
#endif
/** @overload
@ -515,11 +538,11 @@ template<class T, class K
template<class V, class R> Player<T, K>& addWithCallbackOnChange(const Track<K, V, R>& track, void(*callback)(K, const R&, void*), R& destination, void* userData = nullptr);
#elif !defined(CORRADE_MSVC2019_COMPATIBILITY) /* See above why */
template<class V, class R, class Callback> Player<T, K>& addWithCallbackOnChange(const Track<K, V, R>& track, Callback callback, R& destination, void* userData = nullptr) {
return addWithCallbackOnChange(TrackView<K, V, R>{track}, callback, destination, userData);
return addWithCallbackOnChange(TrackView<const K, const V, R>{track}, callback, destination, userData);
}
#else /* see the add() function for explanation */
template<class Track, class R, class Callback> Player<T, K>& addWithCallbackOnChange(const Track& track, Callback callback, R& destination, void* userData = nullptr) {
return addWithCallbackOnChange<typename Track::ValueType, R, Callback>(static_cast<const TrackView<K, typename Track::ValueType, R>&>(track), callback, destination, userData);
return addWithCallbackOnChange<typename Track::ValueType, R, Callback>(static_cast<const TrackView<const K, const typename Track::ValueType, R>&>(track), callback, destination, userData);
}
#endif
@ -533,9 +556,15 @@ template<class T, class K
* @ref addRawCallback() for optimization possibilities.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class V, class R, class U> Player<T, K>& addWithCallbackOnChange(const TrackView<const K, const V, R>& track, void(*callback)(K, const R&, void*), R& destination, U& userData);
/** @overload */
template<class V, class R, class U> Player<T, K>& addWithCallbackOnChange(const TrackView<K, V, R>& track, void(*callback)(K, const R&, void*), R& destination, U& userData);
#else /* See above why */
template<class V, class R, class U, class Callback> Player<T, K>& addWithCallbackOnChange(const TrackView<K, V, R>& track, Callback callback, R& destination, U& userData);
template<class V, class R, class U, class Callback> Player<T, K>& addWithCallbackOnChange(const TrackView<const K, const V, R>& track, Callback callback, R& destination, U& userData);
template<class V, class R, class U, class Callback> Player<T, K>& addWithCallbackOnChange(const TrackView<K, V, R>& track, Callback callback, R& destination, U& userData) {
return addWithCallbackOnChange(reinterpret_cast<const TrackView<const K, const V, R>&>(track), callback, destination, userData);
}
#endif
/** @overload
@ -548,11 +577,11 @@ template<class T, class K
template<class V, class R, class U> Player<T, K>& addWithCallbackOnChange(const Track<K, V, R>& track, void(*callback)(K, const R&, void*), R& destination, U& userData);
#elif !defined(CORRADE_MSVC2019_COMPATIBILITY) /* See above why */
template<class V, class R, class U, class Callback> Player<T, K>& addWithCallbackOnChange(const Track<K, V, R>& track, Callback callback, R& destination, U& userData) {
return addWithCallbackOnChange(TrackView<K, V, R>{track}, callback, destination, userData);
return addWithCallbackOnChange(TrackView<const K, const V, R>{track}, callback, destination, userData);
}
#else /* see the add() function for explanation */
template<class Track, class R, class U, class Callback> Player<T, K>& addWithCallbackOnChange(const Track& track, Callback callback, R& destination, U& userData) {
return addWithCallbackOnChange<typename Track::ValueType, R, U, Callback>(static_cast<const TrackView<K, typename Track::ValueType, R>&>(track), callback, destination, userData);
return addWithCallbackOnChange<typename Track::ValueType, R, U, Callback>(static_cast<const TrackView<const K, const typename Track::ValueType, R>&>(track), callback, destination, userData);
}
#endif
@ -579,9 +608,15 @@ template<class T, class K
* @snippet MagnumAnimation.cpp Player-addRawCallback
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class V, class R, class Callback> Player<T, K>& addRawCallback(const TrackView<K, V, R>& track, void(*callback)(const TrackViewStorage<K>&, K, std::size_t&, void*, void(*)(), void*), void* destination, void(*userCallback)(), void* userData);
template<class V, class R, class Callback> Player<T, K>& addRawCallback(const TrackView<const K, const V, R>& track, void(*callback)(const TrackViewStorage<const K>&, K, std::size_t&, void*, void(*)(), void*), void* destination, void(*userCallback)(), void* userData);
/** @overload */
template<class V, class R, class Callback> Player<T, K>& addRawCallback(const TrackView<K, V, R>& track, void(*callback)(const TrackViewStorage<const K>&, K, std::size_t&, void*, void(*)(), void*), void* destination, void(*userCallback)(), void* userData);
#else
template<class V, class R, class Callback> Player<T, K>& addRawCallback(const TrackView<K, V, R>& track, Callback callback, void* destination, void(*userCallback)(), void* userData);
template<class V, class R, class Callback> Player<T, K>& addRawCallback(const TrackView<const K, const V, R>& track, Callback callback, void* destination, void(*userCallback)(), void* userData);
template<class V, class R, class Callback> Player<T, K>& addRawCallback(const TrackView<K, V, R>& track, Callback callback, void* destination, void(*userCallback)(), void* userData) {
return addRawCallback(reinterpret_cast<const TrackView<const K, const V, R>&>(track), callback, destination, userCallback, userData);
}
#endif
/** @overload
@ -591,14 +626,14 @@ template<class T, class K
* whole lifetime of the @ref Player instance.
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class V, class R> Player<T, K>& addRawCallback(const Track<K, V, R>& track, void(*callback)(const TrackViewStorage<K>&, K, std::size_t&, void*, void(*)(), void*), void* destination, void(*userCallback)(), void* userData);
template<class V, class R> Player<T, K>& addRawCallback(const Track<K, V, R>& track, void(*callback)(const TrackViewStorage<const K>&, K, std::size_t&, void*, void(*)(), void*), void* destination, void(*userCallback)(), void* userData);
#elif !defined(CORRADE_MSVC2019_COMPATIBILITY) /* See above why */
template<class V, class R, class Callback> Player<T, K>& addRawCallback(const Track<K, V, R>& track, Callback callback, void* destination, void(*userCallback)(), void* userData) {
return addRawCallback(TrackView<K, V, R>{track}, callback, destination, userCallback, userData);
return addRawCallback(TrackView<const K, const V, R>{track}, callback, destination, userCallback, userData);
}
#else /* see the add() function for explanation */
template<class Track, class Callback> Player<T, K>& addRawCallback(const Track& track, Callback callback, void* destination, void(*userCallback)(), void* userData) {
return addRawCallback<typename Track::ValueType, typename Track::ResultType, Callback>(static_cast<const TrackView<K, typename Track::ValueType, typename Track::ResultType>&>(track), callback, destination, userCallback, userData);
return addRawCallback<typename Track::ValueType, typename Track::ResultType, Callback>(static_cast<const TrackView<const K, const typename Track::ValueType, typename Track::ResultType>&>(track), callback, destination, userCallback, userData);
}
#endif
@ -773,7 +808,7 @@ template<class T, class K
private:
struct Track;
Player<T, K>& addInternal(const TrackViewStorage<K>& track, void (*advancer)(const TrackViewStorage<K>&, K, std::size_t&, void*, void(*)(), void*), void* destination, void(*userCallback)(), void* userCallbackData);
Player<T, K>& addInternal(const TrackViewStorage<const K>& track, void (*advancer)(const TrackViewStorage<const K>&, K, std::size_t&, void*, void(*)(), void*), void* destination, void(*userCallback)(), void* userCallbackData);
Containers::Optional<std::pair<UnsignedInt, K>> elapsedInternal(T time, T& updatedStartTime, T& updatedPauseTime, State& updatedState) const;
@ -785,58 +820,58 @@ template<class T, class K
Scaler _scaler;
};
template<class T, class K> template<class V, class R> Player<T, K>& Player<T, K>::add(const TrackView<K, V, R>& track, R& destination) {
template<class T, class K> template<class V, class R> Player<T, K>& Player<T, K>::add(const TrackView<const K, const V, R>& track, R& destination) {
return addInternal(track,
[](const TrackViewStorage<K>& track, K key, std::size_t& hint, void* destination, void(*)(), void*) {
*static_cast<R*>(destination) = static_cast<const TrackView<K, V, R>&>(track).at(key, hint);
[](const TrackViewStorage<const K>& track, K key, std::size_t& hint, void* destination, void(*)(), void*) {
*static_cast<R*>(destination) = static_cast<const TrackView<const K, const V, R>&>(track).at(key, hint);
}, &destination, nullptr, nullptr);
}
#ifndef DOXYGEN_GENERATING_OUTPUT
template<class T, class K> template<class V, class R, class Callback> Player<T, K>& Player<T, K>::addWithCallback(const TrackView<K, V, R>& track, Callback callback, void* userData) {
template<class T, class K> template<class V, class R, class Callback> Player<T, K>& Player<T, K>::addWithCallback(const TrackView<const K, const V, R>& track, Callback callback, void* userData) {
auto callbackPtr = static_cast<void(*)(K, const R&, void*)>(callback);
return addInternal(track,
[](const TrackViewStorage<K>& track, K key, std::size_t& hint, void*, void(*callback)(), void* userData) {
[](const TrackViewStorage<const K>& track, K key, std::size_t& hint, void*, void(*callback)(), void* userData) {
/** @todo try to use atStrict() if possible */
reinterpret_cast<void(*)(K, const R&, void*)>(callback)(key, static_cast<const TrackView<K, V, R>&>(track).at(key, hint), userData);
reinterpret_cast<void(*)(K, const R&, void*)>(callback)(key, static_cast<const TrackView<const K, const V, R>&>(track).at(key, hint), userData);
}, nullptr, reinterpret_cast<void(*)()>(callbackPtr), userData);
}
template<class T, class K> template<class V, class R, class U, class Callback> Player<T, K>& Player<T, K>::addWithCallback(const TrackView<K, V, R>& track, Callback callback, U& userData) {
template<class T, class K> template<class V, class R, class U, class Callback> Player<T, K>& Player<T, K>::addWithCallback(const TrackView<const K, const V, R>& track, Callback callback, U& userData) {
auto callbackPtr = static_cast<void(*)(K, const R&, U&)>(callback);
return addInternal(track,
[](const TrackViewStorage<K>& track, K key, std::size_t& hint, void*, void(*callback)(), void* userData) {
[](const TrackViewStorage<const K>& track, K key, std::size_t& hint, void*, void(*callback)(), void* userData) {
/** @todo try to use atStrict() if possible */
reinterpret_cast<void(*)(K, const R&, U&)>(callback)(key, static_cast<const TrackView<K, V, R>&>(track).at(key, hint), *static_cast<U*>(userData));
reinterpret_cast<void(*)(K, const R&, U&)>(callback)(key, static_cast<const TrackView<const K, const V, R>&>(track).at(key, hint), *static_cast<U*>(userData));
}, nullptr, reinterpret_cast<void(*)()>(callbackPtr), &userData);
}
template<class T, class K> template<class V, class R, class Callback> Player<T, K>& Player<T, K>::addWithCallbackOnChange(const TrackView<K, V, R>& track, Callback callback, R& destination, void* userData) {
template<class T, class K> template<class V, class R, class Callback> Player<T, K>& Player<T, K>::addWithCallbackOnChange(const TrackView<const K, const V, R>& track, Callback callback, R& destination, void* userData) {
auto callbackPtr = static_cast<void(*)(K, const R&, void*)>(callback);
return addInternal(track,
[](const TrackViewStorage<K>& track, K key, std::size_t& hint, void* destination, void(*callback)(), void* userData) {
[](const TrackViewStorage<const K>& track, K key, std::size_t& hint, void* destination, void(*callback)(), void* userData) {
/** @todo try to use atStrict() if possible */
R result = static_cast<const TrackView<K, V, R>&>(track).at(key, hint);
R result = static_cast<const TrackView<const K, const V, R>&>(track).at(key, hint);
if(result == *static_cast<R*>(destination)) return;
reinterpret_cast<void(*)(K, const R&, void*)>(callback)(key, result, userData);
*static_cast<R*>(destination) = result;
}, &destination, reinterpret_cast<void(*)()>(callbackPtr), userData);
}
template<class T, class K> template<class V, class R, class U, class Callback> Player<T, K>& Player<T, K>::addWithCallbackOnChange(const TrackView<K, V, R>& track, Callback callback, R& destination, U& userData) {
template<class T, class K> template<class V, class R, class U, class Callback> Player<T, K>& Player<T, K>::addWithCallbackOnChange(const TrackView<const K, const V, R>& track, Callback callback, R& destination, U& userData) {
auto callbackPtr = static_cast<void(*)(K, const R&, U&)>(callback);
return addInternal(track,
[](const TrackViewStorage<K>& track, K key, std::size_t& hint, void* destination, void(*callback)(), void* userData) {
[](const TrackViewStorage<const K>& track, K key, std::size_t& hint, void* destination, void(*callback)(), void* userData) {
/** @todo try to use atStrict() if possible */
R result = static_cast<const TrackView<K, V, R>&>(track).at(key, hint);
R result = static_cast<const TrackView<const K, const V, R>&>(track).at(key, hint);
if(result == *static_cast<R*>(destination)) return;
reinterpret_cast<void(*)(K, const R&, U&)>(callback)(key, result, *static_cast<U*>(userData));
*static_cast<R*>(destination) = result;
}, &destination, reinterpret_cast<void(*)()>(callbackPtr), &userData);
}
template<class T, class K> template<class V, class R, class Callback> Player<T, K>& Player<T, K>::addRawCallback(const TrackView<K, V, R>& track, Callback callback, void* destination, void(*userCallback)(), void* userData) {
auto callbackPtr = static_cast<void(*)(const TrackViewStorage<K>&, K, std::size_t&, void*, void(*)(), void*)>(callback);
template<class T, class K> template<class V, class R, class Callback> Player<T, K>& Player<T, K>::addRawCallback(const TrackView<const K, const V, R>& track, Callback callback, void* destination, void(*userCallback)(), void* userData) {
auto callbackPtr = static_cast<void(*)(const TrackViewStorage<const K>&, K, std::size_t&, void*, void(*)(), void*)>(callback);
return addInternal(track, callbackPtr, destination, userCallback, userData);
}
#endif

10
src/Magnum/Animation/Player.hpp

@ -60,10 +60,10 @@ namespace Implementation {
template<class T, class K> struct Player<T, K>::Track {
/* Not sure why is this still needed for emplace_back(). It's 2018,
COME ON ¯\_()_/¯ */
/*implicit*/ Track(const TrackViewStorage<K>& track, void (*advancer)(const TrackViewStorage<K>&, K, std::size_t&, void*, void(*)(), void*), void* destination, void(*userCallback)(), void* userCallbackData, std::size_t hint) noexcept: track{track}, advancer{advancer}, destination{destination}, userCallback{userCallback}, userCallbackData{userCallbackData}, hint{hint} {}
/*implicit*/ Track(const TrackViewStorage<const K>& track, void (*advancer)(const TrackViewStorage<const K>&, K, std::size_t&, void*, void(*)(), void*), void* destination, void(*userCallback)(), void* userCallbackData, std::size_t hint) noexcept: track{track}, advancer{advancer}, destination{destination}, userCallback{userCallback}, userCallbackData{userCallbackData}, hint{hint} {}
TrackViewStorage<K> track;
void (*advancer)(const TrackViewStorage<K>&, K, std::size_t&, void*, void(*)(), void*);
TrackViewStorage<const K> track;
void (*advancer)(const TrackViewStorage<const K>&, K, std::size_t&, void*, void(*)(), void*);
void* destination;
void(*userCallback)();
void* userCallbackData;
@ -93,14 +93,14 @@ template<class T, class K> std::size_t Player<T, K>::size() const {
return _tracks.size();
}
template<class T, class K> const TrackViewStorage<K>& Player<T, K>::track(std::size_t i) const {
template<class T, class K> const TrackViewStorage<const K>& Player<T, K>::track(std::size_t i) const {
CORRADE_ASSERT(i < _tracks.size(),
/* Returning track 0 so we can test this w/ MSVC debug iterators */
"Animation::Player::track(): index out of range", _tracks[0].track);
return _tracks[i].track;
}
template<class T, class K> Player<T, K>& Player<T, K>::addInternal(const TrackViewStorage<K>& track, void(*const advancer)(const TrackViewStorage<K>&, K, std::size_t&, void*, void(*)(), void*), void* const destination, void(*const userCallback)(), void* const userCallbackData) {
template<class T, class K> Player<T, K>& Player<T, K>::addInternal(const TrackViewStorage<const K>& track, void(*const advancer)(const TrackViewStorage<const K>&, K, std::size_t&, void*, void(*)(), void*), void* const destination, void(*const userCallback)(), void* const userCallbackData) {
if(_tracks.empty() && _duration == Math::Range1D<K>{})
_duration = track.duration();
else

14
src/Magnum/Animation/Test/Benchmark.cpp

@ -55,8 +55,8 @@ struct Benchmark: TestSuite::Tester {
Containers::Array<std::pair<Float, Int>> _interleaved;
Containers::StridedArrayView1D<const Float> _keysInterleaved;
Containers::StridedArrayView1D<const Int> _valuesInterleaved;
TrackView<Float, Int> _track;
TrackView<Float, Int> _trackInterleaved;
TrackView<const Float, const Int> _track;
TrackView<const Float, const Int> _trackInterleaved;
};
namespace {
@ -91,7 +91,7 @@ Benchmark::Benchmark() {
_keysInterleaved = {_interleaved, &_interleaved[0].first, _interleaved.size(), sizeof(std::pair<Float, Int>)};
_valuesInterleaved = {_interleaved, &_interleaved[0].second, _interleaved.size(), sizeof(std::pair<Float, Int>)};
_track = TrackView<Float, Int>{
_track = TrackView<const Float, const Int>{
Containers::arrayView(_keys), Containers::arrayView(_values), Math::select};
_trackInterleaved = {_keysInterleaved, _valuesInterleaved, Math::select};
}
@ -235,8 +235,8 @@ void Benchmark::playerAdvanceCallback() {
void Benchmark::playerAdvanceRawCallback() {
Int result{};
Player<Float> player;
player.addRawCallback(_track, [](const TrackViewStorage<Float>& track, Float key, std::size_t& hint, void* destination, void(*)(), void*) {
*static_cast<Int*>(destination) += static_cast<const TrackView<Float, Int>&>(track).atStrict(key, hint);
player.addRawCallback(_track, [](const TrackViewStorage<const Float>& track, Float key, std::size_t& hint, void* destination, void(*)(), void*) {
*static_cast<Int*>(destination) += static_cast<const TrackView<const Float, const Int>&>(track).atStrict(key, hint);
}, &result, nullptr, nullptr)
.play({});
CORRADE_BENCHMARK(250) {
@ -249,8 +249,8 @@ void Benchmark::playerAdvanceRawCallback() {
void Benchmark::playerAdvanceRawCallbackDirectInterpolator() {
Int result{};
Player<Float> player;
player.addRawCallback(_track, [](const TrackViewStorage<Float>& track, Float key, std::size_t& hint, void* destination, void(*)(), void*) {
*static_cast<Int*>(destination) += static_cast<const TrackView<Float, Int>&>(track).atStrict(Math::select, key, hint);
player.addRawCallback(_track, [](const TrackViewStorage<const Float>& track, Float key, std::size_t& hint, void* destination, void(*)(), void*) {
*static_cast<Int*>(destination) += static_cast<const TrackView<const Float, const Int>&>(track).atStrict(Math::select, key, hint);
}, &result, nullptr, nullptr)
.play({});
CORRADE_BENCHMARK(250) {

94
src/Magnum/Animation/Test/PlayerTest.cpp

@ -77,17 +77,26 @@ struct PlayerTest: TestSuite::Tester {
void setState();
void add();
void addWithCallback();
void addWithCallbackTemplate();
void addWithCallbackOnChange();
void addWithCallbackOnChangeTemplate();
void addRawCallback();
template<class T> const T& addTemplateTrack();
template<class T> void add();
template<class T> void addWithCallback();
template<class T> void addWithCallbackTemplate();
template<class T> void addWithCallbackOnChange();
template<class T> void addWithCallbackOnChangeTemplate();
template<class T> void addRawCallback();
void runFor100YearsFloat();
void runFor100YearsChrono();
void debugState();
Animation::Track<Float, Float> mutableTrack{{
{1.0f, 1.5f},
{2.5f, 3.0f},
{3.0f, 5.0f},
{4.0f, 2.0f}
}, Math::lerp};
Animation::TrackView<Float, Float> mutableView = mutableTrack;
};
const struct {
@ -159,12 +168,18 @@ PlayerTest::PlayerTest() {
&PlayerTest::setState,
&PlayerTest::add,
&PlayerTest::addWithCallback,
&PlayerTest::addWithCallbackTemplate,
&PlayerTest::addWithCallbackOnChange,
&PlayerTest::addWithCallbackOnChangeTemplate,
&PlayerTest::addRawCallback});
&PlayerTest::add<Track<Float, Float>>,
&PlayerTest::add<TrackView<Float, Float>>,
&PlayerTest::addWithCallback<Track<Float, Float>>,
&PlayerTest::addWithCallback<TrackView<Float, Float>>,
&PlayerTest::addWithCallbackTemplate<Track<Float, Float>>,
&PlayerTest::addWithCallbackTemplate<TrackView<Float, Float>>,
&PlayerTest::addWithCallbackOnChange<Track<Float, Float>>,
&PlayerTest::addWithCallbackOnChange<TrackView<Float, Float>>,
&PlayerTest::addWithCallbackOnChangeTemplate<Track<Float, Float>>,
&PlayerTest::addWithCallbackOnChangeTemplate<TrackView<Float, Float>>,
&PlayerTest::addRawCallback<Track<Float, Float>>,
&PlayerTest::addRawCallback<TrackView<Float, Float>>});
addInstancedTests({
&PlayerTest::runFor100YearsFloat,
@ -1114,10 +1129,27 @@ void PlayerTest::setState() {
CORRADE_COMPARE(player.state(), State::Stopped);
}
void PlayerTest::add() {
/* So we don't need to duplicate the add*() tests by hand */
template<class T> struct AddTemplate;
template<> struct AddTemplate<Animation::Track<Float, Float>> {
static const char* name() { return "Track<Float, Float>"; };
};
template<> struct AddTemplate<Animation::TrackView<Float, Float>> {
static const char* name() { return "TrackView<Float, Float>"; };
};
template<> const Animation::Track<Float, Float>& PlayerTest::addTemplateTrack() {
return Track;
}
template<> const Animation::TrackView<Float, Float>& PlayerTest::addTemplateTrack() {
return mutableView;
}
template<class T> void PlayerTest::add() {
setTestCaseTemplateName(AddTemplate<T>::name());
Float value = -1.0f;
Player<Float> player;
player.add(Track, value)
player.add(addTemplateTrack<T>(), value)
.play(2.0f);
CORRADE_COMPARE(player.duration().size(), 3.0f);
@ -1130,13 +1162,15 @@ void PlayerTest::add() {
CORRADE_COMPARE(value, 4.0f);
}
void PlayerTest::addWithCallback() {
template<class T> void PlayerTest::addWithCallback() {
setTestCaseTemplateName(AddTemplate<T>::name());
struct Data {
Float value = -1.0f;
Int called = 0;
} data;
Player<Float> player;
player.addWithCallback(Track, [](Float, const Float& value, void* userData) {
player.addWithCallback(addTemplateTrack<T>(), [](Float, const Float& value, void* userData) {
static_cast<Data*>(userData)->value = value;
++static_cast<Data*>(userData)->called;
}, &data)
@ -1154,13 +1188,15 @@ void PlayerTest::addWithCallback() {
CORRADE_COMPARE(data.called, 1);
}
void PlayerTest::addWithCallbackTemplate() {
template<class T> void PlayerTest::addWithCallbackTemplate() {
setTestCaseTemplateName(AddTemplate<T>::name());
struct Data {
Float value = -1.0f;
Int called = 0;
} data;
Player<Float> player;
player.addWithCallback(Track, [](Float, const Float& value, Data& userData) {
player.addWithCallback(addTemplateTrack<T>(), [](Float, const Float& value, Data& userData) {
userData.value = value;
++userData.called;
}, data)
@ -1178,13 +1214,15 @@ void PlayerTest::addWithCallbackTemplate() {
CORRADE_COMPARE(data.called, 1);
}
void PlayerTest::addWithCallbackOnChange() {
template<class T> void PlayerTest::addWithCallbackOnChange() {
setTestCaseTemplateName(AddTemplate<T>::name());
struct Data {
Float value = -1.0f;
Int called = 0;
} data;
Player<Float> player;
player.addWithCallbackOnChange(Track, [](Float, const Float& value, void* userData) {
player.addWithCallbackOnChange(addTemplateTrack<T>(), [](Float, const Float& value, void* userData) {
static_cast<Data*>(userData)->value = value;
++static_cast<Data*>(userData)->called;
}, data.value, &data)
@ -1212,13 +1250,15 @@ void PlayerTest::addWithCallbackOnChange() {
CORRADE_COMPARE(data.called, 2);
}
void PlayerTest::addWithCallbackOnChangeTemplate() {
template<class T> void PlayerTest::addWithCallbackOnChangeTemplate() {
setTestCaseTemplateName(AddTemplate<T>::name());
struct Data {
Float value = -1.0f;
Int called = 0;
} data;
Player<Float> player;
player.addWithCallbackOnChange(Track, [](Float, const Float& value, Data& userData) {
player.addWithCallbackOnChange(addTemplateTrack<T>(), [](Float, const Float& value, Data& userData) {
userData.value = value;
++userData.called;
}, data.value, data)
@ -1251,17 +1291,19 @@ void callback(std::vector<Int>& data, Int value) {
data.push_back(value);
}
void PlayerTest::addRawCallback() {
Animation::Track<Float, Int> track;
template<class T> void PlayerTest::addRawCallback() {
setTestCaseTemplateName(AddTemplate<T>::name());
T track;
Int result = -1;
std::vector<Int> data;
Animation::Player<Float> player;
player.addRawCallback(track,
[](const Animation::TrackViewStorage<Float>& track, Float key,
[](const Animation::TrackViewStorage<const Float>& track, Float key,
std::size_t& hint, void* destination, void(*callback)(), void* userData) {
Int value = static_cast<const Animation::TrackView<Float, Int>&>(track).at(key, hint);
Int value = static_cast<const Animation::TrackView<const Float, const Int>&>(track).at(key, hint);
if(value == *static_cast<Int*>(destination)) return;
*static_cast<Int*>(destination) = value;
reinterpret_cast<void(*)(std::vector<Int>&, Int)>(callback)(*static_cast<std::vector<Int>*>(userData), value);

55
src/Magnum/Animation/Test/TrackTest.cpp

@ -118,34 +118,45 @@ TrackTest::TrackTest() {
using namespace Math::Literals;
void TrackTest::constructEmpty() {
const Track<Float, Vector3> a;
Track<Float, Vector3> a;
const Track<Float, Vector3>& ca = a;
CORRADE_VERIFY(!a.interpolator());
CORRADE_VERIFY(!a.size());
CORRADE_VERIFY(a.keys().empty());
CORRADE_VERIFY(!ca.interpolator());
CORRADE_VERIFY(!ca.size());
CORRADE_VERIFY(ca.keys().empty());
CORRADE_VERIFY(ca.keys().empty());
CORRADE_VERIFY(a.values().empty());
CORRADE_COMPARE(a.at(42.0f), Vector3{});
CORRADE_VERIFY(ca.values().empty());
CORRADE_COMPARE(ca.at(42.0f), Vector3{});
}
void TrackTest::constructArrayInterpolator() {
const Track<Float, Vector3> a{
Track<Float, Vector3> a{
Containers::Array<std::pair<Float, Vector3>>{Containers::InPlaceInit,
{{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}}},
Math::select, Extrapolation::Extrapolated, Extrapolation::Constant};
CORRADE_COMPARE(a.interpolation(), Interpolation::Custom);
CORRADE_COMPARE(a.interpolator(), Math::select);
CORRADE_COMPARE(a.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(a.after(), Extrapolation::Constant);
CORRADE_COMPARE(a.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(a.size(), 2);
const Track<Float, Vector3>& ca = a;
CORRADE_COMPARE(ca.interpolation(), Interpolation::Custom);
CORRADE_COMPARE(ca.interpolator(), Math::select);
CORRADE_COMPARE(ca.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(ca.after(), Extrapolation::Constant);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(a.data().size(), 2);
CORRADE_COMPARE(ca.data().size(), 2);
CORRADE_COMPARE(a.keys().size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(a.values().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
CORRADE_COMPARE(a[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
CORRADE_COMPARE(ca.data()[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(ca.keys()[1], 5.0f);
CORRADE_COMPARE(a.keys()[1], 5.0f);
CORRADE_COMPARE(ca.values()[0], (Vector3{3.0f, 1.0f, 0.1f}));
CORRADE_COMPARE(a.values()[0], (Vector3{3.0f, 1.0f, 0.1f}));
}
@ -379,12 +390,13 @@ void TrackTest::constructInitializerListInterpolationInterpolatorDefaults() {
}
void TrackTest::convertView() {
const Track<Float, Vector3> a{
Track<Float, Vector3> a{
{{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}},
Interpolation::Linear, customLerp, Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
const TrackView<Float, Vector3> av = a;
const Track<Float, Vector3>& ca = a;
const TrackView<Float, Vector3> av = a;
CORRADE_COMPARE(av.interpolation(), Interpolation::Linear);
CORRADE_COMPARE(av.interpolator(), customLerp);
CORRADE_COMPARE(av.before(), Extrapolation::Extrapolated);
@ -396,6 +408,19 @@ void TrackTest::convertView() {
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}));
const TrackView<const Float, const Vector3> cav = ca;
CORRADE_COMPARE(cav.interpolation(), Interpolation::Linear);
CORRADE_COMPARE(cav.interpolator(), customLerp);
CORRADE_COMPARE(cav.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(cav.after(), Extrapolation::DefaultConstructed);
CORRADE_COMPARE(cav.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(cav.size(), 2);
CORRADE_COMPARE(cav.keys().size(), 2);
CORRADE_COMPARE(cav.values().size(), 2);
CORRADE_COMPARE(cav[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
CORRADE_COMPARE(cav.keys()[1], 5.0f);
CORRADE_COMPARE(cav.values()[0], (Vector3{3.0f, 1.0f, 0.1f}));
}
void TrackTest::at() {

280
src/Magnum/Animation/Test/TrackViewTest.cpp

@ -49,6 +49,7 @@ struct TrackViewTest: TestSuite::Tester {
void constructSingleArrayInterpolationInterpolatorDefaults();
void constructCopyStorage();
void convertToConstView();
void at();
void atStrict();
@ -106,7 +107,8 @@ TrackViewTest::TrackViewTest() {
&TrackViewTest::constructSingleArrayInterpolationInterpolator,
&TrackViewTest::constructSingleArrayInterpolationInterpolatorDefaults,
&TrackViewTest::constructCopyStorage});
&TrackViewTest::constructCopyStorage,
&TrackViewTest::convertToConstView});
addInstancedTests({&TrackViewTest::at,
&TrackViewTest::atStrict}, Containers::arraySize(AtData));
@ -119,6 +121,7 @@ using namespace Math::Literals;
void TrackViewTest::constructEmpty() {
const TrackView<Float, Vector3> a;
const TrackView<const Float, const Vector3> ca;
CORRADE_VERIFY(!a.interpolator());
CORRADE_COMPARE(a.duration(), Range1D{});
@ -126,11 +129,18 @@ void TrackViewTest::constructEmpty() {
CORRADE_VERIFY(a.keys().empty());
CORRADE_VERIFY(a.values().empty());
CORRADE_COMPARE(a.at(42.0f), Vector3{});
CORRADE_VERIFY(!ca.interpolator());
CORRADE_COMPARE(ca.duration(), Range1D{});
CORRADE_VERIFY(!ca.size());
CORRADE_VERIFY(ca.keys().empty());
CORRADE_VERIFY(ca.values().empty());
CORRADE_COMPARE(ca.at(42.0f), Vector3{});
}
void TrackViewTest::constructInterpolator() {
constexpr Float keys[]{1.0f, 5.0f};
constexpr Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
Float keys[]{1.0f, 5.0f};
Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<Float, Vector3> a{keys, values, Math::select,
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
@ -144,11 +154,27 @@ void TrackViewTest::constructInterpolator() {
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}}));
constexpr Float ckeys[]{1.0f, 5.0f};
constexpr Vector3 cvalues[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<const Float, const Vector3> ca{ckeys, cvalues, Math::select,
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Custom);
CORRADE_COMPARE(ca.interpolator(), Math::select);
CORRADE_COMPARE(ca.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(ca.after(), Extrapolation::DefaultConstructed);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructInterpolatorDefaults() {
constexpr Float keys[]{1.0f, 5.0f};
constexpr Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
Float keys[]{1.0f, 5.0f};
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};
@ -162,11 +188,27 @@ void TrackViewTest::constructInterpolatorDefaults() {
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}}));
constexpr Float ckeys[]{1.0f, 5.0f};
constexpr Vector3 cvalues[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<const Float, const Vector3> ca{ckeys, cvalues, Math::lerp,
Extrapolation::Constant};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Custom);
CORRADE_COMPARE(ca.interpolator(), Math::lerp);
CORRADE_COMPARE(ca.before(), Extrapolation::Constant);
CORRADE_COMPARE(ca.after(), Extrapolation::Constant);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructInterpolation() {
constexpr Float keys[]{1.0f, 5.0f};
constexpr Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
Float keys[]{1.0f, 5.0f};
Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<Float, Vector3> a{keys, values, Interpolation::Linear,
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
@ -180,11 +222,27 @@ void TrackViewTest::constructInterpolation() {
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}}));
constexpr Float ckeys[]{1.0f, 5.0f};
constexpr Vector3 cvalues[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<const Float, const Vector3> ca{ckeys, cvalues, Interpolation::Linear,
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Linear);
CORRADE_COMPARE(ca.interpolator(), Math::lerp);
CORRADE_COMPARE(ca.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(ca.after(), Extrapolation::DefaultConstructed);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructInterpolationDefaults() {
constexpr Float keys[]{1.0f, 5.0f};
constexpr Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
Float keys[]{1.0f, 5.0f};
Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<Float, Vector3> a{keys, values, Interpolation::Constant,
Extrapolation::Constant};
@ -198,13 +256,29 @@ void TrackViewTest::constructInterpolationDefaults() {
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}}));
constexpr Float ckeys[]{1.0f, 5.0f};
constexpr Vector3 cvalues[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<const Float, const Vector3> ca{ckeys, cvalues, Interpolation::Constant,
Extrapolation::Constant};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Constant);
CORRADE_COMPARE(ca.interpolator(), Math::select);
CORRADE_COMPARE(ca.before(), Extrapolation::Constant);
CORRADE_COMPARE(ca.after(), Extrapolation::Constant);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
Vector3 customLerp(const Vector3&, const Vector3&, Float) { return {}; }
void TrackViewTest::constructInterpolationInterpolator() {
constexpr Float keys[]{1.0f, 5.0f};
constexpr Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
Float keys[]{1.0f, 5.0f};
Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<Float, Vector3> a{keys, values, Interpolation::Linear,
customLerp, Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
@ -218,11 +292,27 @@ void TrackViewTest::constructInterpolationInterpolator() {
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}}));
constexpr Float ckeys[]{1.0f, 5.0f};
constexpr Vector3 cvalues[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<const Float, const Vector3> ca{ckeys, cvalues,
Interpolation::Linear, customLerp, Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Linear);
CORRADE_COMPARE(ca.interpolator(), customLerp);
CORRADE_COMPARE(ca.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(ca.after(), Extrapolation::DefaultConstructed);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructInterpolationInterpolatorDefaults() {
constexpr Float keys[]{1.0f, 5.0f};
constexpr Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
Float keys[]{1.0f, 5.0f};
Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<Float, Vector3> a{keys, values, Interpolation::Constant,
customLerp, Extrapolation::Constant};
@ -236,10 +326,26 @@ void TrackViewTest::constructInterpolationInterpolatorDefaults() {
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}}));
constexpr Float ckeys[]{1.0f, 5.0f};
constexpr Vector3 cvalues[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<const Float, const Vector3> ca{ckeys, cvalues,
Interpolation::Constant, customLerp, Extrapolation::Constant};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Constant);
CORRADE_COMPARE(ca.interpolator(), customLerp);
CORRADE_COMPARE(ca.before(), Extrapolation::Constant);
CORRADE_COMPARE(ca.after(), Extrapolation::Constant);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructSingleArrayInterpolator() {
const std::pair<Float, Vector3> data[]{
std::pair<Float, Vector3> data[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
@ -255,10 +361,27 @@ void TrackViewTest::constructSingleArrayInterpolator() {
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}}));
const std::pair<Float, Vector3> cdata[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
const TrackView<const Float, const Vector3> ca{cdata, Math::select,
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Custom);
CORRADE_COMPARE(ca.interpolator(), Math::select);
CORRADE_COMPARE(ca.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(ca.after(), Extrapolation::DefaultConstructed);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructSingleArrayInterpolatorDefaults() {
const std::pair<Float, Vector3> data[]{
std::pair<Float, Vector3> data[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
@ -274,10 +397,27 @@ void TrackViewTest::constructSingleArrayInterpolatorDefaults() {
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}}));
const std::pair<Float, Vector3> cdata[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
const TrackView<const Float, const Vector3> ca{cdata, Math::lerp,
Extrapolation::Constant};
CORRADE_COMPARE(a.interpolation(), Interpolation::Custom);
CORRADE_COMPARE(a.interpolator(), Math::lerp);
CORRADE_COMPARE(a.before(), Extrapolation::Constant);
CORRADE_COMPARE(a.after(), Extrapolation::Constant);
CORRADE_COMPARE(a.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(a.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}}));
}
void TrackViewTest::constructSingleArrayInterpolation() {
const std::pair<Float, Vector3> data[]{
std::pair<Float, Vector3> data[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
@ -293,10 +433,27 @@ void TrackViewTest::constructSingleArrayInterpolation() {
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}}));
const std::pair<Float, Vector3> cdata[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
const TrackView<const Float, const Vector3> ca{cdata, Interpolation::Linear,
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Linear);
CORRADE_COMPARE(ca.interpolator(), Math::lerp);
CORRADE_COMPARE(ca.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(ca.after(), Extrapolation::DefaultConstructed);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructSingleArrayInterpolationDefaults() {
const std::pair<Float, Vector3> data[]{
std::pair<Float, Vector3> data[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
@ -312,10 +469,27 @@ void TrackViewTest::constructSingleArrayInterpolationDefaults() {
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}}));
const std::pair<Float, Vector3> cdata[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
const TrackView<const Float, const Vector3> ca{cdata, Interpolation::Constant,
Extrapolation::Constant};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Constant);
CORRADE_COMPARE(ca.interpolator(), Math::select);
CORRADE_COMPARE(ca.before(), Extrapolation::Constant);
CORRADE_COMPARE(ca.after(), Extrapolation::Constant);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructSingleArrayInterpolationInterpolator() {
const std::pair<Float, Vector3> data[]{
std::pair<Float, Vector3> data[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
@ -331,10 +505,27 @@ void TrackViewTest::constructSingleArrayInterpolationInterpolator() {
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}}));
const std::pair<Float, Vector3> cdata[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
const TrackView<const Float, const Vector3> ca{cdata, Interpolation::Linear, customLerp,
Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Linear);
CORRADE_COMPARE(ca.interpolator(), customLerp);
CORRADE_COMPARE(ca.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(ca.after(), Extrapolation::DefaultConstructed);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructSingleArrayInterpolationInterpolatorDefaults() {
const std::pair<Float, Vector3> data[]{
std::pair<Float, Vector3> data[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
@ -350,10 +541,27 @@ void TrackViewTest::constructSingleArrayInterpolationInterpolatorDefaults() {
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}}));
const std::pair<Float, Vector3> cdata[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
const TrackView<const Float, const Vector3> ca{cdata, Interpolation::Constant,
customLerp, Extrapolation::Constant};
CORRADE_COMPARE(ca.interpolation(), Interpolation::Constant);
CORRADE_COMPARE(ca.interpolator(), customLerp);
CORRADE_COMPARE(ca.before(), Extrapolation::Constant);
CORRADE_COMPARE(ca.after(), Extrapolation::Constant);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::constructCopyStorage() {
const std::pair<Float, Vector3> data[]{
std::pair<Float, Vector3> data[]{
{1.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}};
@ -375,6 +583,30 @@ void TrackViewTest::constructCopyStorage() {
CORRADE_COMPARE(bv[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
}
void TrackViewTest::convertToConstView() {
Float keys[]{1.0f, 5.0f};
Vector3 values[]{{3.0f, 1.0f, 0.1f}, {0.3f, 0.6f, 1.0f}};
const TrackView<Float, Vector3> a{keys, values, Interpolation::Linear,
customLerp, Extrapolation::Extrapolated, Extrapolation::DefaultConstructed};
const TrackView<const Float, const Vector3> ca = a;
CORRADE_COMPARE(ca.interpolation(), Interpolation::Linear);
CORRADE_COMPARE(ca.interpolator(), customLerp);
CORRADE_COMPARE(ca.before(), Extrapolation::Extrapolated);
CORRADE_COMPARE(ca.after(), Extrapolation::DefaultConstructed);
CORRADE_COMPARE(ca.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(ca.size(), 2);
CORRADE_COMPARE(ca.keys().size(), 2);
CORRADE_COMPARE(ca.values().size(), 2);
CORRADE_COMPARE(ca[1], (std::pair<Float, Vector3>{5.0f, {0.3f, 0.6f, 1.0f}}));
/* Conversion back is not possible */
CORRADE_VERIFY((std::is_convertible<TrackView<Float, Vector3>, TrackView<const Float, const Vector3>>::value));
CORRADE_VERIFY(!(std::is_convertible<TrackView<const Float, const Vector3>, TrackView<Float, Vector3>>::value));
}
const std::pair<Float, Float> Keyframes[]{
{0.0f, 3.0f},
{2.0f, 1.0f},
@ -386,7 +618,7 @@ void TrackViewTest::at() {
const auto& data = AtData[testCaseInstanceId()];
setTestCaseDescription(data.name);
const TrackView<Float, Float> a{Keyframes, Math::lerp,
const TrackView<const Float, const Float> a{Keyframes, Math::lerp,
data.extrapolationBefore, data.extrapolationAfter};
std::size_t hint{};
@ -399,7 +631,7 @@ void TrackViewTest::atStrict() {
const auto& data = AtData[testCaseInstanceId()];
setTestCaseDescription(data.name);
const TrackView<Float, Float> a{Keyframes, Math::lerp,
const TrackView<const Float, const Float> a{Keyframes, Math::lerp,
data.extrapolationBefore, data.extrapolationAfter};
std::size_t hint{};
@ -416,7 +648,7 @@ Float lerpHalf(const Half& a, const Half& b, Float t) {
}
void TrackViewTest::atDifferentResultType() {
const TrackView<Float, Half, Float> a{
const TrackView<const Float, const Half, Float> a{
{Keyframes, &Keyframes[0].first, Containers::arraySize(Keyframes), sizeof(Keyframes[0])},
HalfValues, lerpHalf};
@ -427,7 +659,7 @@ void TrackViewTest::atDifferentResultType() {
}
void TrackViewTest::atDifferentResultTypeStrict() {
const TrackView<Float, Half, Float> a{
const TrackView<const Float, const Half, Float> a{
{Keyframes, &Keyframes[0].first, Containers::arraySize(Keyframes), sizeof(Keyframes[0])},
HalfValues, lerpHalf};

112
src/Magnum/Animation/Track.h

@ -243,7 +243,12 @@ template<class K, class V, class R
Track<K, V, R>& operator=(Track<K, V, R>&&) = default;
/** @brief Conversion to a view */
operator TrackView<K, V, R>() const noexcept {
operator TrackView<const K, const V, R>() const noexcept {
return TrackView<const K, const V, R>{_data, _interpolation, _interpolator, _before, _after};
}
/** @overload */
operator TrackView<K, V, R>() noexcept {
return TrackView<K, V, R>{_data, _interpolation, _interpolator, _before, _after};
}
@ -298,6 +303,9 @@ template<class K, class V, class R
*/
Containers::ArrayView<const std::pair<K, V>> data() const { return _data; }
/** @overload */
Containers::ArrayView<std::pair<K, V>> data() { return _data; }
/**
* @brief Key data
*
@ -307,6 +315,11 @@ template<class K, class V, class R
return _data ? Containers::StridedArrayView1D<const K>{_data, &_data[0].first, _data.size(), sizeof(std::pair<K, V>)} : nullptr;
}
/** @overload */
Containers::StridedArrayView1D<K> keys() {
return _data ? Containers::StridedArrayView1D<K>{_data, &_data[0].first, _data.size(), sizeof(std::pair<K, V>)} : nullptr;
}
/**
* @brief Value data
*
@ -316,6 +329,11 @@ template<class K, class V, class R
return _data ? Containers::StridedArrayView1D<const V>{_data, &_data[0].second, _data.size(), sizeof(std::pair<K, V>)} : nullptr;
}
/** @overload */
Containers::StridedArrayView1D<V> values() {
return _data ? Containers::StridedArrayView1D<V>{_data, &_data[0].second, _data.size(), sizeof(std::pair<K, V>)} : nullptr;
}
/**
* @brief Keyframe access
*
@ -323,6 +341,9 @@ template<class K, class V, class R
*/
const std::pair<K, V>& operator[](std::size_t i) const { return _data[i]; }
/** @overload */
std::pair<K, V>& operator[](std::size_t i) { return _data[i]; }
/**
* @brief Animated value at a given time
*
@ -452,8 +473,8 @@ template<class K> class TrackViewStorage {
* a default-constructed value is returned. Use @ref Math::join() to
* calculate combined duration for a set of tracks.
*/
Math::Range1D<K> duration() const {
return _keys.empty() ? Math::Range1D<K>{} : Math::Range1D<K>{_keys.front(), _keys.back()};
Math::Range1D<typename std::remove_const<K>::type> duration() const {
return _keys.empty() ? Math::Range1D<typename std::remove_const<K>::type>{} : Math::Range1D<typename std::remove_const<K>::type>{_keys.front(), _keys.back()};
}
/** @brief Keyframe count */
@ -466,17 +487,19 @@ template<class K> class TrackViewStorage {
*
* @see @ref TrackView::values(), @ref TrackView::operator[]()
*/
Containers::StridedArrayView1D<const K> keys() const {
Containers::StridedArrayView1D<K> keys() const {
return _keys;
}
private:
template<class, class, class> friend class TrackView;
template<class V, class R> explicit TrackViewStorage(const Containers::StridedArrayView1D<K>& keys, const Containers::StridedArrayView1D<V>& values, Interpolation interpolation, R(*interpolator)(const V&, const V&, Float), Extrapolation before, Extrapolation after) noexcept: _keys{keys}, _values{reinterpret_cast<const Containers::StridedArrayView1D<char>&>(values)}, _interpolator{reinterpret_cast<void(*)()>(interpolator)}, _interpolation{interpolation}, _before{before}, _after{after} {}
template<class V, class R> explicit TrackViewStorage(const Containers::StridedArrayView1D<const K>& keys, const Containers::StridedArrayView1D<const V>& values, Interpolation interpolation, R(*interpolator)(const V&, const V&, Float), Extrapolation before, Extrapolation after) noexcept: _keys{keys}, _values{reinterpret_cast<const Containers::StridedArrayView1D<const char>&>(values)}, _interpolator{reinterpret_cast<void(*)()>(interpolator)}, _interpolation{interpolation}, _before{before}, _after{after} {}
Containers::StridedArrayView1D<const K> _keys;
Containers::StridedArrayView1D<const char> _values;
Containers::StridedArrayView1D<K> _keys;
Containers::StridedArrayView1D<typename std::conditional<std::is_const<K>::value, const char, char>::type> _values;
void(*_interpolator)(void);
Interpolation _interpolation;
Extrapolation _before, _after;
@ -488,8 +511,9 @@ template<class K> class TrackViewStorage {
@tparam V Value type
@tparam R Result type
Unlike @ref Track this is a non-owning view onto keyframe + value pairs. See
its documentation for more information.
Unlike @ref Track this is a non-owning view onto keyframe + value pairs. The
@p K and @p V can be either both mutable or both @cpp const @ce. See the
@ref Track documentation for more information.
@experimental
*/
template<class K, class V, class R
@ -497,10 +521,23 @@ template<class K, class V, class R
= ResultOf<V>
#endif
> class TrackView: public TrackViewStorage<K> {
static_assert(std::is_const<K>::value == std::is_const<V>::value && !std::is_const<R>::value,
"K and V should be either both mutable or both const; R shouldn't be const");
public:
/** @brief Value type */
typedef V ValueType;
/**
* @brief Key-value type
*
* Used mainly when converting from @ref Track. Equal to
* @cpp std::pair<K, V> @ce if @p K and @p V are not @cpp const @ce,
* and to @cpp const std::pair<K_, V_> @ce (where @p K_ / @p V_ are
* with @cpp const @ce removed) when they are @cpp const @ce.
*/
typedef typename std::conditional<std::is_const<K>::value, const std::pair<typename std::remove_const<K>::type, typename std::remove_const<V>::type>, std::pair<K, V>>::type KeyValueType;
/** @brief Animation result type */
typedef R ResultType;
@ -527,17 +564,17 @@ template<class K, class V, class R
* 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 @ref interpolation() field is set to @ref Interpolation::Custom.
* See @ref TrackView(const Containers::StridedArrayView1D<const K>&, const Containers::StridedArrayView1D<const V>&, Interpolation, Interpolator, Extrapolation, Extrapolation) or
* @ref TrackView(const Containers::StridedArrayView1D<const K>&, const Containers::StridedArrayView1D<const V>&, Interpolation, Extrapolation, Extrapolation)
* See @ref TrackView(const Containers::StridedArrayView1D<K>&, const Containers::StridedArrayView1D<V>&, Interpolation, Interpolator, Extrapolation, Extrapolation) or
* @ref TrackView(const Containers::StridedArrayView1D<K>&, const Containers::StridedArrayView1D<V>&, Interpolation, Extrapolation, Extrapolation)
* for an alternative.
*/
/*implicit*/ TrackView(const Containers::StridedArrayView1D<const K>& keys, const Containers::StridedArrayView1D<const V>& values, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: TrackViewStorage<K>{keys, values, Interpolation::Custom, interpolator, before, after} {}
/*implicit*/ TrackView(const Containers::StridedArrayView1D<K>& keys, const Containers::StridedArrayView1D<V>& values, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: TrackViewStorage<K>{keys, values, Interpolation::Custom, interpolator, before, after} {}
/** @overload
* Equivalent to calling @ref TrackView(const Containers::StridedArrayView1D<const K>&, const Containers::StridedArrayView1D<const V>&, Interpolator, Extrapolation, Extrapolation)
* Equivalent to calling @ref TrackView(const Containers::StridedArrayView1D<K>&, const Containers::StridedArrayView1D<V>&, Interpolator, Extrapolation, Extrapolation)
* with both @p before and @p after set to @p extrapolation.
*/
/*implicit*/ TrackView(const Containers::StridedArrayView1D<const K>& keys, const Containers::StridedArrayView1D<const V>& values, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{keys, values, interpolator, extrapolation, extrapolation} {}
/*implicit*/ TrackView(const Containers::StridedArrayView1D<K>& keys, const Containers::StridedArrayView1D<V>& values, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{keys, values, interpolator, extrapolation, extrapolation} {}
/**
* @brief Construct with custom interpolator from an interleaved array
@ -547,15 +584,15 @@ template<class K, class V, class R
* @param after Extrapolation behavior after
*
* Converts @p data to a pair of strided array views and calls
* @ref TrackView(const Containers::StridedArrayView1D<const K>&, const Containers::StridedArrayView1D<const V>&, Interpolator, Extrapolation, Extrapolation).
* @ref TrackView(const Containers::StridedArrayView1D<K>&, const Containers::StridedArrayView1D<V>&, Interpolator, Extrapolation, Extrapolation).
*/
/*implicit*/ TrackView(Containers::ArrayView<const std::pair<K, V>> data, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: TrackView<K, V, R>{Containers::StridedArrayView1D<const K>{data, data ? &data[0].first : nullptr, data.size(), sizeof(std::pair<K, V>)}, Containers::StridedArrayView1D<const V>{data, data ? &data[0].second : nullptr, data.size(), sizeof(std::pair<K, V>)}, interpolator, before, after} {}
/*implicit*/ TrackView(Containers::ArrayView<KeyValueType> data, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: TrackView<K, V, R>{Containers::StridedArrayView1D<K>{data, data ? &data[0].first : nullptr, data.size(), sizeof(std::pair<K, V>)}, Containers::StridedArrayView1D<V>{data, data ? &data[0].second : nullptr, data.size(), sizeof(std::pair<K, V>)}, interpolator, before, after} {}
/** @overload
* Equivalent to calling @ref TrackView(Containers::ArrayView<const std::pair<K, V>>, Interpolator, Extrapolation, Extrapolation)
* Equivalent to calling @ref TrackView(Containers::ArrayView<KeyValueType>, Interpolator, Extrapolation, Extrapolation)
* with both @p before and @p after set to @p extrapolation.
*/
explicit TrackView(Containers::ArrayView<const std::pair<K, V>> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{data, interpolator, extrapolation, extrapolation} {}
explicit TrackView(Containers::ArrayView<KeyValueType> data, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{data, interpolator, extrapolation, extrapolation} {}
/**
* @brief Construct with both generic and custom interpolator
@ -572,13 +609,13 @@ template<class K, class V, class R
* supply their own interpolator function to @ref at() or
* @ref atStrict().
*/
/*implicit*/ TrackView(const Containers::StridedArrayView1D<const K>& keys, const Containers::StridedArrayView1D<const V>& values, Interpolation interpolation, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: TrackViewStorage<K>{keys, values, interpolation, interpolator, before, after} {}
/*implicit*/ TrackView(const Containers::StridedArrayView1D<K>& keys, const Containers::StridedArrayView1D<V>& values, Interpolation interpolation, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: TrackViewStorage<K>{keys, values, interpolation, interpolator, before, after} {}
/** @overload
* Equivalent to calling @ref TrackView(const Containers::StridedArrayView1D<const K>&, const Containers::StridedArrayView1D<const V>&, Interpolation, Interpolator, Extrapolation, Extrapolation)
* Equivalent to calling @ref TrackView(const Containers::StridedArrayView1D<K>&, const Containers::StridedArrayView1D<V>&, Interpolation, Interpolator, Extrapolation, Extrapolation)
* with both @p before and @p after set to @p extrapolation.
*/
/*implicit*/ TrackView(const Containers::StridedArrayView1D<const K>& keys, const Containers::StridedArrayView1D<const V>& values, Interpolation interpolation, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{keys, values, interpolation, interpolator, extrapolation, extrapolation} {}
/*implicit*/ TrackView(const Containers::StridedArrayView1D<K>& keys, const Containers::StridedArrayView1D<V>& values, Interpolation interpolation, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{keys, values, interpolation, interpolator, extrapolation, extrapolation} {}
/**
* @brief Construct with both generic and custom interpolator from an interleaved array
@ -589,15 +626,15 @@ template<class K, class V, class R
* @param after Extrapolation behavior after
*
* Converts @p data to a pair of strided array views and calls
* @ref TrackView(const Containers::StridedArrayView1D<const K>&, const Containers::StridedArrayView1D<const V>&, Interpolator, Extrapolation, Extrapolation).
* @ref TrackView(const Containers::StridedArrayView1D<K>&, const Containers::StridedArrayView1D<V>&, Interpolator, Extrapolation, Extrapolation).
*/
/*implicit*/ TrackView(Containers::ArrayView<const std::pair<K, V>> data, Interpolation interpolation, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: TrackViewStorage<K>{Containers::StridedArrayView1D<const K>{data, data ? &data[0].first : nullptr, data.size(), sizeof(std::pair<K, V>)}, Containers::StridedArrayView1D<const V>{data, data ? &data[0].second : nullptr, data.size(), sizeof(std::pair<K, V>)}, interpolation, interpolator, before, after} {}
/*implicit*/ TrackView(Containers::ArrayView<KeyValueType> data, Interpolation interpolation, Interpolator interpolator, Extrapolation before, Extrapolation after) noexcept: TrackViewStorage<K>{Containers::StridedArrayView1D<K>{data, data ? &data[0].first : nullptr, data.size(), sizeof(std::pair<K, V>)}, Containers::StridedArrayView1D<V>{data, data ? &data[0].second : nullptr, data.size(), sizeof(std::pair<K, V>)}, interpolation, interpolator, before, after} {}
/** @overload
* Equivalent to calling @ref TrackView(Containers::ArrayView<const std::pair<K, V>>, Interpolation, Interpolator, Extrapolation, Extrapolation)
* Equivalent to calling @ref TrackView(Containers::ArrayView<KeyValueType>, Interpolation, Interpolator, Extrapolation, Extrapolation)
* with both @p before and @p after set to @p extrapolation.
*/
/*implicit*/ TrackView(Containers::ArrayView<const std::pair<K, V>> data, Interpolation interpolation, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{data, interpolation, interpolator, extrapolation, extrapolation} {}
/*implicit*/ TrackView(Containers::ArrayView<KeyValueType> data, Interpolation interpolation, Interpolator interpolator, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{data, interpolation, interpolator, extrapolation, extrapolation} {}
/**
* @brief Construct with generic interpolation behavior
@ -613,13 +650,13 @@ template<class K, class V, class R
* @p interpolation using @ref interpolatorFor(). See its documentation
* for more information.
*/
/*implicit*/ TrackView(const Containers::StridedArrayView1D<const K>& keys, const Containers::StridedArrayView1D<const V>& values, Interpolation interpolation, Extrapolation before, Extrapolation after) noexcept: TrackViewStorage<K>{keys, values, interpolation, interpolatorFor<V, R>(interpolation), before, after} {}
/*implicit*/ TrackView(const Containers::StridedArrayView1D<K>& keys, const Containers::StridedArrayView1D<V>& values, Interpolation interpolation, Extrapolation before, Extrapolation after) noexcept: TrackViewStorage<K>{keys, values, interpolation, interpolatorFor<V, R>(interpolation), before, after} {}
/** @overload
* Equivalent to calling @ref TrackView(const Containers::StridedArrayView1D<const K>&, const Containers::StridedArrayView1D<const V>&, Interpolation, Extrapolation, Extrapolation)
* Equivalent to calling @ref TrackView(const Containers::StridedArrayView1D<K>&, const Containers::StridedArrayView1D<V>&, Interpolation, Extrapolation, Extrapolation)
* with both @p before and @p after set to @p extrapolation.
*/
/*implicit*/ TrackView(const Containers::StridedArrayView1D<const K>& keys, const Containers::StridedArrayView1D<const V>& values, Interpolation interpolation, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{keys, values, interpolation, extrapolation, extrapolation} {}
/*implicit*/ TrackView(const Containers::StridedArrayView1D<K>& keys, const Containers::StridedArrayView1D<V>& values, Interpolation interpolation, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{keys, values, interpolation, extrapolation, extrapolation} {}
/**
* @brief Construct with generic interpolation behavior from an interleaved array
@ -629,15 +666,18 @@ template<class K, class V, class R
* @param after Extrapolation behavior after
*
* Converts @p data to a pair of strided array views and calls
* @ref TrackView(const Containers::StridedArrayView1D<const K>&, const Containers::StridedArrayView1D<const V>&, Interpolator, Extrapolation, Extrapolation).
* @ref TrackView(const Containers::StridedArrayView1D<K>&, const Containers::StridedArrayView1D<V>&, Interpolator, Extrapolation, Extrapolation).
*/
/*implicit*/ TrackView(Containers::ArrayView<const std::pair<K, V>> data, Interpolation interpolation, Extrapolation before, Extrapolation after) noexcept: TrackView<K, V, R>{Containers::StridedArrayView1D<const K>{data, data ? &data[0].first : nullptr, data.size(), sizeof(std::pair<K, V>)}, Containers::StridedArrayView1D<const V>{data, data ? &data[0].second : nullptr, data.size(), sizeof(std::pair<K, V>)}, interpolation, before, after} {}
/*implicit*/ TrackView(Containers::ArrayView<KeyValueType> data, Interpolation interpolation, Extrapolation before, Extrapolation after) noexcept: TrackView<K, V, R>{Containers::StridedArrayView1D<K>{data, data ? &data[0].first : nullptr, data.size(), sizeof(std::pair<K, V>)}, Containers::StridedArrayView1D<V>{data, data ? &data[0].second : nullptr, data.size(), sizeof(std::pair<K, V>)}, interpolation, before, after} {}
/** @overload
* Equivalent to calling @ref TrackView(Containers::ArrayView<const std::pair<K, V>>, Interpolation, Extrapolation, Extrapolation)
* Equivalent to calling @ref TrackView(Containers::ArrayView<KeyValueType>, Interpolation, Extrapolation, Extrapolation)
* with both @p before and @p after set to @p extrapolation.
*/
/*implicit*/ TrackView(Containers::ArrayView<const std::pair<K, V>> data, Interpolation interpolation, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{data, interpolation, extrapolation, extrapolation} {}
/*implicit*/ TrackView(Containers::ArrayView<KeyValueType> data, Interpolation interpolation, Extrapolation extrapolation = Extrapolation::Constant) noexcept: TrackView<K, V, R>{data, interpolation, extrapolation, extrapolation} {}
/** @brief Convert a mutable view to a const one */
template<class L = K, class = typename std::enable_if<std::is_const<L>::value>::type> /*implicit*/ TrackView(const TrackView<typename std::remove_const<K>::type, typename std::remove_const<V>::type, R>& other) noexcept: TrackViewStorage<K>{other._keys, reinterpret_cast<const Containers::StridedArrayView1D<V>&>(other._values), other._interpolation, reinterpret_cast<Interpolator>(other._interpolator), other._before, other._after} {}
/**
* @brief Interpolation function
@ -653,8 +693,8 @@ template<class K, class V, class R
*
* @see @ref keys(), @ref operator[]()
*/
Containers::StridedArrayView1D<const V> values() const {
return reinterpret_cast<const Containers::StridedArrayView1D<const V>&>(TrackViewStorage<K>::_values);
Containers::StridedArrayView1D<V> values() const {
return reinterpret_cast<const Containers::StridedArrayView1D<V>&>(TrackViewStorage<K>::_values);
}
/**
@ -662,7 +702,7 @@ template<class K, class V, class R
*
* @see @ref size()
*/
std::pair<K, V> operator[](std::size_t i) const {
std::pair<typename std::remove_const<K>::type, typename std::remove_const<V>::type> operator[](std::size_t i) const {
return {TrackViewStorage<K>::_keys[i], values()[i]};
}
@ -715,7 +755,7 @@ template<class K, class V, class R
* @see @ref atStrict(Interpolator, K, std::size_t&) const
*/
R at(Interpolator interpolator, K frame, std::size_t& hint) const {
return interpolate(TrackViewStorage<K>::_keys, values(), TrackViewStorage<K>::_before, TrackViewStorage<K>::_after, interpolator, frame, hint);
return interpolate<typename std::remove_const<K>::type, typename std::remove_const<V>::type, R>(TrackViewStorage<K>::_keys, values(), TrackViewStorage<K>::_before, TrackViewStorage<K>::_after, interpolator, frame, hint);
}
/**
@ -739,7 +779,7 @@ template<class K, class V, class R
* @see @ref at(K, std::size_t&) const
*/
R atStrict(Interpolator interpolator, K frame, std::size_t& hint) const {
return interpolateStrict(TrackViewStorage<K>::_keys, values(), interpolator, frame, hint);
return interpolateStrict<typename std::remove_const<K>::type, typename std::remove_const<V>::type, R>(TrackViewStorage<K>::_keys, values(), interpolator, frame, hint);
}
};

Loading…
Cancel
Save