From 4da64d61e2833a2761ab1f95921fd738181dfa8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 2 Sep 2021 16:59:59 +0200 Subject: [PATCH] Trade: reintroduce original deprecated SceneData APIs. Those now operate on top of the new data layout. --- doc/changelog.dox | 13 +++ src/Magnum/Trade/SceneData.cpp | 62 ++++++++++++ src/Magnum/Trade/SceneData.h | 33 ++++++ src/Magnum/Trade/Test/SceneDataTest.cpp | 129 +++++++++++++++++++++++- 4 files changed, 234 insertions(+), 3 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index db333ca6b..28a708d8e 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -632,6 +632,15 @@ See also: directly but rather generated on-the-fly from attribute data, which makes them less efficient than calling @ref Trade::MaterialData::hasAttribute() etc. +- @ref Trade::SceneData constructor taking a @ref std::vector of 2D and 3D + children is deprecated in favor of the new scene representation. Use + @ref Trade::SceneData::SceneData(SceneObjectType, UnsignedLong, Containers::Array&&, Containers::Array&&, const void*) + instead. +- @cpp Trade::SceneData::children2D() @ce and + @cpp Trade::SceneData::children3D() @ce are deprecated in favor of the + 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. - @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 @@ -805,6 +814,10 @@ See also: @cpp Trade::AbstractMaterialData @ce aliases to, doesn't have a @cpp virtual @ce destructor as subclasses with extra data members aren't a desired use case anymore. +- @ref Trade::SceneData constructor taking a @ref std::vector of 2D and 3D + children that got deprecated in favor of + @ref Trade::SceneData::SceneData(SceneObjectType, UnsignedLong, Containers::Array&&, Containers::Array&&, const void*) + no longer accepts a scene that has both 2D and 3D children. - @ref Trade::AbstractImporter::doDefaultScene() is now @cpp const @ce --- since the function is not expected to fail, no kind of complex lazy population can be done anyway. This is now consistent with `do*Count()` diff --git a/src/Magnum/Trade/SceneData.cpp b/src/Magnum/Trade/SceneData.cpp index 8fa76a42d..b5599796c 100644 --- a/src/Magnum/Trade/SceneData.cpp +++ b/src/Magnum/Trade/SceneData.cpp @@ -39,6 +39,12 @@ #include "Magnum/Math/PackingBatch.h" #include "Magnum/Trade/Implementation/arrayUtilities.h" +#ifdef MAGNUM_BUILD_DEPRECATED +#include +#include +#include +#endif + namespace Magnum { namespace Trade { Debug& operator<<(Debug& debug, const SceneObjectType value) { @@ -580,6 +586,48 @@ SceneData::SceneData(const SceneObjectType objectType, const UnsignedLong object SceneData::SceneData(const SceneObjectType objectType, const UnsignedLong objectCount, const DataFlags dataFlags, const Containers::ArrayView data, const std::initializer_list fields, const void* const importerState): SceneData{objectType, objectCount, dataFlags, data, Implementation::initializerListToArrayWithDefaultDeleter(fields), importerState} {} +#ifdef MAGNUM_BUILD_DEPRECATED +SceneData::SceneData(std::vector children2D, std::vector children3D, const void* const importerState): _dataFlags{DataFlag::Owned|DataFlag::Mutable}, _objectType{SceneObjectType::UnsignedInt}, _importerState{importerState} { + /* Assume nobody ever created a scene with both 2D and 3D children. + (PrimitiveImporter did, but that's an exception and blame goes on me.) + If this blows up for you, please complain. Or rather upgrade to the new + API which ... forces you to have a separate scene for 2D and 3D. But you + can share the data among the two, at least. */ + CORRADE_ASSERT(children2D.empty() || children3D.empty(), + "Trade::SceneData: it's no longer possible to have a scene with both 2D and 3D objects", ); + Containers::ArrayView children; + if(!children2D.empty()) { + _dimensions = 2; + children = children2D; + } else if(!children3D.empty()) { + _dimensions = 3; + children = children3D; + } else _dimensions = 0; + + /* Set object count to the max found child index. It's not great as it + doesn't take any nested object into account but SceneData created this + way is expected to be used only through the deprecated APIs anyway, + which don't care about this value. */ + _objectCount = children.empty() ? 0 : Math::max(children) + 1; + + /* Convert the vector with top-level object IDs to the parent field, where + all have -1 as a parent. This way the (also deprecated) children2D() / + children3D() will return the desired values. */ + Containers::ArrayView objects; + Containers::ArrayView parents; + _data = Containers::ArrayTuple{ + {NoInit, children.size(), objects}, + {NoInit, children.size(), parents}, + }; + _fields = {InPlaceInit, { + SceneFieldData{SceneField::Parent, objects, parents} + }}; + Utility::copy(children, objects); + constexpr Int parent[]{-1}; + Utility::copy(Containers::stridedArrayView(parent).broadcasted<0>(parents.size()), parents); +} +#endif + SceneData::SceneData(SceneData&&) noexcept = default; SceneData::~SceneData() = default; @@ -1932,6 +1980,20 @@ Containers::Optional SceneData::importerStateFor(const UnsignedInt return *importerState; } +#ifdef MAGNUM_BUILD_DEPRECATED +std::vector SceneData::children2D() const { + if(_dimensions != 2) return {}; + const Containers::Array children = childrenFor(-1); + return {children.begin(), children.end()}; +} + +std::vector SceneData::children3D() const { + if(_dimensions != 3) return {}; + const Containers::Array children = childrenFor(-1); + return {children.begin(), children.end()}; +} +#endif + Containers::Array SceneData::releaseFieldData() { Containers::Array out = std::move(_fields); _fields = {}; diff --git a/src/Magnum/Trade/SceneData.h b/src/Magnum/Trade/SceneData.h index 0884eb174..e6e4a4344 100644 --- a/src/Magnum/Trade/SceneData.h +++ b/src/Magnum/Trade/SceneData.h @@ -36,6 +36,11 @@ #include "Magnum/Trade/Trade.h" #include "Magnum/Trade/visibility.h" +#ifdef MAGNUM_BUILD_DEPRECATED +#include +#include +#endif + namespace Magnum { namespace Trade { /** @@ -821,6 +826,18 @@ class MAGNUM_TRADE_EXPORT SceneData { /* Not noexcept because allocation happens inside */ explicit SceneData(SceneObjectType objectType, UnsignedLong objectCount, DataFlags dataFlags, Containers::ArrayView data, std::initializer_list fields, const void* importerState = nullptr); + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief Constructor + * @param children2D Two-dimensional child objects + * @param children3D Three-dimensional child objects + * @param importerState Importer-specific state + * @m_deprecated_since_latest Use @ref SceneData(SceneObjectType, UnsignedLong, Containers::Array&&, Containers::Array&&, const void*) + * instead. + */ + explicit CORRADE_DEPRECATED("use SceneData(SceneObjectType, UnsignedLong, Containers::Array&&, Containers::Array&&, const void*) instead") SceneData(std::vector children2D, std::vector children3D, const void* importerState = nullptr); + #endif + /** @brief Copying is not allowed */ SceneData(const SceneData&) = delete; @@ -2080,6 +2097,22 @@ class MAGNUM_TRADE_EXPORT SceneData { */ Containers::Optional importerStateFor(UnsignedInt object) const; + #ifdef MAGNUM_BUILD_DEPRECATED + /** + * @brief Two-dimensional root scene objects + * @m_deprecated_since_latest Use @ref childrenFor() with `-1` passed + * as the @p object argument. + */ + CORRADE_DEPRECATED("use childrenFor() instead") std::vector children2D() const; + + /** + * @brief Three-dimensional root scene objects + * @m_deprecated_since_latest Use @ref childrenFor() with `-1` passed + * as the @p object argument. + */ + CORRADE_DEPRECATED("use childrenFor() instead") std::vector children3D() const; + #endif + /** * @brief Release field data storage * @m_since_latest diff --git a/src/Magnum/Trade/Test/SceneDataTest.cpp b/src/Magnum/Trade/Test/SceneDataTest.cpp index 95d69eedc..ecf3f3f51 100644 --- a/src/Magnum/Trade/Test/SceneDataTest.cpp +++ b/src/Magnum/Trade/Test/SceneDataTest.cpp @@ -40,6 +40,11 @@ #include "Magnum/Math/Range.h" #include "Magnum/Trade/SceneData.h" +#ifdef MAGNUM_BUILD_DEPRECATED +#include +#include +#endif + namespace Magnum { namespace Trade { namespace Test { namespace { struct SceneDataTest: TestSuite::Tester { @@ -85,8 +90,11 @@ struct SceneDataTest: TestSuite::Tester { void construct(); void constructZeroFields(); void constructZeroObjects(); - void constructNotOwned(); + #ifdef MAGNUM_BUILD_DEPRECATED + void constructDeprecated(); + void constructDeprecatedBoth2DAnd3D(); + #endif void constructDuplicateField(); void constructDuplicateCustomField(); @@ -171,6 +179,10 @@ struct SceneDataTest: TestSuite::Tester { void skinsFor(); void importerStateFor(); + #ifdef MAGNUM_BUILD_DEPRECATED + void childrenDeprecated(); + #endif + void fieldForFieldMissing(); void fieldForInvalidObject(); @@ -198,6 +210,18 @@ const struct { {"offset at the end", 3, 10, 0} }; +#ifdef MAGNUM_BUILD_DEPRECATED +const struct { + const char* name; + bool is2D; + bool is3D; +} ChildrenDeprecatedData[]{ + {"2D", true, false}, + {"3D", false, true}, + {"neither", false, false} +}; +#endif + SceneDataTest::SceneDataTest() { addTests({&SceneDataTest::objectTypeSize, &SceneDataTest::objectTypeSizeInvalid, @@ -243,6 +267,13 @@ SceneDataTest::SceneDataTest() { addInstancedTests({&SceneDataTest::constructNotOwned}, Containers::arraySize(NotOwnedData)); + #ifdef MAGNUM_BUILD_DEPRECATED + addInstancedTests({&SceneDataTest::constructDeprecated}, + Containers::arraySize(ChildrenDeprecatedData)); + + addTests({&SceneDataTest::constructDeprecatedBoth2DAnd3D}); + #endif + addTests({&SceneDataTest::constructDuplicateField, &SceneDataTest::constructDuplicateCustomField, &SceneDataTest::constructInconsistentObjectType, @@ -380,9 +411,14 @@ SceneDataTest::SceneDataTest() { &SceneDataTest::lightsFor, &SceneDataTest::camerasFor, &SceneDataTest::skinsFor, - &SceneDataTest::importerStateFor, + &SceneDataTest::importerStateFor}); + + #ifdef MAGNUM_BUILD_DEPRECATED + addInstancedTests({&SceneDataTest::childrenDeprecated}, + Containers::arraySize(ChildrenDeprecatedData)); + #endif - &SceneDataTest::fieldForFieldMissing, + addTests({&SceneDataTest::fieldForFieldMissing, &SceneDataTest::fieldForInvalidObject, &SceneDataTest::releaseFieldData, @@ -1419,6 +1455,56 @@ void SceneDataTest::constructNotOwned() { CORRADE_COMPARE(scene.mutableField(0)[2], 0); } +#ifdef MAGNUM_BUILD_DEPRECATED +void SceneDataTest::constructDeprecated() { + auto&& data = ChildrenDeprecatedData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + int a; + CORRADE_IGNORE_DEPRECATED_PUSH + SceneData scene{ + data.is2D ? std::vector{5, 17, 36, 22} : std::vector{}, + data.is3D ? std::vector{5, 17, 36, 22} : std::vector{}, + &a}; + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(scene.objectType(), SceneObjectType::UnsignedInt); + if(data.is2D || data.is3D) + CORRADE_COMPARE(scene.objectCount(), 37); + else + CORRADE_COMPARE(scene.objectCount(), 0); + CORRADE_COMPARE(scene.dataFlags(), DataFlag::Mutable|DataFlag::Owned); + CORRADE_COMPARE(scene.importerState(), &a); + CORRADE_COMPARE(scene.fieldCount(), 1); + CORRADE_COMPARE(scene.fieldName(0), SceneField::Parent); + CORRADE_COMPARE(scene.fieldType(0), SceneFieldType::Int); + if(data.is2D || data.is3D) { + CORRADE_COMPARE_AS(scene.objects(0), + Containers::arrayView({5, 17, 36, 22}), + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(scene.field(0), + Containers::arrayView({-1, -1, -1, -1}), + TestSuite::Compare::Container); + } else CORRADE_COMPARE(scene.fieldSize(SceneField::Parent), 0); + /* There's no transformation field that would disambiguate this, the state + is set directly */ + CORRADE_COMPARE(scene.is2D(), data.is2D); + CORRADE_COMPARE(scene.is3D(), data.is3D); +} + +void SceneDataTest::constructDeprecatedBoth2DAnd3D() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + std::ostringstream out; + Error redirectError{&out}; + CORRADE_IGNORE_DEPRECATED_PUSH + SceneData scene{{5, 17}, {36, 22}}; + CORRADE_IGNORE_DEPRECATED_POP + CORRADE_COMPARE(out.str(), "Trade::SceneData: it's no longer possible to have a scene with both 2D and 3D objects\n"); +} +#endif + void SceneDataTest::constructDuplicateField() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); @@ -4695,6 +4781,43 @@ void SceneDataTest::importerStateFor() { CORRADE_COMPARE(scene.importerStateFor(1), Containers::NullOpt); } +#ifdef MAGNUM_BUILD_DEPRECATED +void SceneDataTest::childrenDeprecated() { + auto&& data = ChildrenDeprecatedData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + struct Field { + UnsignedByte object; + Short parent; + } fields[]{ + {5, -1}, + {2, 0}, + {3, 0}, + {0, -1}, + {1, 2}, + {4, -1} + }; + Containers::StridedArrayView1D view = fields; + + Containers::Array fieldData; + arrayAppend(fieldData, SceneFieldData{SceneField::Parent, view.slice(&Field::object), view.slice(&Field::parent)}); + if(data.is2D) + arrayAppend(fieldData, SceneFieldData{SceneField::Translation, SceneObjectType::UnsignedByte, nullptr, SceneFieldType::Vector2, nullptr}); + if(data.is3D) + arrayAppend(fieldData, SceneFieldData{SceneField::Translation, SceneObjectType::UnsignedByte, nullptr, SceneFieldType::Vector3, nullptr}); + + SceneData scene{SceneObjectType::UnsignedByte, 25, {}, fields, std::move(fieldData)}; + CORRADE_IGNORE_DEPRECATED_PUSH + CORRADE_COMPARE_AS(scene.children2D(), + (data.is2D ? std::vector{5, 0, 4} : std::vector{}), + TestSuite::Compare::Container); + CORRADE_COMPARE_AS(scene.children3D(), + (data.is3D ? std::vector{5, 0, 4} : std::vector{}), + TestSuite::Compare::Container); + CORRADE_IGNORE_DEPRECATED_POP +} +#endif + void SceneDataTest::fieldForFieldMissing() { SceneData scene{SceneObjectType::UnsignedInt, 7, nullptr, {}};