From 694e60bb3d62ea6fa926bc31aece4b2e880f1abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 5 Apr 2023 16:43:31 +0200 Subject: [PATCH] Trade: ability to provide names for custom animation track targets. Again, similarly to what's done for custom MeshAttribute and SceneField values already. I'm bumping the importer interface version as adding new virtual functions is a silent ABI breakage, but it's good to do in any case as the AnimationTrackTarget enum was extended to 16 bits and the values got shifted. --- src/Magnum/Trade/AbstractImporter.cpp | 24 +++++- src/Magnum/Trade/AbstractImporter.h | 56 ++++++++++++- src/Magnum/Trade/AnimationData.h | 12 ++- .../Trade/Test/AbstractImporterTest.cpp | 83 +++++++++++++++++++ .../AnyImageImporter/AnyImageImporter.cpp | 2 +- .../AnySceneImporter/AnySceneImporter.cpp | 2 +- src/MagnumPlugins/ObjImporter/ObjImporter.cpp | 2 +- src/MagnumPlugins/TgaImporter/TgaImporter.cpp | 2 +- 8 files changed, 173 insertions(+), 10 deletions(-) diff --git a/src/Magnum/Trade/AbstractImporter.cpp b/src/Magnum/Trade/AbstractImporter.cpp index 8bda00fa6..4b3580420 100644 --- a/src/Magnum/Trade/AbstractImporter.cpp +++ b/src/Magnum/Trade/AbstractImporter.cpp @@ -83,7 +83,7 @@ using namespace Containers::Literals; Containers::StringView AbstractImporter::pluginInterface() { return /* [interface] */ -"cz.mosra.magnum.Trade.AbstractImporter/0.5"_s +"cz.mosra.magnum.Trade.AbstractImporter/0.5.1"_s /* [interface] */ ; } @@ -452,6 +452,28 @@ Containers::Optional AbstractImporter::animation(const Containers return animation(id); /* not doAnimation(), so we get the checks also */ } +AnimationTrackTarget AbstractImporter::animationTrackTargetForName(const Containers::StringView name) { + const AnimationTrackTarget out = doAnimationTrackTargetForName(name); + CORRADE_ASSERT(out == AnimationTrackTarget{} || isAnimationTrackTargetCustom(out), + "Trade::AbstractImporter::animationTrackTargetForName(): implementation-returned" << out << "is neither custom nor invalid", {}); + return out; +} + +AnimationTrackTarget AbstractImporter::doAnimationTrackTargetForName(Containers::StringView) { + return {}; +} + +Containers::String AbstractImporter::animationTrackTargetName(const AnimationTrackTarget name) { + CORRADE_ASSERT(isAnimationTrackTargetCustom(name), + "Trade::AbstractImporter::animationTrackTargetName():" << name << "is not custom", {}); + Containers::String out = doAnimationTrackTargetName(animationTrackTargetCustom(name)); + CORRADE_ASSERT(out.isSmall() || !out.deleter(), + "Trade::AbstractImporter::animationTrackTargetName(): implementation is not allowed to use a custom String deleter", {}); + return out; +} + +Containers::String AbstractImporter::doAnimationTrackTargetName(UnsignedShort) { return {}; } + UnsignedInt AbstractImporter::lightCount() const { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::lightCount(): no file opened", {}); return doLightCount(); diff --git a/src/Magnum/Trade/AbstractImporter.h b/src/Magnum/Trade/AbstractImporter.h index dd705bcd6..129b6b7a9 100644 --- a/src/Magnum/Trade/AbstractImporter.h +++ b/src/Magnum/Trade/AbstractImporter.h @@ -290,7 +290,9 @@ name doesn't exist. - Animation names can be retrieved using @ref animationName() and mapped to an ID using @ref animationForName(), imported with - @ref animation(Containers::StringView) + @ref animation(Containers::StringView). Animations can have custom + animation track targets, for which the name mapping can be retrieved using + @ref animationTrackTargetName() and @ref animationTrackTargetForName(). - Camera names using @ref cameraName() & @ref cameraForName(), imported with @ref camera(Containers::StringView) - Image names using @ref image1DName() / @ref image2DName() / @@ -874,7 +876,8 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * * On failure prints a message to @relativeref{Magnum,Error} and * returns @ref Containers::NullOpt. Expects that a file is opened. - * @see @ref animation(Containers::StringView), @ref animationName() + * @see @ref animation(Containers::StringView), @ref animationName(), + * @ref animationTrackTargetName() */ Containers::Optional animation(UnsignedInt id); @@ -890,6 +893,37 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ Containers::Optional animation(Containers::StringView name); + /** + * @brief Animation track target for given name + * @m_since_latest + * + * If the @p name is not recognized, returns a zero (invalid) + * @ref AnimationTrackTarget, otherwise returns a custom animation + * track target. Note that the value returned by this function may + * depend on whether a file is opened or not and also be different for + * different files --- see documentation of a particular importer for + * more information. + * @see @ref animationTrackTargetName(), + * @ref isAnimationTrackTargetCustom() + */ + AnimationTrackTarget animationTrackTargetForName(Containers::StringView name); + + /** + * @brief String name for given custom animation track target + * @m_since_latest + * + * Given a custom @p name returned by @ref animation() in an + * @ref AnimationData, returns a string identifier. If a string + * representation is not available or @p name is not recognized, + * returns an empty string. Expects that @p name is custom. Note that + * the value returned by this function may depend on whether a file is + * opened or not and also be different for different files --- see + * documentation of a particular importer for more information. + * @see @ref animationTrackTargetForName(), + * @ref isAnimationTrackTargetCustom() + */ + Containers::String animationTrackTargetName(AnimationTrackTarget name); + /** * @brief Light count * @@ -1948,6 +1982,24 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi /** @brief Implementation for @ref animation() */ virtual Containers::Optional doAnimation(UnsignedInt id); + /** + * @brief Implementation for @ref animationTrackTargetForName() + * @m_since_latest + * + * Default implementation returns an invalid (zero) value. + */ + virtual AnimationTrackTarget doAnimationTrackTargetForName(Containers::StringView name); + + /** + * @brief Implementation for @ref animationTrackTargetName() + * @m_since_latest + * + * Receives the custom ID extracted via + * @ref animationTrackTargetCustom(AnimationTrackTarget). Default + * implementation returns an empty string. + */ + virtual Containers::String doAnimationTrackTargetName(UnsignedShort name); + /** * @brief Implementation for @ref lightCount() * diff --git a/src/Magnum/Trade/AnimationData.h b/src/Magnum/Trade/AnimationData.h index c286bce85..d3c6d71ed 100644 --- a/src/Magnum/Trade/AnimationData.h +++ b/src/Magnum/Trade/AnimationData.h @@ -180,7 +180,11 @@ the upper half of the enum range. Those are detected via 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. +not point to an existing object. An importer that exposes custom types then may +also provide a string mapping using +@ref AbstractImporter::animationTrackTargetForName() and +@ref AbstractImporter::animationTrackTargetName(). See documentation of a +particular importer for details. @see @ref AnimationTrackData @experimental */ @@ -288,7 +292,8 @@ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, AnimationTrackTarget value); 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) + @ref animationTrackTargetCustom(AnimationTrackTarget), + @ref AbstractImporter::animationTrackTargetName() */ constexpr bool isAnimationTrackTargetCustom(AnimationTrackTarget name) { return UnsignedShort(name) >= Implementation::AnimationTrackTargetCustom; @@ -317,7 +322,8 @@ constexpr AnimationTrackTarget animationTrackTargetCustom(UnsignedShort id) { Inverse to @ref animationTrackTargetCustom(UnsignedShort). Expects that the type is custom. -@see @ref isAnimationTrackTargetCustom() +@see @ref isAnimationTrackTargetCustom(), + @ref AbstractImporter::animationTrackTargetName() */ constexpr UnsignedShort animationTrackTargetCustom(AnimationTrackTarget name) { return CORRADE_CONSTEXPR_ASSERT(isAnimationTrackTargetCustom(name), diff --git a/src/Magnum/Trade/Test/AbstractImporterTest.cpp b/src/Magnum/Trade/Test/AbstractImporterTest.cpp index 1c5290c41..9d13dfe4f 100644 --- a/src/Magnum/Trade/Test/AbstractImporterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImporterTest.cpp @@ -172,6 +172,11 @@ struct AbstractImporterTest: TestSuite::Tester { void animationCustomDataDeleter(); void animationCustomTrackDeleter(); + void animationTrackTargetName(); + void animationTrackTargetNameNotImplemented(); + void animationTrackTargetNameNotCustom(); + void animationTrackTargetNameCustomDeleter(); + void light(); void lightFailed(); void lightNameNotImplemented(); @@ -494,6 +499,11 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::animationCustomDataDeleter, &AbstractImporterTest::animationCustomTrackDeleter, + &AbstractImporterTest::animationTrackTargetName, + &AbstractImporterTest::animationTrackTargetNameNotImplemented, + &AbstractImporterTest::animationTrackTargetNameNotCustom, + &AbstractImporterTest::animationTrackTargetNameCustomDeleter, + &AbstractImporterTest::light, &AbstractImporterTest::lightFailed, &AbstractImporterTest::lightForNameOutOfRange, @@ -4078,6 +4088,79 @@ void AbstractImporterTest::animationCustomTrackDeleter() { "Trade::AbstractImporter::animation(): implementation is not allowed to use a custom Array deleter\n"); } +void AbstractImporterTest::animationTrackTargetName() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + + AnimationTrackTarget doAnimationTrackTargetForName(Containers::StringView name) override { + if(name == "visibility") return animationTrackTargetCustom(37); + return AnimationTrackTarget{}; + } + + Containers::String doAnimationTrackTargetName(UnsignedShort id) override { + if(id == 37) return "visibility"; + return ""; + } + } importer; + + CORRADE_COMPARE(importer.animationTrackTargetForName("visibility"), animationTrackTargetCustom(37)); + CORRADE_COMPARE(importer.animationTrackTargetName(animationTrackTargetCustom(37)), "visibility"); +} + +void AbstractImporterTest::animationTrackTargetNameNotImplemented() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + CORRADE_COMPARE(importer.animationTrackTargetForName(""), AnimationTrackTarget{}); + CORRADE_COMPARE(importer.animationTrackTargetName(animationTrackTargetCustom(37)), ""); +} + +void AbstractImporterTest::animationTrackTargetNameNotCustom() { + CORRADE_SKIP_IF_NO_ASSERT(); + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + + AnimationTrackTarget doAnimationTrackTargetForName(Containers::StringView) override { + return AnimationTrackTarget::Rotation2D; + } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + importer.animationTrackTargetForName("visibility"); + importer.animationTrackTargetName(AnimationTrackTarget::Rotation2D); + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::animationTrackTargetForName(): implementation-returned Trade::AnimationTrackTarget::Rotation2D is neither custom nor invalid\n" + "Trade::AbstractImporter::animationTrackTargetName(): Trade::AnimationTrackTarget::Rotation2D is not custom\n"); +} + +void AbstractImporterTest::animationTrackTargetNameCustomDeleter() { + CORRADE_SKIP_IF_NO_ASSERT(); + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + Containers::String doAnimationTrackTargetName(UnsignedShort) override { + return Containers::String{"a", 1, [](char*, std::size_t) {}}; + } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + importer.animationTrackTargetName(animationTrackTargetCustom(0)); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animationTrackTargetName(): implementation is not allowed to use a custom String deleter\n"); +} + void AbstractImporterTest::light() { struct: AbstractImporter { ImporterFeatures doFeatures() const override { return {}; } diff --git a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp index 66e09ea32..635a92b50 100644 --- a/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp +++ b/src/MagnumPlugins/AnyImageImporter/AnyImageImporter.cpp @@ -337,4 +337,4 @@ Containers::Optional AnyImageImporter::doImage3D(const UnsignedInt }} CORRADE_PLUGIN_REGISTER(AnyImageImporter, Magnum::Trade::AnyImageImporter, - "cz.mosra.magnum.Trade.AbstractImporter/0.5") + "cz.mosra.magnum.Trade.AbstractImporter/0.5.1") diff --git a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp index 4e34e620f..17abaf463 100644 --- a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp +++ b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp @@ -301,4 +301,4 @@ Containers::Optional AnySceneImporter::doImage3D(const UnsignedInt }} CORRADE_PLUGIN_REGISTER(AnySceneImporter, Magnum::Trade::AnySceneImporter, - "cz.mosra.magnum.Trade.AbstractImporter/0.5") + "cz.mosra.magnum.Trade.AbstractImporter/0.5.1") diff --git a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp index 71b551690..1265dabb3 100644 --- a/src/MagnumPlugins/ObjImporter/ObjImporter.cpp +++ b/src/MagnumPlugins/ObjImporter/ObjImporter.cpp @@ -489,4 +489,4 @@ Containers::Optional ObjImporter::doMesh(UnsignedInt id, UnsignedInt) }} CORRADE_PLUGIN_REGISTER(ObjImporter, Magnum::Trade::ObjImporter, - "cz.mosra.magnum.Trade.AbstractImporter/0.5") + "cz.mosra.magnum.Trade.AbstractImporter/0.5.1") diff --git a/src/MagnumPlugins/TgaImporter/TgaImporter.cpp b/src/MagnumPlugins/TgaImporter/TgaImporter.cpp index 4dced365f..321076f6b 100644 --- a/src/MagnumPlugins/TgaImporter/TgaImporter.cpp +++ b/src/MagnumPlugins/TgaImporter/TgaImporter.cpp @@ -263,4 +263,4 @@ Containers::Optional TgaImporter::doImage2D(UnsignedInt, UnsignedIn }} CORRADE_PLUGIN_REGISTER(TgaImporter, Magnum::Trade::TgaImporter, - "cz.mosra.magnum.Trade.AbstractImporter/0.5") + "cz.mosra.magnum.Trade.AbstractImporter/0.5.1")