diff --git a/doc/changelog.dox b/doc/changelog.dox index 71b134a08..384080f6c 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -667,6 +667,8 @@ See also: `--info-materials`, `--info-meshes`, `--info-skins` and `--info-textures` for printing information just about particular data type, with `--info` being a shortcut for all specified together +- Added a `--object-hierarchy` option to @ref magnum-sceneconverter "magnum-sceneconverter" + that visualizes scene hierarchy in each scene by indenting object info - Added a `--prefer` option to @ref magnum-sceneconverter "magnum-sceneconverter", allowing to specify what plugins should be preferred for particular import and conversion plugin aliases diff --git a/src/Magnum/SceneTools/Implementation/sceneConverterUtilities.h b/src/Magnum/SceneTools/Implementation/sceneConverterUtilities.h index a411659fb..b3d8955b6 100644 --- a/src/Magnum/SceneTools/Implementation/sceneConverterUtilities.h +++ b/src/Magnum/SceneTools/Implementation/sceneConverterUtilities.h @@ -33,6 +33,7 @@ #include #include "Magnum/Math/FunctionsBatch.h" +#include "Magnum/SceneTools/Hierarchy.h" #include "Magnum/Trade/AbstractSceneConverter.h" #include "Magnum/Trade/AnimationData.h" #include "Magnum/Trade/CameraData.h" @@ -157,6 +158,8 @@ bool printInfo(const Debug::Flags useColor, const bool useColor24, const Utility std::size_t dataSize; Trade::DataFlags dataFlags; Containers::String name; + /* Populated only if --object-hierarchy is set */ + Containers::Array> childrenDepthFirst; }; struct ObjectInfo { @@ -198,13 +201,15 @@ bool printInfo(const Debug::Flags useColor, const bool useColor24, const Utility Containers::Array meshReferenceCount; Containers::Array skin2DReferenceCount; Containers::Array skin3DReferenceCount; - if((args.isSet("info") || args.isSet("info-scenes")) && importer.sceneCount()) { - materialReferenceCount = Containers::Array{importer.materialCount()}; - lightReferenceCount = Containers::Array{importer.lightCount()}; - cameraReferenceCount = Containers::Array{importer.cameraCount()}; - meshReferenceCount = Containers::Array{importer.meshCount()}; - skin2DReferenceCount = Containers::Array{importer.skin2DCount()}; - skin3DReferenceCount = Containers::Array{importer.skin3DCount()}; + if((args.isSet("info") || args.isSet("info-scenes") || args.isSet("object-hierarchy")) && importer.sceneCount()) { + if(args.isSet("info") || args.isSet("info-scenes")) { + materialReferenceCount = Containers::Array{importer.materialCount()}; + lightReferenceCount = Containers::Array{importer.lightCount()}; + cameraReferenceCount = Containers::Array{importer.cameraCount()}; + meshReferenceCount = Containers::Array{importer.meshCount()}; + skin2DReferenceCount = Containers::Array{importer.skin2DCount()}; + skin3DReferenceCount = Containers::Array{importer.skin3DCount()}; + } for(UnsignedInt i = 0; i != importer.sceneCount(); ++i) { Containers::Optional scene = importer.scene(i); @@ -221,7 +226,7 @@ bool printInfo(const Debug::Flags useColor, const bool useColor24, const Utility info.dataSize = scene->data().size(); info.dataFlags = scene->dataFlags(); info.name = importer.sceneName(i); - for(UnsignedInt j = 0; j != scene->fieldCount(); ++j) { + if(args.isSet("info") || args.isSet("info-scenes")) for(UnsignedInt j = 0; j != scene->fieldCount(); ++j) { const Trade::SceneField name = scene->fieldName(j); if(name == Trade::SceneField::Mesh) for(const Containers::Pair>& meshMaterial: scene->meshesMaterialsAsArray()) { @@ -279,6 +284,9 @@ bool printInfo(const Debug::Flags useColor, const bool useColor24, const Utility } } + if(args.isSet("object-hierarchy") && scene->hasField(Trade::SceneField::Parent)) + info.childrenDepthFirst = SceneTools::childrenDepthFirst(*scene); + arrayAppend(sceneInfos, std::move(info)); } } @@ -603,6 +611,26 @@ bool printInfo(const Debug::Flags useColor, const bool useColor24, const Utility if((args.isSet("info") || args.isSet("info-scenes")) && importer.defaultScene() != -1) Debug{useColor} << Debug::boldColor(Debug::Color::Default) << "Default scene:" << Debug::resetColor << importer.defaultScene(); + const auto printObjectFieldInfo = [&sceneFieldNames](Debug& d, const ObjectInfo& info) { + for(std::size_t i = 0; i != info.fields.size(); ++i) { + if(i) d << Debug::nospace << ","; + const Containers::Pair nameCount = info.fields[i]; + d << Debug::color(Debug::Color::Cyan); + if(Trade::isSceneFieldCustom(nameCount.first())) { + d << "Custom(" << Debug::nospace + << Trade::sceneFieldCustom(nameCount.first()) + << Debug::nospace << ":" << Debug::nospace + << Debug::color(Debug::Color::Yellow) + << sceneFieldNames[sceneFieldCustom(nameCount.first())] + << Debug::nospace + << Debug::color(Debug::Color::Cyan) << ")"; + } else d << Debug::packed << nameCount.first(); + if(nameCount.second() != 1) + d << Debug::nospace << Utility::format("[{}]", nameCount.second()); + d << Debug::resetColor; + } + }; + std::size_t totalSceneDataSize = 0; for(const SceneInfo& info: sceneInfos) { Debug d{useColor}; @@ -620,28 +648,62 @@ bool printInfo(const Debug::Flags useColor, const bool useColor24, const Utility << Debug::resetColor; d << Debug::nospace << ")"; - d << Debug::newline << " Fields:"; - for(const SceneFieldInfo& field: info.fields) { - d << Debug::newline << " " - << Debug::boldColor(Debug::Color::Default); - if(Trade::isSceneFieldCustom(field.name)) { - d << "Custom(" << Debug::nospace - << Trade::sceneFieldCustom(field.name) - << Debug::nospace << ":" << Debug::nospace - << Debug::color(Debug::Color::Yellow) - << sceneFieldNames[sceneFieldCustom(field.name)] - << Debug::nospace - << Debug::boldColor(Debug::Color::Default) << ")"; - } else d << Debug::packed << field.name; + if(info.fields) { + d << Debug::newline << " Fields:"; + for(const SceneFieldInfo& field: info.fields) { + d << Debug::newline << " " + << Debug::boldColor(Debug::Color::Default); + if(Trade::isSceneFieldCustom(field.name)) { + d << "Custom(" << Debug::nospace + << Trade::sceneFieldCustom(field.name) + << Debug::nospace << ":" << Debug::nospace + << Debug::color(Debug::Color::Yellow) + << sceneFieldNames[sceneFieldCustom(field.name)] + << Debug::nospace + << Debug::boldColor(Debug::Color::Default) << ")"; + } else d << Debug::packed << field.name; - d << Debug::color(Debug::Color::Blue) << "@" << Debug::packed << Debug::color(Debug::Color::Cyan) << field.type; - if(field.arraySize) - d << Debug::nospace << Utility::format("[{}]", field.arraySize); - d << Debug::resetColor; - if(field.flags) d << Debug::nospace << "," - << Debug::packed << Debug::color(Debug::Color::Green) - << field.flags << Debug::resetColor; - d << Debug::nospace << "," << field.size << "entries"; + d << Debug::color(Debug::Color::Blue) << "@" << Debug::packed << Debug::color(Debug::Color::Cyan) << field.type; + if(field.arraySize) + d << Debug::nospace << Utility::format("[{}]", field.arraySize); + d << Debug::resetColor; + if(field.flags) d << Debug::nospace << "," + << Debug::packed << Debug::color(Debug::Color::Green) + << field.flags << Debug::resetColor; + d << Debug::nospace << "," << field.size << "entries"; + } + } + + if(args.isSet("object-hierarchy") && objectInfos) { + d << Debug::newline << " Object hierarchy:"; + + Containers::Array childRangeEnds; + arrayAppend(childRangeEnds, info.childrenDepthFirst.size()); + for(std::size_t i = 0; i != info.childrenDepthFirst.size(); ++i) { + while(childRangeEnds.back() == i) + arrayRemoveSuffix(childRangeEnds, 1); + + const UnsignedInt object = info.childrenDepthFirst[i].first(); + const UnsignedInt childCount = info.childrenDepthFirst[i].second(); + const ObjectInfo& objectInfo = objectInfos[object]; + + const Containers::String indent = " "_s*(childRangeEnds.size()); + + d << Debug::newline << indent << Debug::nospace << Debug::boldColor(Debug::Color::Default) << " Object" + << object << Debug::nospace << ":" << Debug::resetColor; + if(objectInfo.name) d << Debug::boldColor(Debug::Color::Yellow) + << objectInfo.name << Debug::resetColor; + + if(objectInfo.fields) { + d << Debug::newline << indent << Debug::nospace << " Fields:"; + printObjectFieldInfo(d, objectInfo); + } + + if(childCount) { + CORRADE_INTERNAL_ASSERT(childRangeEnds.back() > i + 1); + arrayAppend(childRangeEnds, i + childCount + 1); + } + } } totalSceneDataSize += info.dataSize; @@ -649,7 +711,9 @@ bool printInfo(const Debug::Flags useColor, const bool useColor24, const Utility if(!sceneInfos.isEmpty()) Debug{} << "Total scene data size:" << Utility::format("{:.1f}", totalSceneDataSize/1024.0f) << "kB"; - for(const ObjectInfo& info: objectInfos) { + /* If --object-hierarchy was specified, the object list was printed as part + of the scene already */ + if(!args.isSet("object-hierarchy")) for(const ObjectInfo& info: objectInfos) { /* Objects without a name and not referenced by any scenes are useless, ignore */ if(!info.name && !info.scenes) continue; @@ -670,24 +734,7 @@ bool printInfo(const Debug::Flags useColor, const bool useColor24, const Utility << info.name << Debug::resetColor; if(info.scenes) { d << Debug::newline << " Fields:"; - - for(std::size_t i = 0; i != info.fields.size(); ++i) { - if(i) d << Debug::nospace << ","; - const Containers::Pair nameCount = info.fields[i]; - d << Debug::color(Debug::Color::Cyan); - if(Trade::isSceneFieldCustom(nameCount.first())) { - d << "Custom(" << Debug::nospace - << Trade::sceneFieldCustom(nameCount.first()) - << Debug::nospace << ":" << Debug::nospace - << Debug::color(Debug::Color::Yellow) - << sceneFieldNames[sceneFieldCustom(nameCount.first())] - << Debug::nospace - << Debug::color(Debug::Color::Cyan) << ")"; - } else d << Debug::packed << nameCount.first(); - if(nameCount.second() != 1) - d << Debug::nospace << Utility::format("[{}]", nameCount.second()); - d << Debug::resetColor; - } + printObjectFieldInfo(d, info); } } diff --git a/src/Magnum/SceneTools/Test/CMakeLists.txt b/src/Magnum/SceneTools/Test/CMakeLists.txt index c5cbc5318..b2ee46743 100644 --- a/src/Magnum/SceneTools/Test/CMakeLists.txt +++ b/src/Magnum/SceneTools/Test/CMakeLists.txt @@ -67,6 +67,10 @@ corrade_add_test(SceneToolsSceneConverterImple___Test SceneConverterImplementati SceneConverterImplementationTestFiles/info-meshes-bounds.txt SceneConverterImplementationTestFiles/info-meshes.txt SceneConverterImplementationTestFiles/info-objects.txt + SceneConverterImplementationTestFiles/info-object-hierarchy.txt + SceneConverterImplementationTestFiles/info-object-hierarchy-no-parents.txt + SceneConverterImplementationTestFiles/info-object-hierarchy-only-objects.txt + SceneConverterImplementationTestFiles/info-object-hierarchy-only-objects-no-parents.txt SceneConverterImplementationTestFiles/info-references.txt SceneConverterImplementationTestFiles/info-scenes.txt SceneConverterImplementationTestFiles/info-scenes-no-default.txt diff --git a/src/Magnum/SceneTools/Test/SceneConverterImplementationTest.cpp b/src/Magnum/SceneTools/Test/SceneConverterImplementationTest.cpp index 3c605a3c5..fc1f4b90d 100644 --- a/src/Magnum/SceneTools/Test/SceneConverterImplementationTest.cpp +++ b/src/Magnum/SceneTools/Test/SceneConverterImplementationTest.cpp @@ -76,15 +76,47 @@ using namespace Math::Literals; const struct { const char* name; - const char* arg; + Containers::Array args; const char* expected; Int defaultScene; bool printVisualCheck; + bool omitParent; } InfoScenesObjectsData[]{ - {"", "--info", "info-scenes-objects.txt", 1, true}, - {"only scenes", "--info-scenes", "info-scenes.txt", 0, false}, - {"only scenes, no default scene", "--info-scenes", "info-scenes-no-default.txt", -1, false}, - {"only objects", "--info-objects", "info-objects.txt", 1, false} + {"all", {InPlaceInit, { + "", "--info" + }}, "info-scenes-objects.txt", 1, true, false}, + {"both", {InPlaceInit, { + "", "--info-objects", "--info-scenes" + }}, "info-scenes-objects.txt", 1, false, false}, + {"only scenes", {InPlaceInit, { + "", "--info-scenes" + }}, "info-scenes.txt", 0, false, false}, + {"only scenes, no default scene", {InPlaceInit, { + "", "--info-scenes" + }}, "info-scenes-no-default.txt", -1, false, false}, + {"only objects", {InPlaceInit, { + "", "--info-objects" + }}, "info-objects.txt", 1, false, false}, + {"object hierarchy, all", {InPlaceInit, { + "", "--info", "--object-hierarchy" + }}, "info-object-hierarchy.txt", -1, true, false}, + {"object hierarchy, both", {InPlaceInit, { + "", "--info-objects", "--info-scenes", "--object-hierarchy" + }}, "info-object-hierarchy.txt", -1, false, false}, + {"object hierarchy, no parents", {InPlaceInit, { + "", "--info", "--object-hierarchy" + }}, "info-object-hierarchy-no-parents.txt", -1, false, true}, + {"object hierarchy, only scenes", {InPlaceInit, { + /* --object-hierarchy is only used if --info-objects is present + so this is the same as just --info-scenes alone */ + "", "--info-scenes", "--object-hierarchy" + }}, "info-scenes-no-default.txt", -1, false, false}, + {"object hierarchy, only objects", {InPlaceInit, { + "", "--info-objects", "--object-hierarchy" + }}, "info-object-hierarchy-only-objects.txt", -1, true, false}, + {"object hierarchy, only objects, no parents", {InPlaceInit, { + "", "--info-objects", "--object-hierarchy" + }}, "info-object-hierarchy-only-objects-no-parents.txt", -1, false, true}, }; const struct { @@ -133,7 +165,8 @@ SceneConverterImplementationTest::SceneConverterImplementationTest() { .addBooleanOption("info-meshes") .addBooleanOption("info-textures") .addBooleanOption("info-images") - .addBooleanOption("bounds"); + .addBooleanOption("bounds") + .addBooleanOption("object-hierarchy"); /* Load the plugin directly from the build tree. Otherwise it's static and already loaded. */ @@ -200,7 +233,7 @@ void SceneConverterImplementationTest::infoScenesObjects() { setTestCaseDescription(data.name); struct Importer: Trade::AbstractImporter { - explicit Importer(Int defaultScene): _defaultScene{defaultScene} {} + explicit Importer(Int defaultScene, bool omitParent): _defaultScene{defaultScene}, _omitParent{omitParent} {} Trade::ImporterFeatures doFeatures() const override { return {}; } bool doIsOpened() const override { return true; } @@ -236,24 +269,27 @@ void SceneConverterImplementationTest::infoScenesObjects() { Containers::ArrayView meshMapping; Containers::ArrayView meshes; Containers::ArrayTuple data{ - {NoInit, 3, parentMapping}, - {ValueInit, 3, parents}, + {NoInit, 5, parentMapping}, + {NoInit, 5, parents}, {NoInit, 4, meshMapping}, {ValueInit, 4, meshes}, }; - Utility::copy({1, 3, 2}, parentMapping); + Utility::copy({1, 2, 5, 4, 0}, parentMapping); + Utility::copy({2, -1, 1, 2, 5}, parents); 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}, + /* No need to fill the other data, zero-init is fine */ + return Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 6, std::move(data), { + Trade::SceneFieldData{_omitParent ? Trade::sceneFieldCustom(0) : 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. */ + /* Two custom fields, one array, parent. 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{_omitParent ? Trade::sceneFieldCustom(0) : Trade::SceneField::Parent, Containers::arrayView(scene2Data->parentCustomMapping), Containers::arrayView(scene2Data->parent)}, + Trade::SceneFieldData{Trade::sceneFieldCustom(42), Containers::arrayView(scene2Data->parentCustomMapping), Containers::arrayView(scene2Data->custom)}, Trade::SceneFieldData{Trade::sceneFieldCustom(1337), Trade::SceneMappingType::UnsignedByte, scene2Data->customArrayMapping, Trade::SceneFieldType::Short, scene2Data->customArray, 3}, }}; } @@ -262,20 +298,21 @@ void SceneConverterImplementationTest::infoScenesObjects() { } struct { - UnsignedByte customMapping[2]; + UnsignedByte parentCustomMapping[2]; + Int parent[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}, {} + /* No need to fill data other than parents, zero-init is fine */ + {7, 3}, {3, -1}, {}, {2, 4, 4}, {} }}; Int _defaultScene; - } importer{data.defaultScene}; + bool _omitParent; + } importer{data.defaultScene, data.omitParent}; - const char* argv[]{"", data.arg}; - CORRADE_VERIFY(_infoArgs.tryParse(Containers::arraySize(argv), argv)); + CORRADE_VERIFY(_infoArgs.tryParse(data.args.size(), data.args)); std::chrono::high_resolution_clock::duration time; diff --git a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy-no-parents.txt b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy-no-parents.txt new file mode 100644 index 000000000..245f5b4cc --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy-no-parents.txt @@ -0,0 +1,14 @@ +Scene 0: A simple scene + Bound: 6 objects @ UnsignedInt (0.1 kB) + Fields: + Custom(0:) @ Int, 5 entries + Mesh @ UnsignedInt, OrderedMapping, 4 entries + Object hierarchy: +Scene 1: + Bound: 8 objects @ UnsignedByte (0.1 kB, ExternallyOwned|Mutable) + Fields: + Custom(0:) @ Int, 2 entries + Custom(42:) @ Double, 2 entries + Custom(1337:directionVector) @ Short[3], 3 entries + Object hierarchy: +Total scene data size: 0.1 kB diff --git a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy-only-objects-no-parents.txt b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy-only-objects-no-parents.txt new file mode 100644 index 000000000..e0329f90e --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy-only-objects-no-parents.txt @@ -0,0 +1,7 @@ +Scene 0: A simple scene + Bound: 6 objects @ UnsignedInt (0.1 kB) + Object hierarchy: +Scene 1: + Bound: 8 objects @ UnsignedByte (0.1 kB, ExternallyOwned|Mutable) + Object hierarchy: +Total scene data size: 0.1 kB diff --git a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy-only-objects.txt b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy-only-objects.txt new file mode 100644 index 000000000..6a073fb02 --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy-only-objects.txt @@ -0,0 +1,14 @@ +Scene 0: A simple scene + Bound: 6 objects @ UnsignedInt (0.1 kB) + Object hierarchy: + Object 2: Two meshes, shared among two scenes + Object 1: + Object 5: + Object 0: Parent-less mesh + Object 4: Two custom arrays +Scene 1: + Bound: 8 objects @ UnsignedByte (0.1 kB, ExternallyOwned|Mutable) + Object hierarchy: + Object 3: + Object 7: +Total scene data size: 0.1 kB diff --git a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy.txt b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy.txt new file mode 100644 index 000000000..4eb638ca3 --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-object-hierarchy.txt @@ -0,0 +1,28 @@ +Scene 0: A simple scene + Bound: 6 objects @ UnsignedInt (0.1 kB) + Fields: + Parent @ Int, 5 entries + Mesh @ UnsignedInt, OrderedMapping, 4 entries + Object hierarchy: + Object 2: Two meshes, shared among two scenes + Fields: Parent, Mesh[2], Custom(1337:directionVector) + Object 1: + Fields: Parent, Mesh + Object 5: + Fields: Parent + Object 0: Parent-less mesh + Fields: Parent, Mesh + Object 4: Two custom arrays + Fields: Parent, Custom(1337:directionVector)[2] +Scene 1: + Bound: 8 objects @ UnsignedByte (0.1 kB, ExternallyOwned|Mutable) + Fields: + Parent @ Int, 2 entries + Custom(42:) @ Double, 2 entries + Custom(1337:directionVector) @ Short[3], 3 entries + Object hierarchy: + Object 3: + Fields: Parent, Custom(42:) + Object 7: + Fields: Parent, Custom(42:) +Total scene data size: 0.1 kB diff --git a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes-no-default.txt b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes-no-default.txt index 5410f9833..66153f59e 100644 --- a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes-no-default.txt +++ b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes-no-default.txt @@ -1,11 +1,12 @@ Scene 0: A simple scene - Bound: 4 objects @ UnsignedInt (0.1 kB) + Bound: 6 objects @ UnsignedInt (0.1 kB) Fields: - Parent @ Int, 3 entries + Parent @ Int, 5 entries Mesh @ UnsignedInt, OrderedMapping, 4 entries Scene 1: - Bound: 8 objects @ UnsignedByte (0.0 kB, ExternallyOwned|Mutable) + Bound: 8 objects @ UnsignedByte (0.1 kB, ExternallyOwned|Mutable) Fields: + Parent @ Int, 2 entries Custom(42:) @ Double, 2 entries Custom(1337:directionVector) @ Short[3], 3 entries Total scene data size: 0.1 kB diff --git a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes-objects.txt b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes-objects.txt index 462e0544a..d12f81152 100644 --- a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes-objects.txt +++ b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes-objects.txt @@ -1,26 +1,29 @@ Default scene: 1 Scene 0: A simple scene - Bound: 4 objects @ UnsignedInt (0.1 kB) + Bound: 6 objects @ UnsignedInt (0.1 kB) Fields: - Parent @ Int, 3 entries + Parent @ Int, 5 entries Mesh @ UnsignedInt, OrderedMapping, 4 entries Scene 1: - Bound: 8 objects @ UnsignedByte (0.0 kB, ExternallyOwned|Mutable) + Bound: 8 objects @ UnsignedByte (0.1 kB, ExternallyOwned|Mutable) Fields: + Parent @ Int, 2 entries Custom(42:) @ Double, 2 entries Custom(1337:directionVector) @ Short[3], 3 entries Total scene data size: 0.1 kB Object 0 (referenced by 1 scenes): Parent-less mesh - Fields: Mesh + Fields: Parent, Mesh Object 1 (referenced by 1 scenes): Fields: Parent, Mesh Object 2 (referenced by 2 scenes): Two meshes, shared among two scenes Fields: Parent, Mesh[2], Custom(1337:directionVector) -Object 3 (referenced by 2 scenes): +Object 3 (referenced by 1 scenes): Fields: Parent, Custom(42:) -Object 4 (referenced by 1 scenes): Two custom arrays - Fields: Custom(1337:directionVector)[2] +Object 4 (referenced by 2 scenes): Two custom arrays + Fields: Parent, Custom(1337:directionVector)[2] +Object 5 (referenced by 1 scenes): + Fields: Parent Object 6 (referenced by 0 scenes): Only in the second scene, but no fields, thus same as unreferenced Object 7 (referenced by 1 scenes): - Fields: Custom(42:) + Fields: Parent, Custom(42:) Object 8 (referenced by 0 scenes): Not in any scene diff --git a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes.txt b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes.txt index 2fab1ae80..9339540cf 100644 --- a/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes.txt +++ b/src/Magnum/SceneTools/Test/SceneConverterImplementationTestFiles/info-scenes.txt @@ -1,12 +1,13 @@ Default scene: 0 Scene 0: A simple scene - Bound: 4 objects @ UnsignedInt (0.1 kB) + Bound: 6 objects @ UnsignedInt (0.1 kB) Fields: - Parent @ Int, 3 entries + Parent @ Int, 5 entries Mesh @ UnsignedInt, OrderedMapping, 4 entries Scene 1: - Bound: 8 objects @ UnsignedByte (0.0 kB, ExternallyOwned|Mutable) + Bound: 8 objects @ UnsignedByte (0.1 kB, ExternallyOwned|Mutable) Fields: + Parent @ Int, 2 entries Custom(42:) @ Double, 2 entries Custom(1337:directionVector) @ Short[3], 3 entries Total scene data size: 0.1 kB diff --git a/src/Magnum/SceneTools/sceneconverter.cpp b/src/Magnum/SceneTools/sceneconverter.cpp index 904824890..4c41fae4f 100644 --- a/src/Magnum/SceneTools/sceneconverter.cpp +++ b/src/Magnum/SceneTools/sceneconverter.cpp @@ -194,7 +194,7 @@ magnum-sceneconverter [-h|--help] [-I|--importer PLUGIN] [--info-images] [--info-lights] [--info-cameras] [--info-materials] [--info-meshes] [--info-objects] [--info-scenes] [--info-skins] [--info-textures] [--info] [--color on|4bit|off|auto] [--bounds] - [-v|--verbose] [--profile] [--] input output + [--object-hierarchy] [-v|--verbose] [--profile] [--] input output @endcode Arguments: @@ -263,6 +263,7 @@ Arguments: as specifying all other data-related `--info-*` options together - `--color` --- colored output for `--info` (default: `auto`) - `--bounds` --- show bounds of known attributes in `--info` output +- `--object-hierarchy` --- visualize object hierarchy in `--info` output - `-v`, `--verbose` --- verbose output from importer and converter plugins - `--profile` --- measure import and conversion time @@ -451,6 +452,7 @@ int main(int argc, char** argv) { .addBooleanOption("info").setHelp("info", "print info about everything in the input file and exit, same as specifying all other data-related --info-* options together") .addOption("color", "auto").setHelp("color", "colored output for --info", "on|4bit|off|auto") .addBooleanOption("bounds").setHelp("bounds", "show bounds of known attributes in --info output") + .addBooleanOption("object-hierarchy").setHelp("object-hierarchy", "visualize object hierarchy in --info output") .addBooleanOption('v', "verbose").setHelp("verbose", "verbose output from importer and converter plugins") .addBooleanOption("profile").setHelp("profile", "measure import and conversion time") .setParseErrorCallback([](const Utility::Arguments& args, Utility::Arguments::ParseError error, const std::string& key) {