Browse Source

MeshTools: support morph targets in transform().

pull/623/head
Vladimír Vondruš 3 years ago
parent
commit
02e0d85f51
  1. 414
      src/Magnum/MeshTools/Test/TransformTest.cpp
  2. 175
      src/Magnum/MeshTools/Transform.cpp
  3. 184
      src/Magnum/MeshTools/Transform.h

414
src/Magnum/MeshTools/Test/TransformTest.cpp

@ -104,28 +104,43 @@ const struct {
const char* name; const char* name;
bool indexed; bool indexed;
UnsignedInt id; UnsignedInt id;
Int morphTargetId;
Matrix3 transformation; Matrix3 transformation;
} MeshData2DData[]{ } MeshData2DData[]{
{"", false, 0, {"", false, 0, -1,
Matrix3::translation({1.5f, 3.0f})* Matrix3::translation({1.5f, 3.0f})*
Matrix3::rotation(35.0_degf)}, Matrix3::rotation(35.0_degf)},
{"indexed", true, 0, {"indexed", true, 0, -1,
Matrix3::translation({1.5f, 3.0f})* Matrix3::translation({1.5f, 3.0f})*
Matrix3::rotation(35.0_degf)}, Matrix3::rotation(35.0_degf)},
{"second set", false, 1, {"second set", false, 1, -1,
Matrix3::translation({1.5f, 3.0f})*
Matrix3::rotation(35.0_degf)},
{"morph target", false, 0, 37,
Matrix3::translation({1.5f, 3.0f})* Matrix3::translation({1.5f, 3.0f})*
Matrix3::rotation(35.0_degf)} Matrix3::rotation(35.0_degf)}
/** @todo negative scaling that flips face winding */ /** @todo negative scaling that flips face winding */
}; };
const struct {
const char* name;
UnsignedInt id;
Int morphTargetId;
} NoAttributeData[]{
{"", 1, -1},
{"morph target", 0, 37}
};
const struct { const struct {
const char* name; const char* name;
bool indexed; bool indexed;
UnsignedInt id; UnsignedInt id;
Int morphTargetId;
} MeshData2DRvaluePassthroughData[]{ } MeshData2DRvaluePassthroughData[]{
{"", false, 0}, {"", false, 0, -1},
{"indexed", true, 0}, {"indexed", true, 0, -1},
{"second set", false, 1} {"second set", false, 1, -1},
{"morph target", false, 0, 37}
}; };
const struct { const struct {
@ -133,55 +148,65 @@ const struct {
bool indexed; bool indexed;
bool tangents, tangents4, bitangents, normals; bool tangents, tangents4, bitangents, normals;
UnsignedInt id; UnsignedInt id;
Int morphTargetId;
Matrix4 transformation; Matrix4 transformation;
Matrix3x3 expectedNormalTransformation; Matrix3x3 expectedNormalTransformation;
} MeshData3DData[]{ } MeshData3DData[]{
{"", false, false, false, false, false, 0, {"", false, false, false, false, false, 0, -1,
Matrix4::translation({1.5f, 3.0f, -0.5f})* Matrix4::translation({1.5f, 3.0f, -0.5f})*
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"indexed", true, false, false, false, false, 0, {"indexed", true, false, false, false, false, 0, -1,
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"normals", false, false, false, false, true, 0, {"normals", false, false, false, false, true, 0, -1,
Matrix4::translation({1.5f, 3.0f, -0.5f})* Matrix4::translation({1.5f, 3.0f, -0.5f})*
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"tangents", false, true, false, false, false, 0, {"tangents", false, true, false, false, false, 0, -1,
Matrix4::translation({1.5f, 3.0f, -0.5f})* Matrix4::translation({1.5f, 3.0f, -0.5f})*
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"four-component tangents", false, true, true, false, false, 0, {"four-component tangents", false, true, true, false, false, 0, -1,
Matrix4::translation({1.5f, 3.0f, -0.5f})* Matrix4::translation({1.5f, 3.0f, -0.5f})*
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"bitangents", false, false, false, true, false, 0, {"bitangents", false, false, false, true, false, 0, -1,
Matrix4::translation({1.5f, 3.0f, -0.5f})* Matrix4::translation({1.5f, 3.0f, -0.5f})*
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"all + indexed", true, true, true, true, true, 0, {"all + indexed", true, true, true, true, true, 0, -1,
Matrix4::translation({1.5f, 3.0f, -0.5f})* Matrix4::translation({1.5f, 3.0f, -0.5f})*
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"second set ", false, false, false, false, false, 1, {"second set", false, false, false, false, false, 1, -1,
Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()},
{"second set + normals", false, false, false, false, true, 1, -1,
Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()},
{"second set + tangents", false, true, false, false, false, 1, -1,
Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()},
{"second set + four-component tangents", false, true, true, false, false, 1, -1,
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"second set + normals", false, false, false, false, true, 1, {"second set + bitangents", false, false, false, true, false, 1, -1,
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"second set + tangents", false, true, false, false, false, 1, {"second set + all + indexed", true, true, true, true, true, 1, -1,
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"second set + four-component tangents", false, true, true, false, false, 1, {"morph target", false, false, false, false, false, 0, 37,
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"second set + bitangents", false, false, false, true, false, 1, {"morph target + tangents", false, true, false, false, false, 0, 37,
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"second set + all + indexed", true, true, true, true, true, 1, {"morph target + allindexed", false, true, true, true, true, 0, 37,
Matrix4::rotationX(35.0_degf), Matrix4::rotationX(35.0_degf),
Matrix4::rotationX(35.0_degf).rotationScaling()}, Matrix4::rotationX(35.0_degf).rotationScaling()},
{"non-uniform scaling", false, true, true, true, true, 0, {"non-uniform scaling", false, true, true, true, true, 0, -1,
Matrix4::translation({1.5f, 3.0f, -0.5f})* Matrix4::translation({1.5f, 3.0f, -0.5f})*
Matrix4::rotationX(35.0_degf)* Matrix4::rotationX(35.0_degf)*
Matrix4::scaling({2.0f, 1.0f, 0.5f}), Matrix4::scaling({2.0f, 1.0f, 0.5f}),
@ -207,20 +232,24 @@ const struct {
bool indexed; bool indexed;
bool tangents, tangents4, bitangents, normals; bool tangents, tangents4, bitangents, normals;
UnsignedInt id; UnsignedInt id;
Int morphTargetId;
} MeshData3DRvaluePassthroughData[]{ } MeshData3DRvaluePassthroughData[]{
{"", false, false, false, false, false, 0}, {"", false, false, false, false, false, 0, -1},
{"indexed", true, false, false, false, false, 0}, {"indexed", true, false, false, false, false, 0, -1},
{"normals", false, false, false, false, true, 0}, {"normals", false, false, false, false, true, 0, -1},
{"tangents", false, true, false, false, false, 0}, {"tangents", false, true, false, false, false, 0, -1},
{"four-component tangents", false, true, true, false, false, 0}, {"four-component tangents", false, true, true, false, false, 0, -1},
{"bitangents", false, false, false, true, false, 0}, {"bitangents", false, false, false, true, false, 0, -1},
{"all + indexed", true, true, true, true, true, 0}, {"all + indexed", true, true, true, true, true, 0, -1},
{"second set ", false, false, false, false, false, 1}, {"second set", false, false, false, false, false, 1, -1},
{"second set + normals", false, false, false, false, true, 1}, {"second set + normals", false, false, false, false, true, 1, -1},
{"second set + tangents", false, true, false, false, false, 1}, {"second set + tangents", false, true, false, false, false, 1, -1},
{"second set + four-component tangents", false, true, true, false, false, 1}, {"second set + four-component tangents", false, true, true, false, false, 1, -1},
{"second set + bitangents", false, false, false, true, false, 1}, {"second set + bitangents", false, false, false, true, false, 1, -1},
{"second set + all + indexed", true, true, true, true, true, 1}, {"second set + all + indexed", true, true, true, true, true, 1, -1},
{"morph target", false, false, false, false, false, 0, 37},
{"morph target + tangents", false, true, false, false, false, 0, 37},
{"morph target + all", false, true, true, true, true, 0, 37}
}; };
const struct { const struct {
@ -252,15 +281,19 @@ const struct {
const char* name; const char* name;
bool indexed; bool indexed;
UnsignedInt id; UnsignedInt id;
Int morphTargetId;
Matrix3 transformation; Matrix3 transformation;
} MeshDataTextureCoordinatesData[]{ } MeshDataTextureCoordinatesData[]{
{"", false, 0, {"", false, 0, -1,
Matrix3::translation({1.5f, 3.0f})*
Matrix3::rotation(35.0_degf)},
{"indexed", true, 0, -1,
Matrix3::translation({1.5f, 3.0f})* Matrix3::translation({1.5f, 3.0f})*
Matrix3::rotation(35.0_degf)}, Matrix3::rotation(35.0_degf)},
{"indexed", true, 0, {"second set", false, 1, -1,
Matrix3::translation({1.5f, 3.0f})* Matrix3::translation({1.5f, 3.0f})*
Matrix3::rotation(35.0_degf)}, Matrix3::rotation(35.0_degf)},
{"second set", false, 1, {"morph target", false, 0, 37,
Matrix3::translation({1.5f, 3.0f})* Matrix3::translation({1.5f, 3.0f})*
Matrix3::rotation(35.0_degf)} Matrix3::rotation(35.0_degf)}
}; };
@ -269,10 +302,12 @@ const struct {
const char* name; const char* name;
bool indexed; bool indexed;
UnsignedInt id; UnsignedInt id;
Int morphTargetId;
} MeshDataTextureCoordinatesRvaluePassthroughData[]{ } MeshDataTextureCoordinatesRvaluePassthroughData[]{
{"", false, 0}, {"", false, 0, -1},
{"indexed", true, 0}, {"indexed", true, 0, -1},
{"second set", false, 1} {"second set", false, 1, -1},
{"morph target", false, 0, 37}
}; };
TransformTest::TransformTest() { TransformTest::TransformTest() {
@ -287,8 +322,10 @@ TransformTest::TransformTest() {
&TransformTest::meshData2D<Half> &TransformTest::meshData2D<Half>
}, Containers::arraySize(MeshData2DData)); }, Containers::arraySize(MeshData2DData));
addTests({&TransformTest::meshData2DNoPosition, addInstancedTests({&TransformTest::meshData2DNoPosition},
&TransformTest::meshData2DNot2D, Containers::arraySize(NoAttributeData));
addTests({&TransformTest::meshData2DNot2D,
&TransformTest::meshData2DImplementationSpecificIndexType, &TransformTest::meshData2DImplementationSpecificIndexType,
&TransformTest::meshData2DImplementationSpecificVertexFormat}); &TransformTest::meshData2DImplementationSpecificVertexFormat});
@ -296,13 +333,19 @@ TransformTest::TransformTest() {
Containers::arraySize(MeshData2DRvaluePassthroughData)); Containers::arraySize(MeshData2DRvaluePassthroughData));
addTests({&TransformTest::meshData2DRvaluePassthroughIndexDataNotOwned, addTests({&TransformTest::meshData2DRvaluePassthroughIndexDataNotOwned,
&TransformTest::meshData2DRvaluePassthroughVertexDataNotOwned, &TransformTest::meshData2DRvaluePassthroughVertexDataNotOwned});
&TransformTest::meshData2DRvaluePassthroughNoPosition,
&TransformTest::meshData2DRvaluePassthroughWrongFormat});
addTests({&TransformTest::meshData2DInPlaceNotMutable, addInstancedTests({&TransformTest::meshData2DRvaluePassthroughNoPosition},
&TransformTest::meshData2DInPlaceNoPosition, Containers::arraySize(NoAttributeData));
&TransformTest::meshData2DInPlaceWrongFormat});
addTests({&TransformTest::meshData2DRvaluePassthroughWrongFormat});
addTests({&TransformTest::meshData2DInPlaceNotMutable});
addInstancedTests({&TransformTest::meshData2DInPlaceNoPosition},
Containers::arraySize(NoAttributeData));
addTests({&TransformTest::meshData2DInPlaceWrongFormat});
addInstancedTests<TransformTest>({ addInstancedTests<TransformTest>({
&TransformTest::meshData3D<Float, Float, Float, Float>, &TransformTest::meshData3D<Float, Float, Float, Float>,
@ -310,8 +353,10 @@ TransformTest::TransformTest() {
&TransformTest::meshData3D<Float, Half, Float, Half>, &TransformTest::meshData3D<Float, Half, Float, Half>,
}, Containers::arraySize(MeshData3DData)); }, Containers::arraySize(MeshData3DData));
addTests({&TransformTest::meshData3DNoPosition, addInstancedTests({&TransformTest::meshData3DNoPosition},
&TransformTest::meshData3DNot3D, Containers::arraySize(NoAttributeData));
addTests({&TransformTest::meshData3DNot3D,
&TransformTest::meshData3DImplementationSpecificIndexType}); &TransformTest::meshData3DImplementationSpecificIndexType});
addInstancedTests({&TransformTest::meshData3DImplementationSpecificVertexFormat}, addInstancedTests({&TransformTest::meshData3DImplementationSpecificVertexFormat},
@ -321,14 +366,18 @@ TransformTest::TransformTest() {
Containers::arraySize(MeshData3DRvaluePassthroughData)); Containers::arraySize(MeshData3DRvaluePassthroughData));
addTests({&TransformTest::meshData3DRvaluePassthroughIndexDataNotOwned, addTests({&TransformTest::meshData3DRvaluePassthroughIndexDataNotOwned,
&TransformTest::meshData3DRvaluePassthroughVertexDataNotOwned, &TransformTest::meshData3DRvaluePassthroughVertexDataNotOwned});
&TransformTest::meshData3DRvaluePassthroughNoPosition});
addInstancedTests({&TransformTest::meshData3DRvaluePassthroughNoPosition},
Containers::arraySize(NoAttributeData));
addInstancedTests({&TransformTest::meshData3DRvaluePassthroughWrongFormat}, addInstancedTests({&TransformTest::meshData3DRvaluePassthroughWrongFormat},
Containers::arraySize(MeshData3DWrongFormatData)); Containers::arraySize(MeshData3DWrongFormatData));
addTests({&TransformTest::meshData3DInPlaceNotMutable, addTests({&TransformTest::meshData3DInPlaceNotMutable});
&TransformTest::meshData3DInPlaceNoPosition});
addInstancedTests({&TransformTest::meshData3DInPlaceNoPosition},
Containers::arraySize(NoAttributeData));
addInstancedTests({&TransformTest::meshData3DInPlaceWrongFormat}, addInstancedTests({&TransformTest::meshData3DInPlaceWrongFormat},
Containers::arraySize(MeshData3DWrongFormatData)); Containers::arraySize(MeshData3DWrongFormatData));
@ -338,21 +387,29 @@ TransformTest::TransformTest() {
&TransformTest::meshDataTextureCoordinates2D<Half> &TransformTest::meshDataTextureCoordinates2D<Half>
}, Containers::arraySize(MeshDataTextureCoordinatesData)); }, Containers::arraySize(MeshDataTextureCoordinatesData));
addTests({&TransformTest::meshDataTextureCoordinates2DNoCoordinates, addInstancedTests({&TransformTest::meshDataTextureCoordinates2DNoCoordinates},
&TransformTest::meshDataTextureCoordinates2DImplementationSpecificIndexType, Containers::arraySize(NoAttributeData));
addTests({&TransformTest::meshDataTextureCoordinates2DImplementationSpecificIndexType,
&TransformTest::meshDataTextureCoordinates2DImplementationSpecificVertexFormat}); &TransformTest::meshDataTextureCoordinates2DImplementationSpecificVertexFormat});
addInstancedTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthrough}, addInstancedTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthrough},
Containers::arraySize(MeshDataTextureCoordinatesRvaluePassthroughData)); Containers::arraySize(MeshDataTextureCoordinatesRvaluePassthroughData));
addTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughIndexDataNotOwned, addTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughIndexDataNotOwned,
&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughVertexDataNotOwned, &TransformTest::meshDataTextureCoordinates2DRvaluePassthroughVertexDataNotOwned});
&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughNoCoordinates,
&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughWrongFormat});
addTests({&TransformTest::meshDataTextureCoordinates2DInPlaceNotMutable, addInstancedTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughNoCoordinates},
&TransformTest::meshDataTextureCoordinates2DInPlaceNoCoordinates, Containers::arraySize(NoAttributeData));
&TransformTest::meshDataTextureCoordinates2DInPlaceWrongFormat});
addTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughWrongFormat});
addTests({&TransformTest::meshDataTextureCoordinates2DInPlaceNotMutable});
addInstancedTests({&TransformTest::meshDataTextureCoordinates2DInPlaceNoCoordinates},
Containers::arraySize(NoAttributeData));
addTests({&TransformTest::meshDataTextureCoordinates2DInPlaceWrongFormat});
} }
constexpr static std::array<Vector2, 2> points2D{{ constexpr static std::array<Vector2, 2> points2D{{
@ -441,11 +498,14 @@ template<class T> void TransformTest::meshData2D() {
Containers::StridedArrayView1D<const Vertex> view = vertices; Containers::StridedArrayView1D<const Vertex> view = vertices;
Containers::Array<Trade::MeshAttributeData> attributes; Containers::Array<Trade::MeshAttributeData> attributes;
if(data.id == 1) if(data.id == 1 || data.morphTargetId != -1)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, view.slice(&Vertex::secondaryPosition)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, view.slice(&Vertex::secondaryPosition)});
else CORRADE_COMPARE(data.id, 0); else {
CORRADE_COMPARE(data.id, 0);
CORRADE_COMPARE(data.morphTargetId, -1);
}
arrayAppend(attributes, { arrayAppend(attributes, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, view.slice(&Vertex::position)}, Trade::MeshAttributeData{Trade::MeshAttribute::Position, view.slice(&Vertex::position), data.morphTargetId},
Trade::MeshAttributeData{Trade::meshAttributeCustom(0), view.slice(&Vertex::somethingElse)} Trade::MeshAttributeData{Trade::meshAttributeCustom(0), view.slice(&Vertex::somethingElse)}
}); });
@ -455,7 +515,7 @@ template<class T> void TransformTest::meshData2D() {
{}, vertices, std::move(attributes)}; {}, vertices, std::move(attributes)};
CORRADE_COMPARE(mesh.isIndexed(), data.indexed); CORRADE_COMPARE(mesh.isIndexed(), data.indexed);
Trade::MeshData out = transform2D(mesh, data.transformation, data.id); Trade::MeshData out = transform2D(mesh, data.transformation, data.id, data.morphTargetId);
CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleStrip); CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleStrip);
/* Indices should be preserved */ /* Indices should be preserved */
@ -473,8 +533,8 @@ template<class T> void TransformTest::meshData2D() {
TestSuite::Compare::Container); TestSuite::Compare::Container);
/* The vertices should be expanded to floats and transformed */ /* The vertices should be expanded to floats and transformed */
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id), VertexFormat::Vector2); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id, data.morphTargetId), VertexFormat::Vector2);
CORRADE_COMPARE_AS(out.attribute<Vector2>(Trade::MeshAttribute::Position, data.id), Containers::arrayView({ CORRADE_COMPARE_AS(out.attribute<Vector2>(Trade::MeshAttribute::Position, data.id, data.morphTargetId), Containers::arrayView({
data.transformation.transformPoint({0.0f, 0.0f}), data.transformation.transformPoint({0.0f, 0.0f}),
data.transformation.transformPoint({1.0f, 0.0f}), data.transformation.transformPoint({1.0f, 0.0f}),
data.transformation.transformPoint({0.0f, 2.0f}) data.transformation.transformPoint({0.0f, 2.0f})
@ -482,6 +542,9 @@ template<class T> void TransformTest::meshData2D() {
} }
void TransformTest::meshData2DNoPosition() { void TransformTest::meshData2DNoPosition() {
auto&& data = NoAttributeData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { Trade::MeshData mesh{MeshPrimitive::Points, nullptr, {
@ -490,8 +553,11 @@ void TransformTest::meshData2DNoPosition() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
transform2D(mesh, {}, 1); transform2D(mesh, {}, data.id, data.morphTargetId);
CORRADE_COMPARE(out.str(), "MeshTools::transform2D(): the mesh has no positions with index 1\n"); if(data.morphTargetId == -1)
CORRADE_COMPARE(out.str(), "MeshTools::transform2D(): the mesh has no positions with index 1\n");
else
CORRADE_COMPARE(out.str(), "MeshTools::transform2D(): the mesh has no positions with index 0 in morph target 37\n");
} }
void TransformTest::meshData2DNot2D() { void TransformTest::meshData2DNot2D() {
@ -519,7 +585,7 @@ void TransformTest::meshData2DImplementationSpecificIndexType() {
{}, vertices, {Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(vertices)}}}; {}, vertices, {Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(vertices)}}};
/* Just verify the index data get passed through with no information loss */ /* Just verify the index data get passed through with no information loss */
Trade::MeshData out = transform2D(mesh, Matrix3{}, 0, InterleaveFlag::PreserveStridedIndices); Trade::MeshData out = transform2D(mesh, Matrix3{}, 0, -1, InterleaveFlag::PreserveStridedIndices);
CORRADE_COMPARE(out.primitive(), MeshPrimitive::Points); CORRADE_COMPARE(out.primitive(), MeshPrimitive::Points);
CORRADE_COMPARE(out.indexType(), meshIndexTypeWrap(0xcaca)); CORRADE_COMPARE(out.indexType(), meshIndexTypeWrap(0xcaca));
CORRADE_COMPARE(out.indexOffset(), 2); CORRADE_COMPARE(out.indexOffset(), 2);
@ -568,11 +634,14 @@ void TransformTest::meshData2DRvaluePassthrough() {
}, vertices); }, vertices);
Containers::Array<Trade::MeshAttributeData> attributes; Containers::Array<Trade::MeshAttributeData> attributes;
if(data.id == 1) if(data.id == 1 || data.morphTargetId != -1)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::secondaryPosition)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::secondaryPosition)});
else CORRADE_COMPARE(data.id, 0); else {
CORRADE_COMPARE(data.id, 0);
CORRADE_COMPARE(data.morphTargetId, -1);
}
arrayAppend(attributes, { arrayAppend(attributes, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)} Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position), data.morphTargetId}
}); });
const void* originalAttributeData = attributes; const void* originalAttributeData = attributes;
@ -582,7 +651,7 @@ void TransformTest::meshData2DRvaluePassthrough() {
std::move(vertexData), std::move(attributes)}; std::move(vertexData), std::move(attributes)};
const Matrix3 transformation = Matrix3::rotation(35.0_degf); const Matrix3 transformation = Matrix3::rotation(35.0_degf);
Trade::MeshData out = transform2D(std::move(mesh), transformation, data.id); Trade::MeshData out = transform2D(std::move(mesh), transformation, data.id, data.morphTargetId);
CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleFan); CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleFan);
/* Indices should be passed through unchanged */ /* Indices should be passed through unchanged */
@ -594,8 +663,8 @@ void TransformTest::meshData2DRvaluePassthrough() {
} }
/* The vertices should be expanded to floats and transformed */ /* The vertices should be expanded to floats and transformed */
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id), VertexFormat::Vector2); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id, data.morphTargetId), VertexFormat::Vector2);
CORRADE_COMPARE_AS(out.attribute<Vector2>(Trade::MeshAttribute::Position, data.id), Containers::arrayView({ CORRADE_COMPARE_AS(out.attribute<Vector2>(Trade::MeshAttribute::Position, data.id, data.morphTargetId), Containers::arrayView({
transformation.transformPoint({0.0f, 0.0f}), transformation.transformPoint({0.0f, 0.0f}),
transformation.transformPoint({1.0f, 0.0f}), transformation.transformPoint({1.0f, 0.0f}),
transformation.transformPoint({0.0f, 2.0f}) transformation.transformPoint({0.0f, 2.0f})
@ -696,16 +765,23 @@ void TransformTest::meshData2DRvaluePassthroughVertexDataNotOwned() {
} }
void TransformTest::meshData2DRvaluePassthroughNoPosition() { void TransformTest::meshData2DRvaluePassthroughNoPosition() {
auto&& data = NoAttributeData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
/* Mainly to verify there's no other accidental assertion from checking /* Mainly to verify there's no other accidental assertion from checking
vertex format, this message comes from the l-value overload */ vertex format and that the ID + morph target ID gets correctly passed
through, this message comes from the l-value overload */
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
transform2D(Trade::MeshData{MeshPrimitive::Points, nullptr, { transform2D(Trade::MeshData{MeshPrimitive::Points, nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector2, nullptr}, Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector2, nullptr},
}}, {}, 1); }}, {}, data.id, data.morphTargetId);
CORRADE_COMPARE(out.str(), "MeshTools::transform2D(): the mesh has no positions with index 1\n"); if(data.morphTargetId == -1)
CORRADE_COMPARE(out.str(), "MeshTools::transform2D(): the mesh has no positions with index 1\n");
else
CORRADE_COMPARE(out.str(), "MeshTools::transform2D(): the mesh has no positions with index 0 in morph target 37\n");
} }
void TransformTest::meshData2DRvaluePassthroughWrongFormat() { void TransformTest::meshData2DRvaluePassthroughWrongFormat() {
@ -754,6 +830,9 @@ void TransformTest::meshData2DInPlaceNotMutable() {
} }
void TransformTest::meshData2DInPlaceNoPosition() { void TransformTest::meshData2DInPlaceNoPosition() {
auto&& data = NoAttributeData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { Trade::MeshData mesh{MeshPrimitive::Points, nullptr, {
@ -762,8 +841,11 @@ void TransformTest::meshData2DInPlaceNoPosition() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
transform2DInPlace(mesh, {}, 1); transform2DInPlace(mesh, {}, data.id, data.morphTargetId);
CORRADE_COMPARE(out.str(), "MeshTools::transform2DInPlace(): the mesh has no positions with index 1\n"); if(data.morphTargetId == -1)
CORRADE_COMPARE(out.str(), "MeshTools::transform2DInPlace(): the mesh has no positions with index 1\n");
else
CORRADE_COMPARE(out.str(), "MeshTools::transform2DInPlace(): the mesh has no positions with index 0 in morph target 37\n");
} }
void TransformTest::meshData2DInPlaceWrongFormat() { void TransformTest::meshData2DInPlaceWrongFormat() {
@ -817,7 +899,7 @@ template<class T, class U, class V, class W> void TransformTest::meshData3D() {
Containers::StridedArrayView1D<const Vertex> view = vertices; Containers::StridedArrayView1D<const Vertex> view = vertices;
Containers::Array<Trade::MeshAttributeData> attributes; Containers::Array<Trade::MeshAttributeData> attributes;
if(data.id == 1) { if(data.id == 1 || data.morphTargetId != -1) {
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)});
if(data.tangents) if(data.tangents)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, VertexFormat::Vector3bNormalized, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, VertexFormat::Vector3bNormalized, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)});
@ -825,17 +907,20 @@ template<class T, class U, class V, class W> void TransformTest::meshData3D() {
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, VertexFormat::Vector3bNormalized, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, VertexFormat::Vector3bNormalized, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)});
if(data.normals) if(data.normals)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3bNormalized, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3bNormalized, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)});
} else CORRADE_COMPARE(data.id, 0); } else {
CORRADE_COMPARE(data.id, 0);
CORRADE_COMPARE(data.morphTargetId, -1);
}
arrayAppend(attributes, { arrayAppend(attributes, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, view.slice(&Vertex::position)}, Trade::MeshAttributeData{Trade::MeshAttribute::Position, view.slice(&Vertex::position), data.morphTargetId},
Trade::MeshAttributeData{Trade::meshAttributeCustom(0), view.slice(&Vertex::somethingElse)} Trade::MeshAttributeData{Trade::meshAttributeCustom(0), view.slice(&Vertex::somethingElse)}
}); });
if(data.tangents) if(data.tangents)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, data.tangents4 ? Trade::Implementation::vertexFormatFor<Math::Vector4<U>>() : Trade::Implementation::vertexFormatFor<Math::Vector3<U>>(), view.slice(&Vertex::tangent)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, data.tangents4 ? Trade::Implementation::vertexFormatFor<Math::Vector4<U>>() : Trade::Implementation::vertexFormatFor<Math::Vector3<U>>(), view.slice(&Vertex::tangent), 0, data.morphTargetId});
if(data.bitangents) if(data.bitangents)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, view.slice(&Vertex::bitangent)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, view.slice(&Vertex::bitangent), data.morphTargetId});
if(data.normals) if(data.normals)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Normal, view.slice(&Vertex::normal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Normal, view.slice(&Vertex::normal), data.morphTargetId});
Trade::MeshData mesh{MeshPrimitive::TriangleStrip, Trade::MeshData mesh{MeshPrimitive::TriangleStrip,
{}, data.indexed ? Containers::arrayView(indices) : nullptr, {}, data.indexed ? Containers::arrayView(indices) : nullptr,
@ -843,7 +928,7 @@ template<class T, class U, class V, class W> void TransformTest::meshData3D() {
{}, vertices, std::move(attributes)}; {}, vertices, std::move(attributes)};
CORRADE_COMPARE(mesh.isIndexed(), data.indexed); CORRADE_COMPARE(mesh.isIndexed(), data.indexed);
Trade::MeshData out = transform3D(mesh, data.transformation, data.id); Trade::MeshData out = transform3D(mesh, data.transformation, data.id, data.morphTargetId);
CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleStrip); CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleStrip);
/* Indices should be preserved */ /* Indices should be preserved */
@ -861,8 +946,8 @@ template<class T, class U, class V, class W> void TransformTest::meshData3D() {
TestSuite::Compare::Container); TestSuite::Compare::Container);
/* The vertices should be expanded to floats and transformed */ /* The vertices should be expanded to floats and transformed */
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id), VertexFormat::Vector3); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id, data.morphTargetId), VertexFormat::Vector3);
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Position, data.id), Containers::arrayView({ CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Position, data.id, data.morphTargetId), Containers::arrayView({
data.transformation.transformPoint({0.0f, 0.0f, -1.0f}), data.transformation.transformPoint({0.0f, 0.0f, -1.0f}),
data.transformation.transformPoint({1.0f, 0.0f, -2.0f}), data.transformation.transformPoint({1.0f, 0.0f, -2.0f}),
data.transformation.transformPoint({0.0f, 2.0f, -1.0f}) data.transformation.transformPoint({0.0f, 2.0f, -1.0f})
@ -872,15 +957,15 @@ template<class T, class U, class V, class W> void TransformTest::meshData3D() {
const Matrix3x3 normalMatrix = data.transformation.normalMatrix(); const Matrix3x3 normalMatrix = data.transformation.normalMatrix();
if(data.tangents) { if(data.tangents) {
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Tangent, data.id), data.tangents4 ? VertexFormat::Vector4 : VertexFormat::Vector3); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), data.tangents4 ? VertexFormat::Vector4 : VertexFormat::Vector3);
if(data.tangents4) if(data.tangents4)
CORRADE_COMPARE_AS(out.attribute<Vector4>(Trade::MeshAttribute::Tangent, data.id), Containers::arrayView<Vector4>({ CORRADE_COMPARE_AS(out.attribute<Vector4>(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), Containers::arrayView<Vector4>({
{normalMatrix*Vector3{0.0f, 1.0f, 0.0f}, 1.0f}, {normalMatrix*Vector3{0.0f, 1.0f, 0.0f}, 1.0f},
{normalMatrix*Vector3{1.0f, 0.0f, 0.0f}, 1.0f}, {normalMatrix*Vector3{1.0f, 0.0f, 0.0f}, 1.0f},
{normalMatrix*Vector3{0.0f, 1.0f, 0.0f}, -1.0f} {normalMatrix*Vector3{0.0f, 1.0f, 0.0f}, -1.0f}
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
else else
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Tangent, data.id), Containers::arrayView<Vector3>({ CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), Containers::arrayView<Vector3>({
normalMatrix*Vector3{0.0f, 1.0f, 0.0f}, normalMatrix*Vector3{0.0f, 1.0f, 0.0f},
normalMatrix*Vector3{1.0f, 0.0f, 0.0f}, normalMatrix*Vector3{1.0f, 0.0f, 0.0f},
normalMatrix*Vector3{0.0f, 1.0f, 0.0f} normalMatrix*Vector3{0.0f, 1.0f, 0.0f}
@ -888,8 +973,8 @@ template<class T, class U, class V, class W> void TransformTest::meshData3D() {
} }
if(data.bitangents) { if(data.bitangents) {
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Bitangent, data.id), VertexFormat::Vector3); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Bitangent, data.id, data.morphTargetId), VertexFormat::Vector3);
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Bitangent, data.id), Containers::arrayView<Vector3>({ CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Bitangent, data.id, data.morphTargetId), Containers::arrayView<Vector3>({
normalMatrix*Vector3{-1.0f, 0.0f, 0.0f}, normalMatrix*Vector3{-1.0f, 0.0f, 0.0f},
normalMatrix*Vector3{0.0f, -1.0f, 0.0f}, normalMatrix*Vector3{0.0f, -1.0f, 0.0f},
normalMatrix*Vector3{0.0f, 0.0f, -1.0f} normalMatrix*Vector3{0.0f, 0.0f, -1.0f}
@ -897,8 +982,8 @@ template<class T, class U, class V, class W> void TransformTest::meshData3D() {
} }
if(data.normals) { if(data.normals) {
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Normal, data.id), VertexFormat::Vector3); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Normal, data.id, data.morphTargetId), VertexFormat::Vector3);
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Normal, data.id), Containers::arrayView<Vector3>({ CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Normal, data.id, data.morphTargetId), Containers::arrayView<Vector3>({
normalMatrix*Vector3{0.0f, 0.0f, 1.0f}, normalMatrix*Vector3{0.0f, 0.0f, 1.0f},
normalMatrix*Vector3{0.0f, 0.0f, 1.0f}, normalMatrix*Vector3{0.0f, 0.0f, 1.0f},
normalMatrix*Vector3{1.0f, 0.0f, 0.0f} normalMatrix*Vector3{1.0f, 0.0f, 0.0f}
@ -907,6 +992,9 @@ template<class T, class U, class V, class W> void TransformTest::meshData3D() {
} }
void TransformTest::meshData3DNoPosition() { void TransformTest::meshData3DNoPosition() {
auto&& data = NoAttributeData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { Trade::MeshData mesh{MeshPrimitive::Points, nullptr, {
@ -915,8 +1003,11 @@ void TransformTest::meshData3DNoPosition() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
transform3D(mesh, {}, 1); transform3D(mesh, {}, data.id, data.morphTargetId);
CORRADE_COMPARE(out.str(), "MeshTools::transform3D(): the mesh has no positions with index 1\n"); if(data.morphTargetId == -1)
CORRADE_COMPARE(out.str(), "MeshTools::transform3D(): the mesh has no positions with index 1\n");
else
CORRADE_COMPARE(out.str(), "MeshTools::transform3D(): the mesh has no positions with index 0 in morph target 37\n");
} }
void TransformTest::meshData3DNot3D() { void TransformTest::meshData3DNot3D() {
@ -944,7 +1035,7 @@ void TransformTest::meshData3DImplementationSpecificIndexType() {
{}, vertices, {Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(vertices)}}}; {}, vertices, {Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(vertices)}}};
/* Just verify the index data get passed through with no information loss */ /* Just verify the index data get passed through with no information loss */
Trade::MeshData out = transform3D(mesh, Matrix4{}, 0, InterleaveFlag::PreserveStridedIndices); Trade::MeshData out = transform3D(mesh, Matrix4{}, 0, -1, InterleaveFlag::PreserveStridedIndices);
CORRADE_COMPARE(out.primitive(), MeshPrimitive::Points); CORRADE_COMPARE(out.primitive(), MeshPrimitive::Points);
CORRADE_COMPARE(out.indexType(), meshIndexTypeWrap(0xcaca)); CORRADE_COMPARE(out.indexType(), meshIndexTypeWrap(0xcaca));
CORRADE_COMPARE(out.indexOffset(), 2); CORRADE_COMPARE(out.indexOffset(), 2);
@ -1010,7 +1101,7 @@ void TransformTest::meshData3DRvaluePassthrough() {
}, vertices); }, vertices);
Containers::Array<Trade::MeshAttributeData> attributes; Containers::Array<Trade::MeshAttributeData> attributes;
if(data.id == 1) { if(data.id == 1 || data.morphTargetId != -1) {
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::secondaryPositionTangentBitangentNormal)});
if(data.tangents) if(data.tangents)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, VertexFormat::Vector3bNormalized, vertices.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, VertexFormat::Vector3bNormalized, vertices.slice(&Vertex::secondaryPositionTangentBitangentNormal)});
@ -1018,16 +1109,19 @@ void TransformTest::meshData3DRvaluePassthrough() {
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, VertexFormat::Vector3bNormalized, vertices.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, VertexFormat::Vector3bNormalized, vertices.slice(&Vertex::secondaryPositionTangentBitangentNormal)});
if(data.normals) if(data.normals)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3bNormalized, vertices.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3bNormalized, vertices.slice(&Vertex::secondaryPositionTangentBitangentNormal)});
} else CORRADE_COMPARE(data.id, 0); } else {
CORRADE_COMPARE(data.id, 0);
CORRADE_COMPARE(data.morphTargetId, -1);
}
arrayAppend(attributes, { arrayAppend(attributes, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)} Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position), data.morphTargetId}
}); });
if(data.tangents) if(data.tangents)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, data.tangents4 ? VertexFormat::Vector4 : VertexFormat::Vector3, vertices.slice(&Vertex::tangent)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, data.tangents4 ? VertexFormat::Vector4 : VertexFormat::Vector3, vertices.slice(&Vertex::tangent), 0, data.morphTargetId});
if(data.bitangents) if(data.bitangents)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, vertices.slice(&Vertex::bitangent)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, vertices.slice(&Vertex::bitangent), data.morphTargetId});
if(data.normals) if(data.normals)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Normal, vertices.slice(&Vertex::normal)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Normal, vertices.slice(&Vertex::normal), data.morphTargetId});
const void* originalAttributeData = attributes; const void* originalAttributeData = attributes;
Trade::MeshData mesh{MeshPrimitive::TriangleFan, Trade::MeshData mesh{MeshPrimitive::TriangleFan,
@ -1036,7 +1130,7 @@ void TransformTest::meshData3DRvaluePassthrough() {
std::move(vertexData), std::move(attributes)}; std::move(vertexData), std::move(attributes)};
const Matrix4 transformation = Matrix4::rotationX(35.0_degf); const Matrix4 transformation = Matrix4::rotationX(35.0_degf);
Trade::MeshData out = transform3D(std::move(mesh), transformation, data.id); Trade::MeshData out = transform3D(std::move(mesh), transformation, data.id, data.morphTargetId);
CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleFan); CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleFan);
/* Indices should be passed through unchanged */ /* Indices should be passed through unchanged */
@ -1048,23 +1142,23 @@ void TransformTest::meshData3DRvaluePassthrough() {
} }
/* The vertices should be expanded to floats and transformed */ /* The vertices should be expanded to floats and transformed */
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id), VertexFormat::Vector3); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id, data.morphTargetId), VertexFormat::Vector3);
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Position, data.id), Containers::arrayView({ CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Position, data.id, data.morphTargetId), Containers::arrayView({
transformation.transformPoint({0.0f, 0.0f, -1.0f}), transformation.transformPoint({0.0f, 0.0f, -1.0f}),
transformation.transformPoint({1.0f, 0.0f, -2.0f}), transformation.transformPoint({1.0f, 0.0f, -2.0f}),
transformation.transformPoint({0.0f, 2.0f, -1.0f}) transformation.transformPoint({0.0f, 2.0f, -1.0f})
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
if(data.tangents) { if(data.tangents) {
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Tangent, data.id), data.tangents4 ? VertexFormat::Vector4 : VertexFormat::Vector3); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), data.tangents4 ? VertexFormat::Vector4 : VertexFormat::Vector3);
if(data.tangents4) if(data.tangents4)
CORRADE_COMPARE_AS(out.attribute<Vector4>(Trade::MeshAttribute::Tangent, data.id), Containers::arrayView<Vector4>({ CORRADE_COMPARE_AS(out.attribute<Vector4>(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), Containers::arrayView<Vector4>({
{transformation.transformVector({0.0f, 1.0f, 0.0f}), 1.0f}, {transformation.transformVector({0.0f, 1.0f, 0.0f}), 1.0f},
{transformation.transformVector({1.0f, 0.0f, 0.0f}), 1.0f}, {transformation.transformVector({1.0f, 0.0f, 0.0f}), 1.0f},
{transformation.transformVector({0.0f, 1.0f, 0.0f}), -1.0f} {transformation.transformVector({0.0f, 1.0f, 0.0f}), -1.0f}
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
else else
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Tangent, data.id), Containers::arrayView({ CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), Containers::arrayView({
transformation.transformVector({0.0f, 1.0f, 0.0f}), transformation.transformVector({0.0f, 1.0f, 0.0f}),
transformation.transformVector({1.0f, 0.0f, 0.0f}), transformation.transformVector({1.0f, 0.0f, 0.0f}),
transformation.transformVector({0.0f, 1.0f, 0.0f}) transformation.transformVector({0.0f, 1.0f, 0.0f})
@ -1072,8 +1166,8 @@ void TransformTest::meshData3DRvaluePassthrough() {
} }
if(data.bitangents) { if(data.bitangents) {
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Bitangent, data.id), VertexFormat::Vector3); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Bitangent, data.id, data.morphTargetId), VertexFormat::Vector3);
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Bitangent, data.id), Containers::arrayView({ CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Bitangent, data.id, data.morphTargetId), Containers::arrayView({
transformation.transformVector({-1.0f, 0.0f, 0.0f}), transformation.transformVector({-1.0f, 0.0f, 0.0f}),
transformation.transformVector({0.0f, -1.0f, 0.0f}), transformation.transformVector({0.0f, -1.0f, 0.0f}),
transformation.transformVector({0.0f, 0.0f, -1.0f}) transformation.transformVector({0.0f, 0.0f, -1.0f})
@ -1081,8 +1175,8 @@ void TransformTest::meshData3DRvaluePassthrough() {
} }
if(data.normals) { if(data.normals) {
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Normal, data.id), VertexFormat::Vector3); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Normal, data.id, data.morphTargetId), VertexFormat::Vector3);
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Normal, data.id), Containers::arrayView({ CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Normal, data.id, data.morphTargetId), Containers::arrayView({
transformation.transformVector({0.0f, 0.0f, 1.0f}), transformation.transformVector({0.0f, 0.0f, 1.0f}),
transformation.transformVector({0.0f, 0.0f, 1.0f}), transformation.transformVector({0.0f, 0.0f, 1.0f}),
transformation.transformVector({1.0f, 0.0f, 0.0f}) transformation.transformVector({1.0f, 0.0f, 0.0f})
@ -1184,16 +1278,23 @@ void TransformTest::meshData3DRvaluePassthroughVertexDataNotOwned() {
} }
void TransformTest::meshData3DRvaluePassthroughNoPosition() { void TransformTest::meshData3DRvaluePassthroughNoPosition() {
auto&& data = NoAttributeData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
/* Mainly to verify there's no other accidental assertion from checking /* Mainly to verify there's no other accidental assertion from checking
vertex format, this message comes from the l-value overload */ vertex format and that the ID + morph target ID gets correctly passed
through, this message comes from the l-value overload */
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
transform3D(Trade::MeshData{MeshPrimitive::Points, nullptr, { transform3D(Trade::MeshData{MeshPrimitive::Points, nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr}, Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr},
}}, {}, 1); }}, {}, data.id, data.morphTargetId);
CORRADE_COMPARE(out.str(), "MeshTools::transform3D(): the mesh has no positions with index 1\n"); if(data.morphTargetId == -1)
CORRADE_COMPARE(out.str(), "MeshTools::transform3D(): the mesh has no positions with index 1\n");
else
CORRADE_COMPARE(out.str(), "MeshTools::transform3D(): the mesh has no positions with index 0 in morph target 37\n");
} }
void TransformTest::meshData3DRvaluePassthroughWrongFormat() { void TransformTest::meshData3DRvaluePassthroughWrongFormat() {
@ -1297,6 +1398,9 @@ void TransformTest::meshData3DInPlaceNotMutable() {
} }
void TransformTest::meshData3DInPlaceNoPosition() { void TransformTest::meshData3DInPlaceNoPosition() {
auto&& data = NoAttributeData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { Trade::MeshData mesh{MeshPrimitive::Points, nullptr, {
@ -1305,8 +1409,11 @@ void TransformTest::meshData3DInPlaceNoPosition() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
transform3DInPlace(mesh, {}, 1); transform3DInPlace(mesh, {}, data.id, data.morphTargetId);
CORRADE_COMPARE(out.str(), "MeshTools::transform3DInPlace(): the mesh has no positions with index 1\n"); if(data.morphTargetId == -1)
CORRADE_COMPARE(out.str(), "MeshTools::transform3DInPlace(): the mesh has no positions with index 1\n");
else
CORRADE_COMPARE(out.str(), "MeshTools::transform3DInPlace(): the mesh has no positions with index 0 in morph target 37\n");
} }
void TransformTest::meshData3DInPlaceWrongFormat() { void TransformTest::meshData3DInPlaceWrongFormat() {
@ -1357,11 +1464,14 @@ template<class T> void TransformTest::meshDataTextureCoordinates2D() {
Containers::StridedArrayView1D<const Vertex> view = vertices; Containers::StridedArrayView1D<const Vertex> view = vertices;
Containers::Array<Trade::MeshAttributeData> attributes; Containers::Array<Trade::MeshAttributeData> attributes;
if(data.id == 1) if(data.id == 1 || data.morphTargetId != -1)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, view.slice(&Vertex::secondaryTextureCoordinates)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, view.slice(&Vertex::secondaryTextureCoordinates)});
else CORRADE_COMPARE(data.id, 0); else {
CORRADE_COMPARE(data.id, 0);
CORRADE_COMPARE(data.morphTargetId, -1);
}
arrayAppend(attributes, { arrayAppend(attributes, {
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, view.slice(&Vertex::textureCoordinates)}, Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, view.slice(&Vertex::textureCoordinates), data.morphTargetId},
Trade::MeshAttributeData{Trade::meshAttributeCustom(0), view.slice(&Vertex::somethingElse)} Trade::MeshAttributeData{Trade::meshAttributeCustom(0), view.slice(&Vertex::somethingElse)}
}); });
@ -1371,7 +1481,7 @@ template<class T> void TransformTest::meshDataTextureCoordinates2D() {
{}, vertices, std::move(attributes)}; {}, vertices, std::move(attributes)};
CORRADE_COMPARE(mesh.isIndexed(), data.indexed); CORRADE_COMPARE(mesh.isIndexed(), data.indexed);
Trade::MeshData out = transformTextureCoordinates2D(mesh, data.transformation, data.id); Trade::MeshData out = transformTextureCoordinates2D(mesh, data.transformation, data.id, data.morphTargetId);
CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleStrip); CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleStrip);
/* Indices should be preserved */ /* Indices should be preserved */
@ -1389,8 +1499,8 @@ template<class T> void TransformTest::meshDataTextureCoordinates2D() {
TestSuite::Compare::Container); TestSuite::Compare::Container);
/* The vertices should be expanded to floats and transformed */ /* The vertices should be expanded to floats and transformed */
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::TextureCoordinates, data.id), VertexFormat::Vector2); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::TextureCoordinates, data.id, data.morphTargetId), VertexFormat::Vector2);
CORRADE_COMPARE_AS(out.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates, data.id), Containers::arrayView({ CORRADE_COMPARE_AS(out.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates, data.id, data.morphTargetId), Containers::arrayView({
data.transformation.transformPoint({0.0f, 0.0f}), data.transformation.transformPoint({0.0f, 0.0f}),
data.transformation.transformPoint({1.0f, 0.0f}), data.transformation.transformPoint({1.0f, 0.0f}),
data.transformation.transformPoint({0.0f, 2.0f}) data.transformation.transformPoint({0.0f, 2.0f})
@ -1398,6 +1508,9 @@ template<class T> void TransformTest::meshDataTextureCoordinates2D() {
} }
void TransformTest::meshDataTextureCoordinates2DNoCoordinates() { void TransformTest::meshDataTextureCoordinates2DNoCoordinates() {
auto&& data = NoAttributeData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { Trade::MeshData mesh{MeshPrimitive::Points, nullptr, {
@ -1406,8 +1519,11 @@ void TransformTest::meshDataTextureCoordinates2DNoCoordinates() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
transformTextureCoordinates2D(mesh, {}, 1); transformTextureCoordinates2D(mesh, {}, data.id, data.morphTargetId);
CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index 1\n"); if(data.morphTargetId == -1)
CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index 1\n");
else
CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index 0 in morph target 37\n");
} }
void TransformTest::meshDataTextureCoordinates2DImplementationSpecificIndexType() { void TransformTest::meshDataTextureCoordinates2DImplementationSpecificIndexType() {
@ -1422,7 +1538,7 @@ void TransformTest::meshDataTextureCoordinates2DImplementationSpecificIndexType(
{}, vertices, {Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, Containers::arrayView(vertices)}}}; {}, vertices, {Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, Containers::arrayView(vertices)}}};
/* Just verify the index data get passed through with no information loss */ /* Just verify the index data get passed through with no information loss */
Trade::MeshData out = transformTextureCoordinates2D(mesh, Matrix3{}, 0, InterleaveFlag::PreserveStridedIndices); Trade::MeshData out = transformTextureCoordinates2D(mesh, Matrix3{}, 0, -1, InterleaveFlag::PreserveStridedIndices);
CORRADE_COMPARE(out.primitive(), MeshPrimitive::Points); CORRADE_COMPARE(out.primitive(), MeshPrimitive::Points);
CORRADE_COMPARE(out.indexType(), meshIndexTypeWrap(0xcaca)); CORRADE_COMPARE(out.indexType(), meshIndexTypeWrap(0xcaca));
CORRADE_COMPARE(out.indexOffset(), 2); CORRADE_COMPARE(out.indexOffset(), 2);
@ -1471,11 +1587,14 @@ void TransformTest::meshDataTextureCoordinates2DRvaluePassthrough() {
}, vertices); }, vertices);
Containers::Array<Trade::MeshAttributeData> attributes; Containers::Array<Trade::MeshAttributeData> attributes;
if(data.id == 1) if(data.id == 1 || data.morphTargetId != -1)
arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::secondaryTextureCoordinates)}); arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::secondaryTextureCoordinates)});
else CORRADE_COMPARE(data.id, 0); else {
CORRADE_COMPARE(data.id, 0);
CORRADE_COMPARE(data.morphTargetId, -1);
}
arrayAppend(attributes, { arrayAppend(attributes, {
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates)} Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates), data.morphTargetId}
}); });
const void* originalAttributeData = attributes; const void* originalAttributeData = attributes;
@ -1485,7 +1604,7 @@ void TransformTest::meshDataTextureCoordinates2DRvaluePassthrough() {
std::move(vertexData), std::move(attributes)}; std::move(vertexData), std::move(attributes)};
const Matrix3 transformation = Matrix3::rotation(35.0_degf); const Matrix3 transformation = Matrix3::rotation(35.0_degf);
Trade::MeshData out = transformTextureCoordinates2D(std::move(mesh), transformation, data.id); Trade::MeshData out = transformTextureCoordinates2D(std::move(mesh), transformation, data.id, data.morphTargetId);
CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleFan); CORRADE_COMPARE(out.primitive(), MeshPrimitive::TriangleFan);
/* Indices should be passed through unchanged */ /* Indices should be passed through unchanged */
@ -1497,8 +1616,8 @@ void TransformTest::meshDataTextureCoordinates2DRvaluePassthrough() {
} }
/* The vertices should be expanded to floats and transformed */ /* The vertices should be expanded to floats and transformed */
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::TextureCoordinates, data.id), VertexFormat::Vector2); CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::TextureCoordinates, data.id, data.morphTargetId), VertexFormat::Vector2);
CORRADE_COMPARE_AS(out.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates, data.id), Containers::arrayView({ CORRADE_COMPARE_AS(out.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates, data.id, data.morphTargetId), Containers::arrayView({
transformation.transformPoint({0.0f, 0.0f}), transformation.transformPoint({0.0f, 0.0f}),
transformation.transformPoint({1.0f, 0.0f}), transformation.transformPoint({1.0f, 0.0f}),
transformation.transformPoint({0.0f, 2.0f}) transformation.transformPoint({0.0f, 2.0f})
@ -1599,16 +1718,23 @@ void TransformTest::meshDataTextureCoordinates2DRvaluePassthroughVertexDataNotOw
} }
void TransformTest::meshDataTextureCoordinates2DRvaluePassthroughNoCoordinates() { void TransformTest::meshDataTextureCoordinates2DRvaluePassthroughNoCoordinates() {
auto&& data = NoAttributeData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
/* Mainly to verify there's no other accidental assertion from checking /* Mainly to verify there's no other accidental assertion from checking
vertex format, this message comes from the l-value overload */ vertex format and that the ID + morph target ID gets correctly passed
through, this message comes from the l-value overload */
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
transformTextureCoordinates2D(Trade::MeshData{MeshPrimitive::Points, nullptr, { transformTextureCoordinates2D(Trade::MeshData{MeshPrimitive::Points, nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr}, Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr},
}}, {}, 1); }}, {}, data.id, data.morphTargetId);
CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index 1\n"); if(data.morphTargetId == -1)
CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index 1\n");
else
CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index 0 in morph target 37\n");
} }
void TransformTest::meshDataTextureCoordinates2DRvaluePassthroughWrongFormat() { void TransformTest::meshDataTextureCoordinates2DRvaluePassthroughWrongFormat() {
@ -1657,6 +1783,9 @@ void TransformTest::meshDataTextureCoordinates2DInPlaceNotMutable() {
} }
void TransformTest::meshDataTextureCoordinates2DInPlaceNoCoordinates() { void TransformTest::meshDataTextureCoordinates2DInPlaceNoCoordinates() {
auto&& data = NoAttributeData[testCaseInstanceId()];
setTestCaseDescription(data.name);
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { Trade::MeshData mesh{MeshPrimitive::Points, nullptr, {
@ -1665,8 +1794,11 @@ void TransformTest::meshDataTextureCoordinates2DInPlaceNoCoordinates() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
transformTextureCoordinates2DInPlace(mesh, {}, 1); transformTextureCoordinates2DInPlace(mesh, {}, data.id, data.morphTargetId);
CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2DInPlace(): the mesh has no texture coordinates with index 1\n"); if(data.morphTargetId == -1)
CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2DInPlace(): the mesh has no texture coordinates with index 1\n");
else
CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2DInPlace(): the mesh has no texture coordinates with index 0 in morph target 37\n");
} }
void TransformTest::meshDataTextureCoordinates2DInPlaceWrongFormat() { void TransformTest::meshDataTextureCoordinates2DInPlaceWrongFormat() {

175
src/Magnum/MeshTools/Transform.cpp

@ -33,11 +33,16 @@
namespace Magnum { namespace MeshTools { namespace Magnum { namespace MeshTools {
Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) { Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const Int morphTargetId, const InterleaveFlags flags) {
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId);
CORRADE_ASSERT(positionAttributeId, #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform2D(): the mesh has no positions with index" << id, "MeshTools::transform2D(): the mesh has no positions with index" << id,
(Trade::MeshData{MeshPrimitive::Triangles, 0})); (Trade::MeshData{MeshPrimitive::Triangles, 0}));
else CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform2D(): the mesh has no positions with index" << id << "in morph target" << morphTargetId,
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
#endif
const VertexFormat positionAttributeFormat = mesh.attributeFormat(*positionAttributeId); const VertexFormat positionAttributeFormat = mesh.attributeFormat(*positionAttributeId);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(positionAttributeFormat), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(positionAttributeFormat),
"MeshTools::transform2D(): positions have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(positionAttributeFormat)), "MeshTools::transform2D(): positions have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(positionAttributeFormat)),
@ -57,7 +62,7 @@ Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transfor
/* If the position attribute isn't in a desired format, replace it with an /* If the position attribute isn't in a desired format, replace it with an
empty placeholder that we'll unpack the data into */ empty placeholder that we'll unpack the data into */
if(positionAttributeFormat != VertexFormat::Vector2) if(positionAttributeFormat != VertexFormat::Vector2)
attributes[*positionAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector2, nullptr}; attributes[*positionAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector2, nullptr, 0, morphTargetId};
/* Create the output mesh, making more room for the full formats if /* Create the output mesh, making more room for the full formats if
necessary */ necessary */
@ -67,38 +72,54 @@ Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transfor
/* If the position attribute wasn't in a desired format, unpack it */ /* If the position attribute wasn't in a desired format, unpack it */
if(positionAttributeFormat != VertexFormat::Vector2) if(positionAttributeFormat != VertexFormat::Vector2)
mesh.positions2DInto(out.mutableAttribute<Vector2>(*positionAttributeId), id); mesh.positions2DInto(out.mutableAttribute<Vector2>(*positionAttributeId), id, morphTargetId);
/* Delegate to the in-place implementation and return */ /* Delegate to the in-place implementation and return */
transform2DInPlace(out, transformation, id); transform2DInPlace(out, transformation, id, morphTargetId);
return out; return out;
} }
Trade::MeshData transform2D(Trade::MeshData&& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) { #ifdef MAGNUM_BUILD_DEPRECATED
Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
return transform2D(mesh, transformation, id, -1, flags);
}
#endif
Trade::MeshData transform2D(Trade::MeshData&& mesh, const Matrix3& transformation, const UnsignedInt id, const Int morphTargetId, const InterleaveFlags flags) {
/* Perform the operation in-place, if we can transfer the ownership and /* Perform the operation in-place, if we can transfer the ownership and
have positions in the right format already. Explicitly checking for have positions in the right format already. Explicitly checking for
presence of the position attribute so we don't need to duplicate the presence of the position attribute so we don't need to duplicate the
assert here again. */ assert here again. */
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId);
if((mesh.indexDataFlags() & Trade::DataFlag::Owned) && if((mesh.indexDataFlags() & Trade::DataFlag::Owned) &&
(mesh.vertexDataFlags() & Trade::DataFlag::Owned) && (mesh.vertexDataFlags() & Trade::DataFlag::Owned) &&
positionAttributeId && mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector2 positionAttributeId && mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector2
) { ) {
transform2DInPlace(mesh, transformation, id); transform2DInPlace(mesh, transformation, id, morphTargetId);
return std::move(mesh); return std::move(mesh);
} }
/* Otherwise delegate to the function that does all the copying and format /* Otherwise delegate to the function that does all the copying and format
expansion */ expansion */
return transform2D(mesh, transformation, id, flags); return transform2D(mesh, transformation, id, morphTargetId, flags);
}
#ifdef MAGNUM_BUILD_DEPRECATED
Trade::MeshData transform2D(Trade::MeshData&& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
return transform2D(std::move(mesh), transformation, id, -1, flags);
} }
#endif
void transform2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id) { void transform2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const Int morphTargetId) {
CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable, CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable,
"MeshTools::transform2DInPlace(): vertex data not mutable", ); "MeshTools::transform2DInPlace(): vertex data not mutable", );
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId);
CORRADE_ASSERT(positionAttributeId, #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform2DInPlace(): the mesh has no positions with index" << id, ); "MeshTools::transform2DInPlace(): the mesh has no positions with index" << id, );
else CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform2DInPlace(): the mesh has no positions with index" << id << "in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector2, CORRADE_ASSERT(mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector2,
"MeshTools::transform2DInPlace(): expected" << VertexFormat::Vector2 << "positions but got" << mesh.attributeFormat(*positionAttributeId), ); "MeshTools::transform2DInPlace(): expected" << VertexFormat::Vector2 << "positions but got" << mesh.attributeFormat(*positionAttributeId), );
@ -107,11 +128,16 @@ void transform2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, co
position = transformation.transformPoint(position); position = transformation.transformPoint(position);
} }
Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, const UnsignedInt id, const InterleaveFlags flags) { Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, const UnsignedInt id, const Int morphTargetId, const InterleaveFlags flags) {
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId);
CORRADE_ASSERT(positionAttributeId, #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform3D(): the mesh has no positions with index" << id, "MeshTools::transform3D(): the mesh has no positions with index" << id,
(Trade::MeshData{MeshPrimitive::Triangles, 0})); (Trade::MeshData{MeshPrimitive::Triangles, 0}));
else CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform3D(): the mesh has no positions with index" << id << "in morph target" << morphTargetId,
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
#endif
const VertexFormat positionAttributeFormat = mesh.attributeFormat(*positionAttributeId); const VertexFormat positionAttributeFormat = mesh.attributeFormat(*positionAttributeId);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(positionAttributeFormat), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(positionAttributeFormat),
"MeshTools::transform3D(): positions have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(positionAttributeFormat)), "MeshTools::transform3D(): positions have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(positionAttributeFormat)),
@ -119,9 +145,9 @@ Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transfor
CORRADE_ASSERT(vertexFormatComponentCount(positionAttributeFormat) == 3, CORRADE_ASSERT(vertexFormatComponentCount(positionAttributeFormat) == 3,
"MeshTools::transform3D(): expected 3D positions but got" << positionAttributeFormat, "MeshTools::transform3D(): expected 3D positions but got" << positionAttributeFormat,
(Trade::MeshData{MeshPrimitive::Triangles, 0})); (Trade::MeshData{MeshPrimitive::Triangles, 0}));
const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id); const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id, morphTargetId);
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id); const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id, morphTargetId);
const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id); const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id, morphTargetId);
/* Copy original attributes to a mutable array so we can update the /* Copy original attributes to a mutable array so we can update the
position attribute format, if needed. Not using Utility::copy() here as position attribute format, if needed. Not using Utility::copy() here as
@ -134,7 +160,7 @@ Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transfor
/* If the position/TBN attributes aren't in a desired format, replace them /* If the position/TBN attributes aren't in a desired format, replace them
with an empty placeholder that we'll unpack the data into */ with an empty placeholder that we'll unpack the data into */
if(positionAttributeFormat != VertexFormat::Vector3) if(positionAttributeFormat != VertexFormat::Vector3)
attributes[*positionAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr}; attributes[*positionAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr, 0, morphTargetId};
VertexFormat tangentAttributeFormat{}; VertexFormat tangentAttributeFormat{};
VertexFormat desiredTangentVertexFormat{}; VertexFormat desiredTangentVertexFormat{};
if(tangentAttributeId) { if(tangentAttributeId) {
@ -145,7 +171,7 @@ Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transfor
desiredTangentVertexFormat = vertexFormatComponentCount(mesh.attributeFormat(*tangentAttributeId)) == 4 ? desiredTangentVertexFormat = vertexFormatComponentCount(mesh.attributeFormat(*tangentAttributeId)) == 4 ?
VertexFormat::Vector4 : VertexFormat::Vector3; VertexFormat::Vector4 : VertexFormat::Vector3;
if(tangentAttributeFormat != desiredTangentVertexFormat) if(tangentAttributeFormat != desiredTangentVertexFormat)
attributes[*tangentAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, desiredTangentVertexFormat, nullptr}; attributes[*tangentAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, desiredTangentVertexFormat, nullptr, 0, morphTargetId};
} }
VertexFormat bitangentAttributeFormat{}; VertexFormat bitangentAttributeFormat{};
if(bitangentAttributeId) { if(bitangentAttributeId) {
@ -154,7 +180,7 @@ Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transfor
"MeshTools::transform3D(): bitangents have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(bitangentAttributeFormat)), "MeshTools::transform3D(): bitangents have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(bitangentAttributeFormat)),
(Trade::MeshData{MeshPrimitive::Points, 0})); (Trade::MeshData{MeshPrimitive::Points, 0}));
if(bitangentAttributeFormat != VertexFormat::Vector3) if(bitangentAttributeFormat != VertexFormat::Vector3)
attributes[*bitangentAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, VertexFormat::Vector3, nullptr}; attributes[*bitangentAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, VertexFormat::Vector3, nullptr, 0, morphTargetId};
} }
VertexFormat normalAttributeFormat{}; VertexFormat normalAttributeFormat{};
if(normalAttributeId) { if(normalAttributeId) {
@ -163,7 +189,7 @@ Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transfor
"MeshTools::transform3D(): normals have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(normalAttributeFormat)), "MeshTools::transform3D(): normals have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(normalAttributeFormat)),
(Trade::MeshData{MeshPrimitive::Points, 0})); (Trade::MeshData{MeshPrimitive::Points, 0}));
if(normalAttributeFormat != VertexFormat::Vector3) if(normalAttributeFormat != VertexFormat::Vector3)
attributes[*normalAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3, nullptr}; attributes[*normalAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3, nullptr, 0, morphTargetId};
} }
/* Create the output mesh, making more room for the full formats if /* Create the output mesh, making more room for the full formats if
@ -174,34 +200,40 @@ Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transfor
/* If the position/TBN attributes weren't in a desired format, unpack them */ /* If the position/TBN attributes weren't in a desired format, unpack them */
if(positionAttributeFormat != VertexFormat::Vector3) if(positionAttributeFormat != VertexFormat::Vector3)
mesh.positions3DInto(out.mutableAttribute<Vector3>(*positionAttributeId), id); mesh.positions3DInto(out.mutableAttribute<Vector3>(*positionAttributeId), id, morphTargetId);
if(tangentAttributeId && tangentAttributeFormat != desiredTangentVertexFormat) { if(tangentAttributeId && tangentAttributeFormat != desiredTangentVertexFormat) {
if(desiredTangentVertexFormat == VertexFormat::Vector4) { if(desiredTangentVertexFormat == VertexFormat::Vector4) {
mesh.tangentsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::xyz), id); mesh.tangentsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::xyz), id, morphTargetId);
mesh.bitangentSignsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::w), id); mesh.bitangentSignsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::w), id, morphTargetId);
} else { } else {
mesh.tangentsInto(out.mutableAttribute<Vector3>(*tangentAttributeId), id); mesh.tangentsInto(out.mutableAttribute<Vector3>(*tangentAttributeId), id, morphTargetId);
} }
} }
if(bitangentAttributeId && bitangentAttributeFormat != VertexFormat::Vector3) if(bitangentAttributeId && bitangentAttributeFormat != VertexFormat::Vector3)
mesh.bitangentsInto(out.mutableAttribute<Vector3>(*bitangentAttributeId), id); mesh.bitangentsInto(out.mutableAttribute<Vector3>(*bitangentAttributeId), id, morphTargetId);
if(normalAttributeId && normalAttributeFormat != VertexFormat::Vector3) if(normalAttributeId && normalAttributeFormat != VertexFormat::Vector3)
mesh.normalsInto(out.mutableAttribute<Vector3>(*normalAttributeId), id); mesh.normalsInto(out.mutableAttribute<Vector3>(*normalAttributeId), id, morphTargetId);
/* Delegate to the in-place implementation and return */ /* Delegate to the in-place implementation and return */
transform3DInPlace(out, transformation, id); transform3DInPlace(out, transformation, id, morphTargetId);
return out; return out;
} }
Trade::MeshData transform3D(Trade::MeshData&& mesh, const Matrix4& transformation, const UnsignedInt id, const InterleaveFlags flags) { #ifdef MAGNUM_BUILD_DEPRECATED
Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, const UnsignedInt id, const InterleaveFlags flags) {
return transform3D(mesh, transformation, id, -1, flags);
}
#endif
Trade::MeshData transform3D(Trade::MeshData&& mesh, const Matrix4& transformation, const UnsignedInt id, const Int morphTargetId, const InterleaveFlags flags) {
/* Perform the operation in-place, if we can transfer the ownership and /* Perform the operation in-place, if we can transfer the ownership and
have positions in the right format already. Explicitly checking for have positions in the right format already. Explicitly checking for
presence of the position attribute so we don't need to duplicate the presence of the position attribute so we don't need to duplicate the
assert here again. */ assert here again. */
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId);
const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id); const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id, morphTargetId);
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id); const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id, morphTargetId);
const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id); const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id, morphTargetId);
if((mesh.indexDataFlags() & Trade::DataFlag::Owned) && if((mesh.indexDataFlags() & Trade::DataFlag::Owned) &&
(mesh.vertexDataFlags() & Trade::DataFlag::Owned) && (mesh.vertexDataFlags() & Trade::DataFlag::Owned) &&
positionAttributeId && mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector3 && positionAttributeId && mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector3 &&
@ -209,31 +241,41 @@ Trade::MeshData transform3D(Trade::MeshData&& mesh, const Matrix4& transformatio
(!bitangentAttributeId || mesh.attributeFormat(*bitangentAttributeId) == VertexFormat::Vector3) && (!bitangentAttributeId || mesh.attributeFormat(*bitangentAttributeId) == VertexFormat::Vector3) &&
(!normalAttributeId || mesh.attributeFormat(*normalAttributeId) == VertexFormat::Vector3) (!normalAttributeId || mesh.attributeFormat(*normalAttributeId) == VertexFormat::Vector3)
) { ) {
transform3DInPlace(mesh, transformation, id); transform3DInPlace(mesh, transformation, id, morphTargetId);
return std::move(mesh); return std::move(mesh);
} }
/* Otherwise delegate to the function that does all the copying and format /* Otherwise delegate to the function that does all the copying and format
expansion */ expansion */
return transform3D(mesh, transformation, id, flags); return transform3D(mesh, transformation, id, morphTargetId, flags);
}
#ifdef MAGNUM_BUILD_DEPRECATED
Trade::MeshData transform3D(Trade::MeshData&& mesh, const Matrix4& transformation, const UnsignedInt id, const InterleaveFlags flags) {
return transform3D(std::move(mesh), transformation, id, -1, flags);
} }
#endif
void transform3DInPlace(Trade::MeshData& mesh, const Matrix4& transformation, const UnsignedInt id) { void transform3DInPlace(Trade::MeshData& mesh, const Matrix4& transformation, const UnsignedInt id, const Int morphTargetId) {
CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable, CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable,
"MeshTools::transform3DInPlace(): vertex data not mutable", ); "MeshTools::transform3DInPlace(): vertex data not mutable", );
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId);
CORRADE_ASSERT(positionAttributeId, #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform3DInPlace(): the mesh has no positions with index" << id, ); "MeshTools::transform3DInPlace(): the mesh has no positions with index" << id, );
else CORRADE_ASSERT(positionAttributeId,
"MeshTools::transform3DInPlace(): the mesh has no positions with index" << id << "in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector3, CORRADE_ASSERT(mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector3,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "positions but got" << mesh.attributeFormat(*positionAttributeId), ); "MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "positions but got" << mesh.attributeFormat(*positionAttributeId), );
const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id); const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id, morphTargetId);
const VertexFormat tangentAttributeFormat = tangentAttributeId ? mesh.attributeFormat(*tangentAttributeId) : VertexFormat{}; const VertexFormat tangentAttributeFormat = tangentAttributeId ? mesh.attributeFormat(*tangentAttributeId) : VertexFormat{};
CORRADE_ASSERT(!tangentAttributeId || tangentAttributeFormat == VertexFormat::Vector3 || tangentAttributeFormat == VertexFormat::Vector4, CORRADE_ASSERT(!tangentAttributeId || tangentAttributeFormat == VertexFormat::Vector3 || tangentAttributeFormat == VertexFormat::Vector4,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "or" << VertexFormat::Vector4 << "tangents but got" << mesh.attributeFormat(*tangentAttributeId), ); "MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "or" << VertexFormat::Vector4 << "tangents but got" << mesh.attributeFormat(*tangentAttributeId), );
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id); const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id, morphTargetId);
CORRADE_ASSERT(!bitangentAttributeId || mesh.attributeFormat(*bitangentAttributeId) == VertexFormat::Vector3, CORRADE_ASSERT(!bitangentAttributeId || mesh.attributeFormat(*bitangentAttributeId) == VertexFormat::Vector3,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "bitangents but got" << mesh.attributeFormat(*bitangentAttributeId), ); "MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "bitangents but got" << mesh.attributeFormat(*bitangentAttributeId), );
const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id); const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id, morphTargetId);
CORRADE_ASSERT(!normalAttributeId || mesh.attributeFormat(*normalAttributeId) == VertexFormat::Vector3, CORRADE_ASSERT(!normalAttributeId || mesh.attributeFormat(*normalAttributeId) == VertexFormat::Vector3,
"MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "normals but got" << mesh.attributeFormat(*normalAttributeId), ); "MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "normals but got" << mesh.attributeFormat(*normalAttributeId), );
@ -265,11 +307,16 @@ void transform3DInPlace(Trade::MeshData& mesh, const Matrix4& transformation, co
normal = normalMatrix*normal; normal = normalMatrix*normal;
} }
Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) { Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const Int morphTargetId, const InterleaveFlags flags) {
const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id); const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id, morphTargetId);
CORRADE_ASSERT(textureCoordinateAttributeId, #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(textureCoordinateAttributeId,
"MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index" << id, "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index" << id,
(Trade::MeshData{MeshPrimitive::Triangles, 0})); (Trade::MeshData{MeshPrimitive::Triangles, 0}));
else CORRADE_ASSERT(textureCoordinateAttributeId,
"MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index" << id << "in morph target" << morphTargetId,
(Trade::MeshData{MeshPrimitive::Triangles, 0}));
#endif
const VertexFormat textureCoordinateAttributeFormat = mesh.attributeFormat(*textureCoordinateAttributeId); const VertexFormat textureCoordinateAttributeFormat = mesh.attributeFormat(*textureCoordinateAttributeId);
CORRADE_ASSERT(!isVertexFormatImplementationSpecific(textureCoordinateAttributeFormat), CORRADE_ASSERT(!isVertexFormatImplementationSpecific(textureCoordinateAttributeFormat),
"MeshTools::transformTextureCoordinates2D(): texture coordinates have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(textureCoordinateAttributeFormat)), "MeshTools::transformTextureCoordinates2D(): texture coordinates have an implementation-specific format" << reinterpret_cast<void*>(vertexFormatUnwrap(textureCoordinateAttributeFormat)),
@ -286,7 +333,7 @@ Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const
/* If the position attribute isn't in a desired format, replace it with an /* If the position attribute isn't in a desired format, replace it with an
empty placeholder that we'll unpack the data into */ empty placeholder that we'll unpack the data into */
if(textureCoordinateAttributeFormat != VertexFormat::Vector2) if(textureCoordinateAttributeFormat != VertexFormat::Vector2)
attributes[*textureCoordinateAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr}; attributes[*textureCoordinateAttributeId] = Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr, 0, morphTargetId};
/* Create the output mesh, making more room for the full formats if /* Create the output mesh, making more room for the full formats if
necessary */ necessary */
@ -296,38 +343,54 @@ Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const
/* If the position attribute wasn't in a desired format, unpack it */ /* If the position attribute wasn't in a desired format, unpack it */
if(mesh.attributeFormat(*textureCoordinateAttributeId) != VertexFormat::Vector2) if(mesh.attributeFormat(*textureCoordinateAttributeId) != VertexFormat::Vector2)
mesh.textureCoordinates2DInto(out.mutableAttribute<Vector2>(*textureCoordinateAttributeId), id); mesh.textureCoordinates2DInto(out.mutableAttribute<Vector2>(*textureCoordinateAttributeId), id, morphTargetId);
/* Delegate to the in-place implementation and return */ /* Delegate to the in-place implementation and return */
transformTextureCoordinates2DInPlace(out, transformation, id); transformTextureCoordinates2DInPlace(out, transformation, id, morphTargetId);
return out; return out;
} }
Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) { #ifdef MAGNUM_BUILD_DEPRECATED
Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
return transformTextureCoordinates2D(mesh, transformation, id, -1, flags);
}
#endif
Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& mesh, const Matrix3& transformation, const UnsignedInt id, const Int morphTargetId, const InterleaveFlags flags) {
/* Perform the operation in-place, if we can transfer the ownership and /* Perform the operation in-place, if we can transfer the ownership and
have positions in the right format already. Explicitly checking for have positions in the right format already. Explicitly checking for
presence of the position attribute so we don't need to duplicate the presence of the position attribute so we don't need to duplicate the
assert here again. */ assert here again. */
const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id); const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id, morphTargetId);
if((mesh.indexDataFlags() & Trade::DataFlag::Owned) && if((mesh.indexDataFlags() & Trade::DataFlag::Owned) &&
(mesh.vertexDataFlags() & Trade::DataFlag::Owned) && (mesh.vertexDataFlags() & Trade::DataFlag::Owned) &&
textureCoordinateAttributeId && mesh.attributeFormat(*textureCoordinateAttributeId) == VertexFormat::Vector2 textureCoordinateAttributeId && mesh.attributeFormat(*textureCoordinateAttributeId) == VertexFormat::Vector2
) { ) {
transformTextureCoordinates2DInPlace(mesh, transformation, id); transformTextureCoordinates2DInPlace(mesh, transformation, id, morphTargetId);
return std::move(mesh); return std::move(mesh);
} }
/* Otherwise delegate to the function that does all the copying and format /* Otherwise delegate to the function that does all the copying and format
expansion */ expansion */
return transformTextureCoordinates2D(mesh, transformation, id, flags); return transformTextureCoordinates2D(mesh, transformation, id, morphTargetId, flags);
}
#ifdef MAGNUM_BUILD_DEPRECATED
Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) {
return transformTextureCoordinates2D(std::move(mesh), transformation, id, -1, flags);
} }
#endif
void transformTextureCoordinates2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id) { void transformTextureCoordinates2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const Int morphTargetId) {
CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable, CORRADE_ASSERT(mesh.vertexDataFlags() & Trade::DataFlag::Mutable,
"MeshTools::transformTextureCoordinates2DInPlace(): vertex data not mutable", ); "MeshTools::transformTextureCoordinates2DInPlace(): vertex data not mutable", );
const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id); const Containers::Optional<UnsignedInt> textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id, morphTargetId);
CORRADE_ASSERT(textureCoordinateAttributeId, #ifndef CORRADE_NO_ASSERT
if(morphTargetId == -1) CORRADE_ASSERT(textureCoordinateAttributeId,
"MeshTools::transformTextureCoordinates2DInPlace(): the mesh has no texture coordinates with index" << id, ); "MeshTools::transformTextureCoordinates2DInPlace(): the mesh has no texture coordinates with index" << id, );
else CORRADE_ASSERT(textureCoordinateAttributeId,
"MeshTools::transformTextureCoordinates2DInPlace(): the mesh has no texture coordinates with index" << id << "in morph target" << morphTargetId, );
#endif
CORRADE_ASSERT(mesh.attributeFormat(*textureCoordinateAttributeId) == VertexFormat::Vector2, CORRADE_ASSERT(mesh.attributeFormat(*textureCoordinateAttributeId) == VertexFormat::Vector2,
"MeshTools::transformTextureCoordinates2DInPlace(): expected" << VertexFormat::Vector2 << "texture coordinates but got" << mesh.attributeFormat(*textureCoordinateAttributeId), ); "MeshTools::transformTextureCoordinates2DInPlace(): expected" << VertexFormat::Vector2 << "texture coordinates but got" << mesh.attributeFormat(*textureCoordinateAttributeId), );

