Explorar el Código

Merge remote-tracking branch 'origin/master' into bensewell-fixifcopening4343

Ben Sewell hace 3 años
padre
commit
3e6fc3a64b
Se han modificado 62 ficheros con 889 adiciones y 663 borrados
  1. 3 14
      code/AssetLib/3DS/3DSLoader.cpp
  2. 5 17
      code/AssetLib/3MF/D3MFImporter.cpp
  3. 3 12
      code/AssetLib/AC/ACLoader.cpp
  4. 3 13
      code/AssetLib/AMF/AMFImporter.cpp
  5. 3 13
      code/AssetLib/ASE/ASELoader.cpp
  6. 2 1
      code/AssetLib/ASE/ASEParser.cpp
  7. 2 2
      code/AssetLib/B3D/B3DImporter.cpp
  8. 3 12
      code/AssetLib/BVH/BVHLoader.cpp
  9. 4 12
      code/AssetLib/Blender/BlenderLoader.cpp
  10. 13 2
      code/AssetLib/C4D/C4DImporter.cpp
  11. 3 11
      code/AssetLib/COB/COBLoader.cpp
  12. 3 12
      code/AssetLib/CSM/CSMLoader.cpp
  13. 7 29
      code/AssetLib/Collada/ColladaLoader.cpp
  14. 30 15
      code/AssetLib/Collada/ColladaParser.cpp
  15. 3 12
      code/AssetLib/DXF/DXFLoader.cpp
  16. 4 12
      code/AssetLib/FBX/FBXImporter.cpp
  17. 7 14
      code/AssetLib/HMP/HMPLoader.cpp
  18. 6 12
      code/AssetLib/IFC/IFCLoader.cpp
  19. 322 0
      code/AssetLib/IQM/IQMImporter.cpp
  20. 78 0
      code/AssetLib/IQM/IQMImporter.h
  21. 134 0
      code/AssetLib/IQM/iqm.h
  22. 3 17
      code/AssetLib/Irr/IRRLoader.cpp
  23. 7 21
      code/AssetLib/Irr/IRRMeshLoader.cpp
  24. 7 15
      code/AssetLib/LWO/LWOLoader.cpp
  25. 6 14
      code/AssetLib/LWS/LWSLoader.cpp
  26. 12 27
      code/AssetLib/M3D/M3DImporter.cpp
  27. 3 12
      code/AssetLib/MD2/MD2Loader.cpp
  28. 3 12
      code/AssetLib/MD3/MD3Loader.cpp
  29. 3 14
      code/AssetLib/MD5/MD5Loader.cpp
  30. 3 13
      code/AssetLib/MDC/MDCLoader.cpp
  31. 12 17
      code/AssetLib/MDL/MDLLoader.cpp
  32. 3 8
      code/AssetLib/MMD/MMDImporter.cpp
  33. 3 17
      code/AssetLib/MS3D/MS3DLoader.cpp
  34. 3 14
      code/AssetLib/NDO/NDOLoader.cpp
  35. 1 3
      code/AssetLib/NFF/NFFLoader.cpp
  36. 3 12
      code/AssetLib/OFF/OFFLoader.cpp
  37. 4 10
      code/AssetLib/Obj/ObjFileImporter.cpp
  38. 3 7
      code/AssetLib/Ogre/OgreImporter.cpp
  39. 3 10
      code/AssetLib/OpenGEX/OpenGEXImporter.cpp
  40. 3 18
      code/AssetLib/Ply/PlyLoader.cpp
  41. 3 4
      code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp
  42. 3 12
      code/AssetLib/Q3D/Q3DLoader.cpp
  43. 2 2
      code/AssetLib/Raw/RawLoader.cpp
  44. 2 5
      code/AssetLib/SIB/SIBImporter.cpp
  45. 11 12
      code/AssetLib/SMD/SMDLoader.cpp
  46. 3 16
      code/AssetLib/STL/STLLoader.cpp
  47. 3 21
      code/AssetLib/Terragen/TerragenLoader.cpp
  48. 9 5
      code/AssetLib/Unreal/UnrealLoader.cpp
  49. 3 11
      code/AssetLib/X/XFileImporter.cpp
  50. 3 19
      code/AssetLib/XGL/XGLLoader.cpp
  51. 6 16
      code/AssetLib/glTF/glTFImporter.cpp
  52. 32 30
      code/AssetLib/glTF2/glTF2Importer.cpp
  53. 1 1
      code/AssetLib/glTF2/glTF2Importer.h
  54. 6 0
      code/CMakeLists.txt
  55. 4 3
      code/Common/BaseImporter.cpp
  56. 58 16
      code/Common/Importer.cpp
  57. 6 0
      code/Common/ImporterRegistry.cpp
  58. 9 14
      include/assimp/BaseImporter.h
  59. 2 0
      include/assimp/defs.h
  60. BIN
      test/models/IQM/Body.jpg
  61. BIN
      test/models/IQM/Head.jpg
  62. BIN
      test/models/IQM/mrfixit.iqm

+ 3 - 14
code/AssetLib/3DS/3DSLoader.cpp

@@ -111,20 +111,9 @@ Discreet3DSImporter::~Discreet3DSImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    std::string extension = GetExtension(pFile);
-    if (extension == "3ds" || extension == "prj") {
-        return true;
-    }
-
-    if (!extension.length() || checkSig) {
-        uint16_t token[3];
-        token[0] = 0x4d4d;
-        token[1] = 0x3dc2;
-        //token[2] = 0x3daa;
-        return CheckMagicToken(pIOHandler, pFile, token, 2, 0, 2);
-    }
-    return false;
+bool Discreet3DSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint16_t token[] = { 0x4d4d, 0x3dc2 /*, 0x3daa */ };
+    return CheckMagicToken(pIOHandler, pFile, token, AI_COUNT_OF(token), 0, sizeof token[0]);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 5 - 17
code/AssetLib/3MF/D3MFImporter.cpp

@@ -90,24 +90,12 @@ D3MFImporter::~D3MFImporter() {
     // empty
     // empty
 }
 }
 
 
-bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension(GetExtension(filename));
-    if (extension == desc.mFileExtensions) {
-        return true;
-    } 
-
-    if (!extension.length() || checkSig) {
-        if (nullptr == pIOHandler) {
-            return false;
-        }
-        if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
-            return false;
-        }
-        D3MFOpcPackage opcPackage(pIOHandler, filename);
-        return opcPackage.validate();
+bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
+        return false;
     }
     }
