From e858ab2dd85c27150d3114e064392719a5ab7dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 11 Oct 2021 19:29:24 +0200 Subject: [PATCH] Trade: add scene{Object,Field}TypeAlignment(). Support utilities needed for SceneTools that will operate on arbitrary SceneData (adding/removing fields, objects...) without having to know what each field means and how it needs to be treated. Honestly the same would make sense for the VertexFormat enum as well. But not now, later. --- src/Magnum/Trade/SceneData.cpp | 130 ++++++++++++++++++++++++ src/Magnum/Trade/SceneData.h | 28 ++++- src/Magnum/Trade/Test/SceneDataTest.cpp | 47 ++++++--- 3 files changed, 188 insertions(+), 17 deletions(-) diff --git a/src/Magnum/Trade/SceneData.cpp b/src/Magnum/Trade/SceneData.cpp index b5599796c..cc83bb710 100644 --- a/src/Magnum/Trade/SceneData.cpp +++ b/src/Magnum/Trade/SceneData.cpp @@ -82,6 +82,24 @@ UnsignedInt sceneObjectTypeSize(const SceneObjectType type) { CORRADE_ASSERT_UNREACHABLE("Trade::sceneObjectTypeSize(): invalid type" << type, {}); } +UnsignedInt sceneObjectTypeAlignment(const SceneObjectType type) { + #ifdef CORRADE_TARGET_GCC + #pragma GCC diagnostic push + #pragma GCC diagnostic error "-Wswitch" + #endif + switch(type) { + case SceneObjectType::UnsignedByte: return 1; + case SceneObjectType::UnsignedShort: return 2; + case SceneObjectType::UnsignedInt: return 4; + case SceneObjectType::UnsignedLong: return 8; + } + #ifdef CORRADE_TARGET_GCC + #pragma GCC diagnostic pop + #endif + + CORRADE_ASSERT_UNREACHABLE("Trade::sceneObjectTypeAlignment(): invalid type" << type, {}); +} + Debug& operator<<(Debug& debug, const SceneField value) { debug << "Trade::SceneField" << Debug::nospace; @@ -343,6 +361,118 @@ UnsignedInt sceneFieldTypeSize(const SceneFieldType type) { CORRADE_ASSERT_UNREACHABLE("Trade::sceneFieldTypeSize(): invalid type" << type, {}); } +UnsignedInt sceneFieldTypeAlignment(const SceneFieldType type) { + #ifdef CORRADE_TARGET_GCC + #pragma GCC diagnostic push + #pragma GCC diagnostic error "-Wswitch" + #endif + switch(type) { + case SceneFieldType::UnsignedByte: + case SceneFieldType::Vector2ub: + case SceneFieldType::Vector3ub: + case SceneFieldType::Vector4ub: + case SceneFieldType::Byte: + case SceneFieldType::Vector2b: + case SceneFieldType::Vector3b: + case SceneFieldType::Vector4b: + return 1; + case SceneFieldType::UnsignedShort: + case SceneFieldType::Vector2us: + case SceneFieldType::Vector3us: + case SceneFieldType::Vector4us: + case SceneFieldType::Short: + case SceneFieldType::Vector2s: + case SceneFieldType::Vector3s: + case SceneFieldType::Vector4s: + case SceneFieldType::Half: + case SceneFieldType::Vector2h: + case SceneFieldType::Vector3h: + case SceneFieldType::Vector4h: + case SceneFieldType::Matrix2x2h: + case SceneFieldType::Matrix2x3h: + case SceneFieldType::Matrix2x4h: + case SceneFieldType::Matrix3x2h: + case SceneFieldType::Matrix3x3h: + case SceneFieldType::Matrix3x4h: + case SceneFieldType::Matrix4x2h: + case SceneFieldType::Matrix4x3h: + case SceneFieldType::Matrix4x4h: + case SceneFieldType::Range1Dh: + case SceneFieldType::Range2Dh: + case SceneFieldType::Range3Dh: + case SceneFieldType::Degh: + case SceneFieldType::Radh: + return 2; + case SceneFieldType::UnsignedInt: + case SceneFieldType::Vector2ui: + case SceneFieldType::Vector3ui: + case SceneFieldType::Vector4ui: + case SceneFieldType::Int: + case SceneFieldType::Vector2i: + case SceneFieldType::Vector3i: + case SceneFieldType::Vector4i: + case SceneFieldType::Float: + case SceneFieldType::Vector2: + case SceneFieldType::Vector3: + case SceneFieldType::Vector4: + case SceneFieldType::Matrix2x2: + case SceneFieldType::Matrix2x3: + case SceneFieldType::Matrix2x4: + case SceneFieldType::Matrix3x2: + case SceneFieldType::Matrix3x3: + case SceneFieldType::Matrix3x4: + case SceneFieldType::Matrix4x2: + case SceneFieldType::Matrix4x3: + case SceneFieldType::Matrix4x4: + case SceneFieldType::Range1Di: + case SceneFieldType::Range2Di: + case SceneFieldType::Range3Di: + case SceneFieldType::Range1D: + case SceneFieldType::Range2D: + case SceneFieldType::Range3D: + case SceneFieldType::Complex: + case SceneFieldType::Quaternion: + case SceneFieldType::DualComplex: + case SceneFieldType::DualQuaternion: + case SceneFieldType::Deg: + case SceneFieldType::Rad: + return 4; + case SceneFieldType::UnsignedLong: + case SceneFieldType::Long: + case SceneFieldType::Double: + case SceneFieldType::Vector2d: + case SceneFieldType::Vector3d: + case SceneFieldType::Vector4d: + case SceneFieldType::Matrix2x2d: + case SceneFieldType::Matrix2x3d: + case SceneFieldType::Matrix2x4d: + case SceneFieldType::Matrix3x2d: + case SceneFieldType::Matrix3x3d: + case SceneFieldType::Matrix3x4d: + case SceneFieldType::Matrix4x2d: + case SceneFieldType::Matrix4x3d: + case SceneFieldType::Matrix4x4d: + case SceneFieldType::Range1Dd: + case SceneFieldType::Range2Dd: + case SceneFieldType::Range3Dd: + case SceneFieldType::Complexd: + case SceneFieldType::Quaterniond: + case SceneFieldType::DualComplexd: + case SceneFieldType::DualQuaterniond: + case SceneFieldType::Degd: + case SceneFieldType::Radd: + return 8; + case SceneFieldType::Pointer: + case SceneFieldType::MutablePointer: + return sizeof(void*); + } + #ifdef CORRADE_TARGET_GCC + #pragma GCC diagnostic pop + #endif + + CORRADE_ASSERT_UNREACHABLE("Trade::sceneFieldTypeAlignment(): invalid type" << type, {}); +} + SceneFieldData::SceneFieldData(const SceneField name, const Containers::StridedArrayView2D& objectData, const SceneFieldType fieldType, const Containers::StridedArrayView2D& fieldData, const UnsignedShort fieldArraySize) noexcept: SceneFieldData{name, {}, Containers::StridedArrayView1D{{objectData.data(), ~std::size_t{}}, objectData.size()[0], objectData.stride()[0]}, fieldType, Containers::StridedArrayView1D{{fieldData.data(), ~std::size_t{}}, fieldData.size()[0], fieldData.stride()[0]}, fieldArraySize} { /* Yes, this calls into a constexpr function defined in the header -- because I feel that makes more sense than duplicating the full assert diff --git a/src/Magnum/Trade/SceneData.h b/src/Magnum/Trade/SceneData.h index e6e4a4344..a3f825854 100644 --- a/src/Magnum/Trade/SceneData.h +++ b/src/Magnum/Trade/SceneData.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class @ref Magnum::Trade::SceneData, @ref Magnum::Trade::SceneFieldData, enum @ref Magnum::Trade::SceneObjectType, @ref Magnum::Trade::SceneField, @ref Magnum::Trade::SceneFieldType, function @ref Magnum::sceneObjectTypeSize(), @ref Magnum::sceneFieldTypeSize(), @ref Magnum::Trade::isSceneFieldCustom(), @ref Magnum::sceneFieldCustom() + * @brief Class @ref Magnum::Trade::SceneData, @ref Magnum::Trade::SceneFieldData, enum @ref Magnum::Trade::SceneObjectType, @ref Magnum::Trade::SceneField, @ref Magnum::Trade::SceneFieldType, function @ref Magnum::sceneObjectTypeSize(), @ref Magnum::sceneObjectTypeAlignment(), @ref Magnum::sceneFieldTypeSize(), @ref Magnum::sceneFieldTypeAlignment(), @ref Magnum::Trade::isSceneFieldCustom(), @ref Magnum::sceneFieldCustom() */ #include @@ -51,7 +51,8 @@ Type used for mapping fields to corresponding objects. Unlike @ref SceneFieldType that is different for different fields, the object type is the same for all fields, and is guaranteed to be large enough to fit all @ref SceneData::objectCount() objects. -@see @ref SceneData::objectType(), @ref sceneObjectTypeSize() +@see @ref SceneData::objectType(), @ref sceneObjectTypeSize(), + @ref sceneObjectTypeAlignment() */ enum class SceneObjectType: UnsignedByte { /* Zero used for an invalid value */ @@ -80,9 +81,19 @@ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, SceneObjectType value); /** @brief Size of given scene object type @m_since_latest + +@see @ref sceneObjectTypeAlignment() */ MAGNUM_TRADE_EXPORT UnsignedInt sceneObjectTypeSize(SceneObjectType type); +/** +@brief Alignment of given scene object type +@m_since_latest + +Returns the same value as @ref sceneObjectTypeSize(). +*/ +MAGNUM_TRADE_EXPORT UnsignedInt sceneObjectTypeAlignment(SceneObjectType type); + /** @brief Scene field name @m_since_latest @@ -368,7 +379,8 @@ constexpr UnsignedInt sceneFieldCustom(SceneField name) { A type in which a @ref SceneField is stored. See @ref SceneData for more information. -@see @ref SceneFieldData, @ref sceneFieldTypeSize() +@see @ref SceneFieldData, @ref sceneFieldTypeSize(), + @ref sceneFieldTypeAlignment() */ enum class SceneFieldType: UnsignedShort { /* Zero used for an invalid value */ @@ -509,9 +521,19 @@ MAGNUM_TRADE_EXPORT Debug& operator<<(Debug& debug, SceneFieldType value); /** @brief Size of given scene field type @m_since_latest + +@see @ref sceneFieldTypeAlignment() */ MAGNUM_TRADE_EXPORT UnsignedInt sceneFieldTypeSize(SceneFieldType type); +/** +@brief Alignment of given scene field type +@m_since_latest + +@see @ref sceneFieldTypeSize() +*/ +MAGNUM_TRADE_EXPORT UnsignedInt sceneFieldTypeAlignment(SceneFieldType type); + /** @brief Scene field data @m_since_latest diff --git a/src/Magnum/Trade/Test/SceneDataTest.cpp b/src/Magnum/Trade/Test/SceneDataTest.cpp index ecf3f3f51..e990ccf65 100644 --- a/src/Magnum/Trade/Test/SceneDataTest.cpp +++ b/src/Magnum/Trade/Test/SceneDataTest.cpp @@ -50,8 +50,8 @@ namespace Magnum { namespace Trade { namespace Test { namespace { struct SceneDataTest: TestSuite::Tester { explicit SceneDataTest(); - void objectTypeSize(); - void objectTypeSizeInvalid(); + void objectTypeSizeAlignment(); + void objectTypeSizeAlignmentInvalid(); void debugObjectType(); void customFieldName(); @@ -59,8 +59,8 @@ struct SceneDataTest: TestSuite::Tester { void customFieldNameNotCustom(); void debugFieldName(); - void fieldTypeSize(); - void fieldTypeSizeInvalid(); + void fieldTypeSizeAlignment(); + void fieldTypeSizeAlignmentInvalid(); void debugFieldType(); void constructField(); @@ -223,8 +223,8 @@ const struct { #endif SceneDataTest::SceneDataTest() { - addTests({&SceneDataTest::objectTypeSize, - &SceneDataTest::objectTypeSizeInvalid, + addTests({&SceneDataTest::objectTypeSizeAlignment, + &SceneDataTest::objectTypeSizeAlignmentInvalid, &SceneDataTest::debugObjectType, &SceneDataTest::customFieldName, @@ -232,8 +232,8 @@ SceneDataTest::SceneDataTest() { &SceneDataTest::customFieldNameNotCustom, &SceneDataTest::debugFieldName, - &SceneDataTest::fieldTypeSize, - &SceneDataTest::fieldTypeSizeInvalid, + &SceneDataTest::fieldTypeSizeAlignment, + &SceneDataTest::fieldTypeSizeAlignmentInvalid, &SceneDataTest::debugFieldType, &SceneDataTest::constructField, @@ -427,14 +427,18 @@ SceneDataTest::SceneDataTest() { using namespace Math::Literals; -void SceneDataTest::objectTypeSize() { +void SceneDataTest::objectTypeSizeAlignment() { CORRADE_COMPARE(sceneObjectTypeSize(SceneObjectType::UnsignedByte), 1); + CORRADE_COMPARE(sceneObjectTypeAlignment(SceneObjectType::UnsignedByte), 1); CORRADE_COMPARE(sceneObjectTypeSize(SceneObjectType::UnsignedShort), 2); + CORRADE_COMPARE(sceneObjectTypeAlignment(SceneObjectType::UnsignedShort), 2); CORRADE_COMPARE(sceneObjectTypeSize(SceneObjectType::UnsignedInt), 4); + CORRADE_COMPARE(sceneObjectTypeAlignment(SceneObjectType::UnsignedInt), 4); CORRADE_COMPARE(sceneObjectTypeSize(SceneObjectType::UnsignedLong), 8); + CORRADE_COMPARE(sceneObjectTypeAlignment(SceneObjectType::UnsignedLong), 8); } -void SceneDataTest::objectTypeSizeInvalid() { +void SceneDataTest::objectTypeSizeAlignmentInvalid() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif @@ -443,11 +447,15 @@ void SceneDataTest::objectTypeSizeInvalid() { Error redirectError{&out}; sceneObjectTypeSize(SceneObjectType{}); + sceneObjectTypeAlignment(SceneObjectType{}); sceneObjectTypeSize(SceneObjectType(0x73)); + sceneObjectTypeAlignment(SceneObjectType(0x73)); CORRADE_COMPARE(out.str(), "Trade::sceneObjectTypeSize(): invalid type Trade::SceneObjectType(0x0)\n" - "Trade::sceneObjectTypeSize(): invalid type Trade::SceneObjectType(0x73)\n"); + "Trade::sceneObjectTypeAlignment(): invalid type Trade::SceneObjectType(0x0)\n" + "Trade::sceneObjectTypeSize(): invalid type Trade::SceneObjectType(0x73)\n" + "Trade::sceneObjectTypeAlignment(): invalid type Trade::SceneObjectType(0x73)\n"); } void SceneDataTest::debugObjectType() { @@ -506,7 +514,7 @@ void SceneDataTest::debugFieldName() { CORRADE_COMPARE(out.str(), "Trade::SceneField::Transformation Trade::SceneField::Custom(73) Trade::SceneField(0xdeadda7)\n"); } -void SceneDataTest::fieldTypeSize() { +void SceneDataTest::fieldTypeSizeAlignment() { /* Test at least one of every size */ CORRADE_COMPARE(sceneFieldTypeSize(SceneFieldType::Byte), sizeof(Byte)); CORRADE_COMPARE(sceneFieldTypeSize(SceneFieldType::Degh), sizeof(Degh)); @@ -526,9 +534,16 @@ void SceneDataTest::fieldTypeSize() { CORRADE_COMPARE(sceneFieldTypeSize(SceneFieldType::Matrix3x4d), sizeof(Matrix3x4d)); CORRADE_COMPARE(sceneFieldTypeSize(SceneFieldType::Matrix4x4d), sizeof(Matrix4x4d)); CORRADE_COMPARE(sceneFieldTypeSize(SceneFieldType::Pointer), sizeof(const void*)); + + /* Test at least one of every alignment */ + CORRADE_COMPARE(sceneFieldTypeAlignment(SceneFieldType::Vector3ub), alignof(UnsignedByte)); + CORRADE_COMPARE(sceneFieldTypeAlignment(SceneFieldType::Matrix3x3h), alignof(Half)); + CORRADE_COMPARE(sceneFieldTypeAlignment(SceneFieldType::Range3Di), alignof(UnsignedInt)); + CORRADE_COMPARE(sceneFieldTypeAlignment(SceneFieldType::DualComplexd), alignof(Double)); + CORRADE_COMPARE(sceneFieldTypeAlignment(SceneFieldType::Pointer), alignof(const void*)); } -void SceneDataTest::fieldTypeSizeInvalid() { +void SceneDataTest::fieldTypeSizeAlignmentInvalid() { #ifdef CORRADE_NO_ASSERT CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); #endif @@ -537,11 +552,15 @@ void SceneDataTest::fieldTypeSizeInvalid() { Error redirectError{&out}; sceneFieldTypeSize(SceneFieldType{}); + sceneFieldTypeAlignment(SceneFieldType{}); sceneFieldTypeSize(SceneFieldType(0xdead)); + sceneFieldTypeAlignment(SceneFieldType(0xdead)); CORRADE_COMPARE(out.str(), "Trade::sceneFieldTypeSize(): invalid type Trade::SceneFieldType(0x0)\n" - "Trade::sceneFieldTypeSize(): invalid type Trade::SceneFieldType(0xdead)\n"); + "Trade::sceneFieldTypeAlignment(): invalid type Trade::SceneFieldType(0x0)\n" + "Trade::sceneFieldTypeSize(): invalid type Trade::SceneFieldType(0xdead)\n" + "Trade::sceneFieldTypeAlignment(): invalid type Trade::SceneFieldType(0xdead)\n"); } void SceneDataTest::debugFieldType() {