From 02e0d85f51cfad56a9f4a0cb2c1ee4f14c91641a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 21 Jun 2023 13:04:31 +0200 Subject: [PATCH] MeshTools: support morph targets in transform(). --- src/Magnum/MeshTools/Test/TransformTest.cpp | 414 +++++++++++++------- src/Magnum/MeshTools/Transform.cpp | 175 ++++++--- src/Magnum/MeshTools/Transform.h | 184 ++++++--- 3 files changed, 515 insertions(+), 258 deletions(-) diff --git a/src/Magnum/MeshTools/Test/TransformTest.cpp b/src/Magnum/MeshTools/Test/TransformTest.cpp index b1af2d137..7d8948204 100644 --- a/src/Magnum/MeshTools/Test/TransformTest.cpp +++ b/src/Magnum/MeshTools/Test/TransformTest.cpp @@ -104,28 +104,43 @@ const struct { const char* name; bool indexed; UnsignedInt id; + Int morphTargetId; Matrix3 transformation; } MeshData2DData[]{ - {"", false, 0, + {"", false, 0, -1, Matrix3::translation({1.5f, 3.0f})* Matrix3::rotation(35.0_degf)}, - {"indexed", true, 0, + {"indexed", true, 0, -1, Matrix3::translation({1.5f, 3.0f})* 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::rotation(35.0_degf)} /** @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 char* name; bool indexed; UnsignedInt id; + Int morphTargetId; } MeshData2DRvaluePassthroughData[]{ - {"", false, 0}, - {"indexed", true, 0}, - {"second set", false, 1} + {"", false, 0, -1}, + {"indexed", true, 0, -1}, + {"second set", false, 1, -1}, + {"morph target", false, 0, 37} }; const struct { @@ -133,55 +148,65 @@ const struct { bool indexed; bool tangents, tangents4, bitangents, normals; UnsignedInt id; + Int morphTargetId; Matrix4 transformation; Matrix3x3 expectedNormalTransformation; } MeshData3DData[]{ - {"", false, false, false, false, false, 0, + {"", false, false, false, false, false, 0, -1, Matrix4::translation({1.5f, 3.0f, -0.5f})* Matrix4::rotationX(35.0_degf), 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).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::rotationX(35.0_degf), 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::rotationX(35.0_degf), 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::rotationX(35.0_degf), 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::rotationX(35.0_degf), 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::rotationX(35.0_degf), 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).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).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).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).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).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).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::rotationX(35.0_degf)* Matrix4::scaling({2.0f, 1.0f, 0.5f}), @@ -207,20 +232,24 @@ const struct { bool indexed; bool tangents, tangents4, bitangents, normals; UnsignedInt id; + Int morphTargetId; } MeshData3DRvaluePassthroughData[]{ - {"", false, false, false, false, false, 0}, - {"indexed", true, false, false, false, false, 0}, - {"normals", false, false, false, false, true, 0}, - {"tangents", false, true, false, false, false, 0}, - {"four-component tangents", false, true, true, false, false, 0}, - {"bitangents", false, false, false, true, false, 0}, - {"all + indexed", true, true, true, true, true, 0}, - {"second set ", false, false, false, false, false, 1}, - {"second set + normals", false, false, false, false, true, 1}, - {"second set + tangents", false, true, false, false, false, 1}, - {"second set + four-component tangents", false, true, true, false, false, 1}, - {"second set + bitangents", false, false, false, true, false, 1}, - {"second set + all + indexed", true, true, true, true, true, 1}, + {"", false, false, false, false, false, 0, -1}, + {"indexed", true, false, false, false, false, 0, -1}, + {"normals", false, false, false, false, true, 0, -1}, + {"tangents", false, true, false, false, false, 0, -1}, + {"four-component tangents", false, true, true, false, false, 0, -1}, + {"bitangents", false, false, false, true, false, 0, -1}, + {"all + indexed", true, true, true, true, true, 0, -1}, + {"second set", false, false, false, false, false, 1, -1}, + {"second set + normals", false, false, false, false, true, 1, -1}, + {"second set + tangents", false, true, false, false, false, 1, -1}, + {"second set + four-component tangents", false, true, true, false, false, 1, -1}, + {"second set + bitangents", false, false, false, true, false, 1, -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 { @@ -252,15 +281,19 @@ const struct { const char* name; bool indexed; UnsignedInt id; + Int morphTargetId; Matrix3 transformation; } 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::rotation(35.0_degf)}, - {"indexed", true, 0, + {"second set", false, 1, -1, Matrix3::translation({1.5f, 3.0f})* Matrix3::rotation(35.0_degf)}, - {"second set", false, 1, + {"morph target", false, 0, 37, Matrix3::translation({1.5f, 3.0f})* Matrix3::rotation(35.0_degf)} }; @@ -269,10 +302,12 @@ const struct { const char* name; bool indexed; UnsignedInt id; + Int morphTargetId; } MeshDataTextureCoordinatesRvaluePassthroughData[]{ - {"", false, 0}, - {"indexed", true, 0}, - {"second set", false, 1} + {"", false, 0, -1}, + {"indexed", true, 0, -1}, + {"second set", false, 1, -1}, + {"morph target", false, 0, 37} }; TransformTest::TransformTest() { @@ -287,8 +322,10 @@ TransformTest::TransformTest() { &TransformTest::meshData2D }, Containers::arraySize(MeshData2DData)); - addTests({&TransformTest::meshData2DNoPosition, - &TransformTest::meshData2DNot2D, + addInstancedTests({&TransformTest::meshData2DNoPosition}, + Containers::arraySize(NoAttributeData)); + + addTests({&TransformTest::meshData2DNot2D, &TransformTest::meshData2DImplementationSpecificIndexType, &TransformTest::meshData2DImplementationSpecificVertexFormat}); @@ -296,13 +333,19 @@ TransformTest::TransformTest() { Containers::arraySize(MeshData2DRvaluePassthroughData)); addTests({&TransformTest::meshData2DRvaluePassthroughIndexDataNotOwned, - &TransformTest::meshData2DRvaluePassthroughVertexDataNotOwned, - &TransformTest::meshData2DRvaluePassthroughNoPosition, - &TransformTest::meshData2DRvaluePassthroughWrongFormat}); + &TransformTest::meshData2DRvaluePassthroughVertexDataNotOwned}); - addTests({&TransformTest::meshData2DInPlaceNotMutable, - &TransformTest::meshData2DInPlaceNoPosition, - &TransformTest::meshData2DInPlaceWrongFormat}); + addInstancedTests({&TransformTest::meshData2DRvaluePassthroughNoPosition}, + Containers::arraySize(NoAttributeData)); + + addTests({&TransformTest::meshData2DRvaluePassthroughWrongFormat}); + + addTests({&TransformTest::meshData2DInPlaceNotMutable}); + + addInstancedTests({&TransformTest::meshData2DInPlaceNoPosition}, + Containers::arraySize(NoAttributeData)); + + addTests({&TransformTest::meshData2DInPlaceWrongFormat}); addInstancedTests({ &TransformTest::meshData3D, @@ -310,8 +353,10 @@ TransformTest::TransformTest() { &TransformTest::meshData3D, }, Containers::arraySize(MeshData3DData)); - addTests({&TransformTest::meshData3DNoPosition, - &TransformTest::meshData3DNot3D, + addInstancedTests({&TransformTest::meshData3DNoPosition}, + Containers::arraySize(NoAttributeData)); + + addTests({&TransformTest::meshData3DNot3D, &TransformTest::meshData3DImplementationSpecificIndexType}); addInstancedTests({&TransformTest::meshData3DImplementationSpecificVertexFormat}, @@ -321,14 +366,18 @@ TransformTest::TransformTest() { Containers::arraySize(MeshData3DRvaluePassthroughData)); addTests({&TransformTest::meshData3DRvaluePassthroughIndexDataNotOwned, - &TransformTest::meshData3DRvaluePassthroughVertexDataNotOwned, - &TransformTest::meshData3DRvaluePassthroughNoPosition}); + &TransformTest::meshData3DRvaluePassthroughVertexDataNotOwned}); + + addInstancedTests({&TransformTest::meshData3DRvaluePassthroughNoPosition}, + Containers::arraySize(NoAttributeData)); addInstancedTests({&TransformTest::meshData3DRvaluePassthroughWrongFormat}, Containers::arraySize(MeshData3DWrongFormatData)); - addTests({&TransformTest::meshData3DInPlaceNotMutable, - &TransformTest::meshData3DInPlaceNoPosition}); + addTests({&TransformTest::meshData3DInPlaceNotMutable}); + + addInstancedTests({&TransformTest::meshData3DInPlaceNoPosition}, + Containers::arraySize(NoAttributeData)); addInstancedTests({&TransformTest::meshData3DInPlaceWrongFormat}, Containers::arraySize(MeshData3DWrongFormatData)); @@ -338,21 +387,29 @@ TransformTest::TransformTest() { &TransformTest::meshDataTextureCoordinates2D }, Containers::arraySize(MeshDataTextureCoordinatesData)); - addTests({&TransformTest::meshDataTextureCoordinates2DNoCoordinates, - &TransformTest::meshDataTextureCoordinates2DImplementationSpecificIndexType, + addInstancedTests({&TransformTest::meshDataTextureCoordinates2DNoCoordinates}, + Containers::arraySize(NoAttributeData)); + + addTests({&TransformTest::meshDataTextureCoordinates2DImplementationSpecificIndexType, &TransformTest::meshDataTextureCoordinates2DImplementationSpecificVertexFormat}); addInstancedTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthrough}, Containers::arraySize(MeshDataTextureCoordinatesRvaluePassthroughData)); addTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughIndexDataNotOwned, - &TransformTest::meshDataTextureCoordinates2DRvaluePassthroughVertexDataNotOwned, - &TransformTest::meshDataTextureCoordinates2DRvaluePassthroughNoCoordinates, - &TransformTest::meshDataTextureCoordinates2DRvaluePassthroughWrongFormat}); + &TransformTest::meshDataTextureCoordinates2DRvaluePassthroughVertexDataNotOwned}); - addTests({&TransformTest::meshDataTextureCoordinates2DInPlaceNotMutable, - &TransformTest::meshDataTextureCoordinates2DInPlaceNoCoordinates, - &TransformTest::meshDataTextureCoordinates2DInPlaceWrongFormat}); + addInstancedTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughNoCoordinates}, + Containers::arraySize(NoAttributeData)); + + addTests({&TransformTest::meshDataTextureCoordinates2DRvaluePassthroughWrongFormat}); + + addTests({&TransformTest::meshDataTextureCoordinates2DInPlaceNotMutable}); + + addInstancedTests({&TransformTest::meshDataTextureCoordinates2DInPlaceNoCoordinates}, + Containers::arraySize(NoAttributeData)); + + addTests({&TransformTest::meshDataTextureCoordinates2DInPlaceWrongFormat}); } constexpr static std::array points2D{{ @@ -441,11 +498,14 @@ template void TransformTest::meshData2D() { Containers::StridedArrayView1D view = vertices; Containers::Array attributes; - if(data.id == 1) + if(data.id == 1 || data.morphTargetId != -1) 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, { - 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)} }); @@ -455,7 +515,7 @@ template void TransformTest::meshData2D() { {}, vertices, std::move(attributes)}; 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); /* Indices should be preserved */ @@ -473,8 +533,8 @@ template void TransformTest::meshData2D() { TestSuite::Compare::Container); /* The vertices should be expanded to floats and transformed */ - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id), VertexFormat::Vector2); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Position, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id, data.morphTargetId), VertexFormat::Vector2); + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Position, data.id, data.morphTargetId), Containers::arrayView({ data.transformation.transformPoint({0.0f, 0.0f}), data.transformation.transformPoint({1.0f, 0.0f}), data.transformation.transformPoint({0.0f, 2.0f}) @@ -482,6 +542,9 @@ template void TransformTest::meshData2D() { } void TransformTest::meshData2DNoPosition() { + auto&& data = NoAttributeData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + CORRADE_SKIP_IF_NO_ASSERT(); Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { @@ -490,8 +553,11 @@ void TransformTest::meshData2DNoPosition() { std::ostringstream out; Error redirectError{&out}; - transform2D(mesh, {}, 1); - CORRADE_COMPARE(out.str(), "MeshTools::transform2D(): the mesh has no positions with index 1\n"); + transform2D(mesh, {}, data.id, data.morphTargetId); + 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() { @@ -519,7 +585,7 @@ void TransformTest::meshData2DImplementationSpecificIndexType() { {}, vertices, {Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(vertices)}}}; /* 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.indexType(), meshIndexTypeWrap(0xcaca)); CORRADE_COMPARE(out.indexOffset(), 2); @@ -568,11 +634,14 @@ void TransformTest::meshData2DRvaluePassthrough() { }, vertices); Containers::Array attributes; - if(data.id == 1) + if(data.id == 1 || data.morphTargetId != -1) 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, { - Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)} + Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position), data.morphTargetId} }); const void* originalAttributeData = attributes; @@ -582,7 +651,7 @@ void TransformTest::meshData2DRvaluePassthrough() { std::move(vertexData), std::move(attributes)}; 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); /* Indices should be passed through unchanged */ @@ -594,8 +663,8 @@ void TransformTest::meshData2DRvaluePassthrough() { } /* The vertices should be expanded to floats and transformed */ - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id), VertexFormat::Vector2); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Position, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id, data.morphTargetId), VertexFormat::Vector2); + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Position, data.id, data.morphTargetId), Containers::arrayView({ transformation.transformPoint({0.0f, 0.0f}), transformation.transformPoint({1.0f, 0.0f}), transformation.transformPoint({0.0f, 2.0f}) @@ -696,16 +765,23 @@ void TransformTest::meshData2DRvaluePassthroughVertexDataNotOwned() { } void TransformTest::meshData2DRvaluePassthroughNoPosition() { + auto&& data = NoAttributeData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + CORRADE_SKIP_IF_NO_ASSERT(); /* 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; Error redirectError{&out}; transform2D(Trade::MeshData{MeshPrimitive::Points, nullptr, { Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector2, nullptr}, - }}, {}, 1); - CORRADE_COMPARE(out.str(), "MeshTools::transform2D(): the mesh has no positions with index 1\n"); + }}, {}, data.id, data.morphTargetId); + 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() { @@ -754,6 +830,9 @@ void TransformTest::meshData2DInPlaceNotMutable() { } void TransformTest::meshData2DInPlaceNoPosition() { + auto&& data = NoAttributeData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + CORRADE_SKIP_IF_NO_ASSERT(); Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { @@ -762,8 +841,11 @@ void TransformTest::meshData2DInPlaceNoPosition() { std::ostringstream out; Error redirectError{&out}; - transform2DInPlace(mesh, {}, 1); - CORRADE_COMPARE(out.str(), "MeshTools::transform2DInPlace(): the mesh has no positions with index 1\n"); + transform2DInPlace(mesh, {}, data.id, data.morphTargetId); + 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() { @@ -817,7 +899,7 @@ template void TransformTest::meshData3D() { Containers::StridedArrayView1D view = vertices; Containers::Array attributes; - if(data.id == 1) { + if(data.id == 1 || data.morphTargetId != -1) { arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); if(data.tangents) arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, VertexFormat::Vector3bNormalized, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); @@ -825,17 +907,20 @@ template void TransformTest::meshData3D() { arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, VertexFormat::Vector3bNormalized, view.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); if(data.normals) 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, { - 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)} }); if(data.tangents) - arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, data.tangents4 ? Trade::Implementation::vertexFormatFor>() : Trade::Implementation::vertexFormatFor>(), view.slice(&Vertex::tangent)}); + arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, data.tangents4 ? Trade::Implementation::vertexFormatFor>() : Trade::Implementation::vertexFormatFor>(), view.slice(&Vertex::tangent), 0, data.morphTargetId}); 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) - 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, {}, data.indexed ? Containers::arrayView(indices) : nullptr, @@ -843,7 +928,7 @@ template void TransformTest::meshData3D() { {}, vertices, std::move(attributes)}; 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); /* Indices should be preserved */ @@ -861,8 +946,8 @@ template void TransformTest::meshData3D() { TestSuite::Compare::Container); /* The vertices should be expanded to floats and transformed */ - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id), VertexFormat::Vector3); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Position, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id, data.morphTargetId), VertexFormat::Vector3); + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Position, data.id, data.morphTargetId), Containers::arrayView({ data.transformation.transformPoint({0.0f, 0.0f, -1.0f}), data.transformation.transformPoint({1.0f, 0.0f, -2.0f}), data.transformation.transformPoint({0.0f, 2.0f, -1.0f}) @@ -872,15 +957,15 @@ template void TransformTest::meshData3D() { const Matrix3x3 normalMatrix = data.transformation.normalMatrix(); 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) - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Tangent, data.id), Containers::arrayView({ + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), Containers::arrayView({ {normalMatrix*Vector3{0.0f, 1.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} }), TestSuite::Compare::Container); else - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Tangent, data.id), Containers::arrayView({ + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), Containers::arrayView({ normalMatrix*Vector3{0.0f, 1.0f, 0.0f}, normalMatrix*Vector3{1.0f, 0.0f, 0.0f}, normalMatrix*Vector3{0.0f, 1.0f, 0.0f} @@ -888,8 +973,8 @@ template void TransformTest::meshData3D() { } if(data.bitangents) { - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Bitangent, data.id), VertexFormat::Vector3); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Bitangent, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Bitangent, data.id, data.morphTargetId), VertexFormat::Vector3); + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Bitangent, data.id, data.morphTargetId), Containers::arrayView({ normalMatrix*Vector3{-1.0f, 0.0f, 0.0f}, normalMatrix*Vector3{0.0f, -1.0f, 0.0f}, normalMatrix*Vector3{0.0f, 0.0f, -1.0f} @@ -897,8 +982,8 @@ template void TransformTest::meshData3D() { } if(data.normals) { - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Normal, data.id), VertexFormat::Vector3); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Normal, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Normal, data.id, data.morphTargetId), VertexFormat::Vector3); + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Normal, data.id, data.morphTargetId), Containers::arrayView({ normalMatrix*Vector3{0.0f, 0.0f, 1.0f}, normalMatrix*Vector3{0.0f, 0.0f, 1.0f}, normalMatrix*Vector3{1.0f, 0.0f, 0.0f} @@ -907,6 +992,9 @@ template void TransformTest::meshData3D() { } void TransformTest::meshData3DNoPosition() { + auto&& data = NoAttributeData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + CORRADE_SKIP_IF_NO_ASSERT(); Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { @@ -915,8 +1003,11 @@ void TransformTest::meshData3DNoPosition() { std::ostringstream out; Error redirectError{&out}; - transform3D(mesh, {}, 1); - CORRADE_COMPARE(out.str(), "MeshTools::transform3D(): the mesh has no positions with index 1\n"); + transform3D(mesh, {}, data.id, data.morphTargetId); + 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() { @@ -944,7 +1035,7 @@ void TransformTest::meshData3DImplementationSpecificIndexType() { {}, vertices, {Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(vertices)}}}; /* 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.indexType(), meshIndexTypeWrap(0xcaca)); CORRADE_COMPARE(out.indexOffset(), 2); @@ -1010,7 +1101,7 @@ void TransformTest::meshData3DRvaluePassthrough() { }, vertices); Containers::Array attributes; - if(data.id == 1) { + if(data.id == 1 || data.morphTargetId != -1) { arrayAppend(attributes, Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::secondaryPositionTangentBitangentNormal)}); if(data.tangents) 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)}); if(data.normals) 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, { - Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)} + Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position), data.morphTargetId} }); 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) - 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) - 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; Trade::MeshData mesh{MeshPrimitive::TriangleFan, @@ -1036,7 +1130,7 @@ void TransformTest::meshData3DRvaluePassthrough() { std::move(vertexData), std::move(attributes)}; 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); /* Indices should be passed through unchanged */ @@ -1048,23 +1142,23 @@ void TransformTest::meshData3DRvaluePassthrough() { } /* The vertices should be expanded to floats and transformed */ - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id), VertexFormat::Vector3); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Position, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Position, data.id, data.morphTargetId), VertexFormat::Vector3); + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Position, data.id, data.morphTargetId), Containers::arrayView({ transformation.transformPoint({0.0f, 0.0f, -1.0f}), transformation.transformPoint({1.0f, 0.0f, -2.0f}), transformation.transformPoint({0.0f, 2.0f, -1.0f}) }), TestSuite::Compare::Container); 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) - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Tangent, data.id), Containers::arrayView({ + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), Containers::arrayView({ {transformation.transformVector({0.0f, 1.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} }), TestSuite::Compare::Container); else - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Tangent, data.id), Containers::arrayView({ + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Tangent, data.id, data.morphTargetId), Containers::arrayView({ transformation.transformVector({0.0f, 1.0f, 0.0f}), transformation.transformVector({1.0f, 0.0f, 0.0f}), transformation.transformVector({0.0f, 1.0f, 0.0f}) @@ -1072,8 +1166,8 @@ void TransformTest::meshData3DRvaluePassthrough() { } if(data.bitangents) { - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Bitangent, data.id), VertexFormat::Vector3); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Bitangent, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Bitangent, data.id, data.morphTargetId), VertexFormat::Vector3); + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Bitangent, data.id, data.morphTargetId), Containers::arrayView({ transformation.transformVector({-1.0f, 0.0f, 0.0f}), transformation.transformVector({0.0f, -1.0f, 0.0f}), transformation.transformVector({0.0f, 0.0f, -1.0f}) @@ -1081,8 +1175,8 @@ void TransformTest::meshData3DRvaluePassthrough() { } if(data.normals) { - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Normal, data.id), VertexFormat::Vector3); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::Normal, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Normal, data.id, data.morphTargetId), VertexFormat::Vector3); + CORRADE_COMPARE_AS(out.attribute(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({1.0f, 0.0f, 0.0f}) @@ -1184,16 +1278,23 @@ void TransformTest::meshData3DRvaluePassthroughVertexDataNotOwned() { } void TransformTest::meshData3DRvaluePassthroughNoPosition() { + auto&& data = NoAttributeData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + CORRADE_SKIP_IF_NO_ASSERT(); /* 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; Error redirectError{&out}; transform3D(Trade::MeshData{MeshPrimitive::Points, nullptr, { Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr}, - }}, {}, 1); - CORRADE_COMPARE(out.str(), "MeshTools::transform3D(): the mesh has no positions with index 1\n"); + }}, {}, data.id, data.morphTargetId); + 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() { @@ -1297,6 +1398,9 @@ void TransformTest::meshData3DInPlaceNotMutable() { } void TransformTest::meshData3DInPlaceNoPosition() { + auto&& data = NoAttributeData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + CORRADE_SKIP_IF_NO_ASSERT(); Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { @@ -1305,8 +1409,11 @@ void TransformTest::meshData3DInPlaceNoPosition() { std::ostringstream out; Error redirectError{&out}; - transform3DInPlace(mesh, {}, 1); - CORRADE_COMPARE(out.str(), "MeshTools::transform3DInPlace(): the mesh has no positions with index 1\n"); + transform3DInPlace(mesh, {}, data.id, data.morphTargetId); + 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() { @@ -1357,11 +1464,14 @@ template void TransformTest::meshDataTextureCoordinates2D() { Containers::StridedArrayView1D view = vertices; Containers::Array attributes; - if(data.id == 1) + if(data.id == 1 || data.morphTargetId != -1) 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, { - 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)} }); @@ -1371,7 +1481,7 @@ template void TransformTest::meshDataTextureCoordinates2D() { {}, vertices, std::move(attributes)}; 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); /* Indices should be preserved */ @@ -1389,8 +1499,8 @@ template void TransformTest::meshDataTextureCoordinates2D() { TestSuite::Compare::Container); /* The vertices should be expanded to floats and transformed */ - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::TextureCoordinates, data.id), VertexFormat::Vector2); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::TextureCoordinates, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::TextureCoordinates, data.id, data.morphTargetId), VertexFormat::Vector2); + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::TextureCoordinates, data.id, data.morphTargetId), Containers::arrayView({ data.transformation.transformPoint({0.0f, 0.0f}), data.transformation.transformPoint({1.0f, 0.0f}), data.transformation.transformPoint({0.0f, 2.0f}) @@ -1398,6 +1508,9 @@ template void TransformTest::meshDataTextureCoordinates2D() { } void TransformTest::meshDataTextureCoordinates2DNoCoordinates() { + auto&& data = NoAttributeData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + CORRADE_SKIP_IF_NO_ASSERT(); Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { @@ -1406,8 +1519,11 @@ void TransformTest::meshDataTextureCoordinates2DNoCoordinates() { std::ostringstream out; Error redirectError{&out}; - transformTextureCoordinates2D(mesh, {}, 1); - CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index 1\n"); + transformTextureCoordinates2D(mesh, {}, data.id, data.morphTargetId); + 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() { @@ -1422,7 +1538,7 @@ void TransformTest::meshDataTextureCoordinates2DImplementationSpecificIndexType( {}, vertices, {Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, Containers::arrayView(vertices)}}}; /* 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.indexType(), meshIndexTypeWrap(0xcaca)); CORRADE_COMPARE(out.indexOffset(), 2); @@ -1471,11 +1587,14 @@ void TransformTest::meshDataTextureCoordinates2DRvaluePassthrough() { }, vertices); Containers::Array attributes; - if(data.id == 1) + if(data.id == 1 || data.morphTargetId != -1) 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, { - Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates)} + Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, vertices.slice(&Vertex::textureCoordinates), data.morphTargetId} }); const void* originalAttributeData = attributes; @@ -1485,7 +1604,7 @@ void TransformTest::meshDataTextureCoordinates2DRvaluePassthrough() { std::move(vertexData), std::move(attributes)}; 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); /* Indices should be passed through unchanged */ @@ -1497,8 +1616,8 @@ void TransformTest::meshDataTextureCoordinates2DRvaluePassthrough() { } /* The vertices should be expanded to floats and transformed */ - CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::TextureCoordinates, data.id), VertexFormat::Vector2); - CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::TextureCoordinates, data.id), Containers::arrayView({ + CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::TextureCoordinates, data.id, data.morphTargetId), VertexFormat::Vector2); + CORRADE_COMPARE_AS(out.attribute(Trade::MeshAttribute::TextureCoordinates, data.id, data.morphTargetId), Containers::arrayView({ transformation.transformPoint({0.0f, 0.0f}), transformation.transformPoint({1.0f, 0.0f}), transformation.transformPoint({0.0f, 2.0f}) @@ -1599,16 +1718,23 @@ void TransformTest::meshDataTextureCoordinates2DRvaluePassthroughVertexDataNotOw } void TransformTest::meshDataTextureCoordinates2DRvaluePassthroughNoCoordinates() { + auto&& data = NoAttributeData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + CORRADE_SKIP_IF_NO_ASSERT(); /* 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; Error redirectError{&out}; transformTextureCoordinates2D(Trade::MeshData{MeshPrimitive::Points, nullptr, { Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr}, - }}, {}, 1); - CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index 1\n"); + }}, {}, data.id, data.morphTargetId); + 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() { @@ -1657,6 +1783,9 @@ void TransformTest::meshDataTextureCoordinates2DInPlaceNotMutable() { } void TransformTest::meshDataTextureCoordinates2DInPlaceNoCoordinates() { + auto&& data = NoAttributeData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + CORRADE_SKIP_IF_NO_ASSERT(); Trade::MeshData mesh{MeshPrimitive::Points, nullptr, { @@ -1665,8 +1794,11 @@ void TransformTest::meshDataTextureCoordinates2DInPlaceNoCoordinates() { std::ostringstream out; Error redirectError{&out}; - transformTextureCoordinates2DInPlace(mesh, {}, 1); - CORRADE_COMPARE(out.str(), "MeshTools::transformTextureCoordinates2DInPlace(): the mesh has no texture coordinates with index 1\n"); + transformTextureCoordinates2DInPlace(mesh, {}, data.id, data.morphTargetId); + 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() { diff --git a/src/Magnum/MeshTools/Transform.cpp b/src/Magnum/MeshTools/Transform.cpp index ce5c46fbd..2799d374a 100644 --- a/src/Magnum/MeshTools/Transform.cpp +++ b/src/Magnum/MeshTools/Transform.cpp @@ -33,11 +33,16 @@ namespace Magnum { namespace MeshTools { -Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) { - const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); - CORRADE_ASSERT(positionAttributeId, +Trade::MeshData transform2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const Int morphTargetId, const InterleaveFlags flags) { + const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId); + #ifndef CORRADE_NO_ASSERT + if(morphTargetId == -1) CORRADE_ASSERT(positionAttributeId, "MeshTools::transform2D(): the mesh has no positions with index" << id, (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); CORRADE_ASSERT(!isVertexFormatImplementationSpecific(positionAttributeFormat), "MeshTools::transform2D(): positions have an implementation-specific format" << reinterpret_cast(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 empty placeholder that we'll unpack the data into */ 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 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(positionAttributeFormat != VertexFormat::Vector2) - mesh.positions2DInto(out.mutableAttribute(*positionAttributeId), id); + mesh.positions2DInto(out.mutableAttribute(*positionAttributeId), id, morphTargetId); /* Delegate to the in-place implementation and return */ - transform2DInPlace(out, transformation, id); + transform2DInPlace(out, transformation, id, morphTargetId); 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 have positions in the right format already. Explicitly checking for presence of the position attribute so we don't need to duplicate the assert here again. */ - const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); + const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId); if((mesh.indexDataFlags() & Trade::DataFlag::Owned) && (mesh.vertexDataFlags() & Trade::DataFlag::Owned) && positionAttributeId && mesh.attributeFormat(*positionAttributeId) == VertexFormat::Vector2 ) { - transform2DInPlace(mesh, transformation, id); + transform2DInPlace(mesh, transformation, id, morphTargetId); return std::move(mesh); } /* Otherwise delegate to the function that does all the copying and format 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, "MeshTools::transform2DInPlace(): vertex data not mutable", ); - const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); - CORRADE_ASSERT(positionAttributeId, + const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId); + #ifndef CORRADE_NO_ASSERT + if(morphTargetId == -1) CORRADE_ASSERT(positionAttributeId, "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, "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); } -Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, const UnsignedInt id, const InterleaveFlags flags) { - const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); - CORRADE_ASSERT(positionAttributeId, +Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transformation, const UnsignedInt id, const Int morphTargetId, const InterleaveFlags flags) { + const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId); + #ifndef CORRADE_NO_ASSERT + if(morphTargetId == -1) CORRADE_ASSERT(positionAttributeId, "MeshTools::transform3D(): the mesh has no positions with index" << id, (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); CORRADE_ASSERT(!isVertexFormatImplementationSpecific(positionAttributeFormat), "MeshTools::transform3D(): positions have an implementation-specific format" << reinterpret_cast(vertexFormatUnwrap(positionAttributeFormat)), @@ -119,9 +145,9 @@ Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transfor CORRADE_ASSERT(vertexFormatComponentCount(positionAttributeFormat) == 3, "MeshTools::transform3D(): expected 3D positions but got" << positionAttributeFormat, (Trade::MeshData{MeshPrimitive::Triangles, 0})); - const Containers::Optional tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id); - const Containers::Optional bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id); - const Containers::Optional normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id); + const Containers::Optional tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id, morphTargetId); + const Containers::Optional bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id, morphTargetId); + const Containers::Optional normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id, morphTargetId); /* Copy original attributes to a mutable array so we can update the 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 with an empty placeholder that we'll unpack the data into */ 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 desiredTangentVertexFormat{}; if(tangentAttributeId) { @@ -145,7 +171,7 @@ Trade::MeshData transform3D(const Trade::MeshData& mesh, const Matrix4& transfor desiredTangentVertexFormat = vertexFormatComponentCount(mesh.attributeFormat(*tangentAttributeId)) == 4 ? VertexFormat::Vector4 : VertexFormat::Vector3; 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{}; 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(vertexFormatUnwrap(bitangentAttributeFormat)), (Trade::MeshData{MeshPrimitive::Points, 0})); 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{}; 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(vertexFormatUnwrap(normalAttributeFormat)), (Trade::MeshData{MeshPrimitive::Points, 0})); 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 @@ -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(positionAttributeFormat != VertexFormat::Vector3) - mesh.positions3DInto(out.mutableAttribute(*positionAttributeId), id); + mesh.positions3DInto(out.mutableAttribute(*positionAttributeId), id, morphTargetId); if(tangentAttributeId && tangentAttributeFormat != desiredTangentVertexFormat) { if(desiredTangentVertexFormat == VertexFormat::Vector4) { - mesh.tangentsInto(out.mutableAttribute(*tangentAttributeId).slice(&Vector4::xyz), id); - mesh.bitangentSignsInto(out.mutableAttribute(*tangentAttributeId).slice(&Vector4::w), id); + mesh.tangentsInto(out.mutableAttribute(*tangentAttributeId).slice(&Vector4::xyz), id, morphTargetId); + mesh.bitangentSignsInto(out.mutableAttribute(*tangentAttributeId).slice(&Vector4::w), id, morphTargetId); } else { - mesh.tangentsInto(out.mutableAttribute(*tangentAttributeId), id); + mesh.tangentsInto(out.mutableAttribute(*tangentAttributeId), id, morphTargetId); } } if(bitangentAttributeId && bitangentAttributeFormat != VertexFormat::Vector3) - mesh.bitangentsInto(out.mutableAttribute(*bitangentAttributeId), id); + mesh.bitangentsInto(out.mutableAttribute(*bitangentAttributeId), id, morphTargetId); if(normalAttributeId && normalAttributeFormat != VertexFormat::Vector3) - mesh.normalsInto(out.mutableAttribute(*normalAttributeId), id); + mesh.normalsInto(out.mutableAttribute(*normalAttributeId), id, morphTargetId); /* Delegate to the in-place implementation and return */ - transform3DInPlace(out, transformation, id); + transform3DInPlace(out, transformation, id, morphTargetId); 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 have positions in the right format already. Explicitly checking for presence of the position attribute so we don't need to duplicate the assert here again. */ - const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); - const Containers::Optional tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id); - const Containers::Optional bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id); - const Containers::Optional normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id); + const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId); + const Containers::Optional tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id, morphTargetId); + const Containers::Optional bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id, morphTargetId); + const Containers::Optional normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id, morphTargetId); if((mesh.indexDataFlags() & Trade::DataFlag::Owned) && (mesh.vertexDataFlags() & Trade::DataFlag::Owned) && 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) && (!normalAttributeId || mesh.attributeFormat(*normalAttributeId) == VertexFormat::Vector3) ) { - transform3DInPlace(mesh, transformation, id); + transform3DInPlace(mesh, transformation, id, morphTargetId); return std::move(mesh); } /* Otherwise delegate to the function that does all the copying and format 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, "MeshTools::transform3DInPlace(): vertex data not mutable", ); - const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id); - CORRADE_ASSERT(positionAttributeId, + const Containers::Optional positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId); + #ifndef CORRADE_NO_ASSERT + if(morphTargetId == -1) CORRADE_ASSERT(positionAttributeId, "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, "MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "positions but got" << mesh.attributeFormat(*positionAttributeId), ); - const Containers::Optional tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id); + const Containers::Optional tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id, morphTargetId); const VertexFormat tangentAttributeFormat = tangentAttributeId ? mesh.attributeFormat(*tangentAttributeId) : VertexFormat{}; CORRADE_ASSERT(!tangentAttributeId || tangentAttributeFormat == VertexFormat::Vector3 || tangentAttributeFormat == VertexFormat::Vector4, "MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "or" << VertexFormat::Vector4 << "tangents but got" << mesh.attributeFormat(*tangentAttributeId), ); - const Containers::Optional bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id); + const Containers::Optional bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id, morphTargetId); CORRADE_ASSERT(!bitangentAttributeId || mesh.attributeFormat(*bitangentAttributeId) == VertexFormat::Vector3, "MeshTools::transform3DInPlace(): expected" << VertexFormat::Vector3 << "bitangents but got" << mesh.attributeFormat(*bitangentAttributeId), ); - const Containers::Optional normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id); + const Containers::Optional normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id, morphTargetId); CORRADE_ASSERT(!normalAttributeId || mesh.attributeFormat(*normalAttributeId) == VertexFormat::Vector3, "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; } -Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const InterleaveFlags flags) { - const Containers::Optional textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id); - CORRADE_ASSERT(textureCoordinateAttributeId, +Trade::MeshData transformTextureCoordinates2D(const Trade::MeshData& mesh, const Matrix3& transformation, const UnsignedInt id, const Int morphTargetId, const InterleaveFlags flags) { + const Containers::Optional textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id, morphTargetId); + #ifndef CORRADE_NO_ASSERT + if(morphTargetId == -1) CORRADE_ASSERT(textureCoordinateAttributeId, "MeshTools::transformTextureCoordinates2D(): the mesh has no texture coordinates with index" << id, (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); CORRADE_ASSERT(!isVertexFormatImplementationSpecific(textureCoordinateAttributeFormat), "MeshTools::transformTextureCoordinates2D(): texture coordinates have an implementation-specific format" << reinterpret_cast(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 empty placeholder that we'll unpack the data into */ 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 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(mesh.attributeFormat(*textureCoordinateAttributeId) != VertexFormat::Vector2) - mesh.textureCoordinates2DInto(out.mutableAttribute(*textureCoordinateAttributeId), id); + mesh.textureCoordinates2DInto(out.mutableAttribute(*textureCoordinateAttributeId), id, morphTargetId); /* Delegate to the in-place implementation and return */ - transformTextureCoordinates2DInPlace(out, transformation, id); + transformTextureCoordinates2DInPlace(out, transformation, id, morphTargetId); 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 have positions in the right format already. Explicitly checking for presence of the position attribute so we don't need to duplicate the assert here again. */ - const Containers::Optional textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id); + const Containers::Optional textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id, morphTargetId); if((mesh.indexDataFlags() & Trade::DataFlag::Owned) && (mesh.vertexDataFlags() & Trade::DataFlag::Owned) && textureCoordinateAttributeId && mesh.attributeFormat(*textureCoordinateAttributeId) == VertexFormat::Vector2 ) { - transformTextureCoordinates2DInPlace(mesh, transformation, id); + transformTextureCoordinates2DInPlace(mesh, transformation, id, morphTargetId); return std::move(mesh); } /* Otherwise delegate to the function that does all the copying and format 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, "MeshTools::transformTextureCoordinates2DInPlace(): vertex data not mutable", ); - const Containers::Optional textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id); - CORRADE_ASSERT(textureCoordinateAttributeId, + const Containers::Optional textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id, morphTargetId); + #ifndef CORRADE_NO_ASSERT + if(morphTargetId == -1) CORRADE_ASSERT(textureCoordinateAttributeId, "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, "MeshTools::transformTextureCoordinates2DInPlace(): expected" << VertexFormat::Vector2 << "texture coordinates but got" << mesh.attributeFormat(*textureCoordinateAttributeId), ); diff --git a/src/Magnum/MeshTools/Transform.h b/src/Magnum/MeshTools/Transform.h index 43c9fd460..db1a05afd 100644 --- a/src/Magnum/MeshTools/Transform.h +++ b/src/Magnum/MeshTools/Transform.h @@ -149,15 +149,16 @@ template U transformPoints(const T& transformation, U vectors) @m_since_latest Expects that the mesh contains a two-dimensional -@ref Trade::MeshAttribute::Position with index @p id and that the attribute -does not have an implementation-specific format. To avoid data loss with packed -types, the positions are converted to @ref VertexFormat::Vector2 if not +@ref Trade::MeshAttribute::Position with index @p id (and in morph target +@p morphTargetId if not @cpp -1 @ce) and that the attribute does not have an +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() with the @p flags parameter propagated to it, see its documentation for 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 copy, you can also do an in-place transformation using @ref transform2DInPlace(). @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 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 @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 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 -@ref VertexFormat::Vector2. +owned, vertex data is mutable and the positions with index @p id in +@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 @m_since_latest 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 -packed types, the in-place operation requires the position type to be -@ref VertexFormat::Vector2 --- if you can't guarantee that, use -@ref transform2D() instead. Other attributes, position attributes other than -@p id, and indices (if any) are left untouched. +@ref Trade::MeshAttribute::Position with index @p id (and in morph target +@p morphTargetId if not @cpp -1 @ce). To avoid data loss with packed types, the +in-place operation requires the position type to be @ref VertexFormat::Vector2 +--- if you can't guarantee that, use @ref transform2D() instead. Other +attributes, position attributes other than @p id or with different +@p morphTargetId, and indices (if any) are left untouched. @see @ref transform3DInPlace(), @ref transformTextureCoordinates2DInPlace(), @ref Trade::MeshData::vertexDataFlags(), @ref Trade::MeshData::attributeCount(MeshAttribute, 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 @m_since_latest Expects that the mesh contains a three-dimensional -@ref Trade::MeshAttribute::Position with index @p id. If -@ref Trade::MeshAttribute::Normal, @ref Trade::MeshAttribute::Tangent or -@ref Trade::MeshAttribute::Bitangent with index @p id are present as well, -those get transformed with @ref Matrix4::normalMatrix() extracted out of -@p transformation. All these attributes are expected to not have an -implementation-specific format. To avoid data loss with packed types, the -positions, normals and bitangents are converted to @ref VertexFormat::Vector3 -if not already, tangents to either @ref VertexFormat::Vector3 or -@ref VertexFormat::Vector4 if not already. In that case the data layouting is -done by @ref interleavedLayout() with the @p flags parameter propagated to it, -see its documentation for detailed behavior description. Other attributes, -additional position/TBN attributes other than @p id, and indices (if any) are +@ref Trade::MeshAttribute::Position with index @p id (and in morph target +@p morphTargetId if not @cpp -1 @ce). If @ref Trade::MeshAttribute::Normal, +@ref Trade::MeshAttribute::Tangent or @ref Trade::MeshAttribute::Bitangent with +index @p id in @p morphTargetId are present as well, those get transformed with +@ref Matrix4::normalMatrix() extracted out of @p transformation. All these +attributes are expected to not have an implementation-specific format. To avoid +data loss with packed types, the positions, normals and bitangents are +converted to @ref VertexFormat::Vector3 if not already, tangents to either +@ref VertexFormat::Vector3 or @ref VertexFormat::Vector4 if not already. In +that case the data layouting is done by @ref interleavedLayout() with the +@p flags parameter propagated to it, see its documentation for detailed +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. -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 copy, you can also do an in-place transformation using @ref transform3DInPlace(). @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 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 @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 data ownership to the returned instance, if both vertex and index data is -owned, vertex data is mutable, positions, normals and bitangents (if present) -are @ref VertexFormat::Vector3 and tangents (if present) either +owned, vertex data is mutable, positions, normals and bitangents with index +@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. */ -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 @m_since_latest Expects that the mesh has mutable vertex data and contains at least a -three-dimensional @ref Trade::MeshAttribute::Position with index @p id; -optionally also @ref Trade::MeshAttribute::Normal, -@ref Trade::MeshAttribute::Tangent or @ref Trade::MeshAttribute::Bitangent with -index @p id, those get transformed with @ref Matrix4::normalMatrix() extracted -out of @p transformation. To avoid data loss with packed types, the in-place -operation requires the position, normal and bitangent types to be +three-dimensional @ref Trade::MeshAttribute::Position with index @p id (and in +morph target @p morphTargetId if not @cpp -1 @ce); optionally also +@ref Trade::MeshAttribute::Normal, @ref Trade::MeshAttribute::Tangent or +@ref Trade::MeshAttribute::Bitangent with index @p id in @p morphTargetId, +those get transformed with @ref Matrix4::normalMatrix() extracted out of +@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::Vector4 --- if you can't guarantee that, use @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(), @ref Trade::MeshData::vertexDataFlags(), @ref Trade::MeshData::attributeCount(MeshAttribute, 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 @m_since_latest Expects that the mesh contains a @ref Trade::MeshAttribute::TextureCoordinates -with index id. To avoid data loss with packed types, the coordinattes are -converted to @ref VertexFormat::Vector2 if not already. In that case the data -layouting is done by @ref interleavedLayout() with the @p flags parameter -propagated to it, see its documentation for detailed behavior description. -Other attributes, texture coordinate attributes other than @p id, and indices -(if any) are passed through untouched. - -See also @ref transformTextureCoordinates2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, InterleaveFlags) +with index @p id (and in morph target @p morphTargetId if not @cpp -1 @ce). To +avoid data loss with packed types, the coordinattes are converted to +@ref VertexFormat::Vector2 if not already. In that case the data layouting is +done by @ref interleavedLayout() with the @p flags parameter propagated to it, +see its documentation for detailed behavior description. Other attributes, +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, Int, InterleaveFlags) for a potentially more efficient operation instead of always performing a full copy, you can also do an in-place transformation using @ref transformTextureCoordinates2DInPlace(). @@ -280,38 +323,57 @@ copy, you can also do an in-place transformation using @ref Trade::MeshData::attributeCount(MeshAttribute, Int) const, @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 @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 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 -@ref VertexFormat::Vector2. +owned, vertex data is mutable and the coordinates with index @p id in +@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 @m_since_latest Expects that the mesh has mutable vertex data and contains a -@ref Trade::MeshAttribute::TextureCoordinates with index @p id and that the -attribute does not have an implementation-specific format. To avoid data loss -with packed types, the in-place operation requires the coordinate type to be +@ref Trade::MeshAttribute::TextureCoordinates with index @p id (and in morph +target @p morphTargetId if not @cpp -1 @ce) and that the attribute does not +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 transformTextureCoordinates2D() instead. Other attributes, texture -coordinate attributes other than @p id, and indices (if any) are passed through -untouched. +coordinate attributes other than @p id or with different @p morphTargetId, and +indices (if any) are passed through untouched. @see @ref transform2DInPlace(), @ref transform3DInPlace(), @ref Trade::MeshData::vertexDataFlags(), @ref Trade::MeshData::attributeCount(MeshAttribute, 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); }}