From 618fbeccaaa9c863cd88925647dea749f1a42b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 22 Sep 2021 13:28:19 +0200 Subject: [PATCH] Trade: adapt AbstractImporter for the new SceneData workflow. Same as with MeshData2D/3D, the original ObjectData API and plugin interfaces are preserved to keep existing code as well as existing importer implementations working. As Magnum's own importers will get updated to the new SceneData workflow, a backward compatibility layer provided that translates it to the subset that the legacy ObjectData understands. With this commit, both existing plugin code can build (and test against) the new workflow, and any ports to the new workflow can test against the legacy interfaces. Except that for now the compatibility layer doesn't deal with objects that have more than one mesh or for example a light and a camera attached, this will be done in a separate step. --- doc/changelog.dox | 12 + doc/snippets/MagnumTrade.cpp | 28 +- src/Magnum/Trade/AbstractImporter.cpp | 319 ++- src/Magnum/Trade/AbstractImporter.h | 249 ++- src/Magnum/Trade/CMakeLists.txt | 22 +- src/Magnum/Trade/MeshObjectData2D.cpp | 6 + src/Magnum/Trade/MeshObjectData2D.h | 21 +- src/Magnum/Trade/MeshObjectData3D.cpp | 6 + src/Magnum/Trade/MeshObjectData3D.h | 19 +- src/Magnum/Trade/ObjectData2D.cpp | 24 + src/Magnum/Trade/ObjectData2D.h | 57 +- src/Magnum/Trade/ObjectData3D.cpp | 20 + src/Magnum/Trade/ObjectData3D.h | 57 +- src/Magnum/Trade/SceneData.h | 5 + .../Trade/Test/AbstractImporterTest.cpp | 1895 ++++++++++++++--- src/Magnum/Trade/Test/CMakeLists.txt | 8 +- src/Magnum/Trade/Test/ObjectData2DTest.cpp | 7 + src/Magnum/Trade/Test/ObjectData3DTest.cpp | 7 + src/Magnum/Trade/Trade.h | 8 +- 19 files changed, 2407 insertions(+), 363 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 28a708d8e..cc3f4e719 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -641,6 +641,18 @@ See also: new scene representation. Use @ref Trade::SceneData::childrenFor() with @cpp -1 @ce passed as the @p object argument to get a list of top-level objects. +- @cpp Trade::ObjectData*D @ce, @cpp Trade::MeshObjectData*D @ce classes, + @cpp Trade::ObjectInstanceType*D @ce, @cpp Trade::ObjectFlag*D @ce, + @cpp Trade::ObjectFlags*D @ce enums and the corresponding + @cpp Trade::AbstractImporter::object*DCount() @ce, + @cpp Trade::AbstractImporter::object*DForName() @ce, + @cpp Trade::AbstractImporter::object*DName() @ce and + @cpp Trade::AbstractImporter::object*D() @ce accessor APIs are deprecated + in favor of the unified representation in @ref Trade::SceneData and the + @ref Trade::AbstractImporter::objectCount(), + @relativeref{Trade::AbstractImporter,objectForName()} and + @relativeref{Trade::AbstractImporter,objectName()} accessors that are + shared for 2D and 3D. - @ref Trade::AbstractImporter::material() now returns @ref Corrade::Containers::Optional instead of a @ref Corrade::Containers::Pointer, as the new @ref Trade::MaterialData class isn't polymorphic anymore. If diff --git a/doc/snippets/MagnumTrade.cpp b/doc/snippets/MagnumTrade.cpp index e4a1fb3b1..6862caa3c 100644 --- a/doc/snippets/MagnumTrade.cpp +++ b/doc/snippets/MagnumTrade.cpp @@ -47,8 +47,6 @@ #include "Magnum/Trade/LightData.h" #include "Magnum/Trade/MaterialData.h" #include "Magnum/Trade/MeshData.h" -#include "Magnum/Trade/ObjectData2D.h" -#include "Magnum/Trade/MeshObjectData3D.h" #include "Magnum/Trade/PbrClearCoatMaterialData.h" #include "Magnum/Trade/PbrSpecularGlossinessMaterialData.h" #include "Magnum/Trade/PbrMetallicRoughnessMaterialData.h" @@ -66,9 +64,12 @@ #ifdef MAGNUM_BUILD_DEPRECATED #define _MAGNUM_NO_DEPRECATED_MESHDATA /* So it doesn't yell here */ +#define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */ #include "Magnum/Trade/MeshData2D.h" #include "Magnum/Trade/MeshData3D.h" +#include "Magnum/Trade/MeshObjectData3D.h" +#include "Magnum/Trade/ObjectData2D.h" #endif #define DOXYGEN_ELLIPSIS(...) __VA_ARGS__ @@ -180,21 +181,6 @@ importer->openFile("scene.gltf"); // memory-maps all files } #endif -{ -Containers::Pointer importer; -Int materialIndex; -/* [AbstractImporter-usage-cast] */ -Containers::Pointer data = importer->object3D(12); -if(data && data->instanceType() == Trade::ObjectInstanceType3D::Mesh) { - auto& mesh = static_cast(*data); - - materialIndex = mesh.material(); - // ... -} -/* [AbstractImporter-usage-cast] */ -static_cast(materialIndex); -} - { Containers::Pointer importer; /* [AbstractImporter-setFileCallback] */ @@ -844,9 +830,9 @@ MeshTools::transformPointsInPlace(transformation, data.positions(0)); /* [MeshData2D-transform] */ CORRADE_IGNORE_DEPRECATED_POP } -#endif { +CORRADE_IGNORE_DEPRECATED_PUSH Trade::ObjectData2D& baz(); Trade::ObjectData2D& data = baz(); /* [ObjectData2D-transformation] */ @@ -855,9 +841,9 @@ Matrix3 transformation = Matrix3::scaling(data.scaling()); /* [ObjectData2D-transformation] */ static_cast(transformation); +CORRADE_IGNORE_DEPRECATED_POP } -#ifdef MAGNUM_BUILD_DEPRECATED { CORRADE_IGNORE_DEPRECATED_PUSH Trade::MeshData3D& bar(); @@ -871,9 +857,9 @@ MeshTools::transformVectorsInPlace(transformation, data.normals(0)); /* [MeshData3D-transform] */ CORRADE_IGNORE_DEPRECATED_POP } -#endif { +CORRADE_IGNORE_DEPRECATED_PUSH Trade::ObjectData3D& fizz(); Trade::ObjectData3D& data = fizz(); /* [ObjectData3D-transformation] */ @@ -882,6 +868,8 @@ Matrix4 transformation = Matrix4::scaling(data.scaling()); /* [ObjectData3D-transformation] */ static_cast(transformation); +CORRADE_IGNORE_DEPRECATED_POP } +#endif } diff --git a/src/Magnum/Trade/AbstractImporter.cpp b/src/Magnum/Trade/AbstractImporter.cpp index c470ac375..3b027b931 100644 --- a/src/Magnum/Trade/AbstractImporter.cpp +++ b/src/Magnum/Trade/AbstractImporter.cpp @@ -40,17 +40,21 @@ #include "Magnum/Trade/LightData.h" #include "Magnum/Trade/MaterialData.h" #include "Magnum/Trade/MeshData.h" -#include "Magnum/Trade/ObjectData2D.h" -#include "Magnum/Trade/ObjectData3D.h" #include "Magnum/Trade/SceneData.h" #include "Magnum/Trade/SkinData.h" #include "Magnum/Trade/TextureData.h" #ifdef MAGNUM_BUILD_DEPRECATED +#include +#include + #define _MAGNUM_NO_DEPRECATED_MESHDATA /* So it doesn't yell here */ +#define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */ #include "Magnum/Trade/MeshData2D.h" #include "Magnum/Trade/MeshData3D.h" +#include "Magnum/Trade/MeshObjectData2D.h" +#include "Magnum/Trade/MeshObjectData3D.h" #endif #ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT @@ -95,6 +99,12 @@ AbstractImporter::AbstractImporter(PluginManager::Manager& man AbstractImporter::AbstractImporter(PluginManager::AbstractManager& manager, const std::string& plugin): PluginManager::AbstractManagingPlugin{manager, plugin} {} +#ifdef MAGNUM_BUILD_DEPRECATED +/* These twp needed because of the Array member */ +AbstractImporter::AbstractImporter(AbstractImporter&&) noexcept = default; +AbstractImporter::~AbstractImporter() = default; +#endif + void AbstractImporter::setFlags(ImporterFlags flags) { CORRADE_ASSERT(!isOpened(), "Trade::AbstractImporter::setFlags(): can't be set while a file is opened", ); @@ -268,6 +278,13 @@ UnsignedInt AbstractImporter::sceneCount() const { UnsignedInt AbstractImporter::doSceneCount() const { return 0; } +UnsignedLong AbstractImporter::objectCount() const { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::objectCount(): no file opened", {}); + return doObjectCount(); +} + +UnsignedLong AbstractImporter::doObjectCount() const { return 0; } + Int AbstractImporter::sceneForName(const std::string& name) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::sceneForName(): no file opened", -1); const Int id = doSceneForName(name); @@ -278,6 +295,16 @@ Int AbstractImporter::sceneForName(const std::string& name) { Int AbstractImporter::doSceneForName(const std::string&) { return -1; } +Long AbstractImporter::objectForName(const std::string& name) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::objectForName(): no file opened", {}); + const Long id = doObjectForName(name); + CORRADE_ASSERT(id == -1 || UnsignedLong(id) < doObjectCount(), + "Trade::AbstractImporter::objectForName(): implementation-returned index" << id << "out of range for" << doObjectCount() << "entries", {}); + return id; +} + +Long AbstractImporter::doObjectForName(const std::string&) { return -1; } + std::string AbstractImporter::sceneName(const UnsignedInt id) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::sceneName(): no file opened", {}); CORRADE_ASSERT(id < doSceneCount(), "Trade::AbstractImporter::sceneName(): index" << id << "out of range for" << doSceneCount() << "entries", {}); @@ -286,10 +313,23 @@ std::string AbstractImporter::sceneName(const UnsignedInt id) { std::string AbstractImporter::doSceneName(UnsignedInt) { return {}; } +std::string AbstractImporter::objectName(const UnsignedLong id) { + CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::objectName(): no file opened", {}); + CORRADE_ASSERT(id < doObjectCount(), "Trade::AbstractImporter::objectName(): index" << id << "out of range for" << doObjectCount() << "entries", {}); + return doObjectName(id); +} + +std::string AbstractImporter::doObjectName(UnsignedLong) { return {}; } + Containers::Optional AbstractImporter::scene(const UnsignedInt id) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::scene(): no file opened", {}); CORRADE_ASSERT(id < doSceneCount(), "Trade::AbstractImporter::scene(): index" << id << "out of range for" << doSceneCount() << "entries", {}); - return doScene(id); + Containers::Optional scene = doScene(id); + CORRADE_ASSERT(!scene || ( + (!scene->_data.deleter() || scene->_data.deleter() == Implementation::nonOwnedArrayDeleter) && + (!scene->_fields.deleter() || scene->_fields.deleter() == reinterpret_cast(Implementation::nonOwnedArrayDeleter))), + "Trade::AbstractImporter::scene(): implementation is not allowed to use a custom Array deleter", {}); + return scene; } Containers::Optional AbstractImporter::doScene(UnsignedInt) { @@ -465,39 +505,176 @@ Containers::Optional AbstractImporter::camera(const std::string& nam return camera(id); /* not doCamera(), so we get the range checks also */ } +#ifdef MAGNUM_BUILD_DEPRECATED +struct AbstractImporter::CachedScenes { + UnsignedInt object2DCount{}; + UnsignedInt object3DCount{}; + Containers::Array> scenes; +}; + +void AbstractImporter::populateCachedScenes() { + if(_cachedScenes) return; + + _cachedScenes.emplace(); + _cachedScenes->scenes = Containers::Array>{sceneCount()}; + for(UnsignedInt i = 0; i != _cachedScenes->scenes.size(); ++i) { + _cachedScenes->scenes[i] = scene(i); + + /* Return the 2D/3D object count based on which scenes are 2D and which + not. The objectCount() provided by the importer is ignored except + for the above, also because it doesn't take into account the + restriction for unique-functioning objects. */ + if(_cachedScenes->scenes[i]) { + if(_cachedScenes->scenes[i]->is2D()) + _cachedScenes->object2DCount = Math::max(_cachedScenes->object2DCount, UnsignedInt(_cachedScenes->scenes[i]->objectCount())); + if(_cachedScenes->scenes[i]->is3D()) + _cachedScenes->object3DCount = Math::max(_cachedScenes->object3DCount, UnsignedInt(_cachedScenes->scenes[i]->objectCount())); + } + } +} + UnsignedInt AbstractImporter::object2DCount() const { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::object2DCount(): no file opened", {}); + CORRADE_IGNORE_DEPRECATED_PUSH return doObject2DCount(); + CORRADE_IGNORE_DEPRECATED_POP } -UnsignedInt AbstractImporter::doObject2DCount() const { return 0; } +UnsignedInt AbstractImporter::doObject2DCount() const { + /* I know, I know. A cleaner option would be to populate this during + openFile() / openData() but that would mean the backwards compatibility + overhead is there even if not using the deprecated APIs, which is way + worse than using this nasty hack in two places. */ + const_cast(*this).populateCachedScenes(); + return _cachedScenes->object2DCount; +} Int AbstractImporter::object2DForName(const std::string& name) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::object2DForName(): no file opened", {}); + CORRADE_IGNORE_DEPRECATED_PUSH const Int id = doObject2DForName(name); CORRADE_ASSERT(id == -1 || UnsignedInt(id) < doObject2DCount(), "Trade::AbstractImporter::object2DForName(): implementation-returned index" << id << "out of range for" << doObject2DCount() << "entries", {}); return id; + CORRADE_IGNORE_DEPRECATED_POP } -Int AbstractImporter::doObject2DForName(const std::string&) { return -1; } +Int AbstractImporter::doObject2DForName(const std::string& name) { + /* Alias to the new interface. If it returns an ID that's larger than + reported 2D object count, then it's probably for a 3D object instead + -- ignore it in that case. */ + const Long id = doObjectForName(name); + CORRADE_IGNORE_DEPRECATED_PUSH + return id < doObject2DCount() ? id : -1; + CORRADE_IGNORE_DEPRECATED_POP +} std::string AbstractImporter::object2DName(const UnsignedInt id) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::object2DName(): no file opened", {}); + CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_ASSERT(id < doObject2DCount(), "Trade::AbstractImporter::object2DName(): index" << id << "out of range for" << doObject2DCount() << "entries", {}); return doObject2DName(id); + CORRADE_IGNORE_DEPRECATED_POP } -std::string AbstractImporter::doObject2DName(UnsignedInt) { return {}; } +std::string AbstractImporter::doObject2DName(const UnsignedInt id) { + /* Alias to the new interface */ + return doObjectName(id); +} +CORRADE_IGNORE_DEPRECATED_PUSH Containers::Pointer AbstractImporter::object2D(const UnsignedInt id) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::object2D(): no file opened", {}); CORRADE_ASSERT(id < doObject2DCount(), "Trade::AbstractImporter::object2D(): index" << id << "out of range for" << doObject2DCount() << "entries", {}); return doObject2D(id); } -Containers::Pointer AbstractImporter::doObject2D(UnsignedInt) { - CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImporter::object2D(): not implemented", {}); +Containers::Pointer AbstractImporter::doObject2D(const UnsignedInt id) { + /* The code is mostly the same between doObject2D() and doObject3D(), + except that the 2D variant has no lights. Attempting to unify the common + code would be more complex than just having a slightly modified copy. */ + + populateCachedScenes(); + + /* Find the first 2D scene with this object, which we'll detect from the + object count reported for the scene, whether it's 2D or 3D, and a + presence of a parent attribute. If a parent attribute is not present, it + means the object isn't a part of this scene, in which case we skip it. + It could also mean isn't a part of the hierarchy and is standalone + (skyboxes, scene-wide properties), which the legacy API had no way to + deal with anyway so ignoring those is fine. */ + std::size_t sceneCandidate = ~std::size_t{}; + for(std::size_t i = 0; i != _cachedScenes->scenes.size(); ++i) { + const Containers::Optional& scene = _cachedScenes->scenes[i]; + if(scene && scene->is2D() && id < scene->objectCount() && scene->parentFor(id)) { + sceneCandidate = i; + break; + } + } + + if(sceneCandidate == ~std::size_t{}) { + Error{} << "Trade::AbstractImporter::object2D(): object" << id << "not found in any 2D scene hierarchy"; + return {}; + } + + const SceneData& scene = *_cachedScenes->scenes[sceneCandidate]; + + ObjectFlags2D flags; + Containers::Optional transformation = scene.transformation2DFor(id); + Containers::Optional> trs = scene.translationRotationScaling2DFor(id); + if(trs) + flags |= ObjectFlag2D::HasTranslationRotationScaling; + /* If the object has neither a TRS nor a transformation field, assign an + identity transform to it */ + else if(!transformation) transformation = Matrix3{}; + + std::vector children; /* not const so we can move it */ + { + Containers::Array childrenArray = scene.childrenFor(id); + children = {childrenArray.begin(), childrenArray.end()}; + } + const Containers::Array> mesh = scene.meshesMaterialsFor(id); + const Containers::Array camera = scene.camerasFor(id); + const Containers::Array skin = scene.skinsFor(id); + const Containers::Optional importerState = scene.importerStateFor(id); + + /* All these should have at most 1 item as the old API doesn't have + any way to represent multi-function objects. */ + CORRADE_INTERNAL_ASSERT(camera.size() + mesh.size() <= 1); + + if(!mesh.empty()) { + return Containers::pointer(flags & ObjectFlag2D::HasTranslationRotationScaling ? + new MeshObjectData2D{std::move(children), + trs->first(), trs->second(), trs->third(), + mesh.front().first(), mesh.front().second(), + skin.empty() ? -1 : Int(skin.front()), + importerState ? *importerState : nullptr} : + new MeshObjectData2D{std::move(children), + *transformation, + mesh.front().first(), mesh.front().second(), + skin ? Int(*skin) : -1, + importerState ? *importerState : nullptr}); + } + + ObjectInstanceType2D instanceType; + UnsignedInt instance; + if(camera) { + instanceType = ObjectInstanceType2D::Camera; + instance = *camera; + } else { + instanceType = ObjectInstanceType2D::Empty; + instance = UnsignedInt(-1); /* Old APIs, you suck! */ + } + + return Containers::pointer(flags & ObjectFlag2D::HasTranslationRotationScaling ? + new ObjectData2D{std::move(children), + trs->first(), trs->second(), trs->third(), + instanceType, instance, + importerState ? *importerState : nullptr} : + new ObjectData2D{std::move(children), + *transformation, + instanceType, instance, + importerState ? *importerState : nullptr}); } Containers::Pointer AbstractImporter::object2D(const std::string& name) { @@ -509,40 +686,154 @@ Containers::Pointer AbstractImporter::object2D(const std::string& } return object2D(id); /* not doObject2D(), so we get the range checks also */ } +CORRADE_IGNORE_DEPRECATED_POP UnsignedInt AbstractImporter::object3DCount() const { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::object3DCount(): no file opened", {}); + CORRADE_IGNORE_DEPRECATED_PUSH return doObject3DCount(); + CORRADE_IGNORE_DEPRECATED_POP } -UnsignedInt AbstractImporter::doObject3DCount() const { return 0; } +UnsignedInt AbstractImporter::doObject3DCount() const { + /* I know, I know. A cleaner option would be to populate this during + openFile() / openData() but that would mean the backwards compatibility + overhead is there even if not using the deprecated APIs, which is way + worse than using this nasty hack in two places. */ + const_cast(*this).populateCachedScenes(); + return _cachedScenes->object3DCount; +} Int AbstractImporter::object3DForName(const std::string& name) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::object3DForName(): no file opened", {}); + CORRADE_IGNORE_DEPRECATED_PUSH const Int id = doObject3DForName(name); CORRADE_ASSERT(id == -1 || UnsignedInt(id) < doObject3DCount(), "Trade::AbstractImporter::object3DForName(): implementation-returned index" << id << "out of range for" << doObject3DCount() << "entries", {}); + CORRADE_IGNORE_DEPRECATED_POP return id; } -Int AbstractImporter::doObject3DForName(const std::string&) { return -1; } +Int AbstractImporter::doObject3DForName(const std::string& name) { + /* Alias to the new interface. If it returns an ID that's larger than + reported 3D object count, then it's probably for a 2D object instead + -- ignore it in that case. */ + const Long id = doObjectForName(name); + CORRADE_IGNORE_DEPRECATED_PUSH + return id < doObject3DCount() ? id : -1; + CORRADE_IGNORE_DEPRECATED_POP +} std::string AbstractImporter::object3DName(const UnsignedInt id) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::object3DName(): no file opened", {}); + CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_ASSERT(id < doObject3DCount(), "Trade::AbstractImporter::object3DName(): index" << id << "out of range for" << doObject3DCount() << "entries", {}); return doObject3DName(id); + CORRADE_IGNORE_DEPRECATED_POP } -std::string AbstractImporter::doObject3DName(UnsignedInt) { return {}; } +std::string AbstractImporter::doObject3DName(const UnsignedInt id) { + /* Alias to the new interface */ + return doObjectName(id); +} +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ Containers::Pointer AbstractImporter::object3D(const UnsignedInt id) { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::object3D(): no file opened", {}); CORRADE_ASSERT(id < doObject3DCount(), "Trade::AbstractImporter::object3D(): index" << id << "out of range for" << doObject3DCount() << "entries", {}); return doObject3D(id); } -Containers::Pointer AbstractImporter::doObject3D(UnsignedInt) { - CORRADE_ASSERT_UNREACHABLE("Trade::AbstractImporter::object3D(): not implemented", {}); +Containers::Pointer AbstractImporter::doObject3D(const UnsignedInt id) { + /* The code is mostly the same between doObject2D() and doObject3D(), + except that the 2D variant has no lights. Attempting to unify the common + code would be more complex than just having a slightly modified copy. */ + + populateCachedScenes(); + + /* Find the first 3D scene with this object, which we'll detect from the + object count reported for the scene, whether it's 2D or 3D, and a + presence of a parent attribute. If a parent attribute is not present, it + means the object isn't a part of this scene, in which case we skip it. + It could also mean isn't a part of the hierarchy and is standalone + (skyboxes, scene-wide properties), which the legacy API had no way to + deal with anyway so ignoring those is fine. */ + std::size_t sceneCandidate = ~std::size_t{}; + for(std::size_t i = 0; i != _cachedScenes->scenes.size(); ++i) { + const Containers::Optional& scene = _cachedScenes->scenes[i]; + if(scene && scene->is3D() && id < scene->objectCount() && scene->parentFor(id)) { + sceneCandidate = i; + break; + } + } + + if(sceneCandidate == ~std::size_t{}) { + Error{} << "Trade::AbstractImporter::object3D(): object" << id << "not found in any 3D scene hierarchy"; + return {}; + } + + const SceneData& scene = *_cachedScenes->scenes[sceneCandidate]; + + ObjectFlags3D flags; + Containers::Optional transformation = scene.transformation3DFor(id); + Containers::Optional> trs = scene.translationRotationScaling3DFor(id); + if(trs) + flags |= ObjectFlag3D::HasTranslationRotationScaling; + /* If the object has neither a TRS nor a transformation field, assign an + identity transform to it */ + else if(!transformation) transformation = Matrix4{}; + + std::vector children; /* not const so we can move it */ + { + Containers::Array childrenArray = scene.childrenFor(id); + children = {childrenArray.begin(), childrenArray.end()}; + } + const Containers::Array> mesh = scene.meshesMaterialsFor(id); + const Containers::Array camera = scene.camerasFor(id); + const Containers::Array skin = scene.skinsFor(id); + const Containers::Array light = scene.lightsFor(id); + const Containers::Optional importerState = scene.importerStateFor(id); + + /* All these should have at most 1 item as the old API doesn't have + any way to represent multi-function objects. */ + CORRADE_INTERNAL_ASSERT(camera.size() + light.size() + mesh.size() <= 1); + + if(!mesh.empty()) { + return Containers::pointer(flags & ObjectFlag3D::HasTranslationRotationScaling ? + new MeshObjectData3D{std::move(children), + trs->first(), trs->second(), trs->third(), + mesh.front().first(), mesh.front().second(), + skin.empty() ? -1 : Int(skin.front()), + importerState ? *importerState : nullptr} : + new MeshObjectData3D{std::move(children), + *transformation, + mesh.front().first(), mesh.front().second(), + skin ? Int(*skin) : -1, + importerState ? *importerState : nullptr}); + } + + ObjectInstanceType3D instanceType; + UnsignedInt instance; + if(camera) { + instanceType = ObjectInstanceType3D::Camera; + instance = *camera; + } else if(light) { + instanceType = ObjectInstanceType3D::Light; + instance = *light; + } else { + instanceType = ObjectInstanceType3D::Empty; + instance = UnsignedInt(-1); /* Old APIs, you suck! */ + } + + return Containers::pointer(flags & ObjectFlag3D::HasTranslationRotationScaling ? + new ObjectData3D{std::move(children), + trs->first(), trs->second(), trs->third(), + instanceType, instance, + importerState ? *importerState : nullptr} : + new ObjectData3D{std::move(children), + *transformation, + instanceType, instance, + importerState ? *importerState : nullptr}); } Containers::Pointer AbstractImporter::object3D(const std::string& name) { @@ -554,6 +845,8 @@ Containers::Pointer AbstractImporter::object3D(const std::string& } return object3D(id); /* not doObject3D(), so we get the range checks also */ } +CORRADE_IGNORE_DEPRECATED_POP +#endif UnsignedInt AbstractImporter::skin2DCount() const { CORRADE_ASSERT(isOpened(), "Trade::AbstractImporter::skin2DCount(): no file opened", {}); diff --git a/src/Magnum/Trade/AbstractImporter.h b/src/Magnum/Trade/AbstractImporter.h index 47c240250..77500ae28 100644 --- a/src/Magnum/Trade/AbstractImporter.h +++ b/src/Magnum/Trade/AbstractImporter.h @@ -181,14 +181,11 @@ ID of a texture it uses). The following kinds of data can be imported: @ref meshCount(). Similarly as with images, each mesh can also have multiple levels (LODs or for example separate edge/face data), which are requested through the second parameter up to @ref meshLevelCount(). -- @ref ObjectData2D / @ref ObjectData3D using - @ref object2D(UnsignedInt) / @ref object3D(UnsignedInt) up to - @ref object2DCount() / @ref object3DCount(). An object can then reference - its child objects, mesh and a material, camera, light or a skin associated - with it via their IDs. - @ref SceneData using @ref scene(UnsignedInt) up to @ref sceneCount(), with the default scene index exposed through @ref defaultScene(). A scene then - references its child 2D/3D objects via their IDs. + contains all data for its objects such as transformations and parent/child + hierarchy, particular objects are associated with meshes, materials, + cameras, lights or skins via their IDs. - @ref SkinData2D / @ref SkinData3D using @ref skin2D(UnsignedInt) / @ref skin3D(UnsignedInt) up to @ref skin2DCount() / @ref skin3DCount() - @ref TextureData using @ref texture(UnsignedInt) up to @ref textureCount(). @@ -303,10 +300,8 @@ name doesn't exist. @ref mesh(const std::string&, UnsignedInt). Meshes themselves can have custom attributes, for which the name mapping can be retrieved using @ref meshAttributeName() and @ref meshAttributeForName(). -- Objects names using @ref object2DName() / @ref object3DName() & - @ref object2DForName() / @ref object3DForName(), imported with - @ref object2D(const std::string&) / @ref object3D(const std::string&) -- Scene names using @ref sceneName() & @ref sceneForName(), imported with +- Scene and object names using @ref sceneName() / @ref objectName() & + @ref sceneForName() / @ref objectForName(), imported with @ref scene(const std::string&). Scenes themselves can have custom fields, for which the name mapping can be retrieved using @ref sceneFieldName() and @ref sceneFieldForName(). @@ -335,10 +330,9 @@ expose internal state through various accessors: imported by @ref light() - @ref MeshData::importerState() can expose importer state for a mesh imported by @ref mesh() -- @ref ObjectData3D::importerState() can expose importer state for an object - imported by @ref object2D() or @ref object3D() - @ref SceneData::importerState() can expose importer state for a scene - imported by @ref scene() + imported by @ref scene(), per-object importer state can then be stored in + the @ref SceneField::ImporterState field - @ref SkinData::importerState() can expose importer state for a scene imported by @ref skin2D() or @ref skin3D() - @ref TextureData::importerState() can expose importer state for a texture @@ -349,20 +343,6 @@ Besides exposing internal state, importers that support the state using @ref openState(). See documentation of a particular importer for details about concrete types returned and accepted by these functions. -@subsection Trade-AbstractImporter-usage-casting Polymorphic imported data types - -Some data access functions return @relativeref{Corrade,Containers::Pointer} -instead of @relativeref{Corrade,Containers::Optional} because the result might -be a particular subclass of given type. Those functions are @ref object2D() -and @ref object3D(). You can cast the abstract base to a concrete type -depending on its reported type, for example: - -@snippet MagnumTrade.cpp AbstractImporter-usage-cast - -Another option is making use of the @ref Containers::pointerCast() utility, but -note that in that case the original @relativeref{Corrade,Containers::Pointer} -will have to be *moved into* a new instance, which might not be desirable. - @section Trade-AbstractImporter-data-dependency Data dependency The `*Data` instances returned from various functions *by design* have no @@ -493,6 +473,14 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi /** @brief Plugin manager constructor */ explicit AbstractImporter(PluginManager::AbstractManager& manager, const std::string& plugin); + #if defined(MAGNUM_BUILD_DEPRECATED) && !defined(DOXYGEN_GENERATING_OUTPUT) + /* These twp needed because of the Array member + (AnyImageImporter relies on the move), move assignment disabled by + AbstractPlugin already */ + AbstractImporter(AbstractImporter&&) noexcept; + ~AbstractImporter(); + #endif + /** @brief Features supported by this importer */ ImporterFeatures features() const { return doFeatures(); } @@ -723,6 +711,17 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ UnsignedInt sceneCount() const; + /** + * @brief Object count + * + * Total count of all (2D or 3D) objects in all scenes. An object can + * be present in multiple scenes at the same time. Fields corresponding + * to particular objects can be then accessed via the @ref SceneData + * class returned from @ref scene(UnsignedInt). Expects that a file is + * opened. + */ + UnsignedLong objectCount() const; + /** * @brief Scene for given name * @return Scene ID from range [0, @ref sceneCount()) or @cpp -1 @ce if @@ -733,6 +732,16 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ Int sceneForName(const std::string& name); + /** + * @brief Object ID for given name + * + * If no object for given name exists, returns @cpp -1 @ce. Expects + * that a file is opened. Object IDs are shared among all scenes, an + * object can be present in multiple scenes at the same time. + * @see @ref objectName() + */ + Long objectForName(const std::string& name); + /** * @brief Scene name * @param id Scene ID, from range [0, @ref sceneCount()). @@ -743,6 +752,18 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ std::string sceneName(UnsignedInt id); + /** + * @brief Object name + * @param id Object ID, from range [0, @ref objectCount()). + * + * Object IDs are shared among all scenes, an object can be present in + * multiple scenes at the same time. If the object has no name or the + * importer doesn't support object names, returns an empty string. + * Expects that a file is opened. + * @see @ref objectForName() + */ + std::string objectName(UnsignedLong id); + /** * @brief Scene * @param id Scene ID, from range [0, @ref sceneCount()). @@ -940,12 +961,15 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ Containers::Optional camera(const std::string& name); + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Two-dimensional object count * * Expects that a file is opened. + * @m_deprecated_since_latest Use @ref objectCount() instead, which is + * shared for both 2D and 3D objects. */ - UnsignedInt object2DCount() const; + CORRADE_DEPRECATED("use objectCount() instead") UnsignedInt object2DCount() const; /** * @brief Two-dimensional object for given name @@ -953,9 +977,11 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * @cpp -1 @ce if no object for given name exists * * Expects that a file is opened. + * @m_deprecated_since_latest Use @ref objectForName() instead, which + * is shared for both 2D and 3D objects. * @see @ref object2DName(), @ref object2D(const std::string&) */ - Int object2DForName(const std::string& name); + CORRADE_DEPRECATED("use objectForName() instead") Int object2DForName(const std::string& name); /** * @brief Two-dimensional object name @@ -963,9 +989,11 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * * Expects that a file is opened. If the object has no name or the * importer doesn't support object names, returns an empty string. + * @m_deprecated_since_latest Use @ref objectName() instead, which is + * shared for both 2D and 3D objects. * @see @ref object2DForName() */ - std::string object2DName(UnsignedInt id); + CORRADE_DEPRECATED("use objectName() instead") std::string object2DName(UnsignedInt id); /** * @brief Two-dimensional object @@ -973,9 +1001,14 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * * Returns given object or @cpp nullptr @ce if importing failed. * Expects that a file is opened. + * @m_deprecated_since_latest Query object fields on the @ref SceneData + * object returned from @ref scene() instead, which is shared for + * both 2D and 3D objects. * @see @ref object2D(const std::string&) */ - Containers::Pointer object2D(UnsignedInt id); + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ + CORRADE_DEPRECATED("query object fields from scene() instead") Containers::Pointer object2D(UnsignedInt id); + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Two-dimensional object for given name @@ -986,15 +1019,22 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * @cpp -1 @ce, prints an error message and returns * @cpp nullptr @ce, otherwise propagates the result from * @ref object2D(UnsignedInt). Expects that a file is opened. + * @m_deprecated_since_latest Query object fields on the @ref SceneData + * object returned from @ref scene() instead, which is shared for + * both 2D and 3D objects. */ - Containers::Pointer object2D(const std::string& name); + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ + CORRADE_DEPRECATED("query object fields from scene() instead") Containers::Pointer object2D(const std::string& name); + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Three-dimensional object count * * Expects that a file is opened. + * @m_deprecated_since_latest Use @ref objectCount() instead, which is + * shared for both 2D and 3D objects. */ - UnsignedInt object3DCount() const; + CORRADE_DEPRECATED("use objectCount() instead") UnsignedInt object3DCount() const; /** * @brief Three-dimensional object for given name @@ -1002,9 +1042,11 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * @cpp -1 @ce if no object for given name exists * * Expects that a file is opened. + * @m_deprecated_since_latest Use @ref objectForName() instead, which + * is shared for both 2D and 3D objects. * @see @ref object3DName(), @ref object3D(const std::string&) */ - Int object3DForName(const std::string& name); + CORRADE_DEPRECATED("use objectForName() instead") Int object3DForName(const std::string& name); /** * @brief Three-dimensional object name @@ -1012,9 +1054,11 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * * Expects that a file is opened. If the object has no name or the * importer doesn't support object names, returns an empty string. + * @m_deprecated_since_latest Use @ref objectName() instead, which is + * shared for both 2D and 3D objects. * @see @ref object3DForName() */ - std::string object3DName(UnsignedInt id); + CORRADE_DEPRECATED("use objectName() instead") std::string object3DName(UnsignedInt id); /** * @brief Three-dimensional object @@ -1022,9 +1066,14 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * * Returns given object or @cpp nullptr @ce if importing failed. * Expects that a file is opened. + * @m_deprecated_since_latest Query object fields on the @ref SceneData + * object returned from @ref scene() instead, which is shared for + * both 2D and 3D objects. * @see @ref object3D(const std::string&) */ - Containers::Pointer object3D(UnsignedInt id); + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ + CORRADE_DEPRECATED("query object fields from scene() instead") Containers::Pointer object3D(UnsignedInt id); + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Three-dimensional object for given name @@ -1035,8 +1084,14 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi * @cpp -1 @ce, prints an error message and returns * @cpp nullptr @ce, otherwise propagates the result from * @ref object3D(UnsignedInt). Expects that a file is opened. + * @m_deprecated_since_latest Query object fields on the @ref SceneData + * object returned from @ref scene() instead, which is shared for + * both 2D and 3D objects. */ - Containers::Pointer object3D(const std::string& name); + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ + CORRADE_DEPRECATED("query object fields from scene() instead") Containers::Pointer object3D(const std::string& name); + CORRADE_IGNORE_DEPRECATED_POP + #endif /** * @brief Two-dimensional skin count @@ -1772,6 +1827,16 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ virtual UnsignedInt doSceneCount() const; + /** + * @brief Implementation for @ref objectCount() + * + * Default implementation returns @cpp 0 @ce. This function isn't + * expected to fail --- if an import error occus, it should be handled + * preferably during @ref doScene() (with correct object count + * reported), and if not possible, already during file opening. + */ + virtual UnsignedLong doObjectCount() const; + /** * @brief Implementation for @ref sceneForName() * @@ -1779,6 +1844,13 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ virtual Int doSceneForName(const std::string& name); + /** + * @brief Implementation for @ref objectForName() + * + * Default implementation returns @cpp -1 @ce. + */ + virtual Long doObjectForName(const std::string& name); + /** * @brief Implementation for @ref sceneName() * @@ -1786,6 +1858,13 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi */ virtual std::string doSceneName(UnsignedInt id); + /** + * @brief Implementation for @ref objectName() + * + * Default implementation returns an empty string. + */ + virtual std::string doObjectName(UnsignedLong id); + /** @brief Implementation for @ref scene() */ virtual Containers::Optional doScene(UnsignedInt id); @@ -1887,59 +1966,121 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi /** @brief Implementation for @ref camera() */ virtual Containers::Optional doCamera(UnsignedInt id); + #ifdef MAGNUM_BUILD_DEPRECATED /** * @brief Implementation for @ref object2DCount() * - * Default implementation returns @cpp 0 @ce. This function isn't - * expected to fail --- if an import error occus, it should be handled - * preferably during @ref doObject2D() (with correct object count - * reported), and if not possible, already during file opening. + * Default implementation returns @cpp 0 @ce. There weren't any + * importers in existence known to implement 2D scene import, so unlike + * @ref doObject3DCount() this function doesn't delegate to + * @ref doObjectCount(). + * @m_deprecated_since_latest Implement @ref doObjectCount() instead. */ + /* MSVC warns when overriding such methods and there's no way to + suppress that warning, making the RT build (which treats deprecation + warnings as errors) fail and other builds extremely noisy. So + disabling those on MSVC. */ + #if !(defined(CORRADE_TARGET_MSVC) && !defined(CORRADE_TARGET_CLANG)) + CORRADE_DEPRECATED("implement doObjectCount() instead") + #endif virtual UnsignedInt doObject2DCount() const; /** * @brief Implementation for @ref object2DForName() * - * Default implementation returns @cpp -1 @ce. + * Default implementation returns @cpp -1 @ce. There weren't any + * importers in existence known to implement 2D scene import, so unlike + * @ref doObject3DForName() this function doesn't delegate to + * @ref doObjectForName(). + * @m_deprecated_since_latest Implement @ref doObjectForName() instead. */ + #if !(defined(CORRADE_TARGET_MSVC) && !defined(CORRADE_TARGET_CLANG)) + CORRADE_DEPRECATED("implement doObjectForName() instead") + #endif /* See above */ virtual Int doObject2DForName(const std::string& name); /** * @brief Implementation for @ref object2DName() * - * Default implementation returns an empty string. + * Default implementation returns an empty string. There weren't any + * importers in existence known to implement 2D scene import, so unlike + * @ref doObject3DName() this function doesn't delegate to + * @ref doObjectName(). + * @m_deprecated_since_latest Implement @ref doObjectName() instead. */ + #if !(defined(CORRADE_TARGET_MSVC) && !defined(CORRADE_TARGET_CLANG)) + CORRADE_DEPRECATED("implement doObjectName() instead") + #endif /* See above */ virtual std::string doObject2DName(UnsignedInt id); - /** @brief Implementation for @ref object2D() */ + /** + * @brief Implementation for @ref object2D() + * + * There weren't any importers in existence known to implement 2D scene + * import, so unlike @ref doObject3D() this function doesn't proxy + * per-object data returned from @ref doScene(). + * @m_deprecated_since_latest Implement @ref doScene() instead. + */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ + #if !(defined(CORRADE_TARGET_MSVC) && !defined(CORRADE_TARGET_CLANG)) + CORRADE_DEPRECATED("implement doScene() instead") + #endif /* See above */ virtual Containers::Pointer doObject2D(UnsignedInt id); + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Implementation for @ref object3DCount() * - * Default implementation returns @cpp 0 @ce. This function isn't - * expected to fail --- if an import error occus, it should be handled - * preferably during @ref doObject3D() (with correct object count - * reported), and if not possible, already during file opening. + * Default implementation returns @ref doObjectCount() for backwards + * compatibility. + * @m_deprecated_since_latest Implement @ref doObjectCount() instead. */ + #if !(defined(CORRADE_TARGET_MSVC) && !defined(CORRADE_TARGET_CLANG)) + CORRADE_DEPRECATED("implement doObjectCount() instead") + #endif /* See above */ virtual UnsignedInt doObject3DCount() const; /** * @brief Implementation for @ref object3DForName() * - * Default implementation returns @cpp -1 @ce. + * Default implementation returns @ref doObjectForName() for backwards + * compatibility. + * @m_deprecated_since_latest Implement @ref doObjectForName() instead. */ + #if !(defined(CORRADE_TARGET_MSVC) && !defined(CORRADE_TARGET_CLANG)) + CORRADE_DEPRECATED("implement doObjectForName() instead") + #endif /* See above */ virtual Int doObject3DForName(const std::string& name); /** * @brief Implementation for @ref object3DName() * - * Default implementation returns an empty string. + * Default implementation returns @ref doObjectName() for backwards + * compatibility. + * @m_deprecated_since_latest Implement @ref doObjectName() instead. */ + #if !(defined(CORRADE_TARGET_MSVC) && !defined(CORRADE_TARGET_CLANG)) + CORRADE_DEPRECATED("implement doObjectName() instead") + #endif /* See above */ virtual std::string doObject3DName(UnsignedInt id); - /** @brief Implementation for @ref object3D() */ + /** + * @brief Implementation for @ref object3D() + * + * Default implementation retrieves and caches scenes returned from + * @ref doScene(), finds the first scene that contains any fields for + * object @p id and then returns a subset of the data that's + * representable with a @ref ObjectData3D / @ref MeshObjectData3D + * instance. + * @m_deprecated_since_latest Implement @ref doScene() instead. + */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ + #if !(defined(CORRADE_TARGET_MSVC) && !defined(CORRADE_TARGET_CLANG)) + CORRADE_DEPRECATED("implement doScene() instead") + #endif /* See above */ virtual Containers::Pointer doObject3D(UnsignedInt id); + CORRADE_IGNORE_DEPRECATED_POP + #endif /** * @brief Implementation for @ref skin2DCount() @@ -2368,6 +2509,12 @@ class MAGNUM_TRADE_EXPORT AbstractImporter: public PluginManager::AbstractManagi const void* userData; /* GCC 4.8 complains loudly about missing initializers otherwise */ } _fileCallbackTemplate{nullptr, nullptr}; + + #ifdef MAGNUM_BUILD_DEPRECATED + struct CachedScenes; + Containers::Pointer _cachedScenes; + void populateCachedScenes(); + #endif }; #ifndef DOXYGEN_GENERATING_OUTPUT diff --git a/src/Magnum/Trade/CMakeLists.txt b/src/Magnum/Trade/CMakeLists.txt index ec032592e..2a6fc229f 100644 --- a/src/Magnum/Trade/CMakeLists.txt +++ b/src/Magnum/Trade/CMakeLists.txt @@ -28,8 +28,6 @@ find_package(Corrade REQUIRED PluginManager) set(MagnumTrade_SRCS ArrayAllocator.cpp Data.cpp - MeshObjectData2D.cpp - MeshObjectData3D.cpp TextureData.cpp) set(MagnumTrade_GracefulAssert_SRCS @@ -43,8 +41,6 @@ set(MagnumTrade_GracefulAssert_SRCS LightData.cpp MaterialData.cpp MeshData.cpp - ObjectData2D.cpp - ObjectData3D.cpp PbrClearCoatMaterialData.cpp PbrMetallicRoughnessMaterialData.cpp PbrSpecularGlossinessMaterialData.cpp @@ -66,10 +62,6 @@ set(MagnumTrade_HEADERS MaterialData.h MaterialLayerData.h MeshData.h - MeshObjectData2D.h - MeshObjectData3D.h - ObjectData2D.h - ObjectData3D.h PbrClearCoatMaterialData.h PbrMetallicRoughnessMaterialData.h PbrSpecularGlossinessMaterialData.h @@ -87,6 +79,9 @@ set(MagnumTrade_PRIVATE_HEADERS Implementation/materialAttributeProperties.hpp) if(MAGNUM_BUILD_DEPRECATED) + list(APPEND MagnumTrade_SRCS + MeshObjectData2D.cpp + MeshObjectData3D.cpp) list(APPEND MagnumTrade_GracefulAssert_SRCS # These have to be here instead of in MagnumTrade_SRCS because they # include MeshData.h and call (and thus instantiate) various functions @@ -96,12 +91,19 @@ if(MAGNUM_BUILD_DEPRECATED) # causing the tests to blow up. Happens only on the MSVC linker, but # let's be safe and do this everywhere. MeshData2D.cpp - MeshData3D.cpp) + MeshData3D.cpp + + ObjectData2D.cpp + ObjectData3D.cpp) list(APPEND MagnumTrade_HEADERS AbstractMaterialData.h MeshData2D.h - MeshData3D.h) + MeshData3D.h + MeshObjectData2D.h + MeshObjectData3D.h + ObjectData2D.h + ObjectData3D.h) endif() if(NOT CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT) diff --git a/src/Magnum/Trade/MeshObjectData2D.cpp b/src/Magnum/Trade/MeshObjectData2D.cpp index 2d478d8a3..0b587131a 100644 --- a/src/Magnum/Trade/MeshObjectData2D.cpp +++ b/src/Magnum/Trade/MeshObjectData2D.cpp @@ -23,12 +23,18 @@ DEALINGS IN THE SOFTWARE. */ +#define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */ + #include "MeshObjectData2D.h" namespace Magnum { namespace Trade { +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ MeshObjectData2D::MeshObjectData2D(std::vector children, const Matrix3& transformation, const UnsignedInt instance, const Int material, const Int skin, const void* const importerState): ObjectData2D{std::move(children), transformation, ObjectInstanceType2D::Mesh, instance, importerState}, _material{material}, _skin{skin} {} +CORRADE_IGNORE_DEPRECATED_POP +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ MeshObjectData2D::MeshObjectData2D(std::vector children, const Vector2& translation, const Complex& rotation, const Vector2& scaling, const UnsignedInt instance, const Int material, const Int skin, const void* const importerState): ObjectData2D{std::move(children), translation, rotation, scaling, ObjectInstanceType2D::Mesh, instance, importerState}, _material{material}, _skin{skin} {} +CORRADE_IGNORE_DEPRECATED_POP }} diff --git a/src/Magnum/Trade/MeshObjectData2D.h b/src/Magnum/Trade/MeshObjectData2D.h index 5171e5556..1e215f772 100644 --- a/src/Magnum/Trade/MeshObjectData2D.h +++ b/src/Magnum/Trade/MeshObjectData2D.h @@ -25,21 +25,33 @@ DEALINGS IN THE SOFTWARE. */ +#ifdef MAGNUM_BUILD_DEPRECATED /** @file * @brief Class @ref Magnum::Trade::MeshObjectData2D */ +#endif + +#include "Magnum/configure.h" +#ifdef MAGNUM_BUILD_DEPRECATED #include "Magnum/Trade/ObjectData2D.h" +#ifndef _MAGNUM_NO_DEPRECATED_OBJECTDATA +CORRADE_DEPRECATED_FILE("use Magnum/Trade/SceneData.h and the SceneData class instead") +#endif + namespace Magnum { namespace Trade { +CORRADE_IGNORE_DEPRECATED_PUSH /* MSVC warns on the inheritance */ + /** @brief Two-dimensional mesh object data +@m_deprecated_since_latest Use @ref SceneData instead. Provides access to material information for given mesh instance. @see @ref AbstractImporter::object2D(), @ref MeshObjectData3D */ -class MAGNUM_TRADE_EXPORT MeshObjectData2D: public ObjectData2D { +class CORRADE_DEPRECATED("use SceneData instead") MAGNUM_TRADE_EXPORT MeshObjectData2D: public ObjectData2D { public: /** * @brief Construct with combined transformation @@ -54,13 +66,11 @@ class MAGNUM_TRADE_EXPORT MeshObjectData2D: public ObjectData2D { */ explicit MeshObjectData2D(std::vector children, const Matrix3& transformation, UnsignedInt instance, Int material, Int skin, const void* importerState = nullptr); - #ifdef MAGNUM_BUILD_DEPRECATED /** @brief @copybrief MeshObjectData2D(std::vector, const Matrix3&, UnsignedInt, Int, Int, const void*) * @m_deprecated_since_latest Use @ref MeshObjectData2D(std::vector, const Matrix3&, UnsignedInt, Int, Int, const void*) * instead. */ explicit CORRADE_DEPRECATED("use MeshObjectData2D(std::vector, const Matrix4&, UnsignedInt, Int, Int, const void*) instead") MeshObjectData2D(std::vector children, const Matrix3& transformation, UnsignedInt instance, Int material, const void* importerState = nullptr): MeshObjectData2D{std::move(children), transformation, instance, material, -1, importerState} {} - #endif /** * @brief Construct with separate transformations @@ -132,6 +142,11 @@ class MAGNUM_TRADE_EXPORT MeshObjectData2D: public ObjectData2D { Int _material, _skin; }; +CORRADE_IGNORE_DEPRECATED_POP /* MSVC warns on the inheritance */ + }} +#else +#error use Magnum/Trade/SceneData.h and the SceneData class instead +#endif #endif diff --git a/src/Magnum/Trade/MeshObjectData3D.cpp b/src/Magnum/Trade/MeshObjectData3D.cpp index 00f58c2b2..67223b635 100644 --- a/src/Magnum/Trade/MeshObjectData3D.cpp +++ b/src/Magnum/Trade/MeshObjectData3D.cpp @@ -23,12 +23,18 @@ DEALINGS IN THE SOFTWARE. */ +#define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */ + #include "MeshObjectData3D.h" namespace Magnum { namespace Trade { +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ MeshObjectData3D::MeshObjectData3D(std::vector children, const Matrix4& transformation, const UnsignedInt instance, const Int material, const Int skin, const void* const importerState): ObjectData3D{std::move(children), transformation, ObjectInstanceType3D::Mesh, instance, importerState}, _material{material}, _skin{skin} {} +CORRADE_IGNORE_DEPRECATED_POP +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ MeshObjectData3D::MeshObjectData3D(std::vector children, const Vector3& translation, const Quaternion& rotation, const Vector3& scaling, const UnsignedInt instance, const Int material, const Int skin, const void* const importerState): ObjectData3D{std::move(children), translation, rotation, scaling, ObjectInstanceType3D::Mesh, instance, importerState}, _material{material}, _skin{skin} {} +CORRADE_IGNORE_DEPRECATED_POP }} diff --git a/src/Magnum/Trade/MeshObjectData3D.h b/src/Magnum/Trade/MeshObjectData3D.h index ad43aa5ba..64236ccc6 100644 --- a/src/Magnum/Trade/MeshObjectData3D.h +++ b/src/Magnum/Trade/MeshObjectData3D.h @@ -25,21 +25,33 @@ DEALINGS IN THE SOFTWARE. */ +#ifdef MAGNUM_BUILD_DEPRECATED /** @file * @brief Class @ref Magnum::Trade::MeshObjectData3D */ +#endif + +#include "Magnum/configure.h" +#ifdef MAGNUM_BUILD_DEPRECATED #include "Magnum/Trade/ObjectData3D.h" +#ifndef _MAGNUM_NO_DEPRECATED_OBJECTDATA +CORRADE_DEPRECATED_FILE("use Magnum/Trade/SceneData.h and the SceneData class instead") +#endif + namespace Magnum { namespace Trade { +CORRADE_IGNORE_DEPRECATED_PUSH /* MSVC warns on the inheritance */ + /** @brief Three-dimensional mesh object data +@m_deprecated_since_latest Use @ref SceneData instead. Provides access to material information for given mesh instance. @see @ref AbstractImporter::object3D(), @ref MeshObjectData2D */ -class MAGNUM_TRADE_EXPORT MeshObjectData3D: public ObjectData3D { +class CORRADE_DEPRECATED("use SceneData instead") MAGNUM_TRADE_EXPORT MeshObjectData3D: public ObjectData3D { public: /** * @brief Construct with combined transformation @@ -132,6 +144,11 @@ class MAGNUM_TRADE_EXPORT MeshObjectData3D: public ObjectData3D { Int _material, _skin; }; +CORRADE_IGNORE_DEPRECATED_POP /* MSVC warns on the inheritance */ + }} +#else +#error use Magnum/Trade/SceneData.h and the SceneData class instead +#endif #endif diff --git a/src/Magnum/Trade/ObjectData2D.cpp b/src/Magnum/Trade/ObjectData2D.cpp index e2a2cc826..d192bac22 100644 --- a/src/Magnum/Trade/ObjectData2D.cpp +++ b/src/Magnum/Trade/ObjectData2D.cpp @@ -23,62 +23,85 @@ DEALINGS IN THE SOFTWARE. */ +#define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */ + #include "ObjectData2D.h" #include namespace Magnum { namespace Trade { +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectData2D::ObjectData2D(std::vector children, const Matrix3& transformation, const ObjectInstanceType2D instanceType, const UnsignedInt instance, const void* const importerState): _children{std::move(children)}, _transformation{transformation}, _instanceType{instanceType}, _flags{}, _instance{Int(instance)}, _importerState{importerState} {} +CORRADE_IGNORE_DEPRECATED_POP +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectData2D::ObjectData2D(std::vector children, const Vector2& translation, const Complex& rotation, const Vector2& scaling, const ObjectInstanceType2D instanceType, const UnsignedInt instance, const void* const importerState): _children{std::move(children)}, _transformation{translation, rotation, scaling}, _instanceType{instanceType}, _flags{ObjectFlag2D::HasTranslationRotationScaling}, _instance{Int(instance)}, _importerState{importerState} {} +CORRADE_IGNORE_DEPRECATED_POP +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectData2D::ObjectData2D(std::vector children, const Matrix3& transformation, const void* const importerState): _children{std::move(children)}, _transformation{transformation}, _instanceType{ObjectInstanceType2D::Empty}, _flags{}, _instance{-1}, _importerState{importerState} {} +CORRADE_IGNORE_DEPRECATED_POP +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectData2D::ObjectData2D(std::vector children, const Vector2& translation, const Complex& rotation, const Vector2& scaling, const void* const importerState): _children{std::move(children)}, _transformation{translation, rotation, scaling}, _instanceType{ObjectInstanceType2D::Empty}, _flags{ObjectFlag2D::HasTranslationRotationScaling}, _instance{-1}, _importerState{importerState} {} +CORRADE_IGNORE_DEPRECATED_POP +CORRADE_IGNORE_DEPRECATED_PUSH /* MSVC warns here */ ObjectData2D::ObjectData2D(ObjectData2D&&) #if !defined(__GNUC__) || __GNUC__*100 + __GNUC_MINOR__ != 409 noexcept #endif = default; +CORRADE_IGNORE_DEPRECATED_POP ObjectData2D::~ObjectData2D() = default; +CORRADE_IGNORE_DEPRECATED_PUSH /* GCC why you warn on return and not on param */ ObjectData2D& ObjectData2D::operator=(ObjectData2D&&) #if !defined(__GNUC__) || __GNUC__*100 + __GNUC_MINOR__ != 409 noexcept #endif = default; +CORRADE_IGNORE_DEPRECATED_POP Vector2 ObjectData2D::translation() const { + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ CORRADE_ASSERT(_flags & ObjectFlag2D::HasTranslationRotationScaling, "Trade::ObjectData2D::translation(): object has only a combined transformation", {}); + CORRADE_IGNORE_DEPRECATED_POP return _transformation.trs.translation; } Complex ObjectData2D::rotation() const { + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ CORRADE_ASSERT(_flags & ObjectFlag2D::HasTranslationRotationScaling, "Trade::ObjectData2D::rotation(): object has only a combined transformation", {}); + CORRADE_IGNORE_DEPRECATED_POP return _transformation.trs.rotation; } Vector2 ObjectData2D::scaling() const { + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ CORRADE_ASSERT(_flags & ObjectFlag2D::HasTranslationRotationScaling, "Trade::ObjectData2D::scaling(): object has only a combined transformation", {}); + CORRADE_IGNORE_DEPRECATED_POP return _transformation.trs.scaling; } Matrix3 ObjectData2D::transformation() const { + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ if(_flags & ObjectFlag2D::HasTranslationRotationScaling) /* Has to be on a single line otherwise lcov reports an uncovered line. Ugh. */ return Matrix3::from(_transformation.trs.rotation.toMatrix(), _transformation.trs.translation)* Matrix3::scaling(_transformation.trs.scaling); + CORRADE_IGNORE_DEPRECATED_POP return _transformation.matrix; } #ifndef DOXYGEN_GENERATING_OUTPUT +CORRADE_IGNORE_DEPRECATED_PUSH Debug& operator<<(Debug& debug, const ObjectInstanceType2D value) { debug << "Trade::ObjectInstanceType2D" << Debug::nospace; @@ -113,6 +136,7 @@ Debug& operator<<(Debug& debug, const ObjectFlags2D value) { return enumSetDebugOutput(debug, value, "Trade::ObjectFlags2D{}", { ObjectFlag2D::HasTranslationRotationScaling}); } +CORRADE_IGNORE_DEPRECATED_POP #endif }} diff --git a/src/Magnum/Trade/ObjectData2D.h b/src/Magnum/Trade/ObjectData2D.h index 5023dedbe..8f50c129d 100644 --- a/src/Magnum/Trade/ObjectData2D.h +++ b/src/Magnum/Trade/ObjectData2D.h @@ -25,10 +25,17 @@ DEALINGS IN THE SOFTWARE. */ +#ifdef MAGNUM_BUILD_DEPRECATED /** @file * @brief Class @ref Magnum::Trade::ObjectData2D, enum @ref Magnum::Trade::ObjectInstanceType2D + * @m_deprecated_since_latest Use @ref Magnum/Trade/SceneData.h and the + * @relativeref{Magnum::Trade,SceneData} class instead. */ +#endif + +#include "Magnum/configure.h" +#ifdef MAGNUM_BUILD_DEPRECATED #include #include "Magnum/Magnum.h" @@ -36,14 +43,19 @@ #include "Magnum/Math/Complex.h" #include "Magnum/Trade/visibility.h" +#ifndef _MAGNUM_NO_DEPRECATED_OBJECTDATA +CORRADE_DEPRECATED_FILE("use Magnum/Trade/SceneData.h and the SceneData class instead") +#endif + namespace Magnum { namespace Trade { /** @brief Type of instance held by given 2D object +@m_deprecated_since_latest Use @ref SceneData instead. @see @ref ObjectData2D::instanceType() */ -enum class ObjectInstanceType2D: UnsignedByte { +enum class CORRADE_DEPRECATED_ENUM("use SceneData instead") ObjectInstanceType2D: UnsignedByte { Camera, /**< Camera instance (see @ref CameraData) */ /** @@ -57,10 +69,11 @@ enum class ObjectInstanceType2D: UnsignedByte { /** @brief 2D object flag +@m_deprecated_since_latest Use @ref SceneData instead. @see @ref ObjectFlags2D, @ref ObjectData2D::flags() */ -enum class ObjectFlag2D: UnsignedByte { +enum class CORRADE_DEPRECATED_ENUM("use SceneData instead") ObjectFlag2D: UnsignedByte { /** * The object provides separate translation / rotation / scaling * properties. The @ref ObjectData2D::transformation() matrix returns them @@ -73,21 +86,27 @@ enum class ObjectFlag2D: UnsignedByte { /** @brief 2D object flags +@m_deprecated_since_latest Use @ref SceneData instead. @see @ref ObjectData2D::flags() */ -typedef Containers::EnumSet ObjectFlags2D; +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ +typedef CORRADE_DEPRECATED("use SceneData instead") Containers::EnumSet ObjectFlags2D; +CORRADE_IGNORE_DEPRECATED_POP +CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_ENUMSET_OPERATORS(ObjectFlags2D) +CORRADE_IGNORE_DEPRECATED_POP /** @brief Two-dimensional object data +@m_deprecated_since_latest Use @ref SceneData instead. Provides access to object transformation and hierarchy. @see @ref AbstractImporter::object2D(), @ref MeshObjectData2D, @ref ObjectData3D */ -class MAGNUM_TRADE_EXPORT ObjectData2D { +class CORRADE_DEPRECATED("use SceneData instead") MAGNUM_TRADE_EXPORT ObjectData2D { public: /** * @brief Construct with combined transformation @@ -97,7 +116,9 @@ class MAGNUM_TRADE_EXPORT ObjectData2D { * @param instance Instance ID * @param importerState Importer-specific state */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ explicit ObjectData2D(std::vector children, const Matrix3& transformation, ObjectInstanceType2D instanceType, UnsignedInt instance, const void* importerState = nullptr); + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Construct with separate transformations @@ -109,7 +130,9 @@ class MAGNUM_TRADE_EXPORT ObjectData2D { * @param instance Instance ID * @param importerState Importer-specific state */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ explicit ObjectData2D(std::vector children, const Vector2& translation, const Complex& rotation, const Vector2& scaling, ObjectInstanceType2D instanceType, UnsignedInt instance, const void* importerState = nullptr); + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Construct empty instance with combined transformation @@ -163,7 +186,9 @@ class MAGNUM_TRADE_EXPORT ObjectData2D { const std::vector& children() const { return _children; } /**< @overload */ /** @brief Flags */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectFlags2D flags() const { return _flags; } + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Translation (relative to parent) @@ -224,7 +249,9 @@ class MAGNUM_TRADE_EXPORT ObjectData2D { * * @see @ref instance() */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectInstanceType2D instanceType() const { return _instanceType; } + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Instance ID @@ -256,21 +283,37 @@ class MAGNUM_TRADE_EXPORT ObjectData2D { Vector2 scaling; } trs; } _transformation; + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectInstanceType2D _instanceType; ObjectFlags2D _flags; + CORRADE_IGNORE_DEPRECATED_POP Int _instance; const void* _importerState; }; -/** @debugoperatorenum{ObjectInstanceType2D} */ +CORRADE_IGNORE_DEPRECATED_PUSH +/** +@debugoperatorenum{ObjectInstanceType2D} +@m_deprecated_since_latest Use @ref SceneData instead. +*/ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, ObjectInstanceType2D value); -/** @debugoperatorenum{ObjectFlag2D} */ +/** +@debugoperatorenum{ObjectFlag2D} +@m_deprecated_since_latest Use @ref SceneData instead. +*/ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, ObjectFlag2D value); -/** @debugoperatorenum{ObjectFlags2D} */ +/** +@debugoperatorenum{ObjectFlags2D} +@m_deprecated_since_latest Use @ref SceneData instead. +*/ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, ObjectFlags2D value); +CORRADE_IGNORE_DEPRECATED_POP }} +#else +#error use Magnum/Trade/SceneData.h and the SceneData class instead +#endif #endif diff --git a/src/Magnum/Trade/ObjectData3D.cpp b/src/Magnum/Trade/ObjectData3D.cpp index 37d5b2f68..b7eb50c0c 100644 --- a/src/Magnum/Trade/ObjectData3D.cpp +++ b/src/Magnum/Trade/ObjectData3D.cpp @@ -23,62 +23,81 @@ DEALINGS IN THE SOFTWARE. */ +#define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */ + #include "ObjectData3D.h" #include namespace Magnum { namespace Trade { +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectData3D::ObjectData3D(std::vector children, const Matrix4& transformation, const ObjectInstanceType3D instanceType, const UnsignedInt instance, const void* const importerState): _children{std::move(children)}, _transformation{transformation}, _instanceType{instanceType}, _flags{}, _instance{Int(instance)}, _importerState{importerState} {} +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectData3D::ObjectData3D(std::vector children, const Vector3& translation, const Quaternion& rotation, const Vector3& scaling, const ObjectInstanceType3D instanceType, const UnsignedInt instance, const void* const importerState): _children{std::move(children)}, _transformation{translation, rotation, scaling}, _instanceType{instanceType}, _flags{ObjectFlag3D::HasTranslationRotationScaling}, _instance{Int(instance)}, _importerState{importerState} {} +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectData3D::ObjectData3D(std::vector children, const Matrix4& transformation, const void* const importerState): _children{std::move(children)}, _transformation{transformation}, _instanceType{ObjectInstanceType3D::Empty}, _flags{}, _instance{-1}, _importerState{importerState} {} +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectData3D::ObjectData3D(std::vector children, const Vector3& translation, const Quaternion& rotation, const Vector3& scaling, const void* const importerState): _children{std::move(children)}, _transformation{translation, rotation, scaling}, _instanceType{ObjectInstanceType3D::Empty}, _flags{ObjectFlag3D::HasTranslationRotationScaling}, _instance{-1}, _importerState{importerState} {} +CORRADE_IGNORE_DEPRECATED_PUSH /* MSVC warns here */ ObjectData3D::ObjectData3D(ObjectData3D&&) #if !defined(__GNUC__) || __GNUC__*100 + __GNUC_MINOR__ != 409 noexcept #endif = default; +CORRADE_IGNORE_DEPRECATED_POP ObjectData3D::~ObjectData3D() = default; +CORRADE_IGNORE_DEPRECATED_PUSH /* GCC why you warn on return and not on param */ ObjectData3D& ObjectData3D::operator=(ObjectData3D&&) #if !defined(__GNUC__) || __GNUC__*100 + __GNUC_MINOR__ != 409 noexcept #endif = default; +CORRADE_IGNORE_DEPRECATED_POP Vector3 ObjectData3D::translation() const { + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ CORRADE_ASSERT(_flags & ObjectFlag3D::HasTranslationRotationScaling, "Trade::ObjectData3D::translation(): object has only a combined transformation", {}); + CORRADE_IGNORE_DEPRECATED_POP return _transformation.trs.translation; } Quaternion ObjectData3D::rotation() const { + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ CORRADE_ASSERT(_flags & ObjectFlag3D::HasTranslationRotationScaling, "Trade::ObjectData3D::rotation(): object has only a combined transformation", {}); + CORRADE_IGNORE_DEPRECATED_POP return _transformation.trs.rotation; } Vector3 ObjectData3D::scaling() const { + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ CORRADE_ASSERT(_flags & ObjectFlag3D::HasTranslationRotationScaling, "Trade::ObjectData3D::scaling(): object has only a combined transformation", {}); + CORRADE_IGNORE_DEPRECATED_POP return _transformation.trs.scaling; } Matrix4 ObjectData3D::transformation() const { + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ if(_flags & ObjectFlag3D::HasTranslationRotationScaling) /* Has to be on a single line otherwise lcov reports an uncovered line. Ugh. */ return Matrix4::from(_transformation.trs.rotation.toMatrix(), _transformation.trs.translation)* Matrix4::scaling(_transformation.trs.scaling); + CORRADE_IGNORE_DEPRECATED_POP return _transformation.matrix; } #ifndef DOXYGEN_GENERATING_OUTPUT +CORRADE_IGNORE_DEPRECATED_PUSH Debug& operator<<(Debug& debug, const ObjectInstanceType3D value) { debug << "Trade::ObjectInstanceType3D" << Debug::nospace; @@ -114,6 +133,7 @@ Debug& operator<<(Debug& debug, const ObjectFlags3D value) { return enumSetDebugOutput(debug, value, "Trade::ObjectFlags3D{}", { ObjectFlag3D::HasTranslationRotationScaling}); } +CORRADE_IGNORE_DEPRECATED_POP #endif }} diff --git a/src/Magnum/Trade/ObjectData3D.h b/src/Magnum/Trade/ObjectData3D.h index f2acd5b22..f96ab2965 100644 --- a/src/Magnum/Trade/ObjectData3D.h +++ b/src/Magnum/Trade/ObjectData3D.h @@ -25,10 +25,17 @@ DEALINGS IN THE SOFTWARE. */ +#ifdef MAGNUM_BUILD_DEPRECATED /** @file * @brief Class @ref Magnum::Trade::ObjectData3D, enum @ref Magnum::Trade::ObjectInstanceType3D + * @m_deprecated_since_latest Use @ref Magnum/Trade/SceneData.h and the + * @relativeref{Magnum::Trade,SceneData} class instead. */ +#endif + +#include "Magnum/configure.h" +#ifdef MAGNUM_BUILD_DEPRECATED #include #include "Magnum/Magnum.h" @@ -36,14 +43,19 @@ #include "Magnum/Math/Quaternion.h" #include "Magnum/Trade/visibility.h" +#ifndef _MAGNUM_NO_DEPRECATED_OBJECTDATA +CORRADE_DEPRECATED_FILE("use Magnum/Trade/SceneData.h and the SceneData class instead") +#endif + namespace Magnum { namespace Trade { /** @brief Type of instance held by given 3D object +@m_deprecated_since_latest Use @ref SceneData instead. @see @ref ObjectData3D::instanceType() */ -enum class ObjectInstanceType3D: UnsignedByte { +enum class CORRADE_DEPRECATED_ENUM("use SceneData instead") ObjectInstanceType3D: UnsignedByte { Camera, /**< Camera instance (see @ref CameraData) */ Light, /**< Light instance (see @ref LightData) */ @@ -58,10 +70,11 @@ enum class ObjectInstanceType3D: UnsignedByte { /** @brief 3D object flag +@m_deprecated_since_latest Use @ref SceneData instead. @see @ref ObjectFlags3D, @ref ObjectData3D::flags() */ -enum class ObjectFlag3D: UnsignedByte { +enum class CORRADE_DEPRECATED_ENUM("use SceneData instead") ObjectFlag3D: UnsignedByte { /** * The object provides separate translation / rotation / scaling * properties. The @ref ObjectData3D::transformation() matrix returns them @@ -74,21 +87,27 @@ enum class ObjectFlag3D: UnsignedByte { /** @brief 3D object flags +@m_deprecated_since_latest Use @ref SceneData instead. @see @ref ObjectData3D::flags() */ -typedef Containers::EnumSet ObjectFlags3D; +CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ +typedef CORRADE_DEPRECATED("use SceneData instead") Containers::EnumSet ObjectFlags3D; +CORRADE_IGNORE_DEPRECATED_POP +CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_ENUMSET_OPERATORS(ObjectFlags3D) +CORRADE_IGNORE_DEPRECATED_POP /** @brief Three-dimensional object data +@m_deprecated_since_latest Use @ref SceneData instead. Provides access to object transformation and hierarchy. @see @ref AbstractImporter::object3D(), @ref MeshObjectData3D, @ref ObjectData2D */ -class MAGNUM_TRADE_EXPORT ObjectData3D { +class CORRADE_DEPRECATED("use SceneData instead") MAGNUM_TRADE_EXPORT ObjectData3D { public: /** * @brief Construct with combined transformation @@ -98,7 +117,9 @@ class MAGNUM_TRADE_EXPORT ObjectData3D { * @param instance Instance ID * @param importerState Importer-specific state */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ explicit ObjectData3D(std::vector children, const Matrix4& transformation, ObjectInstanceType3D instanceType, UnsignedInt instance, const void* importerState = nullptr); + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Construct with separate transformations @@ -110,7 +131,9 @@ class MAGNUM_TRADE_EXPORT ObjectData3D { * @param instance Instance ID * @param importerState Importer-specific state */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ explicit ObjectData3D(std::vector children, const Vector3& translation, const Quaternion& rotation, const Vector3& scaling, ObjectInstanceType3D instanceType, UnsignedInt instance, const void* importerState = nullptr); + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Construct empty instance with combined transformation @@ -164,7 +187,9 @@ class MAGNUM_TRADE_EXPORT ObjectData3D { const std::vector& children() const { return _children; } /**< @overload */ /** @brief Flags */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectFlags3D flags() const { return _flags; } + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Translation (relative to parent) @@ -225,7 +250,9 @@ class MAGNUM_TRADE_EXPORT ObjectData3D { * * @see @ref instance() */ + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectInstanceType3D instanceType() const { return _instanceType; } + CORRADE_IGNORE_DEPRECATED_POP /** * @brief Instance ID @@ -255,21 +282,37 @@ class MAGNUM_TRADE_EXPORT ObjectData3D { Vector3 scaling; } trs; } _transformation; + CORRADE_IGNORE_DEPRECATED_PUSH /* Clang doesn't warn, but GCC does */ ObjectInstanceType3D _instanceType; ObjectFlags3D _flags; + CORRADE_IGNORE_DEPRECATED_POP Int _instance; const void* _importerState; }; -/** @debugoperatorenum{ObjectInstanceType3D} */ +CORRADE_IGNORE_DEPRECATED_PUSH +/** +@debugoperatorenum{ObjectInstanceType3D} +@m_deprecated_since_latest Use @ref SceneData instead. +*/ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, ObjectInstanceType3D value); -/** @debugoperatorenum{ObjectFlag3D} */ +/** +@debugoperatorenum{ObjectFlag3D} +@m_deprecated_since_latest Use @ref SceneData instead. +*/ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, ObjectFlag3D value); -/** @debugoperatorenum{ObjectFlags3D} */ +/** +@debugoperatorenum{ObjectFlags3D} +@m_deprecated_since_latest Use @ref SceneData instead. +*/ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, ObjectFlags3D value); +CORRADE_IGNORE_DEPRECATED_POP }} +#else +#error use Magnum/Trade/SceneData.h and the SceneData class instead +#endif #endif diff --git a/src/Magnum/Trade/SceneData.h b/src/Magnum/Trade/SceneData.h index a3f825854..24a5bccf3 100644 --- a/src/Magnum/Trade/SceneData.h +++ b/src/Magnum/Trade/SceneData.h @@ -2182,6 +2182,11 @@ class MAGNUM_TRADE_EXPORT SceneData { const void* importerState() const { return _importerState; } private: + /* For custom deleter checks. Not done in the constructors here because + the restriction is pointless when used outside of plugin + implementations. */ + friend AbstractImporter; + /* Internal helper that doesn't assert, unlike fieldId() */ UnsignedInt fieldFor(SceneField name) const; diff --git a/src/Magnum/Trade/Test/AbstractImporterTest.cpp b/src/Magnum/Trade/Test/AbstractImporterTest.cpp index 05deeba0f..09aa1ad70 100644 --- a/src/Magnum/Trade/Test/AbstractImporterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImporterTest.cpp @@ -34,6 +34,8 @@ #include "Magnum/PixelFormat.h" #include "Magnum/FileCallback.h" +#include "Magnum/Math/Matrix3.h" +#include "Magnum/Math/Matrix4.h" #include "Magnum/Trade/AbstractImporter.h" #include "Magnum/Trade/AnimationData.h" #include "Magnum/Trade/ArrayAllocator.h" @@ -41,18 +43,22 @@ #include "Magnum/Trade/ImageData.h" #include "Magnum/Trade/LightData.h" #include "Magnum/Trade/MeshData.h" -#include "Magnum/Trade/MeshObjectData2D.h" -#include "Magnum/Trade/MeshObjectData3D.h" #include "Magnum/Trade/PhongMaterialData.h" #include "Magnum/Trade/SceneData.h" #include "Magnum/Trade/SkinData.h" #include "Magnum/Trade/TextureData.h" #ifdef MAGNUM_BUILD_DEPRECATED +#include +#include + #define _MAGNUM_NO_DEPRECATED_MESHDATA /* So it doesn't yell here */ +#define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */ #include "Magnum/Trade/MeshData2D.h" #include "Magnum/Trade/MeshData3D.h" +#include "Magnum/Trade/MeshObjectData2D.h" +#include "Magnum/Trade/MeshObjectData3D.h" #endif #include "configure.h" @@ -109,11 +115,26 @@ struct AbstractImporterTest: TestSuite::Tester { void defaultSceneOutOfRange(); void scene(); + void object(); + #ifdef MAGNUM_BUILD_DEPRECATED + void sceneDeprecatedFallback2D(); + void sceneDeprecatedFallback3D(); + void sceneDeprecatedFallbackParentless2D(); + void sceneDeprecatedFallbackParentless3D(); + void sceneDeprecatedFallbackTransformless2D(); + void sceneDeprecatedFallbackTransformless3D(); + #endif void sceneNameNotImplemented(); + void objectNameNotImplemented(); void sceneForNameOutOfRange(); + void objectForNameOutOfRange(); void sceneNameOutOfRange(); + void objectNameOutOfRange(); void sceneNotImplemented(); void sceneOutOfRange(); + void sceneNonOwningDeleters(); + void sceneCustomDataDeleter(); + void sceneCustomFieldDataDeleter(); void sceneFieldName(); void sceneFieldNameNotImplemented(); @@ -144,19 +165,35 @@ struct AbstractImporterTest: TestSuite::Tester { void cameraNotImplemented(); void cameraOutOfRange(); + #ifdef MAGNUM_BUILD_DEPRECATED void object2D(); - void object2DNameNotImplemented(); + void object2DCountNotImplemented(); + void object2DCountNoFile(); + void object2DForNameNotImplemented(); + void object2DForNameNoFile(); void object2DForNameOutOfRange(); + void object2DByNameNotFound(); + void object2DNameNotImplemented(); + void object2DNameNoFile(); void object2DNameOutOfRange(); void object2DNotImplemented(); + void object2DNoFile(); void object2DOutOfRange(); void object3D(); - void object3DNameNotImplemented(); + void object3DCountNotImplemented(); + void object3DCountNoFile(); + void object3DForNameNotImplemented(); + void object3DForNameNoFile(); void object3DForNameOutOfRange(); + void object3DByNameNotFound(); + void object3DNameNotImplemented(); + void object3DNameNoFile(); void object3DNameOutOfRange(); void object3DNotImplemented(); + void object3DNoFile(); void object3DOutOfRange(); + #endif void skin2D(); void skin2DNameNotImplemented(); @@ -307,6 +344,8 @@ constexpr struct { {"verify the message", true} }; +using namespace Math::Literals; + AbstractImporterTest::AbstractImporterTest() { addTests({&AbstractImporterTest::construct, &AbstractImporterTest::constructWithPluginManagerReference, @@ -358,11 +397,26 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::defaultSceneNotImplemented, &AbstractImporterTest::scene, + &AbstractImporterTest::object, + #ifdef MAGNUM_BUILD_DEPRECATED + &AbstractImporterTest::sceneDeprecatedFallback2D, + &AbstractImporterTest::sceneDeprecatedFallback3D, + &AbstractImporterTest::sceneDeprecatedFallbackParentless2D, + &AbstractImporterTest::sceneDeprecatedFallbackParentless3D, + &AbstractImporterTest::sceneDeprecatedFallbackTransformless2D, + &AbstractImporterTest::sceneDeprecatedFallbackTransformless3D, + #endif &AbstractImporterTest::sceneForNameOutOfRange, + &AbstractImporterTest::objectForNameOutOfRange, &AbstractImporterTest::sceneNameNotImplemented, + &AbstractImporterTest::objectNameNotImplemented, &AbstractImporterTest::sceneNameOutOfRange, + &AbstractImporterTest::objectNameOutOfRange, &AbstractImporterTest::sceneNotImplemented, &AbstractImporterTest::sceneOutOfRange, + &AbstractImporterTest::sceneNonOwningDeleters, + &AbstractImporterTest::sceneCustomDataDeleter, + &AbstractImporterTest::sceneCustomFieldDataDeleter, &AbstractImporterTest::sceneFieldName, &AbstractImporterTest::sceneFieldNameNotImplemented, @@ -391,23 +445,45 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::cameraNameNotImplemented, &AbstractImporterTest::cameraNameOutOfRange, &AbstractImporterTest::cameraNotImplemented, - &AbstractImporterTest::cameraOutOfRange, + &AbstractImporterTest::cameraOutOfRange}); + + #ifdef MAGNUM_BUILD_DEPRECATED + addTests({&AbstractImporterTest::object2D, + &AbstractImporterTest::object2DCountNotImplemented, + &AbstractImporterTest::object2DCountNoFile, + &AbstractImporterTest::object2DForNameNotImplemented, + &AbstractImporterTest::object2DForNameNoFile, + &AbstractImporterTest::object2DForNameOutOfRange}); + + addInstancedTests({&AbstractImporterTest::object2DByNameNotFound}, + Containers::arraySize(ThingByNameData)); - &AbstractImporterTest::object2D, - &AbstractImporterTest::object2DForNameOutOfRange, - &AbstractImporterTest::object2DNameNotImplemented, + addTests({&AbstractImporterTest::object2DNameNotImplemented, + &AbstractImporterTest::object2DNameNoFile, &AbstractImporterTest::object2DNameOutOfRange, &AbstractImporterTest::object2DNotImplemented, + &AbstractImporterTest::object2DNoFile, &AbstractImporterTest::object2DOutOfRange, &AbstractImporterTest::object3D, - &AbstractImporterTest::object3DForNameOutOfRange, - &AbstractImporterTest::object3DNameNotImplemented, + &AbstractImporterTest::object3DCountNotImplemented, + &AbstractImporterTest::object3DCountNoFile, + &AbstractImporterTest::object3DForNameNotImplemented, + &AbstractImporterTest::object3DForNameNoFile, + &AbstractImporterTest::object3DForNameOutOfRange}); + + addInstancedTests({&AbstractImporterTest::object3DByNameNotFound}, + Containers::arraySize(ThingByNameData)); + + addTests({&AbstractImporterTest::object3DNameNotImplemented, + &AbstractImporterTest::object3DNameNoFile, &AbstractImporterTest::object3DNameOutOfRange, &AbstractImporterTest::object3DNotImplemented, - &AbstractImporterTest::object3DOutOfRange, + &AbstractImporterTest::object3DNoFile, + &AbstractImporterTest::object3DOutOfRange}); + #endif - &AbstractImporterTest::skin2D, + addTests({&AbstractImporterTest::skin2D, &AbstractImporterTest::skin2DForNameOutOfRange, &AbstractImporterTest::skin2DNameNotImplemented, &AbstractImporterTest::skin2DNameOutOfRange, @@ -1210,13 +1286,11 @@ void AbstractImporterTest::thingCountNotImplemented() { } importer; CORRADE_COMPARE(importer.sceneCount(), 0); + CORRADE_COMPARE(importer.objectCount(), 0); CORRADE_COMPARE(importer.animationCount(), 0); CORRADE_COMPARE(importer.lightCount(), 0); CORRADE_COMPARE(importer.cameraCount(), 0); - CORRADE_COMPARE(importer.object2DCount(), 0); - CORRADE_COMPARE(importer.object3DCount(), 0); - CORRADE_COMPARE(importer.skin2DCount(), 0); CORRADE_COMPARE(importer.skin3DCount(), 0); @@ -1244,13 +1318,11 @@ void AbstractImporterTest::thingCountNoFile() { Error redirectError{&out}; importer.sceneCount(); + importer.objectCount(); importer.animationCount(); importer.lightCount(); importer.cameraCount(); - importer.object2DCount(); - importer.object3DCount(); - importer.skin2DCount(); importer.skin3DCount(); @@ -1268,13 +1340,11 @@ void AbstractImporterTest::thingCountNoFile() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::sceneCount(): no file opened\n" + "Trade::AbstractImporter::objectCount(): no file opened\n" "Trade::AbstractImporter::animationCount(): no file opened\n" "Trade::AbstractImporter::lightCount(): no file opened\n" "Trade::AbstractImporter::cameraCount(): no file opened\n" - "Trade::AbstractImporter::object2DCount(): no file opened\n" - "Trade::AbstractImporter::object3DCount(): no file opened\n" - "Trade::AbstractImporter::skin2DCount(): no file opened\n" "Trade::AbstractImporter::skin3DCount(): no file opened\n" @@ -1299,13 +1369,11 @@ void AbstractImporterTest::thingForNameNotImplemented() { } importer; CORRADE_COMPARE(importer.sceneForName(""), -1); + CORRADE_COMPARE(importer.objectForName(""), -1); CORRADE_COMPARE(importer.animationForName(""), -1); CORRADE_COMPARE(importer.lightForName(""), -1); CORRADE_COMPARE(importer.cameraForName(""), -1); - CORRADE_COMPARE(importer.object2DForName(""), -1); - CORRADE_COMPARE(importer.object3DForName(""), -1); - CORRADE_COMPARE(importer.skin2DForName(""), -1); CORRADE_COMPARE(importer.skin3DForName(""), -1); @@ -1333,13 +1401,11 @@ void AbstractImporterTest::thingForNameNoFile() { Error redirectError{&out}; importer.sceneForName(""); + importer.objectForName(""); importer.animationForName(""); importer.lightForName(""); importer.cameraForName(""); - importer.object2DForName(""); - importer.object3DForName(""); - importer.skin2DForName(""); importer.skin3DForName(""); @@ -1353,13 +1419,11 @@ void AbstractImporterTest::thingForNameNoFile() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::sceneForName(): no file opened\n" + "Trade::AbstractImporter::objectForName(): no file opened\n" "Trade::AbstractImporter::animationForName(): no file opened\n" "Trade::AbstractImporter::lightForName(): no file opened\n" "Trade::AbstractImporter::cameraForName(): no file opened\n" - "Trade::AbstractImporter::object2DForName(): no file opened\n" - "Trade::AbstractImporter::object3DForName(): no file opened\n" - "Trade::AbstractImporter::skin2DForName(): no file opened\n" "Trade::AbstractImporter::skin3DForName(): no file opened\n" @@ -1386,19 +1450,16 @@ void AbstractImporterTest::thingByNameNotFound() { UnsignedInt doLightCount() const override { return 3; } UnsignedInt doCameraCount() const override { return 4; } - UnsignedInt doObject2DCount() const override { return 5; } - UnsignedInt doObject3DCount() const override { return 6; } - - UnsignedInt doSkin2DCount() const override { return 7; } - UnsignedInt doSkin3DCount() const override { return 8; } + UnsignedInt doSkin2DCount() const override { return 5; } + UnsignedInt doSkin3DCount() const override { return 6; } - UnsignedInt doMeshCount() const override { return 9; } - UnsignedInt doMaterialCount() const override { return 10; } - UnsignedInt doTextureCount() const override { return 11; } + UnsignedInt doMeshCount() const override { return 7; } + UnsignedInt doMaterialCount() const override { return 8; } + UnsignedInt doTextureCount() const override { return 9; } - UnsignedInt doImage1DCount() const override { return 12; } - UnsignedInt doImage2DCount() const override { return 13; } - UnsignedInt doImage3DCount() const override { return 14; } + UnsignedInt doImage1DCount() const override { return 10; } + UnsignedInt doImage2DCount() const override { return 11; } + UnsignedInt doImage3DCount() const override { return 12; } } importer; std::ostringstream out; @@ -1411,9 +1472,6 @@ void AbstractImporterTest::thingByNameNotFound() { CORRADE_VERIFY(!importer.light("foobar")); CORRADE_VERIFY(!importer.camera("foobar")); - CORRADE_VERIFY(!importer.object2D("foobar")); - CORRADE_VERIFY(!importer.object3D("foobar")); - CORRADE_VERIFY(!importer.skin2D("foobar")); CORRADE_VERIFY(!importer.skin3D("foobar")); @@ -1433,19 +1491,16 @@ void AbstractImporterTest::thingByNameNotFound() { "Trade::AbstractImporter::light(): light foobar not found among 3 entries\n" "Trade::AbstractImporter::camera(): camera foobar not found among 4 entries\n" - "Trade::AbstractImporter::object2D(): object foobar not found among 5 entries\n" - "Trade::AbstractImporter::object3D(): object foobar not found among 6 entries\n" + "Trade::AbstractImporter::skin2D(): skin foobar not found among 5 entries\n" + "Trade::AbstractImporter::skin3D(): skin foobar not found among 6 entries\n" - "Trade::AbstractImporter::skin2D(): skin foobar not found among 7 entries\n" - "Trade::AbstractImporter::skin3D(): skin foobar not found among 8 entries\n" + "Trade::AbstractImporter::mesh(): mesh foobar not found among 7 entries\n" + "Trade::AbstractImporter::material(): material foobar not found among 8 entries\n" + "Trade::AbstractImporter::texture(): texture foobar not found among 9 entries\n" - "Trade::AbstractImporter::mesh(): mesh foobar not found among 9 entries\n" - "Trade::AbstractImporter::material(): material foobar not found among 10 entries\n" - "Trade::AbstractImporter::texture(): texture foobar not found among 11 entries\n" - - "Trade::AbstractImporter::image1D(): image foobar not found among 12 entries\n" - "Trade::AbstractImporter::image2D(): image foobar not found among 13 entries\n" - "Trade::AbstractImporter::image3D(): image foobar not found among 14 entries\n"); + "Trade::AbstractImporter::image1D(): image foobar not found among 10 entries\n" + "Trade::AbstractImporter::image2D(): image foobar not found among 11 entries\n" + "Trade::AbstractImporter::image3D(): image foobar not found among 12 entries\n"); } } @@ -1468,9 +1523,6 @@ void AbstractImporterTest::thingNameNoFile() { importer.lightName(42); importer.cameraName(42); - importer.object2DName(42); - importer.object3DName(42); - importer.skin2DName(42); importer.skin3DName(42); @@ -1488,9 +1540,6 @@ void AbstractImporterTest::thingNameNoFile() { "Trade::AbstractImporter::lightName(): no file opened\n" "Trade::AbstractImporter::cameraName(): no file opened\n" - "Trade::AbstractImporter::object2DName(): no file opened\n" - "Trade::AbstractImporter::object3DName(): no file opened\n" - "Trade::AbstractImporter::skin2DName(): no file opened\n" "Trade::AbstractImporter::skin3DName(): no file opened\n" @@ -1527,11 +1576,6 @@ void AbstractImporterTest::thingNoFile() { importer.camera(42); importer.camera("foo"); - importer.object2D(42); - importer.object2D("foo"); - importer.object3D(42); - importer.object3D("foo"); - importer.skin2D(42); importer.skin2D("foo"); importer.skin3D(42); @@ -1564,11 +1608,6 @@ void AbstractImporterTest::thingNoFile() { "Trade::AbstractImporter::camera(): no file opened\n" "Trade::AbstractImporter::camera(): no file opened\n" - "Trade::AbstractImporter::object2D(): no file opened\n" - "Trade::AbstractImporter::object2D(): no file opened\n" - "Trade::AbstractImporter::object3D(): no file opened\n" - "Trade::AbstractImporter::object3D(): no file opened\n" - "Trade::AbstractImporter::skin2D(): no file opened\n" "Trade::AbstractImporter::skin2D(): no file opened\n" "Trade::AbstractImporter::skin3D(): no file opened\n" @@ -1673,39 +1712,29 @@ void AbstractImporterTest::scene() { } } -void AbstractImporterTest::sceneForNameOutOfRange() { - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif - - struct: AbstractImporter { - ImporterFeatures doFeatures() const override { return {}; } - bool doIsOpened() const override { return true; } - void doClose() override {} - - UnsignedInt doSceneCount() const override { return 8; } - Int doSceneForName(const std::string&) override { return 8; } - } importer; - - std::ostringstream out; - Error redirectError{&out}; - importer.sceneForName(""); - CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::sceneForName(): implementation-returned index 8 out of range for 8 entries\n"); -} - -void AbstractImporterTest::sceneNameNotImplemented() { +void AbstractImporterTest::object() { struct: AbstractImporter { ImporterFeatures doFeatures() const override { return {}; } bool doIsOpened() const override { return true; } void doClose() override {} - UnsignedInt doSceneCount() const override { return 8; } + UnsignedLong doObjectCount() const override { return 8; } + Long doObjectForName(const std::string& name) override { + if(name == "eighth") return 7; + return -1; + } + std::string doObjectName(UnsignedLong id) override { + if(id == 7) return "eighth"; + return {}; + } } importer; - CORRADE_COMPARE(importer.sceneName(7), ""); + CORRADE_COMPARE(importer.objectCount(), 8); + CORRADE_COMPARE(importer.objectForName("eighth"), 7); + CORRADE_COMPARE(importer.objectName(7), "eighth"); } -void AbstractImporterTest::sceneNameOutOfRange() { +void AbstractImporterTest::sceneForNameOutOfRange() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif @@ -1716,16 +1745,16 @@ void AbstractImporterTest::sceneNameOutOfRange() { void doClose() override {} UnsignedInt doSceneCount() const override { return 8; } + Int doSceneForName(const std::string&) override { return 8; } } importer; std::ostringstream out; Error redirectError{&out}; - - importer.sceneName(8); - CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::sceneName(): index 8 out of range for 8 entries\n"); + importer.sceneForName(""); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::sceneForName(): implementation-returned index 8 out of range for 8 entries\n"); } -void AbstractImporterTest::sceneNotImplemented() { +void AbstractImporterTest::objectForNameOutOfRange() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif @@ -1735,155 +1764,1229 @@ void AbstractImporterTest::sceneNotImplemented() { bool doIsOpened() const override { return true; } void doClose() override {} - UnsignedInt doSceneCount() const override { return 8; } + UnsignedLong doObjectCount() const override { return 8; } + Long doObjectForName(const std::string&) override { return 8; } } importer; std::ostringstream out; Error redirectError{&out}; - - importer.scene(7); - CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::scene(): not implemented\n"); + importer.objectForName(""); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::objectForName(): implementation-returned index 8 out of range for 8 entries\n"); } -void AbstractImporterTest::sceneOutOfRange() { - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif +#ifdef MAGNUM_BUILD_DEPRECATED +void AbstractImporterTest::sceneDeprecatedFallback2D() { + /* Need to test the following combinations: + + - few objects in the root + - an object with one child, with more than one, with none + - an object with a mesh and a material + - an object with a mesh and without a material + - an object with a mesh and a skin + - an object with a skin but no mesh + - an object with a camera + - an object with TRS transformation + - an object with TRS transformation and a mesh + - an object with nothing except parent / transformation + */ + + struct Transform { + UnsignedInt object; + Int parent; + Matrix3 transformation; + }; + struct Trs { + UnsignedInt object; + Vector2 translation; + Complex rotation; + Vector2 scaling; + }; + struct Mesh { + UnsignedInt object; + UnsignedShort mesh; + Short meshMaterial; + }; + struct Index { + UnsignedInt object; + UnsignedInt id; + }; + struct ImporterState { + UnsignedInt object; + const void* importerState; + }; + Containers::StridedArrayView1D transformations; + Containers::StridedArrayView1D trs; + Containers::StridedArrayView1D meshes; + Containers::StridedArrayView1D cameras; + Containers::StridedArrayView1D skins; + Containers::StridedArrayView1D importerState; + Containers::Array data = Containers::ArrayTuple{ + {NoInit, 6, transformations}, + {NoInit, 2, trs}, + {NoInit, 2, meshes}, + {NoInit, 1, cameras}, + {NoInit, 2, skins}, + {NoInit, 3, importerState} + }; - struct: AbstractImporter { - ImporterFeatures doFeatures() const override { return {}; } - bool doIsOpened() const override { return true; } - void doClose() override {} + int a, b, c; - UnsignedInt doSceneCount() const override { return 8; } - } importer; + /* Object 3 is in the root, has a camera attached, TRS and children 5 + 4. + Because of the TRS, the actual transformation gets ignored. Has importer + state. */ + transformations[0] = {3, -1, Matrix3::rotation(75.0_degf)}; + trs[0] = {3, {0.0f, 3.0f}, Complex::rotation(15.0_degf), Vector2{1.0f}}; + cameras[0] = {3, 15}; + importerState[0] = {3, &a}; - std::ostringstream out; - Error redirectError{&out}; + /* Object 5 is a child of object 3 (which is at index 0), has a skin (which + gets ignored by the legacy interface) */ + transformations[1] = {5, 0, Matrix3::rotation(-15.0_degf)}; + skins[0] = {5, 226}; - importer.scene(8); - CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::scene(): index 8 out of range for 8 entries\n"); -} + /* Object 1 is a child of object 2 (which will be at index 3) */ + transformations[2] = {1, 3, Matrix3::translation({1.0f, 0.5f})*Matrix3::rotation(15.0_degf)}; -void AbstractImporterTest::sceneFieldName() { - struct: AbstractImporter { - ImporterFeatures doFeatures() const override { return {}; } - bool doIsOpened() const override { return false; } - void doClose() override {} + /* Object 2 is in the root, has object 1 as a child but nothing else */ + transformations[3] = {2, -1, {}}; - SceneField doSceneFieldForName(const std::string& name) override { - if(name == "OctreeCell") return sceneFieldCustom(100037); - return SceneField{}; - } + /* Object 0 is in the root, has a mesh without a material and no children */ + transformations[4] = {0, -1, Matrix3::rotation(30.0_degf)}; + meshes[0] = {0, 33, -1}; - std::string doSceneFieldName(UnsignedInt id) override { - if(id == 100037) return "OctreeCell"; - return ""; - } - } importer; + /* Object 4 has TRS also, a mesh with a material and a skin and is a child + of object 3 (which is at index 0). The transformation gets ignored + again. Has importer state. */ + transformations[5] = {4, 0, Matrix3::translation(Vector2::xAxis(5.0f))}; + trs[1] = {4, {}, {}, {1.5f, -0.5f}}; + meshes[1] = {4, 27, 46}; + skins[1] = {4, 72}; + importerState[1] = {4, &b}; - CORRADE_COMPARE(importer.sceneFieldForName("OctreeCell"), sceneFieldCustom(100037)); - CORRADE_COMPARE(importer.sceneFieldName(sceneFieldCustom(100037)), "OctreeCell"); -} + /* Object 6 has neither a transformation nor a parent, only an importer + state. It should get ignored. */ + importerState[2] = {6, &c}; + + struct Importer: AbstractImporter { + explicit Importer(SceneData&& data): _data{std::move(data)} {} -void AbstractImporterTest::sceneFieldNameNotImplemented() { - struct: AbstractImporter { ImporterFeatures doFeatures() const override { return {}; } - bool doIsOpened() const override { return false; } + bool doIsOpened() const override { return true; } void doClose() override {} - } importer; - CORRADE_COMPARE(importer.sceneFieldForName(""), SceneField{}); - CORRADE_COMPARE(importer.sceneFieldName(sceneFieldCustom(100037)), ""); -} + UnsignedInt doSceneCount() const override { return 3; } + UnsignedLong doObjectCount() const override { return 7; } + Long doObjectForName(const std::string& name) override { + if(name == "sixth") return 5; + return -1; + } + std::string doObjectName(UnsignedLong id) override { + if(id == 5) return "sixth"; + return {}; + } + Containers::Optional doScene(UnsignedInt id) override { + /* This one has seven objects, but no fields for them so it should + get skipped */ + if(id == 0) + return SceneData{SceneObjectType::UnsignedByte, 7, nullptr, {}}; + /* This one has no objects, so it should get skipped as well + without even querying any fieldFor() API (as those would + assert) */ + if(id == 1) + return SceneData{SceneObjectType::UnsignedShort, 0, nullptr, {}}; + /* This one is the one */ + if(id == 2) + return SceneData{SceneObjectType::UnsignedInt, 7, {}, _data.data(), sceneFieldDataNonOwningArray(_data.fieldData())}; + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + } -void AbstractImporterTest::sceneFieldNameNotCustom() { - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif + private: + SceneData _data; + } importer{SceneData{SceneObjectType::UnsignedInt, 7, std::move(data), { + SceneFieldData{SceneField::Parent, + transformations.slice(&Transform::object), + transformations.slice(&Transform::parent)}, + SceneFieldData{SceneField::Transformation, + transformations.slice(&Transform::object), + transformations.slice(&Transform::transformation)}, + SceneFieldData{SceneField::Translation, + trs.slice(&Trs::object), + trs.slice(&Trs::translation)}, + SceneFieldData{SceneField::Rotation, + trs.slice(&Trs::object), + trs.slice(&Trs::rotation)}, + SceneFieldData{SceneField::Scaling, + trs.slice(&Trs::object), + trs.slice(&Trs::scaling)}, + SceneFieldData{SceneField::Mesh, + meshes.slice(&Mesh::object), + meshes.slice(&Mesh::mesh)}, + SceneFieldData{SceneField::MeshMaterial, + meshes.slice(&Mesh::object), + meshes.slice(&Mesh::meshMaterial)}, + SceneFieldData{SceneField::Camera, + cameras.slice(&Index::object), + cameras.slice(&Index::id)}, + SceneFieldData{SceneField::Skin, + skins.slice(&Index::object), + skins.slice(&Index::id)}, + SceneFieldData{SceneField::ImporterState, + importerState.slice(&ImporterState::object), importerState.slice(&ImporterState::importerState)} + }}}; + + CORRADE_COMPARE(importer.sceneCount(), 3); + + Containers::Optional scene = importer.scene(2); + CORRADE_VERIFY(scene); - struct: AbstractImporter { - ImporterFeatures doFeatures() const override { return {}; } - bool doIsOpened() const override { return false; } - void doClose() override {} + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE_AS(scene->children2D(), + (std::vector{3, 2, 0}), + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(scene->children3D(), + (std::vector{}), + TestSuite::Compare::Container); - SceneField doSceneFieldForName(const std::string&) override { - return SceneField::Translation; - } - } importer; + CORRADE_COMPARE(importer.object2DCount(), 7); + CORRADE_COMPARE(importer.object2DForName("sixth"), 5); + CORRADE_COMPARE(importer.object2DName(5), "sixth"); - std::ostringstream out; - Error redirectError{&out}; - importer.sceneFieldForName("OctreeCell"); - importer.sceneFieldName(SceneField::Translation); - CORRADE_COMPARE(out.str(), - "Trade::AbstractImporter::sceneFieldForName(): implementation-returned Trade::SceneField::Translation is neither custom nor invalid\n" - "Trade::AbstractImporter::sceneFieldName(): Trade::SceneField::Translation is not custom\n"); + CORRADE_COMPARE(importer.object3DCount(), 0); + CORRADE_COMPARE(importer.object3DForName("sixth"), -1); + + { + Containers::Pointer o = importer.object2D(0); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Mesh); + CORRADE_COMPARE(o->instance(), 33); + CORRADE_COMPARE(o->flags(), ObjectFlags2D{}); + CORRADE_COMPARE(o->transformation(), Matrix3::rotation(30.0_degf)); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData2D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), -1); + CORRADE_COMPARE(mo.skin(), -1); + } { + Containers::Pointer o = importer.object2D(1); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags2D{}); + CORRADE_COMPARE(o->transformation(), Matrix3::translation({1.0f, 0.5f})*Matrix3::rotation(15.0_degf)); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object2D(2); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags2D{}); + CORRADE_COMPARE(o->transformation(), Matrix3{}); + CORRADE_COMPARE_AS(o->children(), + std::vector{1}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object2D(3); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), &a); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Camera); + CORRADE_COMPARE(o->instance(), 15); + CORRADE_COMPARE(o->flags(), ObjectFlag2D::HasTranslationRotationScaling); + CORRADE_COMPARE(o->transformation(), Matrix3::translation({0.0f, 3.0f})*Matrix3::rotation(15.0_degf)); + CORRADE_COMPARE(o->translation(), (Vector2{0.0f, 3.0f})); + CORRADE_COMPARE(o->rotation(), Complex::rotation(15.0_degf)); + CORRADE_COMPARE(o->scaling(), (Vector2{1.0f})); + CORRADE_COMPARE_AS(o->children(), + (std::vector{5, 4}), + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object2D(4); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), &b); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Mesh); + CORRADE_COMPARE(o->instance(), 27); + CORRADE_COMPARE(o->flags(), ObjectFlag2D::HasTranslationRotationScaling); + CORRADE_COMPARE(o->transformation(), Matrix3::scaling({1.5f, -0.5f})); + CORRADE_COMPARE(o->translation(), Vector2{}); + CORRADE_COMPARE(o->rotation(), Complex{}); + CORRADE_COMPARE(o->scaling(), (Vector2{1.5, -0.5f})); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData2D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 46); + CORRADE_COMPARE(mo.skin(), 72); + } { + Containers::Pointer o = importer.object2D("sixth"); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags2D{}); + CORRADE_COMPARE(o->transformation(), Matrix3::rotation(-15.0_degf)); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } { + /* This one is not contained in any parent hierarchy, so it fails to + import */ + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!importer.object2D(6)); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object2D(): object 6 not found in any 2D scene hierarchy\n"); + } + CORRADE_IGNORE_DEPRECATED_POP } -void AbstractImporterTest::animation() { - struct: AbstractImporter { +void AbstractImporterTest::sceneDeprecatedFallback3D() { + /* Need to test the following combinations: + + - few objects in the root + - an object with one child, with more than one, with none + - an object with a mesh and a material + - an object with a mesh and without a material + - an object with a mesh and a skin + - an object with a skin but no mesh + - an object with a camera + - an object with a light + - an object with TRS transformation + - an object with TRS transformation and a mesh + - an object with nothing except parent / transformation + */ + + struct Transform { + UnsignedInt object; + Int parent; + Matrix4 transformation; + }; + struct Trs { + UnsignedInt object; + Vector3 translation; + Quaternion rotation; + Vector3 scaling; + }; + struct Mesh { + UnsignedInt object; + UnsignedShort mesh; + Short meshMaterial; + }; + struct Index { + UnsignedInt object; + UnsignedInt id; + }; + struct ImporterState { + UnsignedInt object; + const void* importerState; + }; + Containers::StridedArrayView1D transformations; + Containers::StridedArrayView1D trs; + Containers::StridedArrayView1D meshes; + Containers::StridedArrayView1D cameras; + Containers::StridedArrayView1D lights; + Containers::StridedArrayView1D skins; + Containers::StridedArrayView1D importerState; + Containers::Array data = Containers::ArrayTuple{ + {NoInit, 6, transformations}, + {NoInit, 2, trs}, + {NoInit, 2, meshes}, + {NoInit, 1, cameras}, + {NoInit, 1, lights}, + {NoInit, 2, skins}, + {NoInit, 3, importerState} + }; + + int a, b, c; + + /* Object 3 is in the root, has a camera attached, TRS and children 5 + 4. + Because of the TRS, the actual transformation gets ignored. Has importer + state. */ + transformations[0] = {3, -1, Matrix4::rotationX(75.0_degf)}; + trs[0] = {3, {0.0f, 0.0f, 3.0f}, Quaternion::rotation(15.0_degf, Vector3::xAxis()), Vector3{1.0f}}; + cameras[0] = {3, 15}; + importerState[0] = {3, &a}; + + /* Object 5 is a child of object 3 (which is at index 0), has a skin (which + gets ignored by the legacy interface) */ + transformations[1] = {5, 0, Matrix4::rotationY(-15.0_degf)}; + skins[0] = {5, 226}; + + /* Object 1 is a child of object 2 (which will be at index 3), has a light. */ + transformations[2] = {1, 3, Matrix4::translation({1.0f, 0.0f, 1.0f})*Matrix4::rotationZ(15.0_degf)}; + lights[0] = {1, 113}; + + /* Object 2 is in the root, has object 1 as a child but nothing else */ + transformations[3] = {2, -1, {}}; + + /* Object 0 is in the root, has a mesh without a material and no children */ + transformations[4] = {0, -1, Matrix4::rotationX(30.0_degf)}; + meshes[0] = {0, 33, -1}; + + /* Object 4 has TRS also, a mesh with a material and a skin and is a child + of object 3 (which is at index 0). The transformation gets ignored + again. Has importer state. */ + transformations[5] = {4, 0, Matrix4::translation(Vector3::xAxis(5.0f))}; + trs[1] = {4, {}, {}, {1.5f, 3.0f, -0.5f}}; + meshes[1] = {4, 27, 46}; + skins[1] = {4, 72}; + importerState[1] = {4, &b}; + + /* Object 6 has neither a transformation nor a parent, only an importer + state. It should get ignored. */ + importerState[2] = {6, &c}; + + struct Importer: AbstractImporter { + explicit Importer(SceneData&& data): _data{std::move(data)} {} + ImporterFeatures 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; + UnsignedInt doSceneCount() const override { return 3; } + UnsignedLong doObjectCount() const override { return 7; } + Long doObjectForName(const std::string& name) override { + if(name == "sixth") return 5; return -1; } - std::string doAnimationName(UnsignedInt id) override { - if(id == 7) return "eighth"; + std::string doObjectName(UnsignedLong id) override { + if(id == 5) return "sixth"; return {}; } - Containers::Optional doAnimation(UnsignedInt id) override { - /* Verify that initializer list is converted to an array with - the default deleter and not something disallowed */ - if(id == 7) return AnimationData{nullptr, { - AnimationTrackData{AnimationTrackType::Vector3, - AnimationTrackTargetType::Scaling3D, 0, {}} - }, &state}; - return AnimationData{{}, {}}; + Containers::Optional doScene(UnsignedInt id) override { + /* This one has seven objects, but no fields for them so it should + get skipped */ + if(id == 0) + return SceneData{SceneObjectType::UnsignedByte, 7, nullptr, {}}; + /* This one has no objects, so it should get skipped as well + without even querying any fieldFor() API (as those would + assert) */ + if(id == 1) + return SceneData{SceneObjectType::UnsignedShort, 0, nullptr, {}}; + /* This one is the one */ + if(id == 2) + return SceneData{SceneObjectType::UnsignedInt, 7, {}, _data.data(), sceneFieldDataNonOwningArray(_data.fieldData())}; + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); } - } importer; - CORRADE_COMPARE(importer.animationCount(), 8); - CORRADE_COMPARE(importer.animationForName("eighth"), 7); - CORRADE_COMPARE(importer.animationName(7), "eighth"); + private: + SceneData _data; + } importer{SceneData{SceneObjectType::UnsignedInt, 7, std::move(data), { + SceneFieldData{SceneField::Parent, + transformations.slice(&Transform::object), + transformations.slice(&Transform::parent)}, + SceneFieldData{SceneField::Transformation, + transformations.slice(&Transform::object), + transformations.slice(&Transform::transformation)}, + SceneFieldData{SceneField::Translation, + trs.slice(&Trs::object), + trs.slice(&Trs::translation)}, + SceneFieldData{SceneField::Rotation, + trs.slice(&Trs::object), + trs.slice(&Trs::rotation)}, + SceneFieldData{SceneField::Scaling, + trs.slice(&Trs::object), + trs.slice(&Trs::scaling)}, + SceneFieldData{SceneField::Mesh, + meshes.slice(&Mesh::object), + meshes.slice(&Mesh::mesh)}, + SceneFieldData{SceneField::MeshMaterial, + meshes.slice(&Mesh::object), + meshes.slice(&Mesh::meshMaterial)}, + SceneFieldData{SceneField::Camera, + cameras.slice(&Index::object), + cameras.slice(&Index::id)}, + SceneFieldData{SceneField::Light, + lights.slice(&Index::object), + lights.slice(&Index::id)}, + SceneFieldData{SceneField::Skin, + skins.slice(&Index::object), + skins.slice(&Index::id)}, + SceneFieldData{SceneField::ImporterState, + importerState.slice(&ImporterState::object), importerState.slice(&ImporterState::importerState)} + }}}; + + CORRADE_COMPARE(importer.sceneCount(), 3); + + Containers::Optional scene = importer.scene(2); + CORRADE_VERIFY(scene); + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE_AS(scene->children2D(), + std::vector{}, + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(scene->children3D(), + (std::vector{3, 2, 0}), + TestSuite::Compare::Container); + + CORRADE_COMPARE(importer.object2DCount(), 0); + CORRADE_COMPARE(importer.object2DForName("sixth"), -1); + + CORRADE_COMPARE(importer.object3DCount(), 7); + CORRADE_COMPARE(importer.object3DForName("sixth"), 5); + CORRADE_COMPARE(importer.object3DName(5), "sixth"); { - auto data = importer.animation(7); - CORRADE_VERIFY(data); - CORRADE_COMPARE(data->importerState(), &state); + Containers::Pointer o = importer.object3D(0); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Mesh); + CORRADE_COMPARE(o->instance(), 33); + CORRADE_COMPARE(o->flags(), ObjectFlags3D{}); + CORRADE_COMPARE(o->transformation(), Matrix4::rotationX(30.0_degf)); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData3D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), -1); + CORRADE_COMPARE(mo.skin(), -1); } { - auto data = importer.animation("eighth"); - CORRADE_VERIFY(data); - CORRADE_COMPARE(data->importerState(), &state); + Containers::Pointer o = importer.object3D(1); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Light); + CORRADE_COMPARE(o->instance(), 113); + CORRADE_COMPARE(o->flags(), ObjectFlags3D{}); + CORRADE_COMPARE(o->transformation(), Matrix4::translation({1.0f, 0.0f, 1.0f})*Matrix4::rotationZ(15.0_degf)); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object3D(2); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags3D{}); + CORRADE_COMPARE(o->transformation(), Matrix4{}); + CORRADE_COMPARE_AS(o->children(), + std::vector{1}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object3D(3); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), &a); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Camera); + CORRADE_COMPARE(o->instance(), 15); + CORRADE_COMPARE(o->flags(), ObjectFlag3D::HasTranslationRotationScaling); + CORRADE_COMPARE(o->transformation(), Matrix4::translation({0.0f, 0.0f, 3.0f})*Matrix4::rotationX(15.0_degf)); + CORRADE_COMPARE(o->translation(), (Vector3{0.0f, 0.0f, 3.0f})); + CORRADE_COMPARE(o->rotation(), Quaternion::rotation(15.0_degf, Vector3::xAxis())); + CORRADE_COMPARE(o->scaling(), (Vector3{1.0f})); + CORRADE_COMPARE_AS(o->children(), + (std::vector{5, 4}), + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object3D(4); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), &b); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Mesh); + CORRADE_COMPARE(o->instance(), 27); + CORRADE_COMPARE(o->flags(), ObjectFlag3D::HasTranslationRotationScaling); + CORRADE_COMPARE(o->transformation(), Matrix4::scaling({1.5f, 3.0f, -0.5f})); + CORRADE_COMPARE(o->translation(), Vector3{}); + CORRADE_COMPARE(o->rotation(), Quaternion{}); + CORRADE_COMPARE(o->scaling(), (Vector3{1.5, 3.0f, -0.5f})); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData3D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 46); + CORRADE_COMPARE(mo.skin(), 72); + } { + Containers::Pointer o = importer.object3D("sixth"); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags3D{}); + CORRADE_COMPARE(o->transformation(), Matrix4::rotationY(-15.0_degf)); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } { + /* This one is not contained in any parent hierarchy, so it fails to + import */ + std::ostringstream out; + Error redirectError{&out}; + CORRADE_VERIFY(!importer.object3D(6)); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object3D(): object 6 not found in any 3D scene hierarchy\n"); } + CORRADE_IGNORE_DEPRECATED_POP } -void AbstractImporterTest::animationForNameOutOfRange() { - #ifdef CORRADE_NO_ASSERT - CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); - #endif +void AbstractImporterTest::sceneDeprecatedFallbackParentless2D() { + /* As the Parent field is currently used to distinguish which objects + belong to which scene, its absence means the objects are advertised, but + aren't listed as children of any scene, and retrieving them will fail */ + /** @todo adapt when there's a dedicated way to distinguish which objects + belong to which scene */ - struct: AbstractImporter { - ImporterFeatures doFeatures() const override { return {}; } - bool doIsOpened() const override { return true; } - void doClose() override {} + struct Field { + UnsignedInt object; + Matrix3 transformation; + } fields[]{ + {5, Matrix3{}}, + {2, Matrix3{}}, + }; - UnsignedInt doAnimationCount() const override { return 8; } - Int doAnimationForName(const std::string&) override { return 8; } - } importer; + Containers::StridedArrayView1D view = fields; - std::ostringstream out; - Error redirectError{&out}; - importer.animationForName(""); - CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animationForName(): implementation-returned index 8 out of range for 8 entries\n"); -} + struct Importer: AbstractImporter { + explicit Importer(SceneData&& data): _data{std::move(data)} {} -void AbstractImporterTest::animationNameNotImplemented() { - struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 1; } + UnsignedLong doObjectCount() const override { return 6; } + Containers::Optional doScene(UnsignedInt) override { + return SceneData{SceneObjectType::UnsignedInt, 6, {}, _data.data(), sceneFieldDataNonOwningArray(_data.fieldData())}; + } + + private: + SceneData _data; + } importer{SceneData{SceneObjectType::UnsignedInt, 6, {}, fields, { + SceneFieldData{SceneField::Transformation, + view.slice(&Field::object), + view.slice(&Field::transformation)} + }}}; + + CORRADE_COMPARE(importer.sceneCount(), 1); + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(importer.object2DCount(), 6); + CORRADE_COMPARE(importer.object3DCount(), 0); + CORRADE_IGNORE_DEPRECATED_POP + + Containers::Optional scene = importer.scene(0); + CORRADE_VERIFY(scene); + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE_AS(scene->children2D(), + std::vector{}, + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(scene->children3D(), + (std::vector{}), + TestSuite::Compare::Container); + CORRADE_IGNORE_DEPRECATED_POP + + std::ostringstream out; + Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_VERIFY(!importer.object2D(0)); + CORRADE_VERIFY(!importer.object2D(1)); + CORRADE_VERIFY(!importer.object2D(2)); + CORRADE_VERIFY(!importer.object2D(3)); + CORRADE_VERIFY(!importer.object2D(4)); + CORRADE_VERIFY(!importer.object2D(5)); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::object2D(): object 0 not found in any 2D scene hierarchy\n" + "Trade::AbstractImporter::object2D(): object 1 not found in any 2D scene hierarchy\n" + "Trade::AbstractImporter::object2D(): object 2 not found in any 2D scene hierarchy\n" + "Trade::AbstractImporter::object2D(): object 3 not found in any 2D scene hierarchy\n" + "Trade::AbstractImporter::object2D(): object 4 not found in any 2D scene hierarchy\n" + "Trade::AbstractImporter::object2D(): object 5 not found in any 2D scene hierarchy\n"); +} + +void AbstractImporterTest::sceneDeprecatedFallbackParentless3D() { + /* As the Parent field is currently used to distinguish which objects + belong to which scene, its absence means the objects are advertised, but + aren't listed as children of any scene, and retrieving them will fail */ + /** @todo adapt when there's a dedicated way to distinguish which objects + belong to which scene */ + + struct Field { + UnsignedInt object; + Matrix4 transformation; + } fields[]{ + {5, Matrix4{}}, + {2, Matrix4{}}, + }; + + Containers::StridedArrayView1D view = fields; + + struct Importer: AbstractImporter { + explicit Importer(SceneData&& data): _data{std::move(data)} {} + + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 1; } + UnsignedLong doObjectCount() const override { return 6; } + Containers::Optional doScene(UnsignedInt) override { + return SceneData{SceneObjectType::UnsignedInt, 6, {}, _data.data(), sceneFieldDataNonOwningArray(_data.fieldData())}; + } + + private: + SceneData _data; + } importer{SceneData{SceneObjectType::UnsignedInt, 6, {}, fields, { + SceneFieldData{SceneField::Transformation, + view.slice(&Field::object), + view.slice(&Field::transformation)} + }}}; + + CORRADE_COMPARE(importer.sceneCount(), 1); + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(importer.object2DCount(), 0); + CORRADE_COMPARE(importer.object3DCount(), 6); + CORRADE_IGNORE_DEPRECATED_POP + + Containers::Optional scene = importer.scene(0); + CORRADE_VERIFY(scene); + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE_AS(scene->children2D(), + std::vector{}, + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(scene->children3D(), + (std::vector{}), + TestSuite::Compare::Container); + CORRADE_IGNORE_DEPRECATED_POP + + std::ostringstream out; + Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_VERIFY(!importer.object3D(0)); + CORRADE_VERIFY(!importer.object3D(1)); + CORRADE_VERIFY(!importer.object3D(2)); + CORRADE_VERIFY(!importer.object3D(3)); + CORRADE_VERIFY(!importer.object3D(4)); + CORRADE_VERIFY(!importer.object3D(5)); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::object3D(): object 0 not found in any 3D scene hierarchy\n" + "Trade::AbstractImporter::object3D(): object 1 not found in any 3D scene hierarchy\n" + "Trade::AbstractImporter::object3D(): object 2 not found in any 3D scene hierarchy\n" + "Trade::AbstractImporter::object3D(): object 3 not found in any 3D scene hierarchy\n" + "Trade::AbstractImporter::object3D(): object 4 not found in any 3D scene hierarchy\n" + "Trade::AbstractImporter::object3D(): object 5 not found in any 3D scene hierarchy\n"); +} + +void AbstractImporterTest::sceneDeprecatedFallbackTransformless2D() { + /* If no transformation field is present, for backwards compatibility we + assume the objects are 3D -- the only plugin that has a 2D scene is + PrimitiveImporter and it has the transformation field. */ + + struct Field { + UnsignedInt object; + Int parent; + } fields[]{ + {5, -1}, + {2, 0}, + {3, 0}, + {1, -1} + }; + + Containers::StridedArrayView1D view = fields; + + struct Importer: AbstractImporter { + explicit Importer(SceneData&& data): _data{std::move(data)} {} + + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 1; } + UnsignedLong doObjectCount() const override { return 6; } + Containers::Optional doScene(UnsignedInt) override { + return SceneData{SceneObjectType::UnsignedInt, 6, {}, _data.data(), sceneFieldDataNonOwningArray(_data.fieldData())}; + } + + private: + SceneData _data; + } importer{SceneData{SceneObjectType::UnsignedInt, 6, {}, fields, { + SceneFieldData{SceneField::Parent, + view.slice(&Field::object), + view.slice(&Field::parent)}, + /* Required in order to have the scene recognized as 2D */ + SceneFieldData{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Matrix3x3, nullptr} + }}}; + + CORRADE_COMPARE(importer.sceneCount(), 1); + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(importer.object2DCount(), 6); + CORRADE_COMPARE(importer.object3DCount(), 0); + CORRADE_IGNORE_DEPRECATED_POP + + Containers::Optional scene = importer.scene(0); + CORRADE_VERIFY(scene); + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE_AS(scene->children2D(), + (std::vector{5, 1}), + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(scene->children3D(), + std::vector{}, + TestSuite::Compare::Container); + + { + Containers::Pointer o = importer.object2D(5); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags2D{}); + CORRADE_COMPARE(o->transformation(), Matrix3{}); + CORRADE_COMPARE_AS(o->children(), + (std::vector{2, 3}), + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object2D(2); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags2D{}); + CORRADE_COMPARE(o->transformation(), Matrix3{}); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object2D(3); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags2D{}); + CORRADE_COMPARE(o->transformation(), Matrix3{}); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object2D(1); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags2D{}); + CORRADE_COMPARE(o->transformation(), Matrix3{}); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } + CORRADE_IGNORE_DEPRECATED_POP +} +void AbstractImporterTest::sceneDeprecatedFallbackTransformless3D() { + /* If no transformation field is present, for backwards compatibility we + assume the objects are 3D -- the only plugin that has a 2D scene is + PrimitiveImporter and it has the transformation field. */ + + struct Field { + UnsignedInt object; + Int parent; + } fields[]{ + {5, -1}, + {2, 0}, + {3, 0}, + {1, -1} + }; + + Containers::StridedArrayView1D view = fields; + + struct Importer: AbstractImporter { + explicit Importer(SceneData&& data): _data{std::move(data)} {} + + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 1; } + UnsignedLong doObjectCount() const override { return 6; } + Containers::Optional doScene(UnsignedInt) override { + return SceneData{SceneObjectType::UnsignedInt, 6, {}, _data.data(), sceneFieldDataNonOwningArray(_data.fieldData())}; + } + + private: + SceneData _data; + } importer{SceneData{SceneObjectType::UnsignedInt, 6, {}, fields, { + SceneFieldData{SceneField::Parent, + view.slice(&Field::object), + view.slice(&Field::parent)}, + /* Required in order to have the scene recognized as 3D */ + SceneFieldData{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Matrix4x4, nullptr} + }}}; + + CORRADE_COMPARE(importer.sceneCount(), 1); + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(importer.object2DCount(), 0); + CORRADE_COMPARE(importer.object3DCount(), 6); + CORRADE_IGNORE_DEPRECATED_POP + + Containers::Optional scene = importer.scene(0); + CORRADE_VERIFY(scene); + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE_AS(scene->children2D(), + std::vector{}, + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(scene->children3D(), + (std::vector{5, 1}), + TestSuite::Compare::Container); + + { + Containers::Pointer o = importer.object3D(5); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags3D{}); + CORRADE_COMPARE(o->transformation(), Matrix4{}); + CORRADE_COMPARE_AS(o->children(), + (std::vector{2, 3}), + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object3D(2); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags3D{}); + CORRADE_COMPARE(o->transformation(), Matrix4{}); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object3D(3); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags3D{}); + CORRADE_COMPARE(o->transformation(), Matrix4{}); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object3D(1); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->importerState(), nullptr); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Empty); + CORRADE_COMPARE(o->instance(), -1); + CORRADE_COMPARE(o->flags(), ObjectFlags3D{}); + CORRADE_COMPARE(o->transformation(), Matrix4{}); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } + CORRADE_IGNORE_DEPRECATED_POP +} +#endif + +void AbstractImporterTest::sceneNameNotImplemented() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 8; } + } importer; + + CORRADE_COMPARE(importer.sceneName(7), ""); +} + +void AbstractImporterTest::objectNameNotImplemented() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedLong doObjectCount() const override { return 8; } + } importer; + + CORRADE_COMPARE(importer.objectName(7), ""); +} + +void AbstractImporterTest::sceneNameOutOfRange() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.sceneName(8); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::sceneName(): index 8 out of range for 8 entries\n"); +} + +void AbstractImporterTest::objectNameOutOfRange() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedLong doObjectCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.objectName(8); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::objectName(): index 8 out of range for 8 entries\n"); +} + +void AbstractImporterTest::sceneNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.scene(7); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::scene(): not implemented\n"); +} + +void AbstractImporterTest::sceneOutOfRange() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.scene(8); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::scene(): index 8 out of range for 8 entries\n"); +} + +void AbstractImporterTest::sceneNonOwningDeleters() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 1; } + Containers::Optional doScene(UnsignedInt) override { + return SceneData{SceneObjectType::UnsignedInt, 0, + Containers::Array{data, 1, Implementation::nonOwnedArrayDeleter}, + sceneFieldDataNonOwningArray(fields)}; + } + + char data[1]; + SceneFieldData fields[1]{ + SceneFieldData{SceneField::Parent, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Int, nullptr} + }; + } importer; + + auto data = importer.scene(0); + CORRADE_VERIFY(data); + CORRADE_COMPARE(static_cast(data->data()), importer.data); + CORRADE_COMPARE(static_cast(data->fieldData()), importer.fields); +} + +void AbstractImporterTest::sceneCustomDataDeleter() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 1; } + Int doSceneForName(const std::string&) override { return 0; } + Containers::Optional doScene(UnsignedInt) override { + return SceneData{SceneObjectType::UnsignedInt, 0, + Containers::Array{data, 1, [](char*, std::size_t) {}}, + {}}; + } + + char data[1]; + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.scene(0); + importer.scene(""); + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::scene(): implementation is not allowed to use a custom Array deleter\n" + "Trade::AbstractImporter::scene(): implementation is not allowed to use a custom Array deleter\n"); +} + +void AbstractImporterTest::sceneCustomFieldDataDeleter() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doSceneCount() const override { return 1; } + Int doSceneForName(const std::string&) override { return 0; } + Containers::Optional doScene(UnsignedInt) override { + return SceneData{SceneObjectType::UnsignedInt, 0, nullptr, Containers::Array{&parents, 1, [](SceneFieldData*, std::size_t) {}}}; + } + + SceneFieldData parents{SceneField::Parent, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Int, nullptr}; + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.scene(0); + importer.scene(""); + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::scene(): implementation is not allowed to use a custom Array deleter\n" + "Trade::AbstractImporter::scene(): implementation is not allowed to use a custom Array deleter\n" + ); +} + +void AbstractImporterTest::sceneFieldName() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + + SceneField doSceneFieldForName(const std::string& name) override { + if(name == "OctreeCell") return sceneFieldCustom(100037); + return SceneField{}; + } + + std::string doSceneFieldName(UnsignedInt id) override { + if(id == 100037) return "OctreeCell"; + return ""; + } + } importer; + + CORRADE_COMPARE(importer.sceneFieldForName("OctreeCell"), sceneFieldCustom(100037)); + CORRADE_COMPARE(importer.sceneFieldName(sceneFieldCustom(100037)), "OctreeCell"); +} + +void AbstractImporterTest::sceneFieldNameNotImplemented() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + CORRADE_COMPARE(importer.sceneFieldForName(""), SceneField{}); + CORRADE_COMPARE(importer.sceneFieldName(sceneFieldCustom(100037)), ""); +} + +void AbstractImporterTest::sceneFieldNameNotCustom() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + + SceneField doSceneFieldForName(const std::string&) override { + return SceneField::Translation; + } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + importer.sceneFieldForName("OctreeCell"); + importer.sceneFieldName(SceneField::Translation); + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::sceneFieldForName(): implementation-returned Trade::SceneField::Translation is neither custom nor invalid\n" + "Trade::AbstractImporter::sceneFieldName(): Trade::SceneField::Translation is not custom\n"); +} + +void AbstractImporterTest::animation() { + struct: AbstractImporter { + ImporterFeatures 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; + return -1; + } + std::string doAnimationName(UnsignedInt id) override { + if(id == 7) return "eighth"; + return {}; + } + Containers::Optional doAnimation(UnsignedInt id) override { + /* Verify that initializer list is converted to an array with + the default deleter and not something disallowed */ + if(id == 7) return AnimationData{nullptr, { + AnimationTrackData{AnimationTrackType::Vector3, + AnimationTrackTargetType::Scaling3D, 0, {}} + }, &state}; + return AnimationData{{}, {}}; + } + } 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); + } { + auto data = importer.animation("eighth"); + CORRADE_VERIFY(data); + CORRADE_COMPARE(data->importerState(), &state); + } +} + +void AbstractImporterTest::animationForNameOutOfRange() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doAnimationCount() const override { return 8; } + Int doAnimationForName(const std::string&) override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + importer.animationForName(""); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::animationForName(): implementation-returned index 8 out of range for 8 entries\n"); +} + +void AbstractImporterTest::animationNameNotImplemented() { + struct: AbstractImporter { ImporterFeatures doFeatures() const override { return {}; } bool doIsOpened() const override { return true; } void doClose() override {} @@ -2265,80 +3368,175 @@ void AbstractImporterTest::cameraNameOutOfRange() { CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::cameraName(): index 8 out of range for 8 entries\n"); } -void AbstractImporterTest::cameraNotImplemented() { +void AbstractImporterTest::cameraNotImplemented() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doCameraCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.camera(7); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::camera(): not implemented\n"); +} + +void AbstractImporterTest::cameraOutOfRange() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doCameraCount() const override { return 8; } + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + importer.camera(8); + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::camera(): index 8 out of range for 8 entries\n"); +} + +#ifdef MAGNUM_BUILD_DEPRECATED +void AbstractImporterTest::object2D() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doObject2DCount() const override { return 8; } + Int doObject2DForName(const std::string& name) override { + if(name == "eighth") return 7; + return -1; + } + std::string doObject2DName(UnsignedInt id) override { + if(id == 7) return "eighth"; + return {}; + } + CORRADE_IGNORE_DEPRECATED_PUSH + Containers::Pointer doObject2D(UnsignedInt id) override { + if(id == 7) return Containers::pointer(new ObjectData2D{{}, {}, &state}); + return {}; + } + CORRADE_IGNORE_DEPRECATED_POP + } importer; + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(importer.object2DCount(), 8); + CORRADE_COMPARE(importer.object2DForName("eighth"), 7); + CORRADE_COMPARE(importer.object2DName(7), "eighth"); + + { + auto data = importer.object2D(7); + CORRADE_VERIFY(data); + CORRADE_COMPARE(data->importerState(), &state); + } { + auto data = importer.object2D("eighth"); + CORRADE_VERIFY(data); + CORRADE_COMPARE(data->importerState(), &state); + } + CORRADE_IGNORE_DEPRECATED_POP +} + +void AbstractImporterTest::object2DCountNotImplemented() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + } importer; + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(importer.object2DCount(), 0); + CORRADE_IGNORE_DEPRECATED_POP +} + +void AbstractImporterTest::object2DCountNoFile() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif struct: AbstractImporter { ImporterFeatures doFeatures() const override { return {}; } - bool doIsOpened() const override { return true; } + bool doIsOpened() const override { return false; } void doClose() override {} - - UnsignedInt doCameraCount() const override { return 8; } } importer; std::ostringstream out; Error redirectError{&out}; - importer.camera(7); - CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::camera(): not implemented\n"); + CORRADE_IGNORE_DEPRECATED_PUSH + importer.object2DCount(); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object2DCount(): no file opened\n"); } -void AbstractImporterTest::cameraOutOfRange() { +void AbstractImporterTest::object2DForNameNotImplemented() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + } importer; + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(importer.object2DForName(""), -1); + CORRADE_IGNORE_DEPRECATED_POP +} + +void AbstractImporterTest::object2DForNameNoFile() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif struct: AbstractImporter { ImporterFeatures doFeatures() const override { return {}; } - bool doIsOpened() const override { return true; } + bool doIsOpened() const override { return false; } void doClose() override {} - - UnsignedInt doCameraCount() const override { return 8; } } importer; std::ostringstream out; Error redirectError{&out}; - importer.camera(8); - CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::camera(): index 8 out of range for 8 entries\n"); + CORRADE_IGNORE_DEPRECATED_PUSH + importer.object2DForName(""); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object2DForName(): no file opened\n"); } -void AbstractImporterTest::object2D() { +void AbstractImporterTest::object2DByNameNotFound() { + auto&& data = ThingByNameData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + struct: AbstractImporter { ImporterFeatures doFeatures() const override { return {}; } bool doIsOpened() const override { return true; } void doClose() override {} - UnsignedInt doObject2DCount() const override { return 8; } - Int doObject2DForName(const std::string& name) override { - if(name == "eighth") return 7; - return -1; - } - std::string doObject2DName(UnsignedInt id) override { - if(id == 7) return "eighth"; - return {}; - } - Containers::Pointer doObject2D(UnsignedInt id) override { - if(id == 7) return Containers::pointer(new ObjectData2D{{}, {}, &state}); - return {}; - } + UnsignedInt doObject2DCount() const override { return 5; } } importer; - CORRADE_COMPARE(importer.object2DCount(), 8); - CORRADE_COMPARE(importer.object2DForName("eighth"), 7); - CORRADE_COMPARE(importer.object2DName(7), "eighth"); - + std::ostringstream out; { - auto data = importer.object2D(7); - CORRADE_VERIFY(data); - CORRADE_COMPARE(data->importerState(), &state); - } { - auto data = importer.object2D("eighth"); - CORRADE_VERIFY(data); - CORRADE_COMPARE(data->importerState(), &state); + Containers::Optional redirectError; + if(data.checkMessage) redirectError.emplace(&out); + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_VERIFY(!importer.object2D("foobar")); + CORRADE_IGNORE_DEPRECATED_POP } + + if(data.checkMessage) CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::object2D(): object foobar not found among 5 entries\n"); } void AbstractImporterTest::object2DForNameOutOfRange() { @@ -2357,7 +3555,9 @@ void AbstractImporterTest::object2DForNameOutOfRange() { std::ostringstream out; Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH importer.object2DForName(""); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object2DForName(): implementation-returned index 8 out of range for 8 entries\n"); } @@ -2370,7 +3570,29 @@ void AbstractImporterTest::object2DNameNotImplemented() { UnsignedInt doObject2DCount() const override { return 8; } } importer; + CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_COMPARE(importer.object2DName(7), ""); + CORRADE_IGNORE_DEPRECATED_POP +} + +void AbstractImporterTest::object2DNameNoFile() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + CORRADE_IGNORE_DEPRECATED_PUSH + importer.object2DName(42); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object2DName(): no file opened\n"); } void AbstractImporterTest::object2DNameOutOfRange() { @@ -2389,7 +3611,9 @@ void AbstractImporterTest::object2DNameOutOfRange() { std::ostringstream out; Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH importer.object2DName(8); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object2DName(): index 8 out of range for 8 entries\n"); } @@ -2403,14 +3627,44 @@ void AbstractImporterTest::object2DNotImplemented() { bool doIsOpened() const override { return true; } void doClose() override {} + UnsignedInt doSceneCount() const override { return 1; } UnsignedInt doObject2DCount() const override { return 8; } } importer; std::ostringstream out; Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH importer.object2D(7); - CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object2D(): not implemented\n"); + CORRADE_IGNORE_DEPRECATED_POP + /* It delegates to scene(), but since the assert is graceful and returns a + null optional, it errors out immediately after */ + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::scene(): not implemented\n" + "Trade::AbstractImporter::object2D(): object 7 not found in any 2D scene hierarchy\n"); +} + +void AbstractImporterTest::object2DNoFile() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + CORRADE_IGNORE_DEPRECATED_PUSH + importer.object2D(42); + importer.object2D("foo"); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::object2D(): no file opened\n" + "Trade::AbstractImporter::object2D(): no file opened\n"); } void AbstractImporterTest::object2DOutOfRange() { @@ -2429,7 +3683,9 @@ void AbstractImporterTest::object2DOutOfRange() { std::ostringstream out; Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH importer.object2D(8); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object2D(): index 8 out of range for 8 entries\n"); } @@ -2448,12 +3704,15 @@ void AbstractImporterTest::object3D() { if(id == 7) return "eighth"; return {}; } + CORRADE_IGNORE_DEPRECATED_PUSH Containers::Pointer doObject3D(UnsignedInt id) override { if(id == 7) return Containers::pointer(new ObjectData3D{{}, {}, &state}); return {}; } + CORRADE_IGNORE_DEPRECATED_POP } importer; + CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_COMPARE(importer.object3DCount(), 8); CORRADE_COMPARE(importer.object3DForName("eighth"), 7); CORRADE_COMPARE(importer.object3DName(7), "eighth"); @@ -2467,6 +3726,97 @@ void AbstractImporterTest::object3D() { CORRADE_VERIFY(data); CORRADE_COMPARE(data->importerState(), &state); } + CORRADE_IGNORE_DEPRECATED_POP +} + +void AbstractImporterTest::object3DCountNotImplemented() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + } importer; + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(importer.object3DCount(), 0); + CORRADE_IGNORE_DEPRECATED_POP +} + +void AbstractImporterTest::object3DCountNoFile() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + CORRADE_IGNORE_DEPRECATED_PUSH + importer.object3DCount(); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object3DCount(): no file opened\n"); +} + +void AbstractImporterTest::object3DForNameNotImplemented() { + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + } importer; + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE(importer.object3DForName(""), -1); + CORRADE_IGNORE_DEPRECATED_POP +} + +void AbstractImporterTest::object3DForNameNoFile() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + CORRADE_IGNORE_DEPRECATED_PUSH + importer.object2DForName(""); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object2DForName(): no file opened\n"); +} + +void AbstractImporterTest::object3DByNameNotFound() { + auto&& data = ThingByNameData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return true; } + void doClose() override {} + + UnsignedInt doObject3DCount() const override { return 6; } + } importer; + + std::ostringstream out; + { + Containers::Optional redirectError; + if(data.checkMessage) redirectError.emplace(&out); + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_VERIFY(!importer.object3D("foobar")); + CORRADE_IGNORE_DEPRECATED_POP + } + + if(data.checkMessage) CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::object3D(): object foobar not found among 6 entries\n"); } void AbstractImporterTest::object3DForNameOutOfRange() { @@ -2485,7 +3835,9 @@ void AbstractImporterTest::object3DForNameOutOfRange() { std::ostringstream out; Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH importer.object3DForName(""); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object3DForName(): implementation-returned index 8 out of range for 8 entries\n"); } @@ -2498,7 +3850,29 @@ void AbstractImporterTest::object3DNameNotImplemented() { UnsignedInt doObject3DCount() const override { return 8; } } importer; + CORRADE_IGNORE_DEPRECATED_PUSH CORRADE_COMPARE(importer.object3DName(7), ""); + CORRADE_IGNORE_DEPRECATED_POP +} + +void AbstractImporterTest::object3DNameNoFile() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + CORRADE_IGNORE_DEPRECATED_PUSH + importer.object3DName(42); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object3DName(): no file opened\n"); } void AbstractImporterTest::object3DNameOutOfRange() { @@ -2517,7 +3891,9 @@ void AbstractImporterTest::object3DNameOutOfRange() { std::ostringstream out; Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH importer.object3DName(8); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object3DName(): index 8 out of range for 8 entries\n"); } @@ -2531,14 +3907,44 @@ void AbstractImporterTest::object3DNotImplemented() { bool doIsOpened() const override { return true; } void doClose() override {} + UnsignedInt doSceneCount() const override { return 1; } UnsignedInt doObject3DCount() const override { return 8; } } importer; std::ostringstream out; Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH importer.object3D(7); - CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object3D(): not implemented\n"); + CORRADE_IGNORE_DEPRECATED_POP + /* It delegates to scene(), but since the assert is graceful and returns a + null optional, it errors out immediately after */ + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::scene(): not implemented\n" + "Trade::AbstractImporter::object3D(): object 7 not found in any 3D scene hierarchy\n"); +} + +void AbstractImporterTest::object3DNoFile() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + struct: AbstractImporter { + ImporterFeatures doFeatures() const override { return {}; } + bool doIsOpened() const override { return false; } + void doClose() override {} + } importer; + + std::ostringstream out; + Error redirectError{&out}; + + CORRADE_IGNORE_DEPRECATED_PUSH + importer.object3D(42); + importer.object3D("foo"); + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), + "Trade::AbstractImporter::object3D(): no file opened\n" + "Trade::AbstractImporter::object3D(): no file opened\n"); } void AbstractImporterTest::object3DOutOfRange() { @@ -2557,9 +3963,12 @@ void AbstractImporterTest::object3DOutOfRange() { std::ostringstream out; Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH importer.object3D(8); + CORRADE_IGNORE_DEPRECATED_POP CORRADE_COMPARE(out.str(), "Trade::AbstractImporter::object3D(): index 8 out of range for 8 entries\n"); } +#endif void AbstractImporterTest::skin2D() { struct: AbstractImporter { diff --git a/src/Magnum/Trade/Test/CMakeLists.txt b/src/Magnum/Trade/Test/CMakeLists.txt index 75103d461..711436146 100644 --- a/src/Magnum/Trade/Test/CMakeLists.txt +++ b/src/Magnum/Trade/Test/CMakeLists.txt @@ -54,8 +54,6 @@ corrade_add_test(TradeImageDataTest ImageDataTest.cpp LIBRARIES MagnumTradeTestL corrade_add_test(TradeLightDataTest LightDataTest.cpp LIBRARIES MagnumTradeTestLib) corrade_add_test(TradeMaterialDataTest MaterialDataTest.cpp LIBRARIES MagnumTradeTestLib) corrade_add_test(TradeMeshDataTest MeshDataTest.cpp LIBRARIES MagnumTradeTestLib) -corrade_add_test(TradeObjectData2DTest ObjectData2DTest.cpp LIBRARIES MagnumTradeTestLib) -corrade_add_test(TradeObjectData3DTest ObjectData3DTest.cpp LIBRARIES MagnumTradeTestLib) corrade_add_test(TradePbrClearCoatMaterialDataTest PbrClearCoatMaterialDataTest.cpp LIBRARIES MagnumTradeTestLib) corrade_add_test(TradePbrMetallicRoughnessMate___Test PbrMetallicRoughnessMaterialDataTest.cpp LIBRARIES MagnumTradeTestLib) corrade_add_test(TradePbrSpecularGlossinessMat___Test PbrSpecularGlossinessMaterialDataTest.cpp LIBRARIES MagnumTradeTestLib) @@ -81,8 +79,6 @@ set_target_properties( TradeImageDataTest TradeLightDataTest TradeMaterialDataTest - TradeObjectData2DTest - TradeObjectData3DTest TradePbrClearCoatMaterialDataTest TradePbrMetallicRoughnessMate___Test TradePbrSpecularGlossinessMat___Test @@ -94,9 +90,13 @@ set_target_properties( if(MAGNUM_BUILD_DEPRECATED) corrade_add_test(TradeMeshData2DTest MeshData2DTest.cpp LIBRARIES MagnumTrade) corrade_add_test(TradeMeshData3DTest MeshData3DTest.cpp LIBRARIES MagnumTrade) + corrade_add_test(TradeObjectData2DTest ObjectData2DTest.cpp LIBRARIES MagnumTradeTestLib) + corrade_add_test(TradeObjectData3DTest ObjectData3DTest.cpp LIBRARIES MagnumTradeTestLib) set_target_properties( TradeMeshData2DTest TradeMeshData3DTest + TradeObjectData2DTest + TradeObjectData3DTest PROPERTIES FOLDER "Magnum/Trade/Test") endif() diff --git a/src/Magnum/Trade/Test/ObjectData2DTest.cpp b/src/Magnum/Trade/Test/ObjectData2DTest.cpp index a4ad55b57..48e039015 100644 --- a/src/Magnum/Trade/Test/ObjectData2DTest.cpp +++ b/src/Magnum/Trade/Test/ObjectData2DTest.cpp @@ -23,6 +23,9 @@ DEALINGS IN THE SOFTWARE. */ +/* There's no better way to disable file deprecation warnings */ +#define _MAGNUM_NO_DEPRECATED_OBJECTDATA + #include #include #include @@ -51,6 +54,8 @@ class ObjectData2DTest: public TestSuite::Tester { void debugFlags(); }; +CORRADE_IGNORE_DEPRECATED_PUSH + ObjectData2DTest::ObjectData2DTest() { addTests({&ObjectData2DTest::constructEmpty, &ObjectData2DTest::constructEmptyTransformations, @@ -264,6 +269,8 @@ void ObjectData2DTest::debugFlags() { CORRADE_COMPARE(o.str(), "Trade::ObjectFlag2D::HasTranslationRotationScaling Trade::ObjectFlags2D{}\n"); } +CORRADE_IGNORE_DEPRECATED_POP + }}}} CORRADE_TEST_MAIN(Magnum::Trade::Test::ObjectData2DTest) diff --git a/src/Magnum/Trade/Test/ObjectData3DTest.cpp b/src/Magnum/Trade/Test/ObjectData3DTest.cpp index 2b39a4eaa..3fe3a6e84 100644 --- a/src/Magnum/Trade/Test/ObjectData3DTest.cpp +++ b/src/Magnum/Trade/Test/ObjectData3DTest.cpp @@ -23,6 +23,9 @@ DEALINGS IN THE SOFTWARE. */ +/* There's no better way to disable file deprecation warnings */ +#define _MAGNUM_NO_DEPRECATED_OBJECTDATA + #include #include #include @@ -70,6 +73,8 @@ ObjectData3DTest::ObjectData3DTest() { &ObjectData3DTest::debugFlags}); } +CORRADE_IGNORE_DEPRECATED_PUSH + using namespace Math::Literals; void ObjectData3DTest::constructEmpty() { @@ -278,6 +283,8 @@ void ObjectData3DTest::debugFlags() { CORRADE_COMPARE(o.str(), "Trade::ObjectFlag3D::HasTranslationRotationScaling Trade::ObjectFlags3D{}\n"); } +CORRADE_IGNORE_DEPRECATED_POP + }}}} CORRADE_TEST_MAIN(Magnum::Trade::Test::ObjectData3DTest) diff --git a/src/Magnum/Trade/Trade.h b/src/Magnum/Trade/Trade.h index 46f98370c..fdd47b9c7 100644 --- a/src/Magnum/Trade/Trade.h +++ b/src/Magnum/Trade/Trade.h @@ -89,11 +89,11 @@ class MeshData; #ifdef MAGNUM_BUILD_DEPRECATED class CORRADE_DEPRECATED("use MeshData instead") MeshData2D; class CORRADE_DEPRECATED("use MeshData instead") MeshData3D; +class CORRADE_DEPRECATED("use SceneData instead") MeshObjectData2D; +class CORRADE_DEPRECATED("use SceneData instead") MeshObjectData3D; +class CORRADE_DEPRECATED("use SceneData instead") ObjectData2D; +class CORRADE_DEPRECATED("use SceneData instead") ObjectData3D; #endif -class MeshObjectData2D; -class MeshObjectData3D; -class ObjectData2D; -class ObjectData3D; class PbrClearCoatMaterialData; class PbrMetallicRoughnessMaterialData; class PbrSpecularGlossinessMaterialData;