diff --git a/src/Magnum/Shaders/Generic.h b/src/Magnum/Shaders/Generic.h
index c1840777c..fb8db297c 100644
--- a/src/Magnum/Shaders/Generic.h
+++ b/src/Magnum/Shaders/Generic.h
@@ -132,7 +132,7 @@ both bitangents and object ID for instancing, \n
| 7 |
-@ref JointIndices
+@ref JointIds
|
@@ -150,13 +150,13 @@ both bitangents and object ID for instancing, \n
| 10 |
-@ref Weights
+@ref SecondaryWeights
|
| 11 |
-@ref JointIndices
+@ref SecondaryJointIds
|
@@ -469,6 +469,11 @@ struct BaseGeneric {
#ifndef MAGNUM_TARGET_GLES2
typedef GL::Attribute<4, UnsignedInt> ObjectId;
#endif
+ typedef GL::Attribute<6, Vector4> Weights;
+ typedef GL::Attribute<7, Vector4> JointIds;
+
+ typedef GL::Attribute<10, Vector4> SecondaryWeights;
+ typedef GL::Attribute<11, Vector4> SecondaryJointIds;
typedef GL::Attribute<15, Vector2> TextureOffset;
@@ -497,8 +502,6 @@ template<> struct Generic<3>: BaseGeneric {
typedef GL::Attribute<3, Vector4> Tangent4;
typedef GL::Attribute<4, Vector3> Bitangent; /* also ObjectId */
typedef GL::Attribute<5, Vector3> Normal;
- typedef GL::Attribute<6, Vector4> Weights;
- typedef GL::Attribute<7, Vector4> JointIds;
typedef GL::Attribute<8, Matrix4> TransformationMatrix;
/* 9, 10, 11 occupied by TransformationMatrix */
diff --git a/src/Magnum/Trade/MeshData.cpp b/src/Magnum/Trade/MeshData.cpp
index 94ac37036..354949d4e 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 221713b22..4cc12291a 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,
@@ -162,7 +159,7 @@ enum class MeshAttribute: UnsignedShort {
/**
* Joint IDs. Type is usually @ref VertexFormat::Vector4ui, but can be also
* @ref VertexFormat::Vector4us or @ref VertexFormat::Vector4ub.
- * @ref Shaders::Generic::JointIds.
+ * Corresponds to @ref Shaders::Generic::JointIds.
* @see @ref MeshData::jointIdsAsArray()
*/
JointIds,
@@ -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 301d305f4..20ef216fb 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,90 @@ 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.8)});
+ weightsView[1] = T::pad(Math::Vector4{0, Math::pack(1.0f), 0, Math::pack(0.4f)});
+
+ 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.8})),
+ Vector4::pad(Math::Vector::pad(Vector4{0.0f, 1.0f, 0.0f, 0.4f}))
+ }), 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 {