mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1819 lines
89 KiB
1819 lines
89 KiB
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
|
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a |
|
copy of this software and associated documentation files (the "Software"), |
|
to deal in the Software without restriction, including without limitation |
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
and/or sell copies of the Software, and to permit persons to whom the |
|
Software is furnished to do so, subject to the following conditions: |
|
|
|
The above copyright notice and this permission notice shall be included |
|
in all copies or substantial portions of the Software. |
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
DEALINGS IN THE SOFTWARE. |
|
*/ |
|
|
|
#include <sstream> |
|
#include <Corrade/Containers/ArrayTuple.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/Utility/Algorithms.h> |
|
#include <Corrade/Utility/DebugStl.h> |
|
#include <Corrade/Utility/Path.h> |
|
|
|
#include "Magnum/Math/CubicHermite.h" |
|
#include "Magnum/Math/Matrix3.h" |
|
#include "Magnum/Math/Matrix4.h" |
|
#include "Magnum/Trade/AbstractSceneConverter.h" |
|
|
|
#include "Magnum/SceneTools/Implementation/sceneConverterUtilities.h" |
|
|
|
#include "configure.h" |
|
|
|
namespace Magnum { namespace SceneTools { namespace Test { namespace { |
|
|
|
struct SceneConverterTest: TestSuite::Tester { |
|
explicit SceneConverterTest(); |
|
|
|
void infoImplementationEmpty(); |
|
void infoImplementationScenesObjects(); |
|
void infoImplementationAnimations(); |
|
void infoImplementationSkins(); |
|
void infoImplementationLights(); |
|
void infoImplementationCameras(); |
|
void infoImplementationMaterials(); |
|
void infoImplementationMeshes(); |
|
void infoImplementationMeshesBounds(); |
|
void infoImplementationTextures(); |
|
void infoImplementationImages(); |
|
/* Image info further tested in ImageConverterTest */ |
|
void infoImplementationReferenceCount(); |
|
void infoImplementationError(); |
|
|
|
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT |
|
void info(); |
|
void convert(); |
|
void error(); |
|
#endif |
|
|
|
Utility::Arguments _infoArgs; |
|
}; |
|
|
|
using namespace Containers::Literals; |
|
using namespace Math::Literals; |
|
|
|
const struct { |
|
const char* name; |
|
const char* arg; |
|
const char* expected; |
|
bool printVisualCheck; |
|
} InfoImplementationScenesObjectsData[]{ |
|
{"", "--info", "info-scenes-objects.txt", true}, |
|
{"only scenes", "--info-scenes", "info-scenes.txt", false}, |
|
{"only objects", "--info-objects", "info-objects.txt", false}, |
|
}; |
|
|
|
const struct { |
|
const char* name; |
|
bool oneOrAll; |
|
bool printVisualCheck; |
|
} InfoImplementationOneOrAllData[]{ |
|
{"", true, true}, |
|
{"--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; |
|
const char* expected2; |
|
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", 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", |
|
"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", |
|
"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", |
|
"quad.ply", nullptr, |
|
{}}, |
|
{"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", nullptr, |
|
"Trade::AnySceneImporter::openFile(): option nonexistentOption not recognized by ObjImporter\n" |
|
"Trade::AnySceneConverter::beginFile(): 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", nullptr, |
|
"Option nonexistentOption not recognized by ObjImporter\n" |
|
"Option nonexistentConverterOption not recognized by StanfordSceneConverter\n"}, |
|
{"two meshes + scene", Containers::array<Containers::String>({ |
|
/* Removing the generator identifier to have the file fully roundtrip */ |
|
"-c", "generator=", |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}), |
|
"GltfImporter", "GltfSceneConverter", |
|
/* There should be a minimal difference compared to the original */ |
|
"two-quads.gltf", "two-quads.bin", |
|
{}}, |
|
{"concatenate meshes without a scene", Containers::array<Containers::String>({ |
|
"--concatenate-meshes", |
|
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", 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", |
|
"quad-duplicates.ply", nullptr, |
|
{}}, |
|
/** @todo drop --mesh once it's not needed anymore again, then add a |
|
multi-mesh variant */ |
|
{"one mesh, filter mesh attributes", Containers::array<Containers::String>({ |
|
/* Only 0 gets picked from here, others ignored */ |
|
"--mesh", "0", "--only-mesh-attributes", "17,0,25-36", |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-normals-texcoords.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), |
|
"ObjImporter", "StanfordSceneConverter", |
|
"quad.ply", nullptr, |
|
{}}, |
|
{"concatenate meshes, filter mesh attributes", Containers::array<Containers::String>({ |
|
"--concatenate-meshes", "--only-mesh-attributes", "17,0,25-36", |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-normals-texcoords.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), |
|
"ObjImporter", "StanfordSceneConverter", |
|
"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", |
|
"quad.ply", nullptr, |
|
{}}, |
|
{"one implicit mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({ |
|
/* Forcing the importer and converter to avoid AnySceneImporter / |
|
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", |
|
"quad.ply", nullptr, |
|
"Mesh 0 duplicate removal: 6 -> 4 vertices\n"}, |
|
{"one selected mesh, remove duplicate vertices, verbose", Containers::array<Containers::String>({ |
|
/* Forcing the importer and converter to avoid AnySceneImporter / |
|
AnySceneConverter delegation messages */ |
|
"--mesh", "1", "--remove-duplicate-vertices", "-v", "-I", "GltfImporter", "-C", "StanfordSceneConverter", |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), |
|
"GltfImporter", "StanfordSceneConverter", |
|
/* The second mesh in the glTF is deliberately the same as in |
|
quad-duplicates.obj, so this produces the same file */ |
|
"quad.ply", nullptr, |
|
"Duplicate removal: 6 -> 4 vertices\n"}, |
|
{"two meshes + scene, remove duplicate vertices, verbose", Containers::array<Containers::String>({ |
|
/* Forcing the importer and converter to avoid AnySceneImporter / |
|
AnySceneConverter delegation messages */ |
|
"--remove-duplicate-vertices", "-v", "-I", "GltfImporter", "-C", "GltfSceneConverter", |
|
/* Removing the generator identifier for a smaller file */ |
|
"-c", "generator=", |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}), |
|
"GltfImporter", "GltfSceneConverter", |
|
/* There should be a minimal difference compared to the original */ |
|
"two-quads.gltf", "two-quads.bin", |
|
"Mesh 0 duplicate removal: 5 -> 4 vertices\n" |
|
"Mesh 1 duplicate removal: 6 -> 4 vertices\n"}, |
|
{"one implicit mesh, remove duplicate vertices fuzzy", Containers::array<Containers::String>({ |
|
"--remove-duplicate-vertices-fuzzy", "1.0e-1", |
|
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", nullptr, |
|
{}}, |
|
{"one implicit mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({ |
|
/* Forcing the importer and converter to avoid AnySceneImporter / |
|
AnySceneConverter delegation messages */ |
|
"--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "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", nullptr, |
|
"Mesh 0 fuzzy duplicate removal: 6 -> 4 vertices\n"}, |
|
{"one selected mesh, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({ |
|
/* Forcing the importer and converter to avoid AnySceneImporter / |
|
AnySceneConverter delegation messages */ |
|
"--mesh 1", "--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "GltfImporter", "-C", "StanfordSceneConverter", |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), |
|
"GltfImporter", "StanfordSceneConverter", |
|
/* The second mesh in the glTF is deliberately the same as in |
|
quad-duplicates-fuzzy.obj, so this produces the same file */ |
|
"quad.ply", nullptr, |
|
"Fuzzy duplicate removal: 6 -> 4 vertices\n"}, |
|
{"two meshes + scene, remove duplicate vertices fuzzy, verbose", Containers::array<Containers::String>({ |
|
/* Forcing the importer and converter to avoid AnySceneImporter / |
|
AnySceneConverter delegation messages */ |
|
"--remove-duplicate-vertices-fuzzy", "1.0e-1", "-v", "-I", "GltfImporter", "-C", "GltfSceneConverter", |
|
/* Removing the generator identifier for a smaller file */ |
|
"-c", "generator=", |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-quads-duplicates-fuzzy.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/two-quads.gltf")}), |
|
"GltfImporter", "GltfSceneConverter", |
|
"two-quads.gltf", "two-quads.bin", |
|
"Mesh 0 fuzzy duplicate removal: 5 -> 4 vertices\n" |
|
"Mesh 1 fuzzy duplicate removal: 6 -> 4 vertices\n"}, |
|
{"one implicit mesh, two converters", Containers::array<Containers::String>({ |
|
"-C", "MeshOptimizerSceneConverter", |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/quad-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), |
|
"GltfImporter", "GltfSceneConverter", |
|
"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", |
|
"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", |
|
"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 |
|
of MeshOptimizerSceneConverter got actually passed further and not |
|
discarded */ |
|
"Trade::AnySceneImporter::openFile(): using GltfImporter\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::beginFile(): using GltfSceneConverter\n"}, |
|
{"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", |
|
"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 |
|
option the verbose output includes a progress info */ |
|
"Trade::AnySceneImporter::openFile(): using GltfImporter\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 GltfSceneConverter...\n"}, |
|
{"one implicit 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-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.ply")}), |
|
"GltfImporter", "GltfSceneConverter", |
|
"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>({ |
|
"-C", "MeshOptimizerSceneConverter", |
|
"-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", |
|
"quad.ply", nullptr, |
|
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n"}, |
|
{"one implicit 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-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), |
|
"GltfImporter", "GltfSceneConverter", |
|
"quad.ply", nullptr, |
|
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n" |
|
"Trade::AnySceneConverter::beginFile(): option nonexistentAnyConverterOption not recognized by GltfSceneConverter\n"}, |
|
{"one implicit 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-strip.gltf"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/quad.gltf")}), |
|
"GltfImporter", "GltfSceneConverter", |
|
"quad.ply", nullptr, |
|
"Option nonexistentMeshOptimizerOption not recognized by MeshOptimizerSceneConverter\n" |
|
"Option nonexistentStanfordConverterOption not recognized by StanfordSceneConverter\n"}, |
|
{"one mesh, remove duplicate vertices, two converters, verbose", Containers::array<Containers::String>({ |
|
"--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", |
|
"quad.ply", nullptr, |
|
"Trade::AnySceneImporter::openFile(): using ObjImporter\n" |
|
"Mesh 0 duplicate removal: 6 -> 4 vertices\n" |
|
/** @todo this only verifies that the result of duplicate removal is |
|
properly passed to MeshOptimizer, but not that the MeshOptimizer |
|
output is properly passed to StanfordSceneConverter -- needs to |
|
wait until there's a plugin which can verify that with a small |
|
data amount */ |
|
"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::beginFile(): using 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 "}, |
|
{"--mesh and --concatenate-meshes", Containers::array<Containers::String>({ |
|
"--mesh", "0", "--concatenate-meshes", "a", "b"}), |
|
nullptr, nullptr, |
|
"The --mesh and --concatenate-meshes options are mutually exclusive\n"}, |
|
{"--mesh-level but no --mesh", Containers::array<Containers::String>({ |
|
"--mesh-level", "0", "a", "b"}), |
|
nullptr, nullptr, |
|
"The --mesh-level option can only be used with --mesh\n"}, |
|
{"--only-mesh-attributes but no --mesh", Containers::array<Containers::String>({ |
|
"--only-mesh-attributes", "0", "a", "b"}), |
|
nullptr, nullptr, |
|
"The --only-mesh-attributes option can only be used with --mesh or --concatenate-meshes\n"}, |
|
{"can't load importer plugin", Containers::array<Containers::String>({ |
|
/* 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 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, |
|
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, |
|
"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"}, |
|
{"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, |
|
"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, |
|
"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 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", |
|
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", |
|
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", |
|
"Trade::AbstractSceneConverter::end(): the converter requires exactly one mesh, got 0\n" |
|
"Cannot end importer conversion\n"}, |
|
{"can't add importer contents", Containers::array<Containers::String>({ |
|
"-I", "ObjImporter", "-C", "StanfordSceneConverter", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/broken-mesh.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}), |
|
"ObjImporter", "StanfordSceneConverter", |
|
"Trade::ObjImporter::mesh(): wrong index count for point\n" |
|
"Cannot add importer contents\n"}, |
|
{"can't add processed meshes", Containers::array<Containers::String>({ |
|
"-I", "ObjImporter", "-C", "StanfordSceneConverter", "--remove-duplicate-vertices", Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/two-triangles.obj"), Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/whatever.ply")}), |
|
"ObjImporter", "StanfordSceneConverter", |
|
"Trade::AbstractSceneConverter::add(): the converter requires exactly one mesh, got 2\n" |
|
"Cannot add mesh 1\n"}, |
|
{"plugin doesn't support importer conversion", Containers::array<Containers::String>({ |
|
/* Pass the same plugin twice, which means the first instance should |
|
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 importer conversion, only Trade::SceneConverterFeature::ConvertMeshToData\n"}, |
|
}; |
|
#endif |
|
|
|
SceneConverterTest::SceneConverterTest() { |
|
addTests({&SceneConverterTest::infoImplementationEmpty}); |
|
|
|
addInstancedTests({&SceneConverterTest::infoImplementationScenesObjects}, |
|
Containers::arraySize(InfoImplementationScenesObjectsData)); |
|
|
|
addInstancedTests({&SceneConverterTest::infoImplementationAnimations, |
|
&SceneConverterTest::infoImplementationSkins, |
|
&SceneConverterTest::infoImplementationLights, |
|
&SceneConverterTest::infoImplementationCameras, |
|
&SceneConverterTest::infoImplementationMaterials, |
|
&SceneConverterTest::infoImplementationMeshes}, |
|
Containers::arraySize(InfoImplementationOneOrAllData)); |
|
|
|
addTests({&SceneConverterTest::infoImplementationMeshesBounds}); |
|
|
|
addInstancedTests({&SceneConverterTest::infoImplementationTextures, |
|
&SceneConverterTest::infoImplementationImages}, |
|
Containers::arraySize(InfoImplementationOneOrAllData)); |
|
|
|
addTests({&SceneConverterTest::infoImplementationReferenceCount, |
|
&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 */ |
|
_infoArgs.addBooleanOption("info") |
|
.addBooleanOption("info-scenes") |
|
.addBooleanOption("info-objects") |
|
.addBooleanOption("info-animations") |
|
.addBooleanOption("info-skins") |
|
.addBooleanOption("info-lights") |
|
.addBooleanOption("info-cameras") |
|
.addBooleanOption("info-materials") |
|
.addBooleanOption("info-meshes") |
|
.addBooleanOption("info-textures") |
|
.addBooleanOption("info-images") |
|
.addBooleanOption("bounds"); |
|
|
|
/* Create output dir, if doesn't already exist */ |
|
Utility::Path::make(Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles")); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationEmpty() { |
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
} importer; |
|
|
|
const char* argv[]{"", "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, {}, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE(out.str(), ""); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationScenesObjects() { |
|
auto&& data = InfoImplementationScenesObjectsData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
/* First scene has 4, second 7, the last three are not in any scene and |
|
thus not listed. Object 5 has no fields and thus not listed either. */ |
|
UnsignedLong doObjectCount() const override { return 10; } |
|
UnsignedInt doSceneCount() const override { return 2; } |
|
Containers::String doSceneName(UnsignedInt id) override { |
|
return id == 0 ? "A simple scene" : ""; |
|
} |
|
Containers::String doObjectName(UnsignedLong id) override { |
|
if(id == 0) return "Parent-less mesh"; |
|
if(id == 2) return "Two meshes, shared among two scenes"; |
|
if(id == 4) return "Two custom arrays"; |
|
if(id == 6) return "Only in the second scene, but no fields, thus same as unreferenced"; |
|
if(id == 8) return "Not in any scene"; |
|
return ""; |
|
} |
|
Containers::String doSceneFieldName(UnsignedInt name) override { |
|
if(name == 1337) return "DirectionVector"; |
|
return ""; |
|
} |
|
Containers::Optional<Trade::SceneData> doScene(UnsignedInt id) override { |
|
/* Builtin fields, some duplicated, one marked as ordered */ |
|
if(id == 0) { |
|
Containers::ArrayView<UnsignedInt> parentMapping; |
|
Containers::ArrayView<Int> parents; |
|
Containers::ArrayView<UnsignedInt> meshMapping; |
|
Containers::ArrayView<UnsignedInt> meshes; |
|
Containers::ArrayTuple data{ |
|
{NoInit, 3, parentMapping}, |
|
{ValueInit, 3, parents}, |
|
{NoInit, 4, meshMapping}, |
|
{ValueInit, 4, meshes}, |
|
}; |
|
Utility::copy({1, 3, 2}, parentMapping); |
|
Utility::copy({2, 0, 2, 1}, meshMapping); |
|
/* No need to fill the data, zero-init is fine */ |
|
return Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 4, std::move(data), { |
|
Trade::SceneFieldData{Trade::SceneField::Parent, parentMapping, parents}, |
|
Trade::SceneFieldData{Trade::SceneField::Mesh, meshMapping, meshes, Trade::SceneFieldFlag::OrderedMapping}, |
|
}}; |
|
} |
|
|
|
/* Two custom fields, one array. Stored as an external memory. */ |
|
if(id == 1) { |
|
return Trade::SceneData{Trade::SceneMappingType::UnsignedByte, 8, Trade::DataFlag::ExternallyOwned|Trade::DataFlag::Mutable, scene2Data, { |
|
Trade::SceneFieldData{Trade::sceneFieldCustom(42), Containers::arrayView(scene2Data->customMapping), Containers::arrayView(scene2Data->custom)}, |
|
Trade::SceneFieldData{Trade::sceneFieldCustom(1337), Trade::SceneMappingType::UnsignedByte, scene2Data->customArrayMapping, Trade::SceneFieldType::Short, scene2Data->customArray, 3}, |
|
}}; |
|
} |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
struct { |
|
UnsignedByte customMapping[2]; |
|
Double custom[2]; |
|
UnsignedByte customArrayMapping[3]; |
|
Vector3s customArray[3]; |
|
} scene2Data[1]{{ |
|
/* No need to fill the data, zero-init is fine */ |
|
{7, 3}, {}, {2, 4, 4}, {} |
|
}}; |
|
} importer; |
|
|
|
const char* argv[]{"", data.arg}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
if(data.printVisualCheck) { |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, {}, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join({SCENETOOLS_TEST_DIR, "SceneConverterTestFiles", data.expected}), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationAnimations() { |
|
auto&& data = InfoImplementationOneOrAllData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
UnsignedInt doAnimationCount() const override { return 2; } |
|
Containers::String doAnimationName(UnsignedInt id) override { |
|
return id == 1 ? "Custom track duration and interpolator function" : ""; |
|
} |
|
Containers::Optional<Trade::AnimationData> doAnimation(UnsignedInt id) override { |
|
/* First has two tracks with a shared time and implicit duration, |
|
one with a different result type. */ |
|
if(id == 0) { |
|
Containers::ArrayView<Float> time; |
|
Containers::ArrayView<Vector2> translation; |
|
Containers::ArrayView<CubicHermite2D> rotation; |
|
Containers::ArrayTuple data{ |
|
{ValueInit, 3, time}, |
|
{ValueInit, 3, translation}, |
|
{ValueInit, 3, rotation} |
|
}; |
|
Utility::copy({0.5f, 1.0f, 1.25f}, time); |
|
return Trade::AnimationData{std::move(data), { |
|
/** @todo cleanup once AnimationTrackData has sane |
|
constructors */ |
|
Trade::AnimationTrackData{Trade::AnimationTrackTargetType::Translation2D, 17, Animation::TrackView<const Float, const Vector2>{time, translation, Animation::Interpolation::Linear, Animation::Extrapolation::DefaultConstructed, Animation::Extrapolation::Constant}}, |
|
Trade::AnimationTrackData{Trade::AnimationTrackTargetType::Rotation2D, 17, Animation::TrackView<const Float, const CubicHermite2D>{time, rotation, Animation::Interpolation::Constant, Animation::Extrapolation::Extrapolated}}, |
|
}}; |
|
} |
|
|
|
/* Second has track duration different from animation duration and |
|
a custom interpolator. Stored as an external memory. */ |
|
if(id == 1) { |
|
return Trade::AnimationData{Trade::DataFlag::ExternallyOwned, animation2Data, { |
|
/** @todo cleanup once AnimationTrackData has sane |
|
constructors */ |
|
Trade::AnimationTrackData{Trade::AnimationTrackTargetType::Scaling3D, 666, Animation::TrackView<const Float, const Vector3>{animation2Data->time, animation2Data->scaling, Math::lerp, Animation::Extrapolation::DefaultConstructed, Animation::Extrapolation::Constant}}, |
|
}, {0.1f, 1.3f}}; |
|
} |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
struct { |
|
Float time[5]; |
|
Vector3 scaling[5]; |
|
} animation2Data[1]{{ |
|
{0.75f, 0.75f, 1.0f, 1.0f, 1.25f}, |
|
{} |
|
}}; |
|
} importer; |
|
|
|
const char* argv[]{"", data.oneOrAll ? "--info-animations" : "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
if(data.printVisualCheck) { |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, {}, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-animations.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationSkins() { |
|
auto&& data = InfoImplementationOneOrAllData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
UnsignedInt doSkin2DCount() const override { return 2; } |
|
Containers::String doSkin2DName(UnsignedInt id) override { |
|
return id == 1 ? "Second 2D skin, external data" : ""; |
|
} |
|
Containers::Optional<Trade::SkinData2D> doSkin2D(UnsignedInt id) override { |
|
/* First a regular skin, second externally owned */ |
|
if(id == 0) return Trade::SkinData2D{ |
|
{3, 6, 7, 12, 22}, |
|
{{}, {}, {}, {}, {}} |
|
}; |
|
|
|
if(id == 1) return Trade::SkinData2D{Trade::DataFlag::ExternallyOwned, skin2JointData, Trade::DataFlag::ExternallyOwned, skin2MatrixData}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doSkin3DCount() const override { return 3; } |
|
Containers::String doSkin3DName(UnsignedInt id) override { |
|
return id == 0 ? "First 3D skin, external data" : ""; |
|
} |
|
Containers::Optional<Trade::SkinData3D> doSkin3D(UnsignedInt id) override { |
|
/* Reverse order in 3D, plus one more to ensure the count isn't |
|
mismatched between 2D and 3D */ |
|
if(id == 0) return Trade::SkinData3D{Trade::DataFlag::ExternallyOwned, skin3JointData, Trade::DataFlag::ExternallyOwned, skin3MatrixData}; |
|
|
|
if(id == 1) return Trade::SkinData3D{ |
|
{3, 22}, |
|
{{}, {}} |
|
}; |
|
|
|
if(id == 2) return Trade::SkinData3D{ |
|
{3}, |
|
{{}} |
|
}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt skin2JointData[15]; |
|
Matrix3 skin2MatrixData[15]; |
|
UnsignedInt skin3JointData[12]; |
|
Matrix4 skin3MatrixData[12]; |
|
} importer; |
|
|
|
const char* argv[]{"", data.oneOrAll ? "--info-skins" : "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
if(data.printVisualCheck) { |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, {}, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-skins.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationLights() { |
|
auto&& data = InfoImplementationOneOrAllData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
UnsignedInt doLightCount() const override { return 2; } |
|
Containers::String doLightName(UnsignedInt id) override { |
|
return id == 1 ? "Directional light with always-implicit attenuation and range" : ""; |
|
} |
|
Containers::Optional<Trade::LightData> doLight(UnsignedInt id) override { |
|
/* First a blue spot light */ |
|
if(id == 0) return Trade::LightData{ |
|
Trade::LightData::Type::Spot, |
|
0x3457ff_rgbf, |
|
15.0f, |
|
{1.2f, 0.3f, 0.04f}, |
|
100.0f, |
|
55.0_degf, |
|
85.0_degf |
|
}; |
|
|
|
/* Second a yellow directional light with infinite range */ |
|
if(id == 1) return Trade::LightData{ |
|
Trade::LightData::Type::Directional, |
|
0xff5734_rgbf, |
|
5.0f |
|
}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
} importer; |
|
|
|
const char* argv[]{"", data.oneOrAll ? "--info-lights" : "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
if(data.printVisualCheck) { |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, false, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-lights.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationCameras() { |
|
auto&& data = InfoImplementationOneOrAllData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
UnsignedInt doCameraCount() const override { return 3; } |
|
Containers::String doCameraName(UnsignedInt id) override { |
|
return id == 0 ? "Orthographic 2D" : ""; |
|
} |
|
Containers::Optional<Trade::CameraData> doCamera(UnsignedInt id) override { |
|
/* First 2D ortho camera, where near/far will get omited */ |
|
if(id == 0) return Trade::CameraData{ |
|
Trade::CameraType::Orthographic2D, |
|
{5.0f, 6.0f}, |
|
0.0f, 0.0f |
|
}; |
|
|
|
/* 3D ortho camera */ |
|
if(id == 1) return Trade::CameraData{ |
|
Trade::CameraType::Orthographic3D, |
|
{2.0f, 3.0f}, |
|
-1.0f, 0.5f |
|
}; |
|
|
|
/* Third a perspective camera, specified with size, but printed |
|
with FoV */ |
|
if(id == 2) return Trade::CameraData{ |
|
Trade::CameraType::Perspective3D, |
|
35.0_degf, 4.0f/3.0f, 0.01f, 100.0f |
|
}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
} importer; |
|
|
|
const char* argv[]{"", data.oneOrAll ? "--info-cameras" : "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
if(data.printVisualCheck) { |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, false, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-cameras.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationMaterials() { |
|
auto&& data = InfoImplementationOneOrAllData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
UnsignedInt doMaterialCount() const override { return 2; } |
|
Containers::String doMaterialName(UnsignedInt id) override { |
|
return id == 1 ? "Lots o' laierz" : ""; |
|
} |
|
Containers::Optional<Trade::MaterialData> doMaterial(UnsignedInt id) override { |
|
/* First has custom attributes */ |
|
if(id == 0) return Trade::MaterialData{Trade::MaterialType::PbrMetallicRoughness, { |
|
{Trade::MaterialAttribute::BaseColor, 0x3bd26799_rgbaf}, |
|
{Trade::MaterialAttribute::DoubleSided, true}, |
|
{Trade::MaterialAttribute::EmissiveColor, 0xe9eca_rgbf}, |
|
{Trade::MaterialAttribute::RoughnessTexture, 67u}, |
|
{Trade::MaterialAttribute::RoughnessTextureMatrix, Matrix3::translation({0.25f, 0.75f})}, |
|
{Trade::MaterialAttribute::RoughnessTextureSwizzle, Trade::MaterialTextureSwizzle::B}, |
|
{"reflectionAngle", 35.0_degf}, |
|
/* These shouldn't have a color swatch rendered */ |
|
{"notAColour4", Vector4{0.1f, 0.2f, 0.3f, 0.4f}}, |
|
{"notAColour3", Vector3{0.2f, 0.3f, 0.4f}}, |
|
{"deadBeef", reinterpret_cast<const void*>(0xdeadbeef)}, |
|
{"undeadBeef", reinterpret_cast<void*>(0xbeefbeef)}, |
|
}}; |
|
|
|
/* Second has layers, custom layers, unnamed layers and a name */ |
|
if(id == 1) return Trade::MaterialData{Trade::MaterialType::PbrClearCoat|Trade::MaterialType::Phong, { |
|
{Trade::MaterialAttribute::DiffuseColor, 0xc7cf2f99_rgbaf}, |
|
{Trade::MaterialLayer::ClearCoat}, |
|
{Trade::MaterialAttribute::LayerFactor, 0.5f}, |
|
{Trade::MaterialAttribute::LayerFactorTexture, 3u}, |
|
{Trade::MaterialAttribute::LayerName, "anEmptyLayer"}, |
|
{Trade::MaterialAttribute::LayerFactor, 0.25f}, |
|
{Trade::MaterialAttribute::LayerFactorTexture, 2u}, |
|
{"yes", "a string"}, |
|
}, {1, 4, 5, 8}}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
} importer; |
|
|
|
const char* argv[]{"", data.oneOrAll ? "--info-materials" : "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
if(data.printVisualCheck) { |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, false, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-materials.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationMeshes() { |
|
auto&& data = InfoImplementationOneOrAllData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
UnsignedInt doMeshCount() const override { return 3; } |
|
UnsignedInt doMeshLevelCount(UnsignedInt id) override { |
|
return id == 1 ? 2 : 1; |
|
} |
|
Containers::String doMeshName(UnsignedInt id) override { |
|
return id == 1 ? "LODs? No, meshets." : ""; |
|
} |
|
Containers::String doMeshAttributeName(UnsignedShort name) override { |
|
if(name == 25) return "vertices"; |
|
if(name == 26) return "triangles"; |
|
/* 37 (triangleCount) deliberately not named */ |
|
if(name == 116) return "vertexCount"; |
|
|
|
return ""; |
|
} |
|
Containers::Optional<Trade::MeshData> doMesh(UnsignedInt id, UnsignedInt level) override { |
|
/* First is indexed & externally owned */ |
|
if(id == 0 && level == 0) return Trade::MeshData{MeshPrimitive::Points, |
|
Trade::DataFlag::ExternallyOwned, indices, |
|
Trade::MeshIndexData{indices}, |
|
Trade::DataFlag::ExternallyOwned|Trade::DataFlag::Mutable, points, { |
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(points)} |
|
}}; |
|
|
|
/* Second is multi-level, with second level being indexed meshlets |
|
with custom (array) attributes */ |
|
if(id == 1 && level == 0) { |
|
Containers::ArrayView<Vector3> positions; |
|
Containers::ArrayView<Vector4> tangents; |
|
Containers::ArrayTuple data{ |
|
{NoInit, 250, positions}, |
|
{NoInit, 250, tangents}, |
|
}; |
|
return Trade::MeshData{MeshPrimitive::Triangles, std::move(data), { |
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, positions}, |
|
Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, tangents}, |
|
}}; |
|
} |
|
if(id == 1 && level == 1) { |
|
Containers::StridedArrayView2D<UnsignedInt> vertices; |
|
Containers::StridedArrayView2D<Vector3ub> indices; |
|
Containers::ArrayView<UnsignedByte> triangleCount; |
|
Containers::ArrayView<UnsignedByte> vertexCount; |
|
Containers::ArrayTuple data{ |
|
{NoInit, {135, 64}, vertices}, |
|
{NoInit, {135, 126}, indices}, |
|
{NoInit, 135, triangleCount}, |
|
{NoInit, 135, vertexCount}, |
|
}; |
|
return Trade::MeshData{MeshPrimitive::Meshlets, std::move(data), { |
|
Trade::MeshAttributeData{Trade::meshAttributeCustom(25), vertices}, |
|
Trade::MeshAttributeData{Trade::meshAttributeCustom(26), indices}, |
|
Trade::MeshAttributeData{Trade::meshAttributeCustom(37), triangleCount}, |
|
Trade::MeshAttributeData{Trade::meshAttributeCustom(116), vertexCount}, |
|
}}; |
|
} |
|
|
|
/* Third is an empty instance mesh */ |
|
if(id == 2 && level == 0) return Trade::MeshData{MeshPrimitive::Instances, 15}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedShort indices[70]; |
|
Vector3 points[50]; |
|
} importer; |
|
|
|
const char* argv[]{"", data.oneOrAll ? "--info-meshes" : "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
if(data.printVisualCheck) { |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, false, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-meshes.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationMeshesBounds() { |
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
UnsignedInt doMeshCount() const override { return 1; } |
|
Containers::Optional<Trade::MeshData> doMesh(UnsignedInt, UnsignedInt) override { |
|
return Trade::MeshData{MeshPrimitive::Lines, |
|
{}, indexData, Trade::MeshIndexData{indexData}, |
|
{}, vertexData, { |
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::arrayView(vertexData->positions)}, |
|
Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, Containers::arrayView(vertexData->tangent)}, |
|
Trade::MeshAttributeData{Trade::MeshAttribute::Bitangent, Containers::arrayView(vertexData->bitangent)}, |
|
Trade::MeshAttributeData{Trade::MeshAttribute::ObjectId, Containers::arrayView(vertexData->objectId)}, |
|
Trade::MeshAttributeData{Trade::MeshAttribute::Normal, Containers::arrayView(vertexData->normal)}, |
|
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, Containers::arrayView(vertexData->textureCoordinates)}, |
|
Trade::MeshAttributeData{Trade::MeshAttribute::Color, Containers::arrayView(vertexData->color)}, |
|
Trade::MeshAttributeData{Trade::MeshAttribute::ObjectId, Containers::arrayView(vertexData->objectIdSecondary)}, |
|
}}; |
|
} |
|
|
|
UnsignedByte indexData[3]{15, 3, 176}; |
|
|
|
struct { |
|
Vector3 positions[2]; |
|
Vector3 tangent[2]; |
|
Vector3 bitangent[2]; |
|
UnsignedShort objectId[2]; |
|
Vector3 normal[2]; |
|
Vector2 textureCoordinates[2]; |
|
Vector4 color[2]; |
|
UnsignedInt objectIdSecondary[2]; |
|
} vertexData[1]{{ |
|
{{0.1f, -0.1f, 0.2f}, {0.2f, 0.0f, -0.2f}}, |
|
{{0.2f, -0.2f, 0.8f}, {0.3f, 0.8f, 0.2f}}, |
|
{{0.4f, 0.2f, 1.0f}, {0.3f, 0.9f, 0.0f}}, |
|
{155, 12}, |
|
{{0.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 1.0f}}, |
|
{{0.5f, 0.5f}, {1.5f, 0.5f}}, |
|
{0x99336600_rgbaf, 0xff663333_rgbaf}, |
|
{15, 337}, |
|
}}; |
|
} importer; |
|
|
|
const char* argv[]{"", "--info-meshes", "--bounds"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
{ |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, false, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-meshes-bounds.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationTextures() { |
|
auto&& data = InfoImplementationOneOrAllData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
UnsignedInt doTextureCount() const override { return 2; } |
|
Containers::String doTextureName(UnsignedInt id) override { |
|
return id == 1 ? "Name!" : ""; |
|
} |
|
Containers::Optional<Trade::TextureData> doTexture(UnsignedInt id) override { |
|
/* First a 1D texture */ |
|
if(id == 0) return Trade::TextureData{ |
|
Trade::TextureType::Texture1D, |
|
SamplerFilter::Nearest, |
|
SamplerFilter::Linear, |
|
SamplerMipmap::Nearest, |
|
SamplerWrapping::Repeat, |
|
666 |
|
}; |
|
|
|
/* Second a 2D array texture */ |
|
if(id == 1) return Trade::TextureData{ |
|
Trade::TextureType::Texture2DArray, |
|
SamplerFilter::Linear, |
|
SamplerFilter::Nearest, |
|
SamplerMipmap::Linear, |
|
{SamplerWrapping::MirroredRepeat, SamplerWrapping::ClampToEdge, SamplerWrapping::MirrorClampToEdge}, |
|
3 |
|
}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
} importer; |
|
|
|
const char* argv[]{"", data.oneOrAll ? "--info-textures" : "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
if(data.printVisualCheck) { |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, false, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-textures.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationImages() { |
|
auto&& data = InfoImplementationOneOrAllData[testCaseInstanceId()]; |
|
setTestCaseDescription(data.name); |
|
|
|
/* Just the very basics to ensure image info *is* printed. Tested in full |
|
in ImageConverterTest. */ |
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
UnsignedInt doImage1DCount() const override { return 1; } |
|
Containers::Optional<Trade::ImageData1D> doImage1D(UnsignedInt, UnsignedInt) override { |
|
return Trade::ImageData1D{PixelFormat::R32F, 1024, Containers::Array<char>{NoInit, 4096}}; |
|
} |
|
} importer; |
|
|
|
const char* argv[]{"", data.oneOrAll ? "--info-images" : "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
if(data.printVisualCheck) { |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, false, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-images.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationReferenceCount() { |
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
/* One data of each kind should be always referenced twice+, one once, |
|
one not at all, and one reference should be OOB */ |
|
|
|
UnsignedLong doObjectCount() const override { return 4; } |
|
Containers::String doObjectName(UnsignedLong id) override { |
|
return id == 2 ? "Not referenced" : ""; |
|
} |
|
UnsignedInt doSceneCount() const override { return 2; } |
|
Containers::Optional<Trade::SceneData> doScene(UnsignedInt id) override { |
|
if(id == 0) return Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 2, {}, sceneData3D, { |
|
/* To mark the scene as 3D */ |
|
Trade::SceneFieldData{Trade::SceneField::Transformation, Trade::SceneMappingType::UnsignedInt, nullptr, Trade::SceneFieldType::Matrix4x4, nullptr}, |
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
|
Containers::arrayView(sceneData3D->mapping), |
|
Containers::arrayView(sceneData3D->meshes)}, |
|
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, |
|
Containers::arrayView(sceneData3D->mapping), |
|
Containers::arrayView(sceneData3D->materials)}, |
|
Trade::SceneFieldData{Trade::SceneField::Light, |
|
Containers::arrayView(sceneData3D->mapping), |
|
Containers::arrayView(sceneData3D->lights)}, |
|
Trade::SceneFieldData{Trade::SceneField::Camera, |
|
Containers::arrayView(sceneData3D->mapping), |
|
Containers::arrayView(sceneData3D->cameras)}, |
|
Trade::SceneFieldData{Trade::SceneField::Skin, |
|
Containers::arrayView(sceneData3D->mapping), |
|
Containers::arrayView(sceneData3D->skins)}, |
|
}}; |
|
if(id == 1) return Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 4, {}, sceneData2D, { |
|
/* To mark the scene as 2D */ |
|
Trade::SceneFieldData{Trade::SceneField::Transformation, Trade::SceneMappingType::UnsignedInt, nullptr, Trade::SceneFieldType::Matrix3x3, nullptr}, |
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
|
Containers::arrayView(sceneData2D->mapping), |
|
Containers::arrayView(sceneData2D->meshes)}, |
|
Trade::SceneFieldData{Trade::SceneField::Skin, |
|
Containers::arrayView(sceneData2D->mapping), |
|
Containers::arrayView(sceneData2D->skins)}, |
|
}}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doSkin2DCount() const override { return 3; } |
|
Containers::String doSkin2DName(UnsignedInt id) override { |
|
return id == 2 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::SkinData2D> doSkin2D(UnsignedInt id) override { |
|
if(id == 0) return Trade::SkinData2D{ |
|
{35, 22}, |
|
{{}, {}} |
|
}; |
|
if(id == 1) return Trade::SkinData2D{ |
|
{33, 10, 100}, |
|
{{}, {}, {}} |
|
}; |
|
if(id == 2) return Trade::SkinData2D{ |
|
{66}, |
|
{{}} |
|
}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doSkin3DCount() const override { return 3; } |
|
Containers::String doSkin3DName(UnsignedInt id) override { |
|
return id == 0 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::SkinData3D> doSkin3D(UnsignedInt id) override { |
|
if(id == 0) return Trade::SkinData3D{ |
|
{35, 22}, |
|
{{}, {}} |
|
}; |
|
if(id == 1) return Trade::SkinData3D{ |
|
{37}, |
|
{{}} |
|
}; |
|
if(id == 2) return Trade::SkinData3D{ |
|
{300, 10, 1000}, |
|
{{}, {}, {}} |
|
}; |
|
|
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doLightCount() const override { return 3; } |
|
Containers::String doLightName(UnsignedInt id) override { |
|
return id == 1 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::LightData> doLight(UnsignedInt id) override { |
|
if(id == 0) return Trade::LightData{ |
|
Trade::LightData::Type::Directional, |
|
0x57ff34_rgbf, |
|
5.0f |
|
}; |
|
if(id == 1) return Trade::LightData{ |
|
Trade::LightData::Type::Ambient, |
|
0xff5734_rgbf, |
|
0.1f |
|
}; |
|
if(id == 2) return Trade::LightData{ |
|
Trade::LightData::Type::Directional, |
|
0x3457ff_rgbf, |
|
1.0f |
|
}; |
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doCameraCount() const override { return 3; } |
|
Containers::String doCameraName(UnsignedInt id) override { |
|
return id == 0 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::CameraData> doCamera(UnsignedInt id) override { |
|
if(id == 0) return Trade::CameraData{ |
|
Trade::CameraType::Orthographic3D, |
|
{2.0f, 3.0f}, |
|
-1.0f, 0.5f |
|
}; |
|
if(id == 1) return Trade::CameraData{ |
|
Trade::CameraType::Orthographic3D, |
|
{2.0f, 2.0f}, |
|
0.0f, 1.0f |
|
}; |
|
if(id == 2) return Trade::CameraData{ |
|
Trade::CameraType::Orthographic2D, |
|
{2.0f, 2.0f}, |
|
0.0f, 0.0f |
|
}; |
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doMaterialCount() const override { return 3; } |
|
Containers::String doMaterialName(UnsignedInt id) override { |
|
return id == 2 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::MaterialData> doMaterial(UnsignedInt id) override { |
|
if(id == 0) return Trade::MaterialData{{}, { |
|
{Trade::MaterialAttribute::DiffuseTexture, 2u}, |
|
{Trade::MaterialAttribute::BaseColorTexture, 2u}, |
|
}}; |
|
if(id == 1) return Trade::MaterialData{{}, { |
|
{"lookupTexture", 0u}, |
|
{"volumeTexture", 3u}, |
|
{Trade::MaterialAttribute::NormalTexture, 17u}, |
|
{Trade::MaterialAttribute::EmissiveTexture, 4u}, |
|
}}; |
|
if(id == 2) return Trade::MaterialData{{}, {}}; |
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doMeshCount() const override { return 3; } |
|
Containers::String doMeshName(UnsignedInt id) override { |
|
return id == 1 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::MeshData> doMesh(UnsignedInt id, UnsignedInt) override { |
|
if(id == 0) return Trade::MeshData{MeshPrimitive::Points, 5}; |
|
if(id == 1) return Trade::MeshData{MeshPrimitive::Lines, 4}; |
|
if(id == 2) return Trade::MeshData{MeshPrimitive::TriangleFan, 4}; |
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doTextureCount() const override { return 5; } |
|
Containers::String doTextureName(UnsignedInt id) override { |
|
return id == 1 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::TextureData> doTexture(UnsignedInt id) override { |
|
if(id == 0) return Trade::TextureData{ |
|
Trade::TextureType::Texture1D, |
|
SamplerFilter::Nearest, |
|
SamplerFilter::Linear, |
|
SamplerMipmap::Nearest, |
|
SamplerWrapping::Repeat, |
|
1 |
|
}; |
|
if(id == 1) return Trade::TextureData{ |
|
Trade::TextureType::Texture1DArray, |
|
SamplerFilter::Nearest, |
|
SamplerFilter::Linear, |
|
SamplerMipmap::Nearest, |
|
SamplerWrapping::Repeat, |
|
225 |
|
}; |
|
if(id == 2) return Trade::TextureData{ |
|
Trade::TextureType::Texture2D, |
|
SamplerFilter::Nearest, |
|
SamplerFilter::Linear, |
|
SamplerMipmap::Nearest, |
|
SamplerWrapping::Repeat, |
|
0 |
|
}; |
|
if(id == 3) return Trade::TextureData{ |
|
Trade::TextureType::Texture3D, |
|
SamplerFilter::Nearest, |
|
SamplerFilter::Linear, |
|
SamplerMipmap::Nearest, |
|
SamplerWrapping::Repeat, |
|
1 |
|
}; |
|
if(id == 4) return Trade::TextureData{ |
|
Trade::TextureType::Texture2D, |
|
SamplerFilter::Nearest, |
|
SamplerFilter::Linear, |
|
SamplerMipmap::Nearest, |
|
SamplerWrapping::Repeat, |
|
0 |
|
}; |
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doImage1DCount() const override { return 2; } |
|
Containers::String doImage1DName(UnsignedInt id) override { |
|
return id == 0 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::ImageData1D> doImage1D(UnsignedInt id, UnsignedInt) override { |
|
if(id == 0) |
|
return Trade::ImageData1D{PixelFormat::RGBA8I, 1, Containers::Array<char>{NoInit, 4}}; |
|
if(id == 1) |
|
return Trade::ImageData1D{PixelFormat::R8I, 4, Containers::Array<char>{NoInit, 4}}; |
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doImage2DCount() const override { return 2; } |
|
Containers::String doImage2DName(UnsignedInt id) override { |
|
return id == 1 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::ImageData2D> doImage2D(UnsignedInt id, UnsignedInt) override { |
|
if(id == 0) |
|
return Trade::ImageData2D{PixelFormat::RGBA8I, {1, 2}, Containers::Array<char>{NoInit, 8}}; |
|
if(id == 1) |
|
return Trade::ImageData2D{PixelFormat::R8I, {4, 1}, Containers::Array<char>{NoInit, 4}}; |
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
UnsignedInt doImage3DCount() const override { return 2; } |
|
Containers::String doImage3DName(UnsignedInt id) override { |
|
return id == 0 ? "Not referenced" : ""; |
|
} |
|
Containers::Optional<Trade::ImageData3D> doImage3D(UnsignedInt id, UnsignedInt) override { |
|
if(id == 0) |
|
return Trade::ImageData3D{PixelFormat::RGBA8I, {1, 2, 1}, Containers::Array<char>{NoInit, 8}}; |
|
if(id == 1) |
|
return Trade::ImageData3D{PixelFormat::R8I, {4, 1, 1}, Containers::Array<char>{NoInit, 4}}; |
|
CORRADE_INTERNAL_ASSERT_UNREACHABLE(); |
|
} |
|
|
|
struct { |
|
UnsignedInt mapping[4]; |
|
UnsignedInt meshes[4]; |
|
Int materials[4]; |
|
UnsignedInt lights[4]; |
|
UnsignedInt cameras[4]; |
|
UnsignedInt skins[4]; |
|
} sceneData3D[1]{{ |
|
{0, 1, 1, 25}, |
|
{2, 0, 2, 67}, |
|
{0, 1, 23, 0}, |
|
{0, 17, 0, 2}, |
|
{166, 1, 2, 1}, |
|
{1, 1, 22, 2} |
|
}}; |
|
|
|
struct { |
|
UnsignedInt mapping[3]; |
|
UnsignedInt meshes[3]; |
|
UnsignedInt skins[3]; |
|
} sceneData2D[1]{{ |
|
{3, 116, 1}, |
|
{2, 0, 23}, |
|
{177, 0, 1} |
|
}}; |
|
} importer; |
|
|
|
const char* argv[]{"", "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
/* Print to visually verify coloring */ |
|
{ |
|
Debug{} << "======================== visual color verification start ======================="; |
|
Implementation::printInfo(Debug::isTty() ? Debug::Flags{} : Debug::Flag::DisableColors, Debug::isTty(), _infoArgs, importer, time); |
|
Debug{} << "======================== visual color verification end ========================="; |
|
} |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, false, _infoArgs, importer, time) == false); |
|
CORRADE_COMPARE_AS(out.str(), |
|
Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/info-references.txt"), |
|
TestSuite::Compare::StringToFile); |
|
} |
|
|
|
void SceneConverterTest::infoImplementationError() { |
|
struct Importer: Trade::AbstractImporter { |
|
Trade::ImporterFeatures doFeatures() const override { return {}; } |
|
bool doIsOpened() const override { return true; } |
|
void doClose() override {} |
|
|
|
/* The one single object is named, and that name should be printed |
|
after all error messages */ |
|
UnsignedLong doObjectCount() const override { return 1; } |
|
Containers::String doObjectName(UnsignedLong) override { return "A name"; } |
|
|
|
UnsignedInt doSceneCount() const override { return 2; } |
|
Containers::Optional<Trade::SceneData> doScene(UnsignedInt id) override { |
|
Error{} << "Scene" << id << "error!"; |
|
return {}; |
|
} |
|
|
|
UnsignedInt doAnimationCount() const override { return 2; } |
|
Containers::Optional<Trade::AnimationData> doAnimation(UnsignedInt id) override { |
|
Error{} << "Animation" << id << "error!"; |
|
return {}; |
|
} |
|
|
|
UnsignedInt doSkin2DCount() const override { return 2; } |
|
Containers::Optional<Trade::SkinData2D> doSkin2D(UnsignedInt id) override { |
|
Error{} << "2D skin" << id << "error!"; |
|
return {}; |
|
} |
|
|
|
UnsignedInt doSkin3DCount() const override { return 2; } |
|
Containers::Optional<Trade::SkinData3D> doSkin3D(UnsignedInt id) override { |
|
Error{} << "3D skin" << id << "error!"; |
|
return {}; |
|
} |
|
|
|
UnsignedInt doLightCount() const override { return 2; } |
|
Containers::Optional<Trade::LightData> doLight(UnsignedInt id) override { |
|
Error{} << "Light" << id << "error!"; |
|
return {}; |
|
} |
|
|
|
UnsignedInt doCameraCount() const override { return 2; } |
|
Containers::Optional<Trade::CameraData> doCamera(UnsignedInt id) override { |
|
Error{} << "Camera" << id << "error!"; |
|
return {}; |
|
} |
|
|
|
UnsignedInt doMaterialCount() const override { return 2; } |
|
Containers::Optional<Trade::MaterialData> doMaterial(UnsignedInt id) override { |
|
Error{} << "Material" << id << "error!"; |
|
return {}; |
|
} |
|
|
|
UnsignedInt doMeshCount() const override { return 2; } |
|
Containers::Optional<Trade::MeshData> doMesh(UnsignedInt id, UnsignedInt) override { |
|
Error{} << "Mesh" << id << "error!"; |
|
return {}; |
|
} |
|
|
|
UnsignedInt doTextureCount() const override { return 2; } |
|
Containers::Optional<Trade::TextureData> doTexture(UnsignedInt id) override { |
|
Error{} << "Texture" << id << "error!"; |
|
return {}; |
|
} |
|
|
|
/* Errors for all image types tested in ImageConverterTest */ |
|
UnsignedInt doImage2DCount() const override { return 2; } |
|
Containers::Optional<Trade::ImageData2D> doImage2D(UnsignedInt id, UnsignedInt) override { |
|
Error{} << "Image" << id << "error!"; |
|
return {}; |
|
} |
|
} importer; |
|
|
|
const char* argv[]{"", "--info"}; |
|
CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); |
|
|
|
std::chrono::high_resolution_clock::duration time; |
|
|
|
std::ostringstream out; |
|
Debug redirectOutput{&out}; |
|
Error redirectError{&out}; |
|
/* It should return a failure */ |
|
CORRADE_VERIFY(Implementation::printInfo(Debug::Flag::DisableColors, {}, _infoArgs, importer, time) == true); |
|
CORRADE_COMPARE(out.str(), |
|
/* It should not exit after first error... */ |
|
"Scene 0 error!\n" |
|
"Scene 1 error!\n" |
|
"Animation 0 error!\n" |
|
"Animation 1 error!\n" |
|
"2D skin 0 error!\n" |
|
"2D skin 1 error!\n" |
|
"3D skin 0 error!\n" |
|
"3D skin 1 error!\n" |
|
"Light 0 error!\n" |
|
"Light 1 error!\n" |
|
"Camera 0 error!\n" |
|
"Camera 1 error!\n" |
|
"Material 0 error!\n" |
|
"Material 1 error!\n" |
|
"Mesh 0 error!\n" |
|
"Mesh 1 error!\n" |
|
"Texture 0 error!\n" |
|
"Texture 1 error!\n" |
|
"Image 0 error!\n" |
|
"Image 1 error!\n" |
|
/* ... and it should print all info output after the errors */ |
|
"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, data.args); |
|
|
|
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); |
|
if(data.expected2) CORRADE_COMPARE_AS(Utility::Path::join({SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles", data.expected2}), |
|
Utility::Path::join({SCENETOOLS_TEST_DIR, "SceneConverterTestFiles", data.expected2}), |
|
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)
|
|
|