Browse Source

sceneconverter: fully cover with tests.

I'm going to add quite a few features to this one, and doing that
without any regression tests whatsoever would be a misery. Same needs to
eventually be done for the imageconverter and other utils. No bugs found
here, fortunately, except for one message update -- otherwise the
verbose output would contain (1/2) but never (2/2) which may be
confusing.

At the moment the testing is done only on Unix -- originally I wanted to
postpone this until something like Utility::System::execute() is
implemented, with proper argument escaping and output redirection, but I
simply DO NOT HAVE TIME to do that properly now. So instead it's calling
into std::system(), assumes there is no whitespace in the arguments, and
assumes a Unix shell with stdout/stderr redirection to a file. Ugly and
probably way slower than necessary, but works.
pull/580/head
Vladimír Vondruš 4 years ago
parent
commit
443a05f91a
  1. 2
      .editorconfig
  2. 33
      src/Magnum/SceneTools/Test/CMakeLists.txt
  3. 457
      src/Magnum/SceneTools/Test/SceneConverterTest.cpp
  4. 3
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-mesh.obj
  5. 22
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-scene.gltf
  6. 5
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/empty.gltf
  7. 6
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/info-ignored-output.txt
  8. 5
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/info.txt
  9. 2
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/point.obj
  10. 12
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad-duplicates-fuzzy.obj
  11. 12
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad-duplicates.obj
  12. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad-duplicates.ply
  13. 12
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad-normals-texcoords.obj
  14. 10
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad.obj
  15. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad.ply
  16. BIN
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-triangles-transformed.bin
  17. 15
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-triangles-transformed.bin.in
  18. 75
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-triangles-transformed.gltf
  19. 14
      src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-triangles.obj
  20. 24
      src/Magnum/SceneTools/Test/configure.h.cmake
  21. 2
      src/Magnum/SceneTools/sceneconverter.cpp

2
.editorconfig

