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;