Browse Source

Merge branch 'master' into master

Kim Kulling 2 years ago
parent
commit
b9ea538e6f
60 changed files with 826 additions and 542 deletions
  1. 1 1
      .github/workflows/sanitizer.yml
  2. 2 2
      CMakeLists.txt
  3. 21 5
      code/AssetLib/FBX/FBXConverter.cpp
  4. 6 1
      code/AssetLib/FBX/FBXDocument.h
  5. 1 1
      code/AssetLib/FBX/FBXParser.cpp
  6. 8 2
      code/AssetLib/MDL/MDLLoader.cpp
  7. 1 0
      code/AssetLib/MDL/MDLLoader.h
  8. 4 0
      code/AssetLib/NDO/NDOLoader.cpp
  9. 3 0
      code/AssetLib/glTF2/glTF2Asset.inl
  10. 1 1
      code/AssetLib/glTF2/glTF2Exporter.cpp
  11. 2 1
      code/AssetLib/glTF2/glTF2Importer.cpp
  12. 20 16
      code/CMakeLists.txt
  13. 60 34
      code/Common/BaseImporter.cpp
  14. 3 17
      code/Common/Importer.cpp
  15. 7 2
      contrib/openddlparser/CMakeLists.txt
  16. 16 11
      contrib/openddlparser/README.md
  17. 3 2
      contrib/openddlparser/code/OpenDDLExport.cpp
  18. 44 25
      contrib/openddlparser/code/OpenDDLParser.cpp
  19. 2 2
      contrib/openddlparser/include/openddlparser/OpenDDLCommon.h
  20. 0 9
      contrib/openddlparser/include/openddlparser/OpenDDLParser.h
  21. 8 2
      contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h
  22. 11 1
      include/assimp/BaseImporter.h
  23. 1 0
      include/assimp/postprocess.h
  24. 0 1
      port/swig/DONOTUSEYET
  25. 0 140
      port/swig/assimp.i
  26. 0 2
      port/swig/d/build.sh
  27. 0 4
      port/swig/d/generate.sh
  28. 0 5
      port/swig/interface/DefaultLogger.i
  29. 0 5
      port/swig/interface/IOStream.i
  30. 0 11
      port/swig/interface/IOSystem.i
  31. 0 5
      port/swig/interface/LogStream.i
  32. 0 5
      port/swig/interface/Logger.i
  33. 0 5
      port/swig/interface/NullLogger.i
  34. 0 8
      port/swig/interface/aiAnim.i
  35. 0 5
      port/swig/interface/aiAssert.i
  36. 0 5
      port/swig/interface/aiCamera.i
  37. 0 5
      port/swig/interface/aiColor4D.i
  38. 0 5
      port/swig/interface/aiConfig.i
  39. 0 5
      port/swig/interface/aiDefines.i
  40. 0 5
      port/swig/interface/aiFileIO.i
  41. 0 5
      port/swig/interface/aiLight.i
  42. 0 33
      port/swig/interface/aiMaterial.i
  43. 0 5
      port/swig/interface/aiMatrix3x3.i
  44. 0 5
      port/swig/interface/aiMatrix4x4.i
  45. 0 29
      port/swig/interface/aiMesh.i
  46. 0 7
      port/swig/interface/aiPostProcess.i
  47. 0 5
      port/swig/interface/aiQuaternion.i
  48. 0 17
      port/swig/interface/aiScene.i
  49. 0 5
      port/swig/interface/aiTexture.i
  50. 0 8
      port/swig/interface/aiTypes.i
  51. 0 5
      port/swig/interface/aiVector2D.i
  52. 0 5
      port/swig/interface/aiVector3D.i
  53. 0 5
      port/swig/interface/aiVersion.i
  54. 0 45
      port/swig/interface/assimp.i
  55. 1 1
      test/models/IRR/scenegraphAnim.irr
  56. 554 0
      test/models/IRR/scenegraphAnimMod.irr
  57. BIN
      test/models/IRR/scenegraphAnimMod_UTF16LE.irr
  58. BIN
      test/models/IRR/scenegraphAnim_UTF16LE.irr
  59. 34 0
      test/unit/utImporter.cpp
  60. 12 6
      test/unit/utglTF2ImportExport.cpp

+ 1 - 1
.github/workflows/sanitizer.yml

@@ -46,7 +46,7 @@ jobs:
         CC: clang
     
     - name: configure and build
-      uses: lukka/run-cmake@v2
+      uses: lukka/run-cmake@v3
       with:
         cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
         cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'

+ 2 - 2
CMakeLists.txt

@@ -286,9 +286,9 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW)
 ELSEIF(MSVC)
   # enable multi-core compilation with MSVC
   IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
-    ADD_COMPILE_OPTIONS(/bigobj /W4 /WX )
+    ADD_COMPILE_OPTIONS(/bigobj)
   ELSE() # msvc
-    ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX)
+    ADD_COMPILE_OPTIONS(/MP /bigobj)
   ENDIF()
   
   # disable "elements of array '' will be default initialized" warning on MSVC2013

+ 21 - 5
code/AssetLib/FBX/FBXConverter.cpp

@@ -93,6 +93,8 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
         mSceneOut(out),
         doc(doc),
         mRemoveEmptyBones(removeEmptyBones) {
+
+
     // animations need to be converted first since this will
     // populate the node_anim_chain_bits map, which is needed
     // to determine which nodes need to be generated.
@@ -427,12 +429,26 @@ void FBXConverter::ConvertCamera(const Camera &cam, const std::string &orig_name
     out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
     out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
 
-    out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
-
-    out_camera->mClipPlaneNear = cam.NearPlane();
-    out_camera->mClipPlaneFar = cam.FarPlane();
+    // NOTE: Some software (maya) does not put FieldOfView in FBX, so we compute
+    // mHorizontalFOV from FocalLength and FilmWidth with unit conversion.
+
+    // TODO: This is not a complete solution for how FBX cameras can be stored.
+    // TODO: Incorporate non-square pixel aspect ratio.
+    // TODO: FBX aperture mode might be storing vertical FOV in need of conversion with aspect ratio.
+
+    float fov_deg = cam.FieldOfView();
+    // If FOV not specified in file, compute using FilmWidth and FocalLength.
+    if (fov_deg == kFovUnknown) {
+        float film_width_inches = cam.FilmWidth();
+        float focal_length_mm = cam.FocalLength();
+        ASSIMP_LOG_VERBOSE_DEBUG("FBX FOV unspecified. Computing from FilmWidth (", film_width_inches, "inches) and FocalLength (", focal_length_mm, "mm).");
+        double half_fov_rad = std::atan2(film_width_inches * 25.4 * 0.5, focal_length_mm);
+        out_camera->mHorizontalFOV = static_cast<float>(half_fov_rad);
+    } else {
+        // FBX fov is full-view degrees. We want half-view radians.
+        out_camera->mHorizontalFOV = AI_DEG_TO_RAD(fov_deg) * 0.5f;
+    }
 
-    out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
     out_camera->mClipPlaneNear = cam.NearPlane();
     out_camera->mClipPlaneFar = cam.FarPlane();
 }

+ 6 - 1
code/AssetLib/FBX/FBXDocument.h

@@ -55,9 +55,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define _AI_CONCAT(a,b)  a ## b
 #define  AI_CONCAT(a,b)  _AI_CONCAT(a,b)
 
+
 namespace Assimp {
 namespace FBX {
 
+// Use an 'illegal' default FOV value to detect if the FBX camera has set the FOV.
+static const float kFovUnknown = -1.0f;
+
+
 class Parser;
 class Object;
 struct ImportSettings;
@@ -247,7 +252,7 @@ public:
     fbx_simple_property(FilmAspectRatio, float, 1.0f)
     fbx_simple_property(ApertureMode, int, 0)
 
-    fbx_simple_property(FieldOfView, float, 1.0f)
+    fbx_simple_property(FieldOfView, float, kFovUnknown)
     fbx_simple_property(FocalLength, float, 1.0f)
 };
 

+ 1 - 1
code/AssetLib/FBX/FBXParser.cpp

@@ -211,7 +211,7 @@ Scope::Scope(Parser& parser,bool topLevel)
                 elements.insert(ElementMap::value_type(str, element));
                 return;
             }
-            delete element;
+            delete_Element(element);
             ParseError("unexpected end of file",parser.LastToken());
         } else {
             elements.insert(ElementMap::value_type(str, element));

+ 8 - 2
code/AssetLib/MDL/MDLLoader.cpp

@@ -271,10 +271,16 @@ void MDLImporter::InternReadFile(const std::string &pFile,
     }
 }
 
