Browse Source

Trade: mutable access in AnimationData.

Follows the change done in MeshData.
pull/371/head
Vladimír Vondruš 7 years ago
parent
commit
0fd62194c8
  1. 9
      doc/changelog.dox
  2. 17
      doc/snippets/MagnumTrade.cpp
  3. 29
      src/Magnum/Trade/AnimationData.cpp
  4. 132
      src/Magnum/Trade/AnimationData.h
  5. 7
      src/Magnum/Trade/Data.h
  6. 188
      src/Magnum/Trade/Test/AnimationDataTest.cpp

9
doc/changelog.dox

@ -168,6 +168,11 @@ See also:
@ref Trade::AbstractImporter::image2D(), @ref Trade::AbstractImporter::image2D(),
@ref Trade::AbstractImporter::image2DLevelCount() and similar APIs for 1D @ref Trade::AbstractImporter::image2DLevelCount() and similar APIs for 1D
and 3D images and 3D images
- The @ref Trade::AnimationData class received support for mutable data
access with new constructors and the
@ref Trade::AnimationData::mutableData() "mutableData()" and
@ref Trade::AnimationData::mutableTrack() "mutableTrack()" accessors. See
@ref Trade-AnimationData-usage-mutable for more information.
@subsubsection changelog-latest-new-vk Vk library @subsubsection changelog-latest-new-vk Vk library
@ -391,7 +396,9 @@ See also:
values it references. Existing code needs to be changed to say 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. @cpp TrackView<const K, const V> @ce instead of @cpp TrackView<K, V> @ce.
Following this change, @ref Trade::AnimationData now also return instances Following this change, @ref Trade::AnimationData now also return instances
with @cpp const @ce types. with @cpp const @ce types and the non-const
@ref Trade::AnimationData::data() was renamed to
@ref Trade::AnimationData::mutableData() "mutableData()".
- The 4-argument @ref GL::DynamicAttribute constructor was not marked as - The 4-argument @ref GL::DynamicAttribute constructor was not marked as
@cpp explicit @ce by mistake, it's done now to enforce readability in long @cpp explicit @ce by mistake, it's done now to enforce readability in long
expressions. expressions.

17
doc/snippets/MagnumTrade.cpp

