Browse Source

SceneTools: pin down current flattenMeshHierarchy() behavior.

It doesn't discard meshes that are not a part of the hierarchy, but that
was the plan in the beginning. However, over the time I realized that a
better property for it is that the output is guaranteed to be in the
same order and size as the mesh field in the scene. Because that's what
I relied on in every use case, and every time I had to dig that property
out of the sources because it was deliberately not documented *because*
it was meant to change.

No longer. The compatibility with the mesh field ordering is now
documented, the behavior regarding loose objects also, and if there's
ever a need to discard everything that's not in the reachable hierarchy,
it'll probably get its own API. Because it's useful for general
asset cleanup and other use cases, not just meshes.

I'm still keeping the experimental tag here though, tp be sure.
pull/610/head
Vladimír Vondruš 4 years ago
parent
commit
48bd603236
  1. 2
      src/Magnum/SceneTools/FlattenMeshHierarchy.cpp
  2. 30
      src/Magnum/SceneTools/FlattenMeshHierarchy.h
  3. 67
      src/Magnum/SceneTools/Test/FlattenMeshHierarchyTest.cpp

2
src/Magnum/SceneTools/FlattenMeshHierarchy.cpp

@ -113,8 +113,6 @@ Containers::Array<Containers::Triple<UnsignedInt, Int, MatrixTypeFor<dimensions,
absolute transformations to each. The matrix location is abused for absolute transformations to each. The matrix location is abused for
object mapping, which is subsequently replaced by the absolute object object mapping, which is subsequently replaced by the absolute object
transformation for given mesh. */ transformation for given mesh. */
/** @todo skip meshes that aren't part of the hierarchy once we have a
BitArray to efficiently mark what's in the hierarchy and what not */
Containers::Array<Containers::Triple<UnsignedInt, Int, MatrixTypeFor<dimensions, Float>>> out{NoInit, scene.fieldSize(Trade::SceneField::Mesh)}; Containers::Array<Containers::Triple<UnsignedInt, Int, MatrixTypeFor<dimensions, Float>>> out{NoInit, scene.fieldSize(Trade::SceneField::Mesh)};
const auto matrices = stridedArrayView(out).slice(&decltype(out)::Type::third); const auto matrices = stridedArrayView(out).slice(&decltype(out)::Type::third);
const auto mapping = Containers::arrayCast<UnsignedInt>(matrices); const auto mapping = Containers::arrayCast<UnsignedInt>(matrices);

30
src/Magnum/SceneTools/FlattenMeshHierarchy.h

