From 79b3dade228870537018084081d562aa9d70ed00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 4 Nov 2019 19:58:55 +0100 Subject: [PATCH] New MeshAttributeType enum. Not yet sure if I should follow the PixelFormat naming or not. Maybe will change this later. --- doc/changelog.dox | 2 + src/Magnum/CMakeLists.txt | 1 + .../meshAttributeTypeMapping.hpp | 32 +++++++ src/Magnum/Magnum.h | 1 + src/Magnum/Mesh.cpp | 44 +++++++++ src/Magnum/Mesh.h | 55 +++++++++++ src/Magnum/Test/MeshTest.cpp | 91 +++++++++++++++++++ 7 files changed, 226 insertions(+) create mode 100644 src/Magnum/Implementation/meshAttributeTypeMapping.hpp diff --git a/doc/changelog.dox b/doc/changelog.dox index 21aa00928f..3286f69f72 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -40,6 +40,8 @@ See also: @subsection changelog-latest-new New features +- New @ref MeshAttributeType enum for mesh attribute types + @subsubsection changelog-latest-new-gl GL library - Exposed entry points from the desktop / ES @gl_extension{OVR,multiview} and diff --git a/src/Magnum/CMakeLists.txt b/src/Magnum/CMakeLists.txt index a0c9a3b0e7..061eac2982 100644 --- a/src/Magnum/CMakeLists.txt +++ b/src/Magnum/CMakeLists.txt @@ -66,6 +66,7 @@ set(Magnum_HEADERS set(Magnum_PRIVATE_HEADERS Implementation/ImageProperties.h + Implementation/meshAttributeTypeMapping.hpp Implementation/meshIndexTypeMapping.hpp Implementation/meshPrimitiveMapping.hpp Implementation/compressedPixelFormatMapping.hpp diff --git a/src/Magnum/Implementation/meshAttributeTypeMapping.hpp b/src/Magnum/Implementation/meshAttributeTypeMapping.hpp new file mode 100644 index 0000000000..5c24b07a22 --- /dev/null +++ b/src/Magnum/Implementation/meshAttributeTypeMapping.hpp @@ -0,0 +1,32 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/* Each entry is just the name, for debug output and configuration to string */ +#ifdef _c +_c(Vector2) +_c(Vector3) +_c(Vector4) +#endif + diff --git a/src/Magnum/Magnum.h b/src/Magnum/Magnum.h index 5612dca26a..2d45e55fff 100644 --- a/src/Magnum/Magnum.h +++ b/src/Magnum/Magnum.h @@ -736,6 +736,7 @@ typedef BasicMutableCompressedImageView<2> MutableCompressedImageView2D; typedef BasicMutableCompressedImageView<3> MutableCompressedImageView3D; enum class MeshPrimitive: UnsignedInt; +enum class MeshAttributeType: UnsignedInt; enum class MeshIndexType: UnsignedInt; enum class PixelFormat: UnsignedInt; diff --git a/src/Magnum/Mesh.cpp b/src/Magnum/Mesh.cpp index 65fa64b111..be695e1028 100644 --- a/src/Magnum/Mesh.cpp +++ b/src/Magnum/Mesh.cpp @@ -32,6 +32,16 @@ namespace Magnum { +UnsignedInt meshAttributeTypeSize(MeshAttributeType type) { + switch(type) { + case MeshAttributeType::Vector2: return 8; + case MeshAttributeType::Vector3: return 12; + case MeshAttributeType::Vector4: return 16; + } + + CORRADE_ASSERT(false, "meshAttributeTypeSize(): invalid type" << type, {}); +} + UnsignedInt meshIndexTypeSize(MeshIndexType type) { switch(type) { case MeshIndexType::UnsignedByte: return 1; @@ -65,6 +75,26 @@ Debug& operator<<(Debug& debug, const MeshPrimitive value) { namespace { +constexpr const char* MeshAttributeTypeNames[] { + #define _c(type) #type, + #include "Magnum/Implementation/meshAttributeTypeMapping.hpp" + #undef _c +}; + +} + +Debug& operator<<(Debug& debug, const MeshAttributeType value) { + debug << "MeshAttributeType" << Debug::nospace; + + if(UnsignedInt(value) - 1 < Containers::arraySize(MeshAttributeTypeNames)) { + return debug << "::" << Debug::nospace << MeshAttributeTypeNames[UnsignedInt(value) - 1]; + } + + return debug << "(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; +} + +namespace { + constexpr const char* MeshIndexTypeNames[] { #define _c(type) #type, #include "Magnum/Implementation/meshIndexTypeMapping.hpp" @@ -102,6 +132,20 @@ Magnum::MeshPrimitive ConfigurationValue::fromString(cons return {}; } +std::string ConfigurationValue::toString(Magnum::MeshAttributeType value, ConfigurationValueFlags) { + if(Magnum::UnsignedInt(value) - 1 < Containers::arraySize(Magnum::MeshAttributeTypeNames)) + return Magnum::MeshAttributeTypeNames[Magnum::UnsignedInt(value) - 1]; + + return {}; +} + +Magnum::MeshAttributeType ConfigurationValue::fromString(const std::string& stringValue, ConfigurationValueFlags) { + for(std::size_t i = 0; i != Containers::arraySize(Magnum::MeshAttributeTypeNames); ++i) + if(stringValue == Magnum::MeshAttributeTypeNames[i]) return Magnum::MeshAttributeType(i + 1); + + return {}; +} + std::string ConfigurationValue::toString(Magnum::MeshIndexType value, ConfigurationValueFlags) { if(Magnum::UnsignedInt(value) - 1 < Containers::arraySize(Magnum::MeshIndexTypeNames)) return Magnum::MeshIndexTypeNames[Magnum::UnsignedInt(value) - 1]; diff --git a/src/Magnum/Mesh.h b/src/Magnum/Mesh.h index 96b0b6ba32..d937c8f79c 100644 --- a/src/Magnum/Mesh.h +++ b/src/Magnum/Mesh.h @@ -115,6 +115,42 @@ enum class MeshPrimitive: UnsignedInt { /** @debugoperatorenum{MeshPrimitive} */ MAGNUM_EXPORT Debug& operator<<(Debug& debug, MeshPrimitive value); +/** +@brief Mesh attribute type + +Like @ref PixelFormat, but for mesh attributes --- including double-precision +types and matrices. +@see @ref Trade::MeshData, @ref Trade::MeshAttributeData, + @ref Trade::MeshAttributeName +*/ +enum class MeshAttributeType: UnsignedInt { + /* Zero reserved for an invalid type (but not being a named value) */ + + /** + * @ref Magnum::Vector2 "Vector2". Usually used for 2D positions and 2D + * texture coordinates. + */ + Vector2 = 1, + + /** + * @ref Magnum::Vector3 "Vector3" or @ref Magnum::Color3 "Color3". Usually + * used for 3D positions, normals and three-component colors. + */ + Vector3, + + /** + * @ref Magnum::Vector4 "Vector4" or @ref Magnum::Color4 "Color4". Usually + * used for four-component colors. + */ + Vector4 +}; + +/** @brief Size of given mesh attribute type */ +MAGNUM_EXPORT UnsignedInt meshAttributeTypeSize(MeshAttributeType type); + +/** @debugoperatorenum{MeshAttributeType} */ +MAGNUM_EXPORT Debug& operator<<(Debug& debug, MeshAttributeType value); + /** @brief Mesh index type @@ -185,6 +221,25 @@ template<> struct MAGNUM_EXPORT ConfigurationValue { static Magnum::MeshPrimitive fromString(const std::string& stringValue, ConfigurationValueFlags); }; +/** @configurationvalue{Magnum::MeshAttributeType} */ +template<> struct MAGNUM_EXPORT ConfigurationValue { + ConfigurationValue() = delete; + + /** + * @brief Write enum value as string + * + * If the value is invalid, returns empty string. + */ + static std::string toString(Magnum::MeshAttributeType value, ConfigurationValueFlags); + + /** + * @brief Read enum value as string + * + * If the value is invalid, returns a zero (invalid) type. + */ + static Magnum::MeshAttributeType fromString(const std::string& stringValue, ConfigurationValueFlags); +}; + /** @configurationvalue{Magnum::MeshIndexType} */ template<> struct MAGNUM_EXPORT ConfigurationValue { ConfigurationValue() = delete; diff --git a/src/Magnum/Test/MeshTest.cpp b/src/Magnum/Test/MeshTest.cpp index da17fa98f4..43b90bef9f 100644 --- a/src/Magnum/Test/MeshTest.cpp +++ b/src/Magnum/Test/MeshTest.cpp @@ -29,6 +29,7 @@ #include #include "Magnum/Mesh.h" +#include "Magnum/Math/Vector4.h" namespace Magnum { namespace Test { namespace { @@ -36,27 +37,39 @@ struct MeshTest: TestSuite::Tester { explicit MeshTest(); void primitiveMapping(); + void attributeTypeMapping(); void indexTypeMapping(); + void attributeTypeSize(); + void attributeTypeSizeInvalid(); void indexTypeSize(); void indexTypeSizeInvalid(); void debugPrimitive(); + void debugAttributeType(); void debugIndexType(); + void configurationPrimitive(); + void configurationAttributeType(); void configurationIndexType(); }; MeshTest::MeshTest() { addTests({&MeshTest::primitiveMapping, + &MeshTest::attributeTypeMapping, &MeshTest::indexTypeMapping, + &MeshTest::attributeTypeSize, + &MeshTest::attributeTypeSizeInvalid, &MeshTest::indexTypeSize, &MeshTest::indexTypeSizeInvalid, &MeshTest::debugPrimitive, + &MeshTest::debugAttributeType, &MeshTest::debugIndexType, + &MeshTest::configurationPrimitive, + &MeshTest::configurationAttributeType, &MeshTest::configurationIndexType}); } @@ -97,6 +110,44 @@ void MeshTest::primitiveMapping() { CORRADE_COMPARE(firstUnhandled, 0xff); } +void MeshTest::attributeTypeMapping() { + /* This goes through the first 16 bits, which should be enough. Going + through 32 bits takes 8 seconds, too much. */ + UnsignedInt firstUnhandled = 0xffff; + UnsignedInt nextHandled = 1; /* 0 is an invalid type */ + for(UnsignedInt i = 1; i <= 0xffff; ++i) { + const auto type = MeshAttributeType(i); + /* Each case verifies: + - that the cases are ordered by number (so insertion here is done in + proper place) + - that there was no gap (unhandled value inside the range) */ + #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic error "-Wswitch" + #endif + switch(type) { + #define _c(type) \ + case MeshAttributeType::type: \ + CORRADE_COMPARE(nextHandled, i); \ + CORRADE_COMPARE(firstUnhandled, 0xffff); \ + ++nextHandled; \ + continue; + #include "Magnum/Implementation/meshAttributeTypeMapping.hpp" + #undef _c + } + #ifdef __GNUC__ + #pragma GCC diagnostic pop + #endif + + /* Not handled by any value, remember -- we might either be at the end + of the enum range (which is okay) or some value might be unhandled + here */ + firstUnhandled = i; + } + + CORRADE_COMPARE(firstUnhandled, 0xffff); +} + void MeshTest::indexTypeMapping() { /* This goes through the first 8 bits, which should be enough. */ UnsignedInt firstUnhandled = 0xff; @@ -134,6 +185,24 @@ void MeshTest::indexTypeMapping() { CORRADE_COMPARE(firstUnhandled, 0xff); } +void MeshTest::attributeTypeSize() { + CORRADE_COMPARE(meshAttributeTypeSize(MeshAttributeType::Vector2), sizeof(Vector2)); + CORRADE_COMPARE(meshAttributeTypeSize(MeshAttributeType::Vector3), sizeof(Vector3)); + CORRADE_COMPARE(meshAttributeTypeSize(MeshAttributeType::Vector4), sizeof(Vector4)); +} + +void MeshTest::attributeTypeSizeInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + meshAttributeTypeSize(MeshAttributeType{}); + meshAttributeTypeSize(MeshAttributeType(0xdead)); + + CORRADE_COMPARE(out.str(), + "meshAttributeTypeSize(): invalid type MeshAttributeType(0x0)\n" + "meshAttributeTypeSize(): invalid type MeshAttributeType(0xdead)\n"); +} + void MeshTest::indexTypeSize() { CORRADE_COMPARE(meshIndexTypeSize(MeshIndexType::UnsignedByte), 1); CORRADE_COMPARE(meshIndexTypeSize(MeshIndexType::UnsignedShort), 2); @@ -158,6 +227,12 @@ void MeshTest::debugPrimitive() { CORRADE_COMPARE(o.str(), "MeshPrimitive::TriangleFan MeshPrimitive(0xdead)\n"); } +void MeshTest::debugAttributeType() { + std::ostringstream o; + Debug(&o) << MeshAttributeType::Vector4 << MeshAttributeType(0xdead); + CORRADE_COMPARE(o.str(), "MeshAttributeType::Vector4 MeshAttributeType(0xdead)\n"); +} + void MeshTest::debugIndexType() { std::ostringstream o; Debug(&o) << MeshIndexType::UnsignedShort << MeshIndexType(0xdead); @@ -180,6 +255,22 @@ void MeshTest::configurationPrimitive() { CORRADE_COMPARE(c.value("invalid"), MeshPrimitive{}); } +void MeshTest::configurationAttributeType() { + Utility::Configuration c; + + c.setValue("type", MeshAttributeType::Vector3); + CORRADE_COMPARE(c.value("type"), "Vector3"); + CORRADE_COMPARE(c.value("type"), MeshAttributeType::Vector3); + + c.setValue("zero", MeshAttributeType{}); + CORRADE_COMPARE(c.value("zero"), ""); + CORRADE_COMPARE(c.value("zero"), MeshAttributeType{}); + + c.setValue("invalid", MeshAttributeType(0xdead)); + CORRADE_COMPARE(c.value("invalid"), ""); + CORRADE_COMPARE(c.value("invalid"), MeshAttributeType{}); +} + void MeshTest::configurationIndexType() { Utility::Configuration c;