Browse Source

sceneconverter: initial support for whole-scene conversion.

Quite boring commit message for such a FEATURE, eh?? Yes, the docs need
updating at least.
pull/594/head
Vladimír Vondruš 4 years ago
parent
commit
682ba2c41c
  1. 10
      doc/changelog.dox
  2. 6
      src/Magnum/SceneTools/Test/CMakeLists.txt
  3. 165
      src/Magnum/SceneTools/Test/SceneConverterTest.cpp
  4. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates-fuzzy.bin
  5. 33
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates-fuzzy.bin.in
  6. 99
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf
  7. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates.bin
  8. 33
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates.bin.in
  9. 99
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates.gltf
  10. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads.bin
  11. 99
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads.gltf
  12. 409
      src/Magnum/SceneTools/sceneconverter.cpp

10
doc/changelog.dox

@ -220,6 +220,8 @@ See also:
- New @ref SceneTools library that'll be a home for various whole-scene - New @ref SceneTools library that'll be a home for various whole-scene
optimization algorithms such as hierarchy flattening, redundant node optimization algorithms such as hierarchy flattening, redundant node
removal and such removal and such
- The @ref magnum-sceneconverter "magnum-sceneconverter" utility now supports
whole-scene conversion instead of operating just on single meshes
- The @ref magnum-sceneconverter "magnum-sceneconverter" utility gained an - The @ref magnum-sceneconverter "magnum-sceneconverter" utility gained an
experimental `--concatenate-meshes` option, which will flatten the mesh experimental `--concatenate-meshes` option, which will flatten the mesh
hierarchy and concatenate all meshes together. Note that it doesn't hierarchy and concatenate all meshes together. Note that it doesn't
@ -1141,6 +1143,14 @@ See also:
`--only-mesh-attributes`, `--remove-duplicate-vertices` and `--only-mesh-attributes`, `--remove-duplicate-vertices` and
`--remove-duplicate-vertices-fuzzy`, respectively, to make it clear they `--remove-duplicate-vertices-fuzzy`, respectively, to make it clear they
affect meshes and not other scene content affect meshes and not other scene content
- The @ref magnum-sceneconverter "magnum-sceneconverter"
`--mesh-level` option now requires `--mesh` to be specified as well,
instead of being ignored if `--mesh` isn't present
- Because the @ref magnum-sceneconverter "magnum-sceneconverter"
`--only-mesh-attributes` option takes attribute IDs, it can only be used in
combination with `--mesh` or `--concatenate-meshes`. This restriction might
be eventually lifted again once it's possible to specify attributes by
name.
- Due to the rework of @ref Shaders::PhongGL to support directional and - Due to the rework of @ref Shaders::PhongGL to support directional and
attenuated point lights, the original behavior of unattenuated point lights attenuated point lights, the original behavior of unattenuated point lights
isn't available anymore. For backwards compatibility, light positions isn't available anymore. For backwards compatibility, light positions

6
src/Magnum/SceneTools/Test/CMakeLists.txt

@ -86,6 +86,12 @@ corrade_add_test(SceneToolsSceneConverterTest SceneConverterTest.cpp
SceneConverterTestFiles/quad.gltf SceneConverterTestFiles/quad.gltf
SceneConverterTestFiles/quad.obj SceneConverterTestFiles/quad.obj
SceneConverterTestFiles/quad.ply SceneConverterTestFiles/quad.ply
SceneConverterTestFiles/two-quads-duplicates-fuzzy.bin
SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf
SceneConverterTestFiles/two-quads-duplicates.bin
SceneConverterTestFiles/two-quads-duplicates.gltf
SceneConverterTestFiles/two-quads.bin
SceneConverterTestFiles/two-quads.gltf
SceneConverterTestFiles/two-triangles-transformed.bin SceneConverterTestFiles/two-triangles-transformed.bin
SceneConverterTestFiles/two-triangles-transformed.gltf SceneConverterTestFiles/two-triangles-transformed.gltf
SceneConverterTestFiles/two-triangles.obj) SceneConverterTestFiles/two-triangles.obj)

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