@ -174,6 +174,23 @@ Containers::Array<char> animationData = data->release(); /* Take ownership */
/* [AnimationData-usage] */ /* [AnimationData-usage] */
} }
{
Trade::AnimationData data{nullptr, {}};
/* [AnimationData-usage-mutable] */
for(UnsignedInt i = 0; i != data.trackCount(); ++i) {
if(data.trackTargetType(i) != Trade::AnimationTrackTargetType::Translation3D)
continue;
/* Check prerequisites */
if(!(data.dataFlags() & Trade::DataFlag::Mutable) ||
data.trackType(i) != Trade::AnimationTrackType::Vector2)
Fatal{} << "Oops";
MeshTools::transformVectorsInPlace(Matrix4::scaling(Vector3::yScale(-1.0f)),
data.mutableTrack<Vector3>(i).values());
}
/* [AnimationData-usage-mutable] */
}
{ {
/* [ImageData-construction] */ /* [ImageData-construction] */
Containers::Array<char> data; Containers::Array<char> data;

29
src/Magnum/Trade/AnimationData.cpp

@ -32,9 +32,15 @@
namespace Magnum { namespace Trade { namespace Magnum { namespace Trade {
AnimationData::AnimationData(Containers::Array<char>&& data, Containers::Array<AnimationTrackData>&& tracks, const Range1D& duration, const void* importerState) noexcept: _duration{duration}, _data{std::move(data)}, _tracks{std::move(tracks)}, _importerState{importerState} {} AnimationData::AnimationData(Containers::Array<char>&& data, Containers::Array<AnimationTrackData>&& tracks, const Range1D& duration, const void* importerState) noexcept: _dataFlags{DataFlag::Owned|DataFlag::Mutable}, _duration{duration}, _data{std::move(data)}, _tracks{std::move(tracks)}, _importerState{importerState} {}
AnimationData::AnimationData(Containers::Array<char>&& data, Containers::Array<AnimationTrackData>&& tracks, const void* importerState) noexcept: _data{std::move(data)}, _tracks{std::move(tracks)}, _importerState{importerState} { AnimationData::AnimationData(const DataFlags dataFlags, const Containers::ArrayView<const void> data, Containers::Array<AnimationTrackData>&& tracks, const Range1D& duration, const void* importerState) noexcept: AnimationData{Containers::Array<char>{const_cast<char*>(static_cast<const char*>(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, std::move(tracks), duration, importerState} {
CORRADE_ASSERT(!(dataFlags & DataFlag::Owned),
"Trade::AnimationData: can't construct a non-owned instance with" << dataFlags, );
_dataFlags = dataFlags;
}
AnimationData::AnimationData(Containers::Array<char>&& data, Containers::Array<AnimationTrackData>&& tracks, const void* importerState) noexcept: _dataFlags{DataFlag::Owned|DataFlag::Mutable}, _data{std::move(data)}, _tracks{std::move(tracks)}, _importerState{importerState} {
if(!_tracks.empty()) { if(!_tracks.empty()) {
/* Reset duration to duration of the first track so it properly support /* Reset duration to duration of the first track so it properly support
cases where tracks don't start at 0 */ cases where tracks don't start at 0 */
@ -44,12 +50,24 @@ AnimationData::AnimationData(Containers::Array<char>&& data, Containers::Array<A
} }
} }
AnimationData::AnimationData(const DataFlags dataFlags, const Containers::ArrayView<const void> data, Containers::Array<AnimationTrackData>&& tracks, const void* importerState) noexcept: AnimationData{Containers::Array<char>{const_cast<char*>(static_cast<const char*>(data.data())), data.size(), Implementation::nonOwnedArrayDeleter}, std::move(tracks), importerState} {
CORRADE_ASSERT(!(dataFlags & DataFlag::Owned),
"Trade::AnimationData: can't construct a non-owned instance with" << dataFlags, );
_dataFlags = dataFlags;
}
AnimationData::~AnimationData() = default; AnimationData::~AnimationData() = default;
AnimationData::AnimationData(AnimationData&&) noexcept = default; AnimationData::AnimationData(AnimationData&&) noexcept = default;
AnimationData& AnimationData::operator=(AnimationData&&) noexcept = default; AnimationData& AnimationData::operator=(AnimationData&&) noexcept = default;
Containers::ArrayView<char> AnimationData::mutableData() & {
CORRADE_ASSERT(_dataFlags & DataFlag::Mutable,
"Trade::AnimationData::mutableData(): the animation is not mutable", {});
return _data;
}
AnimationTrackType AnimationData::trackType(UnsignedInt id) const { AnimationTrackType AnimationData::trackType(UnsignedInt id) const {
CORRADE_ASSERT(id < _tracks.size(), "Trade::AnimationData::trackType(): index out of range", {}); CORRADE_ASSERT(id < _tracks.size(), "Trade::AnimationData::trackType(): index out of range", {});
return _tracks[id]._type; return _tracks[id]._type;
@ -75,6 +93,13 @@ const Animation::TrackViewStorage<const Float>& AnimationData::track(UnsignedInt
return _tracks[id]._view; return _tracks[id]._view;
} }
const Animation::TrackViewStorage<Float>& AnimationData::mutableTrack(UnsignedInt id) {
CORRADE_ASSERT(_dataFlags & DataFlag::Mutable,
"Trade::AnimationData::mutableTrack(): the animation is not mutable", reinterpret_cast<const Animation::TrackViewStorage<Float>&>(_tracks[id]._view));
CORRADE_ASSERT(id < _tracks.size(), "Trade::AnimationData::track(): index out of range", reinterpret_cast<const Animation::TrackViewStorage<Float>&>(_tracks[id]._view));
return reinterpret_cast<const Animation::TrackViewStorage<Float>&>(_tracks[id]._view);
}
template<class V, class R> auto animationInterpolatorFor(Animation::Interpolation interpolation) -> R(*)(const V&, const V&, Float) { template<class V, class R> auto animationInterpolatorFor(Animation::Interpolation interpolation) -> R(*)(const V&, const V&, Float) {
return Animation::interpolatorFor<V, R>(interpolation); return Animation::interpolatorFor<V, R>(interpolation);
} }

132
src/Magnum/Trade/AnimationData.h

@ -32,6 +32,7 @@
#include "Magnum/Magnum.h" #include "Magnum/Magnum.h"
#include "Magnum/Math/Math.h" #include "Magnum/Math/Math.h"
#include "Magnum/Animation/Track.h" #include "Magnum/Animation/Track.h"
#include "Magnum/Trade/Data.h"
#include "Magnum/Trade/Trade.h" #include "Magnum/Trade/Trade.h"
#include "Magnum/Trade/visibility.h" #include "Magnum/Trade/visibility.h"
@ -278,12 +279,26 @@ array is then updated during calls to @ref Animation::Player::advance().
It's also possible to directly update object transformations using callbacks, It's also possible to directly update object transformations using callbacks,
among other things. See documentation of the @ref Animation::Player class for among other things. See documentation of the @ref Animation::Player class for
more information. more information.
@section Trade-AnimationData-usage-mutable Mutable data access
The interfaces implicitly provide @cpp const @ce views on the contained
keyframe data through the @ref data() and @ref track() accessors. This is done
because in general case the data can also refer to a memory-mapped file or
constant memory. In cases when it's desirable to modify the data in-place,
there's the @ref mutableData() and @ref mutableTrack() set of functions. To use
these, you need to check that the data are mutable using @ref dataFlags()
first. The following snippet inverts the Y coordinate of a translation
animation:
@snippet MagnumTrade.cpp AnimationData-usage-mutable
@experimental @experimental
*/ */
class MAGNUM_TRADE_EXPORT AnimationData { class MAGNUM_TRADE_EXPORT AnimationData {
public: public:
/** /**
* @brief Construct with implicit duration * @brief Construct an animation data
* @param data Buffer containing all keyframe data for this * @param data Buffer containing all keyframe data for this
* animation clip * animation clip
* @param tracks Track data * @param tracks Track data
@ -292,11 +307,33 @@ class MAGNUM_TRADE_EXPORT AnimationData {
* Each item of @p track should have an @ref Animation::TrackView * Each item of @p track should have an @ref Animation::TrackView
* instance pointing its key/value views to @p data. The @ref duration() * instance pointing its key/value views to @p data. The @ref duration()
* is automatically calculated from durations of all tracks. * is automatically calculated from durations of all tracks.
*
* The @ref dataFlags() are implicitly set to a combination of
* @ref DataFlag::Owned and @ref DataFlag::Mutable. For non-owned data
* use the @ref AnimationData(DataFlags, Containers::ArrayView<const void>, Containers::Array<AnimationTrackData>&&, const void*)
* constructor instead.
*/ */
explicit AnimationData(Containers::Array<char>&& data, Containers::Array<AnimationTrackData>&& tracks, const void* importerState = nullptr) noexcept; explicit AnimationData(Containers::Array<char>&& data, Containers::Array<AnimationTrackData>&& tracks, const void* importerState = nullptr) noexcept;
/** /**
* @brief Construct with explicit duration * @brief Construct a non-owned animation data
* @param dataFlags Data flags
* @param data View on a buffer containing all keyframe data
* for this animation clip
* @param tracks Track data
* @param importerState Importer-specific state
* @m_since_latest
*
* Compared to @ref AnimationData(Containers::Array<char>&&, Containers::Array<AnimationTrackData>&&, const void*)
* creates an instance that doesn't own the passed data. The
* @p dataFlags parameter can contain @ref DataFlag::Mutable to
* indicate the external data can be modified, and is expected to *not*
* have @ref DataFlag::Owned set.
*/
explicit AnimationData(DataFlags dataFlags, Containers::ArrayView<const void> data, Containers::Array<AnimationTrackData>&& tracks, const void* importerState = nullptr) noexcept;
/**
* @brief Construct an animation data with explicit duration
* @param data Buffer containing all keyframe data for this * @param data Buffer containing all keyframe data for this
* animation clip * animation clip
* @param tracks Track data * @param tracks Track data
@ -305,9 +342,32 @@ class MAGNUM_TRADE_EXPORT AnimationData {
* *
* Each item of @p track should have an @ref Animation::TrackView * Each item of @p track should have an @ref Animation::TrackView
* instance pointing its key/value views to @p data. * instance pointing its key/value views to @p data.
*
* The @ref dataFlags() are implicitly set to a combination of
* @ref DataFlag::Owned and @ref DataFlag::Mutable. For non-owned data
* use the @ref AnimationData(DataFlags, Containers::ArrayView<const void>, Containers::Array<AnimationTrackData>&&, const Range1D&, const void*)
* constructor instead.
*/ */
explicit AnimationData(Containers::Array<char>&& data, Containers::Array<AnimationTrackData>&& tracks, const Range1D& duration, const void* importerState = nullptr) noexcept; explicit AnimationData(Containers::Array<char>&& data, Containers::Array<AnimationTrackData>&& tracks, const Range1D& duration, const void* importerState = nullptr) noexcept;
/**
* @brief Construct a non-owned animation data with explicit duration
* @param dataFlags Data flags
* @param data View on a buffer containing all keyframe data
* for this animation clip
* @param tracks Track data
* @param duration Animation track duration
* @param importerState Importer-specific state
* @m_since_latest
*
* Compared to @ref AnimationData(Containers::Array<char>&&, Containers::Array<AnimationTrackData>&&, const Range1D&, const void*)
* creates an instance that doesn't own the passed data. The
* @p dataFlags parameter can contain @ref DataFlag::Mutable to
* indicate the external data can be modified, and is expected to *not*
* have @ref DataFlag::Owned set.
*/
explicit AnimationData(DataFlags dataFlags, Containers::ArrayView<const void> data, Containers::Array<AnimationTrackData>&& tracks, const Range1D& duration, const void* importerState = nullptr) noexcept;
~AnimationData(); ~AnimationData();
/** @brief Copying is not allowed */ /** @brief Copying is not allowed */
@ -322,18 +382,40 @@ class MAGNUM_TRADE_EXPORT AnimationData {
/** @brief Move assignment */ /** @brief Move assignment */
AnimationData& operator=(AnimationData&&) noexcept; AnimationData& operator=(AnimationData&&) noexcept;
/**
* @brief Data flags
* @m_since_latest
*
* @see @ref release(), @ref mutableData(), @ref mutableTrack()
*/
DataFlags dataFlags() const { return _dataFlags; }
/** /**
* @brief Raw data * @brief Raw data
* *
* Contains data for all tracks contained in this clip. * Contains data for all tracks contained in this clip.
* @see @ref release() * @see @ref release(), @ref mutableData()
*/ */
Containers::ArrayView<char> data() & { return _data; }
Containers::ArrayView<char> data() && = delete; /**< @overload */
/** @overload */
Containers::ArrayView<const char> data() const & { return _data; } Containers::ArrayView<const char> data() const & { return _data; }
Containers::ArrayView<const char> data() const && = delete; /**< @overload */
/** @brief Taking a view to a r-value instance is not allowed */
Containers::ArrayView<const char> data() const && = delete;
/**
* @brief Mutable raw data
* @m_since_latest
*
* Like @ref data(), but returns a non-const view. Expects that the
* animation is mutable.
* @see @ref dataFlags()
*/
Containers::ArrayView<char> mutableData() &;
/**
* @brief Taking a view to a r-value instance is not allowed
* @m_since_latest
*/
Containers::ArrayView<char> mutableData() && = delete;
/** @brief Duration */ /** @brief Duration */
Range1D duration() const { return _duration; } Range1D duration() const { return _duration; }
@ -402,6 +484,16 @@ class MAGNUM_TRADE_EXPORT AnimationData {
*/ */
const Animation::TrackViewStorage<const Float>& track(UnsignedInt id) const; const Animation::TrackViewStorage<const Float>& track(UnsignedInt id) const;
/**
* @brief Mutable track data storage
* @m_since_latest
*
* Like @ref track(), but returns a mutable view. Expects that the
* animation is mutable.
* @see @ref dataFlags()
*/
const Animation::TrackViewStorage<Float>& mutableTrack(UnsignedInt id);
/** /**
* @brief Track data * @brief Track data
* @tparam V Track value type * @tparam V Track value type
@ -416,12 +508,24 @@ class MAGNUM_TRADE_EXPORT AnimationData {
*/ */
template<class V, class R = Animation::ResultOf<V>> const Animation::TrackView<const Float, const V, R>& track(UnsignedInt id) const; template<class V, class R = Animation::ResultOf<V>> const Animation::TrackView<const Float, const V, R>& track(UnsignedInt id) const;
/**
* @brief Mutable track data
* @m_since_latest
*
* Like @ref track(), but returns a mutable view. Expects that the
* animation is mutable.
* @see @ref dataFlags()
*/
template<class V, class R = Animation::ResultOf<V>> const Animation::TrackView<Float, V, R>& mutableTrack(UnsignedInt id);
/** /**
* @brief Release data storage * @brief Release data storage
* *
* Releases the ownership of the data array and resets internal state * Releases the ownership of the data array and resets internal state
* to default. * to default. Note that the returned array has a custom no-op deleter
* @see @ref data() * when the data are not owned by the animation, and while the returned
* array type is mutable, the actual memory might be not.
* @see @ref data(), @ref dataFlags()
*/ */
Containers::Array<char> release() { return std::move(_data); } Containers::Array<char> release() { return std::move(_data); }
@ -438,6 +542,7 @@ class MAGNUM_TRADE_EXPORT AnimationData {
implementations. */ implementations. */
friend AbstractImporter; friend AbstractImporter;
DataFlags _dataFlags;
Range1D _duration; Range1D _duration;
Containers::Array<char> _data; Containers::Array<char> _data;
Containers::Array<AnimationTrackData> _tracks; Containers::Array<AnimationTrackData> _tracks;
@ -512,6 +617,13 @@ template<class V, class R> const Animation::TrackView<const Float, const V, R>&
return static_cast<const Animation::TrackView<const Float, const V, R>&>(storage); return static_cast<const Animation::TrackView<const Float, const V, R>&>(storage);
} }
template<class V, class R> const Animation::TrackView<Float, V, R>& AnimationData::mutableTrack(UnsignedInt id) {
const Animation::TrackViewStorage<Float>& storage = mutableTrack(id);
CORRADE_ASSERT(Implementation::animationTypeFor<V>() == _tracks[id]._type, "Trade::AnimationData::mutableTrack(): improper type requested for" << _tracks[id]._type, (static_cast<const Animation::TrackView<Float, V, R>&>(storage)));
CORRADE_ASSERT(Implementation::animationTypeFor<R>() == _tracks[id]._resultType, "Trade::AnimationData::mutableTrack(): improper result type requested for" << _tracks[id]._resultType, (static_cast<const Animation::TrackView<Float, V, R>&>(storage)));
return static_cast<const Animation::TrackView<Float, V, R>&>(storage);
}
}} }}
#endif #endif

7
src/Magnum/Trade/Data.h

@ -41,8 +41,8 @@ namespace Magnum { namespace Trade {
@brief Data flag @brief Data flag
@m_since_latest @m_since_latest
@see @ref DataFlags, @ref MeshData::indexDataFlags(), @see @ref DataFlags, @ref AnimationData::dataFlags(),
@ref MeshData::vertexDataFlags() @ref MeshData::indexDataFlags(), @ref MeshData::vertexDataFlags()
*/ */
enum class DataFlag: UnsignedByte { enum class DataFlag: UnsignedByte {
/** /**
@ -71,7 +71,8 @@ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, DataFlag value);
@brief Data flags @brief Data flags
@m_since_latest @m_since_latest
@see @ref MeshData::indexDataFlags(), @ref MeshData::vertexDataFlags() @see @ref AnimationData::dataFlags(), @ref MeshData::indexDataFlags(),
@ref MeshData::vertexDataFlags()
*/ */
typedef Containers::EnumSet<DataFlag> DataFlags; typedef Containers::EnumSet<DataFlag> DataFlags;

188
src/Magnum/Trade/Test/AnimationDataTest.cpp

@ -36,15 +36,21 @@ struct AnimationDataTest: TestSuite::Tester {
explicit AnimationDataTest(); explicit AnimationDataTest();
void construct(); void construct();
void constructNotOwned();
void constructImplicitDuration(); void constructImplicitDuration();
void constructImplicitDurationEmpty(); void constructImplicitDurationEmpty();
void constructImplicitDurationNotOwned();
void constructNotOwnedFlagOwned();
void constructImplicitDurationNotOwnedFlagOwned();
void constructCopy(); void constructCopy();
void constructMove(); void constructMove();
void constructTrackDataDefault(); void constructTrackDataDefault();
void trackCustomResultType(); void mutableAccessNotAllowed();
void trackCustomResultType();
void trackWrongIndex(); void trackWrongIndex();
void trackWrongType(); void trackWrongType();
void trackWrongResultType(); void trackWrongResultType();
@ -53,17 +59,34 @@ struct AnimationDataTest: TestSuite::Tester {
void debugAnimationTrackTargetType(); void debugAnimationTrackTargetType();
}; };
struct {
const char* name;
DataFlags dataFlags;
} NotOwnedData[] {
{"", {}},
{"mutable", DataFlag::Mutable},
};
AnimationDataTest::AnimationDataTest() { AnimationDataTest::AnimationDataTest() {
addTests({&AnimationDataTest::construct, addTests({&AnimationDataTest::construct,
&AnimationDataTest::constructImplicitDuration, &AnimationDataTest::constructImplicitDuration,
&AnimationDataTest::constructImplicitDurationEmpty, &AnimationDataTest::constructImplicitDurationEmpty});
addInstancedTests({&AnimationDataTest::constructNotOwned,
&AnimationDataTest::constructImplicitDurationNotOwned},
Containers::arraySize(NotOwnedData));
addTests({&AnimationDataTest::constructNotOwnedFlagOwned,
&AnimationDataTest::constructImplicitDurationNotOwnedFlagOwned,
&AnimationDataTest::constructCopy, &AnimationDataTest::constructCopy,
&AnimationDataTest::constructMove, &AnimationDataTest::constructMove,
&AnimationDataTest::constructTrackDataDefault, &AnimationDataTest::constructTrackDataDefault,
&AnimationDataTest::trackCustomResultType, &AnimationDataTest::mutableAccessNotAllowed,
&AnimationDataTest::trackCustomResultType,
&AnimationDataTest::trackWrongIndex, &AnimationDataTest::trackWrongIndex,
&AnimationDataTest::trackWrongType, &AnimationDataTest::trackWrongType,
&AnimationDataTest::trackWrongResultType, &AnimationDataTest::trackWrongResultType,
@ -106,8 +129,10 @@ void AnimationDataTest::construct() {
animationInterpolatorFor<Quaternion>(Animation::Interpolation::Linear)}} animationInterpolatorFor<Quaternion>(Animation::Interpolation::Linear)}}
}}, {-1.0f, 7.0f}, &state}; }}, {-1.0f, 7.0f}, &state};
CORRADE_COMPARE(data.dataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(data.duration(), (Range1D{-1.0f, 7.0f})); CORRADE_COMPARE(data.duration(), (Range1D{-1.0f, 7.0f}));
CORRADE_COMPARE(data.data().size(), sizeof(Data)*3); CORRADE_COMPARE(static_cast<const void*>(data.data().data()), view.data());
CORRADE_COMPARE(static_cast<void*>(data.mutableData().data()), view.data());
CORRADE_COMPARE(data.trackCount(), 2); CORRADE_COMPARE(data.trackCount(), 2);
CORRADE_COMPARE(data.importerState(), &state); CORRADE_COMPARE(data.importerState(), &state);
@ -122,6 +147,12 @@ void AnimationDataTest::construct() {
CORRADE_COMPARE(track.values().size(), 3); CORRADE_COMPARE(track.values().size(), 3);
CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Constant); CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(track.at(2.5f), (Vector3{3.0f, 1.0f, 0.1f})); CORRADE_COMPARE(track.at(2.5f), (Vector3{3.0f, 1.0f, 0.1f}));
Animation::TrackView<Float, Vector3> mutableTrack = data.mutableTrack<Vector3>(0);
CORRADE_COMPARE(mutableTrack.keys().size(), 3);
CORRADE_COMPARE(mutableTrack.values().size(), 3);
CORRADE_COMPARE(mutableTrack.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(mutableTrack.at(2.5f), (Vector3{3.0f, 1.0f, 0.1f}));
} { } {
CORRADE_COMPARE(data.trackType(1), AnimationTrackType::Quaternion); CORRADE_COMPARE(data.trackType(1), AnimationTrackType::Quaternion);
CORRADE_COMPARE(data.trackResultType(1), AnimationTrackType::Quaternion); CORRADE_COMPARE(data.trackResultType(1), AnimationTrackType::Quaternion);
@ -133,6 +164,8 @@ void AnimationDataTest::construct() {
CORRADE_COMPARE(track.values().size(), 3); CORRADE_COMPARE(track.values().size(), 3);
CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Linear); CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Linear);
CORRADE_COMPARE(track.at(2.5f), Quaternion::rotation(32.5_degf, Vector3::yAxis())); CORRADE_COMPARE(track.at(2.5f), Quaternion::rotation(32.5_degf, Vector3::yAxis()));
/* Testing the mutable track just once is enough */
} }
} }
@ -166,6 +199,7 @@ void AnimationDataTest::constructImplicitDuration() {
Animation::Interpolation::Linear}} Animation::Interpolation::Linear}}
}}, &state}; }}, &state};
CORRADE_COMPARE(data.dataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(data.duration(), (Range1D{1.0f, 7.0f})); CORRADE_COMPARE(data.duration(), (Range1D{1.0f, 7.0f}));
CORRADE_COMPARE(data.trackCount(), 2); CORRADE_COMPARE(data.trackCount(), 2);
CORRADE_COMPARE(data.importerState(), &state); CORRADE_COMPARE(data.importerState(), &state);
@ -181,6 +215,13 @@ void AnimationDataTest::constructImplicitDuration() {
CORRADE_COMPARE(track.values().size(), 2); CORRADE_COMPARE(track.values().size(), 2);
CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Constant); CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(track.at(6.0f), false); CORRADE_COMPARE(track.at(6.0f), false);
Animation::TrackView<Float, bool> mutableTrack = data.mutableTrack<bool>(0);
CORRADE_COMPARE(mutableTrack.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(mutableTrack.keys().size(), 2);
CORRADE_COMPARE(mutableTrack.values().size(), 2);
CORRADE_COMPARE(mutableTrack.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(mutableTrack.at(6.0f), false);
} { } {
CORRADE_COMPARE(data.trackType(1), AnimationTrackType::Bool); CORRADE_COMPARE(data.trackType(1), AnimationTrackType::Bool);
CORRADE_COMPARE(data.trackResultType(1), AnimationTrackType::Bool); CORRADE_COMPARE(data.trackResultType(1), AnimationTrackType::Bool);
@ -193,6 +234,8 @@ void AnimationDataTest::constructImplicitDuration() {
CORRADE_COMPARE(track.values().size(), 2); CORRADE_COMPARE(track.values().size(), 2);
CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Linear); CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Linear);
CORRADE_COMPARE(track.at(4.5f), true); CORRADE_COMPARE(track.at(4.5f), true);
/* Testing the mutable track just once is enough */
} }
} }
@ -201,6 +244,119 @@ void AnimationDataTest::constructImplicitDurationEmpty() {
CORRADE_COMPARE(data.duration(), Range1D{}); CORRADE_COMPARE(data.duration(), Range1D{});
} }
void AnimationDataTest::constructNotOwned() {
auto&& instanceData = NotOwnedData[testCaseInstanceId()];
setTestCaseDescription(instanceData.name);
std::pair<Float, Vector3> keyframes[] {
{0.0f, {3.0f, 1.0f, 0.1f}},
{5.0f, {0.3f, 0.6f, 1.0f}}
};
const int state = 5;
AnimationData data{instanceData.dataFlags, keyframes, Containers::Array<AnimationTrackData>{Containers::InPlaceInit, {
{AnimationTrackType::Vector3,
AnimationTrackTargetType::Translation3D, 42,
Animation::TrackView<const Float, const Vector3>{
keyframes,
Animation::Interpolation::Constant,
animationInterpolatorFor<Vector3>(Animation::Interpolation::Constant)}}
}}, {-1.0f, 7.0f}, &state};
CORRADE_COMPARE(data.dataFlags(), instanceData.dataFlags);
CORRADE_COMPARE(data.duration(), (Range1D{-1.0f, 7.0f}));
CORRADE_COMPARE(static_cast<const void*>(data.data().data()), keyframes);
if(instanceData.dataFlags & DataFlag::Mutable)
CORRADE_COMPARE(static_cast<const void*>(data.mutableData().data()), keyframes);
CORRADE_COMPARE(data.trackCount(), 1);
CORRADE_COMPARE(data.importerState(), &state);
{
CORRADE_COMPARE(data.trackType(0), AnimationTrackType::Vector3);
CORRADE_COMPARE(data.trackResultType(0), AnimationTrackType::Vector3);
CORRADE_COMPARE(data.trackTargetType(0), AnimationTrackTargetType::Translation3D);
CORRADE_COMPARE(data.trackTarget(0), 42);
Animation::TrackView<const Float, const Vector3> track = data.track<Vector3>(0);
CORRADE_COMPARE(track.keys().size(), 2);
CORRADE_COMPARE(track.values().size(), 2);
CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(track.at(2.5f), (Vector3{3.0f, 1.0f, 0.1f}));
if(instanceData.dataFlags & DataFlag::Mutable) {
Animation::TrackView<Float, Vector3> mutableTrack = data.mutableTrack<Vector3>(0);
CORRADE_COMPARE(mutableTrack.keys().size(), 2);
CORRADE_COMPARE(mutableTrack.values().size(), 2);
CORRADE_COMPARE(mutableTrack.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(mutableTrack.at(2.5f), (Vector3{3.0f, 1.0f, 0.1f}));
}
}
}
void AnimationDataTest::constructImplicitDurationNotOwned() {
auto&& instanceData = NotOwnedData[testCaseInstanceId()];
setTestCaseDescription(instanceData.name);
std::pair<Float, bool> keyframes[] {
{1.0f, true},
{5.0f, false}
};
const int state = 5;
AnimationData data{instanceData.dataFlags, keyframes, Containers::Array<AnimationTrackData>{Containers::InPlaceInit, {
{AnimationTrackType::Bool,
AnimationTrackTargetType(129), 0,
Animation::TrackView<const Float, const bool>{keyframes, Animation::Interpolation::Constant}},
}}, &state};
CORRADE_COMPARE(data.dataFlags(), instanceData.dataFlags);
CORRADE_COMPARE(data.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(static_cast<const void*>(data.data().data()), keyframes);
if(instanceData.dataFlags & DataFlag::Mutable)
CORRADE_COMPARE(static_cast<const void*>(data.mutableData().data()), keyframes);
CORRADE_COMPARE(data.trackCount(), 1);
CORRADE_COMPARE(data.importerState(), &state);
{
CORRADE_COMPARE(data.trackType(0), AnimationTrackType::Bool);
CORRADE_COMPARE(data.trackResultType(0), AnimationTrackType::Bool);
CORRADE_COMPARE(data.trackTargetType(0), AnimationTrackTargetType(129));
CORRADE_COMPARE(data.trackTarget(0), 0);
Animation::TrackView<const Float, const bool> track = data.track<bool>(0);
CORRADE_COMPARE(track.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(track.keys().size(), 2);
CORRADE_COMPARE(track.values().size(), 2);
CORRADE_COMPARE(track.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(track.at(3.0f), true);
if(instanceData.dataFlags & DataFlag::Mutable) {
Animation::TrackView<Float, bool> mutableTrack = data.mutableTrack<bool>(0);
CORRADE_COMPARE(mutableTrack.duration(), (Range1D{1.0f, 5.0f}));
CORRADE_COMPARE(mutableTrack.keys().size(), 2);
CORRADE_COMPARE(mutableTrack.values().size(), 2);
CORRADE_COMPARE(mutableTrack.interpolation(), Animation::Interpolation::Constant);
CORRADE_COMPARE(mutableTrack.at(3.0f), true);
}
}
}
void AnimationDataTest::constructNotOwnedFlagOwned() {
std::ostringstream out;
Error redirectError{&out};
AnimationData data{DataFlag::Owned, nullptr, {}, {-1.0f, 7.0f}};
CORRADE_COMPARE(out.str(),
"Trade::AnimationData: can't construct a non-owned instance with Trade::DataFlag::Owned\n");
}
void AnimationDataTest::constructImplicitDurationNotOwnedFlagOwned() {
std::ostringstream out;
Error redirectError{&out};
AnimationData data{DataFlag::Owned, nullptr, {}};
CORRADE_COMPARE(out.str(),
"Trade::AnimationData: can't construct a non-owned instance with Trade::DataFlag::Owned\n");
}
void AnimationDataTest::constructCopy() { void AnimationDataTest::constructCopy() {
CORRADE_VERIFY(!(std::is_constructible<AnimationData, const AnimationData&>{})); CORRADE_VERIFY(!(std::is_constructible<AnimationData, const AnimationData&>{}));
CORRADE_VERIFY(!(std::is_assignable<AnimationData, const AnimationData&>{})); CORRADE_VERIFY(!(std::is_assignable<AnimationData, const AnimationData&>{}));
@ -310,6 +466,30 @@ void AnimationDataTest::constructTrackDataDefault() {
CORRADE_VERIFY(true); /* no public accessors here, so nothing to check */ CORRADE_VERIFY(true); /* no public accessors here, so nothing to check */
} }
void AnimationDataTest::mutableAccessNotAllowed() {
const std::pair<Float, bool> keyframes[] {
{1.0f, true},
{5.0f, false}
};
AnimationData data{{}, keyframes, Containers::Array<AnimationTrackData>{Containers::InPlaceInit, {
{AnimationTrackType::Bool,
AnimationTrackTargetType(129), 0,
Animation::TrackView<const Float, const bool>{keyframes, Animation::Interpolation::Constant}},
}}};
CORRADE_COMPARE(data.dataFlags(), DataFlags{});
std::ostringstream out;
Error redirectError{&out};
data.mutableData();
data.mutableTrack(0);
data.mutableTrack<bool>(0);
CORRADE_COMPARE(out.str(),
"Trade::AnimationData::mutableData(): the animation is not mutable\n"
"Trade::AnimationData::mutableTrack(): the animation is not mutable\n"
"Trade::AnimationData::mutableTrack(): the animation is not mutable\n");
}
void AnimationDataTest::trackCustomResultType() { void AnimationDataTest::trackCustomResultType() {
using namespace Math::Literals; using namespace Math::Literals;

Loading…
Cancel
Save