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;
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<Half>
}, 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>({
&TransformTest::meshData3D<Float, Float, Float, Float>,
@ -310,8 +353,10 @@ TransformTest::TransformTest() {
&TransformTest::meshData3D<Float, Half, Float, Half>,
}, 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<Half>
}, 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<Vector2, 2> points2D{{
@ -441,11 +498,14 @@ template<class T> void TransformTest::meshData2D() {
Containers::StridedArrayView1D<const Vertex> view = vertices;
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)});
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<class T> 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<class T> 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<Vector2>(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<Vector2>(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<class T> 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<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)});
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<Vector2>(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<Vector2>(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<class T, class U, class V, class W> void TransformTest::meshData3D() {
Containers::StridedArrayView1D<const Vertex> view = vertices;
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)});
if(data.tangents)
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)});
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<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)
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<class T, class U, class V, class W> 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<class T, class U, class V, class W> 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<Vector3>(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<Vector3>(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<class T, class U, class V, class W> 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<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{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<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{1.0f, 0.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) {
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Bitangent, data.id), VertexFormat::Vector3);
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Bitangent, data.id), Containers::arrayView<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, data.morphTargetId), Containers::arrayView<Vector3>({
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<class T, class U, class V, class W> void TransformTest::meshData3D() {
}
if(data.normals) {
CORRADE_COMPARE(out.attributeFormat(Trade::MeshAttribute::Normal, data.id), VertexFormat::Vector3);
CORRADE_COMPARE_AS(out.attribute<Vector3>(Trade::MeshAttribute::Normal, data.id), Containers::arrayView<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, data.morphTargetId), Containers::arrayView<Vector3>({
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<class T, class U, class V, class W> 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<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)});
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<Vector3>(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<Vector3>(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<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({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<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({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<Vector3>(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<Vector3>(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<Vector3>(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<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({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<class T> void TransformTest::meshDataTextureCoordinates2D() {
Containers::StridedArrayView1D<const Vertex> view = vertices;
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)});
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<class T> 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<class T> 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<Vector2>(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<Vector2>(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<class T> 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<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)});
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<Vector2>(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<Vector2>(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() {

175
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<UnsignedInt> 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<UnsignedInt> 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<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
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<Vector2>(*positionAttributeId), id);
mesh.positions2DInto(out.mutableAttribute<Vector2>(*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<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) &&
(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<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id);
CORRADE_ASSERT(positionAttributeId,
const Containers::Optional<UnsignedInt> 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<UnsignedInt> 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<UnsignedInt> 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<void*>(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<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id);
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id);
const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id);
const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id, morphTargetId);
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id, morphTargetId);
const Containers::Optional<UnsignedInt> 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<void*>(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<void*>(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<Vector3>(*positionAttributeId), id);
mesh.positions3DInto(out.mutableAttribute<Vector3>(*positionAttributeId), id, morphTargetId);
if(tangentAttributeId && tangentAttributeFormat != desiredTangentVertexFormat) {
if(desiredTangentVertexFormat == VertexFormat::Vector4) {
mesh.tangentsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::xyz), id);
mesh.bitangentSignsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::w), id);
mesh.tangentsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::xyz), id, morphTargetId);
mesh.bitangentSignsInto(out.mutableAttribute<Vector4>(*tangentAttributeId).slice(&Vector4::w), id, morphTargetId);
} else {
mesh.tangentsInto(out.mutableAttribute<Vector3>(*tangentAttributeId), id);
mesh.tangentsInto(out.mutableAttribute<Vector3>(*tangentAttributeId), id, morphTargetId);
}
}
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)
mesh.normalsInto(out.mutableAttribute<Vector3>(*normalAttributeId), id);
mesh.normalsInto(out.mutableAttribute<Vector3>(*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<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id);
const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id);
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id);
const Containers::Optional<UnsignedInt> normalAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Normal, id);
const Containers::Optional<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id, morphTargetId);
const Containers::Optional<UnsignedInt> tangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Tangent, id, morphTargetId);
const Containers::Optional<UnsignedInt> bitangentAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Bitangent, id, morphTargetId);
const Containers::Optional<UnsignedInt> 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<UnsignedInt> positionAttributeId = mesh.findAttributeId(Trade::MeshAttribute::Position, id);
CORRADE_ASSERT(positionAttributeId,
const Containers::Optional<UnsignedInt> 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<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{};
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<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,
"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,
"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<UnsignedInt> 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<UnsignedInt> 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<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
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<Vector2>(*textureCoordinateAttributeId), id);
mesh.textureCoordinates2DInto(out.mutableAttribute<Vector2>(*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<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) &&
(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<UnsignedInt> textureCoordinateAttributeId = mesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates, id);
CORRADE_ASSERT(textureCoordinateAttributeId,
const Containers::Optional<UnsignedInt> 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), );

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
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);
}}

Loading…
Cancel
Save