diff --git a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp index 5850ad472..62c7420e6 100644 --- a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp +++ b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.cpp @@ -81,6 +81,34 @@ void AnySceneImporter::doOpenFile(const Containers::StringView filename) { extensions as well. But we can lowercase just the filename, at least. */ const Containers::String normalized = Utility::String::lowercase(Utility::Path::filename(filename)); + /* Some extensions supported by AssimpImporter are deliberately not + recognized due to being overly generic, conflicting, or too obscure. In particular: + + - `*.mdl`, used by both Quake I and "3D GameStudio (3DGS)" + - `*.md2`, `*.md3`, `*.pk3`, `*.md5*` used by Quake II and III and + Doom 3, not recognized because Quake I isn't recognized either + - `*.mesh`, which is OGRE, Meshwork and likely other formats too + http://justsolve.archiveteam.org/wiki/Meshwork_model + https://file.org/extension/mesh + - `*.nff`, which is both "Neutral File Format" and + "Sense8 WorldToolKit" + - `*.off`, which is "Object File Format", likely a variant of the + above, feels rather obscure + - `*.ndo`, which is "Izware Nendo", feels rather obscure + - `*.raw`, which can be PovRAY Raw, but also raw image data or just + anything. Especially problematic when e.g. magnum-player first + tries to open a file as a scene and if that fails, falls back to + opening an image. + - `*.xml`, which can be an OGRE XML mesh but also COLLADA. Ogre XML + is recognized as `*.mesh.xml` instead. + - `*.ter`, which is Terragen Terrain. I couldn't find any file that + would load with Assimp, the only `terrain.ter` I found is an + OBJ-like text file for which Assimp complains that "Magic string + 'TERRAGEN' not found". + + The conflicting extensions are explicitly tested in AnySceneImporterTest + to ensure they're not added by accident. */ + /* Detect the plugin from extension */ Containers::StringView plugin; if(normalized.hasSuffix(".3ds"_s) || @@ -135,6 +163,7 @@ void AnySceneImporter::doOpenFile(const Containers::StringView filename) { else if(normalized.hasSuffix(".stl"_s)) plugin = "StlImporter"_s; else if(normalized.hasSuffix(".cob"_s) || + /** @todo isn't *.scn also too generic? */ normalized.hasSuffix(".scn"_s)) plugin = "TrueSpaceImporter"_s; else if(normalized.hasSuffix(".3d"_s)) diff --git a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.h b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.h index 2a7a8c9e7..739dd7988 100644 --- a/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.h +++ b/src/MagnumPlugins/AnySceneImporter/AnySceneImporter.h @@ -85,7 +85,9 @@ tries to open the file with it. Supported formats: - Wavefront OBJ (`*.obj`), loaded with @ref ObjImporter or any other plugin that provides it - OGRE XML (`*.mesh.xml`), loaded with any plugin that provides - `OgreImporter` + `OgreImporter`. The `*.mesh` extension isn't recognized because it's used + by [Meshwork](http://justsolve.archiveteam.org/wiki/Meshwork_model) as + well. - OpenGEX (`*.ogex`), loaded with @ref OpenGexImporter or any other plugin that provides it - Stanford (`*.ply`), loaded with @ref StanfordImporter or any other plugin @@ -99,6 +101,14 @@ tries to open the file with it. Supported formats: `ValveImporter` - XGL (`*.xgl`, `*.zgl`), loaded with any plugin that provides `XglImporter` +@note + Note that this list is not exhaustive, in particular the + @ref AssimpImporter lists many more file extensions. Not all can be + supported by this plugin because they're either very generic or used by + multiple different formats, such as `*.mdl` used for both Quake I and 3D + GameStudio. If file opening fails with this plugin, you can try directly + with a concrete plugin such as the @ref AssimpImporter as a fallback. + Only loading from files is supported as the filename is used to detect the format, however @ref ImporterFeature::FileCallback is supported as well. diff --git a/src/MagnumPlugins/AnySceneImporter/Test/AnySceneImporterTest.cpp b/src/MagnumPlugins/AnySceneImporter/Test/AnySceneImporterTest.cpp index 18e64916d..50fd26d9f 100644 --- a/src/MagnumPlugins/AnySceneImporter/Test/AnySceneImporterTest.cpp +++ b/src/MagnumPlugins/AnySceneImporter/Test/AnySceneImporterTest.cpp @@ -65,6 +65,7 @@ struct AnySceneImporterTest: TestSuite::Tester { void load(); void detect(); + void reject(); void unknown(); @@ -159,6 +160,22 @@ const struct { {"XGL compressed", "thingy.zgl", "XglImporter"}, }; +const struct { + const char* name; + const char* filename; +} RejectData[]{ + /* This lists pairs of filenames where, just based on extension, any + detection cannot be done */ + {"COLLADA with a *.xml extension", "collada.xml"}, + {"OGRE XML with just a *.xml extension", "mesh.xml"}, + {"OGRE *.mesh", "ogre.mesh"}, + {"Meshwork *.mesh", "foo.mesh"}, + {"OBJ-like *.ter file", "terrain.ter"}, + {"Terragen *.ter", "terragen.ter"}, + {"Quake 1 *.mdl", "quake.mdl"}, + {"3D Game Studio (3DGS) *.mdl", "3dgs.mdl"}, +}; + const struct { const char* name; ImporterFlags flags; @@ -175,6 +192,9 @@ AnySceneImporterTest::AnySceneImporterTest() { addInstancedTests({&AnySceneImporterTest::detect}, Containers::arraySize(DetectData)); + addInstancedTests({&AnySceneImporterTest::reject}, + Containers::arraySize(RejectData)); + addTests({&AnySceneImporterTest::unknown, &AnySceneImporterTest::propagateFlags, @@ -270,6 +290,18 @@ void AnySceneImporterTest::detect() { #endif } +void AnySceneImporterTest::reject() { + auto&& data = RejectData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + Containers::Pointer importer = _manager.instantiate("AnySceneImporter"); + + Containers::String out; + Error redirectError{&out}; + CORRADE_VERIFY(!importer->openFile(data.filename)); + CORRADE_COMPARE(out, Utility::format("Trade::AnySceneImporter::openFile(): cannot determine the format of {}\n", data.filename)); +} + void AnySceneImporterTest::unknown() { Containers::Pointer importer = _manager.instantiate("AnySceneImporter");