Browse Source

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

pull/594/head
Vladimír Vondruš 4 years ago
parent
commit
7c5089617a
  1. 16
      src/Magnum/SceneTools/Test/CMakeLists.txt
  2. 285
      src/Magnum/SceneTools/Test/SceneConverterTest.cpp
  3. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/blue4x4.png
  4. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/blue4x4x1.ktx2
  5. 10
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-image-2d.gltf
  6. 26
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-image-3d.gltf
  7. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/dxt1.dds
  8. 13
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-dds.gltf
  9. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-2d-1x1.bin
  10. 34
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-2d-1x1.gltf
  11. 14
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-2d.gltf
  12. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-3d-1x1x1.bin
  13. 58
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-3d-1x1x1.gltf
  14. 38
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-3d.gltf
  15. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/red2x2.png
  16. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/red2x2x1.ktx2
  17. 4
      src/Magnum/SceneTools/Test/configure.h.cmake
  18. 194
      src/Magnum/SceneTools/sceneconverter.cpp

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

@ -59,9 +59,22 @@ corrade_add_test(SceneToolsSceneConverterTest SceneConverterTest.cpp
# executable so plugin existence checks are consistent between the two
${MAGNUM_SCENECONVERTER_STATIC_PLUGINS}
FILES
SceneConverterTestFiles/blue4x4.png
# magnum-imageconverter --layers blue4x4.png --array blue4x4x1.ktx2 -c writerName=
SceneConverterTestFiles/blue4x4x1.ktx2
SceneConverterTestFiles/broken-image-2d.gltf
SceneConverterTestFiles/broken-image-3d.gltf
SceneConverterTestFiles/broken-mesh.obj
SceneConverterTestFiles/broken-scene.gltf
SceneConverterTestFiles/dxt1.dds
SceneConverterTestFiles/empty.gltf
SceneConverterTestFiles/image-dds.gltf
SceneConverterTestFiles/images-2d.gltf
SceneConverterTestFiles/images-2d-1x1.bin
SceneConverterTestFiles/images-2d-1x1.gltf
SceneConverterTestFiles/images-3d.gltf
SceneConverterTestFiles/images-3d-1x1x1.bin
SceneConverterTestFiles/images-3d-1x1x1.gltf
SceneConverterTestFiles/info-animations.txt
SceneConverterTestFiles/info-cameras.txt
SceneConverterTestFiles/info-images.txt
@ -90,6 +103,9 @@ corrade_add_test(SceneToolsSceneConverterTest SceneConverterTest.cpp
SceneConverterTestFiles/quad.gltf
SceneConverterTestFiles/quad.obj
SceneConverterTestFiles/quad.ply
SceneConverterTestFiles/red2x2.png
# magnum-imageconverter --layers red2x2.png --array red2x2x1.ktx2 -c writerName=
SceneConverterTestFiles/red2x2x1.ktx2
SceneConverterTestFiles/two-quads-duplicates-fuzzy.bin
SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf
SceneConverterTestFiles/two-quads-duplicates.bin

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

@ -36,6 +36,7 @@
#include "Magnum/Math/CubicHermite.h"
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
#include "Magnum/Trade/AbstractImageConverter.h"
#include "Magnum/Trade/AbstractSceneConverter.h"
#include "Magnum/SceneTools/Implementation/sceneConverterUtilities.h"
@ -116,7 +117,10 @@ const struct {
const char* name;
Containers::Array<Containers::String> args;
const char* requiresImporter;
const char* requiresImporter2;
const char* requiresConverter;
/* One for image, one for file conversion */
const char* requiresImageConverter[2];
const char* requiresMeshConverter;
const char* expected;
const char* expected2;
@ -124,23 +128,23 @@ const struct {
} ConvertData[]{
{"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")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
{}},
{"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")}),
"ObjImporter", "GltfSceneConverter", nullptr,
"ObjImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"quad.gltf", "quad.bin",
{}},
{"one mesh, explicit importer and converter", Containers::array<Containers::String>({
"-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
{}},
{"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")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
{}},
{"one mesh, options", Containers::array<Containers::String>({
@ -149,7 +153,7 @@ const struct {
just verify the (nonexistent) options arrive there */
"-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")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
"Trade::AnySceneImporter::openFile(): option nonexistentOption not recognized by ObjImporter\n"
"Trade::AnySceneConverter::beginFile(): option nonexistentConverterOption not recognized by StanfordSceneConverter\n"},
@ -160,7 +164,7 @@ const struct {
"-i", "nonexistentOption=13", "-c", "nonexistentConverterOption=26",
"-I", "ObjImporter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
"Option nonexistentOption not recognized by ObjImporter\n"
"Option nonexistentConverterOption not recognized by StanfordSceneConverter\n"},
@ -168,20 +172,20 @@ const struct {
/* 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", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
/* 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",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-duplicates.ply")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad-duplicates.ply", nullptr,
{}},
{"concatenate meshes with a scene", Containers::array<Containers::String>({
"--concatenate-meshes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles-transformed.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad-duplicates.ply")}),
"GltfImporter", "StanfordSceneConverter", nullptr,
"GltfImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad-duplicates.ply", nullptr,
{}},
/** @todo drop --mesh once it's not needed anymore again, then add a
@ -190,19 +194,19 @@ const struct {
/* Only 0 gets picked from here, others ignored */
"--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", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"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")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
{}},
{"one implicit mesh, remove vertex duplicates", Containers::array<Containers::String>({
"--remove-duplicate-vertices",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
{}},
{"one implicit mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({
@ -210,7 +214,7 @@ const struct {
AnySceneConverter delegation messages */
"--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")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
"Mesh 0 duplicate removal: 6 -> 4 vertices\n"},
{"one selected mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({
@ -218,7 +222,7 @@ const struct {
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", nullptr,
"GltfImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
/* The second mesh in the glTF is deliberately the same as in
quad-duplicates.obj, so this produces the same file */
"quad.ply", nullptr,
@ -230,7 +234,7 @@ const struct {
/* 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", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
/* There should be a minimal difference compared to the original */
"two-quads.gltf", "two-quads.bin",
"Mesh 0 duplicate removal: 5 -> 4 vertices\n"
@ -238,7 +242,7 @@ const struct {
{"one implicit mesh, remove duplicate vertices fuzzy", Containers::array<Containers::String>({
"--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")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
{}},
{"one implicit mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({
@ -246,7 +250,7 @@ const struct {
AnySceneConverter delegation messages */
"--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")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, 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>({
@ -254,7 +258,7 @@ const struct {
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", nullptr,
"GltfImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
/* 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,
@ -266,26 +270,26 @@ const struct {
/* 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", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"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",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"quad.gltf", "quad.bin",
{}},
{"one implicit mesh, two converters, explicit last", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "GltfSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"quad.gltf", "quad.bin",
{}},
{"one implicit mesh, two converters, verbose", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"quad.gltf", "quad.bin",
/* While this looks like a no-op in the output, it converts a
triangle strip to indexed triangles, which verifies that the output
@ -309,7 +313,7 @@ const struct {
{"one implicit mesh, two converters, explicit last, verbose", Containers::array<Containers::String>({
"-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")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"quad.gltf", "quad.bin",
/* As the importers and converters are specified explicitly, there's
no messages from AnySceneConverter, OTOH as we have more than one -C
@ -334,7 +338,7 @@ const struct {
"-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one implicit mesh, two converters, explicit last, options for the first only", Containers::array<Containers::String>({
@ -342,7 +346,7 @@ const struct {
"-c", "nonexistentMeshOptimizerOption=yes",
"-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one implicit mesh, two converters, options for both", Containers::array<Containers::String>({
@ -350,7 +354,7 @@ const struct {
"-c", "nonexistentMeshOptimizerOption=yes",
"-c", "nonexistentAnyConverterOption=no",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"
"Trade::AnySceneConverter::beginFile(): option nonexistentAnyConverterOption not recognized by GltfSceneConverter\n"},
@ -360,7 +364,7 @@ const struct {
"-C", "StanfordSceneConverter",
"-c", "nonexistentStanfordConverterOption=no",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
"quad.ply", nullptr,
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"
"Option nonexistentStanfordConverterOption not recognized by StanfordSceneConverter\n"},
@ -368,7 +372,7 @@ const struct {
"--remove-duplicate-vertices",
"-C", "MeshOptimizerSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter", nullptr,
"ObjImporter", nullptr, "StanfordSceneConverter", {}, nullptr,
"quad.ply", nullptr,
"Trade::AnySceneImporter::openFile(): using ObjImporter\n"
"Mesh 0 duplicate removal: 6 -> 4 vertices\n"
@ -396,7 +400,7 @@ const struct {
original */
"--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")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
/* 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
using addSupportedImporterContents() should take care of propagating
@ -408,7 +412,7 @@ const struct {
original */
"--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")}),
"GltfImporter", "GltfSceneConverter", nullptr,
"GltfImporter", nullptr, "GltfSceneConverter", {}, nullptr,
/* 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
using addSupportedImporterContents() should take care of propagating
@ -418,7 +422,8 @@ const struct {
{"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",
"GltfImporter", nullptr, "GltfSceneConverter",
{}, "MeshOptimizerSceneConverter",
/* Converts a triangle strip to indexed triangles, which verifies that
the output of MeshOptimizerSceneConverter got actually passed
further and not discarded */
@ -429,7 +434,8 @@ const struct {
"-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",
"GltfImporter", nullptr, "GltfSceneConverter",
{}, "MeshOptimizerSceneConverter",
"two-quads.gltf", "two-quads.bin",
"Processing mesh 0 with MeshOptimizerSceneConverter...\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
@ -466,7 +472,8 @@ const struct {
"-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",
"GltfImporter", nullptr, "GltfSceneConverter",
{}, "MeshOptimizerSceneConverter",
"quad.gltf", "quad.bin",
"Processing mesh 0 (1/2) with MeshOptimizerSceneConverter...\n"
"Option nonexistentFirstOption not recognized by MeshOptimizerSceneConverter\n"
@ -498,136 +505,263 @@ const struct {
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"},
{"2D image converter, two images", Containers::array<Containers::String>({
"-P", "StbResizeImageConverter", "-p", "size=\"1 1\"",
/* Removing the generator identifier for a smaller file, bundling the
images to avoid having too many files */
"-c", "bundleImages,generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-2d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/images-2d-1x1.gltf")}),
"GltfImporter", "PngImporter", "GltfSceneConverter",
{"StbResizeImageConverter", "PngImageConverter"}, nullptr,
"images-2d-1x1.gltf", "images-2d-1x1.bin",
{}},
{"2D image converter, two images, verbose", Containers::array<Containers::String>({
"-I", "GltfImporter", "-C", "GltfSceneConverter",
"-P", "StbResizeImageConverter", "-p", "size=\"1 1\"",
/* Removing the generator identifier for a smaller file, bundling the
images to avoid having too many files */
"-c", "bundleImages,generator=", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-2d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/images-2d-1x1.gltf")}),
"GltfImporter", "PngImporter", "GltfSceneConverter",
{"StbResizeImageConverter", "PngImageConverter"}, nullptr,
"images-2d-1x1.gltf", "images-2d-1x1.bin",
"Trade::AnyImageImporter::openFile(): using PngImporter\n"
"Processing 2D image 0 with StbResizeImageConverter...\n"
"Trade::AnyImageImporter::openFile(): using PngImporter\n"
"Processing 2D image 1 with StbResizeImageConverter...\n"},
{"two 2D image converters, two images, verbose", Containers::array<Containers::String>({
"-I", "GltfImporter", "-C", "GltfSceneConverter",
"-P", "StbResizeImageConverter", "-p", "size=\"2 2\"",
"-P", "StbResizeImageConverter", "-p", "size=\"1 1\"",
/* Removing the generator identifier for a smaller file, bundling the
images to avoid having too many files */
"-c", "bundleImages,generator=", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-2d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/images-2d-1x1.gltf")}),
"GltfImporter", "PngImporter", "GltfSceneConverter",
{"StbResizeImageConverter", "PngImageConverter"}, nullptr,
"images-2d-1x1.gltf", "images-2d-1x1.bin",
"Trade::AnyImageImporter::openFile(): using PngImporter\n"
"Processing 2D image 0 (1/2) with StbResizeImageConverter...\n"
"Processing 2D image 0 (2/2) with StbResizeImageConverter...\n"
"Trade::AnyImageImporter::openFile(): using PngImporter\n"
"Processing 2D image 1 (1/2) with StbResizeImageConverter...\n"
"Processing 2D image 1 (2/2) with StbResizeImageConverter...\n"},
{"3D image converter, two images", Containers::array<Containers::String>({
"-i", "experimentalKhrTextureKtx",
"-P", "StbResizeImageConverter", "-p", "size=\"1 1\"",
/* Removing the generator identifier for a smaller file, bundling the
images to avoid having too many files */
"-c", "experimentalKhrTextureKtx,imageConverter=KtxImageConverter,bundleImages,generator=",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-3d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/images-3d-1x1x1.gltf")}),
"GltfImporter", "PngImporter", "GltfSceneConverter",
{"StbResizeImageConverter", "KtxImageConverter"}, nullptr,
"images-3d-1x1x1.gltf", "images-3d-1x1x1.bin",
{}},
{"3D image converter, two images, verbose", Containers::array<Containers::String>({
"-I", "GltfImporter", "-C", "GltfSceneConverter",
"-i", "experimentalKhrTextureKtx",
"-P", "StbResizeImageConverter", "-p", "size=\"1 1\"",
/* Removing the generator identifier for a smaller file, bundling the
images to avoid having too many files */
"-c", "experimentalKhrTextureKtx,imageConverter=KtxImageConverter,bundleImages,generator=", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-3d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/images-3d-1x1x1.gltf")}),
"GltfImporter", "PngImporter", "GltfSceneConverter",
{"StbResizeImageConverter", "KtxImageConverter"}, nullptr,
"images-3d-1x1x1.gltf", "images-3d-1x1x1.bin",
"Trade::AnyImageImporter::openFile(): using KtxImporter\n"
"Processing 3D image 0 with StbResizeImageConverter...\n"
"Trade::AnyImageImporter::openFile(): using KtxImporter\n"
"Processing 3D image 1 with StbResizeImageConverter...\n"},
};
const struct {
const char* name;
Containers::Array<Containers::String> args;
const char* requiresImporter;
const char* requiresImageImporter;
const char* requiresConverter;
const char* requiresImageConverter;
Containers::String message;
} ErrorData[]{
{"missing output argument", Containers::array<Containers::String>({
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj")}),
nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
/* The output should be optional only for --info, required otherwise.
No need to test anything else as that's handled by Utility::Arguments
already. Testing just a prefix of the message. */
"Missing command-line argument output\nUsage:\n "},
{"--mesh and --concatenate-meshes", Containers::array<Containers::String>({
"--mesh", "0", "--concatenate-meshes", "a", "b"}),
nullptr, nullptr,
nullptr, nullptr, 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,
nullptr, nullptr, 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,
nullptr, nullptr, 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>({
/* 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")}),
nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr,
"PluginManager::Manager::load(): plugin NonexistentImporter is not static and was not found in nonexistent/importers\n"
"Available importer plugins: "},
{"can't open a file", Containers::array<Containers::String>({
"noexistent.ffs", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"AnySceneImporter", nullptr,
"AnySceneImporter", nullptr, nullptr, nullptr,
"Trade::AnySceneImporter::openFile(): cannot determine the format of noexistent.ffs\n"
"Cannot open file noexistent.ffs\n"},
{"can't map a file", Containers::array<Containers::String>({
"noexistent.ffs", "--map", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"AnySceneImporter", nullptr,
"AnySceneImporter", nullptr, nullptr, nullptr,
"Utility::Path::mapRead(): can't open noexistent.ffs: error 2 (No such file or directory)\n"
"Cannot memory-map file noexistent.ffs\n"},
{"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")}),
"GltfImporter", nullptr,
"GltfImporter", nullptr, nullptr, nullptr,
Utility::format("No meshes found in {}\n", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/empty.gltf"))},
{"can't import a single mesh", Containers::array<Containers::String>({
"-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, nullptr, nullptr,
"Trade::ObjImporter::mesh(): wrong index count for point\n"
"Cannot import the mesh\n"},
{"can't import a mesh for concatenation", Containers::array<Containers::String>({
"-I", "ObjImporter", "--concatenate-meshes", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-mesh.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr,
"ObjImporter", nullptr, nullptr, nullptr,
"Trade::ObjImporter::mesh(): wrong index count for point\n"
"Cannot import mesh 0\n"},
{"can't import a scene for concatenation", Containers::array<Containers::String>({
/** @todo change to an OBJ once ObjImporter imports materials (and thus
scenes) */
"--concatenate-meshes", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-scene.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"GltfImporter", nullptr,
"GltfImporter", nullptr, nullptr, nullptr,
"Trade::GltfImporter::scene(): mesh index 1 in node 0 out of range for 1 meshes\n"
"Cannot import scene 0 for mesh concatenation\n"},
{"can't import a mesh for per-mesh processing", Containers::array<Containers::String>({
"-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,
"ObjImporter", nullptr, nullptr, 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, nullptr, nullptr,
"Utility::parseNumberSequence(): unrecognized character L in LOLNEIN\n"},
{"can't load converter plugin", Containers::array<Containers::String>({
"-C", "NonexistentSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr,
"ObjImporter", nullptr, nullptr, nullptr,
Utility::format("PluginManager::Manager::load(): plugin NonexistentSceneConverter is not static and was not found in {}\n"
"Available converter plugins: ", /* Just a prefix */
MAGNUM_PLUGINS_SCENECONVERTER_INSTALL_DIR)},
{"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")}),
"ObjImporter", "AnySceneConverter",
"ObjImporter", nullptr, "AnySceneConverter", nullptr,
Utility::format("Trade::AnySceneConverter::beginFile(): cannot determine the format of {0}\n"
"Cannot begin conversion of file {0}\n", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.fbx"))},
{"file coversion end failed", Containers::array<Containers::String>({
"-I", "GltfImporter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/empty.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"GltfImporter", "StanfordSceneConverter",
"GltfImporter", nullptr, "StanfordSceneConverter", nullptr,
Utility::format("Trade::AbstractSceneConverter::endFile(): the converter requires exactly one mesh, got 0\n"
"Cannot end conversion of file {0}\n", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply"))},
/** @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",
"GltfImporter", nullptr, "MeshOptimizerSceneConverter", nullptr,
"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",
"ObjImporter", nullptr, "StanfordSceneConverter", nullptr,
"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",
"ObjImporter", nullptr, "StanfordSceneConverter", nullptr,
"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
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")}),
"ObjImporter", "StanfordSceneConverter",
"ObjImporter", nullptr, "StanfordSceneConverter", nullptr,
"StanfordSceneConverter doesn't support importer conversion, only ConvertMeshToData\n"},
{"can't load mesh converter plugin", Containers::array<Containers::String>({
"-M", "NonexistentSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr,
"ObjImporter", nullptr, nullptr, nullptr,
Utility::format("PluginManager::Manager::load(): plugin NonexistentSceneConverter is not static and was not found in {}\n"
"Available mesh converter plugins: ", /* Just a prefix */
MAGNUM_PLUGINS_SCENECONVERTER_INSTALL_DIR)},
{"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",
"ObjImporter", nullptr, "StanfordSceneConverter", nullptr,
"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",
"ObjImporter", nullptr, "MeshOptimizerSceneConverter", nullptr,
"Trade::MeshOptimizerSceneConverter::convert(): expected a triangle mesh, got MeshPrimitive::Points\n"
"Cannot process mesh 0 with MeshOptimizerSceneConverter\n"},
{"can't import a 2D image for per-image processing", Containers::array<Containers::String>({
"-I", "GltfImporter", "-P", "NonexistentImageConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-image-2d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf")}),
"GltfImporter", "AnyImageImporter", nullptr, nullptr,
Utility::format("\n" /* Just a suffix */
"Trade::AbstractImporter::openFile(): cannot open file {}\n"
"Cannot import 2D image 0\n", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/nonexistent.png"))},
{"can't import a 3D image for per-image processing", Containers::array<Containers::String>({
"-I", "GltfImporter", "-i", "experimentalKhrTextureKtx", "-P", "NonexistentImageConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-image-3d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf")}),
"GltfImporter", "AnyImageImporter", nullptr, nullptr,
Utility::format("\n" /* Just a suffix */
"Trade::AbstractImporter::openFile(): cannot open file {}\n"
"Cannot import 3D image 0\n", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/nonexistent.ktx2"))},
{"can't load image converter plugin", Containers::array<Containers::String>({
"-P", "NonexistentImageConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-2d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf")}),
"GltfImporter", "PngImporter", nullptr, nullptr,
Utility::format("PluginManager::Manager::load(): plugin NonexistentImageConverter is not static and was not found in {}\n"
"Available image converter plugins: ", /* Just a prefix */
MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR)},
{"plugin doesn't support image conversion", Containers::array<Containers::String>({
"-I", "GltfImporter", "-P", "PngImageConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-2d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf")}),
"GltfImporter", "PngImporter", nullptr, "PngImageConverter",
"PngImageConverter doesn't support 2D image conversion, only Convert2DToData\n"},
{"plugin doesn't support compressed image conversion", Containers::array<Containers::String>({
"-I", "GltfImporter", "-P", "StbResizeImageConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/image-dds.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf")}),
"GltfImporter", "PngImporter", nullptr, "StbResizeImageConverter",
/** @todo add an ability to pass options to AnyImageImporter to
suppress this */
"Trade::DdsImporter::openData(): block-compressed image is assumed to be encoded with Y down and Z forward, imported data will have wrong orientation. Enable assumeYUpZBackward to suppress this warning.\n"
"StbResizeImageConverter doesn't support compressed 2D image conversion, only Convert2D|Convert3D\n"},
{"can't process a 2D image", Containers::array<Containers::String>({
"-I", "GltfImporter", "-P", "StbResizeImageConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-2d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf")}),
"GltfImporter", "PngImporter", nullptr, "StbResizeImageConverter",
"Trade::StbResizeImageConverter::convert(): output size was not specified\n"
"Cannot process 2D image 0 with StbResizeImageConverter\n"},
{"can't process a 3D image", Containers::array<Containers::String>({
"-I", "GltfImporter", "-i", "experimentalKhrTextureKtx", "-P", "StbResizeImageConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-3d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf")}),
"GltfImporter", "PngImporter", nullptr, "StbResizeImageConverter",
"Trade::StbResizeImageConverter::convert(): output size was not specified\n"
"Cannot process 3D image 0 with StbResizeImageConverter\n"},
{"can't add processed 2D images", Containers::array<Containers::String>({
"-P", "StbResizeImageConverter", "-p", "size=\"1 1\"",
"-I", "GltfImporter", "-C", "GltfSceneConverter",
"-c", "imageConverter=NonexistentImageConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-2d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf")}),
"ObjImporter", "PngImporter", "GltfSceneConverter", "StbResizeImageConverter",
"\n" /* Sust a suffix */
"Trade::GltfSceneConverter::add(): can't load NonexistentImageConverter for image conversion\n"
"Cannot add 2D image 0\n"},
{"can't add processed 3D images", Containers::array<Containers::String>({
"-P", "StbResizeImageConverter", "-p", "size=\"1 1\"",
"-I", "GltfImporter", "-i", "experimentalKhrTextureKtx",
"-C", "GltfSceneConverter",
"-c", "experimentalKhrTextureKtx,imageConverter=NonexistentImageConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/images-3d.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.gltf")}),
"ObjImporter", "PngImporter", "GltfSceneConverter", "StbResizeImageConverter",
"\n" /* Sust a suffix */
"Trade::GltfSceneConverter::add(): can't load NonexistentImageConverter for image conversion\n"
"Cannot add 3D image 0\n"},
};
#endif
@ -1864,17 +1998,26 @@ void SceneConverterTest::convert() {
/* Check if required plugins can be loaded. Catches also ABI and interface
mismatch errors. */
PluginManager::Manager<Trade::AbstractImporter> importerManager{MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR};
PluginManager::Manager<Trade::AbstractImageConverter> imageConverterManager{MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR};
PluginManager::Manager<Trade::AbstractSceneConverter> converterManager{MAGNUM_PLUGINS_SCENECONVERTER_INSTALL_DIR};
if(data.requiresImporter && !(importerManager.load(data.requiresImporter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresImporter << "plugin can't be loaded.");
if(data.requiresImporter2 && !(importerManager.load(data.requiresImporter2) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresImporter2 << "plugin can't be loaded.");
if(data.requiresConverter && !(converterManager.load(data.requiresConverter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresConverter << "plugin can't be loaded.");
if(data.requiresImageConverter[0] && !(imageConverterManager.load(data.requiresImageConverter[0]) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresImageConverter[0] << "plugin can't be loaded.");
if(data.requiresImageConverter[1] && !(imageConverterManager.load(data.requiresImageConverter[1]) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresImageConverter[1] << "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
simplicity */
/* AnySceneImporter, AnyImageImporter & AnySceneConverter are required
implicitly for simplicity */
if(!(importerManager.load("AnySceneImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnySceneImporter plugin can't be loaded.");
if(!(importerManager.load("AnyImageImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter plugin can't be loaded.");
if(!(converterManager.load("AnySceneConverter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnySceneConverter plugin can't be loaded.");
@ -1906,24 +2049,38 @@ void SceneConverterTest::error() {
#else
/* Check if required plugins can be loaded. Catches also ABI and interface
mismatch errors. */
PluginManager::Manager<Trade::AbstractImporter> importerManager{MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR};
PluginManager::Manager<Trade::AbstractImporter> importerManager{MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR};
PluginManager::Manager<Trade::AbstractImageConverter> imageConverterManager{MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR};
PluginManager::Manager<Trade::AbstractSceneConverter> converterManager{MAGNUM_PLUGINS_SCENECONVERTER_INSTALL_DIR};
if(data.requiresImporter && !(importerManager.load(data.requiresImporter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresImporter << "plugin can't be loaded.");
if(data.requiresImageImporter && !(importerManager.load(data.requiresImageImporter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresImageImporter << "plugin can't be loaded.");
if(data.requiresConverter && !(converterManager.load(data.requiresConverter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresConverter << "plugin can't be loaded.");
if(data.requiresImageConverter && !(imageConverterManager.load(data.requiresImageConverter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresImageConverter << "plugin can't be loaded.");
/* AnyImageImporter is required implicitly for simplicity if any importer
is required */
if(data.requiresImageImporter && !(importerManager.load("AnyImageImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter plugin can't be loaded.");
CORRADE_VERIFY(true); /* capture correct function name */
Containers::Pair<bool, Containers::String> output = call(data.args);
/* If the message ends with a \n, assume it's the whole message. Otherwise
it's just a prefix. */
if(data.message.hasSuffix('\n'))
/* If the message begins with a \n, assume it's just a suffix */
if(data.message.hasPrefix('\n'))
CORRADE_COMPARE_AS(output.second(),
data.message,
TestSuite::Compare::StringHasSuffix);
/* If it ends with a \n, assume it's the whole message */
else if(data.message.hasSuffix('\n'))
CORRADE_COMPARE(output.second(), data.message);
/* Otherwise it's just a prefix */
else
CORRADE_COMPARE_AS(output.second(),
data.message,
TestSuite::Compare::StringHasPrefix);
data.message,
TestSuite::Compare::StringHasPrefix);
/* It should return a non-zero code */
CORRADE_VERIFY(!output.first());
#endif

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/blue4x4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 B

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/blue4x4x1.ktx2

Binary file not shown.

10
src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-image-2d.gltf

@ -0,0 +1,10 @@
{
"asset": {
"version": "2.0"
},
"images": [
{
"uri": "nonexistent.png"
}
]
}

26
src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-image-3d.gltf

@ -0,0 +1,26 @@
{
"asset": {
"version": "2.0"
},
"extensionsUsed": [
"KHR_texture_ktx"
],
"extensionsRequired": [
"KHR_texture_ktx"
],
"textures": [
{
"extensions": {
"KHR_texture_ktx": {
"source": 0,
"layer": 0
}
}
}
],
"images": [
{
"uri": "nonexistent.ktx2"
}
]
}

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/dxt1.dds

Binary file not shown.

13
src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-dds.gltf

@ -0,0 +1,13 @@
{
"asset": {
"version": "2.0"
},
"extensionsUsed": [
"MSFT_texture_dds"
],
"images": [
{
"uri": "dxt1.dds"
}
]
}

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-2d-1x1.bin

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

34
src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-2d-1x1.gltf

@ -0,0 +1,34 @@
{
"asset": {
"version": "2.0"
},
"buffers": [
{
"uri": "images-2d-1x1.bin",
"byteLength": 138
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 69
},
{
"buffer": 0,
"byteOffset": 69,
"byteLength": 69
}
],
"images": [
{
"mimeType": "image/png",
"bufferView": 0,
"name": "A large blue image"
},
{
"mimeType": "image/png",
"bufferView": 1
}
]
}

14
src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-2d.gltf

@ -0,0 +1,14 @@
{
"asset": {
"version": "2.0"
},
"images": [
{
"uri": "blue4x4.png",
"name": "A large blue image"
},
{
"uri": "red2x2.png"
}
]
}

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-3d-1x1x1.bin

Binary file not shown.

58
src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-3d-1x1x1.gltf

@ -0,0 +1,58 @@
{
"asset": {
"version": "2.0"
},
"extensionsUsed": [
"KHR_texture_ktx"
],
"extensionsRequired": [
"KHR_texture_ktx"
],
"buffers": [
{
"uri": "images-3d-1x1x1.bin",
"byteLength": 510
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 255
},
{
"buffer": 0,
"byteOffset": 255,
"byteLength": 255
}
],
"textures": [
{
"extensions": {
"KHR_texture_ktx": {
"source": 0,
"layer": 0
}
}
},
{
"extensions": {
"KHR_texture_ktx": {
"source": 1,
"layer": 0
}
}
}
],
"images": [
{
"mimeType": "image/ktx2",
"bufferView": 0,
"name": "A large blue image"
},
{
"mimeType": "image/ktx2",
"bufferView": 1
}
]
}

38
src/Magnum/SceneTools/Test/SceneConverterTestFiles/images-3d.gltf

@ -0,0 +1,38 @@
{
"asset": {
"version": "2.0"
},
"extensionsUsed": [
"KHR_texture_ktx"
],
"extensionsRequired": [
"KHR_texture_ktx"
],
"textures": [
{
"extensions": {
"KHR_texture_ktx": {
"source": 0,
"layer": 0
}
}
},
{
"extensions": {
"KHR_texture_ktx": {
"source": 1,
"layer": 0
}
}
}
],
"images": [
{
"uri": "blue4x4x1.ktx2",
"name": "A large blue image"
},
{
"uri": "red2x2x1.ktx2"
}
]
}

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/red2x2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 B

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/red2x2x1.ktx2

Binary file not shown.

4
src/Magnum/SceneTools/Test/configure.h.cmake

@ -31,20 +31,24 @@
#ifdef CORRADE_IS_DEBUG_BUILD
#define MAGNUM_PLUGINS_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_DEBUG_BINARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_IMPORTER_DEBUG_BINARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_IMAGECONVERTER_DEBUG_BINARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_SCENECONVERTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_SCENECONVERTER_DEBUG_BINARY_INSTALL_DIR}"
#else
#define MAGNUM_PLUGINS_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_RELEASE_BINARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_IMPORTER_RELEASE_BINARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_IMAGECONVERTER_RELEASE_BINARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_SCENECONVERTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_SCENECONVERTER_RELEASE_BINARY_INSTALL_DIR}"
#endif
#else
#ifdef CORRADE_IS_DEBUG_BUILD
#define MAGNUM_PLUGINS_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_DEBUG_LIBRARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_IMPORTER_DEBUG_LIBRARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_IMAGECONVERTER_DEBUG_LIBRARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_SCENECONVERTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_SCENECONVERTER_DEBUG_LIBRARY_INSTALL_DIR}"
#else
#define MAGNUM_PLUGINS_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_RELEASE_LIBRARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_IMPORTER_RELEASE_LIBRARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_IMAGECONVERTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_IMAGECONVERTER_RELEASE_LIBRARY_INSTALL_DIR}"
#define MAGNUM_PLUGINS_SCENECONVERTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_SCENECONVERTER_RELEASE_LIBRARY_INSTALL_DIR}"
#endif
#endif

194
src/Magnum/SceneTools/sceneconverter.cpp

@ -117,11 +117,13 @@ magnum-sceneconverter chair.obj -C MeshOptimizerSceneConverter \
@code{.sh}
magnum-sceneconverter [-h|--help] [-I|--importer PLUGIN]
[-C|--converter PLUGIN]... [-M|--mesh-converter PLUGIN]...
[--plugin-dir DIR] [--map] [--only-mesh-attributes N1,N2-N3]
[--remove-duplicate-vertices] [--remove-duplicate-vertices-fuzzy EPSILON]
[-C|--converter PLUGIN]... [-P|--image-converter PLUGIN]...
[-M|--mesh-converter PLUGIN]... [--plugin-dir DIR] [--map]
[--only-mesh-attributes N1,N2-N3] [--remove-duplicate-vertices]
[--remove-duplicate-vertices-fuzzy EPSILON]
[-i|--importer-options key=val,key2=val2,]
[-c|--converter-options key=val,key2=val2,]...
[-p|--image-converter-options key=val,key2=val2,]...
[-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]
@ -138,6 +140,8 @@ Arguments:
- `-I`, `--importer PLUGIN` --- scene importer plugin (default:
@ref Trade::AnySceneImporter "AnySceneImporter")
- `-C`, `--converter PLUGIN` --- scene converter plugin(s)
- `-P`, `--image-converter PLUGIN` --- converter plugin(s) to apply to each
image in the scene
- `-M`, `--mesh-converter PLUGIN` --- converter plugin(s) to apply to each
mesh in the scene
- `--plugin-dir DIR` --- override base plugin dir
@ -156,6 +160,8 @@ Arguments:
pass to the importer
- `-c`, `--converter-options key=val,key2=val2,` --- configuration options
to pass to scene converter(s)
- `-p`, `--image-converter-options key=val,key2=val2,` --- configuration
options to pass to image 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
@ -206,10 +212,12 @@ converter doesn't support conversion to a file,
@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.
Similarly, the `-P` / `-M` options (and correspondingly also `-p` / `-m`) can
be specified multiple times in order to chain more image / mesh converters
together. All image converters in the chain have to support the ConvertImage*D
feature for given image dimensions, all mesh converters in the chain have to
support the ConvertMesh feature. If no `-P` / `-M` is specified, the imported
images / meshes are passed directly to the scene converter.
The `--remove-duplicate-vertices` operations are performed before passing them
to any converter.
@ -244,6 +252,62 @@ bool isInfoRequested(const Utility::Arguments& args) {
args.isSet("info");
}
template<UnsignedInt dimensions> bool runImageConverters(PluginManager::Manager<Trade::AbstractImageConverter>& imageConverterManager, const Utility::Arguments& args, const UnsignedInt i, Containers::Optional<Trade::ImageData<dimensions>>& image) {
for(std::size_t j = 0, imageConverterCount = args.arrayValueCount("image-converter"); j != imageConverterCount; ++j) {
const Containers::StringView imageConverterName = args.arrayValue<Containers::StringView>("image-converter", j);
if(args.isSet("verbose")) {
Debug d;
d << "Processing" << dimensions << Debug::nospace << "D image" << i;
if(imageConverterCount > 1)
d << "(" << Debug::nospace << (j+1) << Debug::nospace << "/" << Debug::nospace << imageConverterCount << Debug::nospace << ")";
d << "with" << imageConverterName << Debug::nospace << "...";
}
Containers::Pointer<Trade::AbstractImageConverter> imageConverter = imageConverterManager.loadAndInstantiate(imageConverterName);
if(!imageConverter) {
Debug{} << "Available image converter plugins:" << ", "_s.join(imageConverterManager.aliasList());
return false;
}
/* Set options, if passed. The AnyImageConverter check makes no
sense here, is just there because the helper wants it */
if(args.isSet("verbose")) imageConverter->addFlags(Trade::ImageConverterFlag::Verbose);
if(j < args.arrayValueCount("image-converter-options"))
Implementation::setOptions(*imageConverter, "AnyImageConverter", args.arrayValue("image-converter-options", j));
Trade::ImageConverterFeatures expectedFeatures;
if(dimensions == 2) {
expectedFeatures = image->isCompressed() ?
Trade::ImageConverterFeature::ConvertCompressed2D :
Trade::ImageConverterFeature::Convert2D;
} else if(dimensions == 3) {
expectedFeatures = image->isCompressed() ?
Trade::ImageConverterFeature::ConvertCompressed3D :
Trade::ImageConverterFeature::Convert3D;
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
/** @todo level-related features, once testable */
if(!(imageConverter->features() >= expectedFeatures)) {
Error err;
err << imageConverterName << "doesn't support";
/** @todo level-related message, once testable */
if(image->isCompressed())
err << "compressed";
err << dimensions << Debug::nospace << "D image conversion, only" << Debug::packed << imageConverter->features();
return false;
}
/** @todo handle image levels here, once GltfSceneConverter is capable
of converting them (which needs AbstractImageConverter to be
reworked around ImageData) */
if(!(image = imageConverter->convert(*image))) {
Error{} << "Cannot process" << dimensions << Debug::nospace << "D image" << i << "with" << imageConverterName;
return false;
}
}
return true;
}
}
int main(int argc, char** argv) {
@ -252,6 +316,7 @@ int main(int argc, char** argv) {
.addArgument("output").setHelp("output", "output file; ignored if --info is present")
.addOption('I', "importer", "AnySceneImporter").setHelp("importer", "scene importer plugin", "PLUGIN")
.addArrayOption('C', "converter").setHelp("converter", "scene converter plugin(s)", "PLUGIN")
.addArrayOption('P', "image-converter").setHelp("image-converter", "converter plugin(s) to apply to each image in the scene", "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")
#if defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT))
@ -262,6 +327,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('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('p', "image-converter-options").setHelp("image-converter-options", "configuration options to pass to the image 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-level").setHelp("mesh-level", "level to select for single-mesh conversion", "index")
@ -311,10 +377,12 @@ ConvertMeshToFile. If the last converter doesn't support conversion to a file,
AnySceneConverter is used to save its output. If no -C is specified,
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.
Similarly, the -P / -M options (and correspondingly also -p / -m) can be
specified multiple times in order to chain more image / mesh converters
together. All image converters in the chain have to support the ConvertImage*D
feature for given image dimensions, all mesh converters in the chain have to
support the ConvertMesh feature. If no -P / -M is specified, the imported
images / meshes are passed directly to the scene converter.
The --remove-duplicate-vertices operations are performed on meshes before
passing them to any converter.
@ -593,6 +661,59 @@ well, the IDs reference attributes of the first mesh.)")
*previousImporter);
}
/* Operations to perform on all images in the importer. If there are any,
images are supplied manually to the converter from the array below. */
Containers::Array<Trade::ImageData2D> images2D;
Containers::Array<Trade::ImageData3D> images3D;
if(args.arrayValueCount("image-converter")) {
/** @todo implement once there's any file format capable of storing
these */
if(importer->image1DCount()) {
Error{} << "Sorry, 1D image conversion is not implemented yet";
return 1;
}
for(UnsignedInt i = 0; i != importer->image2DCount(); ++i) {
Containers::Optional<Trade::ImageData2D> image;
{
/** @todo handle image levels once GltfSceneConverter can save
them (which needs AbstractImageConverter to be reworked
around ImageData) -- there could be an image2DOffsets
array saying which subrange is levels for which image */
Trade::Implementation::Duration d{importConversionTime};
if(!(image = importer->image2D(i))) {
Error{} << "Cannot import 2D image" << i;
return 1;
}
}
if(!runImageConverters(imageConverterManager, args, i, image))
return 1;
arrayAppend(images2D, *std::move(image));
}
for(UnsignedInt i = 0; i != importer->image3DCount(); ++i) {
Containers::Optional<Trade::ImageData3D> image;
{
/** @todo handle image levels once GltfSceneConverter can save
them (which needs AbstractImageConverter to be reworked
around ImageData) -- there could be an image2DOffsets
array saying which subrange is levels for which image */
Trade::Implementation::Duration d{importConversionTime};
if(!(image = importer->image3D(i))) {
Error{} << "Cannot import 3D image" << i;
return 1;
}
}
if(!runImageConverters(imageConverterManager, args, i, image))
return 1;
arrayAppend(images3D, *std::move(image));
}
}
/* Operations to perform on all meshes in the importer. If there are any,
meshes are supplied manually to the converter from the array below. */
Containers::Array<Trade::MeshData> meshes;
@ -751,6 +872,57 @@ well, the IDs reference attributes of the first mesh.)")
as well */
Trade::SceneContents contents = ~Trade::SceneContents{};
/* If there are any loose images from previous conversion steps, add
them directly, and clear the array so the next iteration (if any)
takes them from the importer instead */
/** @todo 1D images, once there's any format that supports them */
if(images2D) {
if(!(Trade::sceneContentsFor(*converter) & Trade::SceneContent::Images2D)) {
Warning{} << "Ignoring" << images2D.size() << "2D images not supported by the converter";
} else for(UnsignedInt i = 0; i != images2D.size(); ++i) {
Trade::Implementation::Duration d{conversionTime};
if(!converter->add(images2D[i], contents & Trade::SceneContent::Names ? importer->image2DName(i) : Containers::String{})) {
Error{} << "Cannot add 2D image" << i;
return 1;
}
}
/* Ensure the images are not added by addSupportedImporterContents()
below. Do this also in case the converter actually doesn't
support image addition, as it would otherwise cause two warnings
about the same thing being printed. */
contents &= ~Trade::SceneContent::Images2D;
/* 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 first an importer->importer
converter supporting images */
images2D = {};
}
if(images3D) {
if(!(Trade::sceneContentsFor(*converter) & Trade::SceneContent::Images3D)) {
Warning{} << "Ignoring" << images3D.size() << "3D images not supported by the converter";
} else for(UnsignedInt i = 0; i != images3D.size(); ++i) {
Trade::Implementation::Duration d{conversionTime};
if(!converter->add(images3D[i], contents & Trade::SceneContent::Names ? importer->image3DName(i) : Containers::String{})) {
Error{} << "Cannot add 3D image" << i;
return 1;
}
}
/* Ensure the images are not added by addSupportedImporterContents()
below. Do this also in case the converter actually doesn't
support image addition, as it would otherwise cause two warnings
about the same thing being printed. */
contents &= ~Trade::SceneContent::Images3D;
/* 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 first an importer->importer
converter supporting images */
images3D = {};
}
/* If there are any loose meshes from previous conversion steps, add
them directly, and clear the array so the next iteration (if any)
takes them from the importer instead */

Loading…
Cancel
Save