@ -40,11 +40,11 @@ namespace Magnum { namespace SceneTools {
@brief Flatten a 2D mesh hierarchy @brief Flatten a 2D mesh hierarchy
@m_since_latest @m_since_latest
For all @ref Trade::SceneField::Mesh entries that are a part of a hierarchy For all @ref Trade::SceneField::Mesh entries returns a triple of mesh ID,
returns a triple of mesh ID, @ref Trade::SceneField::MeshMaterial and its @ref Trade::SceneField::MeshMaterial and its absolute transformation in the
absolute transformation in the scene with @p globalTransformation prepended. scene with @p globalTransformation prepended. The
The @ref Trade::SceneField::Parent field is expected to be contained in the @ref Trade::SceneField::Parent field is expected to be contained in the scene,
scene, having no cycles or duplicates, and the scene is expected to be 2D. If having no cycles or duplicates, and the scene is expected to be 2D. If
@ref Trade::SceneField::Mesh is not present or is empty, returns an empty @ref Trade::SceneField::Mesh is not present or is empty, returns an empty
array. You can then use @ref MeshTools::transform2D() to apply the array. You can then use @ref MeshTools::transform2D() to apply the
transformations to actual meshes: transformations to actual meshes:
@ -56,6 +56,11 @@ memory complexity, with @f$ m @f$ being size of the @ref Trade::SceneField::Mesh
field and @f$ n @f$ being @ref Trade::SceneData::mappingBound(). The function field and @f$ n @f$ being @ref Trade::SceneData::mappingBound(). The function
calls @ref orderClusterParents() internally. calls @ref orderClusterParents() internally.
The returned data are in the same order as the @ref Trade::SceneField::Mesh
attribute. Meshes attached to objects without a @ref Trade::SceneField::Parent
or to objects in loose hierarchy subtrees will have their transformation set to
an unspecified value.
@experimental @experimental
@see @ref Trade::SceneData::hasField(), @ref Trade::SceneData::is2D(), @see @ref Trade::SceneData::hasField(), @ref Trade::SceneData::is2D(),
@ -73,11 +78,11 @@ MAGNUM_SCENETOOLS_EXPORT Containers::Array<Containers::Triple<UnsignedInt, Int,
@brief Flatten a 3D mesh hierarchy @brief Flatten a 3D mesh hierarchy
@m_since_latest @m_since_latest
For all @ref Trade::SceneField::Mesh entries that are a part of a hierarchy For all @ref Trade::SceneField::Mesh entries returns a triple of mesh ID,
returns a triple of mesh ID, @ref Trade::SceneField::MeshMaterial and its @ref Trade::SceneField::MeshMaterial and its absolute transformation in the
absolute transformation in the scene with @p globalTransformation prepended. scene with @p globalTransformation prepended. The
The @ref Trade::SceneField::Parent field is expected to be contained in the @ref Trade::SceneField::Parent field is expected to be contained in the scene,
scene, having no cycles or duplicates, and the scene is expected to be 3D. If having no cycles or duplicates, and the scene is expected to be 3D. If
@ref Trade::SceneField::Mesh is not present or is empty, returns an empty @ref Trade::SceneField::Mesh is not present or is empty, returns an empty
array. You can then use @ref MeshTools::transform3D() to apply the array. You can then use @ref MeshTools::transform3D() to apply the
transformations to actual meshes: transformations to actual meshes:
@ -89,6 +94,11 @@ memory complexity, with @f$ m @f$ being size of the @ref Trade::SceneField::Mesh
field and @f$ n @f$ being @ref Trade::SceneData::mappingBound(). The function field and @f$ n @f$ being @ref Trade::SceneData::mappingBound(). The function
calls @ref orderClusterParents() internally. calls @ref orderClusterParents() internally.
The returned data are in the same order as the @ref Trade::SceneField::Mesh
attribute. Meshes attached to objects without a @ref Trade::SceneField::Parent
or to objects in loose hierarchy subtrees will have their transformation set to
an unspecified value.
@experimental @experimental
@see @ref Trade::SceneData::hasField(), @ref Trade::SceneData::is3D(), @see @ref Trade::SceneData::hasField(), @ref Trade::SceneData::is3D(),

67
src/Magnum/SceneTools/Test/FlattenMeshHierarchyTest.cpp

@ -52,30 +52,21 @@ struct {
const char* name; const char* name;
Matrix3 globalTransformation2D; Matrix3 globalTransformation2D;
Matrix4 globalTransformation3D; Matrix4 globalTransformation3D;
std::size_t parentsToExclude, transformationsToExclude, meshesToExclude; std::size_t transformationsToExclude, meshesToExclude;
std::size_t expectedOutputSize; std::size_t expectedOutputSize;
} TestData[]{ } TestData[]{
{"", {}, {}, {"", {}, {},
0, 2, 3, 2, 0,
5}, 5},
{"global transformation", {"global transformation",
Matrix3::scaling(Vector2{0.5f}), Matrix4::scaling(Vector3{0.5f}), Matrix3::scaling(Vector2{0.5f}), Matrix4::scaling(Vector3{0.5f}),
0, 2, 3, 2, 0,
5}, 5},
{"transformations not part of the hierarchy", {}, {}, {"transformations not part of the hierarchy", {}, {},
0, 0, 3, 0, 0,
5}, 5},
{"meshes not part of the hierarchy", {}, {},
0, 2, 0,
5},
{"transformations and meshes not part of the hierarchy", {}, {},
0, 0, 0,
5},
{"no parents", {}, {},
9, 2, 3,
0},
{"no meshes", {}, {}, {"no meshes", {}, {},
0, 2, 8, 2, 5,
0}, 0},
}; };
@ -110,7 +101,7 @@ void FlattenMeshHierarchyTest::test2D() {
UnsignedShort object; UnsignedShort object;
UnsignedShort mesh; UnsignedShort mesh;
Short meshMaterial; Short meshMaterial;
} meshes[8]; } meshes[5];
} data[]{{ } data[]{{
/* /*
Cases to test: Cases to test:
@ -156,11 +147,7 @@ void FlattenMeshHierarchyTest::test2D() {
{32, Matrix3::translation({1.0f, 0.5f})}, {32, Matrix3::translation({1.0f, 0.5f})},
{17, Matrix3::translation({2.0f, 1.0f})}, {17, Matrix3::translation({2.0f, 1.0f})},
}, },
{{0, 262, 33}, {{2, 113, 96},
{32, 155, 47},
{0, 127, -1},
/* The above are not part of the hierarchy */
{2, 113, 96},
{3, 266, 74}, {3, 266, 74},
{4, 525, 33}, {4, 525, 33},
{3, 422, -1}, {3, 422, -1},
@ -172,11 +159,9 @@ void FlattenMeshHierarchyTest::test2D() {
Trade::SceneFieldData{Trade::SceneField::Camera, Trade::SceneMappingType::UnsignedShort, nullptr, Trade::SceneFieldType::UnsignedInt, nullptr}, Trade::SceneFieldData{Trade::SceneField::Camera, Trade::SceneMappingType::UnsignedShort, nullptr, Trade::SceneFieldType::UnsignedInt, nullptr},
Trade::SceneFieldData{Trade::SceneField::Parent, Trade::SceneFieldData{Trade::SceneField::Parent,
Containers::stridedArrayView(data->parents) Containers::stridedArrayView(data->parents)
.slice(&Data::Parent::object) .slice(&Data::Parent::object),
.exceptSuffix(instanceData.parentsToExclude),
Containers::stridedArrayView(data->parents) Containers::stridedArrayView(data->parents)
.slice(&Data::Parent::parent) .slice(&Data::Parent::parent)},
.exceptSuffix(instanceData.parentsToExclude)},
Trade::SceneFieldData{Trade::SceneField::Transformation, Trade::SceneFieldData{Trade::SceneField::Transformation,
Containers::stridedArrayView(data->transforms) Containers::stridedArrayView(data->transforms)
.slice(&Data::Transformation::object) .slice(&Data::Transformation::object)
@ -187,17 +172,17 @@ void FlattenMeshHierarchyTest::test2D() {
Trade::SceneFieldData{Trade::SceneField::Mesh, Trade::SceneFieldData{Trade::SceneField::Mesh,
Containers::stridedArrayView(data->meshes) Containers::stridedArrayView(data->meshes)
.slice(&Data::Mesh::object) .slice(&Data::Mesh::object)
.exceptPrefix(instanceData.meshesToExclude), .exceptSuffix(instanceData.meshesToExclude),
Containers::stridedArrayView(data->meshes) Containers::stridedArrayView(data->meshes)
.slice(&Data::Mesh::mesh) .slice(&Data::Mesh::mesh)
.exceptPrefix(instanceData.meshesToExclude)}, .exceptSuffix(instanceData.meshesToExclude)},
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, Trade::SceneFieldData{Trade::SceneField::MeshMaterial,
Containers::stridedArrayView(data->meshes) Containers::stridedArrayView(data->meshes)
.slice(&Data::Mesh::object) .slice(&Data::Mesh::object)
.exceptPrefix(instanceData.meshesToExclude), .exceptSuffix(instanceData.meshesToExclude),
Containers::stridedArrayView(data->meshes) Containers::stridedArrayView(data->meshes)
.slice(&Data::Mesh::meshMaterial) .slice(&Data::Mesh::meshMaterial)
.exceptPrefix(instanceData.meshesToExclude)}, .exceptSuffix(instanceData.meshesToExclude)},
}}; }};
Containers::Array<Containers::Triple<UnsignedInt, Int, Matrix3>> out; Containers::Array<Containers::Triple<UnsignedInt, Int, Matrix3>> out;
@ -207,8 +192,6 @@ void FlattenMeshHierarchyTest::test2D() {
else else
out = flattenMeshHierarchy2D(scene); out = flattenMeshHierarchy2D(scene);
CORRADE_EXPECT_FAIL_IF(instanceData.meshesToExclude == 0 || instanceData.parentsToExclude != 0,
"Meshes that are not part of the hierarchy are not excluded at the moment.");
CORRADE_COMPARE_AS(out, (Containers::arrayView<Containers::Triple<UnsignedInt, Int, Matrix3>>({ CORRADE_COMPARE_AS(out, (Containers::arrayView<Containers::Triple<UnsignedInt, Int, Matrix3>>({
{113, 96, instanceData.globalTransformation2D* {113, 96, instanceData.globalTransformation2D*
Matrix3::translation({1.0f, -1.5f})* Matrix3::translation({1.0f, -1.5f})*
@ -250,7 +233,7 @@ void FlattenMeshHierarchyTest::test3D() {
UnsignedShort object; UnsignedShort object;
UnsignedShort mesh; UnsignedShort mesh;
Short meshMaterial; Short meshMaterial;
} meshes[8]; } meshes[5];
} data[]{{ } data[]{{
/* /*
Cases to test: Cases to test:
@ -296,11 +279,7 @@ void FlattenMeshHierarchyTest::test3D() {
{32, Matrix4::translation({1.0f, 0.5f, 2.0f})}, {32, Matrix4::translation({1.0f, 0.5f, 2.0f})},
{17, Matrix4::translation({2.0f, 1.0f, 4.0f})}, {17, Matrix4::translation({2.0f, 1.0f, 4.0f})},
}, },
{{0, 262, 33}, {{2, 113, 96},
{32, 155, 47},
{0, 127, -1},
/* The above are not part of the hierarchy */
{2, 113, 96},
{3, 266, 74}, {3, 266, 74},
{4, 525, 33}, {4, 525, 33},
{3, 422, -1}, {3, 422, -1},
@ -312,11 +291,9 @@ void FlattenMeshHierarchyTest::test3D() {
Trade::SceneFieldData{Trade::SceneField::Camera, Trade::SceneMappingType::UnsignedShort, nullptr, Trade::SceneFieldType::UnsignedInt, nullptr}, Trade::SceneFieldData{Trade::SceneField::Camera, Trade::SceneMappingType::UnsignedShort, nullptr, Trade::SceneFieldType::UnsignedInt, nullptr},
Trade::SceneFieldData{Trade::SceneField::Parent, Trade::SceneFieldData{Trade::SceneField::Parent,
Containers::stridedArrayView(data->parents) Containers::stridedArrayView(data->parents)
.slice(&Data::Parent::object) .slice(&Data::Parent::object),
.exceptSuffix(instanceData.parentsToExclude),
Containers::stridedArrayView(data->parents) Containers::stridedArrayView(data->parents)
.slice(&Data::Parent::parent) .slice(&Data::Parent::parent)},
.exceptSuffix(instanceData.parentsToExclude)},
Trade::SceneFieldData{Trade::SceneField::Transformation, Trade::SceneFieldData{Trade::SceneField::Transformation,
Containers::stridedArrayView(data->transforms) Containers::stridedArrayView(data->transforms)
.slice(&Data::Transformation::object) .slice(&Data::Transformation::object)
@ -327,17 +304,17 @@ void FlattenMeshHierarchyTest::test3D() {
Trade::SceneFieldData{Trade::SceneField::Mesh, Trade::SceneFieldData{Trade::SceneField::Mesh,
Containers::stridedArrayView(data->meshes) Containers::stridedArrayView(data->meshes)
.slice(&Data::Mesh::object) .slice(&Data::Mesh::object)
.exceptPrefix(instanceData.meshesToExclude), .exceptSuffix(instanceData.meshesToExclude),
Containers::stridedArrayView(data->meshes) Containers::stridedArrayView(data->meshes)
.slice(&Data::Mesh::mesh) .slice(&Data::Mesh::mesh)
.exceptPrefix(instanceData.meshesToExclude)}, .exceptSuffix(instanceData.meshesToExclude)},
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, Trade::SceneFieldData{Trade::SceneField::MeshMaterial,
Containers::stridedArrayView(data->meshes) Containers::stridedArrayView(data->meshes)
.slice(&Data::Mesh::object) .slice(&Data::Mesh::object)
.exceptPrefix(instanceData.meshesToExclude), .exceptSuffix(instanceData.meshesToExclude),
Containers::stridedArrayView(data->meshes) Containers::stridedArrayView(data->meshes)
.slice(&Data::Mesh::meshMaterial) .slice(&Data::Mesh::meshMaterial)
.exceptPrefix(instanceData.meshesToExclude)}, .exceptSuffix(instanceData.meshesToExclude)},
}}; }};
Containers::Array<Containers::Triple<UnsignedInt, Int, Matrix4>> out; Containers::Array<Containers::Triple<UnsignedInt, Int, Matrix4>> out;
@ -347,8 +324,6 @@ void FlattenMeshHierarchyTest::test3D() {
else else
out = flattenMeshHierarchy3D(scene); out = flattenMeshHierarchy3D(scene);
CORRADE_EXPECT_FAIL_IF(instanceData.meshesToExclude == 0 || instanceData.parentsToExclude != 0,
"Meshes that are not part of the hierarchy are not excluded at the moment.");
CORRADE_COMPARE_AS(out, (Containers::arrayView<Containers::Triple<UnsignedInt, Int, Matrix4>>({ CORRADE_COMPARE_AS(out, (Containers::arrayView<Containers::Triple<UnsignedInt, Int, Matrix4>>({
{113, 96, instanceData.globalTransformation3D* {113, 96, instanceData.globalTransformation3D*
Matrix4::translation({1.0f, -1.5f, 0.5f})* Matrix4::translation({1.0f, -1.5f, 0.5f})*

Loading…
Cancel
Save