diff --git a/src/Magnum/SceneTools/Test/CMakeLists.txt b/src/Magnum/SceneTools/Test/CMakeLists.txt index 44c69cb92..be7c6c71a 100644 --- a/src/Magnum/SceneTools/Test/CMakeLists.txt +++ b/src/Magnum/SceneTools/Test/CMakeLists.txt @@ -106,6 +106,10 @@ if(CORRADE_TARGET_UNIX AND NOT CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT) SceneConverterTestFiles/broken-scene.gltf SceneConverterTestFiles/dxt1.dds SceneConverterTestFiles/empty.gltf + # Same as blue4x4.png, just named like this to have the file + # roundtrip on conversion + SceneConverterTestFiles/image-passthrough-on-failure.0.png + SceneConverterTestFiles/image-passthrough-on-failure.gltf SceneConverterTestFiles/image-dds.gltf SceneConverterTestFiles/images-2d.gltf SceneConverterTestFiles/images-2d-1x1.bin @@ -125,6 +129,8 @@ if(CORRADE_TARGET_UNIX AND NOT CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT) SceneConverterTestFiles/materials-phong.mtl SceneConverterTestFiles/materials-phong.obj SceneConverterTestFiles/materials-separate-metalness-roughness.mtl + SceneConverterTestFiles/mesh-passthrough-on-failure.bin + SceneConverterTestFiles/mesh-passthrough-on-failure.gltf SceneConverterTestFiles/point.obj SceneConverterTestFiles/quad-duplicates-fuzzy.obj SceneConverterTestFiles/quad-duplicates.obj diff --git a/src/Magnum/SceneTools/Test/SceneConverterTest.cpp b/src/Magnum/SceneTools/Test/SceneConverterTest.cpp index e62da54be..f16189344 100644 --- a/src/Magnum/SceneTools/Test/SceneConverterTest.cpp +++ b/src/Magnum/SceneTools/Test/SceneConverterTest.cpp @@ -594,6 +594,20 @@ const struct { " 65536 -> 65536 shaded pixels\n" " 65536 -> 65536 covered pixels\n" " overdraw 1 -> 1\n"}, + {"mesh converter, passthrough on failure", {InPlaceInit, { + "-M", "MeshOptimizerSceneConverter", + "--passthrough-on-mesh-converter-failure", + /* Removing the generator identifier for a roundtrip */ + "-c", "generator=", + Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/mesh-passthrough-on-failure.gltf"), + Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/mesh-passthrough-on-failure.gltf") + }}, + "GltfImporter", nullptr, "GltfSceneConverter", + {}, "MeshOptimizerSceneConverter", + /* The output is exactly the same as the input */ + "mesh-passthrough-on-failure.gltf", "mesh-passthrough-on-failure.bin", + "Trade::MeshOptimizerSceneConverter::convert(): expected an indexed mesh\n" + "Cannot process mesh 0 with MeshOptimizerSceneConverter, passing the original through\n"}, {"2D image converter, two images", {InPlaceInit, { "-P", "StbResizeImageConverter", "-p", "size=\"1 1\"", /* Removing the generator identifier for a smaller file, bundling @@ -673,6 +687,21 @@ const struct { "Processing 3D image 1 with StbResizeImageConverter...\n" "Trade::AbstractSceneConverter::addImporterContents(): adding texture 0 out of 2\n" "Trade::AbstractSceneConverter::addImporterContents(): adding texture 1 out of 2\n"}, + {"2D image converter, passthrough on failure", {InPlaceInit, { + /* Size explicitly not set to trigger a failure */ + "-P", "StbResizeImageConverter", + "--passthrough-on-image-converter-failure", + /* Removing the generator identifier for a roundtrip */ + "-c", "generator=", + Utility::Path::join(SCENETOOLS_TEST_DIR, "SceneConverterTestFiles/image-passthrough-on-failure.gltf"), + Utility::Path::join(SCENETOOLS_TEST_OUTPUT_DIR, "SceneConverterTestFiles/image-passthrough-on-failure.gltf") + }}, + "GltfImporter", "PngImporter", "GltfSceneConverter", + {"StbResizeImageConverter", "PngImageConverter"}, nullptr, + /* The output is exactly the same as the input */ + "image-passthrough-on-failure.gltf", "image-passthrough-on-failure.0.png", + "Trade::StbResizeImageConverter::convert(): output size was not specified\n" + "Cannot process 2D image 0 with StbResizeImageConverter, passing the original through\n"}, {"Phong to PBR", {InPlaceInit, { "-I", "UfbxImporter", "-C", "GltfSceneConverter", "--phong-to-pbr", /* We need the file as minimal as possible, so no index buffer. diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.0.png b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.0.png new file mode 100644 index 000000000..ef4d8dc40 Binary files /dev/null and b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.0.png differ diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.gltf b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.gltf new file mode 100644 index 000000000..025381baf --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/image-passthrough-on-failure.gltf @@ -0,0 +1,10 @@ +{ + "asset": { + "version": "2.0" + }, + "images": [ + { + "uri": "image-passthrough-on-failure.0.png" + } + ] +} diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin new file mode 100644 index 000000000..3c4403013 Binary files /dev/null and b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin differ diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin.in b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin.in new file mode 100644 index 000000000..7ee23a0a5 --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.bin.in @@ -0,0 +1,16 @@ +type = "3f3f3f 3f3f3f" +input = [ + # 2 3--5 + # |\ \ | + # | \ \| + # 0--1 4 + -1, -1, 0, + 1, -1, 0, + -1, 1, 0, + + -1, 1, 0, + 1, -1, 0, + 1, 1, 0, +] + +# kate: hl python diff --git a/src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.gltf b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.gltf new file mode 100644 index 000000000..f82d3eba0 --- /dev/null +++ b/src/Magnum/SceneTools/Test/SceneConverterTestFiles/mesh-passthrough-on-failure.gltf @@ -0,0 +1,37 @@ +{ + "asset": { + "version": "2.0" + }, + "buffers": [ + { + "uri": "mesh-passthrough-on-failure.bin", + "byteLength": 72 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 72 + } + ], + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 6, + "type": "VEC3" + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "POSITION": 0 + } + } + ] + } + ] +} diff --git a/src/Magnum/SceneTools/sceneconverter.cpp b/src/Magnum/SceneTools/sceneconverter.cpp index a3759a960..13971e8cb 100644 --- a/src/Magnum/SceneTools/sceneconverter.cpp +++ b/src/Magnum/SceneTools/sceneconverter.cpp @@ -186,6 +186,8 @@ magnum-sceneconverter [-h|--help] [-I|--importer PLUGIN] [-c|--converter-options key=val,key2=val2,…]... [-p|--image-converter-options key=val,key2=val2,…]... [-m|--mesh-converter-options key=val,key2=val2,…]... + [--passthrough-on-image-converter-failure] + [--passthrough-on-mesh-converter-failure] [--mesh ID] [--mesh-level INDEX] [--concatenate-meshes] [--info-importer] [--info-converter] [--info-image-converter] [--info-animations] [--info-images] [--info-lights] [--info-cameras] [--info-materials] @@ -228,6 +230,10 @@ Arguments: options to pass to image converter(s) - `-m`, `--mesh-converter-options key=val,key2=val2,…` --- configuration options to pass to mesh converter(s) +- `--passthrough-on-image-converter-failure` --- pass original data through + if `--image-converter` fails +- `--passthrough-on-mesh-converter-failure` --- pass original data through + if `--mesh-converter` fails - `--mesh ID` --- convert just a single mesh instead of the whole scene - `--mesh-level LEVEL` --- level to select for single-mesh conversion - `--concatenate-meshes` --- flatten mesh hierarchy and concatenate them all @@ -335,6 +341,8 @@ bool isDataInfoRequested(const Utility::Arguments& args) { } template bool runImageConverters(PluginManager::Manager& imageConverterManager, const Utility::Arguments& args, const UnsignedInt i, Containers::Optional>& image) { + const bool passthroughOnConversionFailure = args.isSet("passthrough-on-image-converter-failure"); + for(std::size_t j = 0, imageConverterCount = args.arrayValueCount("image-converter"); j != imageConverterCount; ++j) { const Containers::StringView imageConverterName = args.arrayValue("image-converter", j); if(args.isSet("verbose")) { @@ -381,7 +389,11 @@ template bool runImageConverters(PluginManager::Manager< /** @todo handle image levels here, once GltfSceneConverter is capable of converting them (which needs AbstractImageConverter to be reworked around ImageData) */ - if(!(image = imageConverter->convert(*image))) { + if(Containers::Optional> converted = imageConverter->convert(*image)) { + image = std::move(converted); + } else if(passthroughOnConversionFailure) { + Warning{} << "Cannot process" << dimensions << Debug::nospace << "D image" << i << "with" << imageConverterName << Debug::nospace << ", passing the original through"; + } else { Error{} << "Cannot process" << dimensions << Debug::nospace << "D image" << i << "with" << imageConverterName; return false; } @@ -412,6 +424,8 @@ int main(int argc, char** argv) { .addArrayOption('c', "converter-options").setHelp("converter-options", "configuration options to pass to the converter(s)", "key=val,key2=val2,…") .addArrayOption('p', "image-converter-options").setHelp("image-converter-options", "configuration options to pass to the image converter(s)", "key=val,key2=val2,…") .addArrayOption('m', "mesh-converter-options").setHelp("mesh-converter-options", "configuration options to pass to the mesh converter(s)", "key=val,key2=val2,…") + .addBooleanOption("passthrough-on-image-converter-failure").setHelp("passthrough-on-image-converter-failure", "pass original data through if --image-converter fails") + .addBooleanOption("passthrough-on-mesh-converter-failure").setHelp("passthrough-on-mesh-converter-failure", "pass original data through if --mesh-converter fails") .addOption("mesh").setHelp("mesh", "convert just a single mesh instead of the whole scene, ignored if --concatenate-meshes is specified", "ID") .addOption("mesh-level").setHelp("mesh-level", "level to select for single-mesh conversion", "index") .addBooleanOption("concatenate-meshes").setHelp("concatenate-meshes", "flatten mesh hierarchy and concatenate them all together") @@ -879,6 +893,8 @@ well, the IDs reference attributes of the first mesh.)") args.value("remove-duplicate-vertices-fuzzy") || args.arrayValueCount("mesh-converter")) { + const bool passthroughOnConversionFailure = args.isSet("passthrough-on-mesh-converter-failure"); + arrayReserve(meshes, importer->meshCount()); for(UnsignedInt i = 0; i != importer->meshCount(); ++i) { @@ -954,7 +970,11 @@ well, the IDs reference attributes of the first mesh.)") /** @todo handle mesh levels here, once any plugin is capable of converting them */ - if(!(mesh = meshConverter->convert(*mesh))) { + if(Containers::Optional converted = meshConverter->convert(*mesh)) { + mesh = std::move(converted); + } else if(passthroughOnConversionFailure) { + Warning{} << "Cannot process mesh" << i << "with" << meshConverterName << Debug::nospace << ", passing the original through"; + } else { Error{} << "Cannot process mesh" << i << "with" << meshConverterName; return 1; }