+// ------------------------------------------------------------------------------------------------
+// Check whether we're still inside the valid file range
+bool MDLImporter::IsPosValid(const void *szPos) const {
+    return szPos && (const unsigned char *)szPos <= this->mBuffer + this->iFileSize && szPos >= this->mBuffer;
+}
+
 // ------------------------------------------------------------------------------------------------
 // Check whether we're still inside the valid file range
 void MDLImporter::SizeCheck(const void *szPos) {
-    if (!szPos || (const unsigned char *)szPos > this->mBuffer + this->iFileSize || szPos < this->mBuffer) {
+    if (!IsPosValid(szPos)) {
         throw DeadlyImportError("Invalid MDL file. The file is too small "
                                 "or contains invalid data.");
     }
@@ -284,7 +290,7 @@ void MDLImporter::SizeCheck(const void *szPos) {
 // Just for debugging purposes
 void MDLImporter::SizeCheck(const void *szPos, const char *szFile, unsigned int iLine) {
     ai_assert(nullptr != szFile);
-    if (!szPos || (const unsigned char *)szPos > mBuffer + iFileSize) {
+    if (!IsPosValid(szPos)) {
         // remove a directory if there is one
         const char *szFilePtr = ::strrchr(szFile, '\\');
         if (!szFilePtr) {

+ 1 - 0
code/AssetLib/MDL/MDLLoader.h

@@ -150,6 +150,7 @@ protected:
     */
     void SizeCheck(const void* szPos);
     void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine);
+    bool IsPosValid(const void* szPos) const;
 
     // -------------------------------------------------------------------
     /** Validate the header data structure of a game studio MDL7 file

+ 4 - 0
code/AssetLib/NDO/NDOLoader.cpp

@@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/importerdesc.h>
 #include <assimp/StreamReader.h>
 #include <map>
+#include <limits>
 
 using namespace Assimp;
 
@@ -160,6 +161,9 @@ void NDOImporter::InternReadFile( const std::string& pFile,
 
         temp = file_format >= 12 ? reader.GetU4() : reader.GetU2();
         head = (const char*)reader.GetPtr();
+        if (std::numeric_limits<unsigned int>::max() - 76 < temp) {
+            throw DeadlyImportError("Invalid name length");
+        }
         reader.IncPtr(temp + 76); /* skip unknown stuff */
 
         obj.name = std::string(head, temp);

+ 3 - 0
code/AssetLib/glTF2/glTF2Asset.inl

@@ -45,6 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/StringUtils.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Base64.hpp>
+#include <rapidjson/document.h>
+#include <rapidjson/schema.h>
+#include <rapidjson/stringbuffer.h>
 
 // clang-format off
 #ifdef ASSIMP_ENABLE_DRACO

+ 1 - 1
code/AssetLib/glTF2/glTF2Exporter.cpp

@@ -730,7 +730,7 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
 
 bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) {
     // Specular requires either/or, default factors of zero disables specular, so do not export
-    if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS || mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) {
+    if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS && mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) {
         return false;
     }
     // The spec states that the default is 1.0 and [1.0, 1.0, 1.0]. We if both are 0, which should disable specular. Otherwise, if one is 0, set to 1.0

+ 2 - 1
code/AssetLib/glTF2/glTF2Importer.cpp

@@ -234,7 +234,8 @@ inline void SetMaterialTextureProperty(std::vector<int> &embeddedTexIdxs, Asset
     SetMaterialTextureProperty(embeddedTexIdxs, r, (glTF2::TextureInfo)prop, mat, texType, texSlot);
 
     if (prop.texture && prop.texture->source) {
-        mat->AddProperty(&prop.strength, 1, AI_MATKEY_GLTF_TEXTURE_STRENGTH(texType, texSlot));
+        std::string textureStrengthKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + "strength";
+        mat->AddProperty(&prop.strength, 1, textureStrengthKey.c_str(), texType, texSlot);
     }
 }
 

+ 20 - 16
code/CMakeLists.txt

@@ -1418,25 +1418,29 @@ if(MSVC AND ASSIMP_INSTALL_PDB)
       COMPILE_PDB_NAME assimp${LIBRARY_SUFFIX}
       COMPILE_PDB_NAME_DEBUG assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}
     )
-  ENDIF()
 
-  IF(CMAKE_GENERATOR MATCHES "^Visual Studio")
-    install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
-      DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
-      CONFIGURATIONS Debug
-    )
-    install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp${LIBRARY_SUFFIX}.pdb
-      DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
-      CONFIGURATIONS RelWithDebInfo
-    )
+    IF(GENERATOR_IS_MULTI_CONFIG)
+      install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
+        DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
+        CONFIGURATIONS Debug
+      )
+      install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp${LIBRARY_SUFFIX}.pdb
+        DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
+        CONFIGURATIONS RelWithDebInfo
+      )
+    ELSE()
+      install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
+        DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
+        CONFIGURATIONS Debug
+      )
+      install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}.pdb
+        DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
+        CONFIGURATIONS RelWithDebInfo
+      )
+    ENDIF()
   ELSE()
-    install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
-      DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
-      CONFIGURATIONS Debug
-    )
-    install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}.pdb
+    install(FILES $<TARGET_PDB_FILE:assimp>
       DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
-      CONFIGURATIONS RelWithDebInfo
     )
   ENDIF()
 ENDIF ()

+ 60 - 34
code/Common/BaseImporter.cpp

@@ -59,6 +59,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <memory>
 #include <sstream>
 
+namespace {
+// Checks whether the passed string is a gcs version.
+bool IsGcsVersion(const std::string &s) {
+    if (s.empty()) return false;
+    return std::all_of(s.cbegin(), s.cend(), [](const char c) {
+        // gcs only permits numeric characters.
+        return std::isdigit(static_cast<int>(c));
+    });
+}
+
+// Removes a possible version hash from a filename, as found for example in
+// gcs uris (e.g. `gs://bucket/model.glb#1234`), see also
+// https://github.com/GoogleCloudPlatform/gsutil/blob/c80f329bc3c4011236c78ce8910988773b2606cb/gslib/storage_url.py#L39.
+std::string StripVersionHash(const std::string &filename) {
+    const std::string::size_type pos = filename.find_last_of('#');
+    // Only strip if the hash is behind a possible file extension and the part
+    // behind the hash is a version string.
+    if (pos != std::string::npos && pos > filename.find_last_of('.') &&
+        IsGcsVersion(filename.substr(pos + 1))) {
+        return filename.substr(0, pos);
+    }
+    return filename;
+}
+}  // namespace
+
 using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
@@ -158,7 +183,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
         std::size_t numTokens,
         unsigned int searchBytes /* = 200 */,
         bool tokensSol /* false */,
-        bool noAlphaBeforeTokens /* false */) {
+        bool noGraphBeforeTokens /* false */) {
     ai_assert(nullptr != tokens);
     ai_assert(0 != numTokens);
     ai_assert(0 != searchBytes);
@@ -207,8 +232,9 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
                 continue;
             }
             // We need to make sure that we didn't accidentally identify the end of another token as our token,
