From 0b3e1e30688a73ee2d3a4e1e00811b5f892d3620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 12 Jul 2018 02:40:30 +0200 Subject: [PATCH] Trade: animation import interface in AbstractImporter. --- doc/changelog.dox | 2 + src/Magnum/Trade/AbstractImporter.cpp | 33 +++ src/Magnum/Trade/AbstractImporter.h | 68 +++++- .../Trade/Test/AbstractImporterTest.cpp | 201 ++++++++++++++++++ 4 files changed, 302 insertions(+), 2 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 72a140e97..5e30a7558 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -93,6 +93,8 @@ See also: @subsubsection changelog-latest-new-trade Trade library +- @ref Trade::AnimationData class and animation import interface in + @ref Trade::AbstractImporter::animation() and related functions - @ref Trade::ObjectData2D and @ref Trade::ObjectData3D now support also separate translation / rotation / scaling specification instead of a combined transformation matrix. See @ref Trade::ObjectData2D::transformation() diff --git a/src/Magnum/Trade/AbstractImporter.cpp b/src/Magnum/Trade/AbstractImporter.cpp index 1123e7e71..c5c406211 100644 --- a/src/Magnum/Trade/AbstractImporter.cpp +++ b/src/Magnum/Trade/AbstractImporter.cpp @@ -32,6 +32,7 @@ #include #include "Magnum/Trade/AbstractMaterialData.h" +#include "Magnum/Trade/AnimationData.h" #include "Magnum/Trade/CameraData.h" #include "Magnum/Trade/ImageData.h" #include "Magnum/Trade/LightData.h" @@ -186,6 +187,38 @@ Containers::Optional AbstractImporter::doScene(UnsignedInt) { CORRADE_ASSERT(false, "Trade::AbstractImporter::scene(): not implemented", {}); } +UnsignedInt AbstractImporter::animationCount() const { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::animationCount(): no file opened", {}); + return doAnimationCount(); +} + +UnsignedInt AbstractImporter::doAnimationCount() const { return 0; } + +Int AbstractImporter::animationForName(const std::string& name) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::animationForName(): no file opened", {}); + return doAnimationForName(name); +} + +Int AbstractImporter::doAnimationForName(const std::string&) { return -1; } + +std::string AbstractImporter::animationName(const UnsignedInt id) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::animationName(): no file opened", {}); + CORRADE_ASSERT(id < doAnimationCount(), "Trade::AbstractImporter::animationName(): index out of range", {}); + return doAnimationName(id); +} + +std::string AbstractImporter::doAnimationName(UnsignedInt) { return {}; } + +Containers::Optional AbstractImporter::animation(const UnsignedInt id) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::animation(): no file opened", {}); + CORRADE_ASSERT(id < doAnimationCount(), "Trade::AbstractImporter::animation(): index out of range", {}); + return doAnimation(id); +} + +Containers::Optional AbstractImporter::doAnimation(UnsignedInt) { + CORRADE_ASSERT(false, "Trade::AbstractImporter::animation(): not implemented", {}); +} + 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 7c178336a..856032063 100644 --- a/src/Magnum/Trade/AbstractImporter.h +++ b/src/Magnum/Trade/AbstractImporter.h @@ -139,6 +139,8 @@ expose internal state through various accessors: state for currently opened file - @ref AbstractMaterialData::importerState() can expose importer state for given material imported by @ref material() +- @ref AnimationData::importerState() can expose importer state for given + animation imported by @ref animation() - @ref CameraData::importerState() can expose importer state for a camera importer by @ref camera() - @ref ImageData::importerState() can expose importer state for an image @@ -204,10 +206,19 @@ checked by the implementation: - All `do*()` implementations taking data ID as parameter are called only if the ID is from valid range. -@attention @ref Corrade::Containers::Array instances returned from the plugin +@attention + @ref Corrade::Containers::Array instances returned from the plugin should *not* use anything else than the default deleter, otherwise this can cause dangling function pointer call on array destruction if the plugin gets unloaded before the array is destroyed. +@attention + Similarly for interpolator functions passed through + @ref Animation::TrackView instances to @ref AnimationData --- to avoid + dangling pointers, be sure to always include an interpolator returned from + @ref animationInterpolatorFor(), which guarantees the function is *not* + instantiated in the plugin binary. Avoid using + @ref Animation::interpolatorFor() (or indirectly it by specifying + just @ref Animation::Interpolation), as it doesn't have such guarantee. */ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagingPlugin { public: @@ -446,6 +457,34 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ Containers::Optional scene(UnsignedInt id); + /** @brief Animation count */ + UnsignedInt animationCount() const; + + /** + * @brief Animation ID for given name + * + * If no animation for given name exists, returns @cpp -1 @ce. + * @see @ref animationName() + */ + Int animationForName(const std::string& name); + + /** + * @brief Animation name + * @param id Animation ID, from range [0, @ref animationCount()). + * + * @see @ref animationForName() + */ + std::string animationName(UnsignedInt id); + + /** + * @brief Animation + * @param id Animation ID, from range [0, @ref animationCount()). + * + * Returns given animation or @ref Containers::NullOpt if importing + * failed. + */ + Containers::Optional animation(UnsignedInt id); + /** @brief Light count */ UnsignedInt lightCount() const; @@ -753,7 +792,8 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * documentation of a particular plugin for more information about * returned type and contents. Returns `nullptr` by default. * @see @ref AbstractMaterialData::importerState(), - * @ref CameraData::importerState(), @ref ImageData::importerState(), + * @ref AnimationData::importerState(), @ref CameraData::importerState(), + * @ref ImageData::importerState(), @ref LightData::importerState(), * @ref MeshData2D::importerState(), @ref MeshData3D::importerState(), * @ref ObjectData2D::importerState(), @ref ObjectData3D::importerState(), * @ref SceneData::importerState(), @ref TextureData::importerState() @@ -834,6 +874,30 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi /** @brief Implementation for @ref scene() */ virtual Containers::Optional doScene(UnsignedInt id); + /** + * @brief Implementation for @ref animationCount() + * + * Default implementation returns @cpp 0 @ce. + */ + virtual UnsignedInt doAnimationCount() const; + + /** + * @brief Implementation for @ref animationForName() + * + * Default implementation returns @cpp -1 @ce. + */ + virtual Int doAnimationForName(const std::string& name); + + /** + * @brief Implementation for @ref animationName() + * + * Default implementation returns empty string. + */ + virtual std::string doAnimationName(UnsignedInt id); + + /** @brief Implementation for @ref animation() */ + virtual Containers::Optional doAnimation(UnsignedInt id); + /** * @brief Implementation for @ref lightCount() * diff --git a/src/Magnum/Trade/Test/AbstractImporterTest.cpp b/src/Magnum/Trade/Test/AbstractImporterTest.cpp index 77a7b5204..5c44ae951 100644 --- a/src/Magnum/Trade/Test/AbstractImporterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImporterTest.cpp @@ -29,6 +29,7 @@ #include #include "Magnum/Trade/AbstractImporter.h" +#include "Magnum/Trade/AnimationData.h" #include "Magnum/Trade/CameraData.h" #include "Magnum/Trade/ImageData.h" #include "Magnum/Trade/LightData.h" @@ -85,6 +86,18 @@ class AbstractImporterTest: public TestSuite::Tester { void sceneNoFile(); void sceneOutOfRange(); + void animation(); + void animationCountNotImplemented(); + void animationCountNoFile(); + void animationForNameNotImplemented(); + void animationForNameNoFile(); + void animationNameNotImplemented(); + void animationNameNoFile(); + void animationNameOutOfRange(); + void animationNotImplemented(); + void animationNoFile(); + void animationOutOfRange(); + void light(); void lightCountNotImplemented(); void lightCountNoFile(); @@ -264,6 +277,18 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::sceneNoFile, &AbstractImporterTest::sceneOutOfRange, + &AbstractImporterTest::animation, + &AbstractImporterTest::animationCountNotImplemented, + &AbstractImporterTest::animationCountNoFile, + &AbstractImporterTest::animationForNameNotImplemented, + &AbstractImporterTest::animationForNameNoFile, + &AbstractImporterTest::animationNameNotImplemented, + &AbstractImporterTest::animationNameNoFile, + &AbstractImporterTest::animationNameOutOfRange, + &AbstractImporterTest::animationNotImplemented, + &AbstractImporterTest::animationNoFile, + &AbstractImporterTest::animationOutOfRange, + &AbstractImporterTest::light, &AbstractImporterTest::lightCountNotImplemented, &AbstractImporterTest::lightCountNoFile, @@ -963,6 +988,182 @@ void AbstractImporterTest::sceneOutOfRange() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::scene(): index out of range\n"); } +void AbstractImporterTest::animation() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doAnimationCount() const override { return 8; } + Int doAnimationForName(const std::string& name) override { + if(name == "eighth") return 7; + else return -1; + } + std::string doAnimationName(UnsignedInt id) override { + if(id == 7) return "eighth"; + else return {}; + } + Containers::Optional doAnimation(UnsignedInt id) override { + if(id == 7) return AnimationData{{}, {}, &state}; + else return AnimationData{{}, {}}; + } + }; + + std::ostringstream out; + Error redirectError{&out}; + + Importer importer; + CORRADE_COMPARE(importer.animationCount(), 8); + CORRADE_COMPARE(importer.animationForName("eighth"), 7); + CORRADE_COMPARE(importer.animationName(7), "eighth"); + + auto data = importer.animation(7); + CORRADE_VERIFY(data); + CORRADE_COMPARE(data->importerState(), &state); +} + +void AbstractImporterTest::animationCountNotImplemented() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + }; + + Importer importer; + CORRADE_COMPARE(importer.animationCount(), 0); +} + +void AbstractImporterTest::animationCountNoFile() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + }; + + std::ostringstream out; + Error redirectError{&out}; + + Importer importer; + importer.animationCount(); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animationCount(): no file opened\n"); +} + +void AbstractImporterTest::animationForNameNotImplemented() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + }; + + Importer importer; + CORRADE_COMPARE(importer.animationForName(""), -1); +} + +void AbstractImporterTest::animationForNameNoFile() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + }; + + std::ostringstream out; + Error redirectError{&out}; + + Importer importer; + importer.animationForName(""); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animationForName(): no file opened\n"); +} + +void AbstractImporterTest::animationNameNotImplemented() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doAnimationCount() const override { return 8; } + }; + + Importer importer; + CORRADE_COMPARE(importer.animationName(7), ""); +} + +void AbstractImporterTest::animationNameNoFile() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + }; + + std::ostringstream out; + Error redirectError{&out}; + + Importer importer; + importer.animationName(42); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animationName(): no file opened\n"); +} + +void AbstractImporterTest::animationNameOutOfRange() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + }; + + std::ostringstream out; + Error redirectError{&out}; + + Importer importer; + importer.animationName(0); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animationName(): index out of range\n"); +} + +void AbstractImporterTest::animationNotImplemented() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doAnimationCount() const override { return 8; } + }; + + std::ostringstream out; + Error redirectError{&out}; + + Importer importer; + importer.animation(7); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animation(): not implemented\n"); +} + +void AbstractImporterTest::animationNoFile() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + }; + + std::ostringstream out; + Error redirectError{&out}; + + Importer importer; + importer.animation(42); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animation(): no file opened\n"); +} + +void AbstractImporterTest::animationOutOfRange() { + class Importer: public Trade::AbstractImporter { + Features doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + }; + + std::ostringstream out; + Error redirectError{&out}; + + Importer importer; + importer.animation(0); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animation(): index out of range\n"); +} + void AbstractImporterTest::light() { class Importer: public Trade::AbstractImporter { Features doFeatures() const override { return {}; }