Skip to content

Commit

Permalink
Trade: mutable access in AnimationData.
Browse files Browse the repository at this point in the history
Follows the change done in MeshData.
  • Loading branch information
mosra committed Nov 11, 2019
1 parent 118c609 commit ad441a1
Show file tree
Hide file tree
Showing 5 changed files with 402 additions and 16 deletions.
12 changes: 11 additions & 1 deletion doc/changelog.dox
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ See also:
with @ref Platform::Sdl2Application (see
[mosra/magnum#387](https://github.com/mosra/magnum/pull/387))

@subsubsection changelog-latest-new-trade Trade library

- 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.

@subsection changelog-latest-changes Changes and improvements

- The @ref PixelFormat and @ref CompressedPixelFormat enums can now be saved
Expand Down Expand Up @@ -114,7 +122,9 @@ See also:
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.
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()".
- @ref MeshPrimitive and @ref MeshIndexType now reserve the zero value to
indicate an invalid primitive / type, better catching accidentally
forgotten initialization. Valid code shouldn't be affected by this change,
Expand Down
17 changes: 17 additions & 0 deletions doc/snippets/MagnumTrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,23 @@ Containers::Array<char> animationData = data->release(); /* Take ownership */
/* [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] */
Containers::Array<char> data;
Expand Down
29 changes: 27 additions & 2 deletions src/Magnum/Trade/AnimationData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@

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()) {
/* Reset duration to duration of the first track so it properly support
cases where tracks don't start at 0 */
Expand All @@ -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(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 {
CORRADE_ASSERT(id < _tracks.size(), "Trade::AnimationData::trackType(): index out of range", {});
return _tracks[id]._type;
Expand All @@ -75,6 +93,13 @@ const Animation::TrackViewStorage<const Float>& AnimationData::track(UnsignedInt
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) {
return Animation::interpolatorFor<V, R>(interpolation);
}
Expand Down
123 changes: 113 additions & 10 deletions src/Magnum/Trade/AnimationData.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "Magnum/Magnum.h"
#include "Magnum/Math/Math.h"
#include "Magnum/Animation/Track.h"
#include "Magnum/Trade/Data.h"
#include "Magnum/Trade/Trade.h"
#include "Magnum/Trade/visibility.h"

Expand Down Expand Up @@ -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,
among other things. See documentation of the @ref Animation::Player class for
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
*/
class MAGNUM_TRADE_EXPORT AnimationData {
public:
/**
* @brief Construct with implicit duration
* @brief Construct an animation data
* @param data Buffer containing all keyframe data for this
* animation clip
* @param tracks Track data
Expand All @@ -292,11 +307,32 @@ class MAGNUM_TRADE_EXPORT AnimationData {
* Each item of @p track should have an @ref Animation::TrackView
* instance pointing its key/value views to @p data. The @ref duration()
* 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;

/**
* @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
*
* 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
* animation clip
* @param tracks Track data
Expand All @@ -305,9 +341,31 @@ class MAGNUM_TRADE_EXPORT AnimationData {
*
* Each item of @p track should have an @ref Animation::TrackView
* 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;

/**
* @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
*
* 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();

/** @brief Copying is not allowed */
Expand All @@ -322,18 +380,35 @@ class MAGNUM_TRADE_EXPORT AnimationData {
/** @brief Move assignment */
AnimationData& operator=(AnimationData&&) noexcept;

/**
* @brief Data flags
*
* @see @ref release(), @ref mutableData(), @ref mutableTrack()
*/
DataFlags dataFlags() const { return _dataFlags; }

/**
* @brief Raw data
*
* 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 && = 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
*
* 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 */
Containers::ArrayView<char> mutableData() && = delete;

/** @brief Duration */
Range1D duration() const { return _duration; }
Expand Down Expand Up @@ -402,6 +477,15 @@ class MAGNUM_TRADE_EXPORT AnimationData {
*/
const Animation::TrackViewStorage<const Float>& track(UnsignedInt id) const;

/**
* @brief Mutable track data storage
*
* 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
* @tparam V Track value type
Expand All @@ -416,12 +500,23 @@ 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;

/**
* @brief Mutable track data
*
* 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
*
* Releases the ownership of the data array and resets internal state
* to default.
* @see @ref data()
* to default. Note that the returned array has a custom no-op deleter
* 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); }

Expand All @@ -438,6 +533,7 @@ class MAGNUM_TRADE_EXPORT AnimationData {
implementations. */
friend AbstractImporter;

DataFlags _dataFlags;
Range1D _duration;
Containers::Array<char> _data;
Containers::Array<AnimationTrackData> _tracks;
Expand Down Expand Up @@ -512,6 +608,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);
}

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
Loading

0 comments on commit ad441a1

Please sign in to comment.