-
-    return false;
+    D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
+    return opcPackage.validate();
 }
 }
 
 
 void D3MFImporter::SetupProperties(const Importer*) {
 void D3MFImporter::SetupProperties(const Importer*) {

+ 3 - 12
code/AssetLib/AC/ACLoader.cpp

@@ -152,18 +152,9 @@ AC3DImporter::~AC3DImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    std::string extension = GetExtension(pFile);
-
-    // fixme: are acc and ac3d *really* used? Some sources say they are
-    if (extension == "ac" || extension == "ac3d" || extension == "acc") {
-        return true;
-    }
-    if (!extension.length() || checkSig) {
-        uint32_t token = AI_MAKE_MAGIC("AC3D");
-        return CheckMagicToken(pIOHandler, pFile, &token, 1, 0);
-    }
-    return false;
+bool AC3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = { AI_MAKE_MAGIC("AC3D") };
+    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 13
code/AssetLib/AMF/AMFImporter.cpp

@@ -503,19 +503,9 @@ void AMFImporter::ParseNode_Metadata(XmlNode &node) {
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
 
 
-bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "amf") {
-        return true;
-    }
-
-    if (extension.empty() || pCheckSig) {
-        static const char * const tokens[] = { "<amf" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-
-    return false;
+bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*pCheckSig*/) const {
+    static const char *tokens[] = { "<amf" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 const aiImporterDesc *AMFImporter::GetInfo() const {
 const aiImporterDesc *AMFImporter::GetInfo() const {

+ 3 - 13
code/AssetLib/ASE/ASELoader.cpp

@@ -95,19 +95,9 @@ ASEImporter::~ASEImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "ase" || extension == "ask") {
-        return true;
-    }
-
-    if ((!extension.length() || cs) && pIOHandler) {
-        static const char * const tokens[] = { "*3dsmax_asciiexport" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool ASEImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "*3dsmax_asciiexport" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 2 - 1
code/AssetLib/ASE/ASEParser.cpp

@@ -486,8 +486,9 @@ void Parser::ParseLV1MaterialListBlock() {
                 ParseLV4MeshLong(iIndex);
                 ParseLV4MeshLong(iIndex);
 
 
                 if (iIndex >= iMaterialCount) {
                 if (iIndex >= iMaterialCount) {
-                    LogWarning("Out of range: material index is too large");
+                    LogError("Out of range: material index is too large");
                     iIndex = iMaterialCount - 1;
                     iIndex = iMaterialCount - 1;
+                    return;
                 }
                 }
 
 
                 // get a reference to the material
                 // get a reference to the material

+ 2 - 2
code/AssetLib/B3D/B3DImporter.cpp

@@ -81,7 +81,7 @@ static const aiImporterDesc desc = {
 
 
 //#define DEBUG_B3D
 //#define DEBUG_B3D
 
 
-template <typename T>
+template<typename T>
 void DeleteAllBarePointers(std::vector<T> &x) {
 void DeleteAllBarePointers(std::vector<T> &x) {
     for (auto p : x) {
     for (auto p : x) {
         delete p;
         delete p;
@@ -89,11 +89,11 @@ void DeleteAllBarePointers(std::vector<T> &x) {
 }
 }
 
 
 B3DImporter::~B3DImporter() {
 B3DImporter::~B3DImporter() {
+    // empty
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
 bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
-
     size_t pos = pFile.find_last_of('.');
     size_t pos = pFile.find_last_of('.');
     if (pos == string::npos) {
     if (pos == string::npos) {
         return false;
         return false;

+ 3 - 12
code/AssetLib/BVH/BVHLoader.cpp

@@ -92,18 +92,9 @@ BVHLoader::~BVHLoader() {}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "bvh")
-        return true;
-
-    if ((!extension.length() || cs) && pIOHandler) {
-        static const char * const tokens[] = { "HIERARCHY" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "HIERARCHY" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 4 - 12
code/AssetLib/Blender/BlenderLoader.cpp

@@ -114,22 +114,14 @@ BlenderImporter::~BlenderImporter() {
 }
 }
 
 
 static const char * const Tokens[] = { "BLENDER" };
 static const char * const Tokens[] = { "BLENDER" };
-static const char * const TokensForSearch[] = { "blender" };
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string &extension = GetExtension(pFile);
-    if (extension == "blend") {
-        return true;
-    }
-
-    if ((!extension.length() || checkSig) && pIOHandler) {
-        // note: this won't catch compressed files
-        return SearchFileHeaderForToken(pIOHandler, pFile, TokensForSearch, 1);
-    }
+bool BlenderImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    // note: this won't catch compressed files
+    static const char *tokens[] = { "<BLENDER", "blender" };
 
 
-    return false;
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 13 - 2
code/AssetLib/C4D/C4DImporter.cpp

@@ -106,14 +106,25 @@ static const aiImporterDesc desc = {
 
 
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
+C4DImporter::C4DImporter()
+: BaseImporter() {
+    // empty
+}
+
+// ------------------------------------------------------------------------------------------------
+C4DImporter::~C4DImporter() {
+    // empty
+}
+
+// ------------------------------------------------------------------------------------------------
+bool C4DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const {
     const std::string& extension = GetExtension(pFile);
     const std::string& extension = GetExtension(pFile);
     if (extension == "c4d") {
     if (extension == "c4d") {
         return true;
         return true;
     } else if ((!extension.length() || checkSig) && pIOHandler)   {
     } else if ((!extension.length() || checkSig) && pIOHandler)   {
         // TODO
         // TODO
     }
     }
-
+    
     return false;
     return false;
 }
 }
 
 

+ 3 - 11
code/AssetLib/COB/COBLoader.cpp

@@ -103,17 +103,9 @@ COBImporter::~COBImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string &extension = GetExtension(pFile);
-    if (extension == "cob" || extension == "scn" || extension == "COB" || extension == "SCN") {
-        return true;
-    }
-
-    else if ((!extension.length() || checkSig) && pIOHandler) {
-        static const char * const tokens[] = { "Caligary" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool COBImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "Caligary" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/CSM/CSMLoader.cpp

@@ -90,19 +90,10 @@ CSMImporter::~CSMImporter()
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
 {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-
-    if( extension == "csm")
-        return true;
-
-    if ((checkSig || !extension.length()) && pIOHandler) {
-        static const char * const tokens[] = {"$Filename"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-    }
-    return false;
+    static const char* tokens[] = {"$Filename"};
+    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 7 - 29
code/AssetLib/Collada/ColladaLoader.cpp

@@ -116,37 +116,15 @@ ColladaLoader::~ColladaLoader() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-    const bool readSig = checkSig && (pIOHandler != nullptr);
-    if (!readSig) {
-        if (extension == "dae" || extension == "zae") {
-            return true;
-        }
-    } else {
-        // Look for a DAE file inside, but don't extract it
-        ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
-        if (zip_archive.isOpen()) {
-            return !ColladaParser::ReadZaeManifest(zip_archive).empty();
-        }
-    }
-
-    // XML - too generic, we need to open the file and search for typical keywords
-    if (extension == "xml" || !extension.length() || checkSig) {
-        //  If CanRead() is called in order to check whether we
-        //  support a specific file extension in general pIOHandler
-        //  might be nullptr and it's our duty to return true here.
-        if (nullptr == pIOHandler) {
-            return true;
-        }
-        static const char * const tokens[] = {
-            "<collada"
-        };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    // Look for a DAE file inside, but don't extract it
+    ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
+    if (zip_archive.isOpen()) {
+        return !ColladaParser::ReadZaeManifest(zip_archive).empty();
     }
     }
 
 
-    return false;
+    static const char *tokens[] = { "<collada" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 30 - 15
code/AssetLib/Collada/ColladaParser.cpp

@@ -331,7 +331,16 @@ void ColladaParser::ReadAssetInfo(XmlNode &node) {
         const std::string &currentName = currentNode.name();
         const std::string &currentName = currentNode.name();
         if (currentName == "unit") {
         if (currentName == "unit") {
             mUnitSize = 1.f;
             mUnitSize = 1.f;
-            XmlParser::getRealAttribute(currentNode, "meter", mUnitSize);
+            std::string tUnitSizeString;
+            if (XmlParser::getStdStrAttribute(currentNode, "meter", tUnitSizeString)) {
+                try {
+                    fast_atoreal_move<ai_real>(tUnitSizeString.data(), mUnitSize);
+                } catch (const DeadlyImportError& die) {
+                    std::string warning("Collada: Failed to parse meter parameter to real number. Exception:\n");
+                    warning.append(die.what());
+                    ASSIMP_LOG_WARN(warning.data());
+                }
+            }
         } else if (currentName == "up_axis") {
         } else if (currentName == "up_axis") {
             std::string v;
             std::string v;
             if (!XmlParser::getValueAsString(currentNode, v)) {
             if (!XmlParser::getValueAsString(currentNode, v)) {
@@ -2242,20 +2251,26 @@ void ColladaParser::ReadNodeGeometry(XmlNode &node, Node *pNode) {
         if (currentName == "bind_material") {
         if (currentName == "bind_material") {
             XmlNode techNode = currentNode.child("technique_common");
             XmlNode techNode = currentNode.child("technique_common");
             if (techNode) {
             if (techNode) {
-                XmlNode instanceMatNode = techNode.child("instance_material");
-                // read ID of the geometry subgroup and the target material
-                std::string group;
-                XmlParser::getStdStrAttribute(instanceMatNode, "symbol", group);
-                XmlParser::getStdStrAttribute(instanceMatNode, "target", url);
-                const char *urlMat = url.c_str();
-                Collada::SemanticMappingTable s;
-                if (urlMat[0] == '#')
-                    urlMat++;
-
-                s.mMatName = urlMat;
-                // store the association
-                instance.mMaterials[group] = s;
-                ReadMaterialVertexInputBinding(instanceMatNode, s);
+                for (XmlNode instanceMatNode = techNode.child("instance_material"); instanceMatNode; instanceMatNode = instanceMatNode.next_sibling())
+                {
+                    const std::string &instance_name = instanceMatNode.name();
+                    if (instance_name == "instance_material")
+                    {
+                        // read ID of the geometry subgroup and the target material
+                        std::string group;
+                        XmlParser::getStdStrAttribute(instanceMatNode, "symbol", group);
+                        XmlParser::getStdStrAttribute(instanceMatNode, "target", url);
+                        const char *urlMat = url.c_str();
+                        Collada::SemanticMappingTable s;
+                        if (urlMat[0] == '#')
+                            urlMat++;
+
+                        s.mMatName = urlMat;
+                        // store the association
+                        instance.mMaterials[group] = s;
+                        ReadMaterialVertexInputBinding(instanceMatNode, s);
+                    }
+                }
             }
             }
         }
         }
     }
     }

+ 3 - 12
code/AssetLib/DXF/DXFLoader.cpp

@@ -123,18 +123,9 @@ DXFImporter::~DXFImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool checkSig ) const {
-    const std::string& extension = GetExtension( filename );
-    if ( extension == desc.mFileExtensions ) {
-        return true;
-    }
-
-    if ( extension.empty() || checkSig ) {
-        static const char * const pTokens[] = { "SECTION", "HEADER", "ENDSEC", "BLOCKS" };
-        return SearchFileHeaderForToken(pIOHandler, filename, pTokens, 4, 32 );
-    }
-
-    return false;
+bool DXFImporter::CanRead( const std::string& filename, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
+    static const char *tokens[] = { "SECTION", "HEADER", "ENDSEC", "BLOCKS" };
+    return SearchFileHeaderForToken(pIOHandler, filename, tokens, AI_COUNT_OF(tokens), 32);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 4 - 12
code/AssetLib/FBX/FBXImporter.cpp

@@ -100,18 +100,10 @@ FBXImporter::~FBXImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-	const std::string &extension = GetExtension(pFile);
-	if (extension == std::string(desc.mFileExtensions)) {
-		return true;
-	}
-
-	else if ((!extension.length() || checkSig) && pIOHandler) {
-		// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
-		static const char * const tokens[] = { "fbx" };
-		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-	}
-	return false;
+bool FBXImporter::CanRead(const std::string & pFile, IOSystem * pIOHandler, bool /*checkSig*/) const {
+	// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
+	static const char *tokens[] = { "fbx" };
+	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 7 - 14
code/AssetLib/HMP/HMPLoader.cpp

@@ -84,20 +84,13 @@ HMPImporter::~HMPImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool HMPImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "hmp")
-        return true;
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || cs) {
-        uint32_t tokens[3];
-        tokens[0] = AI_HMP_MAGIC_NUMBER_LE_4;
-        tokens[1] = AI_HMP_MAGIC_NUMBER_LE_5;
-        tokens[2] = AI_HMP_MAGIC_NUMBER_LE_7;
-        return CheckMagicToken(pIOHandler, pFile, tokens, 3, 0);
-    }
-    return false;
+bool HMPImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = {
+        AI_HMP_MAGIC_NUMBER_LE_4,
+        AI_HMP_MAGIC_NUMBER_LE_5,
+        AI_HMP_MAGIC_NUMBER_LE_7
+    };
+    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 6 - 12
code/AssetLib/IFC/IFCLoader.cpp

@@ -129,18 +129,12 @@ IFCImporter::~IFCImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool IFCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string &extension = GetExtension(pFile);
-    if (extension == "ifc" || extension == "ifczip") {
-        return true;
-    } else if ((!extension.length() || checkSig) && pIOHandler) {
-        // note: this is the common identification for STEP-encoded files, so
-        // it is only unambiguous as long as we don't support any further
-        // file formats with STEP as their encoding.
-        static const char * const tokens[] = { "ISO-10303-21" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool IFCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    // note: this is the common identification for STEP-encoded files, so
+    // it is only unambiguous as long as we don't support any further
+    // file formats with STEP as their encoding.
+    static const char *tokens[] = { "ISO-10303-21" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 322 - 0
code/AssetLib/IQM/IQMImporter.cpp

@@ -0,0 +1,322 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2021, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
+
+#include <assimp/DefaultIOSystem.h>
+#include <assimp/IOStreamBuffer.h>
+#include <assimp/ai_assert.h>
+#include <assimp/importerdesc.h>
+#include <assimp/scene.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/Importer.hpp>
+#include <assimp/ByteSwapper.h>
+#include <memory>
+#include <numeric>
+
+#include "IQMImporter.h"
+#include "iqm.h"
+
+// RESOURCES:
+// http://sauerbraten.org/iqm/
+// https://github.com/lsalzman/iqm
+
+
+inline void swap_block( uint32_t *block, size_t size ){
+    (void)block; // suppress 'unreferenced formal parameter' MSVC warning
+    size >>= 2;
+    for ( size_t i = 0; i < size; ++i )
+        AI_SWAP4( block[ i ] );
+}
+
+static const aiImporterDesc desc = {
+    "Inter-Quake Model Importer",
+    "",
+    "",
+    "",
+    aiImporterFlags_SupportBinaryFlavour,
+    0,
+    0,
+    0,
+    0,
+    "iqm"
+};
+
+namespace Assimp {
+
+// ------------------------------------------------------------------------------------------------
+//  Default constructor
+IQMImporter::IQMImporter() :
+        mScene(nullptr) {
+    // empty
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Returns true, if file is a binary Inter-Quake Model file.
+bool IQMImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
+    const std::string extension = GetExtension(pFile);
+
+    if (extension == "iqm")
+        return true;
+    else if (!extension.length() || checkSig) {
+        if (!pIOHandler) {
+            return true;
+        }
+        /*
+         * don't use CheckMagicToken because that checks with swapped bytes too, leading to false
+         * positives. This magic is not uint32_t, but char[4], so memcmp is the best way
+
+        const char* tokens[] = {"3DMO", "3dmo"};
+        return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
+        */
+        std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
+        unsigned char data[15];
+        if (!pStream || 15 != pStream->Read(data, 1, 15)) {
+            return false;
+        }
+        return !memcmp(data, "INTERQUAKEMODEL", 15);
+    }
+    return false;
+}
+
+// ------------------------------------------------------------------------------------------------
+const aiImporterDesc *IQMImporter::GetInfo() const {
+    return &desc;
+}
+
+// ------------------------------------------------------------------------------------------------
+//  Model 3D import implementation
+void IQMImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSystem *pIOHandler) {
+    // Read file into memory
+    std::unique_ptr<IOStream> pStream(pIOHandler->Open(file, "rb"));
+    if (!pStream.get()) {
+        throw DeadlyImportError("Failed to open file ", file, ".");
+    }
+
+    // Get the file-size and validate it, throwing an exception when fails
+    const size_t fileSize = pStream->FileSize();
+    if (fileSize < sizeof( iqmheader )) {
+        throw DeadlyImportError("IQM-file ", file, " is too small.");
+    }
+    std::vector<unsigned char> buffer(fileSize);
+    unsigned char *data = buffer.data();
+    if (fileSize != pStream->Read(data, 1, fileSize)) {
+        throw DeadlyImportError("Failed to read the file ", file, ".");
+    }
+
+    // get header
+    iqmheader &hdr = reinterpret_cast<iqmheader&>( *data );
+    swap_block( &hdr.version, sizeof( iqmheader ) - sizeof( iqmheader::magic ) );
+
+    // extra check for header
+    if (memcmp(data, IQM_MAGIC, sizeof( IQM_MAGIC ) )
+     || hdr.version != IQM_VERSION
+     || hdr.filesize != fileSize) {
+        throw DeadlyImportError("Bad binary header in file ", file, ".");
+    }
+
+    ASSIMP_LOG_DEBUG("IQM: loading ", file);
+
+    // create the root node
+    pScene->mRootNode = new aiNode( "<IQMRoot>" );
+    // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
+    pScene->mRootNode->mTransformation = aiMatrix4x4(
+            1.f, 0.f, 0.f, 0.f,
+            0.f, 0.f, 1.f, 0.f,
+            0.f, -1.f, 0.f, 0.f,
+            0.f, 0.f, 0.f, 1.f);
+    pScene->mRootNode->mNumMeshes = hdr.num_meshes;
+    pScene->mRootNode->mMeshes = new unsigned int[hdr.num_meshes];
+    std::iota( pScene->mRootNode->mMeshes, pScene->mRootNode->mMeshes + pScene->mRootNode->mNumMeshes, 0 );
+
+    mScene = pScene;
+
+    // Allocate output storage
+    pScene->mNumMeshes = 0;
+    pScene->mMeshes = new aiMesh *[hdr.num_meshes](); // Set arrays to zero to ensue proper destruction if an exception is raised
+
+    pScene->mNumMaterials = 0;
+    pScene->mMaterials = new aiMaterial *[hdr.num_meshes]();
+
+    // swap vertex arrays beforehand...
+    for( auto array = reinterpret_cast<iqmvertexarray*>( data + hdr.ofs_vertexarrays ), end = array + hdr.num_vertexarrays; array != end; ++array )
+    {
+        swap_block( &array->type, sizeof( iqmvertexarray ) );
+    }
+
+    // Read all surfaces from the file
+    for( auto imesh = reinterpret_cast<iqmmesh*>( data + hdr.ofs_meshes ), end_ = imesh + hdr.num_meshes; imesh != end_; ++imesh )
+    {
+        swap_block( &imesh->name, sizeof( iqmmesh ) );
+        // Allocate output mesh & material
+        auto mesh = pScene->mMeshes[pScene->mNumMeshes++] = new aiMesh();
+        mesh->mMaterialIndex = pScene->mNumMaterials;
+        auto mat = pScene->mMaterials[pScene->mNumMaterials++] = new aiMaterial();
+
+        {
+            auto text = reinterpret_cast<char*>( data + hdr.ofs_text );
+            aiString name( text + imesh->material );
+            mat->AddProperty( &name, AI_MATKEY_NAME );
+            mat->AddProperty( &name, AI_MATKEY_TEXTURE_DIFFUSE(0) );
+        }
+
+        // Fill mesh information
+        mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+        mesh->mNumFaces = 0;
+        mesh->mFaces = new aiFace[imesh->num_triangles];
+
+        // Fill in all triangles
+        for( auto tri = reinterpret_cast<iqmtriangle*>( data + hdr.ofs_triangles ) + imesh->first_triangle, end = tri + imesh->num_triangles; tri != end; ++tri )
+        {
+            swap_block( tri->vertex, sizeof( tri->vertex ) );
+            auto& face = mesh->mFaces[mesh->mNumFaces++];
+            face.mNumIndices = 3;
+            face.mIndices = new unsigned int[3]{ tri->vertex[0] - imesh->first_vertex,
+                                                 tri->vertex[2] - imesh->first_vertex,
+                                                 tri->vertex[1] - imesh->first_vertex };
+        }
+
+        // Fill in all vertices
+        for( auto array = reinterpret_cast<const iqmvertexarray*>( data + hdr.ofs_vertexarrays ), end__ = array + hdr.num_vertexarrays; array != end__; ++array )
+        {
+            const unsigned int nVerts = imesh->num_vertexes;
+            const unsigned int step = array->size;
+
+            switch ( array->type )
+            {
+            case IQM_POSITION:
+                if( array->format == IQM_FLOAT && step >= 3 ){
+                    mesh->mNumVertices = nVerts;
+                    auto v = mesh->mVertices = new aiVector3D[nVerts];
+                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
+                        end = f + nVerts * step; f != end; f += step, ++v )
+                    {
+                        *v = { AI_BE( f[0] ),
+                               AI_BE( f[1] ),
+                               AI_BE( f[2] ) };
+                    }
+                }
+                break;
+               case IQM_TEXCOORD:
+                if( array->format == IQM_FLOAT && step >= 2)
+                {
+                    auto v = mesh->mTextureCoords[0] = new aiVector3D[nVerts];
+                    mesh->mNumUVComponents[0] = 2;
+                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
+                        end = f + nVerts * step; f != end; f += step, ++v )
+                    {
+                        *v = { AI_BE( f[0] ),
+                           1 - AI_BE( f[1] ), 0 };
+                    }
+                }
+                break;
+            case IQM_NORMAL:
+                if (array->format == IQM_FLOAT && step >= 3)
+                {
+                    auto v = mesh->mNormals = new aiVector3D[nVerts];
+                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
+                        end = f + nVerts * step; f != end; f += step, ++v )
+                    {
+                        *v = { AI_BE( f[0] ),
+                               AI_BE( f[1] ),
+                               AI_BE( f[2] ) };
+                    }
+                }
+                break;
+            case IQM_COLOR:
+                if (array->format == IQM_UBYTE && step >= 3)
+                {
+                    auto v = mesh->mColors[0] = new aiColor4D[nVerts];
+                    for( auto f = ( data + array->offset ) + imesh->first_vertex * step,
+                        end = f + nVerts * step; f != end; f += step, ++v )
+                    {
+                        *v = { ( f[0] ) / 255.f,
+                               ( f[1] ) / 255.f,
+                               ( f[2] ) / 255.f,
+                               step == 3? 1 : ( f[3] ) / 255.f };
+                    }
+                }
+                else if (array->format == IQM_FLOAT && step >= 3)
+                {
+                    auto v = mesh->mColors[0] = new aiColor4D[nVerts];
+                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
+                        end = f + nVerts * step; f != end; f += step, ++v )
+                    {
+                        *v = { AI_BE( f[0] ),
+                               AI_BE( f[1] ),
+                               AI_BE( f[2] ),
+                               step == 3? 1 : AI_BE( f[3] ) };
+                    }
+                }
+                break;
+            case IQM_TANGENT:
+#if 0
+                if (array->format == IQM_FLOAT && step >= 3)
+                {
+                    auto v = mesh->mTangents = new aiVector3D[nVerts];
+                    for( auto f = reinterpret_cast<const float*>( data + array->offset ) + imesh->first_vertex * step,
+                        end = f + nVerts * step; f != end; f += step, ++v )
+                    {
+                        *v = { AI_BE( f[0] ),
+                               AI_BE( f[1] ),
+                               AI_BE( f[2] ) };
+                    }
+                }
+#endif
+                break;
+            case IQM_BLENDINDEXES:
+            case IQM_BLENDWEIGHTS:
+            case IQM_CUSTOM:
+                break; // these attributes are not relevant.
+
+            default:
+                break;
+            }
+        }
+    }
+}
+
+
+// ------------------------------------------------------------------------------------------------
+
+} // Namespace Assimp
+
+#endif // !! ASSIMP_BUILD_NO_IQM_IMPORTER

+ 78 - 0
code/AssetLib/IQM/IQMImporter.h

@@ -0,0 +1,78 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2021, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+/** @file IQMImporter.h
+*   @brief Declares the importer class to read a scene from an Inter-Quake Model file
+*/
+
+#pragma once
+
+#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
+
+#include <assimp/BaseImporter.h>
+#include <assimp/material.h>
+
+namespace Assimp {
+
+class IQMImporter : public BaseImporter {
+public:
+	/// \brief  Default constructor
+	IQMImporter();
+    ~IQMImporter() override {}
+
+	/// \brief  Returns whether the class can handle the format of the given file.
+	/// \remark See BaseImporter::CanRead() for details.
+	bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
+
+protected:
+    //! \brief  Appends the supported extension.
+    const aiImporterDesc *GetInfo() const override;
+
+    //! \brief  File import implementation.
+    void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
+
+private:
+    aiScene *mScene = nullptr; // the scene to import to
+};
+
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_IQM_IMPORTER

+ 134 - 0
code/AssetLib/IQM/iqm.h

@@ -0,0 +1,134 @@
+#ifndef __IQM_H__
+#define __IQM_H__
+
+#define IQM_MAGIC "INTERQUAKEMODEL"
+#define IQM_VERSION 2
+
+struct iqmheader
+{
+    char magic[16];
+    unsigned int version;
+    unsigned int filesize;
+    unsigned int flags;
+    unsigned int num_text, ofs_text;
+    unsigned int num_meshes, ofs_meshes;
+    unsigned int num_vertexarrays, num_vertexes, ofs_vertexarrays;
+    unsigned int num_triangles, ofs_triangles, ofs_adjacency;
+    unsigned int num_joints, ofs_joints;
+    unsigned int num_poses, ofs_poses;
+    unsigned int num_anims, ofs_anims;
+    unsigned int num_frames, num_framechannels, ofs_frames, ofs_bounds;
+    unsigned int num_comment, ofs_comment;
+    unsigned int num_extensions, ofs_extensions;
+};
+
+struct iqmmesh
+{
+    unsigned int name;
+    unsigned int material;
+    unsigned int first_vertex, num_vertexes;
+    unsigned int first_triangle, num_triangles;
+};
+
+enum
+{
+    IQM_POSITION     = 0,
+    IQM_TEXCOORD     = 1,
+    IQM_NORMAL       = 2,
+    IQM_TANGENT      = 3,
+    IQM_BLENDINDEXES = 4,
+    IQM_BLENDWEIGHTS = 5,
+    IQM_COLOR        = 6,
+    IQM_CUSTOM       = 0x10
+};
+
+enum
+{
+    IQM_BYTE   = 0,
+    IQM_UBYTE  = 1,
+    IQM_SHORT  = 2,
+    IQM_USHORT = 3,
+    IQM_INT    = 4,
+    IQM_UINT   = 5,
+    IQM_HALF   = 6,
+    IQM_FLOAT  = 7,
+    IQM_DOUBLE = 8
+};
+
+struct iqmtriangle
+{
+    unsigned int vertex[3];
+};
+
+struct iqmadjacency
+{
+    unsigned int triangle[3];
+};
+
+struct iqmjointv1
+{
+    unsigned int name;
+    int parent;
+    float translate[3], rotate[3], scale[3];
+};
+
+struct iqmjoint
+{
+    unsigned int name;
+    int parent;
+    float translate[3], rotate[4], scale[3];
+};
+
+struct iqmposev1
+{
+    int parent;
+    unsigned int mask;
+    float channeloffset[9];
+    float channelscale[9];
+};
+
+struct iqmpose
+{
+    int parent;
+    unsigned int mask;
+    float channeloffset[10];
+    float channelscale[10];
+};
+
+struct iqmanim
+{
+    unsigned int name;
+    unsigned int first_frame, num_frames;
+    float framerate;
+    unsigned int flags;
+};
+
+enum
+{
+    IQM_LOOP = 1<<0
+};
+
+struct iqmvertexarray
+{
+    unsigned int type;
+    unsigned int flags;
+    unsigned int format;
+    unsigned int size;
+    unsigned int offset;
+};
+
+struct iqmbounds
+{
+    float bbmin[3], bbmax[3];
+    float xyradius, radius;
+};
+
+struct iqmextension
+{
+    unsigned int name;
+    unsigned int num_data, ofs_data;
+    unsigned int ofs_extensions; // pointer to next extension
+};
+
+#endif
+

+ 3 - 17
code/AssetLib/Irr/IRRLoader.cpp

@@ -94,23 +94,9 @@ IRRImporter::~IRRImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool IRRImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-	const std::string extension = GetExtension(pFile);
-	if (extension == "irr") {
-		return true;
-	} else if (extension == "xml" || checkSig) {
-		/*  If CanRead() is called in order to check whether we
-         *  support a specific file extension in general pIOHandler
-         *  might be nullptr and it's our duty to return true here.
-         */
-		if (nullptr == pIOHandler) {
-			return true;
-		}
-		static const char * const tokens[] = { "irr_scene" };
-		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-	}
-
-	return false;
+bool IRRImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+	static const char *tokens[] = { "irr_scene" };
+	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 7 - 21
code/AssetLib/Irr/IRRMeshLoader.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2022, assimp team
 Copyright (c) 2006-2022, assimp team
 
 
-
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -85,26 +83,14 @@ IRRMeshImporter::~IRRMeshImporter() {}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
+bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
 	/* NOTE: A simple check for the file extension is not enough
 	/* NOTE: A simple check for the file extension is not enough
-     * here. Irrmesh and irr are easy, but xml is too generic
-     * and could be collada, too. So we need to open the file and
-     * search for typical tokens.
-     */
-	const std::string extension = GetExtension(pFile);
-
-	if (extension == "irrmesh")
-		return true;
-	else if (extension == "xml" || checkSig) {
-		/*  If CanRead() is called to check whether the loader
-         *  supports a specific file extension in general we
-         *  must return true here.
-         */
-		if (!pIOHandler) return true;
-		static const char * const tokens[] = { "irrmesh" };
-		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-	}
-	return false;
+	 * here. Irrmesh and irr are easy, but xml is too generic
+	 * and could be collada, too. So we need to open the file and
+	 * search for typical tokens.
+	 */
+	static const char *tokens[] = { "irrmesh" };
+	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 7 - 15
code/AssetLib/LWO/LWOLoader.cpp

@@ -105,21 +105,13 @@ LWOImporter::~LWOImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(file);
-    if (extension == "lwo" || extension == "lxo") {
-        return true;
-    }
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[3];
-        tokens[0] = AI_LWO_FOURCC_LWOB;
-        tokens[1] = AI_LWO_FOURCC_LWO2;
-        tokens[2] = AI_LWO_FOURCC_LXOB;
-        return CheckMagicToken(pIOHandler, file, tokens, 3, 8);
-    }
-    return false;
+bool LWOImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = {
+        AI_LWO_FOURCC_LWOB,
+        AI_LWO_FOURCC_LWO2,
+        AI_LWO_FOURCC_LXOB
+    };
+    return CheckMagicToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens), 8);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 6 - 14
code/AssetLib/LWS/LWSLoader.cpp

@@ -147,20 +147,12 @@ LWSImporter::~LWSImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "lws" || extension == "mot") {
-        return true;
-    }
-
-    // if check for extension is not enough, check for the magic tokens LWSC and LWMO
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[2];
-        tokens[0] = AI_MAKE_MAGIC("LWSC");
-        tokens[1] = AI_MAKE_MAGIC("LWMO");
-        return CheckMagicToken(pIOHandler, pFile, tokens, 2);
-    }
-    return false;
+bool LWSImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = {
+        AI_MAKE_MAGIC("LWSC"),
+        AI_MAKE_MAGIC("LWMO")
+    };
+    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 12 - 27
code/AssetLib/M3D/M3DImporter.cpp

@@ -111,34 +111,19 @@ M3DImporter::M3DImporter() :
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //  Returns true, if file is a binary or ASCII Model 3D file.
 //  Returns true, if file is a binary or ASCII Model 3D file.
-bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "m3d"
-            || extension == "a3d"
-    )
-        return true;
-    else if (!extension.length() || checkSig) {
-        if (!pIOHandler) {
-            return true;
-        }
-        /*
-         * don't use CheckMagicToken because that checks with swapped bytes too, leading to false
-         * positives. This magic is not uint32_t, but char[4], so memcmp is the best way
-
-        const char* tokens[] = {"3DMO", "3dmo"};
-        return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
-        */
-        std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
-        unsigned char data[4];
-        if (!pStream || 4 != pStream->Read(data, 1, 4)) {
-            return false;
-        }
-        return !memcmp(data, "3DMO", 4) /* bin */
-               || !memcmp(data, "3dmo", 4) /* ASCII */
-                ;
+bool M3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    // don't use CheckMagicToken because that checks with swapped bytes too, leading to false
+    // positives. This magic is not uint32_t, but char[4], so memcmp is the best way
+    std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile, "rb"));
+    unsigned char data[4];
+    if (4 != pStream->Read(data, 1, 4)) {
+        return false;
     }
     }
-    return false;
+    return !memcmp(data, "3DMO", 4) /* bin */
+#ifdef M3D_ASCII
+        || !memcmp(data, "3dmo", 4) /* ASCII */
+#endif
+            ;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/MD2/MD2Loader.cpp

@@ -107,19 +107,10 @@ MD2Importer::~MD2Importer()
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool MD2Importer::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
 {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "md2")
-        return true;
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[1];
-        tokens[0] = AI_MD2_MAGIC_NUMBER_LE;
-        return CheckMagicToken(pIOHandler,pFile,tokens,1);
-    }
-    return false;
+    static const uint32_t tokens[] = { AI_MD2_MAGIC_NUMBER_LE };
+    return CheckMagicToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 12
code/AssetLib/MD3/MD3Loader.cpp

@@ -349,18 +349,9 @@ MD3Importer::~MD3Importer() {}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool MD3Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "md3")
-        return true;
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[1];
-        tokens[0] = AI_MD3_MAGIC_NUMBER_LE;
-        return CheckMagicToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool MD3Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = { AI_MD3_MAGIC_NUMBER_LE };
+    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 14
code/AssetLib/MD5/MD5Loader.cpp

@@ -100,20 +100,9 @@ MD5Importer::~MD5Importer() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "md5anim" || extension == "md5mesh" || extension == "md5camera")
-        return true;
-    else if (!extension.length() || checkSig) {
-        if (!pIOHandler) {
-            return true;
-        }
-        static const char * const tokens[] = { "MD5Version" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-
-    return false;
+bool MD5Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "MD5Version" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 13
code/AssetLib/MDC/MDCLoader.cpp

@@ -111,19 +111,9 @@ MDCImporter::~MDCImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "mdc") {
-        return true;
-    }
-
-    // if check for extension is not enough, check for the magic tokens
-    if (!extension.length() || checkSig) {
-        uint32_t tokens[1];
-        tokens[0] = AI_MDC_MAGIC_NUMBER_LE;
-        return CheckMagicToken(pIOHandler, pFile, tokens, 1);
-    }
-    return false;
+bool MDCImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = { AI_MDC_MAGIC_NUMBER_LE };
+    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 12 - 17
code/AssetLib/MDL/MDLLoader.cpp

@@ -104,23 +104,18 @@ MDLImporter::~MDLImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    // if check for extension is not enough, check for the magic tokens
-    if (extension == "mdl" || !extension.length() || checkSig) {
-        uint32_t tokens[8];
-        tokens[0] = AI_MDL_MAGIC_NUMBER_LE_HL2a;
-        tokens[1] = AI_MDL_MAGIC_NUMBER_LE_HL2b;
-        tokens[2] = AI_MDL_MAGIC_NUMBER_LE_GS7;
-        tokens[3] = AI_MDL_MAGIC_NUMBER_LE_GS5b;
-        tokens[4] = AI_MDL_MAGIC_NUMBER_LE_GS5a;
-        tokens[5] = AI_MDL_MAGIC_NUMBER_LE_GS4;
-        tokens[6] = AI_MDL_MAGIC_NUMBER_LE_GS3;
-        tokens[7] = AI_MDL_MAGIC_NUMBER_LE;
-        return CheckMagicToken(pIOHandler, pFile, tokens, 8, 0);
-    }
-    return false;
+bool MDLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t tokens[] = {
+        AI_MDL_MAGIC_NUMBER_LE_HL2a,
+        AI_MDL_MAGIC_NUMBER_LE_HL2b,
+        AI_MDL_MAGIC_NUMBER_LE_GS7,
+        AI_MDL_MAGIC_NUMBER_LE_GS5b,
+        AI_MDL_MAGIC_NUMBER_LE_GS5a,
+        AI_MDL_MAGIC_NUMBER_LE_GS4,
+        AI_MDL_MAGIC_NUMBER_LE_GS3,
+        AI_MDL_MAGIC_NUMBER_LE
+    };
+    return CheckMagicToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 8
code/AssetLib/MMD/MMDImporter.cpp

@@ -89,14 +89,9 @@ MMDImporter::~MMDImporter() {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //  Returns true, if file is an pmx file.
 //  Returns true, if file is an pmx file.
 bool MMDImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler,
 bool MMDImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler,
-        bool checkSig) const {
-    if (!checkSig) {
-        return SimpleExtensionCheck(pFile, "pmx");
-    } else {
-        // Check file Header
-        static const char * const pTokens[] = { "PMX " };
-        return SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 1);
-    }
+        bool /*checkSig*/) const {
+    static const char *tokens[] = { "PMX " };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 17
code/AssetLib/MS3D/MS3DLoader.cpp

@@ -88,26 +88,12 @@ MS3DImporter::MS3DImporter()
 // Destructor, private as well
 // Destructor, private as well
 MS3DImporter::~MS3DImporter()
 MS3DImporter::~MS3DImporter()
 {}
 {}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool MS3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool MS3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
 {
-    // first call - simple extension check
-    const std::string extension = GetExtension(pFile);
-    if (extension == "ms3d") {
-        return true;
-    }
-
-    // second call - check for magic identifiers
-    else if (!extension.length() || checkSig)   {
-        if (!pIOHandler) {
-            return true;
-        }
-        static const char * const tokens[] = {"MS3D000000"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-    }
-    return false;
+    static const char* tokens[] = { "MS3D000000" };
+    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 14
code/AssetLib/NDO/NDOLoader.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2022, assimp team
 Copyright (c) 2006-2022, assimp team
 
 
-
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -82,19 +80,10 @@ NDOImporter::~NDOImporter()
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool NDOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool NDOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
 {
-    // check file extension
-    const std::string extension = GetExtension(pFile);
-
-    if( extension == "ndo")
-        return true;
-
-    if ((checkSig || !extension.length()) && pIOHandler) {
-        static const char * const tokens[] = {"nendo"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,5);
-    }
-    return false;
+    static const char* tokens[] = {"nendo"};
+    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens),5);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 1 - 3
code/AssetLib/NFF/NFFLoader.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2022, assimp team
 Copyright (c) 2006-2022, assimp team
 
 
-
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -83,7 +81,7 @@ NFFImporter::~NFFImporter() {}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool NFFImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
+bool NFFImporter::CanRead(const std::string & pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
     return SimpleExtensionCheck(pFile, "nff", "enff");
     return SimpleExtensionCheck(pFile, "nff", "enff");
 }
 }
 
 

+ 3 - 12
code/AssetLib/OFF/OFFLoader.cpp

@@ -83,19 +83,10 @@ OFFImporter::~OFFImporter()
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
+bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const
 {
 {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "off")
-        return true;
-    else if (!extension.length() || checkSig)
-    {
-        if (!pIOHandler)return true;
-        static const char * const tokens[] = {"off"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,3);
-    }
-    return false;
+    static const char* tokens[] = { "off" };
+    return SearchFileHeaderForToken(pIOHandler,pFile,tokens,AI_COUNT_OF(tokens),3);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 4 - 10
code/AssetLib/Obj/ObjFileImporter.cpp

@@ -87,16 +87,10 @@ ObjFileImporter::~ObjFileImporter() {
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-//  Returns true, if file is an obj file.
-bool ObjFileImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    if (!checkSig) {
-        //Check File Extension
-        return SimpleExtensionCheck(pFile, "obj");
-    } else {
-        // Check file Header
-        static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
-        return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9, 200, false, true);
-    }
+//  Returns true if file is an obj file.
+bool ObjFileImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
+    return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens), 200, false, true);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 7
code/AssetLib/Ogre/OgreImporter.cpp

@@ -73,14 +73,10 @@ void OgreImporter::SetupProperties(const Importer *pImp) {
     m_detectTextureTypeFromFilename = pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false);
     m_detectTextureTypeFromFilename = pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false);
 }
 }
 
 
-bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const {
-    if (!checkSig) {
-        return EndsWith(pFile, ".mesh.xml", false) || EndsWith(pFile, ".mesh", false);
-    }
-
+bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool /*checkSig*/) const {
     if (EndsWith(pFile, ".mesh.xml", false)) {
     if (EndsWith(pFile, ".mesh.xml", false)) {
-        static const char * const tokens[] = { "<mesh>" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+        static const char *tokens[] = { "<mesh>" };
+        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
     }
     }
 
 
     /// @todo Read and validate first header chunk?
     /// @todo Read and validate first header chunk?

+ 3 - 10
code/AssetLib/OpenGEX/OpenGEXImporter.cpp

@@ -290,16 +290,9 @@ OpenGEXImporter::~OpenGEXImporter() {
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool checkSig) const {
-    bool canRead(false);
-    if (!checkSig) {
-        canRead = SimpleExtensionCheck(file, "ogex");
-    } else {
-        static const char * const token[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
-        canRead = SearchFileHeaderForToken(pIOHandler, file, token, 4);
-    }
-
-    return canRead;
+bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
+    return SearchFileHeaderForToken(pIOHandler, file, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------

+ 3 - 18
code/AssetLib/Ply/PlyLoader.cpp

@@ -100,24 +100,9 @@ PLYImporter::~PLYImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool PLYImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "ply") {
-        return true;
-    }
-
-    if (!extension.length() || checkSig) {
-        if (!pIOHandler) {
-            return true;
-        }
-        static const char * const tokens[] = {
-            "ply"
-        };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-
-    return false;
+bool PLYImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "ply" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 4
code/AssetLib/Q3BSP/Q3BSPFileImporter.cpp

@@ -156,12 +156,11 @@ Q3BSPFileImporter::~Q3BSPFileImporter() {
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-//  Returns true, if the loader can read this.
-bool Q3BSPFileImporter::CanRead(const std::string &rFile, IOSystem * /*pIOHandler*/, bool checkSig) const {
+//  Returns true if the loader can read this.
+bool Q3BSPFileImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool checkSig) const {
     if (!checkSig) {
     if (!checkSig) {
-        return SimpleExtensionCheck(rFile, "pk3", "bsp");
+        return SimpleExtensionCheck(filename, "pk3", "bsp");
     }
     }
-
     return false;
     return false;
 }
 }
 
 

+ 3 - 12
code/AssetLib/Q3D/Q3DLoader.cpp

@@ -84,18 +84,9 @@ Q3DImporter::~Q3DImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool Q3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "q3s" || extension == "q3o")
-        return true;
-    else if (!extension.length() || checkSig) {
-        if (!pIOHandler)
-            return true;
-        static const char * const tokens[] = { "quick3Do", "quick3Ds" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 2);
-    }
-    return false;
+bool Q3DImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "quick3Do", "quick3Ds" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 2 - 2
code/AssetLib/Raw/RawLoader.cpp

@@ -84,8 +84,8 @@ RAWImporter::~RAWImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool RAWImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
-    return SimpleExtensionCheck(pFile, "raw");
+bool RAWImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
+    return SimpleExtensionCheck(filename, "raw");
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 2 - 5
code/AssetLib/SIB/SIBImporter.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2022, assimp team
 Copyright (c) 2006-2022, assimp team
 
 
-
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -61,7 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifdef ASSIMP_USE_HUNTER
 #ifdef ASSIMP_USE_HUNTER
 #include <utf8.h>
 #include <utf8.h>
 #else
 #else
-//#  include "../contrib/ConvertUTF/ConvertUTF.h"
 #include "../contrib/utf8cpp/source/utf8.h"
 #include "../contrib/utf8cpp/source/utf8.h"
 #endif
 #endif
 #include <assimp/importerdesc.h>
 #include <assimp/importerdesc.h>
@@ -217,8 +214,8 @@ SIBImporter::~SIBImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool SIBImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
-    return SimpleExtensionCheck(pFile, "sib");
+bool SIBImporter::CanRead(const std::string &filename, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
+    return SimpleExtensionCheck(filename, "sib");
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 11 - 12
code/AssetLib/SMD/SMDLoader.cpp

@@ -81,15 +81,15 @@ static const aiImporterDesc desc = {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
-SMDImporter::SMDImporter()
-: configFrameID()
-, mBuffer()
-, pScene( nullptr )
-, iFileSize( 0 )
-, iSmallestFrame( INT_MAX )
-, dLengthOfAnim( 0.0 )
-, bHasUVs(false )
-, iLineNumber((unsigned int)-1)  {
+SMDImporter::SMDImporter() :
+        configFrameID(), 
+        mBuffer(), 
+        pScene( nullptr ), 
+        iFileSize( 0 ), 
+        iSmallestFrame( INT_MAX ),
+        dLengthOfAnim( 0.0 ),
+        bHasUVs(false ), 
+        iLineNumber((unsigned int)-1)  {
     // empty
     // empty
 }
 }
 
 
@@ -101,9 +101,8 @@ SMDImporter::~SMDImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool SMDImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool) const {
-    // fixme: auto format detection
-    return SimpleExtensionCheck(pFile,"smd","vta");
+bool SMDImporter::CanRead( const std::string& filename, IOSystem* /*pIOHandler*/, bool) const {
+    return SimpleExtensionCheck(filename, "smd", "vta");
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 16
code/AssetLib/STL/STLLoader.cpp

@@ -140,22 +140,9 @@ STLImporter::~STLImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool STLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-
-    if (extension == "stl") {
-        return true;
-    }
-
-    if (!extension.length() || checkSig) {
-        if (!pIOHandler) {
-            return true;
-        }
-        static const char * const tokens[] = { "STL", "solid" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 2);
-    }
-
-    return false;
+bool STLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "STL", "solid" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 21
code/AssetLib/Terragen/TerragenLoader.cpp

@@ -81,27 +81,9 @@ TerragenImporter::~TerragenImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool TerragenImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    // check file extension
-    std::string extension = GetExtension(pFile);
-
-    if (extension == "ter")
-        return true;
-
-    if (!extension.length() || checkSig) {
-        /*  If CanRead() is called in order to check whether we
-         *  support a specific file extension in general pIOHandler
-         *  might be nullptr and it's our duty to return true here.
-         */
-        if (!pIOHandler) {
-            return true;
-        }
-
-        static const char * const tokens[] = { "terragen" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-
-    return false;
+bool TerragenImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+    static const char *tokens[] = { "terragen" };
+    return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 9 - 5
code/AssetLib/Unreal/UnrealLoader.cpp

@@ -74,7 +74,7 @@ namespace Unreal {
     3 = Masked two-sided
     3 = Masked two-sided
     4 = Modulation blended two-sided
     4 = Modulation blended two-sided
     8 = Placeholder triangle for weapon positioning (invisible)
     8 = Placeholder triangle for weapon positioning (invisible)
-    */
+*/
 enum MeshFlags {
 enum MeshFlags {
     MF_NORMAL_OS = 0,
     MF_NORMAL_OS = 0,
     MF_NORMAL_TS = 1,
     MF_NORMAL_TS = 1,
@@ -168,16 +168,20 @@ static const aiImporterDesc desc = {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 UnrealImporter::UnrealImporter() :
 UnrealImporter::UnrealImporter() :
-        mConfigFrameID(0), mConfigHandleFlags(true) {}
+        mConfigFrameID(0), mConfigHandleFlags(true) {
+    // empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 // Destructor, private as well
-UnrealImporter::~UnrealImporter() {}
+UnrealImporter::~UnrealImporter() {
+    // empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool UnrealImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
-    return SimpleExtensionCheck(pFile, "3d", "uc");
+bool UnrealImporter::CanRead(const std::string & filename, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
+    return SimpleExtensionCheck(filename, "3d", "uc");
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 11
code/AssetLib/X/XFileImporter.cpp

@@ -88,17 +88,9 @@ XFileImporter::~XFileImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
-    std::string extension = GetExtension(pFile);
-    if(extension == "x") {
-        return true;
-    }
-    if (!extension.length() || checkSig) {
-        uint32_t token[1];
-        token[0] = AI_MAKE_MAGIC("xof ");
-        return CheckMagicToken(pIOHandler,pFile,token,1,0);
-    }
-    return false;
+bool XFileImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/) const {
+    static const uint32_t token[] = { AI_MAKE_MAGIC("xof ") };
+    return CheckMagicToken(pIOHandler,pFile,token,AI_COUNT_OF(token));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 3 - 19
code/AssetLib/XGL/XGLLoader.cpp

@@ -104,25 +104,9 @@ XGLImporter::~XGLImporter() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-	/* NOTE: A simple check for the file extension is not enough
-     * here. XGL and ZGL are ok, but xml is too generic
-     * and might be collada as well. So open the file and
-     * look for typical signal tokens.
-     */
-	const std::string extension = GetExtension(pFile);
-
-	if (extension == "xgl" || extension == "zgl") {
-		return true;
-	}
-
-  if (extension == "xml" || checkSig) {
-		ai_assert(pIOHandler != nullptr);
-		static const char * const tokens[] = { "<world>", "<World>", "<WORLD>" };
-		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 3);
-	}
-
-    return false;
+bool XGLImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /*checkSig*/) const {
+	static const char *tokens[] = { "<world>", "<World>", "<WORLD>" };
+	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, AI_COUNT_OF(tokens));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 6 - 16
code/AssetLib/glTF/glTFImporter.cpp

@@ -93,24 +93,14 @@ const aiImporterDesc *glTFImporter::GetInfo() const {
 }
 }
 
 
 bool glTFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
 bool glTFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool /* checkSig */) const {
-    const std::string &extension = GetExtension(pFile);
-
-    if (extension != "gltf" && extension != "glb") {
+    glTF::Asset asset(pIOHandler);
+    try {
+        asset.Load(pFile, GetExtension(pFile) == "glb");
+        std::string version = asset.asset.version;
+        return !version.empty() && version[0] == '1';
+    } catch (...) {
         return false;
         return false;
     }
     }
-
-    if (pIOHandler) {
-        glTF::Asset asset(pIOHandler);
-        try {
-            asset.Load(pFile, extension == "glb");
-            std::string version = asset.asset.version;
-            return !version.empty() && version[0] == '1';
-        } catch (...) {
-            return false;
-        }
-    }
-
-    return false;
 }
 }
 
 
 inline void SetMaterialColorProperty(std::vector<int> &embeddedTexIdxs, Asset & /*r*/, glTF::TexProperty prop, aiMaterial *mat,
 inline void SetMaterialColorProperty(std::vector<int> &embeddedTexIdxs, Asset & /*r*/, glTF::TexProperty prop, aiMaterial *mat,

+ 32 - 30
code/AssetLib/glTF2/glTF2Importer.cpp

@@ -98,7 +98,7 @@ static const aiImporterDesc desc = {
 glTF2Importer::glTF2Importer() :
 glTF2Importer::glTF2Importer() :
         BaseImporter(),
         BaseImporter(),
         meshOffsets(),
         meshOffsets(),
-        embeddedTexIdxs(),
+        mEmbeddedTexIdxs(),
         mScene(nullptr) {
         mScene(nullptr) {
     // empty
     // empty
 }
 }
@@ -111,21 +111,21 @@ const aiImporterDesc *glTF2Importer::GetInfo() const {
     return &desc;
     return &desc;
 }
 }
 
 
-bool glTF2Importer::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig ) const {
-	const std::string &extension = GetExtension(pFile);
-
-	if (!checkSig && (extension != "gltf") && (extension != "glb"))
-		return false;
+bool glTF2Importer::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig ) const {
+    const std::string extension = GetExtension(filename);
+    if (!checkSig && (extension != "gltf") && (extension != "glb")) {
+        return false;
+    }
 
 
-	if (pIOHandler) {
-		glTF2::Asset asset(pIOHandler);
-		return asset.CanRead(pFile, extension == "glb");
-	}
+    if (pIOHandler) {
+        glTF2::Asset asset(pIOHandler);
+        return asset.CanRead(filename, extension == "glb");
+    }
 
 
     return false;
     return false;
 }
 }
 
 
-static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) {
+static inline aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) {
     switch (gltfWrapMode) {
     switch (gltfWrapMode) {
         case SamplerWrap::Mirrored_Repeat:
         case SamplerWrap::Mirrored_Repeat:
             return aiTextureMapMode_Mirror;
             return aiTextureMapMode_Mirror;
@@ -140,21 +140,21 @@ static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) {
     }
     }
 }
 }
 
 
-inline void SetMaterialColorProperty(Asset & /*r*/, vec4 &prop, aiMaterial *mat,
+static inline void SetMaterialColorProperty(Asset & /*r*/, vec4 &prop, aiMaterial *mat,
         const char *pKey, unsigned int type, unsigned int idx) {
         const char *pKey, unsigned int type, unsigned int idx) {
     aiColor4D col;
     aiColor4D col;
     CopyValue(prop, col);
     CopyValue(prop, col);
     mat->AddProperty(&col, 1, pKey, type, idx);
     mat->AddProperty(&col, 1, pKey, type, idx);
 }
 }
 
 
-inline void SetMaterialColorProperty(Asset & /*r*/, vec3 &prop, aiMaterial *mat,
+static inline void SetMaterialColorProperty(Asset & /*r*/, vec3 &prop, aiMaterial *mat,
         const char *pKey, unsigned int type, unsigned int idx) {
         const char *pKey, unsigned int type, unsigned int idx) {
     aiColor4D col;
     aiColor4D col;
     glTFCommon::CopyValue(prop, col);
     glTFCommon::CopyValue(prop, col);
     mat->AddProperty(&col, 1, pKey, type, idx);
     mat->AddProperty(&col, 1, pKey, type, idx);
 }
 }
 
 
-inline void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset & /*r*/,
+static void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset & /*r*/,
         glTF2::TextureInfo prop, aiMaterial *mat, aiTextureType texType,
         glTF2::TextureInfo prop, aiMaterial *mat, aiTextureType texType,
         unsigned int texSlot = 0) {
         unsigned int texSlot = 0) {
     if (prop.texture && prop.texture->source) {
     if (prop.texture && prop.texture->source) {
@@ -371,10 +371,10 @@ void glTF2Importer::ImportMaterials(Asset &r) {
     mScene->mNumMaterials = numImportedMaterials + 1;
     mScene->mNumMaterials = numImportedMaterials + 1;
     mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials];
     mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials];
     std::fill(mScene->mMaterials, mScene->mMaterials + mScene->mNumMaterials, nullptr);
     std::fill(mScene->mMaterials, mScene->mMaterials + mScene->mNumMaterials, nullptr);
-    mScene->mMaterials[numImportedMaterials] = ImportMaterial(embeddedTexIdxs, r, defaultMaterial);
+    mScene->mMaterials[numImportedMaterials] = ImportMaterial(mEmbeddedTexIdxs, r, defaultMaterial);
 
 
     for (unsigned int i = 0; i < numImportedMaterials; ++i) {
     for (unsigned int i = 0; i < numImportedMaterials; ++i) {
-        mScene->mMaterials[i] = ImportMaterial(embeddedTexIdxs, r, r.materials[i]);
+        mScene->mMaterials[i] = ImportMaterial(mEmbeddedTexIdxs, r, r.materials[i]);
     }
     }
 }
 }
 
 
@@ -802,8 +802,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
                 if (actualNumFaces < nFaces) {
                 if (actualNumFaces < nFaces) {
                     ASSIMP_LOG_WARN("Some faces had out-of-range indices. Those faces were dropped.");
                     ASSIMP_LOG_WARN("Some faces had out-of-range indices. Those faces were dropped.");
                 }
                 }
-                if (actualNumFaces == 0)
-                {
+                if (actualNumFaces == 0) {
                     throw DeadlyImportError("Mesh \"", aim->mName.C_Str(), "\" has no faces");
                     throw DeadlyImportError("Mesh \"", aim->mName.C_Str(), "\" has no faces");
                 }
                 }
                 aim->mNumFaces = actualNumFaces;
                 aim->mNumFaces = actualNumFaces;
@@ -843,7 +842,6 @@ void glTF2Importer::ImportCameras(glTF2::Asset &r) {
         aicam->mLookAt = aiVector3D(0.f, 0.f, -1.f);
         aicam->mLookAt = aiVector3D(0.f, 0.f, -1.f);
 
 
         if (cam.type == Camera::Perspective) {
         if (cam.type == Camera::Perspective) {
-
             aicam->mAspect = cam.cameraProperties.perspective.aspectRatio;
             aicam->mAspect = cam.cameraProperties.perspective.aspectRatio;
             aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect);
             aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect);
             aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar;
             aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar;
@@ -862,8 +860,9 @@ void glTF2Importer::ImportCameras(glTF2::Asset &r) {
 }
 }
 
 
 void glTF2Importer::ImportLights(glTF2::Asset &r) {
 void glTF2Importer::ImportLights(glTF2::Asset &r) {
-    if (!r.lights.Size())
+    if (!r.lights.Size()) {
         return;
         return;
+    }
 
 
     const unsigned int numLights = r.lights.Size();
     const unsigned int numLights = r.lights.Size();
     ASSIMP_LOG_DEBUG("Importing ", numLights, " lights");
     ASSIMP_LOG_DEBUG("Importing ", numLights, " lights");
@@ -1125,8 +1124,8 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
                         bone->mNumWeights = static_cast<uint32_t>(weights.size());
                         bone->mNumWeights = static_cast<uint32_t>(weights.size());
 
 
                         if (bone->mNumWeights > 0) {
                         if (bone->mNumWeights > 0) {
-                          bone->mWeights = new aiVertexWeight[bone->mNumWeights];
-                          memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
+                            bone->mWeights = new aiVertexWeight[bone->mNumWeights];
+                            memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight));
                         } else {
                         } else {
                             // Assimp expects all bones to have at least 1 weight.
                             // Assimp expects all bones to have at least 1 weight.
                             bone->mWeights = new aiVertexWeight[1];
                             bone->mWeights = new aiVertexWeight[1];
@@ -1167,8 +1166,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
                 if (!ainode->mMetaData) {
                 if (!ainode->mMetaData) {
                     ainode->mMetaData = aiMetadata::Alloc(1);
                     ainode->mMetaData = aiMetadata::Alloc(1);
                     ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
                     ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
-                }
-                else {
+                } else {
                     ainode->mMetaData->Add("PBR_LightRange", node.light->range.value);
                     ainode->mMetaData->Add("PBR_LightRange", node.light->range.value);
                 }
                 }
             }
             }
@@ -1509,16 +1507,20 @@ void glTF2Importer::ImportAnimations(glTF2::Asset &r) {
     }
     }
 }
 }
 
 
-void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
-    embeddedTexIdxs.resize(r.images.Size(), -1);
-
-    int numEmbeddedTexs = 0;
+static unsigned int countEmbeddedTextures(glTF2::Asset &r) {
+    unsigned int numEmbeddedTexs = 0;
     for (size_t i = 0; i < r.images.Size(); ++i) {
     for (size_t i = 0; i < r.images.Size(); ++i) {
         if (r.images[i].HasData()) {
         if (r.images[i].HasData()) {
             numEmbeddedTexs += 1;
             numEmbeddedTexs += 1;
         }
         }
     }
     }
 
 
+    return numEmbeddedTexs;
+}
+
+void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
+    mEmbeddedTexIdxs.resize(r.images.Size(), -1);
+    const unsigned int numEmbeddedTexs = countEmbeddedTextures(r);
     if (numEmbeddedTexs == 0) {
     if (numEmbeddedTexs == 0) {
         return;
         return;
     }
     }
@@ -1536,7 +1538,7 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
         }
         }
 
 
         int idx = mScene->mNumTextures++;
         int idx = mScene->mNumTextures++;
-        embeddedTexIdxs[i] = idx;
+        mEmbeddedTexIdxs[i] = idx;
 
 
         aiTexture *tex = mScene->mTextures[idx] = new aiTexture();
         aiTexture *tex = mScene->mTextures[idx] = new aiTexture();
 
 
@@ -1597,7 +1599,7 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
 
 
     // clean all member arrays
     // clean all member arrays
     meshOffsets.clear();
     meshOffsets.clear();
-    embeddedTexIdxs.clear();
+    mEmbeddedTexIdxs.clear();
 
 
     this->mScene = pScene;
     this->mScene = pScene;
 
 

+ 1 - 1
code/AssetLib/glTF2/glTF2Importer.h

@@ -79,7 +79,7 @@ private:
 
 
 private:
 private:
     std::vector<unsigned int> meshOffsets;
     std::vector<unsigned int> meshOffsets;
-    std::vector<int> embeddedTexIdxs;
+    std::vector<int> mEmbeddedTexIdxs;
     aiScene *mScene;
     aiScene *mScene;
 
 
     /// An instance of rapidjson::IRemoteSchemaDocumentProvider
     /// An instance of rapidjson::IRemoteSchemaDocumentProvider

+ 6 - 0
code/CMakeLists.txt

@@ -376,6 +376,12 @@ ADD_ASSIMP_IMPORTER( IRRMESH
   AssetLib/Irr/IRRShared.h
   AssetLib/Irr/IRRShared.h
 )
 )
 
 
+ADD_ASSIMP_IMPORTER( IQM
+  AssetLib/IQM/IQMImporter.cpp
+  AssetLib/IQM/iqm.h
+  AssetLib/IQM/IQMImporter.h
+)
+
 ADD_ASSIMP_IMPORTER( IRR
 ADD_ASSIMP_IMPORTER( IRR
   AssetLib/Irr/IRRLoader.cpp
   AssetLib/Irr/IRRLoader.cpp
   AssetLib/Irr/IRRLoader.h
   AssetLib/Irr/IRRLoader.h

+ 4 - 3
code/Common/BaseImporter.cpp

@@ -156,8 +156,8 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 /*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem *pIOHandler,
 /*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem *pIOHandler,
         const std::string &pFile,
         const std::string &pFile,
-        const char * const *tokens,
-        unsigned int numTokens,
+        const char **tokens,
+        std::size_t numTokens,
         unsigned int searchBytes /* = 200 */,
         unsigned int searchBytes /* = 200 */,
         bool tokensSol /* false */,
         bool tokensSol /* false */,
         bool noAlphaBeforeTokens /* false */) {
         bool noAlphaBeforeTokens /* false */) {
@@ -268,10 +268,11 @@ std::string BaseImporter::GetExtension(const std::string &file) {
     return ret;
     return ret;
 }
 }
 
 
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Check for magic bytes at the beginning of the file.
 // Check for magic bytes at the beginning of the file.
 /* static */ bool BaseImporter::CheckMagicToken(IOSystem *pIOHandler, const std::string &pFile,
 /* static */ bool BaseImporter::CheckMagicToken(IOSystem *pIOHandler, const std::string &pFile,
-        const void *_magic, unsigned int num, unsigned int offset, unsigned int size) {
+        const void *_magic, std::size_t num, unsigned int offset, unsigned int size) {
     ai_assert(size <= 16);
     ai_assert(size <= 16);
     ai_assert(_magic);
     ai_assert(_magic);
 
 

+ 58 - 16
code/Common/Importer.cpp

@@ -617,29 +617,71 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
             profiler->BeginRegion("total");
             profiler->BeginRegion("total");
         }
         }
 
 
-        // Find an worker class which can handle the file
-        BaseImporter* imp = nullptr;
+        // Find an worker class which can handle the file extension.
+        // Multiple importers may be able to handle the same extension (.xml!); gather them all.
         SetPropertyInteger("importerIndex", -1);
         SetPropertyInteger("importerIndex", -1);
-        for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
+        struct ImporterAndIndex {
+            BaseImporter * importer;
+            unsigned int   index;
+        };
+        std::vector<ImporterAndIndex> possibleImporters;
+        for (unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
+
+            // Every importer has a list of supported extensions.
+            std::set<std::string> extensions;
+            pimpl->mImporter[a]->GetExtensionList(extensions);
+
+            // CAUTION: Do not just search for the extension!
+            // GetExtension() returns the part after the *last* dot, but some extensions have dots
+            // inside them, e.g. ogre.mesh.xml. Compare the entire end of the string.
+            for (std::set<std::string>::const_iterator it = extensions.cbegin(); it != extensions.cend(); ++it) {
+
+                // Yay for C++<20 not having std::string::ends_with()
+                std::string extension = "." + *it;
+                if (extension.length() <= pFile.length()) {
+                    // Possible optimization: Fetch the lowercase filename!
+                    if (0 == ASSIMP_stricmp(pFile.c_str() + pFile.length() - extension.length(), extension.c_str())) {
+                        ImporterAndIndex candidate = { pimpl->mImporter[a], a };
+                        possibleImporters.push_back(candidate);
+                        break;
+                    }
+                }
+
+            }
+
+        }
+
+        // If just one importer supports this extension, pick it and close the case.
+        BaseImporter* imp = nullptr;
+        if (1 == possibleImporters.size()) {
+            imp = possibleImporters[0].importer;
+            SetPropertyInteger("importerIndex", possibleImporters[0].index);
+        }
+        // If multiple importers claim this file extension, ask them to look at the actual file data to decide.
+        // This can happen e.g. with XML (COLLADA vs. Irrlicht).
+        else {
+            for (std::vector<ImporterAndIndex>::const_iterator it = possibleImporters.begin(); it < possibleImporters.end(); ++it) {
+                BaseImporter & importer = *it->importer;
+
+                ASSIMP_LOG_INFO("Found a possible importer: " + std::string(importer.GetInfo()->mName) + "; trying signature-based detection");
+                if (importer.CanRead( pFile, pimpl->mIOHandler, true)) {
+                    imp = &importer;
+                    SetPropertyInteger("importerIndex", it->index);
+                    break;
+                }
 
 
-            if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
-                imp = pimpl->mImporter[a];
-                SetPropertyInteger("importerIndex", a);
-                break;
             }
             }
+
         }
         }
 
 
         if (!imp)   {
         if (!imp)   {
             // not so bad yet ... try format auto detection.
             // not so bad yet ... try format auto detection.
-            const std::string::size_type s = pFile.find_last_of('.');
-            if (s != std::string::npos) {
-                ASSIMP_LOG_INFO("File extension not known, trying signature-based detection");
-                for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
-                    if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
-                        imp = pimpl->mImporter[a];
-                        SetPropertyInteger("importerIndex", a);
-                        break;
-                    }
+            ASSIMP_LOG_INFO("File extension not known, trying signature-based detection");
+            for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
+                if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
+                    imp = pimpl->mImporter[a];
+                    SetPropertyInteger("importerIndex", a);
+                    break;
                 }
                 }
             }
             }
             // Put a proper error message if no suitable importer was found
             // Put a proper error message if no suitable importer was found

+ 6 - 0
code/Common/ImporterRegistry.cpp

@@ -202,6 +202,9 @@ corresponding preprocessor flag to selectively disable formats.
 #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
 #ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
 #include "AssetLib/M3D/M3DImporter.h"
 #include "AssetLib/M3D/M3DImporter.h"
 #endif
 #endif
+#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
+#include "AssetLib/IQM/IQMImporter.h"
+#endif
 
 
 namespace Assimp {
 namespace Assimp {
 
 
@@ -370,6 +373,9 @@ void GetImporterInstanceList(std::vector<BaseImporter *> &out) {
 #endif
 #endif
 #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
 #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
     out.push_back(new MMDImporter());
     out.push_back(new MMDImporter());
+#endif
+#ifndef ASSIMP_BUILD_NO_IQM_IMPORTER
+    out.push_back(new IQMImporter());
 #endif
 #endif
     //#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
     //#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
     //    out.push_back(new StepFile::StepFileImporter());
     //    out.push_back(new StepFile::StepFileImporter());

+ 9 - 14
include/assimp/BaseImporter.h

@@ -95,20 +95,15 @@ public:
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.
     /** Returns whether the class can handle the format of the given file.
      *
      *
-     * The implementation should be as quick as possible. A check for
-     * the file extension is enough. If no suitable loader is found with
-     * this strategy, CanRead() is called again, the 'checkSig' parameter
-     * set to true this time. Now the implementation is expected to
-     * perform a full check of the file structure, possibly searching the
-     * first bytes of the file for magic identifiers or keywords.
+     * The implementation is expected to perform a full check of the file
+     * structure, possibly searching the first bytes of the file for magic
+     * identifiers or keywords.
      *
      *
      * @param pFile Path and file name of the file to be examined.
      * @param pFile Path and file name of the file to be examined.
      * @param pIOHandler The IO handler to use for accessing any file.
      * @param pIOHandler The IO handler to use for accessing any file.
-     * @param checkSig Set to true if this method is called a second time.
-     *   This time, the implementation may take more time to examine the
-     *   contents of the file to be loaded for magic bytes, keywords, etc
-     *   to be able to load files with unknown/not existent file extensions.
-     * @return true if the class can read this file, false if not.
+     * @param checkSig Legacy; do not use.
+     * @return true if the class can read this file, false if not or if
+     * unsure.
      */
      */
     virtual bool CanRead(
     virtual bool CanRead(
             const std::string &pFile,
             const std::string &pFile,
@@ -259,8 +254,8 @@ public: // static utilities
     static bool SearchFileHeaderForToken(
     static bool SearchFileHeaderForToken(
             IOSystem *pIOSystem,
             IOSystem *pIOSystem,
             const std::string &file,
             const std::string &file,
-            const char * const *tokens,
-            unsigned int numTokens,
+            const char **tokens,
+            std::size_t numTokens,
             unsigned int searchBytes = 200,
             unsigned int searchBytes = 200,
             bool tokensSol = false,
             bool tokensSol = false,
             bool noAlphaBeforeTokens = false);
             bool noAlphaBeforeTokens = false);
@@ -305,7 +300,7 @@ public: // static utilities
             IOSystem *pIOHandler,
             IOSystem *pIOHandler,
             const std::string &pFile,
             const std::string &pFile,
             const void *magic,
             const void *magic,
-            unsigned int num,
+            std::size_t num,
             unsigned int offset = 0,
             unsigned int offset = 0,
             unsigned int size = 4);
             unsigned int size = 4);
 
 

+ 2 - 0
include/assimp/defs.h

@@ -331,4 +331,6 @@ static const ai_real ai_epsilon = (ai_real)0.00001;
 #define AI_DEBUG_INVALIDATE_PTR(x)
 #define AI_DEBUG_INVALIDATE_PTR(x)
 #endif
 #endif
 
 
+#define AI_COUNT_OF(X) (sizeof(X) / sizeof((X)[0]))
+
 #endif // !! AI_DEFINES_H_INC
 #endif // !! AI_DEFINES_H_INC

BIN
test/models/IQM/Body.jpg


BIN
test/models/IQM/Head.jpg


BIN
test/models/IQM/mrfixit.iqm