Browse Source

sceneconverter: ability to apply a converter to each mesh in the scene.

pull/594/head
Vladimír Vondruš 4 years ago
parent
commit
387d0dcd84
  1. 170
      src/Magnum/SceneTools/Test/SceneConverterTest.cpp
  2. 201
      src/Magnum/SceneTools/sceneconverter.cpp

170
src/Magnum/SceneTools/Test/SceneConverterTest.cpp

@ -117,29 +117,30 @@ const struct {
Containers::Array<Containers::String> args; Containers::Array<Containers::String> args;
const char* requiresImporter; const char* requiresImporter;
const char* requiresConverter; const char* requiresConverter;
const char* requiresMeshConverter;
const char* expected; const char* expected;
const char* expected2; const char* expected2;
Containers::String message; Containers::String message;
} ConvertData[]{ } ConvertData[]{
{"one mesh", Containers::array<Containers::String>({ {"one mesh", Containers::array<Containers::String>({
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"one mesh, whole scene converter", Containers::array<Containers::String>({ {"one mesh, whole scene converter", Containers::array<Containers::String>({
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"ObjImporter", "GltfSceneConverter", "ObjImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin", "quad.gltf", "quad.bin",
{}}, {}},
{"one mesh, explicit importer and converter", Containers::array<Containers::String>({ {"one mesh, explicit importer and converter", Containers::array<Containers::String>({
"-I", "ObjImporter", "-C", "StanfordSceneConverter", "-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"one mesh, map", Containers::array<Containers::String>({ {"one mesh, map", Containers::array<Containers::String>({
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"one mesh, options", Containers::array<Containers::String>({ {"one mesh, options", Containers::array<Containers::String>({
@ -148,7 +149,7 @@ const struct {
just verify the (nonexistent) options arrive there */ just verify the (nonexistent) options arrive there */
"-i", "nonexistentOption=13", "-c", "nonexistentConverterOption=26", "-i", "nonexistentOption=13", "-c", "nonexistentConverterOption=26",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
"Trade::AnySceneImporter::openFile(): option nonexistentOption not recognized by ObjImporter\n" "Trade::AnySceneImporter::openFile(): option nonexistentOption not recognized by ObjImporter\n"
"Trade::AnySceneConverter::beginFile(): option nonexistentConverterOption not recognized by StanfordSceneConverter\n"}, "Trade::AnySceneConverter::beginFile(): option nonexistentConverterOption not recognized by StanfordSceneConverter\n"},
@ -159,7 +160,7 @@ const struct {
"-i", "nonexistentOption=13", "-c", "nonexistentConverterOption=26", "-i", "nonexistentOption=13", "-c", "nonexistentConverterOption=26",
"-I", "ObjImporter", "-C", "StanfordSceneConverter", "-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
"Option nonexistentOption not recognized by ObjImporter\n" "Option nonexistentOption not recognized by ObjImporter\n"
"Option nonexistentConverterOption not recognized by StanfordSceneConverter\n"}, "Option nonexistentConverterOption not recognized by StanfordSceneConverter\n"},
@ -167,20 +168,20 @@ const struct {
/* Removing the generator identifier to have the file fully roundtrip */ /* Removing the generator identifier to have the file fully roundtrip */
"-c", "generator=", "-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
/* There should be a minimal difference compared to the original */ /* There should be a minimal difference compared to the original */
"two-quads.gltf", "two-quads.bin", "two-quads.gltf", "two-quads.bin",
{}}, {}},
{"concatenate meshes without a scene", Containers::array<Containers::String>({ {"concatenate meshes without a scene", Containers::array<Containers::String>({
"--concatenate-meshes", "--concatenate-meshes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-duplicates.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-duplicates.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad-duplicates.ply", nullptr, "quad-duplicates.ply", nullptr,
{}}, {}},
{"concatenate meshes with a scene", Containers::array<Containers::String>({ {"concatenate meshes with a scene", Containers::array<Containers::String>({
"--concatenate-meshes", "--concatenate-meshes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles-transformed.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-duplicates.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles-transformed.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-duplicates.ply")}),
"GltfImporter", "StanfordSceneConverter", "GltfImporter", "StanfordSceneConverter", nullptr,
"quad-duplicates.ply", nullptr, "quad-duplicates.ply", nullptr,
{}}, {}},
/** @todo drop --mesh once it's not needed anymore again, then add a /** @todo drop --mesh once it's not needed anymore again, then add a
@ -189,19 +190,19 @@ const struct {
/* Only 0 gets picked from here, others ignored */ /* Only 0 gets picked from here, others ignored */
"--mesh", "0", "--only-mesh-attributes", "17,0,25-36", "--mesh", "0", "--only-mesh-attributes", "17,0,25-36",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-normals-texcoords.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-normals-texcoords.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"concatenate meshes, filter mesh attributes", Containers::array<Containers::String>({ {"concatenate meshes, filter mesh attributes", Containers::array<Containers::String>({
"--concatenate-meshes", "--only-mesh-attributes", "17,0,25-36", "--concatenate-meshes", "--only-mesh-attributes", "17,0,25-36",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-normals-texcoords.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-normals-texcoords.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"one implicit mesh, remove vertex duplicates", Containers::array<Containers::String>({ {"one implicit mesh, remove vertex duplicates", Containers::array<Containers::String>({
"--remove-duplicate-vertices", "--remove-duplicate-vertices",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"one implicit mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({ {"one implicit mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({
@ -209,7 +210,7 @@ const struct {
AnySceneConverter delegation messages */ AnySceneConverter delegation messages */
"--remove-duplicate-vertices", "-v", "-I", "ObjImporter", "-C", "StanfordSceneConverter", "--remove-duplicate-vertices", "-v", "-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
"Mesh 0 duplicate removal: 6 -> 4 vertices\n"}, "Mesh 0 duplicate removal: 6 -> 4 vertices\n"},
{"one selected mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({ {"one selected mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({
@ -217,7 +218,7 @@ const struct {
AnySceneConverter delegation messages */ AnySceneConverter delegation messages */
"--mesh", "1", "--remove-duplicate-vertices", "-v", "-I", "GltfImporter", "-C", "StanfordSceneConverter", "--mesh", "1", "--remove-duplicate-vertices", "-v", "-I", "GltfImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "StanfordSceneConverter", "GltfImporter", "StanfordSceneConverter", nullptr,
/* The second mesh in the glTF is deliberately the same as in /* The second mesh in the glTF is deliberately the same as in
quad-duplicates.obj, so this produces the same file */ quad-duplicates.obj, so this produces the same file */
"quad.ply", nullptr, "quad.ply", nullptr,
@ -229,7 +230,7 @@ const struct {
/* Removing the generator identifier for a smaller file */ /* Removing the generator identifier for a smaller file */
"-c", "generator=", "-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
/* There should be a minimal difference compared to the original */ /* There should be a minimal difference compared to the original */
"two-quads.gltf", "two-quads.bin", "two-quads.gltf", "two-quads.bin",
"Mesh 0 duplicate removal: 5 -> 4 vertices\n" "Mesh 0 duplicate removal: 5 -> 4 vertices\n"
@ -237,7 +238,7 @@ const struct {
{"one implicit mesh, remove duplicate vertices fuzzy", Containers::array<Containers::String>({ {"one implicit mesh, remove duplicate vertices fuzzy", Containers::array<Containers::String>({
"--remove-duplicate-vertices-fuzzy", "1.0e-1", "--remove-duplicate-vertices-fuzzy", "1.0e-1",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates-fuzzy.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates-fuzzy.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"one implicit mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({ {"one implicit mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({
@ -245,7 +246,7 @@ const struct {
AnySceneConverter delegation messages */ AnySceneConverter delegation messages */
"--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "ObjImporter", "-C", "StanfordSceneConverter", "--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates-fuzzy.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates-fuzzy.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
"Mesh 0 fuzzy duplicate removal: 6 -> 4 vertices\n"}, "Mesh 0 fuzzy duplicate removal: 6 -> 4 vertices\n"},
{"one selected mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({ {"one selected mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({
@ -253,7 +254,7 @@ const struct {
AnySceneConverter delegation messages */ AnySceneConverter delegation messages */
"--mesh 1", "--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "GltfImporter", "-C", "StanfordSceneConverter", "--mesh 1", "--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "GltfImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "StanfordSceneConverter", "GltfImporter", "StanfordSceneConverter", nullptr,
/* The second mesh in the glTF is deliberately the same as in /* The second mesh in the glTF is deliberately the same as in
quad-duplicates-fuzzy.obj, so this produces the same file */ quad-duplicates-fuzzy.obj, so this produces the same file */
"quad.ply", nullptr, "quad.ply", nullptr,
@ -265,26 +266,26 @@ const struct {
/* Removing the generator identifier for a smaller file */ /* Removing the generator identifier for a smaller file */
"-c", "generator=", "-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
"two-quads.gltf", "two-quads.bin", "two-quads.gltf", "two-quads.bin",
"Mesh 0 fuzzy duplicate removal: 5 -> 4 vertices\n" "Mesh 0 fuzzy duplicate removal: 5 -> 4 vertices\n"
"Mesh 1 fuzzy duplicate removal: 6 -> 4 vertices\n"}, "Mesh 1 fuzzy duplicate removal: 6 -> 4 vertices\n"},
{"one implicit mesh, two converters", Containers::array<Containers::String>({ {"one implicit mesh, two converters", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "MeshOptimizerSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin", "quad.gltf", "quad.bin",
{}}, {}},
{"one implicit mesh, two converters, explicit last", Containers::array<Containers::String>({ {"one implicit mesh, two converters, explicit last", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "GltfSceneConverter", "-C", "MeshOptimizerSceneConverter", "-C", "GltfSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin", "quad.gltf", "quad.bin",
{}}, {}},
{"one implicit mesh, two converters, verbose", Containers::array<Containers::String>({ {"one implicit mesh, two converters, verbose", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-v", "-C", "MeshOptimizerSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin", "quad.gltf", "quad.bin",
/* While this looks like a no-op in the output, it converts a /* While this looks like a no-op in the output, it converts a
triangle strip to indexed triangles, which verifies that the output triangle strip to indexed triangles, which verifies that the output
@ -308,7 +309,7 @@ const struct {
{"one implicit mesh, two converters, explicit last, verbose", Containers::array<Containers::String>({ {"one implicit mesh, two converters, explicit last, verbose", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "GltfSceneConverter", "-v", "-C", "MeshOptimizerSceneConverter", "-C", "GltfSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
"quad.gltf", "quad.bin", "quad.gltf", "quad.bin",
/* As the importers and converters are specified explicitly, there's /* As the importers and converters are specified explicitly, there's
no messages from AnySceneConverter, OTOH as we have more than one -C no messages from AnySceneConverter, OTOH as we have more than one -C
@ -333,7 +334,7 @@ const struct {
"-C", "MeshOptimizerSceneConverter", "-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes", "-c", "nonexistentMeshOptimizerOption=yes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"}, "Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one implicit mesh, two converters, explicit last, options for the first only", Containers::array<Containers::String>({ {"one implicit mesh, two converters, explicit last, options for the first only", Containers::array<Containers::String>({
@ -341,7 +342,7 @@ const struct {
"-c", "nonexistentMeshOptimizerOption=yes", "-c", "nonexistentMeshOptimizerOption=yes",
"-C", "StanfordSceneConverter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"}, "Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one implicit mesh, two converters, options for both", Containers::array<Containers::String>({ {"one implicit mesh, two converters, options for both", Containers::array<Containers::String>({
@ -349,7 +350,7 @@ const struct {
"-c", "nonexistentMeshOptimizerOption=yes", "-c", "nonexistentMeshOptimizerOption=yes",
"-c", "nonexistentAnyConverterOption=no", "-c", "nonexistentAnyConverterOption=no",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n" "Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"
"Trade::AnySceneConverter::beginFile(): option nonexistentAnyConverterOption not recognized by GltfSceneConverter\n"}, "Trade::AnySceneConverter::beginFile(): option nonexistentAnyConverterOption not recognized by GltfSceneConverter\n"},
@ -359,7 +360,7 @@ const struct {
"-C", "StanfordSceneConverter", "-C", "StanfordSceneConverter",
"-c", "nonexistentStanfordConverterOption=no", "-c", "nonexistentStanfordConverterOption=no",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n" "Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"
"Option nonexistentStanfordConverterOption not recognized by StanfordSceneConverter\n"}, "Option nonexistentStanfordConverterOption not recognized by StanfordSceneConverter\n"},
@ -367,7 +368,7 @@ const struct {
"--remove-duplicate-vertices", "--remove-duplicate-vertices",
"-C", "MeshOptimizerSceneConverter", "-v", "-C", "MeshOptimizerSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter", nullptr,
"quad.ply", nullptr, "quad.ply", nullptr,
"Trade::AnySceneImporter::openFile(): using ObjImporter\n" "Trade::AnySceneImporter::openFile(): using ObjImporter\n"
"Mesh 0 duplicate removal: 6 -> 4 vertices\n" "Mesh 0 duplicate removal: 6 -> 4 vertices\n"
@ -395,7 +396,7 @@ const struct {
original */ original */
"--remove-duplicate-vertices", "-c", "generator=", "--remove-duplicate-vertices", "-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-name-custom-attributes-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-name-custom-attributes.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-name-custom-attributes-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-name-custom-attributes.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
/* The output should be mostly the same, except that there's now only 4 /* The output should be mostly the same, except that there's now only 4
vertices instead of 6. The code that adds meshes manually instead of vertices instead of 6. The code that adds meshes manually instead of
using addSupportedImporterContents() should take care of propagating using addSupportedImporterContents() should take care of propagating
@ -407,13 +408,96 @@ const struct {
original */ original */
"--mesh", "0", "--remove-duplicate-vertices", "-c", "generator=", "--mesh", "0", "--remove-duplicate-vertices", "-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-name-custom-attributes-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-name-custom-attributes.gltf")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-name-custom-attributes-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-name-custom-attributes.gltf")}),
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter", nullptr,
/* The output should be mostly the same, except that there's now only 4 /* The output should be mostly the same, except that there's now only 4
vertices instead of 6. The code that adds meshes manually instead of vertices instead of 6. The code that adds meshes manually instead of
using addSupportedImporterContents() should take care of propagating using addSupportedImporterContents() should take care of propagating
mesh names and custom attributes as well. */ mesh names and custom attributes as well. */
"quad-name-custom-attributes.gltf", "quad-name-custom-attributes.bin", "quad-name-custom-attributes.gltf", "quad-name-custom-attributes.bin",
{}}, {}},
{"mesh converter", Containers::array<Containers::String>({
"-M", "MeshOptimizerSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "MeshOptimizerSceneConverter",
/* Converts a triangle strip to indexed triangles, which verifies that
the output of MeshOptimizerSceneConverter got actually passed
further and not discarded */
"quad.gltf", "quad.bin",
{}},
{"mesh converter, two meshes, verbose", Containers::array<Containers::String>({
/* Removing the generator identifier for a smaller file */
"-I", "GltfImporter", "-C", "GltfSceneConverter", "-c", "generator=",
"-M", "MeshOptimizerSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter", "MeshOptimizerSceneConverter",
"two-quads.gltf", "two-quads.bin",
"Processing mesh 0 with MeshOptimizerSceneConverter...\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"
"Processing mesh 1 with MeshOptimizerSceneConverter...\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"},
{"two mesh converters, two options, one mesh, verbose", Containers::array<Containers::String>({
"-I", "GltfImporter", "-C", "GltfSceneConverter",
"-M", "MeshOptimizerSceneConverter",
"-m", "nonexistentFirstOption=yes",
"-M", "MeshOptimizerSceneConverter",
"-m", "nonexistentSecondOption=yes", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", "MeshOptimizerSceneConverter",
"quad.gltf", "quad.bin",
"Processing mesh 0 (1/2) with MeshOptimizerSceneConverter...\n"
"Option nonexistentFirstOption not recognized by MeshOptimizerSceneConverter\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"
"Processing mesh 0 (2/2) with MeshOptimizerSceneConverter...\n"
"Option nonexistentSecondOption not recognized by MeshOptimizerSceneConverter\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"},
}; };
const struct { const struct {
@ -538,6 +622,30 @@ const struct {
"-I", "ObjImporter", "-C", "StanfordSceneConverter", "-C", "StanfordSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}), "-I", "ObjImporter", "-C", "StanfordSceneConverter", "-C", "StanfordSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter",
"StanfordSceneConverter doesn't support importer conversion, only ConvertMeshToData\n"}, "StanfordSceneConverter doesn't support importer conversion, only ConvertMeshToData\n"},
{"can't load mesh converter plugin", Containers::array<Containers::String>({
/* Override also the plugin directory for consistent output, however
then the importer plugin has to be loaded through an absolute file
path (unless using static plugins) */
"--plugin-dir", "nonexistent", "-I",
#ifndef MAGNUM_BUILD_STATIC
Utility::Path::join(MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR, "ObjImporter" + Trade::AbstractImporter::pluginSuffix()),
#else
"ObjImporter",
#endif
"-M", "NonexistentSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr,
/* Just a prefix */
"PluginManager::Manager::load(): plugin NonexistentSceneConverter is not static and was not found in nonexistent/sceneconverters\n"
"Available mesh converter plugins: "},
{"plugin doesn't support mesh conversion", Containers::array<Containers::String>({
"-I", "ObjImporter", "-M", "StanfordSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", "StanfordSceneConverter",
"StanfordSceneConverter doesn't support mesh conversion, only ConvertMeshToData\n"},
{"can't process a mesh", Containers::array<Containers::String>({
"-I", "ObjImporter", "-M", "MeshOptimizerSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", "MeshOptimizerSceneConverter",
"Trade::MeshOptimizerSceneConverter::convert(): expected a triangle mesh, got MeshPrimitive::Points\n"
"Cannot process mesh 0 with MeshOptimizerSceneConverter\n"},
}; };
#endif #endif
@ -1779,6 +1887,8 @@ void SceneConverterTest::convert() {
CORRADE_SKIP(data.requiresImporter << "plugin can't be loaded."); CORRADE_SKIP(data.requiresImporter << "plugin can't be loaded.");
if(data.requiresConverter && !(converterManager.load(data.requiresConverter) & PluginManager::LoadState::Loaded)) if(data.requiresConverter && !(converterManager.load(data.requiresConverter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresConverter << "plugin can't be loaded."); CORRADE_SKIP(data.requiresConverter << "plugin can't be loaded.");
if(data.requiresMeshConverter && !(converterManager.load(data.requiresMeshConverter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresMeshConverter << "plugin can't be loaded.");
/* AnySceneImporter & AnySceneConverter are required implicitly for /* AnySceneImporter & AnySceneConverter are required implicitly for
simplicity */ simplicity */
if(!(importerManager.load("AnySceneImporter") & PluginManager::LoadState::Loaded)) if(!(importerManager.load("AnySceneImporter") & PluginManager::LoadState::Loaded))

201
src/Magnum/SceneTools/sceneconverter.cpp

@ -117,12 +117,13 @@ magnum-sceneconverter chair.obj -C MeshOptimizerSceneConverter \
@code{.sh} @code{.sh}
magnum-sceneconverter [-h|--help] [-I|--importer PLUGIN] magnum-sceneconverter [-h|--help] [-I|--importer PLUGIN]
[-C|--converter PLUGIN]... [--plugin-dir DIR] [--map] [-C|--converter PLUGIN]... [-M|--mesh-converter PLUGIN]...
[--only-mesh-attributes N1,N2-N3] [--remove-duplicate-vertices] [--plugin-dir DIR] [--map] [--only-mesh-attributes N1,N2-N3]
[--remove-duplicate-vertices-fuzzy EPSILON] [--remove-duplicate-vertices] [--remove-duplicate-vertices-fuzzy EPSILON]
[-i|--importer-options key=val,key2=val2,] [-i|--importer-options key=val,key2=val2,]
[-c|--converter-options key=val,key2=val2,]... [--mesh ID] [-c|--converter-options key=val,key2=val2,]...
[--mesh-level INDEX] [--concatenate-meshes] [--info-animations] [-m|--mesh-converter-options key=val,key2=val2,]...
[--mesh ID] [--mesh-level INDEX] [--concatenate-meshes] [--info-animations]
[--info-images] [--info-lights] [--info-cameras] [--info-materials] [--info-images] [--info-lights] [--info-cameras] [--info-materials]
[--info-meshes] [--info-objects] [--info-scenes] [--info-skins] [--info-meshes] [--info-objects] [--info-scenes] [--info-skins]
[--info-textures] [--info] [--color on|4bit|off|auto] [--bounds] [--info-textures] [--info] [--color on|4bit|off|auto] [--bounds]
@ -137,6 +138,8 @@ Arguments:
- `-I`, `--importer PLUGIN` --- scene importer plugin (default: - `-I`, `--importer PLUGIN` --- scene importer plugin (default:
@ref Trade::AnySceneImporter "AnySceneImporter") @ref Trade::AnySceneImporter "AnySceneImporter")
- `-C`, `--converter PLUGIN` --- scene converter plugin(s) - `-C`, `--converter PLUGIN` --- scene converter plugin(s)
- `-M`, `--mesh-converter PLUGIN` --- converter plugin(s) to apply to each
mesh in the scene
- `--plugin-dir DIR` --- override base plugin dir - `--plugin-dir DIR` --- override base plugin dir
- `--map` --- memory-map the input for zero-copy import (works only for - `--map` --- memory-map the input for zero-copy import (works only for
standalone files) standalone files)
@ -152,7 +155,9 @@ Arguments:
- `-i`, `--importer-options key=val,key2=val2,` --- configuration options to - `-i`, `--importer-options key=val,key2=val2,` --- configuration options to
pass to the importer pass to the importer
- `-c`, `--converter-options key=val,key2=val2,` --- configuration options - `-c`, `--converter-options key=val,key2=val2,` --- configuration options
to pass to the converter(s) to pass to scene converter(s)
- `-m`, `--mesh-converter-options key=val,key2=val2,` --- configuration
options to pass to mesh converter(s)
- `--mesh ID` --- convert just a single mesh instead of the whole scene - `--mesh ID` --- convert just a single mesh instead of the whole scene
- `--mesh-level LEVEL` --- level to select for single-mesh conversion - `--mesh-level LEVEL` --- level to select for single-mesh conversion
- `--concatenate-meshes` -- flatten mesh hierarchy and concatenate them all - `--concatenate-meshes` -- flatten mesh hierarchy and concatenate them all
@ -183,29 +188,39 @@ and both `--info-*` options are specified, the output will also list reference
count (for example, `--info-scenes` together with `--info-meshes` will print count (for example, `--info-scenes` together with `--info-meshes` will print
how many objects reference given mesh). how many objects reference given mesh).
The `-i` / `--importer-options` and `-c` / `--converter-options` arguments The `-i`, `-c` and `-m` arguments accept a comma-separated list of key/value
accept a comma-separated list of key/value pairs to set in the importer / pairs to set in the importer / converter plugin configuration. If the `=`
converter plugin configuration. If the `=` character is omitted, it's character is omitted, it's equivalent to saying `key=true`; configuration
equivalent to saying `key=true`; configuration subgroups are delimited with subgroups are delimited with `/`.
`/`.
It's possible to specify the `-C` option (and correspondingly also `-c`)
It's possible to specify the `-C` / `--converter` option (and correspondingly multiple times in order to chain more converters together. All converters in
also `-c` / `--converter-options`) multiple times in order to chain more the chain have to support the
converters together. All converters in the chain have to support the @ref Trade::SceneConverterFeature::ConvertMultiple or
@ref Trade::SceneConverterFeature::ConvertMesh feature, @relativeref{Trade::SceneCOnverterFeature,ConvertMesh} feature, the last
the last converter either @ref Trade::SceneConverterFeature::ConvertMesh or converter either @ref Trade::SceneConverterFeature::ConvertMultiple,
@ref Trade::SceneConverterFeature::ConvertMeshToFile. If the last converter @relativeref{Trade::SceneCOnverterFeature,ConvertMesh},
doesn't support conversion to a file, @relativeref{Trade::SceneCOnverterFeature,ConvertMultipleToFile} or
@ref Trade::AnySceneConverter "AnySceneConverter" is used to save its output; @relativeref{Trade::SceneCOnverterFeature,ConvertMeshToFile}. If the last
if no `-C` / `--converter` is specified, converter doesn't support conversion to a file,
@ref Trade::AnySceneConverter "AnySceneConverter" is used. @relativeref{Trade,AnySceneConverter} is used to save its output. If no `-C` is
specified, @relativeref{Trade,AnySceneConverter} is used.
Similarly, the `-M` option (and correspondingly also `-m`) can be specified
multiple times in order to chain more mesh converters together. All mesh
converters in the chain have to support the ConvertMesh feature. If no `-M` is
specified, the imported meshes are passed directly to the scene converter.
The `--remove-duplicate-vertices` operations are performed before passing them
to any converter.
If `--concatenate-meshes` is given, all meshes of the input file are If `--concatenate-meshes` is given, all meshes of the input file are
concatenated into a single mesh using @ref MeshTools::concatenate(), with the first concatenated into a single mesh using @ref MeshTools::concatenate(), with
scene hierarchy transformation baked in using the scene hierarchy transformation baked in using
@ref SceneTools::flattenMeshHierarchy3D(). Only attributes that are present in @ref SceneTools::flattenMeshHierarchy3D(), and then passed through the
the first mesh are taken, if `--only-mesh-attributes` is specified as well, the remaining operations. Only attributes that are present in the first mesh are
IDs reference attributes of the first mesh. taken, if `--only-mesh-attributes` is specified as well, the IDs reference
attributes of the first mesh.
*/ */
} }
@ -237,6 +252,7 @@ int main(int argc, char** argv) {
.addArgument("output").setHelp("output", "output file; ignored if --info is present") .addArgument("output").setHelp("output", "output file; ignored if --info is present")
.addOption('I', "importer", "AnySceneImporter").setHelp("importer", "scene importer plugin", "PLUGIN") .addOption('I', "importer", "AnySceneImporter").setHelp("importer", "scene importer plugin", "PLUGIN")
.addArrayOption('C', "converter").setHelp("converter", "scene converter plugin(s)", "PLUGIN") .addArrayOption('C', "converter").setHelp("converter", "scene converter plugin(s)", "PLUGIN")
.addArrayOption('M', "mesh-converter").setHelp("mesh-converter", "converter plugin(s) to apply to each mesh in the scene", "PLUGIN")
.addOption("plugin-dir").setHelp("plugin-dir", "override base plugin dir", "DIR") .addOption("plugin-dir").setHelp("plugin-dir", "override base plugin dir", "DIR")
#if defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) #if defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT))
.addBooleanOption("map").setHelp("map", "memory-map the input for zero-copy import (works only for standalone files)") .addBooleanOption("map").setHelp("map", "memory-map the input for zero-copy import (works only for standalone files)")
@ -246,6 +262,7 @@ int main(int argc, char** argv) {
.addOption("remove-duplicate-vertices-fuzzy").setHelp("remove-duplicate-vertices-fuzzy", "remove duplicate vertices with fuzzy comparison in all meshes after import", "EPSILON") .addOption("remove-duplicate-vertices-fuzzy").setHelp("remove-duplicate-vertices-fuzzy", "remove duplicate vertices with fuzzy comparison in all meshes after import", "EPSILON")
.addOption('i', "importer-options").setHelp("importer-options", "configuration options to pass to the importer", "key=val,key2=val2,…") .addOption('i', "importer-options").setHelp("importer-options", "configuration options to pass to the importer", "key=val,key2=val2,…")
.addArrayOption('c', "converter-options").setHelp("converter-options", "configuration options to pass to the converter(s)", "key=val,key2=val2,…") .addArrayOption('c', "converter-options").setHelp("converter-options", "configuration options to pass to the converter(s)", "key=val,key2=val2,…")
.addArrayOption('m', "mesh-converter-options").setHelp("mesh-converter-options", "configuration options to pass to the mesh converter(s)", "key=val,key2=val2,…")
.addOption("mesh").setHelp("mesh", "convert just a single mesh instead of the whole scene, ignored if --concatenate-meshes is specified", "ID") .addOption("mesh").setHelp("mesh", "convert just a single mesh instead of the whole scene, ignored if --concatenate-meshes is specified", "ID")
.addOption("mesh-level").setHelp("mesh-level", "level to select for single-mesh conversion", "index") .addOption("mesh-level").setHelp("mesh-level", "level to select for single-mesh conversion", "index")
.addBooleanOption("concatenate-meshes").setHelp("concatenate-meshes", "flatten mesh hierarchy and concatenate them all together") .addBooleanOption("concatenate-meshes").setHelp("concatenate-meshes", "flatten mesh hierarchy and concatenate them all together")
@ -281,24 +298,32 @@ and both --info-* options are specified, the output will also list reference
count (for example, --info-scenes together with --info-meshes will print how count (for example, --info-scenes together with --info-meshes will print how
many objects reference given mesh). many objects reference given mesh).
The -i / --importer-options and -c / --converter-options arguments accept a The -i, -c and -m arguments accept a comma-separated list of key/value
comma-separated list of key/value pairs to set in the importer / converter pairs to set in the importer / converter plugin configuration. If the =
plugin configuration. If the = character is omitted, it's equivalent to saying character is omitted, it's equivalent to saying key=true; configuration
key=true; configuration subgroups are delimited with /. subgroups are delimited with /.
It's possible to specify the -C / --converter option (and correspondingly also It's possible to specify the -C option (and correspondingly also -c) multiple
-c / --converter-options) multiple times in order to chain more converters times in order to chain more scene converters together. All converters in the
together. All converters in the chain have to support the ConvertMesh feature, chain have to support the ConvertMultiple or ConvertMesh feature, the last
the last converter either ConvertMesh or ConvertMeshToFile. If the last converter either ConvertMultiple, ConvertMesh, ConvertMultipleToFile or
converter doesn't support conversion to a file, AnySceneConverter is used to ConvertMeshToFile. If the last converter doesn't support conversion to a file,
save its output; if no -C / --converter is specified, AnySceneConverter is AnySceneConverter is used to save its output. If no -C is specified,
used. AnySceneConverter is used.
If --concatenate-meshes is given, all meshes of the input file are concatenated Similarly, the -M option (and correspondingly also -m) can be specified
into a single mesh, with the scene hierarchy transformation baked in. Only multiple times in order to chain more mesh converters together. All mesh
attributes that are present in the first mesh are taken, if converters in the chain have to support the ConvertMesh feature. If no -M is
--only-mesh-attributes is specified as well, the IDs reference attributes of specified, the imported meshes are passed directly to the scene converter.
the first mesh.)")
The --remove-duplicate-vertices operations are performed on meshes before
passing them to any converter.
If --concatenate-meshes is given, all meshes of the input file are first
concatenated into a single mesh, with the scene hierarchy transformation baked
in, and then passed through the remaining operations. Only attributes that are
present in the first mesh are taken, if --only-mesh-attributes is specified as
well, the IDs reference attributes of the first mesh.)")
.parse(argc, argv); .parse(argc, argv);
/* Colored output. Enable only if a TTY. */ /* Colored output. Enable only if a TTY. */
@ -572,7 +597,8 @@ the first mesh.)")
meshes are supplied manually to the converter from the array below. */ meshes are supplied manually to the converter from the array below. */
Containers::Array<Trade::MeshData> meshes; Containers::Array<Trade::MeshData> meshes;
if(args.isSet("remove-duplicate-vertices") || if(args.isSet("remove-duplicate-vertices") ||
args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy")) args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy") ||
args.arrayValueCount("mesh-converter"))
{ {
for(UnsignedInt i = 0; i != importer->meshCount(); ++i) { for(UnsignedInt i = 0; i != importer->meshCount(); ++i) {
Containers::Optional<Trade::MeshData> mesh; Containers::Optional<Trade::MeshData> mesh;
@ -586,30 +612,71 @@ the first mesh.)")
} }
} }
const UnsignedInt beforeVertexCount = mesh->vertexCount(); /* Duplicate removal */
const bool fuzzy = !!args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy"); if(args.isSet("remove-duplicate-vertices") ||
args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy"))
{
const UnsignedInt beforeVertexCount = mesh->vertexCount();
const bool fuzzy = !!args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy");
/** @todo accept two values for float and double fuzzy comparison, /** @todo accept two values for float and double fuzzy
or maybe also different for positions, normals and texcoords? comparison, or maybe also different for positions, normals
ugh... */ and texcoords? ugh... */
if(fuzzy) { if(fuzzy) {
Trade::Implementation::Duration d{conversionTime}; Trade::Implementation::Duration d{conversionTime};
mesh = MeshTools::removeDuplicatesFuzzy(*std::move(mesh), args.value<Float>("remove-duplicate-vertices-fuzzy")); mesh = MeshTools::removeDuplicatesFuzzy(*std::move(mesh), args.value<Float>("remove-duplicate-vertices-fuzzy"));
} else { } else {
Trade::Implementation::Duration d{conversionTime}; Trade::Implementation::Duration d{conversionTime};
mesh = MeshTools::removeDuplicates(*std::move(mesh)); mesh = MeshTools::removeDuplicates(*std::move(mesh));
}
if(args.isSet("verbose")) {
Debug d;
/* Mesh index 0 would be confusing in case of
--concatenate-meshes and plain wrong with --mesh, so
don't even print it */
if(singleMesh)
d << (fuzzy ? "Fuzzy duplicate removal:" : "Duplicate removal:");
else
d << "Mesh" << i << (fuzzy ? "fuzzy duplicate removal:" : "duplicate removal:");
d << beforeVertexCount << "->" << mesh->vertexCount() << "vertices";
}
} }
if(args.isSet("verbose")) { /* Arbitrary mesh converters */
Debug d; for(std::size_t j = 0, meshConverterCount = args.arrayValueCount("mesh-converter"); j != meshConverterCount; ++j) {
/* Mesh index 0 would be confusing in case of const Containers::StringView meshConverterName = args.arrayValue<Containers::StringView>("mesh-converter", j);
--concatenate-meshes and plain wrong with --mesh, so if(args.isSet("verbose")) {
don't even print it */ Debug d;
if(singleMesh) d << "Processing mesh" << i;
d << (fuzzy ? "Fuzzy duplicate removal:" : "Duplicate removal:"); if(meshConverterCount > 1)
else d << "(" << Debug::nospace << (j+1) << Debug::nospace << "/" << Debug::nospace << meshConverterCount << Debug::nospace << ")";
d << "Mesh" << i << (fuzzy ? "fuzzy duplicate removal:" : "duplicate removal:"); d << "with" << meshConverterName << Debug::nospace << "...";
d << beforeVertexCount << "->" << mesh->vertexCount() << "vertices"; }
Containers::Pointer<Trade::AbstractSceneConverter> meshConverter = converterManager.loadAndInstantiate(meshConverterName);
if(!meshConverter) {
Debug{} << "Available mesh converter plugins:" << ", "_s.join(converterManager.aliasList());
return 2;
}
/* Set options, if passed. The AnySceneConverter check makes no
sense here, is just there because the helper wants it */
if(args.isSet("verbose")) meshConverter->addFlags(Trade::SceneConverterFlag::Verbose);
if(j < args.arrayValueCount("mesh-converter-options"))
Implementation::setOptions(*meshConverter, "AnySceneConverter", args.arrayValue("mesh-converter-options", j));
if(!(meshConverter->features() & (Trade::SceneConverterFeature::ConvertMesh))) {
Error{} << meshConverterName << "doesn't support mesh conversion, only" << Debug::packed << meshConverter->features();
return 1;
}
/** @todo handle mesh levels here, once any plugin is capable
of converting them */
if(!(mesh = meshConverter->convert(*mesh))) {
Error{} << "Cannot process mesh" << i << "with" << meshConverterName;
return 1;
}
} }
arrayAppend(meshes, *std::move(mesh)); arrayAppend(meshes, *std::move(mesh));

Loading…
Cancel
Save