diff --git a/src/Magnum/Implementation/vertexFormatMapping.hpp b/src/Magnum/Implementation/vertexFormatMapping.hpp index 405eaa1be..2b2dc2b45 100644 --- a/src/Magnum/Implementation/vertexFormatMapping.hpp +++ b/src/Magnum/Implementation/vertexFormatMapping.hpp @@ -26,13 +26,55 @@ /* Each entry is just the name, for debug output and configuration to string */ #ifdef _c _c(Float) +_c(Half) +_c(Double) _c(UnsignedByte) +_c(UnsignedByteNormalized) _c(Byte) +_c(ByteNormalized) _c(UnsignedShort) +_c(UnsignedShortNormalized) _c(Short) +_c(ShortNormalized) _c(UnsignedInt) _c(Int) _c(Vector2) +_c(Vector2h) +_c(Vector2d) +_c(Vector2ub) +_c(Vector2ubNormalized) +_c(Vector2b) +_c(Vector2bNormalized) +_c(Vector2us) +_c(Vector2usNormalized) +_c(Vector2s) +_c(Vector2sNormalized) +_c(Vector2ui) +_c(Vector2i) _c(Vector3) +_c(Vector3h) +_c(Vector3d) +_c(Vector3ub) +_c(Vector3ubNormalized) +_c(Vector3b) +_c(Vector3bNormalized) +_c(Vector3us) +_c(Vector3usNormalized) +_c(Vector3s) +_c(Vector3sNormalized) +_c(Vector3ui) +_c(Vector3i) _c(Vector4) +_c(Vector4h) +_c(Vector4d) +_c(Vector4ub) +_c(Vector4ubNormalized) +_c(Vector4b) +_c(Vector4bNormalized) +_c(Vector4us) +_c(Vector4usNormalized) +_c(Vector4s) +_c(Vector4sNormalized) +_c(Vector4ui) +_c(Vector4i) #endif diff --git a/src/Magnum/Test/VertexFormatTest.cpp b/src/Magnum/Test/VertexFormatTest.cpp index a95fef885..635225c92 100644 --- a/src/Magnum/Test/VertexFormatTest.cpp +++ b/src/Magnum/Test/VertexFormatTest.cpp @@ -40,16 +40,59 @@ struct VertexFormatTest: TestSuite::Tester { void size(); void sizeInvalid(); + void componentCount(); + void componentCountInvalid(); + void componentFormat(); + void componentFormatInvalid(); + void isNormalized(); + void isNormalizedInvalid(); + + void assemble(); + void assembleRoundtrip(); + void assembleCantNormalize(); + void assembleInvalidComponentCount(); void debug(); void configuration(); }; +constexpr struct { + VertexFormat componentType; + bool normalized; +} CombineRoundtripData[] { + {VertexFormat::Float, false}, + {VertexFormat::Double, false}, + {VertexFormat::UnsignedByte, false}, + {VertexFormat::UnsignedByte, true}, + {VertexFormat::Byte, false}, + {VertexFormat::Byte, true}, + {VertexFormat::UnsignedShort, false}, + {VertexFormat::UnsignedShort, true}, + {VertexFormat::Short, false}, + {VertexFormat::Short, true}, + {VertexFormat::UnsignedInt, false}, + {VertexFormat::Int, false} +}; + VertexFormatTest::VertexFormatTest() { addTests({&VertexFormatTest::mapping, &VertexFormatTest::size, &VertexFormatTest::sizeInvalid, + &VertexFormatTest::componentCount, + &VertexFormatTest::componentCountInvalid, + &VertexFormatTest::componentFormat, + &VertexFormatTest::componentFormatInvalid, + &VertexFormatTest::isNormalized, + &VertexFormatTest::isNormalizedInvalid, + + &VertexFormatTest::assemble}); + + addRepeatedInstancedTests({&VertexFormatTest::assembleRoundtrip}, 4, + Containers::arraySize(CombineRoundtripData)); + + addTests({&VertexFormatTest::assembleCantNormalize, + &VertexFormatTest::assembleInvalidComponentCount, &VertexFormatTest::debug, &VertexFormatTest::configuration}); @@ -112,6 +155,120 @@ void VertexFormatTest::sizeInvalid() { "vertexFormatSize(): invalid format VertexFormat(0xdead)\n"); } +void VertexFormatTest::componentCount() { + CORRADE_COMPARE(Magnum::vertexFormatComponentCount(VertexFormat::UnsignedByteNormalized), 1); + CORRADE_COMPARE(Magnum::vertexFormatComponentCount(VertexFormat::Vector2us), 2); + CORRADE_COMPARE(Magnum::vertexFormatComponentCount(VertexFormat::Vector3bNormalized), 3); + CORRADE_COMPARE(Magnum::vertexFormatComponentCount(VertexFormat::Vector4), 4); +} + +void VertexFormatTest::componentCountInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + Magnum::vertexFormatComponentCount(VertexFormat{}); + Magnum::vertexFormatComponentCount(VertexFormat(0xdead)); + + CORRADE_COMPARE(out.str(), + "vertexFormatComponentCount(): invalid format VertexFormat(0x0)\n" + "vertexFormatComponentCount(): invalid format VertexFormat(0xdead)\n"); +} + +void VertexFormatTest::componentFormat() { + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector4), VertexFormat::Float); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector3h), VertexFormat::Half); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector2d), VertexFormat::Double); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::UnsignedByte), VertexFormat::UnsignedByte); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::UnsignedByteNormalized), VertexFormat::UnsignedByte); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector3bNormalized), VertexFormat::Byte); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector2us), VertexFormat::UnsignedShort); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector2sNormalized), VertexFormat::Short); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector2ui), VertexFormat::UnsignedInt); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(VertexFormat::Vector3i), VertexFormat::Int); +} + +void VertexFormatTest::componentFormatInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + Magnum::vertexFormatComponentFormat(VertexFormat{}); + Magnum::vertexFormatComponentFormat(VertexFormat(0xdead)); + + CORRADE_COMPARE(out.str(), + "vertexFormatComponentType(): invalid format VertexFormat(0x0)\n" + "vertexFormatComponentType(): invalid format VertexFormat(0xdead)\n"); +} + +void VertexFormatTest::isNormalized() { + CORRADE_VERIFY(isVertexFormatNormalized(VertexFormat::UnsignedByteNormalized)); + CORRADE_VERIFY(!isVertexFormatNormalized(VertexFormat::Vector2us)); + CORRADE_VERIFY(isVertexFormatNormalized(VertexFormat::Vector3bNormalized)); + CORRADE_VERIFY(!isVertexFormatNormalized(VertexFormat::Vector4)); +} + +void VertexFormatTest::isNormalizedInvalid() { + std::ostringstream out; + Error redirectError{&out}; + + isVertexFormatNormalized(VertexFormat{}); + isVertexFormatNormalized(VertexFormat(0xdead)); + + CORRADE_COMPARE(out.str(), + "isVertexFormatNormalized(): invalid format VertexFormat(0x0)\n" + "isVertexFormatNormalized(): invalid format VertexFormat(0xdead)\n"); +} + +void VertexFormatTest::assemble() { + CORRADE_COMPARE(vertexFormat(VertexFormat::UnsignedShort, 3, true), + VertexFormat::Vector3usNormalized); + CORRADE_COMPARE(vertexFormat(VertexFormat::Int, 4, false), + VertexFormat::Vector4i); + CORRADE_COMPARE(vertexFormat(VertexFormat::Double, 1, false), + VertexFormat::Double); + CORRADE_COMPARE(vertexFormat(VertexFormat::Byte, 1, true), + VertexFormat::ByteNormalized); + + /* Non-scalar types allowed too, as that makes the internal checking + much simpler than when requiring the type to be scalar non-normalized */ + CORRADE_COMPARE(vertexFormat(VertexFormat::Vector4bNormalized, 2, false), + VertexFormat::Vector2b); + CORRADE_COMPARE(vertexFormat(VertexFormat::Vector3h, 2, false), + VertexFormat::Vector2h); +} + +void VertexFormatTest::assembleRoundtrip() { + auto&& data = CombineRoundtripData[testCaseInstanceId()]; + + std::ostringstream out; + { + Debug d{&out, Debug::Flag::NoNewlineAtTheEnd}; + d << data.componentType; + if(data.normalized) d << Debug::nospace << ", normalized"; + } + setTestCaseDescription(out.str()); + + VertexFormat result = vertexFormat(data.componentType, testCaseRepeatId() + 1, data.normalized); + CORRADE_COMPARE(Magnum::vertexFormatComponentFormat(result), data.componentType); + CORRADE_COMPARE(Magnum::vertexFormatComponentCount(result), testCaseRepeatId() + 1); + CORRADE_COMPARE(isVertexFormatNormalized(result), data.normalized); +} + +void VertexFormatTest::assembleCantNormalize() { + std::ostringstream out; + Error redirectError{&out}; + vertexFormat(VertexFormat::Vector2, 1, true); + CORRADE_COMPARE(out.str(), + "vertexFormat(): VertexFormat::Vector2 can't be made normalized\n"); +} + +void VertexFormatTest::assembleInvalidComponentCount() { + std::ostringstream out; + Error redirectError{&out}; + vertexFormat(VertexFormat::Vector3, 5, false); + CORRADE_COMPARE(out.str(), + "vertexFormat(): invalid component count 5\n"); +} + void VertexFormatTest::debug() { std::ostringstream o; Debug(&o) << VertexFormat::Vector4 << VertexFormat(0xdead); diff --git a/src/Magnum/VertexFormat.cpp b/src/Magnum/VertexFormat.cpp index 344c35c2a..cfe0ac031 100644 --- a/src/Magnum/VertexFormat.cpp +++ b/src/Magnum/VertexFormat.cpp @@ -35,23 +35,318 @@ namespace Magnum { UnsignedInt vertexFormatSize(const VertexFormat format) { switch(format) { case VertexFormat::UnsignedByte: + case VertexFormat::UnsignedByteNormalized: case VertexFormat::Byte: + case VertexFormat::ByteNormalized: return 1; + case VertexFormat::Half: case VertexFormat::UnsignedShort: + case VertexFormat::UnsignedShortNormalized: case VertexFormat::Short: + case VertexFormat::ShortNormalized: + case VertexFormat::Vector2ub: + case VertexFormat::Vector2ubNormalized: + case VertexFormat::Vector2b: + case VertexFormat::Vector2bNormalized: return 2; + case VertexFormat::Vector3ub: + case VertexFormat::Vector3ubNormalized: + case VertexFormat::Vector3b: + case VertexFormat::Vector3bNormalized: + return 3; case VertexFormat::Float: case VertexFormat::UnsignedInt: case VertexFormat::Int: + case VertexFormat::Vector2h: + case VertexFormat::Vector2us: + case VertexFormat::Vector2usNormalized: + case VertexFormat::Vector2s: + case VertexFormat::Vector2sNormalized: + case VertexFormat::Vector4ub: + case VertexFormat::Vector4ubNormalized: + case VertexFormat::Vector4b: + case VertexFormat::Vector4bNormalized: return 4; - case VertexFormat::Vector2: return 8; - case VertexFormat::Vector3: return 12; - case VertexFormat::Vector4: return 16; + case VertexFormat::Vector3h: + case VertexFormat::Vector3us: + case VertexFormat::Vector3usNormalized: + case VertexFormat::Vector3s: + case VertexFormat::Vector3sNormalized: + return 6; + case VertexFormat::Double: + case VertexFormat::Vector2: + case VertexFormat::Vector2ui: + case VertexFormat::Vector2i: + case VertexFormat::Vector4h: + case VertexFormat::Vector4us: + case VertexFormat::Vector4usNormalized: + case VertexFormat::Vector4s: + case VertexFormat::Vector4sNormalized: + return 8; + case VertexFormat::Vector3: + case VertexFormat::Vector3ui: + case VertexFormat::Vector3i: + return 12; + case VertexFormat::Vector2d: + case VertexFormat::Vector4: + case VertexFormat::Vector4ui: + case VertexFormat::Vector4i: + return 16; + case VertexFormat::Vector3d: + return 24; + case VertexFormat::Vector4d: + return 32; } CORRADE_ASSERT(false, "vertexFormatSize(): invalid format" << format, {}); } +UnsignedInt vertexFormatComponentCount(const VertexFormat format) { + switch(format) { + case VertexFormat::Float: + case VertexFormat::Half: + case VertexFormat::Double: + case VertexFormat::UnsignedByte: + case VertexFormat::UnsignedByteNormalized: + case VertexFormat::Byte: + case VertexFormat::ByteNormalized: + case VertexFormat::UnsignedShort: + case VertexFormat::UnsignedShortNormalized: + case VertexFormat::Short: + case VertexFormat::ShortNormalized: + case VertexFormat::UnsignedInt: + case VertexFormat::Int: + return 1; + + case VertexFormat::Vector2: + case VertexFormat::Vector2h: + case VertexFormat::Vector2d: + case VertexFormat::Vector2ub: + case VertexFormat::Vector2ubNormalized: + case VertexFormat::Vector2b: + case VertexFormat::Vector2bNormalized: + case VertexFormat::Vector2us: + case VertexFormat::Vector2usNormalized: + case VertexFormat::Vector2s: + case VertexFormat::Vector2sNormalized: + case VertexFormat::Vector2ui: + case VertexFormat::Vector2i: + return 2; + + case VertexFormat::Vector3: + case VertexFormat::Vector3h: + case VertexFormat::Vector3d: + case VertexFormat::Vector3ub: + case VertexFormat::Vector3ubNormalized: + case VertexFormat::Vector3b: + case VertexFormat::Vector3bNormalized: + case VertexFormat::Vector3us: + case VertexFormat::Vector3usNormalized: + case VertexFormat::Vector3s: + case VertexFormat::Vector3sNormalized: + case VertexFormat::Vector3ui: + case VertexFormat::Vector3i: + return 3; + + case VertexFormat::Vector4: + case VertexFormat::Vector4h: + case VertexFormat::Vector4d: + case VertexFormat::Vector4ub: + case VertexFormat::Vector4ubNormalized: + case VertexFormat::Vector4b: + case VertexFormat::Vector4bNormalized: + case VertexFormat::Vector4us: + case VertexFormat::Vector4usNormalized: + case VertexFormat::Vector4s: + case VertexFormat::Vector4sNormalized: + case VertexFormat::Vector4ui: + case VertexFormat::Vector4i: + return 4; + } + + CORRADE_ASSERT(false, "vertexFormatComponentCount(): invalid format" << format, {}); +} + +VertexFormat vertexFormatComponentFormat(const VertexFormat format) { + switch(format) { + case VertexFormat::Float: + case VertexFormat::Vector2: + case VertexFormat::Vector3: + case VertexFormat::Vector4: + return VertexFormat::Float; + + case VertexFormat::Half: + case VertexFormat::Vector2h: + case VertexFormat::Vector3h: + case VertexFormat::Vector4h: + return VertexFormat::Half; + + case VertexFormat::Double: + case VertexFormat::Vector2d: + case VertexFormat::Vector3d: + case VertexFormat::Vector4d: + return VertexFormat::Double; + + case VertexFormat::UnsignedByte: + case VertexFormat::UnsignedByteNormalized: + case VertexFormat::Vector2ub: + case VertexFormat::Vector2ubNormalized: + case VertexFormat::Vector3ub: + case VertexFormat::Vector3ubNormalized: + case VertexFormat::Vector4ub: + case VertexFormat::Vector4ubNormalized: + return VertexFormat::UnsignedByte; + + case VertexFormat::Byte: + case VertexFormat::ByteNormalized: + case VertexFormat::Vector2b: + case VertexFormat::Vector2bNormalized: + case VertexFormat::Vector3b: + case VertexFormat::Vector3bNormalized: + case VertexFormat::Vector4b: + case VertexFormat::Vector4bNormalized: + return VertexFormat::Byte; + + case VertexFormat::UnsignedShort: + case VertexFormat::UnsignedShortNormalized: + case VertexFormat::Vector2us: + case VertexFormat::Vector2usNormalized: + case VertexFormat::Vector3us: + case VertexFormat::Vector3usNormalized: + case VertexFormat::Vector4us: + case VertexFormat::Vector4usNormalized: + return VertexFormat::UnsignedShort; + + case VertexFormat::Short: + case VertexFormat::ShortNormalized: + case VertexFormat::Vector2s: + case VertexFormat::Vector2sNormalized: + case VertexFormat::Vector3s: + case VertexFormat::Vector3sNormalized: + case VertexFormat::Vector4s: + case VertexFormat::Vector4sNormalized: + return VertexFormat::Short; + + case VertexFormat::UnsignedInt: + case VertexFormat::Vector2ui: + case VertexFormat::Vector3ui: + case VertexFormat::Vector4ui: + return VertexFormat::UnsignedInt; + + case VertexFormat::Int: + case VertexFormat::Vector2i: + case VertexFormat::Vector3i: + case VertexFormat::Vector4i: + return VertexFormat::Int; + } + + CORRADE_ASSERT(false, "vertexFormatComponentType(): invalid format" << format, {}); +} + +bool isVertexFormatNormalized(const VertexFormat format) { + switch(format) { + case VertexFormat::Float: + case VertexFormat::Half: + case VertexFormat::Double: + case VertexFormat::UnsignedByte: + case VertexFormat::Byte: + case VertexFormat::UnsignedShort: + case VertexFormat::Short: + case VertexFormat::UnsignedInt: + case VertexFormat::Int: + case VertexFormat::Vector2: + case VertexFormat::Vector2h: + case VertexFormat::Vector2d: + case VertexFormat::Vector2ub: + case VertexFormat::Vector2b: + case VertexFormat::Vector2us: + case VertexFormat::Vector2s: + case VertexFormat::Vector2ui: + case VertexFormat::Vector2i: + case VertexFormat::Vector3: + case VertexFormat::Vector3h: + case VertexFormat::Vector3d: + case VertexFormat::Vector3ub: + case VertexFormat::Vector3b: + case VertexFormat::Vector3us: + case VertexFormat::Vector3s: + case VertexFormat::Vector3ui: + case VertexFormat::Vector3i: + case VertexFormat::Vector4: + case VertexFormat::Vector4h: + case VertexFormat::Vector4d: + case VertexFormat::Vector4ub: + case VertexFormat::Vector4b: + case VertexFormat::Vector4us: + case VertexFormat::Vector4s: + case VertexFormat::Vector4ui: + case VertexFormat::Vector4i: + return false; + + case VertexFormat::UnsignedByteNormalized: + case VertexFormat::ByteNormalized: + case VertexFormat::UnsignedShortNormalized: + case VertexFormat::ShortNormalized: + case VertexFormat::Vector2ubNormalized: + case VertexFormat::Vector2bNormalized: + case VertexFormat::Vector2usNormalized: + case VertexFormat::Vector2sNormalized: + case VertexFormat::Vector3ubNormalized: + case VertexFormat::Vector3bNormalized: + case VertexFormat::Vector3usNormalized: + case VertexFormat::Vector3sNormalized: + case VertexFormat::Vector4ubNormalized: + case VertexFormat::Vector4bNormalized: + case VertexFormat::Vector4usNormalized: + case VertexFormat::Vector4sNormalized: + return true; + } + + CORRADE_ASSERT(false, "isVertexFormatNormalized(): invalid format" << format, {}); +} + +VertexFormat vertexFormat(const VertexFormat format, UnsignedInt componentCount, bool normalized) { + VertexFormat componentFormat = vertexFormatComponentFormat(format); + + /* First turn the format into a normalized one, if requested */ + if(normalized) { + switch(componentFormat) { + case VertexFormat::UnsignedByte: + componentFormat = VertexFormat::UnsignedByteNormalized; + break; + case VertexFormat::Byte: + componentFormat = VertexFormat::ByteNormalized; + break; + case VertexFormat::UnsignedShort: + componentFormat = VertexFormat::UnsignedShortNormalized; + break; + case VertexFormat::Short: + componentFormat = VertexFormat::ShortNormalized; + break; + default: CORRADE_ASSERT(false, + "vertexFormat():" << format << "can't be made normalized", {}); + } + } + + /* Then turn them into desired component count, assuming the initial order + is the same in all cases */ + if(componentCount == 1) + return componentFormat; + else if(componentCount == 2) + return VertexFormat(UnsignedInt(VertexFormat::Vector2) + + UnsignedInt(componentFormat) - UnsignedInt(VertexFormat::Float)); + else if(componentCount == 3) + return VertexFormat(UnsignedInt(VertexFormat::Vector3) + + UnsignedInt(componentFormat) - UnsignedInt(VertexFormat::Float)); + else if(componentCount == 4) + return VertexFormat(UnsignedInt(VertexFormat::Vector4) + + UnsignedInt(componentFormat) - UnsignedInt(VertexFormat::Float)); + else CORRADE_ASSERT(false, + "vertexFormat(): invalid component count" << componentCount, {}); + + CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ +} + namespace { constexpr const char* VertexFormatNames[] { diff --git a/src/Magnum/VertexFormat.h b/src/Magnum/VertexFormat.h index ce7d3120a..6b66aa88e 100644 --- a/src/Magnum/VertexFormat.h +++ b/src/Magnum/VertexFormat.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Enum @ref Magnum::VertexFormat, function @ref Magnum::vertexFormatSize() + * @brief Enum @ref Magnum::VertexFormat, @ref Magnum::vertexFormatSize(), @ref Magnum::vertexFormatComponentCount(), @ref Magnum::vertexFormatComponentFormat(), @ref Magnum::isVertexFormatNormalized() */ #include @@ -48,37 +48,328 @@ types and matrices. enum class VertexFormat: UnsignedInt { /* Zero reserved for an invalid type (but not being a named value) */ - Float = 1, /**< @ref Float */ - UnsignedByte, /**< @ref UnsignedByte */ - Byte, /**< @ref Byte */ - UnsignedShort, /**< @ref UnsignedShort */ - Short, /**< @ref Short */ - UnsignedInt, /**< @ref UnsignedInt */ - Int, /**< @ref Int */ + /** @ref Float */ + Float = 1, + + /** @ref Half */ + Half, + + /** @ref Double */ + Double, + + /** @ref UnsignedByte */ + UnsignedByte, + + /** + * @ref UnsignedByte, with range @f$ [0, 255] @f$ interpreted as + * @f$ [0.0, 1.0] @f$. + */ + UnsignedByteNormalized, + + /** @ref Byte */ + Byte, + + /** + * @ref Byte, with range @f$ [-127, 127] @f$ interpreted as + * @f$ [-1.0, 1.0] @f$. + */ + ByteNormalized, + + /** @ref UnsignedShort */ + UnsignedShort, + + /** + * @ref UnsignedShort, with range @f$ [0, 65535] @f$ interpreted as + * @f$ [0.0, 1.0] @f$. + */ + UnsignedShortNormalized, + + /** @ref Short */ + Short, + + /** + * @ref Short, with range @f$ [-32767, 32767] @f$ interpreted as + * @f$ [-1.0, 1.0] @f$. + */ + ShortNormalized, + + /** @ref UnsignedInt */ + UnsignedInt, + + /** @ref Int */ + Int, /** * @ref Vector2. Usually used for 2D positions and 2D texture coordinates. */ Vector2, + /** + * @ref Vector2h. Can be used instead of @ref VertexFormat::Vector2 for 2D + * positions and 2D texture coordinates. + */ + Vector2h, + + /** @ref Vector2d */ + Vector2d, + + /** + * @ref Vector2ub. Can be used instead of @ref VertexFormat::Vector2 for + * packed 2D positions and 2D texture coordinates, in which case the range + * @f$ [0, 255] @f$ is interpreted as @f$ [0.0, 255.0] @f$. + */ + Vector2ub, + + /** + * @ref Vector2ub, with range @f$ [0, 255] @f$ interpreted as + * @f$ [0.0, 1.0] @f$. Can be used instead of @ref VertexFormat::Vector2 + * for packed 2D positions and 2D texture coordinates. + */ + Vector2ubNormalized, + + /** + * @ref Vector2b. Can be used instead of @ref VertexFormat::Vector2 for + * packed 2D positions and 2D texture coordinates, in which case the range + * @f$ [-128, 127] @f$ is interpreted as @f$ [-128.0, 127.0] @f$. + */ + Vector2b, + + /** + * @ref Vector2b, with range @f$ [-127, 127] @f$ interpreted as + * @f$ [-1.0, 1.0] @f$. Can be used instead of @ref VertexFormat::Vector2 + * for packed 2D positions and 2D texture coordinates. + */ + Vector2bNormalized, + + /** + * @ref Vector2us. Can be used instead of @ref VertexFormat::Vector2 for + * packed 2D positions and 2D texture coordinates, in which case the range + * @f$ [0, 65535] @f$ is interpreted as @f$ [0.0, 65535.0] @f$. + */ + Vector2us, + + /** + * @ref Vector2us, with range @f$ [0, 65535] @f$ interpreted as + * @f$ [0.0, 1.0] @f$. Can be used instead of @ref VertexFormat::Vector2 + * for packed 2D positions and 2D texture coordinates. + */ + Vector2usNormalized, + + /** + * @ref Vector2s. Can be used instead of @ref VertexFormat::Vector2 for + * packed 2D positions and 2D texture coordinates, in which case the range + * @f$ [-32768, 32767] @f$ is interpreted as @f$ [-32768.0, 32767.0] @f$. + */ + Vector2s, + + /** + * @ref Vector2s, with range @f$ [-32767, 32767] @f$ interpreted as + * @f$ [-1.0, 1.0] @f$. Can be used instead of @ref VertexFormat::Vector2 + * for packed 2D positions and 2D texture coordinates. + */ + Vector2sNormalized, + + /** @ref Vector2ui */ + Vector2ui, + + /** @ref Vector2i */ + Vector2i, + /** * @ref Vector3 or @ref Color3. Usually used for 3D positions, normals and * three-component colors. */ Vector3, + /** + * @ref Vector3h. Can be used instead of @ref VertexFormat::Vector3 for + * packed 3D positions and three-component colors. + */ + Vector3h, + + /** @ref Vector3d */ + Vector3d, + + /** + * @ref Vector3ub. Can be used instead of @ref VertexFormat::Vector3 for + * packed 3D positions, in which case the range @f$ [0, 255] @f$ is + * interpreted as @f$ [0.0, 255.0] @f$. + */ + Vector3ub, + + /** + * @ref Vector3ub, with range @f$ [0, 255] @f$ interpreted as + * @f$ [0.0, 1.0] @f$. Can be used instead of @ref VertexFormat::Vector3 + * for packed 3D positions and three-component colors. + */ + Vector3ubNormalized, + + /** + * @ref Vector3b. Can be used instead of @ref VertexFormat::Vector3 for + * packed 3D positions, in which case the range @f$ [-128, 127] @f$ is + * interpreted as @f$ [-128.0, 127.0] @f$. + */ + Vector3b, + + /** + * @ref Vector3b, with range @f$ [-127, 127] @f$ interpreted as + * @f$ [-1.0, 1.0] @f$. Can be used instead of + * @ref VertexFormat::Vector3 for packed 3D positions and normals. + */ + Vector3bNormalized, + + /** + * @ref Vector3us. Can be used instead of @ref VertexFormat::Vector3 for + * packed 2D positions, in which case the range @f$ [0, 65535] @f$ is + * interpreted as @f$ [0.0, 65535.0] @f$. + */ + Vector3us, + + /** + * @ref Vector3us, with range @f$ [0, 65535] @f$ interpreted as + * @f$ [0.0, 1.0] @f$. Can be used instead of @ref VertexFormat::Vector2 + * for packed 3D positions and three-component colors. + */ + Vector3usNormalized, + + /** + * @ref Vector3s. Can be used instead of @ref VertexFormat::Vector3 for + * packed 3D positions, in which case the range @f$ [-32768, 32767] @f$ is + * interpreted as @f$ [-32768.0, 32767.0] @f$. + */ + Vector3s, + + /** + * @ref Vector3s, with range @f$ [-32767, 32767] @f$ interpreted as + * @f$ [-1.0, 1.0] @f$. Can be used instead of @ref VertexFormat::Vector3 + * for packed 3D positions and normals. + */ + Vector3sNormalized, + + /** @ref Vector3ui */ + Vector3ui, + + /** @ref Vector3i */ + Vector3i, + /** * @ref Vector4 or @ref Color4. Usually used for four-component colors. */ - Vector4 + Vector4, + + /** + * @ref Vector4h. Can be used instead of @ref VertexFormat::Vector4 for + * four-component colors. + */ + Vector4h, + + /** @ref Vector4d */ + Vector4d, + + /** @ref Vector4ub */ + Vector4ub, + + /** + * @ref Vector4ub, with range @f$ [0, 255] @f$ interpreted as + * @f$ [0.0, 1.0] @f$. Can be used instead of @ref VertexFormat::Vector4 + * for packed linear four-component colors. + */ + Vector4ubNormalized, + + /** @ref Vector4b */ + Vector4b, + + /** + * @ref Vector4b, with range @f$ [-127, 127] @f$ interpreted as + * @f$ [-1.0, 1.0] @f$. + */ + Vector4bNormalized, + + /** @ref Vector4us */ + Vector4us, + + /** + * @ref Vector4us, with range @f$ [0, 65535] @f$ interpreted as + * @f$ [0.0, 1.0] @f$. Can be used instead of @ref VertexFormat::Vector4 + * for packed linear four-component colors. + */ + Vector4usNormalized, + + /** @ref Vector4s */ + Vector4s, + + /** + * @ref Vector4s, with range @f$ [-32767, 32767] @f$ interpreted as + * @f$ [-1.0, 1.0] @f$. + */ + Vector4sNormalized, + + /** @ref Vector4ui */ + Vector4ui, + + /** @ref Vector4i */ + Vector4i }; /** @brief Size of given vertex format @m_since_latest + +To get size of a single component, call this function on a result of +@ref vertexFormatComponentFormat(). */ MAGNUM_EXPORT UnsignedInt vertexFormatSize(VertexFormat format); +/** +@brief Component format of given vertex format +@m_since_latest + +The function also removes the normalization aspect from the type --- use +@ref isVertexFormatNormalized() to query that. Returns for example +@ref VertexFormat::Short for @ref VertexFormat::ShortNormalized or +@ref VertexFormat::UnsignedByte for @ref VertexFormat::Vector3ub. +Calling @ref vertexFormatComponentCount() on the return value will always +give @cpp 1 @ce; calling @ref isVertexFormatNormalized() on the return +value will always give @cpp false @ce. +@see @ref vertexFormat(VertexFormat, UnsignedInt, bool) +*/ +MAGNUM_EXPORT VertexFormat vertexFormatComponentFormat(VertexFormat format); + +/** +@brief Component count of given vertex format +@m_since_latest + +Returns @cpp 1 @ce for scalar types and e.g. @cpp 3 @ce for +@ref VertexFormat::Vector3ub. +@see @ref vertexFormat(VertexFormat, UnsignedInt, bool) +*/ +MAGNUM_EXPORT UnsignedInt vertexFormatComponentCount(VertexFormat format); + +/** +@brief Component count of given vertex format +@m_since_latest + +Returns @cpp true @ce for `*Normalized` types, @cpp false @ce otherwise. In +particular, floating-point types are *not* treated as normalized, even though +for example colors might commonly have values only in the @f$ [0.0, 1.0] @f$ +range (or normals in the @f$ [-1.0, 1.0] @f$ range). +@see @ref vertexFormat(VertexFormat, UnsignedInt, bool) +*/ +MAGNUM_EXPORT bool isVertexFormatNormalized(VertexFormat format); + +/** +@brief Assemble a vertex format from parts +@m_since_latest + +Converts @p format to a new format of desired component count and +normalization. Expects that @p componentCount is not larger than @cpp 4 @ce and +@p normalized is @cpp true @ce only for 8- and 16-byte integer types. +@see @ref vertexFormatComponentFormat(), + @ref vertexFormatComponentCount(), + @ref isVertexFormatNormalized() +*/ +MAGNUM_EXPORT VertexFormat vertexFormat(VertexFormat format, UnsignedInt componentCount, bool normalized); + /** @debugoperatorenum{VertexFormat} @m_since_latest