From 4a4eceadc3cf9a91ea672859ed1608970e11a554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 14 Oct 2021 00:09:10 +0200 Subject: [PATCH] [wip] Trade: process SceneData to single-function-objects for backwards compat. Now the code has all needed backwards compatibility in place. TODO: docs about how multi-function objects got changed (new IDs at the end) --- src/Magnum/Trade/AbstractImporter.cpp | 32 +- .../Trade/Test/AbstractImporterTest.cpp | 357 ++++++++++++++++++ 2 files changed, 380 insertions(+), 9 deletions(-) diff --git a/src/Magnum/Trade/AbstractImporter.cpp b/src/Magnum/Trade/AbstractImporter.cpp index 5be72fb39b..86d98e173e 100644 --- a/src/Magnum/Trade/AbstractImporter.cpp +++ b/src/Magnum/Trade/AbstractImporter.cpp @@ -48,6 +48,8 @@ #include #include +#include "Magnum/Trade/Implementation/sceneTools.h" + #define _MAGNUM_NO_DEPRECATED_MESHDATA /* So it doesn't yell here */ #define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */ @@ -488,12 +490,20 @@ void AbstractImporter::populateCachedScenes() { _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]) { + /* Convert the scene so that each object has only either a mesh + (potentially with a material and a skin), a camera or a light. + The tool requires SceneField::Parent to be present, however if + it's not then we treat the scene as empty in the backwards + compatibility code path anyway, so just skip the processing + altogether in that case. */ + if(_cachedScenes->scenes[i]->hasField(SceneField::Parent)) + _cachedScenes->scenes[i] = Implementation::sceneConvertToSingleFunctionObjects(*_cachedScenes->scenes[i], Containers::arrayView({SceneField::Mesh, SceneField::Camera, SceneField::Light}), objectCount()); + + /* 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]->is2D()) _cachedScenes->object2DCount = Math::max(_cachedScenes->object2DCount, UnsignedInt(_cachedScenes->scenes[i]->objectCount())); if(_cachedScenes->scenes[i]->is3D()) @@ -607,8 +617,10 @@ Containers::Pointer AbstractImporter::doObject2D(const UnsignedInt 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. */ + /* All these should have at most 1 item as the SceneData got processed to + have each object contain either just one mesh or one camera (materials + are implicitly shared with a mesh, skins also). Thus it doesn't matter + in which order we decide on the legacy object type. */ CORRADE_INTERNAL_ASSERT(camera.size() + mesh.size() <= 1); if(!mesh.empty()) { @@ -763,8 +775,10 @@ Containers::Pointer AbstractImporter::doObject3D(const UnsignedInt 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. */ + /* All these should have at most 1 item as the SceneData got processed to + have each object contain either just one mesh, one camera or one light + (materials are implicitly shared with a mesh, skins also). Thus it + doesn't matter in which order we decide on the legacy object type. */ CORRADE_INTERNAL_ASSERT(camera.size() + light.size() + mesh.size() <= 1); if(!mesh.empty()) { diff --git a/src/Magnum/Trade/Test/AbstractImporterTest.cpp b/src/Magnum/Trade/Test/AbstractImporterTest.cpp index 2e4d39e662..5fc56590f9 100644 --- a/src/Magnum/Trade/Test/AbstractImporterTest.cpp +++ b/src/Magnum/Trade/Test/AbstractImporterTest.cpp @@ -48,6 +48,7 @@ #ifdef MAGNUM_BUILD_DEPRECATED #include #include +#include #define _MAGNUM_NO_DEPRECATED_MESHDATA /* So it doesn't yell here */ #define _MAGNUM_NO_DEPRECATED_OBJECTDATA /* So it doesn't yell here */ @@ -116,6 +117,8 @@ struct AbstractImporterTest: TestSuite::Tester { void sceneDeprecatedFallbackParentless3D(); void sceneDeprecatedFallbackTransformless2D(); void sceneDeprecatedFallbackTransformless3D(); + void sceneDeprecatedFallbackMultiFunctionObjects2D(); + void sceneDeprecatedFallbackMultiFunctionObjects3D(); #endif void sceneNameNotImplemented(); void objectNameNotImplemented(); @@ -394,6 +397,8 @@ AbstractImporterTest::AbstractImporterTest() { &AbstractImporterTest::sceneDeprecatedFallbackParentless3D, &AbstractImporterTest::sceneDeprecatedFallbackTransformless2D, &AbstractImporterTest::sceneDeprecatedFallbackTransformless3D, + &AbstractImporterTest::sceneDeprecatedFallbackMultiFunctionObjects2D, + &AbstractImporterTest::sceneDeprecatedFallbackMultiFunctionObjects3D, #endif &AbstractImporterTest::sceneForNameOutOfRange, &AbstractImporterTest::objectForNameOutOfRange, @@ -2564,6 +2569,358 @@ void AbstractImporterTest::sceneDeprecatedFallbackTransformless3D() { } CORRADE_IGNORE_DEPRECATED_POP } + +void AbstractImporterTest::sceneDeprecatedFallbackMultiFunctionObjects2D() { + /* Mostly just a copy of SceneToolsTest::convertToSingleFunctionObjects() + except that here we can't use the convenience combining tool so it's + done by hand */ + + struct Parent { + UnsignedInt object; + Int parent; + }; + struct Mesh { + UnsignedInt object; + UnsignedInt mesh; + Int meshMaterial; + }; + struct Camera { + UnsignedInt object; + UnsignedInt camera; + }; + Containers::StridedArrayView1D parents; + Containers::StridedArrayView1D meshes; + Containers::StridedArrayView1D cameras; + Containers::Array dataData = Containers::ArrayTuple{ + {NoInit, 5, parents}, + {NoInit, 7, meshes}, + {NoInit, 2, cameras}, + }; + + SceneData data{SceneObjectType::UnsignedInt, 32, std::move(dataData), { + SceneFieldData{SceneField::Parent, parents.slice(&Parent::object), parents.slice(&Parent::parent)}, + 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(&Camera::object), cameras.slice(&Camera::camera)}, + /* Just to disambiguate this as a 2D scene */ + SceneFieldData{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Matrix3x3, nullptr}, + }}; + Utility::copy(Containers::arrayView({15, 21, 22, 23, 1}), + data.mutableObjects(SceneField::Parent)); + Utility::copy(Containers::arrayView({-1, -1, 1, 2, -1}), + data.mutableField(SceneField::Parent)); + Utility::copy(Containers::arrayView({15, 23, 23, 23, 1, 15, 21}), + data.mutableObjects(SceneField::Mesh)); + Utility::copy(Containers::arrayView({6, 1, 2, 4, 7, 3, 5}), + data.mutableField(SceneField::Mesh)); + Utility::copy(Containers::arrayView({4, 0, 3, 2, 2, 1, -1}), + data.mutableField(SceneField::MeshMaterial)); + Utility::copy(Containers::arrayView({22, 1}), + data.mutableObjects(SceneField::Camera)); + Utility::copy(Containers::arrayView({1, 5}), + data.mutableField(SceneField::Camera)); + 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 63; } + Containers::Optional doScene(UnsignedInt) override { + return SceneData{SceneObjectType::UnsignedInt, 32, {}, _data.data(), sceneFieldDataNonOwningArray(_data.fieldData())}; + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + } + + private: + SceneData _data; + } importer{std::move(data)}; + + CORRADE_COMPARE(importer.sceneCount(), 1); + + Containers::Optional scene = importer.scene(0); + CORRADE_VERIFY(scene); + + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE_AS(scene->children2D(), + (std::vector{15, 21, 1}), + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(scene->children3D(), + std::vector{}, + TestSuite::Compare::Container); + + /* Total object count reported by the importer plus four new added */ + CORRADE_COMPARE(importer.object2DCount(), 63 + 4); + CORRADE_COMPARE(importer.object3DCount(), 0); + + /* Only 9 objects should exist in total, go in order. Usually the object + IDs will be contiguous so no such mess as this happens. */ + { + Containers::Pointer o = importer.object2D(1); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Mesh); + CORRADE_COMPARE(o->instance(), 7); + CORRADE_COMPARE_AS(o->children(), + std::vector{66}, + TestSuite::Compare::Container); + MeshObjectData2D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 2); + } { + Containers::Pointer o = importer.object2D(15); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Mesh); + CORRADE_COMPARE(o->instance(), 6); + CORRADE_COMPARE_AS(o->children(), + std::vector{65}, + TestSuite::Compare::Container); + MeshObjectData2D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 4); + } { + Containers::Pointer o = importer.object2D(21); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Mesh); + CORRADE_COMPARE(o->instance(), 5); + CORRADE_COMPARE_AS(o->children(), + std::vector{22}, + TestSuite::Compare::Container); + MeshObjectData2D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), -1); + } { + Containers::Pointer o = importer.object2D(22); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Camera); + CORRADE_COMPARE(o->instance(), 1); + CORRADE_COMPARE_AS(o->children(), + std::vector{23}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object2D(23); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Mesh); + CORRADE_COMPARE(o->instance(), 1); + CORRADE_COMPARE_AS(o->children(), + (std::vector{63, 64}), + TestSuite::Compare::Container); + MeshObjectData2D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 0); + } { + Containers::Pointer o = importer.object2D(63); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Mesh); + CORRADE_COMPARE(o->instance(), 2); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData2D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 3); + } { + Containers::Pointer o = importer.object2D(64); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Mesh); + CORRADE_COMPARE(o->instance(), 4); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData2D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 2); + } { + Containers::Pointer o = importer.object2D(65); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Mesh); + CORRADE_COMPARE(o->instance(), 3); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData2D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 1); + } { + Containers::Pointer o = importer.object2D(66); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType2D::Camera); + CORRADE_COMPARE(o->instance(), 5); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } + CORRADE_IGNORE_DEPRECATED_POP +} + +void AbstractImporterTest::sceneDeprecatedFallbackMultiFunctionObjects3D() { + /* Mostly just a copy of SceneToolsTest::convertToSingleFunctionObjects() + except that here we can't use the convenience combining tool so it's + done by hand */ + + struct Parent { + UnsignedInt object; + Int parent; + }; + struct Mesh { + UnsignedInt object; + UnsignedInt mesh; + Int meshMaterial; + }; + struct Camera { + UnsignedInt object; + UnsignedInt camera; + }; + Containers::StridedArrayView1D parents; + Containers::StridedArrayView1D meshes; + Containers::StridedArrayView1D cameras; + Containers::Array dataData = Containers::ArrayTuple{ + {NoInit, 5, parents}, + {NoInit, 7, meshes}, + {NoInit, 2, cameras}, + }; + + SceneData data{SceneObjectType::UnsignedInt, 32, std::move(dataData), { + SceneFieldData{SceneField::Parent, parents.slice(&Parent::object), parents.slice(&Parent::parent)}, + 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(&Camera::object), cameras.slice(&Camera::camera)}, + /* Just to disambiguate this as a 3D scene */ + SceneFieldData{SceneField::Transformation, SceneObjectType::UnsignedInt, nullptr, SceneFieldType::Matrix4x4, nullptr}, + }}; + Utility::copy(Containers::arrayView({15, 21, 22, 23, 1}), + data.mutableObjects(SceneField::Parent)); + Utility::copy(Containers::arrayView({-1, -1, 1, 2, -1}), + data.mutableField(SceneField::Parent)); + Utility::copy(Containers::arrayView({15, 23, 23, 23, 1, 15, 21}), + data.mutableObjects(SceneField::Mesh)); + Utility::copy(Containers::arrayView({6, 1, 2, 4, 7, 3, 5}), + data.mutableField(SceneField::Mesh)); + Utility::copy(Containers::arrayView({4, 0, 3, 2, 2, 1, -1}), + data.mutableField(SceneField::MeshMaterial)); + Utility::copy(Containers::arrayView({22, 1}), + data.mutableObjects(SceneField::Camera)); + Utility::copy(Containers::arrayView({1, 5}), + data.mutableField(SceneField::Camera)); + 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 63; } + Containers::Optional doScene(UnsignedInt) override { + return SceneData{SceneObjectType::UnsignedInt, 32, {}, _data.data(), sceneFieldDataNonOwningArray(_data.fieldData())}; + CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + } + + private: + SceneData _data; + } importer{std::move(data)}; + + CORRADE_COMPARE(importer.sceneCount(), 1); + + 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{15, 21, 1}), + TestSuite::Compare::Container); + + /* Total object count reported by the importer plus four new added */ + CORRADE_COMPARE(importer.object2DCount(), 0); + CORRADE_COMPARE(importer.object3DCount(), 63 + 4); + + /* Only 9 objects should exist in total, go in order. Usually the object + IDs will be contiguous so no such mess as this happens. */ + { + Containers::Pointer o = importer.object3D(1); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Mesh); + CORRADE_COMPARE(o->instance(), 7); + CORRADE_COMPARE_AS(o->children(), + std::vector{66}, + TestSuite::Compare::Container); + MeshObjectData3D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 2); + } { + Containers::Pointer o = importer.object3D(15); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Mesh); + CORRADE_COMPARE(o->instance(), 6); + CORRADE_COMPARE_AS(o->children(), + std::vector{65}, + TestSuite::Compare::Container); + MeshObjectData3D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 4); + } { + Containers::Pointer o = importer.object3D(21); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Mesh); + CORRADE_COMPARE(o->instance(), 5); + CORRADE_COMPARE_AS(o->children(), + std::vector{22}, + TestSuite::Compare::Container); + MeshObjectData3D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), -1); + } { + Containers::Pointer o = importer.object3D(22); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Camera); + CORRADE_COMPARE(o->instance(), 1); + CORRADE_COMPARE_AS(o->children(), + std::vector{23}, + TestSuite::Compare::Container); + } { + Containers::Pointer o = importer.object3D(23); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Mesh); + CORRADE_COMPARE(o->instance(), 1); + CORRADE_COMPARE_AS(o->children(), + (std::vector{63, 64}), + TestSuite::Compare::Container); + MeshObjectData3D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 0); + } { + Containers::Pointer o = importer.object3D(63); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Mesh); + CORRADE_COMPARE(o->instance(), 2); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData3D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 3); + } { + Containers::Pointer o = importer.object3D(64); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Mesh); + CORRADE_COMPARE(o->instance(), 4); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData3D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 2); + } { + Containers::Pointer o = importer.object3D(65); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Mesh); + CORRADE_COMPARE(o->instance(), 3); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + MeshObjectData3D& mo = static_cast(*o); + CORRADE_COMPARE(mo.material(), 1); + } { + Containers::Pointer o = importer.object3D(66); + CORRADE_VERIFY(o); + CORRADE_COMPARE(o->instanceType(), ObjectInstanceType3D::Camera); + CORRADE_COMPARE(o->instance(), 5); + CORRADE_COMPARE_AS(o->children(), + std::vector{}, + TestSuite::Compare::Container); + } + CORRADE_IGNORE_DEPRECATED_POP +} #endif void AbstractImporterTest::sceneNameNotImplemented() {