diff --git a/src/Magnum/Trade/sceneconverter.cpp b/src/Magnum/Trade/sceneconverter.cpp index 431d93fb3f..c4ddce3c44 100644 --- a/src/Magnum/Trade/sceneconverter.cpp +++ b/src/Magnum/Trade/sceneconverter.cpp @@ -118,6 +118,38 @@ struct Duration { std::chrono::high_resolution_clock::time_point _t; }; +/* Direct shims for fast deserialization / serialization of blob data. Compared + to MagnumImporter / MagnumSceneConverter these don't make the whole file + resident in memory, so *much* faster. */ +class BlobImporter: public Trade::AbstractImporter { + Trade::ImporterFeatures doFeatures() const override { return {}; } + + bool doIsOpened() const override { return _in; } + void doClose() override { _in = nullptr; } + void doOpenFile(const std::string& filename) override { + _in = Utility::Directory::mapRead(filename); + } + + UnsignedInt doMeshCount() const override { return 1; } + Containers::Optional doMesh(UnsignedInt, UnsignedInt) override { + return Trade::MeshData::deserialize(_in); + } + + Containers::Array _in; +}; + +class BlobSceneConverter: public Trade::AbstractSceneConverter { + Trade::SceneConverterFeatures doFeatures() const override { + return Trade::SceneConverterFeature::ConvertMeshToFile; + } + + bool doConvertToFile(const std::string& filename, const Magnum::Trade::MeshData& mesh) override { + Containers::Array out = Utility::Directory::mapWrite(filename, mesh.serializedSize()); + mesh.serializeInto(out); + return out.size(); + } +}; + } int main(int argc, char** argv) { @@ -151,20 +183,28 @@ plugin configuration. If the = character is omitted, it's equivalent to saying key=true; configuration subgroups are delimited with /.)") .parse(argc, argv); - PluginManager::Manager importerManager{ - args.value("plugin-dir").empty() ? std::string{} : - Utility::Directory::join(args.value("plugin-dir"), Trade::AbstractImporter::pluginSearchPaths()[0])}; + /* Load importer plugin, or use the blob shim in case the extension + matches and we're not overriding the converter to something specific */ + Containers::Optional> importerManager; + Containers::Pointer importer; + if(Utility::String::endsWith(args.value("input"), ".blob") && args.value("importer") == "AnySceneImporter") { + importer.reset(new BlobImporter); + if(!args.value("importer-options").empty()) + Warning{} << "Importer options" << args.value("importer-options") << "ignored when loading a blob file"; + } else { + importerManager.emplace( + args.value("plugin-dir").empty() ? std::string{} : + Utility::Directory::join(args.value("plugin-dir"), Trade::AbstractImporter::pluginSearchPaths()[0])); + importer = importerManager->loadAndInstantiate(args.value("importer")); + if(!importer) { + Debug{} << "Available importer plugins:" << Utility::String::join(importerManager->aliasList(), ", "); + return 1; + } - Containers::Pointer importer = importerManager.loadAndInstantiate(args.value("importer")); - if(!importer) { - Debug{} << "Available importer plugins:" << Utility::String::join(importerManager.aliasList(), ", "); - return 1; + if(args.isSet("verbose")) importer->setFlags(Trade::ImporterFlag::Verbose); + Trade::Implementation::setOptions(*importer, args.value("importer-options")); } - /* Set options, if passed */ - if(args.isSet("verbose")) importer->setFlags(Trade::ImporterFlag::Verbose); - Trade::Implementation::setOptions(*importer, args.value("importer-options")); - std::chrono::high_resolution_clock::duration importTime; /* Open the file */ @@ -311,19 +351,27 @@ key=true; configuration subgroups are delimited with /.)") } } - /* Load converter plugin */ - PluginManager::Manager converterManager{ - args.value("plugin-dir").empty() ? std::string{} : - Utility::Directory::join(args.value("plugin-dir"), Trade::AbstractSceneConverter::pluginSearchPaths()[0])}; - Containers::Pointer converter = converterManager.loadAndInstantiate(args.value("converter")); - if(!converter) { - Debug{} << "Available converter plugins:" << Utility::String::join(converterManager.aliasList(), ", "); - return 2; - } + /* Load converter plugin, or use the blob shim in case the extension + matches and we're not overriding the converter to something specific */ + Containers::Optional> converterManager; + Containers::Pointer converter; + if(Utility::String::endsWith(args.value("output"), ".blob") && args.value("converter") == "AnySceneConverter") { + converter.reset(new BlobSceneConverter); + if(!args.value("converter-options").empty()) + Warning{} << "Converter options" << args.value("converter-options") << "ignored when writing a blob file"; + } else { + converterManager.emplace( + args.value("plugin-dir").empty() ? std::string{} : + Utility::Directory::join(args.value("plugin-dir"), Trade::AbstractSceneConverter::pluginSearchPaths()[0])); + converter = converterManager->loadAndInstantiate(args.value("converter")); + if(!converter) { + Debug{} << "Available converter plugins:" << Utility::String::join(converterManager->aliasList(), ", "); + return 2; + } - /* Set options, if passed */ - if(args.isSet("verbose")) converter->setFlags(Trade::SceneConverterFlag::Verbose); - Trade::Implementation::setOptions(*converter, args.value("converter-options")); + if(args.isSet("verbose")) converter->setFlags(Trade::SceneConverterFlag::Verbose); + Trade::Implementation::setOptions(*converter, args.value("converter-options")); + } std::chrono::high_resolution_clock::duration conversionTime;