-            // e.g. in a previous version the "gltf " present in some gltf files was detected as "f "
-            if (noAlphaBeforeTokens && (r != buffer && isalpha(static_cast<unsigned char>(r[-1])))) {
+            // e.g. in a previous version the "gltf " present in some gltf files was detected as "f ", or a
+            // Blender-exported glb file containing "Khronos glTF Blender I/O " was detected as "o "
+            if (noGraphBeforeTokens && (r != buffer && isgraph(static_cast<unsigned char>(r[-1])))) {
                 continue;
             }
             // We got a match, either we don't care where it is, or it happens to
@@ -229,33 +255,38 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
         const char *ext0,
         const char *ext1,
         const char *ext2) {
-    std::string::size_type pos = pFile.find_last_of('.');
-
-    // no file extension - can't read
-    if (pos == std::string::npos) {
-        return false;
-    }
-
-    const char *ext_real = &pFile[pos + 1];
-    if (!ASSIMP_stricmp(ext_real, ext0)) {
-        return true;
-    }
-
-    // check for other, optional, file extensions
-    if (ext1 && !ASSIMP_stricmp(ext_real, ext1)) {
-        return true;
+    std::set<std::string> extensions;
+    for (const char* ext : {ext0, ext1, ext2}) {
+        if (ext == nullptr) continue;
+        extensions.emplace(ext);
     }
+    return HasExtension(pFile, extensions);
+}
 
-    if (ext2 && !ASSIMP_stricmp(ext_real, ext2)) {
-        return true;
+// ------------------------------------------------------------------------------------------------
+// Check for file extension
+/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set<std::string> &extensions) {
+    const std::string file = StripVersionHash(pFile);
+    // 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 (const std::string& ext : extensions) {
+        // Yay for C++<20 not having std::string::ends_with()
+        const std::string dotExt = "." + ext;
+        if (dotExt.length() > file.length()) continue;
+        // Possible optimization: Fetch the lowercase filename!
+        if (0 == ASSIMP_stricmp(file.c_str() + file.length() - dotExt.length(), dotExt.c_str())) {
+            return true;
+        }
     }
-
     return false;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Get file extension from path
-std::string BaseImporter::GetExtension(const std::string &file) {
+std::string BaseImporter::GetExtension(const std::string &pFile) {
+    const std::string file = StripVersionHash(pFile);
     std::string::size_type pos = file.find_last_of('.');
 
     // no file extension at all
@@ -281,12 +312,7 @@ std::string BaseImporter::GetExtension(const std::string &file) {
     if (!pIOHandler) {
         return false;
     }
-    union {
-        const char *magic;
-        const uint16_t *magic_u16;
-        const uint32_t *magic_u32;
-    };
-    magic = reinterpret_cast<const char *>(_magic);
+    const char *magic = reinterpret_cast<const char *>(_magic);
     std::unique_ptr<IOStream> pStream(pIOHandler->Open(pFile));
     if (pStream) {
 
@@ -308,15 +334,15 @@ std::string BaseImporter::GetExtension(const std::string &file) {
             // that's just for convenience, the chance that we cause conflicts
             // is quite low and it can save some lines and prevent nasty bugs
             if (2 == size) {
-                uint16_t rev = *magic_u16;
-                ByteSwap::Swap(&rev);
-                if (data_u16[0] == *magic_u16 || data_u16[0] == rev) {
+                uint16_t magic_u16;
+                memcpy(&magic_u16, magic, 2);
+                if (data_u16[0] == magic_u16 || data_u16[0] == ByteSwap::Swapped(magic_u16)) {
                     return true;
                 }
             } else if (4 == size) {
-                uint32_t rev = *magic_u32;
-                ByteSwap::Swap(&rev);
-                if (data_u32[0] == *magic_u32 || data_u32[0] == rev) {
+                uint32_t magic_u32;
+                memcpy(&magic_u32, magic, 4);
+                if (data_u32[0] == magic_u32 || data_u32[0] == ByteSwap::Swapped(magic_u32)) {
                     return true;
                 }
             } else {

+ 3 - 17
code/Common/Importer.cpp

@@ -637,24 +637,10 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
             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 (BaseImporter::HasExtension(pFile, extensions)) {
+                ImporterAndIndex candidate = { pimpl->mImporter[a], a };
+                possibleImporters.push_back(candidate);
             }
-
         }
 
         // If just one importer supports this extension, pick it and close the case.

+ 7 - 2
contrib/openddlparser/CMakeLists.txt

@@ -15,9 +15,11 @@ option( DDL_STATIC_LIBRARY		"Deprecated, use BUILD_SHARED_LIBS instead."
 # for backwards compatibility use DDL_STATIC_LIBRARY as initial value for cmake variable BUILD_SHARED_LIBS
 # https://cmake.org/cmake/help/latest/variable/BUILD_SHARED_LIBS.html
 if ( DDL_STATIC_LIBRARY )
-    set ( build_shared_libs_default OFF )
+  message("Building shared lib.")
+  set ( build_shared_libs_default OFF )
 else()
-    set ( build_shared_libs_default ON )
+  message("Building static lib.")
+  set ( build_shared_libs_default ON )
 endif()
 option( DDL_BUILD_SHARED_LIBS   "Set to ON to build shared libary of OpenDDL Parser."                         ${build_shared_libs_default} )
 option( COVERALLS               "Generate coveralls data"                                                     OFF )
@@ -36,6 +38,7 @@ endif()
 add_definitions( -D_VARIADIC_MAX=10 )
 add_definitions( -DGTEST_HAS_PTHREAD=0 )
 if ( DDL_DEBUG_OUTPUT )
+    message("Enable debug output.")
     add_definitions( -DDDL_DEBUG_HEADER_NAME)
 endif()
 
@@ -62,10 +65,12 @@ if (COVERALLS)
     include(Coveralls)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
+    message("Enable coveralls.")
 endif()
 
 # Include the doc component.
 if(DDL_DOCUMENTATION)
+    message("Generate doxygen documentation.")
     find_package(Doxygen REQUIRED)
     CONFIGURE_FILE( doc/openddlparser_doc.in doc/doxygenfile @ONLY )
     add_custom_target(doc ALL

+ 16 - 11
contrib/openddlparser/README.md

@@ -5,13 +5,15 @@ The OpenDDL-Parser is a small and easy to use library for OpenDDL-file-format-pa
 
 Build status
 ============
-Linux build status: [![Build Status](https://travis-ci.org/kimkulling/openddl-parser.png)](https://travis-ci.org/kimkulling/openddl-parser)
+
+Linux build status: [![Build Status](https://travis-ci.com/kimkulling/openddl-parser.svg?branch=master)](https://travis-ci.com/kimkulling/openddl-parser)
 Current coverity check status:
 <a href="https://scan.coverity.com/projects/5606">
   <img alt="Coverity Scan Build Status"
        src="https://scan.coverity.com/projects/5606/badge.svg"/>
 </a>
 Current test coverage:[![Coverage Status](https://coveralls.io/repos/github/kimkulling/openddl-parser/badge.svg?branch=master)](https://coveralls.io/github/kimkulling/openddl-parser?branch=cpp_coveralls)
+
 Get the source code
 ===================
 You can get the code from our git repository, which is located at GitHub. You can clone the repository with the following command:
@@ -57,11 +59,11 @@ USE_ODDLPARSER_NS;
 
 int main( int argc, char *argv[] ) {
     if( argc < 3 ) {
-        return 1;
+        return Error;
     }
 
     char *filename( nullptr );
-    if( 0 == strncmp( FileOption, argv[ 1 ], strlen( FileOption ) ) ) {
+    if( 0 == strncmp( FileOption, argv[1], strlen( FileOption ) ) ) {
         filename = argv[ 2 ];
     }
     std::cout << "file to import: " << filename << std::endl;   
@@ -73,24 +75,27 @@ int main( int argc, char *argv[] ) {
     FILE *fileStream = fopen( filename, "r+" );
     if( NULL == filename ) {
         std::cerr << "Cannot open file " << filename << std::endl;
-        return 1;
+        return Error;
     }
 
     // obtain file size:
     fseek( fileStream, 0, SEEK_END );
-    const size_t size( ftell( fileStream ) );   
+    const size_t size = ftell( fileStream );   
     rewind( fileStream );   
     if( size > 0 ) {
         char *buffer = new char[ size ];
-        const size_t readSize( fread( buffer, sizeof( char ), size, fileStream ) );
+        const size_t readSize = fread( buffer, sizeof( char ), size, fileStream );
         assert( readSize == size );
+
+        // Set the memory buffer
         OpenDDLParser theParser;
         theParser.setBuffer( buffer, size );
-        const bool result( theParser.parse() );
-        if( !result ) {
+        if( !theParser.parse() ) {
             std::cerr << "Error while parsing file " << filename << "." << std::endl;
+            return Error;
         }
     }
+  
     return 0;
 }
 
@@ -106,9 +111,9 @@ theParser.setBuffer( buffer, size );
 const bool result( theParser.parse() );
 if ( result ) {
     DDLNode *root = theParser.getRoot();
-    DDLNode::DllNodeList childs = root->getChildNodeList();
-    for ( size_t i=0; i<childs.size(); i++ ) {
-        DDLNode *child = childs[ i ];
+    DDLNode::DllNodeList children = root->getChildNodeList();
+    for ( size_t i=0; i<children.size(); i++ ) {
+        DDLNode *child = children[ i ];
         Property *prop   = child->getProperty(); // to get properties
         std::string type = child->getType();     // to get the node type
         Value *values    = child->getValue();    // to get the data;

+ 3 - 2
contrib/openddlparser/code/OpenDDLExport.cpp

@@ -134,9 +134,10 @@ bool OpenDDLExport::writeToStream(const std::string &statement) {
 }
 
 bool OpenDDLExport::writeNode(DDLNode *node, std::string &statement) {
+    bool success(true);
     writeNodeHeader(node, statement);
     if (node->hasProperties()) {
-        writeProperties(node, statement);
+        success = writeProperties(node, statement);
     }
     writeLineEnd(statement);
 
@@ -160,7 +161,7 @@ bool OpenDDLExport::writeNode(DDLNode *node, std::string &statement) {
 
     writeToStream(statement);
 
-    return true;
+    return success;
 }
 
 bool OpenDDLExport::writeNodeHeader(DDLNode *node, std::string &statement) {

+ 44 - 25
contrib/openddlparser/code/OpenDDLParser.cpp

@@ -30,7 +30,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <sstream>
 
 #ifdef _WIN32
-#include <windows.h>
+#   ifndef WIN32_LEAN_AND_MEAN
+#     define WIN32_LEAN_AND_MEAN
+#   endif
+#   include <windows.h>
 #endif // _WIN32
 
 BEGIN_ODDLPARSER_NS
@@ -71,7 +74,7 @@ const char *getTypeToken(Value::ValueType type) {
     return Grammar::PrimitiveTypeToken[(size_t)type];
 }
 
-static void logInvalidTokenError(char *in, const std::string &exp, OpenDDLParser::logCallback callback) {
+static void logInvalidTokenError(const char *in, const std::string &exp, OpenDDLParser::logCallback callback) {
     if (callback) {
         std::string full(in);
         std::string part(full.substr(0, 50));
@@ -338,20 +341,25 @@ char *OpenDDLParser::parseStructure(char *in, char *end) {
 
     bool error(false);
     in = lookForNextToken(in, end);
-    if (*in == *Grammar::OpenBracketToken) {
-        // loop over all children ( data and nodes )
-        do {
-            in = parseStructureBody(in, end, error);
-            if (in == nullptr) {
-                return nullptr;
+    if (in != end) {
+        if (*in == *Grammar::OpenBracketToken) {
+            // loop over all children ( data and nodes )
+            do {
+                in = parseStructureBody(in, end, error);
+                if (in == nullptr) {
+                    return nullptr;
+                }
+            } while (in  != end &&
+                     *in != *Grammar::CloseBracketToken);
+            if (in != end) {
+                ++in;
             }
-        } while (*in != *Grammar::CloseBracketToken);
-        ++in;
-    } else {
-        ++in;
-        logInvalidTokenError(in, std::string(Grammar::OpenBracketToken), m_logCallback);
-        error = true;
-        return nullptr;
+        } else {
+            ++in;
+            logInvalidTokenError(in, std::string(Grammar::OpenBracketToken), m_logCallback);
+            error = true;
+            return nullptr;
+        }
     }
     in = lookForNextToken(in, end);
 
@@ -418,8 +426,8 @@ char *OpenDDLParser::parseStructureBody(char *in, char *end, bool &error) {
         }
 
         in = lookForNextToken(in, end);
-        if (*in != '}') {
-            logInvalidTokenError(in, std::string(Grammar::CloseBracketToken), m_logCallback);
+        if (in == end || *in != '}') {
+            logInvalidTokenError(in == end ? "" : in, std::string(Grammar::CloseBracketToken), m_logCallback);
             return nullptr;
         } else {
             //in++;
@@ -455,7 +463,7 @@ DDLNode *OpenDDLParser::top() {
         return nullptr;
     }
 
-    DDLNode *top(m_stack.back());
+    DDLNode *top = m_stack.back();
     return top;
 }
 
@@ -647,12 +655,15 @@ char *OpenDDLParser::parseBooleanLiteral(char *in, char *end, Value **boolean) {
 
     in = lookForNextToken(in, end);
     char *start(in);
+
+    size_t len(0);
     while (!isSeparator(*in) && in != end) {
         ++in;
+        ++len;
     }
-    int res = ::strncmp(Grammar::BoolTrue, start, strlen(Grammar::BoolTrue));
+    int res = ::strncmp(Grammar::BoolTrue, start, len);
     if (0 != res) {
-        res = ::strncmp(Grammar::BoolFalse, start, strlen(Grammar::BoolFalse));
+        res = ::strncmp(Grammar::BoolFalse, start, len);
         if (0 != res) {
             *boolean = nullptr;
             return in;
@@ -733,7 +744,7 @@ char *OpenDDLParser::parseFloatingLiteral(char *in, char *end, Value **floating,
 
     in = lookForNextToken(in, end);
     char *start(in);
-    while (!isSeparator(*in) && in != end) {
+    while (in != end && !isSeparator(*in)) {
         ++in;
     }
 
@@ -838,6 +849,13 @@ char *OpenDDLParser::parseHexaLiteral(char *in, char *end, Value **data) {
     int value(0);
     while (pos > 0) {
         int v = hex2Decimal(*start);
+        if (v < 0) {
+            while (isEndofLine(*in)) {
+                ++in;
+            }
+            return in;
+        }
+            
         --pos;
         value = (value << 4) | v;
         ++start;
@@ -901,10 +919,10 @@ char *OpenDDLParser::parseDataList(char *in, char *end, Value::ValueType type, V
     }
 
     in = lookForNextToken(in, end);
-    if (*in == '{') {
+    if (in != end && *in == '{') {
         ++in;
         Value *current(nullptr), *prev(nullptr);
-        while ('}' != *in) {
+        while (in != end && '}' != *in) {
             current = nullptr;
             in = lookForNextToken(in, end);
             if (Value::ValueType::ddl_ref == type) {
@@ -962,11 +980,12 @@ char *OpenDDLParser::parseDataList(char *in, char *end, Value::ValueType type, V
             }
 
             in = getNextSeparator(in, end);
-            if (',' != *in && Grammar::CloseBracketToken[0] != *in && !isSpace(*in)) {
+            if (in == end || (',' != *in && Grammar::CloseBracketToken[0] != *in && !isSpace(*in))) {
                 break;
             }
         }
-        ++in;
+        if (in != end)
+            ++in;
     }
 
     return in;

+ 2 - 2
contrib/openddlparser/include/openddlparser/OpenDDLCommon.h

@@ -26,8 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <string>
 #include <vector>
 
-#include <stdio.h>
-#include <string.h>
+#include <cstdio>
+#include <cstring>
 #ifndef _WIN32
 #include <inttypes.h>
 #endif

+ 0 - 9
contrib/openddlparser/include/openddlparser/OpenDDLParser.h

@@ -40,15 +40,6 @@ struct Identifier;
 struct Reference;
 struct Property;
 
-template <class T>
-inline bool isEmbeddedCommentOpenTag(T *in, T *end) {
-    if (in == '/' && in + 1 == '*') {
-        return true;
-    }
-
-    return false;
-}
-
 ///	@brief  Utility function to search for the next token or the end of the buffer.
 /// @param  in      [in] The start position in the buffer.
 /// @param  end     [in] The end position in the buffer.

+ 8 - 2
contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h

@@ -54,7 +54,9 @@ inline bool isSeparator(T in) {
     return false;
 }
 
-static const unsigned char chartype_table[256] = {
+const size_t CharTableSize = 256;
+
+static const unsigned char chartype_table[CharTableSize] = {
     0,
     0,
     0,
@@ -318,6 +320,10 @@ static const unsigned char chartype_table[256] = {
 
 template <class T>
 inline bool isNumeric(const T in) {
+    if (static_cast<size_t>(in) >= CharTableSize) {
+        return '\0';
+    }
+
     size_t idx = static_cast<size_t>(in);
     return idx < sizeof(chartype_table) && (chartype_table[idx] == 1);
 }
@@ -433,7 +439,7 @@ inline bool isEndofLine(const T in) {
 
 template <class T>
 inline static T *getNextSeparator(T *in, T *end) {
-    while (!isSeparator(*in) || in == end) {
+    while (in != end && !isSeparator(*in)) {
         ++in;
     }
     return in;

+ 11 - 1
include/assimp/BaseImporter.h

@@ -259,7 +259,7 @@ public: // static utilities
             std::size_t numTokens,
             unsigned int searchBytes = 200,
             bool tokensSol = false,
-            bool noAlphaBeforeTokens = false);
+            bool noGraphBeforeTokens = false);
 
     // -------------------------------------------------------------------
     /** @brief Check whether a file has a specific file extension
@@ -275,6 +275,16 @@ public: // static utilities
             const char *ext1 = nullptr,
             const char *ext2 = nullptr);
 
+    // -------------------------------------------------------------------
+    /** @brief Check whether a file has one of the passed file extensions
+     *  @param pFile Input file
+     *  @param extensions Extensions to check for. Lowercase characters only, no dot!
+     *  @note Case-insensitive
+     */
+    static bool HasExtension(
+            const std::string &pFile,
+            const std::set<std::string> &extensions);
+
     // -------------------------------------------------------------------
     /** @brief Extract file extension from a string
      *  @param pFile Input file

+ 1 - 0
include/assimp/postprocess.h

@@ -94,6 +94,7 @@ enum aiPostProcessSteps
      * indexed geometry, this step is compulsory or you'll just waste rendering
      * time. <b>If this flag is not specified</b>, no vertices are referenced by
      * more than one face and <b>no index buffer is required</b> for rendering.
+     * Unless the importer (like ply) had to split vertices. Then you need one regardless.
      */
     aiProcess_JoinIdenticalVertices = 0x2,
 

+ 0 - 1
port/swig/DONOTUSEYET

@@ -1 +0,0 @@
-The interface files are by no means complete yet and only work with the not-yet-released D SWIG backend, although adding support for other languages should not be too much of problem via #ifdefs.

+ 0 - 140
port/swig/assimp.i

@@ -1,140 +0,0 @@
-%module assimp
-
-// SWIG helpers for std::string and std::vector wrapping.
-%include <std_string.i>
-%include <std_vector.i>
-
-// Globally enable enum prefix stripping.
-%dstripprefix;
-
-
-// PACK_STRUCT is a no-op for SWIG – it does not matter for the generated
-// bindings how the underlying C++ code manages its memory.
-#define PACK_STRUCT
-
-
-// Helper macros for wrapping the pointer-and-length arrays used in the
-// Assimp API.
-
-%define ASSIMP_ARRAY(CLASS, TYPE, NAME, LENGTH)
-%newobject CLASS::NAME;
-%extend CLASS {
-  std::vector<TYPE > *NAME() const {
-    std::vector<TYPE > *result = new std::vector<TYPE >;
-    result->reserve(LENGTH);
-
-    for (unsigned int i = 0; i < LENGTH; ++i) {
-      result->push_back($self->NAME[i]);
-    }
-
-    return result;
-  }
-}
-%ignore CLASS::NAME;
-%enddef
-
-%define ASSIMP_POINTER_ARRAY(CLASS, TYPE, NAME, LENGTH)
-%newobject CLASS::NAME;
-%extend CLASS {
-  std::vector<TYPE *> *NAME() const {
-    std::vector<TYPE *> *result = new std::vector<TYPE *>;
-    result->reserve(LENGTH);
-
-    TYPE *currentValue = $self->NAME;
-    TYPE *valueLimit = $self->NAME + LENGTH;
-    while (currentValue < valueLimit) {
-      result->push_back(currentValue);
-      ++currentValue;
-    }
-
-    return result;
-  }
-}
-%ignore CLASS::NAME;
-%enddef
-
-%define ASSIMP_POINTER_ARRAY_ARRAY(CLASS, TYPE, NAME, OUTER_LENGTH, INNER_LENGTH)
-%newobject CLASS::NAME;
-%extend CLASS {
-  std::vector<std::vector<TYPE *> > *NAME() const {
-    std::vector<std::vector<TYPE *> > *result = new std::vector<std::vector<TYPE *> >;
-    result->reserve(OUTER_LENGTH);
-
-    for (unsigned int i = 0; i < OUTER_LENGTH; ++i) {
-      std::vector<TYPE *> currentElements;
-
-      if ($self->NAME[i] != 0) {
-        currentElements.reserve(INNER_LENGTH);
-
-        TYPE *currentValue = $self->NAME[i];
-        TYPE *valueLimit = $self->NAME[i] + INNER_LENGTH;
-        while (currentValue < valueLimit) {
-          currentElements.push_back(currentValue);
-          ++currentValue;
-        }
-      }
-
-      result->push_back(currentElements);
-    }
-
-    return result;
-  }
-}
-%ignore CLASS::NAME;
-%enddef
-
-
-%include "interface/aiDefines.i"
-%include "interface/aiTypes.i"
-%include "interface/assimp.i"
-%include "interface/aiTexture.i"
-%include "interface/aiMatrix4x4.i"
-%include "interface/aiMatrix3x3.i"
-%include "interface/aiVector3D.i"
-%include "interface/aiVector2D.i"
-%include "interface/aiColor4D.i"
-%include "interface/aiLight.i"
-%include "interface/aiCamera.i"
-%include "interface/aiFileIO.i"
-%include "interface/aiAssert.i"
-%include "interface/aiVersion.i"
-%include "interface/aiAnim.i"
-%include "interface/aiMaterial.i"
-%include "interface/aiMesh.i"
-%include "interface/aiPostProcess.i"
-%include "interface/aiConfig.i"
-%include "interface/assimp.i"
-%include "interface/aiQuaternion.i"
-%include "interface/aiScene.i"
-%include "interface/Logger.i"
-%include "interface/DefaultLogger.i"
-%include "interface/NullLogger.i"
-%include "interface/LogStream.i"
-%include "interface/IOStream.i"
-%include "interface/IOSystem.i"
-
-
-// We have to "instantiate" the templates used by the ASSSIMP_*_ARRAY macros
-// here at the end to avoid running into forward reference issues (SWIG would
-// spit out the helper functions before the header includes for the element
-// types otherwise).
-
-%template(UintVector) std::vector<unsigned int>;
-%template(aiAnimationVector) std::vector<aiAnimation *>;
-%template(aiAnimMeshVector) std::vector<aiAnimMesh *>;
-%template(aiBonesVector) std::vector<aiBone *>;
-%template(aiCameraVector) std::vector<aiCamera *>;
-%template(aiColor4DVector) std::vector<aiColor4D *>;
-%template(aiColor4DVectorVector) std::vector<std::vector<aiColor4D *> >;
-%template(aiFaceVector) std::vector<aiFace *>;
-%template(aiLightVector) std::vector<aiLight *>;
-%template(aiMaterialVector) std::vector<aiMaterial *>;
-%template(aiMaterialPropertyVector) std::vector<aiMaterialProperty *>;
-%template(aiMeshAnimVector) std::vector<aiMeshAnim *>;
-%template(aiMeshVector) std::vector<aiMesh *>;
-%template(aiNodeVector) std::vector<aiNode *>;
-%template(aiNodeAnimVector) std::vector<aiNodeAnim *>;
-%template(aiTextureVector) std::vector<aiTexture *>;
-%template(aiVector3DVector) std::vector<aiVector3D *>;
-%template(aiVector3DVectorVector) std::vector<std::vector<aiVector3D *> >;
-%template(aiVertexWeightVector) std::vector<aiVertexWeight *>;

+ 0 - 2
port/swig/d/build.sh

@@ -1,2 +0,0 @@
-#!/bin/sh
-gcc -shared -fPIC -g3 -I../../../include/ -lassimp -olibassimp_wrap.so assimp_wrap.cxx

+ 0 - 4
port/swig/d/generate.sh

@@ -1,4 +0,0 @@
-#!/bin/sh
-rm -rf assimp/
-mkdir assimp
-swig -c++ -d -outcurrentdir -I../../../include -splitproxy -package assimp $@ ../assimp.i

+ 0 - 5
port/swig/interface/DefaultLogger.i

@@ -1,5 +0,0 @@
-%{
-#include "DefaultLogger.h"
-%}
-
-%include "DefaultLogger.h"

+ 0 - 5
port/swig/interface/IOStream.i

@@ -1,5 +0,0 @@
-%{
-#include "IOStream.h"
-%}
-
-%include "IOStream.h"

+ 0 - 11
port/swig/interface/IOSystem.i

@@ -1,11 +0,0 @@
-%{
-#include "IOSystem.h"
-%}
-
-// The const char* overload is used instead.
-%ignore Assimp::IOSystem::Exists(const std::string&) const;
-%ignore Assimp::IOSystem::Open(const std::string& pFile);
-%ignore Assimp::IOSystem::Open(const std::string& pFile, const std::string& pMode);
-%ignore Assimp::IOSystem::ComparePaths(const std::string& one, const std::string& second) const;
-
-%include "IOSystem.h"

+ 0 - 5
port/swig/interface/LogStream.i

@@ -1,5 +0,0 @@
-%{
-#include "LogStream.h"
-%}
-
-%include "LogStream.h"

+ 0 - 5
port/swig/interface/Logger.i

@@ -1,5 +0,0 @@
-%{
-#include "Logger.h"
-%}
-
-%include "Logger.h"

+ 0 - 5
port/swig/interface/NullLogger.i

@@ -1,5 +0,0 @@
-%{
-#include "NullLogger.h"
-%}
-
-%include "NullLogger.h"

+ 0 - 8
port/swig/interface/aiAnim.i

@@ -1,8 +0,0 @@
-%{
-#include "aiAnim.h"
-%}
-
-ASSIMP_ARRAY(aiAnimation, aiNodeAnim*, mChannels, $self->mNumChannels);
-ASSIMP_ARRAY(aiAnimation, aiMeshAnim*, mMeshChannels, $self->mNumMeshChannels);
-
-%include "aiAnim.h"

+ 0 - 5
port/swig/interface/aiAssert.i

@@ -1,5 +0,0 @@
-%{
-#include "aiAssert.h"
-%}
-
-%include "aiAssert.h"

+ 0 - 5
port/swig/interface/aiCamera.i

@@ -1,5 +0,0 @@
-%{
-#include "aiCamera.h"
-%}
-
-%include "aiCamera.h"

+ 0 - 5
port/swig/interface/aiColor4D.i

@@ -1,5 +0,0 @@
-%{
-#include "aiColor4D.h"
-%}
-
-%include "aiColor4D.h"

+ 0 - 5
port/swig/interface/aiConfig.i

@@ -1,5 +0,0 @@
-%{
-#include "aiConfig.h"
-%}
-
-%include "aiConfig.h"

+ 0 - 5
port/swig/interface/aiDefines.i

@@ -1,5 +0,0 @@
-%{
-#include "aiDefines.h"
-%}
-
-%include "aiDefines.h"

+ 0 - 5
port/swig/interface/aiFileIO.i

@@ -1,5 +0,0 @@
-%{
-#include "aiFileIO.h"
-%}
-
-%include "aiFileIO.h"

+ 0 - 5
port/swig/interface/aiLight.i

@@ -1,5 +0,0 @@
-%{
-#include "aiLight.h"
-%}
-
-%include "aiLight.h"

+ 0 - 33
port/swig/interface/aiMaterial.i

@@ -1,33 +0,0 @@
-%{
-#include "aiMaterial.h"
-%}
-
-ASSIMP_ARRAY(aiMaterial, aiMaterialProperty*, mProperties, $self->mNumProperties)
-
-%include <typemaps.i>
-%apply enum SWIGTYPE *OUTPUT { aiTextureMapping* mapping };
-%apply unsigned int *OUTPUT { unsigned int* uvindex };
-%apply float *OUTPUT { float* blend };
-%apply enum SWIGTYPE *OUTPUT { aiTextureOp* op };
-%apply unsigned int *OUTPUT { unsigned int* flags };
-
-%include "aiMaterial.h"
-
-%clear unsigned int* flags;
-%clear aiTextureOp* op;
-%clear float *blend;
-%clear unsigned int* uvindex;
-%clear aiTextureMapping* mapping;
-
-
-%apply int &OUTPUT { int &pOut };
-%apply float &OUTPUT { float &pOut };
-
-%template(GetInteger) aiMaterial::Get<int>;
-%template(GetFloat) aiMaterial::Get<float>;
-%template(GetColor4D) aiMaterial::Get<aiColor4D>;
-%template(GetColor3D) aiMaterial::Get<aiColor3D>;
-%template(GetString) aiMaterial::Get<aiString>;
-
-%clear int &pOut;
-%clear float &pOut;

+ 0 - 5
port/swig/interface/aiMatrix3x3.i

@@ -1,5 +0,0 @@
-%{
-#include "aiMatrix3x3.h"
-%}
-
-%include "aiMatrix3x3.h"

+ 0 - 5
port/swig/interface/aiMatrix4x4.i

@@ -1,5 +0,0 @@
-%{
-#include "aiMatrix4x4.h"
-%}
-
-%include "aiMatrix4x4.h"

+ 0 - 29
port/swig/interface/aiMesh.i

@@ -1,29 +0,0 @@
-%{
-#include "aiMesh.h"
-%}
-
-
-ASSIMP_ARRAY(aiFace, unsigned int, mIndices, $self->mNumIndices);
-
-ASSIMP_POINTER_ARRAY(aiBone, aiVertexWeight, mWeights, $self->mNumWeights);
-
-ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mVertices, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mNormals, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mTangents, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mBitangents, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices);
-
-ASSIMP_ARRAY(aiMesh, aiAnimMesh*, mAnimMeshes, $self->mNumAnimMeshes);
-ASSIMP_ARRAY(aiMesh, aiBone*, mBones, $self->mNumBones);
-ASSIMP_ARRAY(aiMesh, unsigned int, mNumUVComponents, AI_MAX_NUMBER_OF_TEXTURECOORDS);
-ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mVertices, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mNormals, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mTangents, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mBitangents, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY(aiMesh, aiFace, mFaces, $self->mNumFaces);
-ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices);
-ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices);
-
-
-%include "aiMesh.h"

+ 0 - 7
port/swig/interface/aiPostProcess.i

@@ -1,7 +0,0 @@
-%{
-#include "aiPostProcess.h"
-%}
-
-%feature("d:stripprefix", "aiProcess_") aiPostProcessSteps;
-
-%include "aiPostProcess.h"

+ 0 - 5
port/swig/interface/aiQuaternion.i

@@ -1,5 +0,0 @@
-%{
-#include "aiQuaternion.h"
-%}
-
-%include "aiQuaternion.h"

+ 0 - 17
port/swig/interface/aiScene.i

@@ -1,17 +0,0 @@
-%{
-#include "aiScene.h"
-%}
-
-
-ASSIMP_ARRAY(aiScene, aiAnimation*, mAnimations, $self->mNumAnimations);
-ASSIMP_ARRAY(aiScene, aiCamera*, mCameras, $self->mNumCameras);
-ASSIMP_ARRAY(aiScene, aiLight*, mLights, $self->mNumLights);
-ASSIMP_ARRAY(aiScene, aiMaterial*, mMaterials, $self->mNumMaterials);
-ASSIMP_ARRAY(aiScene, aiMesh*, mMeshes, $self->mNumMeshes);
-ASSIMP_ARRAY(aiScene, aiTexture*, mTextures, $self->mNumTextures);
-
-ASSIMP_ARRAY(aiNode, aiNode*, mChildren, $self->mNumChildren);
-ASSIMP_ARRAY(aiNode, unsigned int, mMeshes, $self->mNumMeshes);
-
-
-%include "aiScene.h"

+ 0 - 5
port/swig/interface/aiTexture.i

@@ -1,5 +0,0 @@
-%{
-#include "aiTexture.h"
-%}
-
-%include "aiTexture.h"

+ 0 - 8
port/swig/interface/aiTypes.i

@@ -1,8 +0,0 @@
-%{
-#include "aiTypes.h"
-%}
-
-// The const char* overload is used instead.
-%ignore aiString::Set(const std::string& pString);
-
-%include "aiTypes.h"

+ 0 - 5
port/swig/interface/aiVector2D.i

@@ -1,5 +0,0 @@
-%{
-#include "aiVector2D.h"
-%}
-
-%include "aiVector2D.h"

+ 0 - 5
port/swig/interface/aiVector3D.i

@@ -1,5 +0,0 @@
-%{
-#include "aiVector3D.h"
-%}
-
-%include "aiVector3D.h"

+ 0 - 5
port/swig/interface/aiVersion.i

@@ -1,5 +0,0 @@
-%{
-#include "aiVersion.h"
-%}
-
-%include "aiVersion.h"

+ 0 - 45
port/swig/interface/assimp.i

@@ -1,45 +0,0 @@
-%{
-#include "assimp.hpp"
-%}
-
-
-namespace Assimp {
-
-// See docs in assimp.hpp.
-%ignore Importer::ReadFile(const std::string& pFile, unsigned int pFlags);
-%ignore Importer::GetExtensionList(std::string& szOut);
-%ignore Importer::IsExtensionSupported(const std::string& szExtension);
-
-// These are only necessary for extending Assimp with custom importers or post
-// processing steps, which would require wrapping the internal BaseImporter and
-// BaseProcess classes.
-%ignore Importer::RegisterLoader(BaseImporter* pImp);
-%ignore Importer::UnregisterLoader(BaseImporter* pImp);
-%ignore Importer::RegisterPPStep(BaseProcess* pImp);
-%ignore Importer::UnregisterPPStep(BaseProcess* pImp);
-%ignore Importer::FindLoader(const char* szExtension);
-
-}
-
-
-// Each aiScene has to keep a reference to the Importer to prevent it from
-// being garbage collected, whose destructor would release the underlying
-// C++ memory the scene is stored in.
-%typemap(dcode) aiScene "package Object m_importer;"
-%typemap(dout)
-    aiScene* GetScene,
-    aiScene* ReadFile,
-    aiScene* ApplyPostProcessing,
-    aiScene* ReadFileFromMemory {
-  void* cPtr = $wcall;
-  $dclassname ret = (cPtr is null) ? null : new $dclassname(cPtr, $owner);$excode
-  ret.m_importer = this;
-  return ret;
-}
-
-%include <typemaps.i>
-%apply bool *OUTPUT { bool *bWasExisting };
-
-%include "assimp.hpp"
-
-%clear bool *bWasExisting;

+ 1 - 1
test/models/IRR/scenegraphAnim.irr

@@ -126,7 +126,7 @@
 					<float name="Shininess" value="0.000000" />
 					<float name="Param1" value="0.000000" />
 					<float name="Param2" value="0.000000" />
-					<texture name="Texture1" value="="UVTransformTestImg.png" />
+					<texture name="Texture1" value="UVTransformTestImg.png" />
 					<texture name="Texture2" value="" />
 					<texture name="Texture3" value="" />
 					<texture name="Texture4" value="" />

+ 554 - 0
test/models/IRR/scenegraphAnimMod.irr

@@ -0,0 +1,554 @@
+<?xml version="1.0"?>
+<irr_scene>
+
+	<attributes>
+		<string name="Name" value="root" />
+		<int name="Id" value="-1" />
+		<colorf name="AmbientLight" value="0.000000, 0.000000, 0.000000, 0.000000" />
+	</attributes>
+
+	<node type="camera">
+
+		<attributes>
+			<string name="Name" value="" />
+			<int name="Id" value="-1" />
+			<vector3d name="Position" value="3.333332, 1.666666, -3.333332" />
+			<vector3d name="Rotation" value="14426.697266, 0.000000, 0.000000" />
+			<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
+			<bool name="Visible" value="true" />
+			<enum name="AutomaticCulling" value="box" />
+			<int name="DebugDataVisible" value="-1" />
+			<bool name="IsDebugObject" value="false" />
+			<vector3d name="Target" value="0.000000, 0.000000, 100.000000" />
+			<vector3d name="UpVector" value="0.000000, 1.000000, 0.000000" />
+			<float name="Fovy" value="1.256637" />
+			<float name="Aspect" value="1.333333" />
+			<float name="ZNear" value="1.000000" />
+			<float name="ZFar" value="3000.000000" />
+		</attributes>
+
+<!--		<animators>-->
+<!--			<attributes>-->
+<!--				<string name="Type" value="rotation" />-->
+<!--				<vector3d name="Rotation" value="0.200000, 0.000000, 0.000000" />-->
+<!--			</attributes>-->
+<!--		</animators>-->
+	</node>
+
+	<node type="light">
+
+		<attributes>
+			<string name="Name" value="SpotLightAnim" />
+			<int name="Id" value="-1" />
+			<vector3d name="Position" value="3.333332, 1.666666, -3.333332" />
+			<vector3d name="Rotation" value="15721.575195, 37111.304688, 29682.550781" />
+			<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
+			<bool name="Visible" value="true" />
+			<enum name="AutomaticCulling" value="box" />
+			<int name="DebugDataVisible" value="-1" />
+			<bool name="IsDebugObject" value="false" />
+			<colorf name="AmbientColor" value="0.000000, 0.000000, 0.000000, 1.000000" />
+			<colorf name="DiffuseColor" value="1.000000, 1.000000, 1.000000, 1.000000" />
+			<colorf name="SpecularColor" value="1.000000, 1.000000, 1.000000, 1.000000" />
+			<float name="Radius" value="100.000000" />
+			<bool name="CastShadows" value="true" />
+			<enum name="LightType" value="Spot" />
+		</attributes>
+
+<!--		<animators>-->
+<!--			<attributes>-->
+<!--				<string name="Type" value="rotation" />-->
+<!--				<vector3d name="Rotation" value="0.200000, 0.500000, 0.400000" />-->
+<!--			</attributes>-->
+<!--		</animators>-->
+	</node>
+
+	<node type="light">
+
+		<attributes>
+			<string name="Name" value="PointLight" />
+			<int name="Id" value="-1" />
+			<vector3d name="Position" value="3.333332, 1.666666, -3.333332" />
+			<vector3d name="Rotation" value="0.000000, 0.000000, 0.000000" />
+			<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
+			<bool name="Visible" value="true" />
+			<enum name="AutomaticCulling" value="box" />
+			<int name="DebugDataVisible" value="-1" />
+			<bool name="IsDebugObject" value="false" />
+			<colorf name="AmbientColor" value="0.000000, 0.000000, 0.000000, 1.000000" />
+			<colorf name="DiffuseColor" value="1.000000, 1.000000, 1.000000, 1.000000" />
+			<colorf name="SpecularColor" value="1.000000, 1.000000, 1.000000, 1.000000" />
+			<float name="Radius" value="100.000000" />
+			<bool name="CastShadows" value="true" />
+			<enum name="LightType" value="Point" />
+		</attributes>
+
+	</node>
+
+	<node type="empty">
+
+		<attributes>
+			<string name="Name" value="ChildOfRoot" />
+			<int name="Id" value="-1" />
+			<vector3d name="Position" value="18.573780, 14.000406, -10.178408" />
+			<vector3d name="Rotation" value="0.000000, 0.000000, 0.000000" />
+			<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
+			<bool name="Visible" value="true" />
+			<enum name="AutomaticCulling" value="false" />
+			<int name="DebugDataVisible" value="0" />
+			<bool name="IsDebugObject" value="false" />
+		</attributes>
+
+		<node type="sphere">
+
+			<attributes>
+				<string name="Name" value="Sphere_ChildOfDummy" />
+				<int name="Id" value="-1" />
+				<vector3d name="Position" value="22.607138, 0.000000, -19.720987" />
+				<vector3d name="Rotation" value="0.000000, 0.000000, 0.000000" />
+				<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
+				<bool name="Visible" value="true" />
+				<enum name="AutomaticCulling" value="box" />
+				<int name="DebugDataVisible" value="0" />
+				<bool name="IsDebugObject" value="false" />
+				<float name="Radius" value="5.000000" />
+				<int name="PolyCountX" value="16" />
+				<int name="PolyCountY" value="16" />
+			</attributes>
+
+			<materials>
+				<attributes>
+					<enum name="Type" value="solid" />
+					<color name="Ambient" value="ffffffff" />
+					<color name="Diffuse" value="ffffffff" />
+					<color name="Emissive" value="00000000" />
+					<color name="Specular" value="ffffffff" />
+					<float name="Shininess" value="0.000000" />
+					<float name="Param1" value="0.000000" />
+					<float name="Param2" value="0.000000" />
+					<texture name="Texture1" value="UVTransformTestImg.png" />
+					<texture name="Texture2" value="" />
+					<texture name="Texture3" value="" />
+					<texture name="Texture4" value="" />
+					<bool name="Wireframe" value="false" />
+					<bool name="GouraudShading" value="true" />
+					<bool name="Lighting" value="false" />
+					<bool name="ZWriteEnable" value="true" />
+					<int name="ZBuffer" value="1" />
+					<bool name="BackfaceCulling" value="true" />
+					<bool name="FogEnable" value="false" />
+					<bool name="NormalizeNormals" value="false" />
+					<bool name="BilinearFilter1" value="true" />
+					<bool name="BilinearFilter2" value="true" />
+					<bool name="BilinearFilter3" value="true" />
+					<bool name="BilinearFilter4" value="true" />
+					<bool name="TrilinearFilter1" value="false" />
+					<bool name="TrilinearFilter2" value="false" />
+					<bool name="TrilinearFilter3" value="false" />
+					<bool name="TrilinearFilter4" value="false" />
+					<bool name="AnisotropicFilter1" value="false" />
+					<bool name="AnisotropicFilter2" value="false" />
+					<bool name="AnisotropicFilter3" value="false" />
+					<bool name="AnisotropicFilter4" value="false" />
+					<enum name="TextureWrap1" value="texture_clamp_repeat" />
+					<enum name="TextureWrap2" value="texture_clamp_repeat" />
+					<enum name="TextureWrap3" value="texture_clamp_repeat" />
+					<enum name="TextureWrap4" value="texture_clamp_repeat" />
+				</attributes>
+			</materials>
+			<animators>
+				<attributes>
+					<string name="Type" value="flyCircle" />
+					<vector3d name="Center" value="0.000000, 0.000000, 0.000000" />
+					<float name="Radius" value="30.000000" />
+					<float name="Speed" value="0.001000" />
+					<vector3d name="Direction" value="0.000000, 1.000000, 0.000000" />
+				</attributes>
+			</animators>
+			<node type="empty">
+
+				<attributes>
+					<string name="Name" value="ChildOfSphere" />
+					<int name="Id" value="-1" />
+					<vector3d name="Position" value="18.573780, 14.000406, -10.178408" />
+					<vector3d name="Rotation" value="0.000000, 0.000000, 0.000000" />
+					<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
+					<bool name="Visible" value="true" />
+					<enum name="AutomaticCulling" value="false" />
+					<int name="DebugDataVisible" value="0" />
+					<bool name="IsDebugObject" value="false" />
+				</attributes>
+
+			</node>
+
+		</node>
+
+	</node>
+
+	<node type="animatedMesh">
+
+		<attributes>
+			<string name="Name" value="" />
+			<int name="Id" value="-1" />
+			<vector3d name="Position" value="18.573780, 14.000406, -10.178408" />
+			<vector3d name="Rotation" value="0.000000, 0.000000, 0.000000" />
+			<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
+			<bool name="Visible" value="true" />
+			<enum name="AutomaticCulling" value="box" />
+			<int name="DebugDataVisible" value="0" />
+			<bool name="IsDebugObject" value="false" />
+			<string name="Mesh" value="dwarf.x" />
+			<bool name="Looping" value="true" />
+			<bool name="ReadOnlyMaterials" value="false" />
+			<float name="FramesPerSecond" value="0.025000" />
+		</attributes>
+
+		<materials>
+			<attributes>
+				<enum name="Type" value="solid" />
+				<color name="Ambient" value="ffffffff" />
+				<color name="Diffuse" value="ffcccccc" />
+				<color name="Emissive" value="ff5d5d5d" />
+				<color name="Specular" value="ff000000" />
+				<float name="Shininess" value="0.000000" />
+				<float name="Param1" value="0.000000" />
+				<float name="Param2" value="0.000000" />
+				<texture name="Texture1" value="axe.jpg" />
+				<texture name="Texture2" value="" />
+				<texture name="Texture3" value="" />
+				<texture name="Texture4" value="" />
+				<bool name="Wireframe" value="false" />
+				<bool name="GouraudShading" value="true" />
+				<bool name="Lighting" value="false" />
+				<bool name="ZWriteEnable" value="true" />
+				<int name="ZBuffer" value="1" />
+				<bool name="BackfaceCulling" value="true" />
+				<bool name="FogEnable" value="false" />
+				<bool name="NormalizeNormals" value="false" />
+				<bool name="BilinearFilter1" value="true" />
+				<bool name="BilinearFilter2" value="true" />
+				<bool name="BilinearFilter3" value="true" />
+				<bool name="BilinearFilter4" value="true" />
+				<bool name="TrilinearFilter1" value="false" />
+				<bool name="TrilinearFilter2" value="false" />
+				<bool name="TrilinearFilter3" value="false" />
+				<bool name="TrilinearFilter4" value="false" />
+				<bool name="AnisotropicFilter1" value="false" />
+				<bool name="AnisotropicFilter2" value="false" />
+				<bool name="AnisotropicFilter3" value="false" />
+				<bool name="AnisotropicFilter4" value="false" />
+				<enum name="TextureWrap1" value="texture_clamp_repeat" />
+				<enum name="TextureWrap2" value="texture_clamp_repeat" />
+				<enum name="TextureWrap3" value="texture_clamp_repeat" />
+				<enum name="TextureWrap4" value="texture_clamp_repeat" />
+			</attributes>
+			<attributes>
+				<enum name="Type" value="solid" />
+				<color name="Ambient" value="ffffffff" />
+				<color name="Diffuse" value="ffcccccc" />
+				<color name="Emissive" value="ff4d4d4d" />
+				<color name="Specular" value="ff000000" />
+				<float name="Shininess" value="0.000000" />
+				<float name="Param1" value="0.000000" />
+				<float name="Param2" value="0.000000" />
+				<texture name="Texture1" value="dwarf.jpg" />
+				<texture name="Texture2" value="" />
+				<texture name="Texture3" value="" />
+				<texture name="Texture4" value="" />
+				<bool name="Wireframe" value="false" />
+				<bool name="GouraudShading" value="true" />
+				<bool name="Lighting" value="false" />
+				<bool name="ZWriteEnable" value="true" />
+				<int name="ZBuffer" value="1" />
+				<bool name="BackfaceCulling" value="true" />
+				<bool name="FogEnable" value="false" />
+				<bool name="NormalizeNormals" value="false" />
+				<bool name="BilinearFilter1" value="true" />
+				<bool name="BilinearFilter2" value="true" />
+				<bool name="BilinearFilter3" value="true" />
+				<bool name="BilinearFilter4" value="true" />
+				<bool name="TrilinearFilter1" value="false" />
+				<bool name="TrilinearFilter2" value="false" />
+				<bool name="TrilinearFilter3" value="false" />
+				<bool name="TrilinearFilter4" value="false" />
+				<bool name="AnisotropicFilter1" value="false" />
+				<bool name="AnisotropicFilter2" value="false" />
+				<bool name="AnisotropicFilter3" value="false" />
+				<bool name="AnisotropicFilter4" value="false" />
+				<enum name="TextureWrap1" value="texture_clamp_repeat" />
+				<enum name="TextureWrap2" value="texture_clamp_repeat" />
+				<enum name="TextureWrap3" value="texture_clamp_repeat" />
+				<enum name="TextureWrap4" value="texture_clamp_repeat" />
+			</attributes>
+			<attributes>
+				<enum name="Type" value="solid" />
+				<color name="Ambient" value="ffffffff" />
+				<color name="Diffuse" value="ffcccccc" />
+				<color name="Emissive" value="ff505050" />
+				<color name="Specular" value="ff000000" />
+				<float name="Shininess" value="0.000000" />
+				<float name="Param1" value="0.000000" />
+				<float name="Param2" value="0.000000" />
+				<texture name="Texture1" value="" />
+				<texture name="Texture2" value="" />
+				<texture name="Texture3" value="" />
+				<texture name="Texture4" value="" />
+				<bool name="Wireframe" value="false" />
+				<bool name="GouraudShading" value="true" />
+				<bool name="Lighting" value="false" />
+				<bool name="ZWriteEnable" value="true" />
+				<int name="ZBuffer" value="1" />
+				<bool name="BackfaceCulling" value="true" />
+				<bool name="FogEnable" value="false" />
+				<bool name="NormalizeNormals" value="false" />
+				<bool name="BilinearFilter1" value="true" />
+				<bool name="BilinearFilter2" value="true" />
+				<bool name="BilinearFilter3" value="true" />
+				<bool name="BilinearFilter4" value="true" />
+				<bool name="TrilinearFilter1" value="false" />
+				<bool name="TrilinearFilter2" value="false" />
+				<bool name="TrilinearFilter3" value="false" />
+				<bool name="TrilinearFilter4" value="false" />
+				<bool name="AnisotropicFilter1" value="false" />
+				<bool name="AnisotropicFilter2" value="false" />
+				<bool name="AnisotropicFilter3" value="false" />
+				<bool name="AnisotropicFilter4" value="false" />
+				<enum name="TextureWrap1" value="texture_clamp_repeat" />
+				<enum name="TextureWrap2" value="texture_clamp_repeat" />
+				<enum name="TextureWrap3" value="texture_clamp_repeat" />
+				<enum name="TextureWrap4" value="texture_clamp_repeat" />
+			</attributes>
+		</materials>
+	</node>
+
+	<node type="mesh">
+
+		<attributes>
+			<string name="Name" value="" />
+			<int name="Id" value="-1" />
+			<vector3d name="Position" value="42.392685, 54.034889, -80.052681" />
+			<vector3d name="Rotation" value="0.000000, 0.000000, 0.000000" />
+			<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
+			<bool name="Visible" value="true" />
+			<enum name="AutomaticCulling" value="box" />
+			<int name="DebugDataVisible" value="0" />
+			<bool name="IsDebugObject" value="false" />
+			<string name="Mesh" value="cellar.irrmesh" />
+			<bool name="ReadOnlyMaterials" value="false" />
+		</attributes>
+
+		<materials>
+			<attributes>
+				<enum name="Type" value="lightmap_m4" />
+				<color name="Ambient" value="ffffffff" />
+				<color name="Diffuse" value="ffffffff" />
+				<color name="Emissive" value="00000000" />
+				<color name="Specular" value="ffffffff" />
+				<float name="Shininess" value="0.750000" />
+				<float name="Param1" value="0.000000" />
+				<float name="Param2" value="0.000000" />
+				<texture name="Texture1" value="brownground_1-1.jpg" />
+				<texture name="Texture2" value="1.png" />
+				<texture name="Texture3" value="" />
+				<texture name="Texture4" value="" />
+				<bool name="Wireframe" value="false" />
+				<bool name="GouraudShading" value="true" />
+				<bool name="Lighting" value="false" />
+				<bool name="ZWriteEnable" value="true" />
+				<int name="ZBuffer" value="1" />
+				<bool name="BackfaceCulling" value="true" />
+				<bool name="FogEnable" value="false" />
+				<bool name="NormalizeNormals" value="false" />
+				<bool name="BilinearFilter1" value="true" />
+				<bool name="BilinearFilter2" value="true" />
+				<bool name="BilinearFilter3" value="true" />
+				<bool name="BilinearFilter4" value="true" />
+				<bool name="TrilinearFilter1" value="false" />
+				<bool name="TrilinearFilter2" value="false" />
+				<bool name="TrilinearFilter3" value="false" />
+				<bool name="TrilinearFilter4" value="false" />
+				<bool name="AnisotropicFilter1" value="false" />
+				<bool name="AnisotropicFilter2" value="false" />
+				<bool name="AnisotropicFilter3" value="false" />
+				<bool name="AnisotropicFilter4" value="false" />
+				<enum name="TextureWrap1" value="texture_clamp_repeat" />
+				<enum name="TextureWrap2" value="texture_clamp_repeat" />
+				<enum name="TextureWrap3" value="texture_clamp_repeat" />
+				<enum name="TextureWrap4" value="texture_clamp_repeat" />
+			</attributes>
+			<attributes>
+				<enum name="Type" value="lightmap_m4" />
+				<color name="Ambient" value="ffdfdfdf" />
+				<color name="Diffuse" value="ffdfdfdf" />
+				<color name="Emissive" value="00000000" />
+				<color name="Specular" value="ffffffff" />
+				<float name="Shininess" value="0.750000" />
+				<float name="Param1" value="0.000000" />
+				<float name="Param2" value="0.000000" />
+				<texture name="Texture1" value="crackedground_1-6.jpg" />
+				<texture name="Texture2" value="1.png" />
+				<texture name="Texture3" value="" />
+				<texture name="Texture4" value="" />
+				<bool name="Wireframe" value="false" />
+				<bool name="GouraudShading" value="true" />
+				<bool name="Lighting" value="false" />
+				<bool name="ZWriteEnable" value="true" />
+				<int name="ZBuffer" value="1" />
+				<bool name="BackfaceCulling" value="true" />
+				<bool name="FogEnable" value="false" />
+				<bool name="NormalizeNormals" value="false" />
+				<bool name="BilinearFilter1" value="true" />
+				<bool name="BilinearFilter2" value="true" />
+				<bool name="BilinearFilter3" value="true" />
+				<bool name="BilinearFilter4" value="true" />
+				<bool name="TrilinearFilter1" value="false" />
+				<bool name="TrilinearFilter2" value="false" />
+				<bool name="TrilinearFilter3" value="false" />
+				<bool name="TrilinearFilter4" value="false" />
+				<bool name="AnisotropicFilter1" value="false" />
+				<bool name="AnisotropicFilter2" value="false" />
+				<bool name="AnisotropicFilter3" value="false" />
+				<bool name="AnisotropicFilter4" value="false" />
+				<enum name="TextureWrap1" value="texture_clamp_repeat" />
+				<enum name="TextureWrap2" value="texture_clamp_repeat" />
+				<enum name="TextureWrap3" value="texture_clamp_repeat" />
+				<enum name="TextureWrap4" value="texture_clamp_repeat" />
+			</attributes>
+		</materials>
+	</node>
+
+	<node type="cube">
+
+		<attributes>
+			<string name="Name" value="JumpingCube" />
+			<int name="Id" value="-1" />
+			<vector3d name="Position" value="16.565477, 21.458202, 15.451395" />
+			<vector3d name="Rotation" value="0.000000, 0.000000, 0.000000" />
+			<vector3d name="Scale" value="1.000000, 1.000000, 1.000000" />
+			<bool name="Visible" value="true" />
+			<enum name="AutomaticCulling" value="box" />
+			<int name="DebugDataVisible" value="0" />
+			<bool name="IsDebugObject" value="false" />
+			<float name="Size" value="10.000000" />
+		</attributes>
+
+		<materials>
+			<attributes>
+				<enum name="Type" value="solid" />
+				<color name="Ambient" value="ffffffff" />
+				<color name="Diffuse" value="ffffffff" />
+				<color name="Emissive" value="00000000" />
+				<color name="Specular" value="ffffffff" />
+				<float name="Shininess" value="0.000000" />
+				<float name="Param1" value="0.000000" />
+				<float name="Param2" value="0.000000" />
+				<texture name="Texture1" value="UVTransformTestImg.png" />
+				<texture name="Texture2" value="" />
+				<texture name="Texture3" value="" />
+				<texture name="Texture4" value="" />
+				<bool name="Wireframe" value="false" />
+				<bool name="GouraudShading" value="true" />
+				<bool name="Lighting" value="false" />
+				<bool name="ZWriteEnable" value="true" />
+				<int name="ZBuffer" value="1" />
+				<bool name="BackfaceCulling" value="true" />
+				<bool name="FogEnable" value="false" />
+				<bool name="NormalizeNormals" value="false" />
+				<bool name="BilinearFilter1" value="true" />
+				<bool name="BilinearFilter2" value="true" />
+				<bool name="BilinearFilter3" value="true" />
+				<bool name="BilinearFilter4" value="true" />
+				<bool name="TrilinearFilter1" value="false" />
+				<bool name="TrilinearFilter2" value="false" />
+				<bool name="TrilinearFilter3" value="false" />
+				<bool name="TrilinearFilter4" value="false" />
+				<bool name="AnisotropicFilter1" value="false" />
+				<bool name="AnisotropicFilter2" value="false" />
+				<bool name="AnisotropicFilter3" value="false" />
+				<bool name="AnisotropicFilter4" value="false" />
+				<enum name="TextureWrap1" value="texture_clamp_repeat" />
+				<enum name="TextureWrap2" value="texture_clamp_repeat" />
+				<enum name="TextureWrap3" value="texture_clamp_repeat" />
+				<enum name="TextureWrap4" value="texture_clamp_repeat" />
+			</attributes>
+		</materials>
+		<animators>
+			<attributes>
+				<string name="Type" value="followSpline" />
+				<float name="Speed" value="1.000000" />
+				<float name="Tightness" value="0.500000" />
+				<vector3d name="Point1" value="0.000000, 0.000000, 0.000000" />
+				<vector3d name="Point2" value="20.000000, 20.000000, 20.000000" />
+				<vector3d name="Point3" value="0.000000, 40.000000, 0.000000" />
+				<vector3d name="Point4" value="32.000000, 0.000000, 30.000000" />
+			</attributes>
+		</animators>
+	</node>
+
+	<node type="sphere">
+
+		<attributes>
+			<string name="Name" value="SillySphere" />
+			<int name="Id" value="-1" />
+			<vector3d name="Position" value="-52.105640, 35.426533, -57.016262" />
+			<vector3d name="Rotation" value="994.501831, 732.416443, 732.416443" />
+			<vector3d name="Scale" value="3.048931, 7.026268, 6.031934" />
+			<bool name="Visible" value="true" />
+			<enum name="AutomaticCulling" value="box" />
+			<int name="DebugDataVisible" value="0" />
+			<bool name="IsDebugObject" value="false" />
+			<float name="Radius" value="5.000000" />
+			<int name="PolyCountX" value="16" />
+			<int name="PolyCountY" value="16" />
+		</attributes>
+
+		<materials>
+			<attributes>
+				<enum name="Type" value="solid" />
+				<color name="Ambient" value="ffffffff" />
+				<color name="Diffuse" value="ffffffff" />
+				<color name="Emissive" value="00000000" />
+				<color name="Specular" value="ffffffff" />
+				<float name="Shininess" value="0.000000" />
+				<float name="Param1" value="0.000000" />
+				<float name="Param2" value="0.000000" />
+				<texture name="Texture1" value="UVTransformTestImg.png" />
+				<texture name="Texture2" value="" />
+				<texture name="Texture3" value="" />
+				<texture name="Texture4" value="" />
+				<bool name="Wireframe" value="false" />
+				<bool name="GouraudShading" value="true" />
+				<bool name="Lighting" value="false" />
+				<bool name="ZWriteEnable" value="true" />
+				<int name="ZBuffer" value="1" />
+				<bool name="BackfaceCulling" value="true" />
+				<bool name="FogEnable" value="false" />
+				<bool name="NormalizeNormals" value="false" />
+				<bool name="BilinearFilter1" value="true" />
+				<bool name="BilinearFilter2" value="true" />
+				<bool name="BilinearFilter3" value="true" />
+				<bool name="BilinearFilter4" value="true" />
+				<bool name="TrilinearFilter1" value="false" />
+				<bool name="TrilinearFilter2" value="false" />
+				<bool name="TrilinearFilter3" value="false" />
+				<bool name="TrilinearFilter4" value="false" />
+				<bool name="AnisotropicFilter1" value="false" />
+				<bool name="AnisotropicFilter2" value="false" />
+				<bool name="AnisotropicFilter3" value="false" />
+				<bool name="AnisotropicFilter4" value="false" />
+				<enum name="TextureWrap1" value="texture_clamp_repeat" />
+				<enum name="TextureWrap2" value="texture_clamp_repeat" />
+				<enum name="TextureWrap3" value="texture_clamp_repeat" />
+				<enum name="TextureWrap4" value="texture_clamp_repeat" />
+			</attributes>
+		</materials>
+<!--		<animators>-->
+<!--			<attributes>-->
+<!--				<string name="Type" value="rotation" />-->
+<!--				<vector3d name="Rotation" value="0.300000, 0.300000, 0.300000" />-->
+<!--			</attributes>-->
+<!--		</animators>-->
+	</node>
+
+</irr_scene>
+

BIN
test/models/IRR/scenegraphAnimMod_UTF16LE.irr


BIN
test/models/IRR/scenegraphAnim_UTF16LE.irr


+ 34 - 0
test/unit/utImporter.cpp

@@ -361,3 +361,37 @@ TEST_F(ImporterTest, unexpectedException) {
         EXPECT_TRUE(false);
     }
 }
+
+// ------------------------------------------------------------------------------------------------
+
+struct ExtensionTestCase {
+    std::string testName;
+    std::string filename;
+    std::string getExtensionResult;
+    std::string hasExtension;
+    bool hasExtensionResult;
+};
+
+using ExtensionTest = ::testing::TestWithParam<ExtensionTestCase>;
+
+TEST_P(ExtensionTest, testGetAndHasExtension) {
+    const ExtensionTestCase& testCase = GetParam();
+    EXPECT_EQ(testCase.getExtensionResult, BaseImporter::GetExtension(testCase.filename));
+    EXPECT_EQ(testCase.hasExtensionResult, BaseImporter::HasExtension(testCase.filename, {testCase.hasExtension}));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    ExtensionTests, ExtensionTest,
+    ::testing::ValuesIn<ExtensionTestCase>({
+        {"NoExtension", "name", "", "glb", false},
+        {"NoExtensionAndEmptyVersion", "name#", "", "glb", false},
+        {"WithExtensionAndEmptyVersion", "name.glb#", "glb#", "glb", false},
+        {"WithExtensionAndVersion", "name.glb#1234", "glb", "glb", true},
+        {"WithExtensionAndHashInStem", "name#1234.glb", "glb", "glb", true},
+        {"WithExtensionAndInvalidVersion", "name.glb#_", "glb#_", "glb", false},
+        {"WithExtensionAndDotAndHashInStem", "name.glb#.abc", "abc", "glb", false},
+        {"WithTwoExtensions", "name.abc.def", "def", "abc.def", true},
+    }),
+    [](const ::testing::TestParamInfo<ExtensionTest::ParamType>& info) {
+        return info.param.testName;
+    });

+ 12 - 6
test/unit/utglTF2ImportExport.cpp

@@ -60,7 +60,7 @@ using namespace Assimp;
 
 class utglTF2ImportExport : public AbstractImportExportBase {
 public:
-    virtual bool importerMatTest(const char *file, bool spec_gloss, std::array<aiTextureMapMode, 2> exp_modes = { aiTextureMapMode_Wrap, aiTextureMapMode_Wrap }) {
+    virtual bool importerMatTest(const char *file, bool spec, bool gloss, std::array<aiTextureMapMode, 2> exp_modes = { aiTextureMapMode_Wrap, aiTextureMapMode_Wrap }) {
         Assimp::Importer importer;
         const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure);
         EXPECT_NE(scene, nullptr);
@@ -105,16 +105,19 @@ public:
 
         aiColor3D spec_color = { 0, 0, 0 };
         ai_real glossiness = ai_real(0.5);
-        if (spec_gloss) {
+        if (spec) {
             EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color));
             constexpr ai_real spec_val(0.20000000298023225); // From the file
             EXPECT_EQ(spec_val, spec_color.r);
             EXPECT_EQ(spec_val, spec_color.g);
             EXPECT_EQ(spec_val, spec_color.b);
+        } else {
+            EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color));
+        }
+        if (gloss) {
             EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness));
             EXPECT_EQ(ai_real(1.0), glossiness);
         } else {
-            EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color));
             EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness));
         }
 
@@ -143,7 +146,7 @@ public:
 };
 
 TEST_F(utglTF2ImportExport, importglTF2FromFileTest) {
-    EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", false, {aiTextureMapMode_Mirror, aiTextureMapMode_Clamp}));
+    EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", false, false, {aiTextureMapMode_Mirror, aiTextureMapMode_Clamp}));
 }
 
 TEST_F(utglTF2ImportExport, importBinaryglTF2FromFileTest) {
@@ -151,7 +154,7 @@ TEST_F(utglTF2ImportExport, importBinaryglTF2FromFileTest) {
 }
 
 TEST_F(utglTF2ImportExport, importglTF2_KHR_materials_pbrSpecularGlossiness) {
-    EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf", true));
+    EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf", true, true));
 }
 
 void VerifyClearCoatScene(const aiScene *scene) {
@@ -223,13 +226,16 @@ TEST_F(utglTF2ImportExport, importglTF2AndExport_KHR_materials_pbrSpecularGlossi
     // Export with specular glossiness disabled
     EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb"));
     
+    // And re-import
+    EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true, false));
+
     // Export with specular glossiness enabled
     ExportProperties props;
     props.SetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS, true);
     EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", 0, &props));
 
     // And re-import
-    EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true));
+    EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true, true));
 }
 
 TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) {