@ -5,6 +5,6 @@ indent_size = 4
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
[*.{css,html,yml,rb}] [*.{css,html,yml,rb,gltf}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

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

@ -29,12 +29,23 @@ set(CMAKE_FOLDER "Magnum/SceneTools/Test")
if(CORRADE_TARGET_EMSCRIPTEN OR CORRADE_TARGET_ANDROID) if(CORRADE_TARGET_EMSCRIPTEN OR CORRADE_TARGET_ANDROID)
set(SCENETOOLS_TEST_DIR ".") set(SCENETOOLS_TEST_DIR ".")
set(SCENETOOLS_TEST_OUTPUT_DIR "write")
else() else()
set(SCENETOOLS_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(SCENETOOLS_TEST_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(SCENETOOLS_TEST_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif() endif()
# Executable testing is implemented on Unix platforms only at the moment, so
# don't even provide the filename elsewhere.
if(MAGNUM_WITH_SCENECONVERTER AND CORRADE_TARGET_UNIX)
set(SCENECONVERTER_EXECUTABLE_FILENAME $<TARGET_FILE:magnum-sceneconverter>)
endif()
# First replace ${} variables, then $<> generator expressions
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h) ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in)
file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/configure.h
INPUT ${CMAKE_CURRENT_BINARY_DIR}/configure.h.in)
corrade_add_test(SceneToolsCombineTest CombineTest.cpp LIBRARIES MagnumTrade) corrade_add_test(SceneToolsCombineTest CombineTest.cpp LIBRARIES MagnumTrade)
corrade_add_test(SceneToolsConvertToSingleFun___Test ConvertToSingleFunctionObjectsTest.cpp LIBRARIES MagnumTrade) corrade_add_test(SceneToolsConvertToSingleFun___Test ConvertToSingleFunctionObjectsTest.cpp LIBRARIES MagnumTrade)
@ -44,6 +55,9 @@ corrade_add_test(SceneToolsOrderClusterParentsTest OrderClusterParentsTest.cpp L
corrade_add_test(SceneToolsSceneConverterTest SceneConverterTest.cpp corrade_add_test(SceneToolsSceneConverterTest SceneConverterTest.cpp
LIBRARIES MagnumSceneTools LIBRARIES MagnumSceneTools
FILES FILES
SceneConverterTestFiles/broken-mesh.obj
SceneConverterTestFiles/broken-scene.gltf
SceneConverterTestFiles/empty.gltf
SceneConverterTestFiles/info-animations.txt SceneConverterTestFiles/info-animations.txt
SceneConverterTestFiles/info-cameras.txt SceneConverterTestFiles/info-cameras.txt
SceneConverterTestFiles/info-images.txt SceneConverterTestFiles/info-images.txt
@ -56,5 +70,18 @@ corrade_add_test(SceneToolsSceneConverterTest SceneConverterTest.cpp
SceneConverterTestFiles/info-scenes-objects.txt SceneConverterTestFiles/info-scenes-objects.txt
SceneConverterTestFiles/info-scenes.txt SceneConverterTestFiles/info-scenes.txt
SceneConverterTestFiles/info-skins.txt SceneConverterTestFiles/info-skins.txt
SceneConverterTestFiles/info-textures.txt) SceneConverterTestFiles/info-textures.txt
target_include_directories(SceneToolsSceneConverterTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) SceneConverterTestFiles/point.obj
SceneConverterTestFiles/quad-duplicates-fuzzy.obj
SceneConverterTestFiles/quad-duplicates.obj
SceneConverterTestFiles/quad-duplicates.ply
SceneConverterTestFiles/quad-normals-texcoords.obj
SceneConverterTestFiles/quad.obj
SceneConverterTestFiles/quad.ply
SceneConverterTestFiles/two-triangles-transformed.bin
SceneConverterTestFiles/two-triangles-transformed.gltf
SceneConverterTestFiles/two-triangles.obj)
target_include_directories(SceneToolsSceneConverterTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
if(MAGNUM_WITH_SCENECONVERTER AND CORRADE_TARGET_UNIX)
add_dependencies(SceneToolsSceneConverterTest magnum-sceneconverter)
endif()

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

@ -26,6 +26,8 @@
#include <sstream> #include <sstream>
#include <Corrade/Containers/ArrayTuple.h> #include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/File.h>
#include <Corrade/TestSuite/Compare/String.h>
#include <Corrade/TestSuite/Compare/StringToFile.h> #include <Corrade/TestSuite/Compare/StringToFile.h>
#include <Corrade/Utility/Algorithms.h> #include <Corrade/Utility/Algorithms.h>
#include <Corrade/Utility/DebugStl.h> #include <Corrade/Utility/DebugStl.h>
@ -34,6 +36,7 @@
#include "Magnum/Math/CubicHermite.h" #include "Magnum/Math/CubicHermite.h"
#include "Magnum/Math/Matrix3.h" #include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h" #include "Magnum/Math/Matrix4.h"
#include "Magnum/Trade/AbstractSceneConverter.h"
#include "Magnum/SceneTools/Implementation/sceneConverterUtilities.h" #include "Magnum/SceneTools/Implementation/sceneConverterUtilities.h"
@ -59,9 +62,16 @@ struct SceneConverterTest: TestSuite::Tester {
void infoImplementationReferenceCount(); void infoImplementationReferenceCount();
void infoImplementationError(); void infoImplementationError();
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
void info();
void convert();
void error();
#endif
Utility::Arguments _infoArgs; Utility::Arguments _infoArgs;
}; };
using namespace Containers::Literals;
using namespace Math::Literals; using namespace Math::Literals;
const struct { const struct {
@ -84,6 +94,299 @@ const struct {
{"--info", false, false}, {"--info", false, false},
}; };
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
const struct {
const char* name;
Containers::Array<Containers::String> args;
const char* expected;
} InfoData[]{
{"", Containers::array<Containers::String>({}),
"info.txt"},
{"map", Containers::array<Containers::String>({
"--map"}),
/** @todo change to something else once we have a plugin that can
zero-copy pass the imported data */
"info.txt"},
{"ignored output file", Containers::array<Containers::String>({
"whatever.ply"}),
"info-ignored-output.txt"},
};
const struct {
const char* name;
Containers::Array<Containers::String> args;
const char* requiresImporter;
const char* requiresConverter;
const char* expected;
Containers::String message;
} 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",
"quad.ply",
{}},
{"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",
"quad.ply",
{}},
{"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",
"quad.ply",
{}},
{"one mesh, options", Containers::array<Containers::String>({
/* It's silly, but since we have option propagation tested in
AnySceneImporter / AnySceneConverter .cpp already, it's enough to
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",
"quad.ply",
"Trade::AnySceneImporter::openFile(): option nonexistentOption not recognized by ObjImporter\n"
"Trade::AnySceneConverter::convertToFile(): option nonexistentConverterOption not recognized by StanfordSceneConverter\n"},
{"one mesh, options, explicit importer and converter", Containers::array<Containers::String>({
/* Same here, since we have option propagation tested in
Magnum/Test/ConverterUtilitiesTest.cpp already, to verify it's
getting called we can just supply nonexistent options */
"-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",
"quad.ply",
"Option nonexistentOption not recognized by ObjImporter\n"
"Option nonexistentConverterOption not recognized by StanfordSceneConverter\n"},
{"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",
"quad-duplicates.ply",
{}},
{"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",
"quad-duplicates.ply",
{}},
{"filter attributes", Containers::array<Containers::String>({
/* Only 0 gets picked from here, others ignored */
"--only-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",
{}},
{"remove duplicates", Containers::array<Containers::String>({
"--remove-duplicates",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-duplicates.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply",
{}},
{"remove duplicates, verbose", Containers::array<Containers::String>({
/* Forcing the importer and converter to avoid AnySceneImporter /
AnySceneConverter delegation messages */
"--remove-duplicates", "-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",
"quad.ply",
"Duplicate removal: 6 -> 4 vertices\n"},
{"remove duplicates fuzzy", Containers::array<Containers::String>({
"--remove-duplicates-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",
"quad.ply",
{}},
{"remove duplicates fuzzy, verbose", Containers::array<Containers::String>({
/* Forcing the importer and converter to avoid AnySceneImporter /
AnySceneConverter delegation messages */
"--remove-duplicates-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",
"quad.ply",
"Fuzzy duplicate removal: 6 -> 4 vertices\n"},
{"one mesh, two converters", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply",
{}},
{"one mesh, two converters, explicit last", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply",
{}},
{"one mesh, two converters, verbose", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply",
/** @todo this is a no-op, use some other converter that tests also
that the resulting mesh is actually passed further */
"Trade::AnySceneImporter::openFile(): using ObjImporter\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"
"Trade::AnySceneConverter::convertToFile(): using StanfordSceneConverter\n"},
{"one mesh, two converters, explicit last, verbose", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter", "-C", "StanfordSceneConverter", "-v",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply",
/* As the importers and converters are specified explicitly, there's
no messages from AnySceneConverter, OTOH as we have more than one -C
option the verbose output includes a progress info */
"Trade::AnySceneImporter::openFile(): using ObjImporter\n"
"Processing (1/2) with MeshOptimizerSceneConverter...\n"
"Trade::MeshOptimizerSceneConverter::convert(): processing stats:\n"
" vertex cache:\n"
" 4 -> 4 transformed vertices\n"
" 1 -> 1 executed warps\n"
" ACMR 2 -> 2\n"
" ATVR 1 -> 1\n"
" vertex fetch:\n"
" 64 -> 64 bytes fetched\n"
" overfetch 1.33333 -> 1.33333\n"
" overdraw:\n"
" 65536 -> 65536 shaded pixels\n"
" 65536 -> 65536 covered pixels\n"
" overdraw 1 -> 1\n"
"Saving output (2/2) with StanfordSceneConverter...\n"},
{"one mesh, two converters, options for the first only", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply",
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one mesh, two converters, explicit last, options for the first only", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes",
"-C", "StanfordSceneConverter",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply",
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"},
{"one mesh, two converters, options for both", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes",
"-c", "nonexistentAnyConverterOption=no",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply",
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"
"Trade::AnySceneConverter::convertToFile(): option nonexistentAnyConverterOption not recognized by StanfordSceneConverter\n"},
{"one mesh, two converters, explicit last, options for both", Containers::array<Containers::String>({
"-C", "MeshOptimizerSceneConverter",
"-c", "nonexistentMeshOptimizerOption=yes",
"-C", "StanfordSceneConverter",
"-c", "nonexistentStanfordConverterOption=no",
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}),
"ObjImporter", "StanfordSceneConverter",
"quad.ply",
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"
"Option nonexistentStanfordConverterOption not recognized by StanfordSceneConverter\n"},
};
const struct {
const char* name;
Containers::Array<Containers::String> args;
const char* requiresImporter;
const char* requiresConverter;
Containers::String message;
} ErrorData[]{
{"missing output argument", Containers::array<Containers::String>({
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj")}),
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 "},
{"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,
"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,
"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,
"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", Containers::array<Containers::String>({
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/empty.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"GltfImporter", nullptr,
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>({
"-I", "ObjImporter", 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 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,
"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,
"Trade::GltfImporter::scene(): mesh index 1 in node 0 out of range for 1 meshes\n"
"Cannot import scene 0 for mesh concatenation\n"},
{"invalid attribute filter", Containers::array<Containers::String>({
"-I", "ObjImporter", "--only-attributes", "LOLNEIN", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr,
"Utility::parseNumberSequence(): unrecognized character L in LOLNEIN\n"},
{"can't load converter plugin", Containers::array<Containers::String>({
/* Override also the plugin directory for consistent output, however
then the importer plugin has to be loaded through an absolute file
path (unless using static plugins) */
"--plugin-dir", "nonexistent", "-I",
#ifndef MAGNUM_BUILD_STATIC
Utility::Path::join(MAGNUM_PLUGINS_IMPORTER_INSTALL_DIR, "ObjImporter" + Trade::AbstractImporter::pluginSuffix()),
#else
"ObjImporter",
#endif
"-C", "NonexistentSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}),
"ObjImporter", nullptr,
/* Just a prefix */
"PluginManager::Manager::load(): plugin NonexistentSceneConverter is not static and was not found in nonexistent/sceneconverters\n"
"Available converter plugins: "},
{"file coversion 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",
Utility::format("Trade::AnySceneConverter::convertToFile(): cannot determine the format of {0}\n"
"Cannot save file {0}\n", Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.fbx"))},
{"mesh coversion 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")}),
"ObjImporter", "MeshOptimizerSceneConverter",
"Trade::MeshOptimizerSceneConverter::convert(): expected a triangle mesh, got MeshPrimitive::Points\n"
"MeshOptimizerSceneConverter cannot convert the mesh\n"},
{"plugin doesn't support mesh 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",
"StanfordSceneConverter doesn't support mesh conversion, only Trade::SceneConverterFeature::ConvertMeshToData\n"},
};
#endif
SceneConverterTest::SceneConverterTest() { SceneConverterTest::SceneConverterTest() {
addTests({&SceneConverterTest::infoImplementationEmpty}); addTests({&SceneConverterTest::infoImplementationEmpty});
@ -107,6 +410,17 @@ SceneConverterTest::SceneConverterTest() {
addTests({&SceneConverterTest::infoImplementationReferenceCount, addTests({&SceneConverterTest::infoImplementationReferenceCount,
&SceneConverterTest::infoImplementationError}); &SceneConverterTest::infoImplementationError});
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
addInstancedTests({&SceneConverterTest::info},
Containers::arraySize(InfoData));
addInstancedTests({&SceneConverterTest::convert},
Containers::arraySize(ConvertData));
addInstancedTests({&SceneConverterTest::error},
Containers::arraySize(ErrorData));
#endif
/* A subset of arguments needed by the info printing code */ /* A subset of arguments needed by the info printing code */
_infoArgs.addBooleanOption("info") _infoArgs.addBooleanOption("info")
.addBooleanOption("info-scenes") .addBooleanOption("info-scenes")
@ -120,6 +434,9 @@ SceneConverterTest::SceneConverterTest() {
.addBooleanOption("info-textures") .addBooleanOption("info-textures")
.addBooleanOption("info-images") .addBooleanOption("info-images")
.addBooleanOption("bounds"); .addBooleanOption("bounds");
/* Create output dir, if doesn't already exist */
Utility::Path::make(Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles"));
} }
void SceneConverterTest::infoImplementationEmpty() { void SceneConverterTest::infoImplementationEmpty() {
@ -1224,6 +1541,146 @@ void SceneConverterTest::infoImplementationError() {
"Object 0: A name\n"); "Object 0: A name\n");
} }
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
namespace {
#ifdef SCENECONVERTER_EXECUTABLE_FILENAME
/** @todo take a StringIterable once it exists */
Containers::Pair<bool, Containers::String> call(Containers::ArrayView<const Containers::String> arguments) {
/* Create a string view array for the arguments, implicitly pass the
application name and plugin directory override */
/** @todo drop once StringIterable exists */
Containers::Array<Containers::StringView> argumentViews{ValueInit, arguments.size() + 3};
argumentViews[0] = ""_s;
argumentViews[1] = "--plugin-dir"_s;
argumentViews[2] = MAGNUM_PLUGINS_INSTALL_DIR;
for(std::size_t i = 0; i != arguments.size(); ++i)
argumentViews[i + 3] = arguments[i];
const Containers::String outputFilename = Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/output.txt");
/** @todo clean up once Utility::System::execute() with output redirection
exists */
const bool success = std::system(Utility::format("{} {} > {} 2>&1",
SCENECONVERTER_EXECUTABLE_FILENAME,
" "_s.join(argumentViews), /** @todo handle space escaping here? */
outputFilename
).data()) == 0;
const Containers::Optional<Containers::String> output = Utility::Path::readString(outputFilename);
CORRADE_VERIFY(output);
return {success, std::move(*output)};
}
#endif
}
void SceneConverterTest::info() {
auto&& data = InfoData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef SCENECONVERTER_EXECUTABLE_FILENAME
#ifdef CORRADE_TARGET_UNIX
CORRADE_SKIP("magnum-sceneconverter not built, can't test");
#else
CORRADE_SKIP("Executable testing implemented only on Unix platforms");
#endif
#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};
if(!(importerManager.load("ObjImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("ObjImporter plugin can't be loaded.");
Containers::Array<Containers::String> args{InPlaceInit,
{"-I", "ObjImporter", "--info", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/point.obj")}};
arrayAppend(args, arrayView(data.args)); /** @todo FFS fix the casts */
CORRADE_VERIFY(true); /* capture correct function name */
Containers::Pair<bool, Containers::String> output = call(args);
CORRADE_COMPARE_AS(output.second(),
Utility::Path::join({SCENETOOLS_TEST_DIR, "SceneConverterTestFiles", data.expected}),
TestSuite::Compare::StringToFile);
CORRADE_VERIFY(output.first());
#endif
}
void SceneConverterTest::convert() {
auto&& data = ConvertData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef SCENECONVERTER_EXECUTABLE_FILENAME
#ifdef CORRADE_TARGET_UNIX
CORRADE_SKIP("magnum-sceneconverter not built, can't test");
#else
CORRADE_SKIP("Executable testing implemented only on Unix platforms");
#endif
#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::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.requiresConverter && !(converterManager.load(data.requiresConverter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresConverter << "plugin can't be loaded.");
/* AnySceneImporter & AnySceneConverter are required implicitly for
simplicity */
if(!(importerManager.load("AnySceneImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnySceneImporter plugin can't be loaded.");
if(!(converterManager.load("AnySceneConverter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnySceneConverter plugin can't be loaded.");
CORRADE_VERIFY(true); /* capture correct function name */
Containers::Pair<bool, Containers::String> output = call(data.args);
CORRADE_COMPARE(output.second(), data.message);
CORRADE_VERIFY(output.first());
CORRADE_COMPARE_AS(Utility::Path::join({SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles", data.expected}),
Utility::Path::join({SCENETOOLS_TEST_DIR, "SceneConverterTestFiles", data.expected}),
TestSuite::Compare::File);
#endif
}
void SceneConverterTest::error() {
auto&& data = ErrorData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef SCENECONVERTER_EXECUTABLE_FILENAME
#ifdef CORRADE_TARGET_UNIX
CORRADE_SKIP("magnum-sceneconverter not built, can't test");
#else
CORRADE_SKIP("Executable testing implemented only on Unix platforms");
#endif
#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::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.requiresConverter && !(converterManager.load(data.requiresConverter) & PluginManager::LoadState::Loaded))
CORRADE_SKIP(data.requiresConverter << "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'))
CORRADE_COMPARE(output.second(), data.message);
else
CORRADE_COMPARE_AS(output.second(),
data.message,
TestSuite::Compare::StringHasPrefix);
/* It should return a non-zero code */
CORRADE_VERIFY(!output.first());
#endif
}
#endif
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::SceneTools::Test::SceneConverterTest) CORRADE_TEST_MAIN(Magnum::SceneTools::Test::SceneConverterTest)

3
src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-mesh.obj

@ -0,0 +1,3 @@
# A point with two indices
v 1 2 3
p 5 5

22
src/Magnum/SceneTools/Test/SceneConverterTestFiles/broken-scene.gltf

@ -0,0 +1,22 @@
{
"asset": {
"version": "2.0"
},
"scenes": [
{
"nodes": [0]
}
],
"meshes": [
{
"primitives": [
{}
]
}
],
"nodes": [
{
"mesh": 1
}
]
}

5
src/Magnum/SceneTools/Test/SceneConverterTestFiles/empty.gltf

@ -0,0 +1,5 @@
{
"asset": {
"version": "2.0"
}
}

6
src/Magnum/SceneTools/Test/SceneConverterTestFiles/info-ignored-output.txt

@ -0,0 +1,6 @@
Ignoring output file for --info: whatever.ply
Mesh 0:
Level 0: 1 vertices @ Points (0.0 kB)
Position @ Vector3, offset 0, stride 12
1 indices @ UnsignedInt, offset 0, stride 4 (0.0 kB)
Total mesh data size: 0.0 kB

5
src/Magnum/SceneTools/Test/SceneConverterTestFiles/info.txt

@ -0,0 +1,5 @@
Mesh 0:
Level 0: 1 vertices @ Points (0.0 kB)
Position @ Vector3, offset 0, stride 12
1 indices @ UnsignedInt, offset 0, stride 4 (0.0 kB)
Total mesh data size: 0.0 kB

2
src/Magnum/SceneTools/Test/SceneConverterTestFiles/point.obj

@ -0,0 +1,2 @@
v 1 2 3
p 1

12
src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad-duplicates-fuzzy.obj

@ -0,0 +1,12 @@
# 1 4--6
# |\ \ |
# | \ \|
# 2--3 5
v -1 1 0
v -1 -1 0
v 1 -1 0
f 1 2 3
v -0.9 0.9 0
v 0.9 -0.9 0
v 1 1 0
f 4 5 6

12
src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad-duplicates.obj

@ -0,0 +1,12 @@
# 1 4--6
# |\ \ |
# | \ \|
# 2--3 5
v -1 1 0
v -1 -1 0
v 1 -1 0
f 1 2 3
v -1 1 0
v 1 -1 0
v 1 1 0
f 4 5 6

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad-duplicates.ply

Binary file not shown.

12
src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad-normals-texcoords.obj

@ -0,0 +1,12 @@
# 1 1--4
# |\ \ |
# | \ \|
# 2--3 3
v -1 1 0
v -1 -1 0
v 1 -1 0
v 1 1 0
vn 0 0 1
vt 0 0
f 1/1/1 2/1/1 3/1/1
f 1/1/1 3/1/1 4/1/1

10
src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad.obj

@ -0,0 +1,10 @@
# 1 1--4
# |\ \ |
# | \ \|
# 2--3 3
v -1 1 0
v -1 -1 0
v 1 -1 0
v 1 1 0
f 1 2 3
f 1 3 4

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/quad.ply

Binary file not shown.

BIN
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-triangles-transformed.bin

Binary file not shown.

15
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-triangles-transformed.bin.in

@ -0,0 +1,15 @@
# Like two-triangles.obj, but the second triangle moved 10 units on Y. Convert
# with magnum-plugins/src/MagnumPlugins/GltfImporter/Test/in2bin.py.
type = "3f3f3f 3f3f3f"
input = [
-1, 1, 0,
-1, -1, 0,
1, -1, 0,
-1, 11, 0,
1, 9, 0,
1, 11, 0
]
# kate: hl python

75
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-triangles-transformed.gltf

@ -0,0 +1,75 @@
{
"asset": {
"version": "2.0"
},
"buffers": [
{
"uri": "two-triangles-transformed.bin",
"byteLength": 72
}
],
"bufferViews": [
{
"buffer": 0,
"byteLength": 36
},
{
"buffer": 0,
"byteOffset": 36,
"byteLength": 36
}
],
"accessors": [
{
"bufferView": 0,
"componentType": 5126,
"count": 3,
"type": "VEC3"
},
{
"bufferView": 1,
"componentType": 5126,
"count": 3,
"type": "VEC3"
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"POSITION": 0
}
}
]
},
{
"primitives": [
{
"attributes": {
"POSITION": 1
}
}
]
}
],
"nodes": [
{
"mesh": 0
},
{
"name": "Explicit intermediate node to test proper traversal",
"translation": [0, -5, 0],
"children": [2]
},
{
"mesh": 1,
"translation": [0, -5, 0]
}
],
"scenes": [
{
"nodes": [0, 1]
}
]
}

14
src/Magnum/SceneTools/Test/SceneConverterTestFiles/two-triangles.obj

@ -0,0 +1,14 @@
# 1 4--6
# |\ \ |
# | \ \|
# 2--3 5
o First
v -1 1 0
v -1 -1 0
v 1 -1 0
f 1 2 3
o Second
v -1 1 0
v 1 -1 0
v 1 1 0
f 4 5 6

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

@ -24,3 +24,27 @@
*/ */
#define SCENETOOLS_TEST_DIR "${SCENETOOLS_TEST_DIR}" #define SCENETOOLS_TEST_DIR "${SCENETOOLS_TEST_DIR}"
#define SCENETOOLS_TEST_OUTPUT_DIR "${SCENETOOLS_TEST_OUTPUT_DIR}"
#cmakedefine SCENECONVERTER_EXECUTABLE_FILENAME "${SCENECONVERTER_EXECUTABLE_FILENAME}"
#ifdef CORRADE_TARGET_WINDOWS
#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_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_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_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_SCENECONVERTER_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${MAGNUM_PLUGINS_SCENECONVERTER_RELEASE_LIBRARY_INSTALL_DIR}"
#endif
#endif

2
src/Magnum/SceneTools/sceneconverter.cpp

@ -510,7 +510,7 @@ is specified as well, the IDs reference attributes of the first mesh.)")
if(i + 1 >= converterCount && (converter->features() & Trade::SceneConverterFeature::ConvertMeshToFile)) { if(i + 1 >= converterCount && (converter->features() & Trade::SceneConverterFeature::ConvertMeshToFile)) {
/* No verbose output for just one converter */ /* No verbose output for just one converter */
if(converterCount > 1 && args.isSet("verbose")) if(converterCount > 1 && args.isSet("verbose"))
Debug{} << "Saving output with" << converterName << Debug::nospace << "..."; Debug{} << "Saving output (" << Debug::nospace << (i+1) << Debug::nospace << "/" << Debug::nospace << converterCount << Debug::nospace << ") with" << converterName << Debug::nospace << "...";
Trade::Implementation::Duration d{conversionTime}; Trade::Implementation::Duration d{conversionTime};
if(!converter->convertToFile(*mesh, args.value("output"))) { if(!converter->convertToFile(*mesh, args.value("output"))) {

Loading…
Cancel
Save