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")