|
|
|
|
/*
|
|
|
|
|
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;
|
|
|
|
|
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() {
|
|
|
|
|
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);
|
|
|
|
|
#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)
|