@ -151,7 +151,7 @@ const struct {
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter",
"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::convertToFile(): option nonexistentConverterOption not recognized by StanfordSceneConverter\n"}, "Trade::AnySceneConverter::beginFile(): option nonexistentConverterOption not recognized by StanfordSceneConverter\n"},
{"one mesh, options, explicit importer and converter", Containers::array<Containers::String>({ {"one mesh, options, explicit importer and converter", Containers::array<Containers::String>({
/* Same here, since we have option propagation tested in /* Same here, since we have option propagation tested in
Magnum/Test/ConverterUtilitiesTest.cpp already, to verify it's Magnum/Test/ConverterUtilitiesTest.cpp already, to verify it's
@ -163,6 +163,14 @@ const struct {
"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"},
{"two meshes + scene", Containers::array<Containers::String>({
/* Removing the generator identifier to have the file fully roundtrip */
"-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter",
/* There should be a minimal difference compared to the original */
"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")}),
@ -175,54 +183,105 @@ const struct {
"GltfImporter", "StanfordSceneConverter", "GltfImporter", "StanfordSceneConverter",
"quad-duplicates.ply", nullptr, "quad-duplicates.ply", nullptr,
{}}, {}},
{"filter mesh attributes", Containers::array<Containers::String>({ /** @todo drop --mesh once it's not needed anymore again, then add a
multi-mesh variant */
{"one mesh, filter mesh attributes", Containers::array<Containers::String>({
/* Only 0 gets picked from here, others ignored */ /* Only 0 gets picked from here, others ignored */
"--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")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply", nullptr,
{}},
{"concatenate meshes, filter mesh attributes", Containers::array<Containers::String>({
"--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",
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"remove duplicate vertices", 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",
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"remove duplicate vertices, verbose", Containers::array<Containers::String>({ {"one implicit mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({
/* Forcing the importer and converter to avoid AnySceneImporter / /* Forcing the importer and converter to avoid AnySceneImporter /
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",
"quad.ply", nullptr, "quad.ply", nullptr,
"Mesh 0 duplicate removal: 6 -> 4 vertices\n"},
{"one selected mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({
/* Forcing the importer and converter to avoid AnySceneImporter /
AnySceneConverter delegation messages */
"--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")}),
"GltfImporter", "StanfordSceneConverter",
/* The second mesh in the glTF is deliberately the same as in
quad-duplicates.obj, so this produces the same file */
"quad.ply", nullptr,
"Duplicate removal: 6 -> 4 vertices\n"}, "Duplicate removal: 6 -> 4 vertices\n"},
{"remove duplicate vertices fuzzy", Containers::array<Containers::String>({ {"two meshes + scene, remove duplicate vertices, verbose", Containers::array<Containers::String>({
/* Forcing the importer and converter to avoid AnySceneImporter /
AnySceneConverter delegation messages */
"--remove-duplicate-vertices", "-v", "-I", "GltfImporter", "-C", "GltfSceneConverter",
/* Removing the generator identifier for a smaller file */
"-c", "generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}),
"GltfImporter", "GltfSceneConverter",
/* There should be a minimal difference compared to the original */
"two-quads.gltf", "two-quads.bin",
"Mesh 0 duplicate removal: 5 -> 4 vertices\n"
"Mesh 1 duplicate removal: 6 -> 4 vertices\n"},
{"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",
"quad.ply", nullptr, "quad.ply", nullptr,
{}}, {}},
{"remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({ {"one implicit mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({
/* Forcing the importer and converter to avoid AnySceneImporter / /* Forcing the importer and converter to avoid AnySceneImporter /
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",
"quad.ply", nullptr, "quad.ply", nullptr,
"Mesh 0 fuzzy duplicate removal: 6 -> 4 vertices\n"},
{"one selected mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({
/* Forcing the importer and converter to avoid AnySceneImporter /
AnySceneConverter delegation messages */
"--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")}),
"GltfImporter", "StanfordSceneConverter",
/* The second mesh in the glTF is deliberately the same as in
quad-duplicates-fuzzy.obj, so this produces the same file */
"quad.ply", nullptr,
"Fuzzy duplicate removal: 6 -> 4 vertices\n"}, "Fuzzy duplicate removal: 6 -> 4 vertices\n"},
{"one mesh, two converters", Containers::array<Containers::String>({ {"two meshes + scene, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({
/* Forcing the importer and converter to avoid AnySceneImporter /
AnySceneConverter delegation messages */
"--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "GltfImporter", "-C", "GltfSceneConverter",
/* Removing the generator identifier for a smaller file */
"-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")}),
"GltfImporter", "GltfSceneConverter",
"two-quads.gltf", "two-quads.bin",
"Mesh 0 fuzzy duplicate removal: 5 -> 4 vertices\n"
"Mesh 1 fuzzy duplicate removal: 6 -> 4 vertices\n"},
{"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",
"quad.gltf", "quad.bin", "quad.gltf", "quad.bin",
{}}, {}},
{"one 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",
"quad.gltf", "quad.bin", "quad.gltf", "quad.bin",
{}}, {}},
{"one 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",
@ -245,8 +304,8 @@ const struct {
" 65536 -> 65536 shaded pixels\n" " 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n" " 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n" " overdraw 1 -> 1\n"
"Trade::AnySceneConverter::convertToFile(): using GltfSceneConverter\n"}, "Trade::AnySceneConverter::beginFile(): using GltfSceneConverter\n"},
{"one 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",
@ -270,14 +329,14 @@ const struct {
" 65536 -> 65536 covered pixels\n" " 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n" " overdraw 1 -> 1\n"
"Saving output (2/2) with GltfSceneConverter...\n"}, "Saving output (2/2) with GltfSceneConverter...\n"},
{"one mesh, two converters, options for the first only", Containers::array<Containers::String>({ {"one implicit mesh, two converters, options for the first only", Containers::array<Containers::String>({
"-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",
"quad.ply", nullptr, "quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"}, "Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one 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>({
"-C", "MeshOptimizerSceneConverter", "-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes", "-c", "nonexistentMeshOptimizerOption=yes",
"-C", "StanfordSceneConverter", "-C", "StanfordSceneConverter",
@ -285,7 +344,7 @@ const struct {
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter",
"quad.ply", nullptr, "quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"}, "Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one mesh, two converters, options for both", Containers::array<Containers::String>({ {"one implicit mesh, two converters, options for both", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes", "-c", "nonexistentMeshOptimizerOption=yes",
"-c", "nonexistentAnyConverterOption=no", "-c", "nonexistentAnyConverterOption=no",
@ -293,8 +352,8 @@ const struct {
"GltfImporter", "GltfSceneConverter", "GltfImporter", "GltfSceneConverter",
"quad.ply", nullptr, "quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n" "Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"
"Trade::AnySceneConverter::convertToFile(): option nonexistentAnyConverterOption not recognized by GltfSceneConverter\n"}, "Trade::AnySceneConverter::beginFile(): option nonexistentAnyConverterOption not recognized by GltfSceneConverter\n"},
{"one mesh, two converters, explicit last, options for both", Containers::array<Containers::String>({ {"one implicit mesh, two converters, explicit last, options for both", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes", "-c", "nonexistentMeshOptimizerOption=yes",
"-C", "StanfordSceneConverter", "-C", "StanfordSceneConverter",
@ -311,7 +370,7 @@ const struct {
"ObjImporter", "StanfordSceneConverter", "ObjImporter", "StanfordSceneConverter",
"quad.ply", nullptr, "quad.ply", nullptr,
"Trade::AnySceneImporter::openFile(): using ObjImporter\n" "Trade::AnySceneImporter::openFile(): using ObjImporter\n"
"Duplicate removal: 6 -> 4 vertices\n" "Mesh 0 duplicate removal: 6 -> 4 vertices\n"
/** @todo this only verifies that the result of duplicate removal is /** @todo this only verifies that the result of duplicate removal is
properly passed to MeshOptimizer, but not that the MeshOptimizer properly passed to MeshOptimizer, but not that the MeshOptimizer
output is properly passed to StanfordSceneConverter -- needs to output is properly passed to StanfordSceneConverter -- needs to
@ -330,7 +389,7 @@ const struct {
" 65536 -> 65536 shaded pixels\n" " 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n" " 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n" " overdraw 1 -> 1\n"
"Trade::AnySceneConverter::convertToFile(): using StanfordSceneConverter\n"}, "Trade::AnySceneConverter::beginFile(): using StanfordSceneConverter\n"},
}; };
const struct { const struct {
@ -347,6 +406,18 @@ const struct {
No need to test anything else as that's handled by Utility::Arguments No need to test anything else as that's handled by Utility::Arguments
already. Testing just a prefix of the message. */ already. Testing just a prefix of the message. */
"Missing command-line argument output\nUsage:\n "}, "Missing command-line argument output\nUsage:\n "},
{"--mesh and --concatenate-meshes", Containers::array<Containers::String>({
"--mesh", "0", "--concatenate-meshes", "a", "b"}),
nullptr, nullptr,
"The --mesh and --concatenate-meshes options are mutually exclusive\n"},
{"--mesh-level but no --mesh", Containers::array<Containers::String>({
"--mesh-level", "0", "a", "b"}),
nullptr, nullptr,
"The --mesh-level option can only be used with --mesh\n"},
{"--only-mesh-attributes but no --mesh", Containers::array<Containers::String>({
"--only-mesh-attributes", "0", "a", "b"}),
nullptr, nullptr,
"The --only-mesh-attributes option can only be used with --mesh or --concatenate-meshes\n"},
{"can't load importer plugin", Containers::array<Containers::String>({ {"can't load importer plugin", Containers::array<Containers::String>({
/* Override also the plugin directory for consistent output */ /* Override also the plugin directory for consistent output */
"--plugin-dir", "nonexistent", "-I", "NonexistentImporter", "whatever.obj", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}), "--plugin-dir", "nonexistent", "-I", "NonexistentImporter", "whatever.obj", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
@ -363,12 +434,13 @@ const struct {
"AnySceneImporter", nullptr, "AnySceneImporter", nullptr,
"Utility::Path::mapRead(): can't open noexistent.ffs: error 2 (No such file or directory)\n" "Utility::Path::mapRead(): can't open noexistent.ffs: error 2 (No such file or directory)\n"
"Cannot memory-map file noexistent.ffs\n"}, "Cannot memory-map file noexistent.ffs\n"},
{"no meshes found", Containers::array<Containers::String>({ {"no meshes found for concatenation", Containers::array<Containers::String>({
"--concatenate-meshes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/empty.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}), Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/empty.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"GltfImporter", nullptr, "GltfImporter", nullptr,
Utility::format("No meshes found in {}\n", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/empty.gltf"))}, Utility::format("No meshes found in {}\n", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/empty.gltf"))},
{"can't import a mesh", Containers::array<Containers::String>({ {"can't import a single mesh", Containers::array<Containers::String>({
"-I", "ObjImporter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-mesh.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}), "-I", "ObjImporter", "--mesh", "0", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-mesh.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr, "ObjImporter", nullptr,
"Trade::ObjImporter::mesh(): wrong index count for point\n" "Trade::ObjImporter::mesh(): wrong index count for point\n"
"Cannot import the mesh\n"}, "Cannot import the mesh\n"},
@ -384,8 +456,14 @@ const struct {
"GltfImporter", nullptr, "GltfImporter", nullptr,
"Trade::GltfImporter::scene(): mesh index 1 in node 0 out of range for 1 meshes\n" "Trade::GltfImporter::scene(): mesh index 1 in node 0 out of range for 1 meshes\n"
"Cannot import scene 0 for mesh concatenation\n"}, "Cannot import scene 0 for mesh concatenation\n"},
{"invalid attribute filter", Containers::array<Containers::String>({ {"can't import a mesh for per-mesh processing", Containers::array<Containers::String>({
"-I", "ObjImporter", "--only-mesh-attributes", "LOLNEIN", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}), "-I", "ObjImporter", "--remove-duplicate-vertices", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-mesh.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr,
"Trade::ObjImporter::mesh(): wrong index count for point\n"
"Cannot import mesh 0\n"},
{"invalid mesh attribute filter", Containers::array<Containers::String>({
/** @todo drop --mesh once it's not needed anymore again */
"-I", "ObjImporter", "--mesh", "0", "--only-mesh-attributes", "LOLNEIN", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr, "ObjImporter", nullptr,
"Utility::parseNumberSequence(): unrecognized character L in LOLNEIN\n"}, "Utility::parseNumberSequence(): unrecognized character L in LOLNEIN\n"},
{"can't load converter plugin", Containers::array<Containers::String>({ {"can't load converter plugin", Containers::array<Containers::String>({
@ -403,22 +481,39 @@ const struct {
/* Just a prefix */ /* Just a prefix */
"PluginManager::Manager::load(): plugin NonexistentSceneConverter is not static and was not found in nonexistent/sceneconverters\n" "PluginManager::Manager::load(): plugin NonexistentSceneConverter is not static and was not found in nonexistent/sceneconverters\n"
"Available converter plugins: "}, "Available converter plugins: "},
{"file coversion failed", Containers::array<Containers::String>({ {"file coversion begin failed", Containers::array<Containers::String>({
"-I", "ObjImporter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.fbx")}), "-I", "ObjImporter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.fbx")}),
"ObjImporter", "AnySceneConverter", "ObjImporter", "AnySceneConverter",
Utility::format("Trade::AnySceneConverter::convertToFile(): cannot determine the format of {0}\n" Utility::format("Trade::AnySceneConverter::beginFile(): cannot determine the format of {0}\n"
"Cannot save file {0}\n", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.fbx"))}, "Cannot begin conversion of file {0}\n", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.fbx"))},
{"mesh coversion failed", Containers::array<Containers::String>({ {"file coversion end failed", Containers::array<Containers::String>({
"-I", "ObjImporter", "-C", "MeshOptimizerSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}), "-I", "GltfImporter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/empty.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", "MeshOptimizerSceneConverter", "GltfImporter", "StanfordSceneConverter",
"Trade::MeshOptimizerSceneConverter::convert(): expected a triangle mesh, got MeshPrimitive::Points\n" Utility::format("Trade::AbstractSceneConverter::endFile(): the converter requires exactly one mesh, got 0\n"
"MeshOptimizerSceneConverter cannot convert the mesh\n"}, "Cannot end conversion of file {0}\n", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply"))},
{"plugin doesn't support mesh conversion", Containers::array<Containers::String>({ /** @todo importer conversion begin failed, once there's a plugin for which
begin() can fail */
{"importer coversion end failed", Containers::array<Containers::String>({
"-I", "GltfImporter", "-C", "MeshOptimizerSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/empty.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"GltfImporter", "MeshOptimizerSceneConverter",
"Trade::AbstractSceneConverter::end(): the converter requires exactly one mesh, got 0\n"
"Cannot end importer conversion\n"},
{"can't add importer contents", Containers::array<Containers::String>({
"-I", "ObjImporter", "-C", "StanfordSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-mesh.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", "StanfordSceneConverter",
"Trade::ObjImporter::mesh(): wrong index count for point\n"
"Cannot add importer contents\n"},
{"can't add processed meshes", Containers::array<Containers::String>({
"-I", "ObjImporter", "-C", "StanfordSceneConverter", "--remove-duplicate-vertices", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", "StanfordSceneConverter",
"Trade::AbstractSceneConverter::add(): the converter requires exactly one mesh, got 2\n"
"Cannot add mesh 1\n"},
{"plugin doesn't support importer conversion", Containers::array<Containers::String>({
/* Pass the same plugin twice, which means the first instance should /* Pass the same plugin twice, which means the first instance should
get used for a mesh-to-mesh conversion */ get used for a mesh-to-mesh conversion */
"-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 mesh conversion, only Trade::SceneConverterFeature::ConvertMeshToData\n"}, "StanfordSceneConverter doesn't support importer conversion, only Trade::SceneConverterFeature::ConvertMeshToData\n"},
}; };
#endif #endif

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates-fuzzy.bin

Binary file not shown.

33
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates-fuzzy.bin.in

@ -0,0 +1,33 @@
type = "6I 3f3f3f 3f3f 6I 3f3f3f 3f3f3f"
input = [
# 2 2--4
# |\ \ |
# | \ \|
# 0--1 3
0, 1, 2, 2, 3, 4,
-10, -10, 10,
10, -10, 10,
-10, 10, 10,
9.9, -9.9, 10,
10, 10, 10,
# 2 3--5
# |\ \ |
# | \ \|
# 0--1 4
0, 1, 2, 3, 4, 5,
-1, -1, 0,
1, -1, 0,
-1, 1, 0,
-0.9, 0.9, 0,
0.9, -0.9, 0,
1, 1, 0,
]
# kate: hl python

99
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf

@ -0,0 +1,99 @@
{
"asset": {
"version": "2.0"
},
"buffers": [
{
"uri": "two-quads-duplicates-fuzzy.bin",
"byteLength": 180
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 24
},
{
"buffer": 0,
"byteOffset": 24,
"byteLength": 60
},
{
"buffer": 0,
"byteOffset": 84,
"byteLength": 24
},
{
"buffer": 0,
"byteOffset": 108,
"byteLength": 72
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5125,
"count": 6,
"type": "SCALAR"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 5,
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5125,
"count": 6,
"type": "SCALAR"
},
{
"bufferView": 3,
"componentType": 5126,
"count": 6,
"type": "VEC3"
}
],
"meshes": [
{
"primitives": [
{
"indices": 0,
"attributes": {
"POSITION": 1
}
}
]
},
{
"primitives": [
{
"indices": 2,
"attributes": {
"POSITION": 3
}
}
]
}
],
"nodes": [
{
"translation": [0, 0, 1],
"mesh": 0
},
{
"children": [2]
},
{
"scale": [0.1, 0.1, 0.1],
"mesh": 1
}
],
"scenes": [
{
"nodes": [0, 1]
}
]
}

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates.bin

Binary file not shown.

33
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates.bin.in

@ -0,0 +1,33 @@
type = "6I 3f3f3f 3f3f 6I 3f3f3f 3f3f3f"
input = [
# 2 2--4
# |\ \ |
# | \ \|
# 0--1 3
0, 1, 2, 2, 3, 4,
-10, -10, 10,
10, -10, 10,
-10, 10, 10,
10, -10, 10,
10, 10, 10,
# 2 3--5
# |\ \ |
# | \ \|
# 0--1 4
0, 1, 2, 3, 4, 5,
-1, -1, 0,
1, -1, 0,
-1, 1, 0,
-1, 1, 0,
1, -1, 0,
1, 1, 0,
]
# kate: hl python

99
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads-duplicates.gltf

@ -0,0 +1,99 @@
{
"asset": {
"version": "2.0"
},
"buffers": [
{
"uri": "two-quads-duplicates.bin",
"byteLength": 180
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 24
},
{
"buffer": 0,
"byteOffset": 24,
"byteLength": 60
},
{
"buffer": 0,
"byteOffset": 84,
"byteLength": 24
},
{
"buffer": 0,
"byteOffset": 108,
"byteLength": 72
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5125,
"count": 6,
"type": "SCALAR"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 5,
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5125,
"count": 6,
"type": "SCALAR"
},
{
"bufferView": 3,
"componentType": 5126,
"count": 6,
"type": "VEC3"
}
],
"meshes": [
{
"primitives": [
{
"indices": 0,
"attributes": {
"POSITION": 1
}
}
]
},
{
"primitives": [
{
"indices": 2,
"attributes": {
"POSITION": 3
}
}
]
}
],
"nodes": [
{
"translation": [0, 0, 1],
"mesh": 0
},
{
"children": [2]
},
{
"scale": [0.1, 0.1, 0.1],
"mesh": 1
}
],
"scenes": [
{
"nodes": [0, 1]
}
]
}

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads.bin

Binary file not shown.

99
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-quads.gltf

@ -0,0 +1,99 @@
{
"asset": {
"version": "2.0"
},
"buffers": [
{
"uri": "two-quads.bin",
"byteLength": 144
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 24
},
{
"buffer": 0,
"byteOffset": 24,
"byteLength": 48
},
{
"buffer": 0,
"byteOffset": 72,
"byteLength": 24
},
{
"buffer": 0,
"byteOffset": 96,
"byteLength": 48
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5125,
"count": 6,
"type": "SCALAR"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 4,
"type": "VEC3"
},
{
"bufferView": 2,
"componentType": 5125,
"count": 6,
"type": "SCALAR"
},
{
"bufferView": 3,
"componentType": 5126,
"count": 4,
"type": "VEC3"
}
],
"meshes": [
{
"primitives": [
{
"indices": 0,
"attributes": {
"POSITION": 1
}
}
]
},
{
"primitives": [
{
"indices": 2,
"attributes": {
"POSITION": 3
}
}
]
}
],
"nodes": [
{
"translation": [0, 0, 1],
"mesh": 0
},
{
"children": [2]
},
{
"scale": [0.1, 0.1, 0.1],
"mesh": 1
}
],
"scenes": [
{
"nodes": [0, 1]
}
]
}

409
src/Magnum/SceneTools/sceneconverter.cpp

@ -33,11 +33,13 @@
#include <Corrade/Utility/Path.h> #include <Corrade/Utility/Path.h>
#include "Magnum/MeshTools/Concatenate.h" #include "Magnum/MeshTools/Concatenate.h"
#include "Magnum/MeshTools/Reference.h"
#include "Magnum/MeshTools/RemoveDuplicates.h" #include "Magnum/MeshTools/RemoveDuplicates.h"
#include "Magnum/MeshTools/Transform.h" #include "Magnum/MeshTools/Transform.h"
#include "Magnum/SceneTools/FlattenMeshHierarchy.h" #include "Magnum/SceneTools/FlattenMeshHierarchy.h"
#include "Magnum/Trade/AbstractImporter.h" #include "Magnum/Trade/AbstractImporter.h"
#include "Magnum/Trade/MeshData.h" #include "Magnum/Trade/MeshData.h"
#include "Magnum/Trade/AbstractImageConverter.h"
#include "Magnum/Trade/AbstractSceneConverter.h" #include "Magnum/Trade/AbstractSceneConverter.h"
#include "Magnum/Implementation/converterUtilities.h" #include "Magnum/Implementation/converterUtilities.h"
@ -142,18 +144,17 @@ Arguments:
given IDs in the output. See @ref Utility::String::parseNumberSequence() given IDs in the output. See @ref Utility::String::parseNumberSequence()
for syntax description. for syntax description.
- `--remove-duplicate-vertices` --- remove duplicate vertices using - `--remove-duplicate-vertices` --- remove duplicate vertices using
@ref MeshTools::removeDuplicates(const Trade::MeshData&) after import @ref MeshTools::removeDuplicates(const Trade::MeshData&) in all meshes
after import
- `--remove-duplicate-vertices-fuzzy EPSILON` --- remove duplicate vertices - `--remove-duplicate-vertices-fuzzy EPSILON` --- remove duplicate vertices
using @ref MeshTools::removeDuplicatesFuzzy(const Trade::MeshData&, Float, Double) using @ref MeshTools::removeDuplicatesFuzzy(const Trade::MeshData&, Float, Double)
after import in all meshes after import
- `-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 the converter(s)
- `--mesh ID` --- mesh to import (default: `0`), ignored if - `--mesh ID` --- convert just a single mesh instead of the whole scene
`--concatenate-meshes` is specified - `--mesh-level LEVEL` --- level to select for single-mesh conversion
- `--mesh-level INDEX` --- mesh level to import (default: `0`), ignored if
`--concatenate-meshes` is specified
- `--concatenate-meshes` -- flatten mesh hierarchy and concatenate them all - `--concatenate-meshes` -- flatten mesh hierarchy and concatenate them all
together @m_class{m-label m-warning} **experimental** together @m_class{m-label m-warning} **experimental**
- `--info-animations` --- print into about animations in the input file and - `--info-animations` --- print into about animations in the input file and
@ -241,12 +242,12 @@ int main(int argc, char** argv) {
.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)")
#endif #endif
.addOption("only-mesh-attributes").setHelp("only-mesh-attributes", "include only mesh attributes of given IDs in the output", "N1,N2-N3…") .addOption("only-mesh-attributes").setHelp("only-mesh-attributes", "include only mesh attributes of given IDs in the output", "N1,N2-N3…")
.addBooleanOption("remove-duplicate-vertices").setHelp("remove-duplicate-vertices", "remove duplicate vertices in the mesh after import") .addBooleanOption("remove-duplicate-vertices").setHelp("remove-duplicate-vertices", "remove duplicate vertices in all meshes after import")
.addOption("remove-duplicate-vertices-fuzzy").setHelp("remove-duplicate-vertices-fuzzy", "remove duplicate vertices with fuzzy comparison in the mesh 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,…")
.addOption("mesh", "0").setHelp("mesh", "mesh to import, 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", "0").setHelp("mesh-level", "mesh level to import, ignored if --concatenate-meshes is specified", "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")
.addBooleanOption("info-animations").setHelp("info-animations", "print info about animations in the input file and exit") .addBooleanOption("info-animations").setHelp("info-animations", "print info about animations in the input file and exit")
.addBooleanOption("info-images").setHelp("info-images", "print info about images in the input file and exit") .addBooleanOption("info-images").setHelp("info-images", "print info about images in the input file and exit")
@ -333,16 +334,38 @@ the first mesh.)")
if(isInfoRequested(args)) if(isInfoRequested(args))
Warning{} << "Ignoring output file for --info:" << args.value<Containers::StringView>("output"); Warning{} << "Ignoring output file for --info:" << args.value<Containers::StringView>("output");
} }
if(args.isSet("concatenate-meshes") && args.value<Containers::StringView>("mesh")) {
Error{} << "The --mesh and --concatenate-meshes options are mutually exclusive";
return 1;
}
if(args.value<Containers::StringView>("mesh-level") && !args.value<Containers::StringView>("mesh")) {
Error{} << "The --mesh-level option can only be used with --mesh";
return 1;
}
/** @todo remove this once only-attributes can work with attribute names
and thus for more meshes */
if(args.value<Containers::StringView>("only-mesh-attributes") && !args.value<Containers::StringView>("mesh") && !args.isSet("concatenate-meshes")) {
Error{} << "The --only-mesh-attributes option can only be used with --mesh or --concatenate-meshes";
return 1;
}
/* Importer manager */ /* Importer manager */
PluginManager::Manager<Trade::AbstractImporter> importerManager{ PluginManager::Manager<Trade::AbstractImporter> importerManager{
args.value("plugin-dir").empty() ? Containers::String{} : args.value("plugin-dir").empty() ? Containers::String{} :
Utility::Path::join(args.value("plugin-dir"), Utility::Path::split(Trade::AbstractImporter::pluginSearchPaths().back()).second())}; Utility::Path::join(args.value("plugin-dir"), Utility::Path::split(Trade::AbstractImporter::pluginSearchPaths().back()).second())};
/* Scene converter manager */ /* Image converter manager for potential dependencies. Needs to be
constructed before the scene converter manager for proper destruction
order. */
PluginManager::Manager<Trade::AbstractImageConverter> imageConverterManager{
args.value("plugin-dir").empty() ? Containers::String{} :
Utility::Path::join(args.value("plugin-dir"), Trade::AbstractImageConverter::pluginSearchPaths().back())};
/* Scene converter manager, register the image converter manager with it */
PluginManager::Manager<Trade::AbstractSceneConverter> converterManager{ PluginManager::Manager<Trade::AbstractSceneConverter> converterManager{
args.value("plugin-dir").empty() ? Containers::String{} : args.value("plugin-dir").empty() ? Containers::String{} :
Utility::Path::join(args.value("plugin-dir"), Utility::Path::split(Trade::AbstractSceneConverter::pluginSearchPaths().back()).second())}; Utility::Path::join(args.value("plugin-dir"), Utility::Path::split(Trade::AbstractSceneConverter::pluginSearchPaths().back()).second())};
converterManager.registerExternalManager(imageConverterManager);
Containers::Pointer<Trade::AbstractImporter> importer = importerManager.loadAndInstantiate(args.value("importer")); Containers::Pointer<Trade::AbstractImporter> importer = importerManager.loadAndInstantiate(args.value("importer"));
if(!importer) { if(!importer) {
@ -354,14 +377,19 @@ the first mesh.)")
if(args.isSet("verbose")) importer->addFlags(Trade::ImporterFlag::Verbose); if(args.isSet("verbose")) importer->addFlags(Trade::ImporterFlag::Verbose);
Implementation::setOptions(*importer, "AnySceneImporter", args.value("importer-options")); Implementation::setOptions(*importer, "AnySceneImporter", args.value("importer-options"));
/* Wow, C++, you suck. This implicitly initializes to random shit?! */ /* Wow, C++, you suck. This implicitly initializes to random shit?!
std::chrono::high_resolution_clock::duration importTime{};
Also, because of addSupportedImporterContents() it's not really possible
to distinguish between time spent importing and time spent converting.
So it's lumped into a single variable. Steps that are really just
conversion are measured separately. */
std::chrono::high_resolution_clock::duration importConversionTime{};
/* Open the file or map it if requested */ /* Open the file or map it if requested */
#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))
Containers::Optional<Containers::Array<const char, Utility::Path::MapDeleter>> mapped; Containers::Optional<Containers::Array<const char, Utility::Path::MapDeleter>> mapped;
if(args.isSet("map")) { if(args.isSet("map")) {
Trade::Implementation::Duration d{importTime}; Trade::Implementation::Duration d{importConversionTime};
if(!(mapped = Utility::Path::mapRead(args.value("input"))) || !importer->openMemory(*mapped)) { if(!(mapped = Utility::Path::mapRead(args.value("input"))) || !importer->openMemory(*mapped)) {
Error() << "Cannot memory-map file" << args.value("input"); Error() << "Cannot memory-map file" << args.value("input");
return 3; return 3;
@ -369,7 +397,7 @@ the first mesh.)")
} else } else
#endif #endif
{ {
Trade::Implementation::Duration d{importTime}; Trade::Implementation::Duration d{importConversionTime};
if(!importer->openFile(args.value("input"))) { if(!importer->openFile(args.value("input"))) {
Error() << "Cannot open file" << args.value("input"); Error() << "Cannot open file" << args.value("input");
return 3; return 3;
@ -378,122 +406,180 @@ the first mesh.)")
/* Print file info, if requested */ /* Print file info, if requested */
if(isInfoRequested(args)) { if(isInfoRequested(args)) {
const bool error = SceneTools::Implementation::printInfo(useColor, useColor24, args, *importer, importTime); const bool error = SceneTools::Implementation::printInfo(useColor, useColor24, args, *importer, importConversionTime);
if(args.isSet("profile")) { if(args.isSet("profile")) {
Debug{} << "Import took" << UnsignedInt(std::chrono::duration_cast<std::chrono::milliseconds>(importTime).count())/1.0e3f << "seconds"; Debug{} << "Import took" << UnsignedInt(std::chrono::duration_cast<std::chrono::milliseconds>(importConversionTime).count())/1.0e3f << "seconds";
} }
return error ? 1 : 0; return error ? 1 : 0;
} }
if(!importer->meshCount()) {
Error{} << "No meshes found in" << args.value("input");
return 1;
}
/* Wow, C++, you suck. This implicitly initializes to random shit?! */ /* Wow, C++, you suck. This implicitly initializes to random shit?! */
std::chrono::high_resolution_clock::duration conversionTime{}; std::chrono::high_resolution_clock::duration conversionTime{};
Containers::Optional<Trade::MeshData> mesh; /* Take a single mesh or concatenate all meshes together, if requested.
After that, the importer is changed to one that contains just a single
/* Concatenate input meshes, if requested */ mesh... */
if(args.isSet("concatenate-meshes")) { bool singleMesh = false;
Containers::Array<Trade::MeshData> meshes; if(args.isSet("concatenate-meshes") || args.value<Containers::StringView>("mesh")) {
arrayReserve(meshes, importer->meshCount()); singleMesh = true;
for(std::size_t i = 0, iMax = importer->meshCount(); i != iMax; ++i) { /* ... and subsequent conversion deals with just meshes, throwing away
Trade::Implementation::Duration d{importTime}; materials and everything else (if present). */
Containers::Optional<Trade::MeshData> meshToConcatenate = importer->mesh(i);
if(!meshToConcatenate) { Containers::Optional<Trade::MeshData> mesh;
Error{} << "Cannot import mesh" << i;
/* Concatenate all meshes together */
if(args.isSet("concatenate-meshes")) {
if(!importer->meshCount()) {
Error{} << "No meshes found in" << args.value("input");
return 1; return 1;
} }
arrayAppend(meshes, *std::move(meshToConcatenate)); Containers::Array<Trade::MeshData> meshes;
} arrayReserve(meshes, importer->meshCount());
/** @todo handle mesh levels here, once any plugin is capable of
/* If there's a scene, use it to flatten mesh hierarchy. If not, assume importing them */
all meshes are in the root. */ for(std::size_t i = 0, iMax = importer->meshCount(); i != iMax; ++i) {
/** @todo make it possible to choose the scene */ Trade::Implementation::Duration d{importConversionTime};
if(importer->defaultScene() != -1) { Containers::Optional<Trade::MeshData> meshToConcatenate = importer->mesh(i);
Containers::Optional<Trade::SceneData> scene; if(!meshToConcatenate) {
{ Error{} << "Cannot import mesh" << i;
Trade::Implementation::Duration d{importTime};
if(!(scene = importer->scene(importer->defaultScene()))) {
Error{} << "Cannot import scene" << importer->defaultScene() << "for mesh concatenation";
return 1; return 1;
} }
arrayAppend(meshes, *std::move(meshToConcatenate));
}
/* If there's a scene, use it to flatten mesh hierarchy. If not,
assume all meshes are in the root. */
/** @todo make it possible to choose the scene */
if(importer->defaultScene() != -1) {
Containers::Optional<Trade::SceneData> scene;
{
Trade::Implementation::Duration d{importConversionTime};
if(!(scene = importer->scene(importer->defaultScene()))) {
Error{} << "Cannot import scene" << importer->defaultScene() << "for mesh concatenation";
return 1;
}
}
Containers::Array<Trade::MeshData> flattenedMeshes;
{
Trade::Implementation::Duration d{conversionTime};
/** @todo once there are 2D scenes, check the scene is 3D */
for(const Containers::Triple<UnsignedInt, Int, Matrix4>& meshTransformation: SceneTools::flattenMeshHierarchy3D(*scene))
arrayAppend(flattenedMeshes, MeshTools::transform3D(meshes[meshTransformation.first()], meshTransformation.third()));
}
meshes = std::move(flattenedMeshes);
} }
Containers::Array<Trade::MeshData> flattenedMeshes;
{ {
Trade::Implementation::Duration d{conversionTime}; Trade::Implementation::Duration d{conversionTime};
/** @todo once there are 2D scenes, check the scene is 3D */ /** @todo this will assert if the meshes have incompatible primitives
for(const Containers::Triple<UnsignedInt, Int, Matrix4>& meshTransformation: SceneTools::flattenMeshHierarchy3D(*scene)) (such as some triangles, some lines), or if they have
arrayAppend(flattenedMeshes, MeshTools::transform3D(meshes[meshTransformation.first()], meshTransformation.third())); loops/strips/fans -- handle that explicitly */
mesh = MeshTools::concatenate(meshes);
} }
meshes = std::move(flattenedMeshes);
}
/* Concatenate all meshes together */ /* Otherwise import just one */
{ } else {
Trade::Implementation::Duration d{conversionTime}; Trade::Implementation::Duration d{importConversionTime};
/** @todo this will assert if the meshes have incompatible primitives if(!(mesh = importer->mesh(args.value<UnsignedInt>("mesh"), args.value<UnsignedInt>("mesh-level")))) {
(such as some triangles, some lines), or if they have Error{} << "Cannot import the mesh";
loops/strips/fans -- handle that explicitly */ return 4;
mesh = MeshTools::concatenate(meshes); }
} }
/* Otherwise import just one */ /* Filter mesh attributes, if requested */
} else { /** @todo move outside of the --mesh / --concatenate-meshes branch once
Trade::Implementation::Duration d{importTime}; it's possible to filter attributes by name */
if(!(mesh = importer->mesh(args.value<UnsignedInt>("mesh"), args.value<UnsignedInt>("mesh-level")))) { if(Containers::StringView onlyAttributes = args.value<Containers::StringView>("only-mesh-attributes")) {
Error{} << "Cannot import the mesh"; const Containers::Optional<Containers::Array<UnsignedInt>> only = Utility::String::parseNumberSequence(onlyAttributes, 0, mesh->attributeCount());
return 4; if(!only) return 2;
/** @todo use MeshTools::filterOnlyAttributes() once it has a
rvalue overload that transfers ownership */
Containers::Array<Trade::MeshAttributeData> attributes;
arrayReserve(attributes, only->size());
for(UnsignedInt i: *only)
arrayAppend(attributes, mesh->attributeData(i));
const Trade::MeshIndexData indices{mesh->indices()};
const UnsignedInt vertexCount = mesh->vertexCount();
mesh = Trade::MeshData{mesh->primitive(),
mesh->releaseIndexData(), indices,
mesh->releaseVertexData(), std::move(attributes),
vertexCount};
} }
}
/* Filter mesh attributes, if requested */ /* Create an importer instance that contains just the single mesh for
if(const Containers::StringView onlyMeshAttributes = args.value<Containers::StringView>("only-mesh-attributes")) { further step, without any other data. Simpler than having to
const Containers::Optional<Containers::Array<UnsignedInt>> only = Utility::String::parseNumberSequence(onlyMeshAttributes, 0, mesh->attributeCount()); special-case the single-mesh case in all following steps. */
if(!only) return 2; struct SingleMeshImporter: Trade::AbstractImporter {
explicit SingleMeshImporter(Trade::MeshData&& mesh): mesh{std::move(mesh)} {}
/** @todo use MeshTools::filterOnlyAttributes() once it has a rvalue
overload that transfers ownership */
Containers::Array<Trade::MeshAttributeData> attributes;
arrayReserve(attributes, only->size());
for(UnsignedInt i: *only)
arrayAppend(attributes, mesh->attributeData(i));
const Trade::MeshIndexData indices{mesh->indices()};
const UnsignedInt vertexCount = mesh->vertexCount();
mesh = Trade::MeshData{mesh->primitive(),
mesh->releaseIndexData(), indices,
mesh->releaseVertexData(), std::move(attributes),
vertexCount};
}
/* Remove duplicate vertices, if requested */ Trade::ImporterFeatures doFeatures() const override { return {}; } /* LCOV_EXCL_LINE */
if(args.isSet("remove-duplicate-vertices")) { bool doIsOpened() const override { return true; }
const UnsignedInt beforeVertexCount = mesh->vertexCount(); void doClose() override {} /* LCOV_EXCL_LINE */
{
Trade::Implementation::Duration d{conversionTime}; UnsignedInt doMeshCount() const override { return 1; }
mesh = MeshTools::removeDuplicates(*std::move(mesh)); Containers::Optional<Trade::MeshData> doMesh(UnsignedInt, UnsignedInt) override {
} return MeshTools::reference(mesh);
if(args.isSet("verbose")) }
Debug{} << "Duplicate removal:" << beforeVertexCount << "->" << mesh->vertexCount() << "vertices";
Trade::MeshData mesh;
};
importer.emplace<SingleMeshImporter>(*std::move(mesh));
} }
/* Remove duplicate vertices with fuzzy comparison, if requested */ /* Operations to perform on all meshes in the importer. If there are any,
/** @todo accept two values for float and double fuzzy comparison */ meshes are supplied manually to the converter from the array below. */
if(args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy")) { Containers::Array<Trade::MeshData> meshes;
const UnsignedInt beforeVertexCount = mesh->vertexCount(); if(args.isSet("remove-duplicate-vertices") ||
{ args.value<Containers::StringView>("remove-duplicate-vertices-fuzzy"))
Trade::Implementation::Duration d{conversionTime}; {
mesh = MeshTools::removeDuplicatesFuzzy(*std::move(mesh), args.value<Float>("remove-duplicate-vertices-fuzzy")); for(UnsignedInt i = 0; i != importer->meshCount(); ++i) {
Containers::Optional<Trade::MeshData> mesh;
{
/** @todo handle mesh levels here, once any plugin is capable
of importing them */
Trade::Implementation::Duration d{importConversionTime};
if(!(mesh = importer->mesh(i))) {
Error{} << "Cannot import mesh" << i;
return 1;
}
}
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,
or maybe also different for positions, normals and texcoords?
ugh... */
if(fuzzy) {
Trade::Implementation::Duration d{conversionTime};
mesh = MeshTools::removeDuplicatesFuzzy(*std::move(mesh), args.value<Float>("remove-duplicate-vertices-fuzzy"));
} else {
Trade::Implementation::Duration d{conversionTime};
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";
}
arrayAppend(meshes, *std::move(mesh));
} }
if(args.isSet("verbose"))
Debug{} << "Fuzzy duplicate removal:" << beforeVertexCount << "->" << mesh->vertexCount() << "vertices";
} }
/* Assume there's always one passed --converter option less, and the last /* Assume there's always one passed --converter option less, and the last
@ -516,43 +602,118 @@ the first mesh.)")
if(i < args.arrayValueCount("converter-options")) if(i < args.arrayValueCount("converter-options"))
Implementation::setOptions(*converter, "AnySceneConverter", args.arrayValue("converter-options", i)); Implementation::setOptions(*converter, "AnySceneConverter", args.arrayValue("converter-options", i));
/* This is the last --converter (or the implicit AnySceneConverter at /* Decide if this is the last converter, capable of saving to a file */
the end), output to a file and exit the loop */ const bool isLastConverter = i + 1 >= converterCount && (converter->features() & (Trade::SceneConverterFeature::ConvertMeshToFile|Trade::SceneConverterFeature::ConvertMultipleToFile));
if(i + 1 >= converterCount && ((converter->features() & Trade::SceneConverterFeature::ConvertMeshToFile) || converter->features() >= (Trade::SceneConverterFeature::ConvertMultipleToFile|Trade::SceneConverterFeature::AddMeshes))) {
/* No verbose output for just one converter */
if(converterCount > 1 && args.isSet("verbose"))
Debug{} << "Saving output (" << Debug::nospace << (i+1) << Debug::nospace << "/" << Debug::nospace << converterCount << Debug::nospace << ") with" << converterName << Debug::nospace << "...";
Trade::Implementation::Duration d{conversionTime}; /* No verbose output for just one converter */
if(!converter->convertToFile(*mesh, args.value("output"))) { if(converterCount > 1 && args.isSet("verbose")) {
Error{} << "Cannot save file" << args.value("output"); if(isLastConverter) {
return 5; Debug{} << "Saving output (" << Debug::nospace << (i+1) << Debug::nospace << "/" << Debug::nospace << converterCount << Debug::nospace << ") with" << converterName << Debug::nospace << "...";
} else {
CORRADE_INTERNAL_ASSERT(i < converterCount);
Debug{} << "Processing (" << Debug::nospace << (i+1) << Debug::nospace << "/" << Debug::nospace << converterCount << Debug::nospace << ") with" << converterName << Debug::nospace << "...";
} }
}
break; /* This is the last --converter (or the implicit AnySceneConverter at
the end), output to a file */
if(isLastConverter) {
{
Trade::Implementation::Duration d{conversionTime};
if(!converter->beginFile(args.value("output"))) {
Error{} << "Cannot begin conversion of file" << args.value("output");
return 1;
}
}
/* This is not the last converter, expect that it's capable of /* This is not the last converter, expect that it's capable of
ConvertMesh */ converting to an importer instance (or a MeshData wrapped in an
importer instance) */
} else { } else {
CORRADE_INTERNAL_ASSERT(i < converterCount); if(!(converter->features() & (Trade::SceneConverterFeature::ConvertMesh|Trade::SceneConverterFeature::ConvertMultiple))) {
if(converterCount > 1 && args.isSet("verbose")) Error{} << converterName << "doesn't support importer conversion, only" << converter->features();
Debug{} << "Processing (" << Debug::nospace << (i+1) << Debug::nospace << "/" << Debug::nospace << converterCount << Debug::nospace << ") with" << converterName << Debug::nospace << "...";
if(!(converter->features() & Trade::SceneConverterFeature::ConvertMesh)) {
Error{} << converterName << "doesn't support mesh conversion, only" << converter->features();
return 6; return 6;
} }
{
Trade::Implementation::Duration d{conversionTime};
if(!converter->begin()) {
Error{} << "Cannot begin importer conversion";
return 1;
}
}
}
/* Contents to convert, by default all of them */
/** @todo make it possible to filter this on the command line, once the
converters receive this for SceneData, MaterialData and TextureData
as well */
Trade::SceneContents contents = ~Trade::SceneContents{};
/* If there are any loose meshes from previous conversion steps, add
them directly instead, and clear the array so the next iteration (if
any) takes them from the importer instead */
if(meshes) {
if(!(Trade::sceneContentsFor(*converter) & Trade::SceneContent::Meshes)) {
Warning{} << "Ignoring" << meshes.size() << "meshes not supported by the converter";
} else for(UnsignedInt i = 0; i != meshes.size(); ++i) {
Trade::Implementation::Duration d{conversionTime};
if(!converter->add(meshes[i])) {
Error{} << "Cannot add mesh" << i;
return 1;
}
}
/* Ensure the meshes are not added by addSupportedImporterContents()
below. Do this also in case the converter actually doesn't
support mesh addition, as it would otherwise cause two warnings
about the same thing being printed. */
contents &= ~Trade::SceneContent::Meshes;
/* Delete the list to avoid adding them again for the next
converter (at which point they would be stale) */
/** @todo this line is untested, needs two chained conversion steps
that each change the output to verify the old meshes don't get
reused in the next step again */
meshes = {};
}
{
Trade::Implementation::Duration d{importConversionTime};
if(!converter->addSupportedImporterContents(*importer, contents)) {
Error{} << "Cannot add importer contents";
return 5;
}
}
/* This is the last --converter (or the implicit AnySceneConverter at
the end), end the file and exit the loop */
if(isLastConverter) {
Trade::Implementation::Duration d{conversionTime};
if(!converter->endFile()) {
Error{} << "Cannot end conversion of file" << args.value("output");
return 5;
}
break;
/* This is not the last converter, save the resulting importer instance
for the next loop iteration. By design, the importer should not
depend on any data from the converter instance, only on the
converter plugin, so we should be fine replacing the converter with
a different one in the next iteration and keeping just the importer
returned from it. */
} else {
Trade::Implementation::Duration d{conversionTime}; Trade::Implementation::Duration d{conversionTime};
if(!(mesh = converter->convert(*mesh))) { if(!(importer = converter->end())) {
Error{} << converterName << "cannot convert the mesh"; Error{} << "Cannot end importer conversion";
return 7; return 1;
} }
} }
} }
if(args.isSet("profile")) { if(args.isSet("profile")) {
Debug{} << "Import took" << UnsignedInt(std::chrono::duration_cast<std::chrono::milliseconds>(importTime).count())/1.0e3f << "seconds, conversion" Debug{} << "Import and conversion took" << UnsignedInt(std::chrono::duration_cast<std::chrono::milliseconds>(importConversionTime).count())/1.0e3f << "seconds, conversion"
<< UnsignedInt(std::chrono::duration_cast<std::chrono::milliseconds>(conversionTime).count())/1.0e3f << "seconds"; << UnsignedInt(std::chrono::duration_cast<std::chrono::milliseconds>(conversionTime).count())/1.0e3f << "seconds";
} }
} }

Loading…
Cancel
Save