diff --git a/src/Magnum/Trade/MeshData.cpp b/src/Magnum/Trade/MeshData.cpp index 94ac37036d..354949d4e9 100644 --- a/src/Magnum/Trade/MeshData.cpp +++ b/src/Magnum/Trade/MeshData.cpp @@ -791,26 +791,13 @@ void MeshData::weightsInto(const Containers::StridedArrayView1D destina Utility::copy(Containers::arrayCast(attributeData), destination); else if(attribute._format == VertexFormat::Vector4h) Math::unpackHalfInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4ub) - Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4b) - Math::castInto(Containers::arrayCast<2, const Byte>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4us) - Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4s) - Math::castInto(Containers::arrayCast<2, const Short>(attributeData, 4), destination4f); else if(attribute._format == VertexFormat::Vector4ubNormalized) Math::unpackInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4bNormalized) - Math::unpackInto(Containers::arrayCast<2, const Byte>(attributeData, 4), destination4f); else if(attribute._format == VertexFormat::Vector4usNormalized) Math::unpackInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4f); - else if(attribute._format == VertexFormat::Vector4sNormalized) - Math::unpackInto(Containers::arrayCast<2, const Short>(attributeData, 4), destination4f); else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } - Containers::Array MeshData::weightsAsArray(const UnsignedInt id) const { Containers::Array out{_vertexCount}; weightsInto(out, id); @@ -825,13 +812,14 @@ void MeshData::jointIdsInto(const Containers::StridedArrayView1D dest CORRADE_ASSERT(!isVertexFormatImplementationSpecific(attribute._format), "Trade::MeshData::jointIdsInto(): can't extract data out of an implementation-specific vertex format" << reinterpret_cast(vertexFormatUnwrap(attribute._format)), ); const Containers::StridedArrayView1D attributeData = attributeDataViewInternal(attribute); + const Containers::StridedArrayView2D destination4ui = Containers::arrayCast<2, UnsignedInt>(destination); if(attribute._format == VertexFormat::Vector4ui) Utility::copy(Containers::arrayCast(attributeData), destination); else if(attribute._format == VertexFormat::Vector4ub) - Utility::copy(Containers::arrayCast(attributeData), destination); + Math::castInto(Containers::arrayCast<2, const UnsignedByte>(attributeData, 4), destination4ui); else if(attribute._format == VertexFormat::Vector4us) - Utility::copy(Containers::arrayCast(attributeData), destination); + Math::castInto(Containers::arrayCast<2, const UnsignedShort>(attributeData, 4), destination4ui); else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ } diff --git a/src/Magnum/Trade/MeshData.h b/src/Magnum/Trade/MeshData.h index 221713b220..b555c5318b 100644 --- a/src/Magnum/Trade/MeshData.h +++ b/src/Magnum/Trade/MeshData.h @@ -149,12 +149,9 @@ enum class MeshAttribute: UnsignedShort { /** * Weights. Type is usually @ref VertexFormat::Vector4, but can be also - * @ref VertexFormat::Vector4h, @ref VertexFormat::Vector4ub, - * @ref VertexFormat::Vector4b, @ref VertexFormat::Vector4us, - * @ref VertexFormat::Vector4s, @ref VertexFormat::Vector4ubNormalized, - * @ref VertexFormat::Vector4bNormalized, @ref VertexFormat::Vector4usNormalized - * or @ref VertexFormat::Vector4sNormalized. - * Corresponds to * @ref Shaders::Generic::Weights. + * @ref VertexFormat::Vector4h, @ref VertexFormat::Vector4ubNormalized + * or @ref VertexFormat::Vector4usNormalized. + * Corresponds to @ref Shaders::Generic::Weights. * @see @ref MeshData::weightsAsArray() */ Weights, @@ -2132,6 +2129,15 @@ namespace Implementation { (format == VertexFormat::UnsignedInt || format == VertexFormat::UnsignedShort || format == VertexFormat::UnsignedByte)) || + (name == MeshAttribute::Weights && + (format == VertexFormat::Vector4 || + format == VertexFormat::Vector4h || + format == VertexFormat::Vector4ubNormalized || + format == VertexFormat::Vector4usNormalized)) || + (name == MeshAttribute::JointIds && + (format == VertexFormat::Vector4ui || + format == VertexFormat::Vector4ub || + format == VertexFormat::Vector4us)) || /* Custom attributes can be anything */ isMeshAttributeCustom(name); } diff --git a/src/Magnum/Trade/Test/MeshDataTest.cpp b/src/Magnum/Trade/Test/MeshDataTest.cpp index 301d305f4f..e767f79247 100644 --- a/src/Magnum/Trade/Test/MeshDataTest.cpp +++ b/src/Magnum/Trade/Test/MeshDataTest.cpp @@ -146,6 +146,14 @@ struct MeshDataTest: TestSuite::Tester { template void objectIdsAsArray(); void objectIdsIntoArrayInvalidSize(); + template void weightsAsArray(); + template void weightsAsArrayPackedUnsignedNormalized(); + template void weightsAsArrayPackedSignedNormalized(); + void weightsIntoArrayInvalidSize(); + + template void jointIdsAsArray(); + void jointIdsIntoArrayInvalidSize(); + void implementationSpecificVertexFormat(); void implementationSpecificVertexFormatWrongAccess(); void implementationSpecificVertexFormatNotContained(); @@ -364,6 +372,17 @@ MeshDataTest::MeshDataTest() { &MeshDataTest::objectIdsAsArray, &MeshDataTest::objectIdsIntoArrayInvalidSize, + &MeshDataTest::weightsAsArray, + &MeshDataTest::weightsAsArray, + &MeshDataTest::weightsAsArrayPackedUnsignedNormalized, + &MeshDataTest::weightsAsArrayPackedUnsignedNormalized, + &MeshDataTest::weightsIntoArrayInvalidSize, + + &MeshDataTest::jointIdsAsArray, + &MeshDataTest::jointIdsAsArray, + &MeshDataTest::jointIdsAsArray, + &MeshDataTest::jointIdsIntoArrayInvalidSize, + &MeshDataTest::implementationSpecificVertexFormat, &MeshDataTest::implementationSpecificVertexFormatWrongAccess, &MeshDataTest::implementationSpecificVertexFormatNotContained, @@ -1856,8 +1875,11 @@ _c(Vector3b) _c(Vector3us) _c(Vector3s) _c(Vector4) +_c(Vector4ui) _c(Vector4h) +_c(Vector4ub) _c(Vector4b) +_c(Vector4us) _c(Vector4s) _c(Color3) _c(Color3h) @@ -2500,6 +2522,108 @@ void MeshDataTest::objectIdsIntoArrayInvalidSize() { "Trade::MeshData::objectIdsInto(): expected a view with 3 elements but got 2\n"); } +template void MeshDataTest::weightsAsArray() { + setTestCaseTemplateName(NameTraits::name()); + typedef typename T::Type U; + + Containers::Array vertexData{3*sizeof(T)}; + auto weightsView = Containers::arrayCast(vertexData); + /* Needs to be sufficiently representable to have the test work also for + half floats */ + weightsView[0] = T::pad(Math::Vector4{U(2.0f), U(1.0f), U(0.75f), U(3.0f)}); + weightsView[1] = T::pad(Math::Vector4{U(0.0f), U(-1.0f), U(1.25f), U(1.0f)}); + weightsView[2] = T::pad(Math::Vector4{U(-2.0f), U(3.0f), U(2.5f), U(2.5f)}); + + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Weights, weightsView}}}; + CORRADE_COMPARE_AS(data.weightsAsArray(), Containers::arrayView({ + {2.0f, 1.0f, 0.75f, 3.0f}, {0.0f, -1.0f, 1.25f, 1.0f}, {-2.0f, 3.0f, 2.5f, 2.5f}, + }), TestSuite::Compare::Container); +} + +template void MeshDataTest::weightsAsArrayPackedUnsignedNormalized() { + setTestCaseTemplateName(NameTraits::name()); + + Containers::Array vertexData{2*sizeof(T)}; + auto weightsView = Containers::arrayCast(vertexData); + weightsView[0] = T::pad(Math::Vector4{Math::pack(1.0f), 0, Math::pack(1.0f), Math::pack(0.25f)}); + weightsView[1] = T::pad(Math::Vector4{0, Math::pack(1.0f), 0, Math::pack(0.5f)}); + + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Weights, + /* Assuming the normalized enum is always after the non-normalized */ + VertexFormat(UnsignedInt(Implementation::vertexFormatFor()) + 1), + weightsView}}}; + CORRADE_COMPARE_AS(data.weightsAsArray(), Containers::arrayView({ + Vector4::pad(Math::Vector::pad(Vector4{1.0f, 0.0f, 1.0f, 0.25f})), + Vector4::pad(Math::Vector::pad(Vector4{0.0f, 1.0f, 0.0f, 0.5f})) + }), TestSuite::Compare::Container); +} + +template void MeshDataTest::weightsAsArrayPackedSignedNormalized() { + setTestCaseTemplateName(NameTraits::name()); + + Containers::Array vertexData{2*sizeof(T)}; + auto weightsView = Containers::arrayCast(vertexData); + weightsView[0] = T::pad(Math::Vector4{Math::pack(1.0f), 0, Math::pack(1.0f), Math::pack(0.25f)}); + weightsView[1] = T::pad(Math::Vector4{0, Math::pack(-1.0f), 0, Math::pack(0.5f)}); + + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Weights, + /* Assuming the normalized enum is always after the non-normalized */ + VertexFormat(UnsignedInt(Implementation::vertexFormatFor()) + 1), + weightsView}}}; + CORRADE_COMPARE_AS(data.weightsAsArray(), Containers::arrayView({ + Vector4::pad(Math::Vector::pad(Vector4{1.0f, 0.0f, 1.0f, 0.25f})), + Vector4::pad(Math::Vector::pad(Vector4{0.0f, -1.0f, 0.0f, 0.5f})) + }), TestSuite::Compare::Container); +} + +void MeshDataTest::weightsIntoArrayInvalidSize() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + Containers::Array vertexData{3*sizeof(Vector4)}; + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::Weights, Containers::arrayCast(vertexData)}}}; + + std::ostringstream out; + Error redirectError{&out}; + Vector4 destination[2]; + data.weightsInto(destination); + CORRADE_COMPARE(out.str(), + "Trade::MeshData::weightsInto(): expected a view with 3 elements but got 2\n"); +} + +template void MeshDataTest::jointIdsAsArray() { + setTestCaseTemplateName(NameTraits::name()); + typedef typename T::Type U; + + Containers::Array vertexData{3*sizeof(T)}; + auto joinIdsView = Containers::arrayCast(vertexData); + joinIdsView[0] = {U(0), U(1), U(2), U(3)}; + joinIdsView[1] = {U(4), U(5), U(6), U(7)}; + joinIdsView[2] = {U(8), U(9), U(10), U(11)}; + + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::JointIds, joinIdsView}}}; + CORRADE_COMPARE_AS(data.jointIdsAsArray(), Containers::arrayView({ + {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}, + }), TestSuite::Compare::Container); +} + +void MeshDataTest::jointIdsIntoArrayInvalidSize() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + Containers::Array vertexData{3*sizeof(Vector4ui)}; + MeshData data{MeshPrimitive::Points, std::move(vertexData), {MeshAttributeData{MeshAttribute::JointIds, Containers::arrayCast(vertexData)}}}; + + std::ostringstream out; + Error redirectError{&out}; + Vector4ui destination[2]; + data.jointIdsInto(destination); + CORRADE_COMPARE(out.str(), + "Trade::MeshData::jointIdsInto(): expected a view with 3 elements but got 2\n"); +} + /* MSVC 2015 doesn't like anonymous bitfields in inline structs, so putting the declaration outside */ struct VertexWithImplementationSpecificData {