diff --git a/src/Magnum/Trade/AnimationData.cpp b/src/Magnum/Trade/AnimationData.cpp index b965d8258..f8fa56134 100644 --- a/src/Magnum/Trade/AnimationData.cpp +++ b/src/Magnum/Trade/AnimationData.cpp @@ -198,8 +198,8 @@ Debug& operator<<(Debug& debug, const AnimationTrackTarget value) { if(!packed) debug << "Trade::AnimationTrackTarget" << Debug::nospace; - if(UnsignedShort(value) >= UnsignedShort(AnimationTrackTarget::Custom)) - return debug << (packed ? "Custom(" : "::Custom(") << Debug::nospace << UnsignedShort(value) << Debug::nospace << ")"; + if(isAnimationTrackTargetCustom(value)) + return debug << (packed ? "Custom(" : "::Custom(") << Debug::nospace << animationTrackTargetCustom(value) << Debug::nospace << ")"; switch(value) { /* LCOV_EXCL_START */ @@ -213,8 +213,12 @@ Debug& operator<<(Debug& debug, const AnimationTrackTarget value) { #undef _c /* LCOV_EXCL_STOP */ + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_IGNORE_DEPRECATED_PUSH /* To silence compiler warnings about unhandled values */ case AnimationTrackTarget::Custom: CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + CORRADE_IGNORE_DEPRECATED_POP + #endif } return debug << (packed ? "" : "(") << Debug::nospace << reinterpret_cast(UnsignedShort(value)) << Debug::nospace << (packed ? "" : ")"); diff --git a/src/Magnum/Trade/AnimationData.h b/src/Magnum/Trade/AnimationData.h index b3f72c8f9..c286bce85 100644 --- a/src/Magnum/Trade/AnimationData.h +++ b/src/Magnum/Trade/AnimationData.h @@ -165,10 +165,23 @@ enum class AnimationTrackType: UnsignedByte { /** @debugoperatorenum{AnimationTrackType} */ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, AnimationTrackType value); +namespace Implementation { + enum: UnsignedShort { AnimationTrackTargetCustom = 32768 }; +} + /** @brief Target of an animation track -@see @ref AnimationData +See @ref AnimationData for more information. + +Apart from builtin target types it's possible to have custom ones, which use +the upper half of the enum range. Those are detected via +@ref isAnimationTrackTargetCustom() and can be converted to and from a +numeric identifier using @ref animationTrackTargetCustom(AnimationTrackTarget) +and @ref animationTrackTargetCustom(UnsignedShort). Unlike the builtin ones, +these can be of any type and @ref AnimationData::trackTarget() might or might +not point to an existing object. +@see @ref AnimationTrackData @experimental */ enum class AnimationTrackTarget: UnsignedShort { @@ -246,13 +259,15 @@ enum class AnimationTrackTarget: UnsignedShort { */ Scaling3D, + #ifdef MAGNUM_BUILD_DEPRECATED /** - * This and all higher values are for importer-specific targets. Can be of - * any type, @ref AnimationData::trackTarget() might or might not point to - * an existing object. See documentation of a particular importer for - * details. + * This and all higher values are for importer-specific targets. + * + * @m_deprecated_since_latest Use @ref animationTrackTargetCustom() and + * @ref isAnimationTrackTargetCustom() instead. */ - Custom = 32768 + Custom CORRADE_DEPRECATED_ENUM("use animationTrackTargetCustom() instead") = Implementation::AnimationTrackTargetCustom + #endif }; #ifdef MAGNUM_BUILD_DEPRECATED @@ -266,6 +281,50 @@ typedef CORRADE_DEPRECATED("use AnimationTrackTarget instead") AnimationTrackTar /** @debugoperatorenum{AnimationTrackTarget} */ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, AnimationTrackTarget value); +/** +@brief Whether a target for an animation track is custom +@m_since_latest + +Returns @cpp true @ce if @p name has a value in the upper 15 bits of the enum +range, @cpp false @ce otherwise. +@see @ref animationTrackTargetCustom(UnsignedShort), + @ref animationTrackTargetCustom(AnimationTrackTarget) +*/ +constexpr bool isAnimationTrackTargetCustom(AnimationTrackTarget name) { + return UnsignedShort(name) >= Implementation::AnimationTrackTargetCustom; +} + +/** +@brief Create a custom target for an animation track +@m_since_latest + +Returns a custom animation track target with index @p id. The index is expected +to fit into 15 bits. Use +@ref animationTrackTargetCustom(AnimationTrackTarget) to get the index +back. +*/ +/* Constexpr so it's usable for creating compile-time AnimationData + instances */ +constexpr AnimationTrackTarget animationTrackTargetCustom(UnsignedShort id) { + return CORRADE_CONSTEXPR_ASSERT(id < Implementation::AnimationTrackTargetCustom, + "Trade::animationTrackTargetCustom(): index" << id << "too large"), + AnimationTrackTarget(Implementation::AnimationTrackTargetCustom + id); +} + +/** +@brief Get index of a custom target for an animation track +@m_since_latest + +Inverse to @ref animationTrackTargetCustom(UnsignedShort). Expects that the +type is custom. +@see @ref isAnimationTrackTargetCustom() +*/ +constexpr UnsignedShort animationTrackTargetCustom(AnimationTrackTarget name) { + return CORRADE_CONSTEXPR_ASSERT(isAnimationTrackTargetCustom(name), + "Trade::animationTrackTargetCustom():" << name << "is not custom"), + UnsignedShort(name) - Implementation::AnimationTrackTargetCustom; +} + /** @brief Animation track data diff --git a/src/Magnum/Trade/Test/AnimationDataTest.cpp b/src/Magnum/Trade/Test/AnimationDataTest.cpp index 7298e760d..3234603a2 100644 --- a/src/Magnum/Trade/Test/AnimationDataTest.cpp +++ b/src/Magnum/Trade/Test/AnimationDataTest.cpp @@ -38,6 +38,10 @@ struct AnimationDataTest: TestSuite::Tester { void debugTrackType(); void debugTrackTypePacked(); + + void customTrackTarget(); + void customTrackTargetTooLarge(); + void customTrackTargetNotCustom(); void debugTrackTarget(); void debugTrackTargetPacked(); @@ -78,6 +82,10 @@ struct { AnimationDataTest::AnimationDataTest() { addTests({&AnimationDataTest::debugTrackType, &AnimationDataTest::debugTrackTypePacked, + + &AnimationDataTest::customTrackTarget, + &AnimationDataTest::customTrackTargetTooLarge, + &AnimationDataTest::customTrackTargetNotCustom, &AnimationDataTest::debugTrackTarget, &AnimationDataTest::debugTrackTargetPacked, @@ -126,18 +134,58 @@ void AnimationDataTest::debugTrackTypePacked() { CORRADE_COMPARE(out.str(), "DualQuaternion 0xde Trade::AnimationTrackType::Float\n"); } +void AnimationDataTest::customTrackTarget() { + CORRADE_VERIFY(!isAnimationTrackTargetCustom(AnimationTrackTarget::Rotation3D)); + CORRADE_VERIFY(!isAnimationTrackTargetCustom(AnimationTrackTarget(32767))); + CORRADE_VERIFY(isAnimationTrackTargetCustom(AnimationTrackTarget(Implementation::AnimationTrackTargetCustom))); + CORRADE_VERIFY(isAnimationTrackTargetCustom(AnimationTrackTarget(65535))); + + CORRADE_COMPARE(UnsignedShort(animationTrackTargetCustom(0)), 32768); + CORRADE_COMPARE(UnsignedShort(animationTrackTargetCustom(8290)), 41058); + CORRADE_COMPARE(UnsignedShort(animationTrackTargetCustom(32767)), 65535); + + CORRADE_COMPARE(animationTrackTargetCustom(AnimationTrackTarget(Implementation::AnimationTrackTargetCustom)), 0); + CORRADE_COMPARE(animationTrackTargetCustom(AnimationTrackTarget(41058)), 8290); + CORRADE_COMPARE(animationTrackTargetCustom(AnimationTrackTarget(65535)), 32767); + + constexpr bool is = isAnimationTrackTargetCustom(AnimationTrackTarget(41058)); + CORRADE_VERIFY(is); + constexpr AnimationTrackTarget a = animationTrackTargetCustom(8290); + CORRADE_COMPARE(UnsignedShort(a), 41058); + constexpr UnsignedShort b = animationTrackTargetCustom(a); + CORRADE_COMPARE(b, 8290); +} + +void AnimationDataTest::customTrackTargetTooLarge() { + CORRADE_SKIP_IF_NO_ASSERT(); + + std::ostringstream out; + Error redirectError{&out}; + animationTrackTargetCustom(32768); + CORRADE_COMPARE(out.str(), "Trade::animationTrackTargetCustom(): index 32768 too large\n"); +} + +void AnimationDataTest::customTrackTargetNotCustom() { + CORRADE_SKIP_IF_NO_ASSERT(); + + std::ostringstream out; + Error redirectError{&out}; + animationTrackTargetCustom(AnimationTrackTarget::Translation2D); + CORRADE_COMPARE(out.str(), "Trade::animationTrackTargetCustom(): Trade::AnimationTrackTarget::Translation2D is not custom\n"); +} + void AnimationDataTest::debugTrackTarget() { std::ostringstream out; - Debug{&out} << AnimationTrackTarget::Rotation3D << AnimationTrackTarget(32777) << AnimationTrackTarget(0x4242); - CORRADE_COMPARE(out.str(), "Trade::AnimationTrackTarget::Rotation3D Trade::AnimationTrackTarget::Custom(32777) Trade::AnimationTrackTarget(0x4242)\n"); + Debug{&out} << AnimationTrackTarget::Rotation3D << animationTrackTargetCustom(9) << AnimationTrackTarget(0x4242); + CORRADE_COMPARE(out.str(), "Trade::AnimationTrackTarget::Rotation3D Trade::AnimationTrackTarget::Custom(9) Trade::AnimationTrackTarget(0x4242)\n"); } void AnimationDataTest::debugTrackTargetPacked() { std::ostringstream out; /* Last is not packed, ones before should not make any flags persistent */ - Debug{&out} << Debug::packed << AnimationTrackTarget::Rotation3D << Debug::packed << AnimationTrackTarget(32888) << Debug::packed << AnimationTrackTarget(0x4242) << AnimationTrackType::Float; - CORRADE_COMPARE(out.str(), "Rotation3D Custom(32888) 0x4242 Trade::AnimationTrackType::Float\n"); + Debug{&out} << Debug::packed << AnimationTrackTarget::Rotation3D << Debug::packed << animationTrackTargetCustom(120) << Debug::packed << AnimationTrackTarget(0x4242) << AnimationTrackType::Float; + CORRADE_COMPARE(out.str(), "Rotation3D Custom(120) 0x4242 Trade::AnimationTrackType::Float\n"); } void AnimationDataTest::constructTrack() { @@ -277,12 +325,12 @@ void AnimationDataTest::constructImplicitDuration() { const int state = 5; AnimationData data{std::move(buffer), { - AnimationTrackData{AnimationTrackTarget(32769), 0, + AnimationTrackData{animationTrackTargetCustom(1), 0, Animation::TrackView{ {view, &view[0].time, 2, sizeof(Data)}, {view, &view[0].value, 2, sizeof(Data)}, Animation::Interpolation::Constant}}, - AnimationTrackData{AnimationTrackTarget(32770), 1, + AnimationTrackData{animationTrackTargetCustom(2), 1, Animation::TrackView{ {view, &view[2].time, 2, sizeof(Data)}, {view, &view[2].value, 2, sizeof(Data)}, @@ -296,7 +344,7 @@ void AnimationDataTest::constructImplicitDuration() { { CORRADE_COMPARE(data.trackType(0), AnimationTrackType::Bool); CORRADE_COMPARE(data.trackResultType(0), AnimationTrackType::Bool); - CORRADE_COMPARE(data.trackTargetName(0), AnimationTrackTarget(32769)); + CORRADE_COMPARE(data.trackTargetName(0), animationTrackTargetCustom(1)); CORRADE_COMPARE(data.trackTarget(0), 0); Animation::TrackView track = data.track(0); @@ -315,7 +363,7 @@ void AnimationDataTest::constructImplicitDuration() { } { CORRADE_COMPARE(data.trackType(1), AnimationTrackType::Bool); CORRADE_COMPARE(data.trackResultType(1), AnimationTrackType::Bool); - CORRADE_COMPARE(data.trackTargetName(1), AnimationTrackTarget(32770)); + CORRADE_COMPARE(data.trackTargetName(1), animationTrackTargetCustom(2)); CORRADE_COMPARE(data.trackTarget(1), 1); Animation::TrackView track = data.track(1); @@ -393,7 +441,7 @@ void AnimationDataTest::constructImplicitDurationNotOwned() { const int state = 5; AnimationData data{instanceData.dataFlags, keyframes, { - AnimationTrackData{AnimationTrackTarget(32769), 0, + AnimationTrackData{animationTrackTargetCustom(1), 0, Animation::TrackView{keyframes, Animation::Interpolation::Constant}}, }, &state}; @@ -408,7 +456,7 @@ void AnimationDataTest::constructImplicitDurationNotOwned() { { CORRADE_COMPARE(data.trackType(0), AnimationTrackType::Bool); CORRADE_COMPARE(data.trackResultType(0), AnimationTrackType::Bool); - CORRADE_COMPARE(data.trackTargetName(0), AnimationTrackTarget(32769)); + CORRADE_COMPARE(data.trackTargetName(0), animationTrackTargetCustom(1)); CORRADE_COMPARE(data.trackTarget(0), 0); Animation::TrackView track = data.track(0); @@ -560,7 +608,7 @@ void AnimationDataTest::mutableAccessNotAllowed() { }; AnimationData data{{}, keyframes, { - AnimationTrackData{AnimationTrackTarget(32769), 0, + AnimationTrackData{animationTrackTargetCustom(1), 0, Animation::TrackView{keyframes, Animation::Interpolation::Constant}}, }}; CORRADE_COMPARE(data.dataFlags(), DataFlags{}); @@ -668,7 +716,7 @@ void AnimationDataTest::release() { }; AnimationData data{{}, keyframes, { - AnimationTrackData{AnimationTrackTarget(32769), 0, + AnimationTrackData{animationTrackTargetCustom(1), 0, Animation::TrackView{keyframes, Animation::Interpolation::Constant}}, }}; CORRADE_COMPARE(data.trackCount(), 1);