184
src/Magnum/MeshTools/Transform.h

@ -149,15 +149,16 @@ template<class T, class U> U transformPoints(const T& transformation, U vectors)
@m_since_latest @m_since_latest
Expects that the mesh contains a two-dimensional Expects that the mesh contains a two-dimensional
@ref Trade::MeshAttribute::Position with index @p id and that the attribute @ref Trade::MeshAttribute::Position with index @p id (and in morph target
does not have an implementation-specific format. To avoid data loss with packed @p morphTargetId if not @cpp -1 @ce) and that the attribute does not have an
types, the positions are converted to @ref VertexFormat::Vector2 if not implementation-specific format. To avoid data loss with packed types, the positions are converted to @ref VertexFormat::Vector2 if not
already. In that case the data layouting is done by @ref interleavedLayout() already. In that case the data layouting is done by @ref interleavedLayout()
with the @p flags parameter propagated to it, see its documentation for with the @p flags parameter propagated to it, see its documentation for
detailed behavior description. Other attributes, position attributes other than detailed behavior description. Other attributes, position attributes other than
@p id, and indices (if any) are passed through untouched. @p id or with different @p morphTargetId, and indices (if any) are passed
through untouched.
See also @ref transform2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, InterleaveFlags) See also @ref transform2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
for a potentially more efficient operation instead of always performing a full for a potentially more efficient operation instead of always performing a full
copy, you can also do an in-place transformation using @ref transform2DInPlace(). copy, you can also do an in-place transformation using @ref transform2DInPlace().
@see @ref transform3D(), @ref transformTextureCoordinates2D(), @see @ref transform3D(), @ref transformTextureCoordinates2D(),
@ -165,57 +166,77 @@ copy, you can also do an in-place transformation using @ref transform2DInPlace()
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const, @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const,
@ref isVertexFormatImplementationSpecific() @ref isVertexFormatImplementationSpecific()
*/ */
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes); MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, Int morphTargetId = -1, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief transform2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
@m_deprecated_since_latest Use @ref transform2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
instead.
*/
CORRADE_DEPRECATED("use transform2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, Int, InterleaveFlags) instead") MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id, InterleaveFlags flags);
#endif
/** /**
@brief Transform 2D positions in a mesh data @brief Transform 2D positions in a mesh data
@m_since_latest @m_since_latest
Compared to @ref transform2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, InterleaveFlags) Compared to @ref transform2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
this function can can perform the transformation in-place, transferring the this function can can perform the transformation in-place, transferring the
data ownership to the returned instance, if both vertex and index data is data ownership to the returned instance, if both vertex and index data is
owned, vertex data is mutable and the positions with index @p id are owned, vertex data is mutable and the positions with index @p id in
@ref VertexFormat::Vector2. @p morphTargetId are @ref VertexFormat::Vector2.
*/
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(Trade::MeshData&& mesh, const Matrix3& transformation, UnsignedInt id = 0, Int morphTargetId = -1, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief transform2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
@m_deprecated_since_latest Use @ref transform2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
instead.
*/ */
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(Trade::MeshData&& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes); CORRADE_DEPRECATED("use transform2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Int, InterleaveFlags) instead") MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform2D(Trade::MeshData&& mesh, const Matrix3& transformation, UnsignedInt id, InterleaveFlags flags);
#endif
/** /**
@brief Transform 2D positions in a mesh data in-place @brief Transform 2D positions in a mesh data in-place
@m_since_latest @m_since_latest
Expects that the mesh has mutable vertex data and contains a two-dimensional Expects that the mesh has mutable vertex data and contains a two-dimensional
@ref Trade::MeshAttribute::Position with index @p id. To avoid data loss with @ref Trade::MeshAttribute::Position with index @p id (and in morph target
packed types, the in-place operation requires the position type to be @p morphTargetId if not @cpp -1 @ce). To avoid data loss with packed types, the
@ref VertexFormat::Vector2 --- if you can't guarantee that, use in-place operation requires the position type to be @ref VertexFormat::Vector2
@ref transform2D() instead. Other attributes, position attributes other than --- if you can't guarantee that, use @ref transform2D() instead. Other
@p id, and indices (if any) are left untouched. attributes, position attributes other than @p id or with different
@p morphTargetId, and indices (if any) are left untouched.
@see @ref transform3DInPlace(), @ref transformTextureCoordinates2DInPlace(), @see @ref transform3DInPlace(), @ref transformTextureCoordinates2DInPlace(),
@ref Trade::MeshData::vertexDataFlags(), @ref Trade::MeshData::vertexDataFlags(),
@ref Trade::MeshData::attributeCount(MeshAttribute, Int) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const
*/ */
MAGNUM_MESHTOOLS_EXPORT void transform2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0); MAGNUM_MESHTOOLS_EXPORT void transform2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, Int morphTargetId = -1);
/** /**
@brief Transform 3D positions, normals, tangents and bitangents in a mesh data @brief Transform 3D positions, normals, tangents and bitangents in a mesh data
@m_since_latest @m_since_latest
Expects that the mesh contains a three-dimensional Expects that the mesh contains a three-dimensional
@ref Trade::MeshAttribute::Position with index @p id. If @ref Trade::MeshAttribute::Position with index @p id (and in morph target
@ref Trade::MeshAttribute::Normal, @ref Trade::MeshAttribute::Tangent or @p morphTargetId if not @cpp -1 @ce). If @ref Trade::MeshAttribute::Normal,
@ref Trade::MeshAttribute::Bitangent with index @p id are present as well, @ref Trade::MeshAttribute::Tangent or @ref Trade::MeshAttribute::Bitangent with
those get transformed with @ref Matrix4::normalMatrix() extracted out of index @p id in @p morphTargetId are present as well, those get transformed with
@p transformation. All these attributes are expected to not have an @ref Matrix4::normalMatrix() extracted out of @p transformation. All these
implementation-specific format. To avoid data loss with packed types, the attributes are expected to not have an implementation-specific format. To avoid
positions, normals and bitangents are converted to @ref VertexFormat::Vector3 data loss with packed types, the positions, normals and bitangents are
if not already, tangents to either @ref VertexFormat::Vector3 or converted to @ref VertexFormat::Vector3 if not already, tangents to either
@ref VertexFormat::Vector4 if not already. In that case the data layouting is @ref VertexFormat::Vector3 or @ref VertexFormat::Vector4 if not already. In
done by @ref interleavedLayout() with the @p flags parameter propagated to it, that case the data layouting is done by @ref interleavedLayout() with the
see its documentation for detailed behavior description. Other attributes, @p flags parameter propagated to it, see its documentation for detailed
additional position/TBN attributes other than @p id, and indices (if any) are behavior description. Other attributes, additional position/TBN attributes
other than @p id or with different @p morphTargetId, and indices (if any) are
passed through untouched. passed through untouched.
See also @ref transform3D(Trade::MeshData&&, const Matrix4&, UnsignedInt, InterleaveFlags) See also @ref transform3D(Trade::MeshData&&, const Matrix4&, UnsignedInt, Int, InterleaveFlags)
for a potentially more efficient operation instead of always performing a full for a potentially more efficient operation instead of always performing a full
copy, you can also do an in-place transformation using @ref transform3DInPlace(). copy, you can also do an in-place transformation using @ref transform3DInPlace().
@see @ref transform2D(), @ref transformTextureCoordinates2D(), @see @ref transform2D(), @ref transformTextureCoordinates2D(),
@ -223,56 +244,78 @@ copy, you can also do an in-place transformation using @ref transform3DInPlace()
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const, @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const,
@ref isVertexFormatImplementationSpecific() @ref isVertexFormatImplementationSpecific()
*/ */
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes); MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0, Int morphTargetId = -1, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief transform3D(const Trade::MeshData&, const Matrix4&, UnsignedInt, Int, InterleaveFlags)
@m_deprecated_since_latest Use @ref transform3D(const Trade::MeshData&, const Matrix4&, UnsignedInt, Int, InterleaveFlags)
instead.
*/
CORRADE_DEPRECATED("use transform3D(const Trade::MeshData&, const Matrix4&, UnsignedInt, Int, InterleaveFlags) instead") MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id, InterleaveFlags flags);
#endif
/** /**
@brief Transform 3D positions, normals, tangenta and bitangents in a mesh data @brief Transform 3D positions, normals, tangenta and bitangents in a mesh data
@m_since_latest @m_since_latest
Compared to @ref transform3D(const Trade::MeshData&, const Matrix4&, UnsignedInt, InterleaveFlags) Compared to @ref transform3D(const Trade::MeshData&, const Matrix4&, UnsignedInt, Int, InterleaveFlags)
this function can can perform the transformation in-place, transferring the this function can can perform the transformation in-place, transferring the
data ownership to the returned instance, if both vertex and index data is data ownership to the returned instance, if both vertex and index data is
owned, vertex data is mutable, positions, normals and bitangents (if present) owned, vertex data is mutable, positions, normals and bitangents with index
are @ref VertexFormat::Vector3 and tangents (if present) either @p id in @p morphTargetId (if present) are @ref VertexFormat::Vector3 and
tangents with index @p id in @p morphTargetId (if present) are either
@ref VertexFormat::Vector3 or @ref VertexFormat::Vector4. @ref VertexFormat::Vector3 or @ref VertexFormat::Vector4.
*/ */
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(Trade::MeshData&& mesh, const Matrix4& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes); MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(Trade::MeshData&& mesh, const Matrix4& transformation, UnsignedInt id = 0, Int morphTargetId = -1, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief transform3D(Trade::MeshData&&, const Matrix4&, UnsignedInt, Int, InterleaveFlags)
@m_deprecated_since_latest Use @ref transform3D(Trade::MeshData&&, const Matrix4&, UnsignedInt, Int, InterleaveFlags)
instead.
*/
CORRADE_DEPRECATED("use transform3D(Trade::MeshData&&, const Matrix4&, UnsignedInt, Int, InterleaveFlags) instead") MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transform3D(Trade::MeshData&& mesh, const Matrix4& transformation, UnsignedInt id, InterleaveFlags flags);
#endif
/** /**
@brief Transform 3D positions, normals, tangents and bitangents in a mesh data in-place @brief Transform 3D positions, normals, tangents and bitangents in a mesh data in-place
@m_since_latest @m_since_latest
Expects that the mesh has mutable vertex data and contains at least a Expects that the mesh has mutable vertex data and contains at least a
three-dimensional @ref Trade::MeshAttribute::Position with index @p id; three-dimensional @ref Trade::MeshAttribute::Position with index @p id (and in
optionally also @ref Trade::MeshAttribute::Normal, morph target @p morphTargetId if not @cpp -1 @ce); optionally also
@ref Trade::MeshAttribute::Tangent or @ref Trade::MeshAttribute::Bitangent with @ref Trade::MeshAttribute::Normal, @ref Trade::MeshAttribute::Tangent or
index @p id, those get transformed with @ref Matrix4::normalMatrix() extracted @ref Trade::MeshAttribute::Bitangent with index @p id in @p morphTargetId,
out of @p transformation. To avoid data loss with packed types, the in-place those get transformed with @ref Matrix4::normalMatrix() extracted out of
operation requires the position, normal and bitangent types to be @p transformation. To avoid data loss with packed types, the in-place operation
requires the position, normal and bitangent types to be
@ref VertexFormat::Vector3 and tangent either @ref VertexFormat::Vector3 or @ref VertexFormat::Vector3 and tangent either @ref VertexFormat::Vector3 or
@ref VertexFormat::Vector4 --- if you can't guarantee that, use @ref VertexFormat::Vector4 --- if you can't guarantee that, use
@ref transform3D() instead. Other attributes, position/TBN attributes other @ref transform3D() instead. Other attributes, position/TBN attributes other
than @p id, and indices (if any) are left untouched. than @p id or with different @p morphTargetId, and indices (if any) are left
untouched.
@see @ref transform2DInPlace(), @ref transformTextureCoordinates2DInPlace(), @see @ref transform2DInPlace(), @ref transformTextureCoordinates2DInPlace(),
@ref Trade::MeshData::vertexDataFlags(), @ref Trade::MeshData::vertexDataFlags(),
@ref Trade::MeshData::attributeCount(MeshAttribute, Int) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const
*/ */
MAGNUM_MESHTOOLS_EXPORT void transform3DInPlace(Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0); MAGNUM_MESHTOOLS_EXPORT void transform3DInPlace(Trade::MeshData& mesh, const Matrix4& transformation, UnsignedInt id = 0, Int morphTargetId = -1);
/** /**
@brief Transform 2D texture coordinates in a mesh data @brief Transform 2D texture coordinates in a mesh data
@m_since_latest @m_since_latest
Expects that the mesh contains a @ref Trade::MeshAttribute::TextureCoordinates Expects that the mesh contains a @ref Trade::MeshAttribute::TextureCoordinates
with index id. To avoid data loss with packed types, the coordinattes are with index @p id (and in morph target @p morphTargetId if not @cpp -1 @ce). To
converted to @ref VertexFormat::Vector2 if not already. In that case the data avoid data loss with packed types, the coordinattes are converted to
layouting is done by @ref interleavedLayout() with the @p flags parameter @ref VertexFormat::Vector2 if not already. In that case the data layouting is
propagated to it, see its documentation for detailed behavior description. done by @ref interleavedLayout() with the @p flags parameter propagated to it,
Other attributes, texture coordinate attributes other than @p id, and indices see its documentation for detailed behavior description. Other attributes,
(if any) are passed through untouched. texture coordinate attributes other than @p id or with different
@p morphTargetId, and indices (if any) are passed through untouched.
See also @ref transformTextureCoordinates2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, InterleaveFlags)
See also @ref transformTextureCoordinates2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
for a potentially more efficient operation instead of always performing a full for a potentially more efficient operation instead of always performing a full
copy, you can also do an in-place transformation using copy, you can also do an in-place transformation using
@ref transformTextureCoordinates2DInPlace(). @ref transformTextureCoordinates2DInPlace().
@ -280,38 +323,57 @@ copy, you can also do an in-place transformation using
@ref Trade::MeshData::attributeCount(MeshAttribute, Int) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref isVertexFormatImplementationSpecific() @ref isVertexFormatImplementationSpecific()
*/ */
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes); MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, Int morphTargetId = -1, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief transformTextureCoordinates2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
@m_deprecated_since_latest Use @ref transformTextureCoordinates2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
instead.
*/
CORRADE_DEPRECATED("use transformTextureCoordinates2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, Int, InterleaveFlags) instead") MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id, InterleaveFlags flags);
#endif
/** /**
@brief Transform 2D texture coordinates in a mesh data @brief Transform 2D texture coordinates in a mesh data
@m_since_latest @m_since_latest
Compared to @ref transformTextureCoordinates2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, InterleaveFlags) Compared to @ref transformTextureCoordinates2D(const Trade::MeshData&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
this function can can perform the transformation in-place, transferring the this function can can perform the transformation in-place, transferring the
data ownership to the returned instance, if both vertex and index data is data ownership to the returned instance, if both vertex and index data is
owned, vertex data is mutable and the coordinates with index @p id are owned, vertex data is mutable and the coordinates with index @p id in
@ref VertexFormat::Vector2. @p morphTargetId are @ref VertexFormat::Vector2.
*/ */
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& mesh, const Matrix3& transformation, UnsignedInt id = 0, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes); MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& mesh, const Matrix3& transformation, UnsignedInt id = 0, Int morphTargetId = -1, InterleaveFlags flags = InterleaveFlag::PreserveInterleavedAttributes);
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief @copybrief transformTextureCoordinates2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
@m_deprecated_since_latest Use @ref transformTextureCoordinates2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Int, InterleaveFlags)
instead.
*/
CORRADE_DEPRECATED("use transformTextureCoordinates2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Int, InterleaveFlags) instead") MAGNUM_MESHTOOLS_EXPORT Trade::MeshData transformTextureCoordinates2D(Trade::MeshData&& mesh, const Matrix3& transformation, UnsignedInt id, InterleaveFlags flags);
#endif
/** /**
@brief Transform 2D texture coordinates in a mesh data in-place @brief Transform 2D texture coordinates in a mesh data in-place
@m_since_latest @m_since_latest
Expects that the mesh has mutable vertex data and contains a Expects that the mesh has mutable vertex data and contains a
@ref Trade::MeshAttribute::TextureCoordinates with index @p id and that the @ref Trade::MeshAttribute::TextureCoordinates with index @p id (and in morph
attribute does not have an implementation-specific format. To avoid data loss target @p morphTargetId if not @cpp -1 @ce) and that the attribute does not
with packed types, the in-place operation requires the coordinate type to be have an implementation-specific format. To avoid data loss with packed types,
the in-place operation requires the coordinate type to be
@ref VertexFormat::Vector2 --- if you can't guarantee that, use @ref VertexFormat::Vector2 --- if you can't guarantee that, use
@ref transformTextureCoordinates2D() instead. Other attributes, texture @ref transformTextureCoordinates2D() instead. Other attributes, texture
coordinate attributes other than @p id, and indices (if any) are passed through coordinate attributes other than @p id or with different @p morphTargetId, and
untouched. indices (if any) are passed through untouched.
@see @ref transform2DInPlace(), @ref transform3DInPlace(), @see @ref transform2DInPlace(), @ref transform3DInPlace(),
@ref Trade::MeshData::vertexDataFlags(), @ref Trade::MeshData::vertexDataFlags(),
@ref Trade::MeshData::attributeCount(MeshAttribute, Int) const, @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const,
@ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const @ref Trade::MeshData::attributeFormat(MeshAttribute, UnsignedInt, Int) const
*/ */
MAGNUM_MESHTOOLS_EXPORT void transformTextureCoordinates2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0); MAGNUM_MESHTOOLS_EXPORT void transformTextureCoordinates2DInPlace(Trade::MeshData& mesh, const Matrix3& transformation, UnsignedInt id = 0, Int morphTargetId = -1);
}} }}

Loading…
Cancel
Save