瀏覽代碼

Merge branch 'master' into master

Kim Kulling 3 年之前
父節點
當前提交
89c4640744
共有 100 個文件被更改,包括 1482 次插入1390 次删除
  1. 6 0
      .github/dependabot.yml
  2. 6 6
      .github/workflows/ccpp.yml
  3. 2 2
      .github/workflows/sanitizer.yml
  4. 27 21
      Build.md
  5. 31 44
      CMakeLists.txt
  6. 1 1
      INSTALL
  7. 0 1
      README
  8. 3 0
      Readme.md
  9. 16 0
      SECURITY.md
  10. 1 1
      cmake-modules/FindDirectX.cmake
  11. 1 1
      cmake-modules/FindPkgMacros.cmake
  12. 1 0
      code/AssetLib/3DS/3DSConverter.cpp
  13. 2 1
      code/AssetLib/3DS/3DSLoader.cpp
  14. 2 0
      code/AssetLib/3MF/3MFXmlTags.h
  15. 3 0
      code/AssetLib/3MF/D3MFOpcPackage.cpp
  16. 32 9
      code/AssetLib/3MF/XmlSerializer.cpp
  17. 1 0
      code/AssetLib/ASE/ASELoader.cpp
  18. 9 4
      code/AssetLib/ASE/ASEParser.cpp
  19. 1 1
      code/AssetLib/Assxml/AssxmlFileWriter.cpp
  20. 4 4
      code/AssetLib/Blender/BlenderDNA.cpp
  21. 2 2
      code/AssetLib/Blender/BlenderLoader.cpp
  22. 1 1
      code/AssetLib/Blender/BlenderLoader.h
  23. 5 0
      code/AssetLib/Collada/ColladaHelper.h
  24. 6 3
      code/AssetLib/Collada/ColladaLoader.cpp
  25. 1 0
      code/AssetLib/Collada/ColladaLoader.h
  26. 2 1
      code/AssetLib/Collada/ColladaParser.cpp
  27. 3 1
      code/AssetLib/DXF/DXFLoader.cpp
  28. 0 21
      code/AssetLib/FBX/FBXAnimation.cpp
  29. 1 1
      code/AssetLib/FBX/FBXBinaryTokenizer.cpp
  30. 2 1
      code/AssetLib/FBX/FBXCommon.h
  31. 0 1
      code/AssetLib/FBX/FBXCompileConfig.h
  32. 116 62
      code/AssetLib/FBX/FBXConverter.cpp
  33. 29 16
      code/AssetLib/FBX/FBXConverter.h
  34. 2 5
      code/AssetLib/FBX/FBXDeformer.cpp
  35. 2 2
      code/AssetLib/FBX/FBXDocument.cpp
  36. 10 10
      code/AssetLib/FBX/FBXDocument.h
  37. 3 6
      code/AssetLib/FBX/FBXDocumentUtil.cpp
  38. 5 7
      code/AssetLib/FBX/FBXDocumentUtil.h
  39. 1 1
      code/AssetLib/FBX/FBXExporter.cpp
  40. 6 0
      code/AssetLib/FBX/FBXImportSettings.h
  41. 22 25
      code/AssetLib/FBX/FBXImporter.cpp
  42. 7 6
      code/AssetLib/FBX/FBXImporter.h
  43. 4 20
      code/AssetLib/FBX/FBXMeshGeometry.cpp
  44. 12 9
      code/AssetLib/FBX/FBXMeshGeometry.h
  45. 29 78
      code/AssetLib/FBX/FBXNodeAttribute.cpp
  46. 1 15
      code/AssetLib/FBX/FBXParser.cpp
  47. 2 2
      code/AssetLib/FBX/FBXParser.h
  48. 4 2
      code/AssetLib/IFC/IFCCurve.cpp
  49. 5 5
      code/AssetLib/IFC/IFCOpenings.cpp
  50. 1 1
      code/AssetLib/Irr/IRRLoader.cpp
  51. 2 2
      code/AssetLib/LWO/LWOLoader.cpp
  52. 3 0
      code/AssetLib/LWS/LWSLoader.cpp
  53. 1 3
      code/AssetLib/M3D/M3DWrapper.h
  54. 3 0
      code/AssetLib/MDL/MDLMaterialLoader.cpp
  55. 21 14
      code/AssetLib/MMD/MMDImporter.cpp
  56. 2 0
      code/AssetLib/MMD/MMDPmxParser.h
  57. 3 1
      code/AssetLib/NDO/NDOLoader.cpp
  58. 45 46
      code/AssetLib/Obj/ObjFileData.h
  59. 57 52
      code/AssetLib/Obj/ObjFileImporter.cpp
  60. 84 52
      code/AssetLib/Obj/ObjFileMtlImporter.cpp
  61. 3 0
      code/AssetLib/Obj/ObjFileMtlImporter.h
  62. 76 74
      code/AssetLib/Obj/ObjFileParser.cpp
  63. 1 4
      code/AssetLib/Obj/ObjFileParser.h
  64. 1 1
      code/AssetLib/Obj/ObjTools.h
  65. 21 11
      code/AssetLib/Ogre/OgreXmlSerializer.cpp
  66. 21 29
      code/AssetLib/OpenGEX/OpenGEXImporter.cpp
  67. 3 8
      code/AssetLib/OpenGEX/OpenGEXImporter.h
  68. 12 2
      code/AssetLib/Q3D/Q3DLoader.cpp
  69. 19 19
      code/AssetLib/STL/STLLoader.cpp
  70. 1 1
      code/AssetLib/STL/STLLoader.h
  71. 47 95
      code/AssetLib/Step/STEPFile.h
  72. 1 1
      code/AssetLib/X3D/X3DImporter.cpp
  73. 5 5
      code/AssetLib/glTF/glTFAsset.inl
  74. 2 0
      code/AssetLib/glTF2/glTF2Asset.h
  75. 13 1
      code/AssetLib/glTF2/glTF2Asset.inl
  76. 2 2
      code/AssetLib/glTF2/glTF2Exporter.cpp
  77. 23 20
      code/AssetLib/glTF2/glTF2Importer.cpp
  78. 30 15
      code/CMakeLists.txt
  79. 6 13
      code/Common/Assimp.cpp
  80. 10 3
      code/Common/DefaultIOStream.cpp
  81. 2 2
      code/Common/FileSystemFilter.h
  82. 29 0
      code/Common/Maybe.h
  83. 29 26
      code/Common/ScenePreprocessor.cpp
  84. 8 6
      code/Common/SkeletonMeshBuilder.cpp
  85. 58 0
      code/Common/StbCommon.h
  86. 5 1
      code/Common/Version.cpp
  87. 2 0
      code/Common/ZipArchiveIOSystem.cpp
  88. 1 1
      code/Common/material.cpp
  89. 2 2
      code/Pbrt/PbrtExporter.cpp
  90. 1 1
      code/PostProcessing/ComputeUVMappingProcess.cpp
  91. 1 1
      code/PostProcessing/EmbedTexturesProcess.cpp
  92. 75 93
      code/PostProcessing/JoinVerticesProcess.cpp
  93. 1 1
      code/PostProcessing/ValidateDataStructure.cpp
  94. 16 55
      code/res/assimp.rc
  95. 0 14
      code/res/resource.h
  96. 7 0
      contrib/clipper/clipper.cpp
  97. 1 1
      contrib/draco/CMakeLists.txt
  98. 120 83
      contrib/gtest/CMakeLists.txt
  99. 164 229
      contrib/gtest/README.md
  100. 9 0
      contrib/gtest/cmake/Config.cmake.in

+ 6 - 0
.github/dependabot.yml

@@ -0,0 +1,6 @@
+version: 2
+updates:
+  - package-ecosystem: "github-actions"
+    directory: "/"
+    schedule:
+      interval: "weekly"

+ 6 - 6
.github/workflows/ccpp.yml

@@ -43,7 +43,7 @@ jobs:
             toolchain: ninja-vs-win64-cxx17
             toolchain: ninja-vs-win64-cxx17
 
 
     steps:
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
     
     
     - uses: lukka/get-cmake@latest
     - uses: lukka/get-cmake@latest
     
     
@@ -64,21 +64,21 @@ jobs:
 
 
     - name: Checkout Hunter toolchains
     - name: Checkout Hunter toolchains
       if: endsWith(matrix.name, 'hunter')
       if: endsWith(matrix.name, 'hunter')
-      uses: actions/checkout@v2
+      uses: actions/checkout@v3
       with:
       with:
         repository: cpp-pm/polly
         repository: cpp-pm/polly
         path: cmake/polly
         path: cmake/polly
 
 
     - name: Remove contrib directory for Hunter builds
     - name: Remove contrib directory for Hunter builds
       if: contains(matrix.name, 'hunter')
       if: contains(matrix.name, 'hunter')
-      uses: JesseTG/[email protected].2
+      uses: JesseTG/[email protected].3
       with:
       with:
         path: contrib
         path: contrib
 
 
     - name: Cache DX SDK
     - name: Cache DX SDK
       id: dxcache
       id: dxcache
       if: contains(matrix.name, 'windows')
       if: contains(matrix.name, 'windows')
-      uses: actions/cache@v2
+      uses: actions/cache@v3
       with:
       with:
         path: '${{ github.workspace }}/DX_SDK'
         path: '${{ github.workspace }}/DX_SDK'
         key: ${{ runner.os }}-DX_SDK
         key: ${{ runner.os }}-DX_SDK
@@ -110,7 +110,7 @@ jobs:
         cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
         cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
         cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
         cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
         cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release ${{ steps.windows_extra_cmake_args.outputs.args }} ${{ steps.hunter_extra_cmake_args.outputs.args }}'
         cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release ${{ steps.windows_extra_cmake_args.outputs.args }} ${{ steps.hunter_extra_cmake_args.outputs.args }}'
-        buildWithCMakeArgs: '-- -v'
+        buildWithCMakeArgs: '-- -j 24 -v'
         buildDirectory: '${{ github.workspace }}/build/'
         buildDirectory: '${{ github.workspace }}/build/'
         
         
     - name: Exclude certain tests in Hunter specific builds
     - name: Exclude certain tests in Hunter specific builds
@@ -122,7 +122,7 @@ jobs:
       run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }}
       run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }}
       shell: bash
       shell: bash
 
 
-    - uses: actions/upload-artifact@v2
+    - uses: actions/upload-artifact@v3
       if: matrix.name == 'windows-msvc'
       if: matrix.name == 'windows-msvc'
       with:
       with:
         name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}'
         name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}'

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

@@ -11,7 +11,7 @@ jobs:
     name: adress-sanitizer
     name: adress-sanitizer
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
     steps:
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
     - uses: lukka/get-cmake@latest    
     - uses: lukka/get-cmake@latest    
     - uses: lukka/set-shell-env@v1
     - uses: lukka/set-shell-env@v1
       with:
       with:
@@ -35,7 +35,7 @@ jobs:
     name: undefined-behavior-sanitizer
     name: undefined-behavior-sanitizer
     runs-on: ubuntu-latest
     runs-on: ubuntu-latest
     steps:
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
     - uses: lukka/get-cmake@latest    
     - uses: lukka/get-cmake@latest    
     - uses: lukka/set-shell-env@v1
     - uses: lukka/set-shell-env@v1
       with:
       with:

+ 27 - 21
Build.md

@@ -14,7 +14,8 @@ The assimp port in vcpkg is kept up to date by Microsoft team members and commun
 ## Install on Ubuntu
 ## Install on Ubuntu
 You can install the Asset-Importer-Lib via apt:
 You can install the Asset-Importer-Lib via apt:
 ```
 ```
-sudo apt-get install assimp
+sudo apt-get update
+sudo apt-get install libassimp-dev
 ```
 ```
 
 
 ## Install pyassimp
 ## Install pyassimp
@@ -84,23 +85,28 @@ Besides the toolchain, compilation should be the same as for Linux / Unix.
 
 
 ### CMake build options
 ### CMake build options
 The cmake-build-environment provides options to configure the build. The following options can be used:
 The cmake-build-environment provides options to configure the build. The following options can be used:
-- **BUILD_SHARED_LIBS ( default ON )**: Generation of shared libs ( dll for windows, so for Linux ). Set this to OFF to get a static lib.
-- **BUILD_FRAMEWORK ( default OFF, MacOnly)**: Build package as Mac OS X Framework bundle
-- **ASSIMP_DOUBLE_PRECISION( default OFF )**: All data will be stored as double values.
-- **ASSIMP_OPT_BUILD_PACKAGES ( default OFF)**: Set to ON to generate CPack configuration files and packaging targets
-- **ASSIMP_ANDROID_JNIIOSYSTEM ( default OFF )**: Android JNI IOSystem support is active
-- **ASSIMP_NO_EXPORT ( default OFF )**: Disable Assimp's export functionality
-- **ASSIMP_BUILD_ZLIB ( default OFF )**: Build your own zlib
-- **ASSIMP_BUILD_ASSIMP_TOOLS ( default ON )**: If the supplementary tools for Assimp are built in addition to the library.
-- **ASSIMP_BUILD_SAMPLES ( default OFF )**: If the official samples are built as well (needs Glut).
-- **ASSIMP_BUILD_TESTS ( default ON )**: If the test suite for Assimp is built in addition to the library.
-- **ASSIMP_COVERALLS ( default OFF )**: Enable this to measure test coverage.
-- **ASSIMP_ERROR_MAX( default OFF)**: Enable all warnings.
-- **ASSIMP_WERROR( default OFF )**: Treat warnings as errors.
-- **ASSIMP_ASAN ( default OFF )**: Enable AddressSanitizer.
-- **ASSIMP_UBSAN ( default OFF )**: Enable Undefined Behavior sanitizer.
-- **SYSTEM_IRRXML ( default OFF )**: Use system installed Irrlicht/IrrXML library.
-- **BUILD_DOCS ( default OFF )**: Build documentation using Doxygen.
-- **INJECT_DEBUG_POSTFIX( default ON )**: Inject debug postfix in .a/.so lib names
-- **IGNORE_GIT_HASH ( default OFF )**: Don't call git to get the hash.
-- **ASSIMP_INSTALL_PDB ( default ON )**: Install MSVC debug files.
+- **ASSIMP_HUNTER_ENABLED (default OFF)**: Enable Hunter package manager support.
+- **BUILD_SHARED_LIBS (default ON)**: Generation of shared libs (dll for windows, so for Linux). Set this to OFF to get a static lib.
+- **ASSIMP_BUILD_FRAMEWORK (default OFF, MacOnly)**: Build package as Mac OS X Framework bundle.
+- **ASSIMP_DOUBLE_PRECISION (default OFF)**: All data will be stored as double values.
+- **ASSIMP_OPT_BUILD_PACKAGES (default OFF)**: Set to ON to generate CPack configuration files and packaging targets.
+- **ASSIMP_ANDROID_JNIIOSYSTEM (default OFF)**: Android JNI IOSystem support is active.
+- **ASSIMP_NO_EXPORT (default OFF)**: Disable Assimp's export functionality.
+- **ASSIMP_BUILD_ZLIB (default OFF)**: Build our own zlib.
+- **ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT (default ON)**: Build Assimp with all exporter senabled.
+- **ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT (default ON)**: Build Assimp with all importer senabled.
+- **ASSIMP_BUILD_ASSIMP_TOOLS (default ON)**: If the supplementary tools for Assimp are built in addition to the library.
+- **ASSIMP_BUILD_SAMPLES (default OFF)**: If the official samples are built as well (needs Glut).
+- **ASSIMP_BUILD_TESTS (default ON)**: If the test suite for Assimp is built in addition to the library.
+- **ASSIMP_COVERALLS (default OFF)**: Enable this to measure test coverage.
+- **ASSIMP_INSTALL (default ON)**: Install Assimp library. Disable this if you want to use Assimp as a submodule.
+- **ASSIMP_WARNINGS_AS_ERRORS (default ON)**: Treat all warnings as errors.
+- **ASSIMP_ASAN (default OFF)**: Enable AddressSanitizer.
+- **ASSIMP_UBSAN (default OFF)**: Enable Undefined Behavior sanitizer.
+- **ASSIMP_BUILD_DOCS (default OFF)**: Build documentation using Doxygen. OBSOLETE, see https://github.com/assimp/assimp-docs
+- **ASSIMP_INJECT_DEBUG_POSTFIX (default ON)**: Inject debug postfix in .a/.so/.lib/.dll lib names
+- **ASSIMP_IGNORE_GIT_HASH (default OFF)**: Don't call git to get the hash.
+- **ASSIMP_INSTALL_PDB (default ON)**: Install MSVC debug files.
+- **USE_STATIC_CRT (default OFF)**: Link against the static MSVC runtime libraries.
+- **ASSIMP_BUILD_DRACO (default OFF)**: Build Draco libraries. Primarily for glTF.
+- **ASSIMP_BUILD_ASSIMP_VIEW (default ON, if DirectX found, OFF otherwise)**: Build Assimp view tool (requires DirectX).

+ 31 - 44
CMakeLists.txt

@@ -56,7 +56,7 @@ IF(ASSIMP_HUNTER_ENABLED)
   add_definitions(-DASSIMP_USE_HUNTER)
   add_definitions(-DASSIMP_USE_HUNTER)
 ENDIF()
 ENDIF()
 
 
-PROJECT(Assimp VERSION 5.2.0)
+PROJECT(Assimp VERSION 5.2.4)
 
 
 # All supported options ###############################################
 # All supported options ###############################################
 
 
@@ -90,7 +90,7 @@ OPTION( ASSIMP_BUILD_ZLIB
 )
 )
 OPTION( ASSIMP_BUILD_ASSIMP_TOOLS
 OPTION( ASSIMP_BUILD_ASSIMP_TOOLS
   "If the supplementary tools for Assimp are built in addition to the library."
   "If the supplementary tools for Assimp are built in addition to the library."
-  ON
+  OFF
 )
 )
 OPTION ( ASSIMP_BUILD_SAMPLES
 OPTION ( ASSIMP_BUILD_SAMPLES
   "If the official samples are built as well (needs Glut)."
   "If the official samples are built as well (needs Glut)."
@@ -108,9 +108,9 @@ OPTION( ASSIMP_INSTALL
   "Disable this if you want to use assimp as a submodule."
   "Disable this if you want to use assimp as a submodule."
   ON
   ON
 )
 )
-OPTION ( ASSIMP_ERROR_MAX
-  "Enable all warnings."
-  OFF
+OPTION ( ASSIMP_WARNINGS_AS_ERRORS
+  "Treat all warnings as errors."
+  ON
 )
 )
 OPTION ( ASSIMP_ASAN
 OPTION ( ASSIMP_ASAN
   "Enable AddressSanitizer."
   "Enable AddressSanitizer."
@@ -139,10 +139,6 @@ IF (WIN32)
   ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
   ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
 
 
   IF(MSVC)
   IF(MSVC)
-    OPTION (ASSIMP_BUILD_ASSIMP_VIEW
-      "If the Assimp view tool is built. (requires DirectX)"
-      OFF )
-
     OPTION( ASSIMP_INSTALL_PDB
     OPTION( ASSIMP_INSTALL_PDB
       "Install MSVC debug files."
       "Install MSVC debug files."
       ON )
       ON )
@@ -164,12 +160,6 @@ IF (WIN32)
           $<$<CONFIG:Debug>:/MTd>
           $<$<CONFIG:Debug>:/MTd>
           $<$<CONFIG:Release>:/MT>
           $<$<CONFIG:Release>:/MT>
       )
       )
-    else()
-      add_compile_options(
-          $<$<CONFIG:>:/MD>
-          $<$<CONFIG:Debug>:/MDd>
-          $<$<CONFIG:Release>:/MD>
-      )
     endif()
     endif()
   ENDIF()
   ENDIF()
 ENDIF()
 ENDIF()
@@ -190,6 +180,7 @@ ENDIF()
 IF(NOT BUILD_SHARED_LIBS)
 IF(NOT BUILD_SHARED_LIBS)
   MESSAGE(STATUS "Shared libraries disabled")
   MESSAGE(STATUS "Shared libraries disabled")
   SET(LINK_SEARCH_START_STATIC TRUE)
   SET(LINK_SEARCH_START_STATIC TRUE)
+  SET(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} ${CMAKE_FIND_LIBRARY_SUFFIXES})
 ELSE()
 ELSE()
   MESSAGE(STATUS "Shared libraries enabled")
   MESSAGE(STATUS "Shared libraries enabled")
 ENDIF()
 ENDIF()
@@ -203,8 +194,8 @@ SET (ASSIMP_SOVERSION 5)
 
 
 SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
 SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
 if(NOT ASSIMP_HUNTER_ENABLED)
 if(NOT ASSIMP_HUNTER_ENABLED)
-  # Enable C++11 support globally
-  set(CMAKE_CXX_STANDARD 11)
+  # Enable C++17 support globally
+  set(CMAKE_CXX_STANDARD 17)
   set(CMAKE_CXX_STANDARD_REQUIRED ON)
   set(CMAKE_CXX_STANDARD_REQUIRED ON)
   set(CMAKE_C_STANDARD 99)
   set(CMAKE_C_STANDARD 99)
 endif()
 endif()
@@ -237,16 +228,6 @@ IF(ASSIMP_DOUBLE_PRECISION)
   ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
   ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
 ENDIF()
 ENDIF()
 
 
-CONFIGURE_FILE(
-  ${CMAKE_CURRENT_LIST_DIR}/revision.h.in
-  ${CMAKE_CURRENT_BINARY_DIR}/revision.h
-)
-
-CONFIGURE_FILE(
-  ${CMAKE_CURRENT_LIST_DIR}/include/assimp/config.h.in
-  ${CMAKE_CURRENT_BINARY_DIR}/include/assimp/config.h
-)
-
 INCLUDE_DIRECTORIES( BEFORE
 INCLUDE_DIRECTORIES( BEFORE
   ./
   ./
   code/
   code/
@@ -276,7 +257,7 @@ ENDIF()
 # Grouped compiler settings ########################################
 # Grouped compiler settings ########################################
 IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW)
 IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT MINGW)
   IF(NOT ASSIMP_HUNTER_ENABLED)
   IF(NOT ASSIMP_HUNTER_ENABLED)
-    SET(CMAKE_CXX_STANDARD 11)
+    SET(CMAKE_CXX_STANDARD 17)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
   ENDIF()
   ENDIF()
   # hide all not-exported symbols
   # hide all not-exported symbols
@@ -306,7 +287,7 @@ ELSEIF(MSVC)
   SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG:FULL /PDBALTPATH:%_PDB% /OPT:REF /OPT:ICF")
   SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG:FULL /PDBALTPATH:%_PDB% /OPT:REF /OPT:ICF")
 ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
 ELSEIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
   IF(NOT ASSIMP_HUNTER_ENABLED)
   IF(NOT ASSIMP_HUNTER_ENABLED)
-    SET(CMAKE_CXX_STANDARD 11)
+    SET(CMAKE_CXX_STANDARD 17)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
   ENDIF()
   ENDIF()
   SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
   SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
@@ -318,11 +299,15 @@ ELSEIF( MINGW )
     message(WARNING "MinGW is old, if you experience errors, update MinGW.")
     message(WARNING "MinGW is old, if you experience errors, update MinGW.")
   ENDIF()
   ENDIF()
   IF(NOT ASSIMP_HUNTER_ENABLED)
   IF(NOT ASSIMP_HUNTER_ENABLED)
-    SET(CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}")
+    SET(CMAKE_CXX_FLAGS "-std=gnu++17 ${CMAKE_CXX_FLAGS}")
     SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
     SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
   ENDIF()
   ENDIF()
-  SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}")
-  SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
+    IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
+      SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -g ${CMAKE_CXX_FLAGS}")
+    ELSE()
+      SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}")
+    ENDIF()
+    SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
 ENDIF()
 ENDIF()
 
 
 IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED)
 IF ( IOS AND NOT ASSIMP_HUNTER_ENABLED)
@@ -343,16 +328,6 @@ IF (ASSIMP_COVERALLS)
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
 ENDIF()
 ENDIF()
 
 
-IF (ASSIMP_ERROR_MAX)
-  MESSAGE(STATUS "Turning on all warnings")
-  IF (MSVC)
-    ADD_COMPILE_OPTIONS(/W4) # NB: there is a /Wall option, pedantic mode
-  ELSE()
-    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
-    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
-  ENDIF()
-ENDIF()
-
 IF (ASSIMP_ASAN)
 IF (ASSIMP_ASAN)
   MESSAGE(STATUS "AddressSanitizer enabled")
   MESSAGE(STATUS "AddressSanitizer enabled")
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
@@ -713,10 +688,12 @@ ENDIF()
 
 
 # Main assimp code
 # Main assimp code
 ADD_SUBDIRECTORY( code/ )
 ADD_SUBDIRECTORY( code/ )
+
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
   # The viewer for windows only
   # The viewer for windows only
   IF (WIN32)
   IF (WIN32)
-    OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" OFF )
+    FIND_PACKAGE(DirectX)
+    OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
     IF ( ASSIMP_BUILD_ASSIMP_VIEW )
     IF ( ASSIMP_BUILD_ASSIMP_VIEW )
       ADD_SUBDIRECTORY( tools/assimp_view/ )
       ADD_SUBDIRECTORY( tools/assimp_view/ )
     ENDIF ()
     ENDIF ()
@@ -741,12 +718,22 @@ IF ( ASSIMP_BUILD_TESTS )
   ADD_SUBDIRECTORY( test/ )
   ADD_SUBDIRECTORY( test/ )
 ENDIF ()
 ENDIF ()
 
 
-# Generate a pkg-config .pc for the Assimp library.
+# Generate a pkg-config .pc, revision.h, and config.h for the Assimp library.
 CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
 CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
 IF ( ASSIMP_INSTALL )
 IF ( ASSIMP_INSTALL )
   INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
   INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
 ENDIF()
 ENDIF()
 
 
+CONFIGURE_FILE(
+  ${CMAKE_CURRENT_LIST_DIR}/revision.h.in
+  ${CMAKE_CURRENT_BINARY_DIR}/revision.h
+)
+
+CONFIGURE_FILE(
+  ${CMAKE_CURRENT_LIST_DIR}/include/assimp/config.h.in
+  ${CMAKE_CURRENT_BINARY_DIR}/include/assimp/config.h
+)
+
 IF ( ASSIMP_INSTALL )
 IF ( ASSIMP_INSTALL )
   IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
   IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
     # Packing information
     # Packing information

+ 1 - 1
INSTALL

@@ -14,4 +14,4 @@ https://assimp-docs.readthedocs.io/en/latest/
 Building Assimp 
 Building Assimp 
 ------------------------------
 ------------------------------
 
 
-Just check the build-instaructions which you can find here: https://github.com/assimp/assimp/blob/master/Build.md
+Just check the build-instructions which you can find here: https://github.com/assimp/assimp/blob/master/Build.md

+ 0 - 1
README

@@ -1 +0,0 @@
-See Readme.md

+ 3 - 0
Readme.md

@@ -9,9 +9,11 @@ A library to import and export various 3d-model-formats including scene-post-pro
        src="https://scan.coverity.com/projects/5607/badge.svg"/>
        src="https://scan.coverity.com/projects/5607/badge.svg"/>
 </a>
 </a>
 [![Codacy Badge](https://app.codacy.com/project/badge/Grade/9973693b7bdd4543b07084d5d9cf4745)](https://www.codacy.com/gh/assimp/assimp/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=assimp/assimp&amp;utm_campaign=Badge_Grade)
 [![Codacy Badge](https://app.codacy.com/project/badge/Grade/9973693b7bdd4543b07084d5d9cf4745)](https://www.codacy.com/gh/assimp/assimp/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=assimp/assimp&amp;utm_campaign=Badge_Grade)
+
 [![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master)
 [![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master)
 [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue")
 [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue")
+[![Percentage of issues still open](http://isitmaintained.com/badge/open/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Percentage of issues still open")
 [![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
 [![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
 <br>
 <br>
 
 
@@ -58,6 +60,7 @@ Open Asset Import Library is implemented in C++. The directory structure looks l
 	/code		Source code
 	/code		Source code
 	/contrib	Third-party libraries
 	/contrib	Third-party libraries
 	/doc		Documentation (doxysource and pre-compiled docs)
 	/doc		Documentation (doxysource and pre-compiled docs)
+	/fuzz           Contains the test-code for the Google-Fuzzer project
 	/include	Public header C and C++ header files
 	/include	Public header C and C++ header files
 	/scripts 	Scripts used to generate the loading code for some formats
 	/scripts 	Scripts used to generate the loading code for some formats
 	/port		Ports to other languages and scripts to maintain those.
 	/port		Ports to other languages and scripts to maintain those.

+ 16 - 0
SECURITY.md

@@ -0,0 +1,16 @@
+# Security Policy
+
+## Supported Versions
+
+Use this section to tell people about which versions of your project are
+currently being supported with security updates.
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 5.2.4   | :white_check_mark: |
+
+## Reporting a Vulnerability
+
+If you have found any security vulnerability you can contact us via 
[email protected]
+

+ 1 - 1
cmake-modules/FindDirectX.cmake

@@ -55,7 +55,7 @@ if(WIN32) # The only platform it makes sense to check for DirectX SDK
   endif(CMAKE_CL_64)
   endif(CMAKE_CL_64)
   find_library(DirectX_LIBRARY NAMES d3d9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
   find_library(DirectX_LIBRARY NAMES d3d9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
   find_library(DirectX_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
   find_library(DirectX_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
-  find_library(DirectX_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
+  find_library(DirectX_DXERR_LIBRARY NAMES DxErr DxErr9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
   find_library(DirectX_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
   find_library(DirectX_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX})
 
 
 
 

+ 1 - 1
cmake-modules/FindPkgMacros.cmake

@@ -54,7 +54,7 @@ macro(clear_if_changed TESTVAR)
       set(${var} "NOTFOUND" CACHE STRING "x" FORCE)
       set(${var} "NOTFOUND" CACHE STRING "x" FORCE)
     endforeach(var)
     endforeach(var)
   endif ()
   endif ()
-  set(${TESTVAR}_INT_CHECK ${${TESTVAR}} CACHE INTERNAL "x" FORCE)
+  set(${TESTVAR}_INT_CHECK "${${TESTVAR}}" CACHE INTERNAL "x" FORCE)
 endmacro(clear_if_changed)
 endmacro(clear_if_changed)
 
 
 # Try to get some hints from pkg-config, if available
 # Try to get some hints from pkg-config, if available

+ 1 - 0
code/AssetLib/3DS/3DSConverter.cpp

@@ -262,6 +262,7 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material &oldMat,
         unsigned int iWire = 1;
         unsigned int iWire = 1;
         mat.AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
         mat.AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
     }
     }
+    [[fallthrough]];
 
 
     case D3DS::Discreet3DS::Gouraud:
     case D3DS::Discreet3DS::Gouraud:
         eShading = aiShadingMode_Gouraud;
         eShading = aiShadingMode_Gouraud;

+ 2 - 1
code/AssetLib/3DS/3DSLoader.cpp

@@ -1284,7 +1284,7 @@ void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) {
     switch (chunk.Flag) {
     switch (chunk.Flag) {
     case Discreet3DS::CHUNK_LINRGBF:
     case Discreet3DS::CHUNK_LINRGBF:
         bGamma = true;
         bGamma = true;
-
+    // fallthrough
     case Discreet3DS::CHUNK_RGBF:
     case Discreet3DS::CHUNK_RGBF:
         if (sizeof(float) * 3 > diff) {
         if (sizeof(float) * 3 > diff) {
             *out = clrError;
             *out = clrError;
@@ -1297,6 +1297,7 @@ void Discreet3DSImporter::ParseColorChunk(aiColor3D *out, bool acceptPercent) {
 
 
     case Discreet3DS::CHUNK_LINRGBB:
     case Discreet3DS::CHUNK_LINRGBB:
         bGamma = true;
         bGamma = true;
+            // fallthrough
     case Discreet3DS::CHUNK_RGBB: {
     case Discreet3DS::CHUNK_RGBB: {
         if (sizeof(char) * 3 > diff) {
         if (sizeof(char) * 3 > diff) {
             *out = clrError;
             *out = clrError;

+ 2 - 0
code/AssetLib/3MF/3MFXmlTags.h

@@ -74,6 +74,8 @@ namespace XmlTag {
     const char* const pid = "pid";
     const char* const pid = "pid";
     const char* const pindex = "pindex";
     const char* const pindex = "pindex";
     const char* const p1 = "p1";
     const char* const p1 = "p1";
+    const char *const p2 = "p2";
+    const char *const p3 = "p3";
     const char* const name = "name";
     const char* const name = "name";
     const char* const type = "type";
     const char* const type = "type";
     const char* const build = "build";
     const char* const build = "build";

+ 3 - 0
code/AssetLib/3MF/D3MFOpcPackage.cpp

@@ -186,6 +186,9 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
 D3MFOpcPackage::~D3MFOpcPackage() {
 D3MFOpcPackage::~D3MFOpcPackage() {
     mZipArchive->Close(mRootStream);
     mZipArchive->Close(mRootStream);
     delete mZipArchive;
     delete mZipArchive;
+    for (auto tex : mEmbeddedTextures) {
+        delete tex;
+    }
 }
 }
 
 
 IOStream *D3MFOpcPackage::RootStream() const {
 IOStream *D3MFOpcPackage::RootStream() const {

+ 32 - 9
code/AssetLib/3MF/XmlSerializer.cpp

@@ -64,7 +64,7 @@ bool validateColorString(const char *color) {
     return true;
     return true;
 }
 }
 
 
-aiFace ReadTriangle(XmlNode &node) {
+aiFace ReadTriangle(XmlNode &node, int &texId0, int &texId1, int &texId2) {
     aiFace face;
     aiFace face;
 
 
     face.mNumIndices = 3;
     face.mNumIndices = 3;
@@ -73,6 +73,11 @@ aiFace ReadTriangle(XmlNode &node) {
     face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v2).as_string()));
     face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v2).as_string()));
     face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v3).as_string()));
     face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(XmlTag::v3).as_string()));
 
 
+    texId0 = texId1 = texId2 = -1;
+    XmlParser::getIntAttribute(node, XmlTag::p1, texId0);
+    XmlParser::getIntAttribute(node, XmlTag::p2, texId1);
+    XmlParser::getIntAttribute(node, XmlTag::p3, texId2);
+
     return face;
     return face;
 }
 }
 
 
@@ -106,7 +111,7 @@ bool getNodeAttribute(const XmlNode &node, const std::string &attribute, int &va
     return false;
     return false;
 }
 }
 
 
-aiMatrix4x4 parseTransformMatrix(std::string matrixStr) {
+aiMatrix4x4 parseTransformMatrix(const std::string& matrixStr) {
     // split the string
     // split the string
     std::vector<float> numbers;
     std::vector<float> numbers;
     std::string currentNumber;
     std::string currentNumber;
@@ -412,6 +417,9 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
             bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
             bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
             bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
             bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
 
 
+            int texId[3];
+            Texture2DGroup *group = nullptr;
+            aiFace face = ReadTriangle(currentNode, texId[0], texId[1], texId[2]);
             if (hasPid && hasP1) {
             if (hasPid && hasP1) {
                 auto it = mResourcesDictionnary.find(pid);
                 auto it = mResourcesDictionnary.find(pid);
                 if (it != mResourcesDictionnary.end()) {
                 if (it != mResourcesDictionnary.end()) {
@@ -420,23 +428,34 @@ void XmlSerializer::ImportTriangles(XmlNode &node, aiMesh *mesh) {
                         mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1];
                         mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1];
                     } else if (it->second->getType() == ResourceType::RT_Texture2DGroup) {
                     } else if (it->second->getType() == ResourceType::RT_Texture2DGroup) {
                         if (mesh->mTextureCoords[0] == nullptr) {
                         if (mesh->mTextureCoords[0] == nullptr) {
-                            Texture2DGroup *group = static_cast<Texture2DGroup *>(it->second);
+                            mesh->mNumUVComponents[0] = 2;
+                            for (unsigned int i = 1; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+                                mesh->mNumUVComponents[i] = 0;
+                            }
+
+                            group = static_cast<Texture2DGroup *>(it->second);
                             const std::string name = ai_to_string(group->mTexId);
                             const std::string name = ai_to_string(group->mTexId);
                             for (size_t i = 0; i < mMaterials.size(); ++i) {
                             for (size_t i = 0; i < mMaterials.size(); ++i) {
                                 if (name == mMaterials[i]->GetName().C_Str()) {
                                 if (name == mMaterials[i]->GetName().C_Str()) {
                                     mesh->mMaterialIndex = static_cast<unsigned int>(i);
                                     mesh->mMaterialIndex = static_cast<unsigned int>(i);
                                 }
                                 }
                             }
                             }
-                            mesh->mTextureCoords[0] = new aiVector3D[group->mTex2dCoords.size()];
-                            for (unsigned int i = 0; i < group->mTex2dCoords.size(); ++i) {
-                                mesh->mTextureCoords[0][i] = aiVector3D(group->mTex2dCoords[i].x, group->mTex2dCoords[i].y, 0);
-                            }
+                            mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
                         }
                         }
                     } 
                     } 
                 }
                 }
             }
             }
 
 
-            aiFace face = ReadTriangle(currentNode);
+            // Load texture coordinates into mesh, when any
+            if (group != nullptr) {
+                size_t i0 = face.mIndices[0];
+                size_t i1 = face.mIndices[1];
+                size_t i2 = face.mIndices[2];
+                mesh->mTextureCoords[0][i0] = aiVector3D(group->mTex2dCoords[texId[0]].x, group->mTex2dCoords[texId[0]].y, 0.0f);
+                mesh->mTextureCoords[0][i1] = aiVector3D(group->mTex2dCoords[texId[1]].x, group->mTex2dCoords[texId[1]].y, 0.0f);
+                mesh->mTextureCoords[0][i2] = aiVector3D(group->mTex2dCoords[texId[2]].x, group->mTex2dCoords[texId[2]].y, 0.0f);
+            }
+
             faces.push_back(face);
             faces.push_back(face);
         }
         }
     }
     }
@@ -578,11 +597,15 @@ aiMaterial *XmlSerializer::readMaterialDef(XmlNode &node, unsigned int basemater
 }
 }
 
 
 void XmlSerializer::StoreMaterialsInScene(aiScene *scene) {
 void XmlSerializer::StoreMaterialsInScene(aiScene *scene) {
-    if (nullptr == scene || mMaterials.empty()) {
+    if (nullptr == scene) {
         return;
         return;
     }
     }
 
 
     scene->mNumMaterials = static_cast<unsigned int>(mMaterials.size());
     scene->mNumMaterials = static_cast<unsigned int>(mMaterials.size());
+    if (scene->mNumMaterials == 0) {
+        return;
+    }
+
     scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
     scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
     for (size_t i = 0; i < mMaterials.size(); ++i) {
     for (size_t i = 0; i < mMaterials.size(); ++i) {
         scene->mMaterials[i] = mMaterials[i];
         scene->mMaterials[i] = mMaterials[i];

+ 1 - 0
code/AssetLib/ASE/ASELoader.cpp

@@ -870,6 +870,7 @@ void ASEImporter::ConvertMaterial(ASE::Material &mat) {
         unsigned int iWire = 1;
         unsigned int iWire = 1;
         mat.pcInstance->AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
         mat.pcInstance->AddProperty<int>((int *)&iWire, 1, AI_MATKEY_ENABLE_WIREFRAME);
     }
     }
+    // fallthrough
     case D3DS::Discreet3DS::Gouraud:
     case D3DS::Discreet3DS::Gouraud:
         eShading = aiShadingMode_Gouraud;
         eShading = aiShadingMode_Gouraud;
         break;
         break;

+ 9 - 4
code/AssetLib/ASE/ASEParser.cpp

@@ -74,7 +74,7 @@ using namespace Assimp::ASE;
             return;                                \
             return;                                \
         }                                          \
         }                                          \
     }                                              \
     }                                              \
-    else if ('\0' == *filePtr) {                   \
+    if ('\0' == *filePtr) {                        \
         return;                                    \
         return;                                    \
     }                                              \
     }                                              \
     if (IsLineEnd(*filePtr) && !bLastWasEndLine) { \
     if (IsLineEnd(*filePtr) && !bLastWasEndLine) { \
@@ -420,6 +420,8 @@ void Parser::ParseLV1SoftSkinBlock() {
                 }
                 }
             }
             }
         }
         }
+        if (*filePtr == '\0')
+            return;
         ++filePtr;
         ++filePtr;
         SkipSpacesAndLineEnd(&filePtr);
         SkipSpacesAndLineEnd(&filePtr);
     }
     }
@@ -646,10 +648,13 @@ void Parser::ParseLV2MaterialBlock(ASE::Material &mat) {
                 }
                 }
 
 
                 // get a reference to the material
                 // get a reference to the material
-                Material &sMat = mat.avSubMaterials[iIndex];
+                if (iIndex < mat.avSubMaterials.size()) {
+                    Material &sMat = mat.avSubMaterials[iIndex];
+
+                    // parse the material block
+                    ParseLV2MaterialBlock(sMat);
+                }
 
 
-                // parse the material block
-                ParseLV2MaterialBlock(sMat);
                 continue;
                 continue;
             }
             }
         }
         }

+ 1 - 1
code/AssetLib/Assxml/AssxmlFileWriter.cpp

@@ -365,7 +365,7 @@ static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene,
 
 
                 ioprintf(io, "\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%u\"",
                 ioprintf(io, "\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%u\"",
                         prop->mKey.data, sz,
                         prop->mKey.data, sz,
-                        ::TextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex);
+                        ::aiTextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex);
 
 
                 if (prop->mType == aiPTI_Float) {
                 if (prop->mType == aiPTI_Float) {
                     ioprintf(io, " size=\"%i\">\n\t\t\t\t",
                     ioprintf(io, " size=\"%i\">\n\t\t\t\t",

+ 4 - 4
code/AssetLib/Blender/BlenderDNA.cpp

@@ -325,10 +325,10 @@ void SectionParser ::Next() {
     stream.SetCurrentPos(current.start + current.size);
     stream.SetCurrentPos(current.start + current.size);
 
 
     const char tmp[] = {
     const char tmp[] = {
-        (const char)stream.GetI1(),
-        (const char)stream.GetI1(),
-        (const char)stream.GetI1(),
-        (const char)stream.GetI1()
+        (char)stream.GetI1(),
+        (char)stream.GetI1(),
+        (char)stream.GetI1(),
+        (char)stream.GetI1()
     };
     };
     current.id = std::string(tmp, tmp[3] ? 4 : tmp[2] ? 3 : tmp[1] ? 2 : 1);
     current.id = std::string(tmp, tmp[3] ? 4 : tmp[2] ? 3 : tmp[1] ? 2 : 1);
 
 

+ 2 - 2
code/AssetLib/Blender/BlenderLoader.cpp

@@ -281,7 +281,7 @@ void BlenderImporter::ExtractScene(Scene &out, const FileDatabase &file) {
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void BlenderImporter::ParseSubCollection(const Blender::Scene &in, aiNode *root, std::shared_ptr<Collection> collection, ConversionData &conv_data) {
+void BlenderImporter::ParseSubCollection(const Blender::Scene &in, aiNode *root, const std::shared_ptr<Collection>& collection, ConversionData &conv_data) {
 
 
     std::deque<Object *> root_objects;
     std::deque<Object *> root_objects;
     // Count number of objects
     // Count number of objects
@@ -986,7 +986,7 @@ void BlenderImporter::ConvertMesh(const Scene & /*in*/, const Object * /*obj*/,
     // key is material number, value is the TextureUVMapping for the material
     // key is material number, value is the TextureUVMapping for the material
     typedef std::map<uint32_t, TextureUVMapping> MaterialTextureUVMappings;
     typedef std::map<uint32_t, TextureUVMapping> MaterialTextureUVMappings;
     MaterialTextureUVMappings matTexUvMappings;
     MaterialTextureUVMappings matTexUvMappings;
-    const uint32_t maxMat = static_cast<const uint32_t>(mesh->mat.size());
+    const uint32_t maxMat = static_cast<uint32_t>(mesh->mat.size());
     for (uint32_t m = 0; m < maxMat; ++m) {
     for (uint32_t m = 0; m < maxMat; ++m) {
         // get material by index
         // get material by index
         const std::shared_ptr<Material> pMat = mesh->mat[m];
         const std::shared_ptr<Material> pMat = mesh->mat[m];

+ 1 - 1
code/AssetLib/Blender/BlenderLoader.h

@@ -117,7 +117,7 @@ protected:
     void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
     void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) override;
     void ParseBlendFile(Blender::FileDatabase &out, std::shared_ptr<IOStream> stream);
     void ParseBlendFile(Blender::FileDatabase &out, std::shared_ptr<IOStream> stream);
     void ExtractScene(Blender::Scene &out, const Blender::FileDatabase &file);
     void ExtractScene(Blender::Scene &out, const Blender::FileDatabase &file);
-    void ParseSubCollection(const Blender::Scene &in, aiNode *root, std::shared_ptr<Blender::Collection> collection, Blender::ConversionData &conv_data);
+    void ParseSubCollection(const Blender::Scene &in, aiNode *root, const std::shared_ptr<Blender::Collection>& collection, Blender::ConversionData &conv_data);
     void ConvertBlendFile(aiScene *out, const Blender::Scene &in, const Blender::FileDatabase &file);
     void ConvertBlendFile(aiScene *out, const Blender::Scene &in, const Blender::FileDatabase &file);
 
 
 private:
 private:

+ 5 - 0
code/AssetLib/Collada/ColladaHelper.h

@@ -621,6 +621,11 @@ struct Animation {
 
 
         for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
         for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
             Animation *anim = *it;
             Animation *anim = *it;
+            // Assign the first animation name to the parent if empty.
+            // This prevents the animation name from being lost when animations are combined
+            if (mName.empty()) {
+              mName = anim->mName;
+            }
             CombineSingleChannelAnimationsRecursively(anim);
             CombineSingleChannelAnimationsRecursively(anim);
 
 
             if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
             if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&

+ 6 - 3
code/AssetLib/Collada/ColladaLoader.cpp

@@ -102,6 +102,7 @@ ColladaLoader::ColladaLoader() :
         mTextures(),
         mTextures(),
         mAnims(),
         mAnims(),
         noSkeletonMesh(false),
         noSkeletonMesh(false),
+        removeEmptyBones(false),
         ignoreUpDirection(false),
         ignoreUpDirection(false),
         useColladaName(false),
         useColladaName(false),
         mNodeNameCounter(0) {
         mNodeNameCounter(0) {
@@ -130,6 +131,7 @@ bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ColladaLoader::SetupProperties(const Importer *pImp) {
 void ColladaLoader::SetupProperties(const Importer *pImp) {
     noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
     noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
+    removeEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true) != 0;
     ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0;
     ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0;
     useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0;
     useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0;
 }
 }
@@ -798,9 +800,10 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
         // count the number of bones which influence vertices of the current submesh
         // count the number of bones which influence vertices of the current submesh
         size_t numRemainingBones = 0;
         size_t numRemainingBones = 0;
         for (const auto & dstBone : dstBones) {
         for (const auto & dstBone : dstBones) {
-            if (!dstBone.empty()) {
-                ++numRemainingBones;
+            if (dstBone.empty() && removeEmptyBones) {
+                continue;
             }
             }
+            ++numRemainingBones;
         }
         }
 
 
         // create bone array and copy bone weights one by one
         // create bone array and copy bone weights one by one
@@ -809,7 +812,7 @@ aiMesh *ColladaLoader::CreateMesh(const ColladaParser &pParser, const Mesh *pSrc
         size_t boneCount = 0;
         size_t boneCount = 0;
         for (size_t a = 0; a < numBones; ++a) {
         for (size_t a = 0; a < numBones; ++a) {
             // omit bones without weights
             // omit bones without weights
-            if (dstBones[a].empty()) {
+            if (dstBones[a].empty() && removeEmptyBones) {
                 continue;
                 continue;
             }
             }
 
 

+ 1 - 0
code/AssetLib/Collada/ColladaLoader.h

@@ -237,6 +237,7 @@ protected:
     std::vector<aiAnimation *> mAnims;
     std::vector<aiAnimation *> mAnims;
 
 
     bool noSkeletonMesh;
     bool noSkeletonMesh;
+    bool removeEmptyBones;
     bool ignoreUpDirection;
     bool ignoreUpDirection;
     bool useColladaName;
     bool useColladaName;
 
 

+ 2 - 1
code/AssetLib/Collada/ColladaParser.cpp

@@ -1616,6 +1616,7 @@ void ColladaParser::ReadIndexData(XmlNode &node, Mesh &pMesh) {
                     XmlParser::getValueAsString(currentNode, v);
                     XmlParser::getValueAsString(currentNode, v);
                     const char *content = v.c_str();
                     const char *content = v.c_str();
                     vcount.reserve(numPrimitives);
                     vcount.reserve(numPrimitives);
+                    SkipSpacesAndLineEnd(&content);
                     for (unsigned int a = 0; a < numPrimitives; a++) {
                     for (unsigned int a = 0; a < numPrimitives; a++) {
                         if (*content == 0) {
                         if (*content == 0) {
                             throw DeadlyImportError("Expected more values while reading <vcount> contents.");
                             throw DeadlyImportError("Expected more values while reading <vcount> contents.");
@@ -2057,7 +2058,7 @@ void ColladaParser::ReadSceneNode(XmlNode &node, Node *pNode) {
                 XmlParser::getStdStrAttribute(currentNode, "id", child->mID);
                 XmlParser::getStdStrAttribute(currentNode, "id", child->mID);
             }
             }
             if (XmlParser::hasAttribute(currentNode, "sid")) {
             if (XmlParser::hasAttribute(currentNode, "sid")) {
-                XmlParser::getStdStrAttribute(currentNode, "id", child->mSID);
+                XmlParser::getStdStrAttribute(currentNode, "sid", child->mSID);
             }
             }
             if (XmlParser::hasAttribute(currentNode, "name")) {
             if (XmlParser::hasAttribute(currentNode, "name")) {
                 XmlParser::getStdStrAttribute(currentNode, "name", child->mName);
                 XmlParser::getStdStrAttribute(currentNode, "name", child->mName);

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

@@ -368,7 +368,9 @@ void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& bloc
         // XXX this would be the place to implement recursive expansion if needed.
         // XXX this would be the place to implement recursive expansion if needed.
         const DXF::Block& bl_src = *(*it).second;
         const DXF::Block& bl_src = *(*it).second;
 
 
-        for (std::shared_ptr<const DXF::PolyLine> pl_in : bl_src.lines) {
+        const size_t size = bl_src.lines.size(); // the size may increase in the loop
+        for (size_t i = 0; i < size; ++i) {
+            std::shared_ptr<const DXF::PolyLine> pl_in = bl_src.lines[i];
             if (!pl_in) {
             if (!pl_in) {
                 ASSIMP_LOG_ERROR("DXF: PolyLine instance is nullptr, skipping.");
                 ASSIMP_LOG_ERROR("DXF: PolyLine instance is nullptr, skipping.");
                 continue;
                 continue;

+ 0 - 21
code/AssetLib/FBX/FBXAnimation.cpp

@@ -4,7 +4,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,
@@ -87,11 +86,6 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element &element, const std::s
     }
     }
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-AnimationCurve::~AnimationCurve() {
-    // empty
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name,
 AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name,
         const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
         const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
@@ -147,11 +141,6 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, cons
     props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
     props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-AnimationCurveNode::~AnimationCurveNode() {
-    // empty
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 const AnimationCurveMap &AnimationCurveNode::Curves() const {
 const AnimationCurveMap &AnimationCurveNode::Curves() const {
     if (curves.empty()) {
     if (curves.empty()) {
@@ -193,11 +182,6 @@ AnimationLayer::AnimationLayer(uint64_t id, const Element &element, const std::s
     props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
     props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-AnimationLayer::~AnimationLayer() {
-    // empty
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/,
 AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/,
         size_t whitelist_size /*= 0*/) const {
         size_t whitelist_size /*= 0*/) const {
@@ -279,11 +263,6 @@ AnimationStack::AnimationStack(uint64_t id, const Element &element, const std::s
     }
     }
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-AnimationStack::~AnimationStack() {
-    // empty
-}
-
 } // namespace FBX
 } // namespace FBX
 } // namespace Assimp
 } // namespace Assimp
 
 

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

@@ -472,7 +472,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
     }
     }
     catch (const DeadlyImportError& e)
     catch (const DeadlyImportError& e)
     {
     {
-        if (!is64bits && (length > std::numeric_limits<std::uint32_t>::max())) {
+        if (!is64bits && (length > std::numeric_limits<uint32_t>::max())) {
             throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (", ai_to_string(version), ") of the FBX format. (", e.what(), ")");
             throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (", ai_to_string(version), ") of the FBX format. (", e.what(), ")");
         }
         }
         throw;
         throw;

+ 2 - 1
code/AssetLib/FBX/FBXCommon.h

@@ -50,7 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace Assimp {
 namespace FBX {
 namespace FBX {
 
 
-const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
+static constexpr size_t NumNullRecords = 25;
+const char NULL_RECORD[NumNullRecords] = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
     '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
     '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
     '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
     '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'
 }; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)
 }; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)

+ 0 - 1
code/AssetLib/FBX/FBXCompileConfig.h

@@ -4,7 +4,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,

+ 116 - 62
code/AssetLib/FBX/FBXConverter.cpp

@@ -65,12 +65,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <stdlib.h>
 #include <stdlib.h>
 #include <cstdint>
 #include <cstdint>
 #include <iomanip>
 #include <iomanip>
-#include <iostream>
 #include <iterator>
 #include <iterator>
 #include <memory>
 #include <memory>
 #include <sstream>
 #include <sstream>
-#include <tuple>
-#include <vector>
 
 
 namespace Assimp {
 namespace Assimp {
 namespace FBX {
 namespace FBX {
@@ -187,8 +184,7 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
 
 
 /// This struct manages nodes which may or may not end up in the node hierarchy.
 /// This struct manages nodes which may or may not end up in the node hierarchy.
 /// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
 /// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
-struct FBXConverter::PotentialNode
-{
+struct FBXConverter::PotentialNode {
     PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
     PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
     PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
     PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
     aiNode* operator->() { return mNode; }
     aiNode* operator->() { return mNode; }
@@ -231,7 +227,6 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
         if (nullptr != model) {
         if (nullptr != model) {
             nodes_chain.clear();
             nodes_chain.clear();
             post_nodes_chain.clear();
             post_nodes_chain.clear();
-
             aiMatrix4x4 new_abs_transform = parent->mTransformation;
             aiMatrix4x4 new_abs_transform = parent->mTransformation;
             std::string node_name = FixNodeName(model->Name());
             std::string node_name = FixNodeName(model->Name());
             // even though there is only a single input node, the design of
             // even though there is only a single input node, the design of
@@ -266,8 +261,6 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
 
 
                 child->mParent = last_parent;
                 child->mParent = last_parent;
                 last_parent = child.mNode;
                 last_parent = child.mNode;
-
-                new_abs_transform *= child->mTransformation;
             }
             }
 
 
             // attach geometry
             // attach geometry
@@ -290,8 +283,6 @@ void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node)
 
 
                     postnode->mParent = last_parent;
                     postnode->mParent = last_parent;
                     last_parent = postnode.mNode;
                     last_parent = postnode.mNode;
-
-                    new_abs_transform *= postnode->mTransformation;
                 }
                 }
             } else {
             } else {
                 // free the nodes we allocated as we don't need them
                 // free the nodes we allocated as we don't need them
@@ -452,7 +443,7 @@ void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueNam
     auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
     auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
     unsigned int &i = it_pair.first->second;
     unsigned int &i = it_pair.first->second;
     while (!it_pair.second) {
     while (!it_pair.second) {
-        i++;
+        ++i;
         std::ostringstream ext;
         std::ostringstream ext;
         ext << name << std::setfill('0') << std::setw(3) << i;
         ext << name << std::setfill('0') << std::setw(3) << i;
         uniqueName = ext.str();
         uniqueName = ext.str();
@@ -651,9 +642,8 @@ void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D &rot
 
 
 bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
 bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
     const PropertyTable &props = model.Props();
     const PropertyTable &props = model.Props();
-    bool ok;
 
 
-    const float zero_epsilon = ai_epsilon;
+    const auto zero_epsilon = ai_epsilon;
     const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
     const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
     for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
     for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
         const TransformationComp comp = static_cast<TransformationComp>(i);
         const TransformationComp comp = static_cast<TransformationComp>(i);
@@ -665,6 +655,7 @@ bool FBXConverter::NeedsComplexTransformationChain(const Model &model) {
 
 
         bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
         bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling);
 
 
+        bool ok = true;
         const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
         const aiVector3D &v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok);
         if (ok && scale_compare) {
         if (ok && scale_compare) {
             if ((v - all_ones).SquareLength() > zero_epsilon) {
             if ((v - all_ones).SquareLength() > zero_epsilon) {
@@ -899,20 +890,17 @@ void FBXConverter::SetupNodeMetadata(const Model &model, aiNode &nd) {
     }
     }
 }
 }
 
 
-void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node,
-        const aiMatrix4x4 &absolute_transform) {
+void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
     const std::vector<const Geometry *> &geos = model.GetGeometry();
     const std::vector<const Geometry *> &geos = model.GetGeometry();
 
 
     std::vector<unsigned int> meshes;
     std::vector<unsigned int> meshes;
     meshes.reserve(geos.size());
     meshes.reserve(geos.size());
 
 
     for (const Geometry *geo : geos) {
     for (const Geometry *geo : geos) {
-
         const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo);
         const MeshGeometry *const mesh = dynamic_cast<const MeshGeometry *>(geo);
         const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo);
         const LineGeometry *const line = dynamic_cast<const LineGeometry *>(geo);
         if (mesh) {
         if (mesh) {
-            const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node,
-                    absolute_transform);
+            const std::vector<unsigned int> &indices = ConvertMesh(*mesh, model, parent, root_node, absolute_transform);
             std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
             std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
         } else if (line) {
         } else if (line) {
             const std::vector<unsigned int> &indices = ConvertLine(*line, root_node);
             const std::vector<unsigned int> &indices = ConvertLine(*line, root_node);
@@ -933,8 +921,7 @@ void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root
 }
 }
 
 
 std::vector<unsigned int>
 std::vector<unsigned int>
-FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
-        const aiMatrix4x4 &absolute_transform) {
+FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform) {
     std::vector<unsigned int> temp;
     std::vector<unsigned int> temp;
 
 
     MeshMap::const_iterator it = meshes_converted.find(&mesh);
     MeshMap::const_iterator it = meshes_converted.find(&mesh);
@@ -957,7 +944,7 @@ FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *
         const MatIndexArray::value_type base = mindices[0];
         const MatIndexArray::value_type base = mindices[0];
         for (MatIndexArray::value_type index : mindices) {
         for (MatIndexArray::value_type index : mindices) {
             if (index != base) {
             if (index != base) {
-                return ConvertMeshMultiMaterial(mesh, model, parent, root_node, absolute_transform);
+                return ConvertMeshMultiMaterial(mesh, model, absolute_transform, parent, root_node);
             }
             }
         }
         }
     }
     }
@@ -1031,9 +1018,36 @@ aiMesh *FBXConverter::SetupEmptyMesh(const Geometry &mesh, aiNode *parent) {
     return out_mesh;
     return out_mesh;
 }
 }
 
 
-unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
-        const aiMatrix4x4 &absolute_transform, aiNode *parent,
-        aiNode *) {
+static aiSkeleton *createAiSkeleton(SkeletonBoneContainer &sbc) {
+    if (sbc.MeshArray.empty() || sbc.SkeletonBoneToMeshLookup.empty()) {
+        return nullptr;
+    }
+
+    aiSkeleton *skeleton = new aiSkeleton;
+    for (auto *mesh : sbc.MeshArray) {
+        auto it = sbc.SkeletonBoneToMeshLookup.find(mesh);
+        if (it == sbc.SkeletonBoneToMeshLookup.end()) {
+            continue;
+        }
+        SkeletonBoneArray *ba = it->second;
+        if (ba == nullptr) {
+            continue;
+        }
+
+        skeleton->mNumBones = static_cast<unsigned int>(ba->size());
+        skeleton->mBones = new aiSkeletonBone*[skeleton->mNumBones];
+        size_t index = 0;
+        for (auto bone : (* ba)) {
+            skeleton->mBones[index] = bone;
+            ++index;
+        }
+    }
+
+    return skeleton;
+}
+
+unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
+        aiNode *parent, aiNode *) {
     const MatIndexArray &mindices = mesh.GetMaterialIndices();
     const MatIndexArray &mindices = mesh.GetMaterialIndices();
     aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
     aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
 
 
@@ -1151,8 +1165,15 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
         ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
         ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
     }
     }
 
 
-    if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) {
+    if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && !doc.Settings().useSkeleton) {
         ConvertWeights(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr);
         ConvertWeights(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr);
+    } else if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr && doc.Settings().useSkeleton) {
+        SkeletonBoneContainer sbc;
+        ConvertWeightsToSkeleton(out_mesh, mesh, absolute_transform, parent, NO_MATERIAL_SEPARATION, nullptr, sbc);
+        aiSkeleton *skeleton = createAiSkeleton(sbc);
+        if (skeleton != nullptr) {
+            mSkeletons.emplace_back(skeleton);
+        }
     }
     }
 
 
     std::vector<aiAnimMesh *> animMeshes;
     std::vector<aiAnimMesh *> animMeshes;
@@ -1199,9 +1220,8 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
 }
 }
 
 
 std::vector<unsigned int>
 std::vector<unsigned int>
-FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent,
-        aiNode *root_node,
-        const aiMatrix4x4 &absolute_transform) {
+FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, aiNode *parent,
+        aiNode *root_node) {
     const MatIndexArray &mindices = mesh.GetMaterialIndices();
     const MatIndexArray &mindices = mesh.GetMaterialIndices();
     ai_assert(mindices.size());
     ai_assert(mindices.size());
 
 
@@ -1211,7 +1231,7 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
     for (MatIndexArray::value_type index : mindices) {
     for (MatIndexArray::value_type index : mindices) {
         if (had.find(index) == had.end()) {
         if (had.find(index) == had.end()) {
 
 
-            indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node, absolute_transform));
+            indices.push_back(ConvertMeshMultiMaterial(mesh, model, absolute_transform, index, parent, root_node));
             had.insert(index);
             had.insert(index);
         }
         }
     }
     }
@@ -1219,10 +1239,8 @@ FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &mo
     return indices;
     return indices;
 }
 }
 
 
-unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model,
-        MatIndexArray::value_type index,
-        aiNode *parent, aiNode *,
-        const aiMatrix4x4 &absolute_transform) {
+unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
+        MatIndexArray::value_type index, aiNode *parent, aiNode *) {
     aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
     aiMesh *const out_mesh = SetupEmptyMesh(mesh, parent);
 
 
     const MatIndexArray &mindices = mesh.GetMaterialIndices();
     const MatIndexArray &mindices = mesh.GetMaterialIndices();
@@ -1435,20 +1453,47 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
     return static_cast<unsigned int>(mMeshes.size() - 1);
     return static_cast<unsigned int>(mMeshes.size() - 1);
 }
 }
 
 
-void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
-        const aiMatrix4x4 &absolute_transform,
+static void copyBoneToSkeletonBone(aiMesh *mesh, aiBone *bone, aiSkeletonBone *skeletonBone ) {
+    skeletonBone->mNumnWeights = bone->mNumWeights;
+    skeletonBone->mWeights = bone->mWeights;
+    skeletonBone->mOffsetMatrix = bone->mOffsetMatrix;
+    skeletonBone->mMeshId = mesh;
+    skeletonBone->mNode = bone->mNode;
+    skeletonBone->mParent = -1;
+}
+
+void FBXConverter::ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent, unsigned int materialIndex,
+        std::vector<unsigned int> *outputVertStartIndices, SkeletonBoneContainer &skeletonContainer) {
+
+    if (skeletonContainer.SkeletonBoneToMeshLookup.find(out) != skeletonContainer.SkeletonBoneToMeshLookup.end()) {
+        return;
+    }
+
+    ConvertWeights(out, geo, absolute_transform, parent, materialIndex, outputVertStartIndices);
+    skeletonContainer.MeshArray.emplace_back(out);
+    SkeletonBoneArray *ba = new SkeletonBoneArray;
+    for (size_t i = 0; i < out->mNumBones; ++i) {
+        aiBone *bone = out->mBones[i];
+        if (bone == nullptr) {
+            continue;
+        }
+        aiSkeletonBone *skeletonBone = new aiSkeletonBone;
+        copyBoneToSkeletonBone(out, bone, skeletonBone);
+        ba->emplace_back(skeletonBone);
+    }
+    skeletonContainer.SkeletonBoneToMeshLookup[out] = ba;
+}
+
+void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
         aiNode *parent, unsigned int materialIndex,
         aiNode *parent, unsigned int materialIndex,
         std::vector<unsigned int> *outputVertStartIndices) {
         std::vector<unsigned int> *outputVertStartIndices) {
     ai_assert(geo.DeformerSkin());
     ai_assert(geo.DeformerSkin());
 
 
-    std::vector<size_t> out_indices;
-    std::vector<size_t> index_out_indices;
-    std::vector<size_t> count_out_indices;
+    std::vector<size_t> out_indices, index_out_indices, count_out_indices;
 
 
     const Skin &sk = *geo.DeformerSkin();
     const Skin &sk = *geo.DeformerSkin();
 
 
-    std::vector<aiBone *> bones;
-
+    std::vector<aiBone*> bones;
     const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
     const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
     ai_assert(no_mat_check || outputVertStartIndices);
     ai_assert(no_mat_check || outputVertStartIndices);
 
 
@@ -1521,26 +1566,20 @@ void FBXConverter::ConvertWeights(aiMesh *out, const MeshGeometry &geo,
         out->mBones = nullptr;
         out->mBones = nullptr;
         out->mNumBones = 0;
         out->mNumBones = 0;
         return;
         return;
-    } else {
-        out->mBones = new aiBone *[bones.size()]();
-        out->mNumBones = static_cast<unsigned int>(bones.size());
+    } 
 
 
-        std::swap_ranges(bones.begin(), bones.end(), out->mBones);
-    }
+    out->mBones = new aiBone *[bones.size()]();
+    out->mNumBones = static_cast<unsigned int>(bones.size());
+    std::swap_ranges(bones.begin(), bones.end(), out->mBones);
 }
 }
 
 
-const aiNode *GetNodeByName(aiNode *current_node) {
-    aiNode *iter = current_node;
-    //printf("Child count: %d", iter->mNumChildren);
-    return iter;
-}
-
-void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
+void FBXConverter::ConvertCluster(std::vector<aiBone*> &local_mesh_bones, const Cluster *cluster,
         std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
         std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
-        std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
+        std::vector<size_t> &count_out_indices, const aiMatrix4x4 & /* absolute_transform*/,
         aiNode *) {
         aiNode *) {
-    ai_assert(cl); // make sure cluster valid
-    std::string deformer_name = cl->TargetNode()->Name();
+    ai_assert(cluster != nullptr); // make sure cluster valid
+
+    std::string deformer_name = cluster->TargetNode()->Name();
     aiString bone_name = aiString(FixNodeName(deformer_name));
     aiString bone_name = aiString(FixNodeName(deformer_name));
 
 
     aiBone *bone = nullptr;
     aiBone *bone = nullptr;
@@ -1553,14 +1592,16 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
         bone = new aiBone();
         bone = new aiBone();
         bone->mName = bone_name;
         bone->mName = bone_name;
 
 
+        bone->mOffsetMatrix = cluster->Transform();
         // store local transform link for post processing
         // store local transform link for post processing
-        bone->mOffsetMatrix = cl->TransformLink();
+        /*
+        bone->mOffsetMatrix = cluster->TransformLink();
         bone->mOffsetMatrix.Inverse();
         bone->mOffsetMatrix.Inverse();
 
 
         aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
         aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
 
 
         bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
         bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
-
+        */
         //
         //
         // Now calculate the aiVertexWeights
         // Now calculate the aiVertexWeights
         //
         //
@@ -1571,7 +1612,7 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
         cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
         cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
 
 
         const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
         const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
-        const WeightArray &weights = cl->GetWeights();
+        const WeightArray &weights = cluster->GetWeights();
 
 
         const size_t c = index_out_indices.size();
         const size_t c = index_out_indices.size();
         for (size_t i = 0; i < c; ++i) {
         for (size_t i = 0; i < c; ++i) {
@@ -2161,6 +2202,9 @@ void FBXConverter::SetShadingPropertiesCommon(aiMaterial *out_mat, const Propert
     const float ShininessExponent = PropertyGet<float>(props, "ShininessExponent", ok);
     const float ShininessExponent = PropertyGet<float>(props, "ShininessExponent", ok);
     if (ok) {
     if (ok) {
         out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS);
         out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS);
+         // Match Blender behavior to extract roughness when only shininess is present
+        const float roughness = 1.0f - (sqrt(ShininessExponent) / 10.0f);
+        out_mat->AddProperty(&roughness, 1, AI_MATKEY_ROUGHNESS_FACTOR);
     }
     }
 
 
     // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
     // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
@@ -2613,7 +2657,7 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
                 meshMorphAnim->mNumKeys = numKeys;
                 meshMorphAnim->mNumKeys = numKeys;
                 meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys];
                 meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys];
                 unsigned int j = 0;
                 unsigned int j = 0;
-                for (auto animIt : *animData) {
+                for (auto &animIt : *animData) {
                     morphKeyData *keyData = animIt.second;
                     morphKeyData *keyData = animIt.second;
                     unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size());
                     unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size());
                     meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
                     meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
@@ -3188,7 +3232,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
 
 
     bool ok = false;
     bool ok = false;
     
     
-    const float zero_epsilon = ai_epsilon;
+    const auto zero_epsilon = ai_epsilon;
 
 
     const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
     const aiVector3D& preRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
     if (ok && preRotation.SquareLength() > zero_epsilon) {
     if (ok && preRotation.SquareLength() > zero_epsilon) {
@@ -3326,13 +3370,17 @@ FBXConverter::KeyFrameListList FBXConverter::GetRotationKeyframeList(const std::
                 float vc = curve->GetValues().at(1);
                 float vc = curve->GetValues().at(1);
                 for (size_t n = 1; n < count; n++) {
                 for (size_t n = 1; n < count; n++) {
                     while (std::abs(vc - vp) >= 180.0f) {
                     while (std::abs(vc - vp) >= 180.0f) {
-                        float step = std::floor(float(tc - tp) / (vc - vp) * 179.0f);
+                        double step = std::floor(double(tc - tp) / std::abs(vc - vp) * 179.0f);
                         int64_t tnew = tp + int64_t(step);
                         int64_t tnew = tp + int64_t(step);
-                        float vnew = vp + (vc - vp) * step / float(tc - tp);
+                        float vnew = vp + (vc - vp) * float(step / (tc - tp));
                         if (tnew >= adj_start && tnew <= adj_stop) {
                         if (tnew >= adj_start && tnew <= adj_stop) {
                             Keys->push_back(tnew);
                             Keys->push_back(tnew);
                             Values->push_back(vnew);
                             Values->push_back(vnew);
                         }
                         }
+                        else {
+                            // Something broke
+                            break;
+                        }
                         tp = tnew;
                         tp = tnew;
                         vp = vnew;
                         vp = vnew;
                     }
                     }
@@ -3633,6 +3681,12 @@ void FBXConverter::TransferDataToScene() {
 
 
         std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures);
         std::swap_ranges(textures.begin(), textures.end(), mSceneOut->mTextures);
     }
     }
+
+    if (!mSkeletons.empty()) {
+        mSceneOut->mSkeletons = new aiSkeleton *[mSkeletons.size()];
+        mSceneOut->mNumSkeletons = static_cast<unsigned int>(mSkeletons.size());
+        std::swap_ranges(mSkeletons.begin(), mSkeletons.end(), mSceneOut->mSkeletons);
+    }
 }
 }
 
 
 void FBXConverter::ConvertOrphanedEmbeddedTextures() {
 void FBXConverter::ConvertOrphanedEmbeddedTextures() {

+ 29 - 16
code/AssetLib/FBX/FBXConverter.h

@@ -75,7 +75,18 @@ typedef std::map<int64_t, morphKeyData*> morphAnimData;
 namespace Assimp {
 namespace Assimp {
 namespace FBX {
 namespace FBX {
 
 
+class MeshGeometry;
+
+using SkeletonBoneArray = std::vector<aiSkeletonBone *>;
+using SkeletonBoneToMesh = std::map<aiMesh*, SkeletonBoneArray*>;
+
+struct SkeletonBoneContainer {
+    std::vector<aiMesh *> MeshArray;
+    SkeletonBoneToMesh SkeletonBoneToMeshLookup;
+};
+
 class Document;
 class Document;
+
 /**
 /**
  *  Convert a FBX #Document to #aiScene
  *  Convert a FBX #Document to #aiScene
  *  @param out Empty scene to be populated
  *  @param out Empty scene to be populated
@@ -180,14 +191,12 @@ private:
     void SetupNodeMetadata(const Model& model, aiNode& nd);
     void SetupNodeMetadata(const Model& model, aiNode& nd);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
-    void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node,
-                      const aiMatrix4x4 &absolute_transform);
+    void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
     // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
     std::vector<unsigned int>
     std::vector<unsigned int>
-    ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
-                const aiMatrix4x4 &absolute_transform);
+    ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     std::vector<unsigned int> ConvertLine(const LineGeometry& line, aiNode *root_node);
     std::vector<unsigned int> ConvertLine(const LineGeometry& line, aiNode *root_node);
@@ -196,18 +205,16 @@ private:
     aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
     aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
-    unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
-                                           const aiMatrix4x4 &absolute_transform, aiNode *parent,
-                                           aiNode *root_node);
+    unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform,
+                                           aiNode *parent, aiNode *root_node);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     std::vector<unsigned int>
     std::vector<unsigned int>
-    ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
-                             const aiMatrix4x4 &absolute_transform);
+    ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, aiNode *parent, aiNode *root_node);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
-    unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index,
-                                          aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
+    unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, const aiMatrix4x4 &absolute_transform, MatIndexArray::value_type index,
+                                          aiNode *parent, aiNode *root_node);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */
     static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */
@@ -220,15 +227,19 @@ private:
     *  - outputVertStartIndices is only used when a material index is specified, it gives for
     *  - outputVertStartIndices is only used when a material index is specified, it gives for
     *    each output vertex the DOM index it maps to.
     *    each output vertex the DOM index it maps to.
     */
     */
-    void ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
-            aiNode *parent = nullptr, unsigned int materialIndex = NO_MATERIAL_SEPARATION,
+    void ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, aiNode *parent = nullptr,
+            unsigned int materialIndex = NO_MATERIAL_SEPARATION,
             std::vector<unsigned int> *outputVertStartIndices = nullptr);
             std::vector<unsigned int> *outputVertStartIndices = nullptr);
 
 
+    // ------------------------------------------------------------------------------------------------
+    void ConvertWeightsToSkeleton(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
+            aiNode *parent, unsigned int materialIndex, std::vector<unsigned int> *outputVertStartIndices,
+            SkeletonBoneContainer &skeletonContainer);
+
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
     void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
                         std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
                         std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
-                        std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
-                        aiNode *parent );
+            std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform, aiNode *parent);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
     void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
@@ -301,7 +312,8 @@ private:
     void ConvertAnimationStack(const AnimationStack& st);
     void ConvertAnimationStack(const AnimationStack& st);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
-    void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node);
+    void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas,
+        const BlendShapeChannel* bsc, const AnimationCurveNode* node);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
     void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims,
@@ -450,6 +462,7 @@ private:
 
 
     double anim_fps;
     double anim_fps;
 
 
+    std::vector<aiSkeleton *> mSkeletons;
     aiScene* const mSceneOut;
     aiScene* const mSceneOut;
     const FBX::Document& doc;
     const FBX::Document& doc;
     bool mRemoveEmptyBones;
     bool mRemoveEmptyBones;

+ 2 - 5
code/AssetLib/FBX/FBXDeformer.cpp

@@ -4,7 +4,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,
@@ -58,16 +57,14 @@ namespace FBX {
 using namespace Util;
 using namespace Util;
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-    : Object(id,element,name)
-{
+Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name) :
+        Object(id,element,name) {
     const Scope& sc = GetRequiredScope(element);
     const Scope& sc = GetRequiredScope(element);
 
 
     const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
     const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
     props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
     props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true);
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 Deformer::~Deformer()
 Deformer::~Deformer()
 {
 {

+ 2 - 2
code/AssetLib/FBX/FBXDocument.cpp

@@ -67,7 +67,7 @@ namespace FBX {
 using namespace Util;
 using namespace Util;
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) : 
+LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) :
         doc(doc), element(element), id(id), flags() {
         doc(doc), element(element), id(id), flags() {
     // empty
     // empty
 }
 }
@@ -544,7 +544,7 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
     ai_assert( count != 0 );
     ai_assert( count != 0 );
     ai_assert( count <= MAX_CLASSNAMES);
     ai_assert( count <= MAX_CLASSNAMES);
 
 
-    size_t lengths[MAX_CLASSNAMES];
+    size_t lengths[MAX_CLASSNAMES] = {};
 
 
     const size_t c = count;
     const size_t c = count;
     for (size_t i = 0; i < c; ++i) {
     for (size_t i = 0; i < c; ++i) {

+ 10 - 10
code/AssetLib/FBX/FBXDocument.h

@@ -164,7 +164,7 @@ class NodeAttribute : public Object {
 public:
 public:
     NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name);
 
 
-    virtual ~NodeAttribute();
+    virtual ~NodeAttribute() = default;
 
 
     const PropertyTable& Props() const {
     const PropertyTable& Props() const {
         ai_assert(props.get());
         ai_assert(props.get());
@@ -180,7 +180,7 @@ class CameraSwitcher : public NodeAttribute {
 public:
 public:
     CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name);
 
 
-    virtual ~CameraSwitcher();
+    virtual ~CameraSwitcher() = default;
 
 
     int CameraID() const {
     int CameraID() const {
         return cameraId;
         return cameraId;
@@ -225,7 +225,7 @@ class Camera : public NodeAttribute {
 public:
 public:
     Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name);
 
 
-    virtual  ~Camera();
+    virtual  ~Camera() = default;
 
 
     fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0))
     fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0))
     fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0))
     fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0))
@@ -250,21 +250,21 @@ public:
 class Null : public NodeAttribute {
 class Null : public NodeAttribute {
 public:
 public:
     Null(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     Null(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-    virtual ~Null();
+    virtual ~Null() = default;
 };
 };
 
 
 /** DOM base class for FBX limb node markers attached to a node */
 /** DOM base class for FBX limb node markers attached to a node */
 class LimbNode : public NodeAttribute {
 class LimbNode : public NodeAttribute {
 public:
 public:
     LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-    virtual ~LimbNode();
+    virtual ~LimbNode() = default;
 };
 };
 
 
 /** DOM base class for FBX lights attached to a node */
 /** DOM base class for FBX lights attached to a node */
 class Light : public NodeAttribute {
 class Light : public NodeAttribute {
 public:
 public:
     Light(uint64_t id, const Element& element, const Document& doc, const std::string& name);
     Light(uint64_t id, const Element& element, const Document& doc, const std::string& name);
-    virtual ~Light();
+    virtual ~Light() = default;
 
 
     enum Type {
     enum Type {
         Type_Point,
         Type_Point,
@@ -690,7 +690,7 @@ using KeyValueList = std::vector<float>;
 class AnimationCurve : public Object {
 class AnimationCurve : public Object {
 public:
 public:
     AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc);
     AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc);
-    virtual ~AnimationCurve();
+    virtual ~AnimationCurve() = default;
 
 
     /** get list of keyframe positions (time).
     /** get list of keyframe positions (time).
      *  Invariant: |GetKeys()| > 0 */
      *  Invariant: |GetKeys()| > 0 */
@@ -731,7 +731,7 @@ public:
     AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc,
     AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc,
             const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0);
             const char *const *target_prop_whitelist = nullptr, size_t whitelist_size = 0);
 
 
-    virtual ~AnimationCurveNode();
+    virtual ~AnimationCurveNode() = default;
 
 
     const PropertyTable& Props() const {
     const PropertyTable& Props() const {
         ai_assert(props.get());
         ai_assert(props.get());
@@ -776,7 +776,7 @@ using AnimationCurveNodeList = std::vector<const AnimationCurveNode*>;
 class AnimationLayer : public Object {
 class AnimationLayer : public Object {
 public:
 public:
     AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc);
     AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc);
-    virtual ~AnimationLayer();
+    virtual ~AnimationLayer() = default;
 
 
     const PropertyTable& Props() const {
     const PropertyTable& Props() const {
         ai_assert(props.get());
         ai_assert(props.get());
@@ -799,7 +799,7 @@ using AnimationLayerList = std::vector<const AnimationLayer*>;
 class AnimationStack : public Object {
 class AnimationStack : public Object {
 public:
 public:
     AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc);
     AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc);
-    virtual ~AnimationStack();
+    virtual ~AnimationStack() = default;
 
 
     fbx_simple_property(LocalStart, int64_t, 0L)
     fbx_simple_property(LocalStart, int64_t, 0L)
     fbx_simple_property(LocalStop, int64_t, 0L)
     fbx_simple_property(LocalStop, int64_t, 0L)

+ 3 - 6
code/AssetLib/FBX/FBXDocumentUtil.cpp

@@ -59,14 +59,12 @@ namespace Util {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
 // signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError.
-void DOMError(const std::string& message, const Token& token)
-{
+void DOMError(const std::string& message, const Token& token) {
     throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message);
     throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void DOMError(const std::string& message, const Element* element /*= nullptr*/)
-{
+void DOMError(const std::string& message, const Element* element /*= nullptr*/) {
     if(element) {
     if(element) {
         DOMError(message,element->KeyToken());
         DOMError(message,element->KeyToken());
     }
     }
@@ -76,8 +74,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // print warning, do return
 // print warning, do return
-void DOMWarning(const std::string& message, const Token& token)
-{
+void DOMWarning(const std::string& message, const Token& token) {
     if(DefaultLogger::get()) {
     if(DefaultLogger::get()) {
         ASSIMP_LOG_WARN("FBX-DOM", Util::GetTokenText(&token), message);
         ASSIMP_LOG_WARN("FBX-DOM", Util::GetTokenText(&token), message);
     }
     }

+ 5 - 7
code/AssetLib/FBX/FBXDocumentUtil.h

@@ -74,13 +74,11 @@ std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 template <typename T>
-inline
-const T* ProcessSimpleConnection(const Connection& con,
-    bool is_object_property_conn,
-    const char* name,
-    const Element& element,
-    const char** propNameOut = nullptr)
-{
+inline const T* ProcessSimpleConnection(const Connection& con,
+        bool is_object_property_conn,
+        const char* name,
+        const Element& element,
+        const char** propNameOut = nullptr) {
     if (is_object_property_conn && !con.PropertyName().length()) {
     if (is_object_property_conn && !con.PropertyName().length()) {
         DOMWarning("expected incoming " + std::string(name) +
         DOMWarning("expected incoming " + std::string(name) +
             " link to be an object-object connection, ignoring",
             " link to be an object-object connection, ignoring",

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

@@ -255,7 +255,7 @@ void FBXExporter::WriteBinaryHeader()
 
 
 void FBXExporter::WriteBinaryFooter()
 void FBXExporter::WriteBinaryFooter()
 {
 {
-    outfile->Write(NULL_RECORD.c_str(), NULL_RECORD.size(), 1);
+    outfile->Write(NULL_RECORD, NumNullRecords, 1);
 
 
     outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1);
     outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1);
 
 

+ 6 - 0
code/AssetLib/FBX/FBXImportSettings.h

@@ -60,6 +60,7 @@ struct ImportSettings {
             readLights(true),
             readLights(true),
             readAnimations(true),
             readAnimations(true),
             readWeights(true),
             readWeights(true),
+            useSkeleton(false),
             preservePivots(true),
             preservePivots(true),
             optimizeEmptyAnimationCurves(true),
             optimizeEmptyAnimationCurves(true),
             useLegacyEmbeddedTextureNaming(false),
             useLegacyEmbeddedTextureNaming(false),
@@ -112,6 +113,11 @@ struct ImportSettings {
      *  Default value is true. */
      *  Default value is true. */
     bool readWeights;
     bool readWeights;
 
 
+    /** will convert all animation data into a skeleton (experimental)
+     *  Default value is false.
+     */
+    bool useSkeleton;
+
     /** preserve transformation pivots and offsets. Since these can
     /** preserve transformation pivots and offsets. Since these can
      *  not directly be represented in assimp, additional dummy
      *  not directly be represented in assimp, additional dummy
      *  nodes will be generated. Note that settings this to false
      *  nodes will be generated. Note that settings this to false

+ 22 - 25
code/AssetLib/FBX/FBXImporter.cpp

@@ -90,12 +90,9 @@ static const aiImporterDesc desc = {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by #Importer
 // Constructor to be privately used by #Importer
-FBXImporter::FBXImporter() {
-}
-
-// ------------------------------------------------------------------------------------------------
-// Destructor, private as well
-FBXImporter::~FBXImporter() {
+FBXImporter::FBXImporter() :
+        mSettings() {
+    // empty
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -115,20 +112,21 @@ const aiImporterDesc *FBXImporter::GetInfo() const {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Setup configuration properties for the loader
 // Setup configuration properties for the loader
 void FBXImporter::SetupProperties(const Importer *pImp) {
 void FBXImporter::SetupProperties(const Importer *pImp) {
-	settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
-	settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
-	settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
-	settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
-	settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
-	settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
-	settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
-	settings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
-	settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
-	settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
-	settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
-	settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
-	settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
-	settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
+    mSettings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
+    mSettings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
+    mSettings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
+    mSettings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
+    mSettings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
+    mSettings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
+    mSettings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
+    mSettings.readWeights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_WEIGHTS, true);
+    mSettings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
+    mSettings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
+    mSettings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
+    mSettings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
+    mSettings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
+    mSettings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
+    mSettings.useSkeleton = pImp->GetPropertyBool(AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER, false);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -155,7 +153,7 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 	contents[contents.size() - 1] = 0;
 	contents[contents.size() - 1] = 0;
 	const char *const begin = &*contents.begin();
 	const char *const begin = &*contents.begin();
 
 
-	// broadphase tokenizing pass in which we identify the core
+	// broad-phase tokenized pass in which we identify the core
 	// syntax elements of FBX (brackets, commas, key:value mappings)
 	// syntax elements of FBX (brackets, commas, key:value mappings)
 	TokenList tokens;
 	TokenList tokens;
 	try {
 	try {
@@ -173,15 +171,14 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 		Parser parser(tokens, is_binary);
 		Parser parser(tokens, is_binary);
 
 
 		// take the raw parse-tree and convert it to a FBX DOM
 		// take the raw parse-tree and convert it to a FBX DOM
-		Document doc(parser, settings);
+		Document doc(parser, mSettings);
 
 
 		// convert the FBX DOM to aiScene
 		// convert the FBX DOM to aiScene
-		ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
+		ConvertToAssimpScene(pScene, doc, mSettings.removeEmptyBones);
 
 
 		// size relative to cm
 		// size relative to cm
 		float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
 		float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
-        if (size_relative_to_cm == 0.0)
-        {
+        if (size_relative_to_cm == 0.0) {
 			// BaseImporter later asserts that fileScale is non-zero.
 			// BaseImporter later asserts that fileScale is non-zero.
 			ThrowException("The UnitScaleFactor must be non-zero");
 			ThrowException("The UnitScaleFactor must be non-zero");
         }
         }

+ 7 - 6
code/AssetLib/FBX/FBXImporter.h

@@ -69,13 +69,14 @@ typedef class basic_formatter<char, std::char_traits<char>, std::allocator<char>
 // -------------------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------------------
 class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
 class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> {
 public:
 public:
+    /// @brief The class constructor.
     FBXImporter();
     FBXImporter();
-    ~FBXImporter() override;
 
 
-    // --------------------
-    bool CanRead(const std::string &pFile,
-            IOSystem *pIOHandler,
-            bool checkSig) const override;
+    ///	@brief The class destructor, default implementation.
+    ~FBXImporter() override = default;
+
+    /// @brief Will check the file for readability.
+    bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
 
 
 protected:
 protected:
     // --------------------
     // --------------------
@@ -90,7 +91,7 @@ protected:
             IOSystem *pIOHandler) override;
             IOSystem *pIOHandler) override;
 
 
 private:
 private:
-    FBX::ImportSettings settings;
+    FBX::ImportSettings mSettings;
 }; // !class FBXImporter
 }; // !class FBXImporter
 
 
 } // end of namespace Assimp
 } // end of namespace Assimp

+ 4 - 20
code/AssetLib/FBX/FBXMeshGeometry.cpp

@@ -4,7 +4,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,
@@ -54,18 +53,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "FBXImportSettings.h"
 #include "FBXImportSettings.h"
 #include "FBXDocumentUtil.h"
 #include "FBXDocumentUtil.h"
 
 
-
 namespace Assimp {
 namespace Assimp {
 namespace FBX {
 namespace FBX {
 
 
 using namespace Util;
 using namespace Util;
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
-    : Object(id, element, name)
-    , skin()
-{
-    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
+Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) :
+        Object(id, element, name), skin() {
+    const std::vector<const Connection*> &conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer");
     for(const Connection* con : conns) {
     for(const Connection* con : conns) {
         const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
         const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element);
         if(sk) {
         if(sk) {
@@ -78,12 +74,6 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name,
     }
     }
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-Geometry::~Geometry()
-{
-    // empty
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
 const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const {
     return blendShapes;
     return blendShapes;
@@ -183,18 +173,12 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
         if(doc.Settings().readAllLayers || index == 0) {
         if(doc.Settings().readAllLayers || index == 0) {
             const Scope& layer = GetRequiredScope(*(*it).second);
             const Scope& layer = GetRequiredScope(*(*it).second);
             ReadLayer(layer);
             ReadLayer(layer);
-        }
-        else {
+        } else {
             FBXImporter::LogWarn("ignoring additional geometry layers");
             FBXImporter::LogWarn("ignoring additional geometry layers");
         }
         }
     }
     }
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-MeshGeometry::~MeshGeometry() {
-    // empty
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
 const std::vector<aiVector3D>& MeshGeometry::GetVertices() const {
     return m_vertices;
     return m_vertices;

+ 12 - 9
code/AssetLib/FBX/FBXMeshGeometry.h

@@ -55,22 +55,25 @@ namespace FBX {
 /**
 /**
  *  DOM base class for all kinds of FBX geometry
  *  DOM base class for all kinds of FBX geometry
  */
  */
-class Geometry : public Object
-{
+class Geometry : public Object {
 public:
 public:
+    /// @brief The class constructor with all parameters.
+    /// @param id       The id.
+    /// @param element  
+    /// @param name 
+    /// @param doc 
     Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
     Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
-    virtual ~Geometry();
+    virtual ~Geometry() = default;
 
 
-    /** Get the Skin attached to this geometry or nullptr */
+    /// Get the Skin attached to this geometry or nullptr
     const Skin* DeformerSkin() const;
     const Skin* DeformerSkin() const;
 
 
-    /** Get the BlendShape attached to this geometry or nullptr */
+    /// Get the BlendShape attached to this geometry or nullptr
     const std::vector<const BlendShape*>& GetBlendShapes() const;
     const std::vector<const BlendShape*>& GetBlendShapes() const;
 
 
 private:
 private:
     const Skin* skin;
     const Skin* skin;
     std::vector<const BlendShape*> blendShapes;
     std::vector<const BlendShape*> blendShapes;
-
 };
 };
 
 
 typedef std::vector<int> MatIndexArray;
 typedef std::vector<int> MatIndexArray;
@@ -79,14 +82,13 @@ typedef std::vector<int> MatIndexArray;
 /**
 /**
  *  DOM class for FBX geometry of type "Mesh"
  *  DOM class for FBX geometry of type "Mesh"
  */
  */
-class MeshGeometry : public Geometry
-{
+class MeshGeometry : public Geometry {
 public:
 public:
     /** The class constructor */
     /** The class constructor */
     MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
     MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc );
 
 
     /** The class destructor */
     /** The class destructor */
-    virtual ~MeshGeometry();
+    virtual ~MeshGeometry() = default;
 
 
     /** Get a list of all vertex points, non-unique*/
     /** Get a list of all vertex points, non-unique*/
     const std::vector<aiVector3D>& GetVertices() const;
     const std::vector<aiVector3D>& GetVertices() const;
@@ -130,6 +132,7 @@ public:
     /** Determine the face to which a particular output vertex index belongs.
     /** Determine the face to which a particular output vertex index belongs.
     *  This mapping is always unique. */
     *  This mapping is always unique. */
     unsigned int FaceForVertexIndex( unsigned int in_index ) const;
     unsigned int FaceForVertexIndex( unsigned int in_index ) const;
+
 private:
 private:
     void ReadLayer( const Scope& layer );
     void ReadLayer( const Scope& layer );
     void ReadLayerElement( const Scope& layerElement );
     void ReadLayerElement( const Scope& layerElement );

+ 29 - 78
code/AssetLib/FBX/FBXNodeAttribute.cpp

@@ -57,114 +57,65 @@ namespace FBX {
 using namespace Util;
 using namespace Util;
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: Object(id,element,name)
-, props()
-{
-    const Scope& sc = GetRequiredScope(element);
+NodeAttribute::NodeAttribute(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
+        Object(id, element, name), props() {
+    const Scope &sc = GetRequiredScope(element);
 
 
-    const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2));
+    const std::string &classname = ParseTokenAsString(GetRequiredToken(element, 2));
 
 
     // hack on the deriving type but Null/LimbNode attributes are the only case in which
     // hack on the deriving type but Null/LimbNode attributes are the only case in which
     // the property table is by design absent and no warning should be generated
     // the property table is by design absent and no warning should be generated
     // for it.
     // for it.
     const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
     const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode");
-    props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb);
+    props = GetPropertyTable(doc, "NodeAttribute.Fbx" + classname, element, sc, is_null_or_limb);
 }
 }
 
 
-
-// ------------------------------------------------------------------------------------------------
-NodeAttribute::~NodeAttribute()
-{
-    // empty
-}
-
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-    : NodeAttribute(id,element,doc,name)
-{
-    const Scope& sc = GetRequiredScope(element);
-    const Element* const CameraId = sc["CameraId"];
-    const Element* const CameraName = sc["CameraName"];
-    const Element* const CameraIndexName = sc["CameraIndexName"];
-
-    if(CameraId) {
-        cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0));
+CameraSwitcher::CameraSwitcher(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
+        NodeAttribute(id, element, doc, name) {
+    const Scope &sc = GetRequiredScope(element);
+    const Element *const CameraId = sc["CameraId"];
+    const Element *const CameraName = sc["CameraName"];
+    const Element *const CameraIndexName = sc["CameraIndexName"];
+
+    if (CameraId) {
+        cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId, 0));
     }
     }
 
 
-    if(CameraName) {
-        cameraName = GetRequiredToken(*CameraName,0).StringContents();
+    if (CameraName) {
+        cameraName = GetRequiredToken(*CameraName, 0).StringContents();
     }
     }
 
 
-    if(CameraIndexName && CameraIndexName->Tokens().size()) {
-        cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents();
+    if (CameraIndexName && CameraIndexName->Tokens().size()) {
+        cameraIndexName = GetRequiredToken(*CameraIndexName, 0).StringContents();
     }
     }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-CameraSwitcher::~CameraSwitcher()
-{
+Camera::Camera(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
+        NodeAttribute(id, element, doc, name) {
     // empty
     // empty
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: NodeAttribute(id,element,doc,name)
-{
+Light::Light(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
+        NodeAttribute(id, element, doc, name) {
     // empty
     // empty
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-Camera::~Camera()
-{
+Null::Null(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
+        NodeAttribute(id, element, doc, name) {
     // empty
     // empty
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: NodeAttribute(id,element,doc,name)
-{
+LimbNode::LimbNode(uint64_t id, const Element &element, const Document &doc, const std::string &name) :
+        NodeAttribute(id, element, doc, name) {
     // empty
     // empty
 }
 }
 
 
+} // namespace FBX
+} // namespace Assimp
 
 
-// ------------------------------------------------------------------------------------------------
-Light::~Light()
-{
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Null::Null(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: NodeAttribute(id,element,doc,name)
-{
-
-}
-
-
-// ------------------------------------------------------------------------------------------------
-Null::~Null()
-{
-
-}
-
-
-// ------------------------------------------------------------------------------------------------
-LimbNode::LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name)
-: NodeAttribute(id,element,doc,name)
-{
-
-}
-
-
-// ------------------------------------------------------------------------------------------------
-LimbNode::~LimbNode()
-{
-
-}
-
-}
-}
-
-#endif
+#endif // ASSIMP_BUILD_NO_FBX_IMPORTER

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

@@ -162,12 +162,6 @@ Element::Element(const Token& key_token, Parser& parser) : key_token(key_token)
     while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
     while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET);
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-Element::~Element()
-{
-     // no need to delete tokens, they are owned by the parser
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 Scope::Scope(Parser& parser,bool topLevel)
 Scope::Scope(Parser& parser,bool topLevel)
 {
 {
@@ -226,12 +220,6 @@ Parser::Parser (const TokenList& tokens, bool is_binary)
     root.reset(new Scope(*this,true));
     root.reset(new Scope(*this,true));
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-Parser::~Parser()
-{
-    // empty
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 TokenPtr Parser::AdvanceToNextToken()
 TokenPtr Parser::AdvanceToNextToken()
 {
 {
@@ -961,8 +949,7 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // read an array of uints
 // read an array of uints
-void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
-{
+void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) {
     out.resize( 0 );
     out.resize( 0 );
     const TokenList& tok = el.Tokens();
     const TokenList& tok = el.Tokens();
     if(tok.empty()) {
     if(tok.empty()) {
@@ -1186,7 +1173,6 @@ aiMatrix4x4 ReadMatrix(const Element& element)
     return result;
     return result;
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // wrapper around ParseTokenAsString() with ParseError handling
 // wrapper around ParseTokenAsString() with ParseError handling
 std::string ParseTokenAsString(const Token& t)
 std::string ParseTokenAsString(const Token& t)

+ 2 - 2
code/AssetLib/FBX/FBXParser.h

@@ -87,7 +87,7 @@ class Element
 {
 {
 public:
 public:
     Element(const Token& key_token, Parser& parser);
     Element(const Token& key_token, Parser& parser);
-    ~Element();
+    ~Element() = default;
 
 
     const Scope* Compound() const {
     const Scope* Compound() const {
         return compound.get();
         return compound.get();
@@ -160,7 +160,7 @@ public:
     /** Parse given a token list. Does not take ownership of the tokens -
     /** Parse given a token list. Does not take ownership of the tokens -
      *  the objects must persist during the entire parser lifetime */
      *  the objects must persist during the entire parser lifetime */
     Parser (const TokenList& tokens,bool is_binary);
     Parser (const TokenList& tokens,bool is_binary);
-    ~Parser();
+    ~Parser() = default;
 
 
     const Scope& GetRootScope() const {
     const Scope& GetRootScope() const {
         return *root.get();
         return *root.get();

+ 4 - 2
code/AssetLib/IFC/IFCCurve.cpp

@@ -4,7 +4,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,
@@ -51,7 +50,6 @@ namespace Assimp {
 namespace IFC {
 namespace IFC {
 namespace {
 namespace {
 
 
-
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // Conic is the base class for Circle and Ellipse
 // Conic is the base class for Circle and Ellipse
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
@@ -546,8 +544,10 @@ IfcFloat RecursiveSearch(const Curve* cv, const IfcVector3& val, IfcFloat a, Ifc
         }
         }
     }
     }
 
 
+#ifndef __INTEL_LLVM_COMPILER
     ai_assert( min_diff[ 0 ] != inf );
     ai_assert( min_diff[ 0 ] != inf );
     ai_assert( min_diff[ 1 ] != inf );
     ai_assert( min_diff[ 1 ] != inf );
+#endif // __INTEL_LLVM_COMPILER
     if ( std::fabs(a-min_point[0]) < threshold || recurse >= max_recurse) {
     if ( std::fabs(a-min_point[0]) < threshold || recurse >= max_recurse) {
         return min_point[0];
         return min_point[0];
     }
     }
@@ -606,8 +606,10 @@ bool BoundedCurve::IsClosed() const {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void BoundedCurve::SampleDiscrete(TempMesh& out) const {
 void BoundedCurve::SampleDiscrete(TempMesh& out) const {
     const ParamRange& range = GetParametricRange();
     const ParamRange& range = GetParametricRange();
+#ifndef __INTEL_LLVM_COMPILER
     ai_assert( range.first != std::numeric_limits<IfcFloat>::infinity() );
     ai_assert( range.first != std::numeric_limits<IfcFloat>::infinity() );
     ai_assert( range.second != std::numeric_limits<IfcFloat>::infinity() );
     ai_assert( range.second != std::numeric_limits<IfcFloat>::infinity() );
+#endif // __INTEL_LLVM_COMPILER
 
 
     return SampleDiscrete(out,range.first,range.second);
     return SampleDiscrete(out,range.first,range.second);
 }
 }

+ 5 - 5
code/AssetLib/IFC/IFCOpenings.cpp

@@ -1428,7 +1428,7 @@ bool GenerateOpenings(std::vector<TempOpening>& openings,
     return true;
     return true;
 }
 }
 
 
-std::vector<IfcVector2> GetContourInPlane2D(std::shared_ptr<TempMesh> mesh,IfcMatrix3 planeSpace,
+std::vector<IfcVector2> GetContourInPlane2D(const std::shared_ptr<TempMesh>& mesh,IfcMatrix3 planeSpace,
     IfcVector3 planeNor,IfcFloat planeOffset,
     IfcVector3 planeNor,IfcFloat planeOffset,
     IfcVector3 extrusionDir,IfcVector3& wall_extrusion,bool& first,bool& ok) {
     IfcVector3 extrusionDir,IfcVector3& wall_extrusion,bool& first,bool& ok) {
     std::vector<IfcVector2> contour;
     std::vector<IfcVector2> contour;
@@ -1476,7 +1476,7 @@ std::vector<IfcVector2> GetContourInPlane2D(std::shared_ptr<TempMesh> mesh,IfcMa
     return contour;
     return contour;
 }
 }
 
 
-const float close{ ai_epsilon };
+const ai_real close{ ai_epsilon };
 
 
 static bool isClose(IfcVector2 first,IfcVector2 second) {
 static bool isClose(IfcVector2 first,IfcVector2 second) {
     auto diff = (second - first);
     auto diff = (second - first);
@@ -1491,7 +1491,7 @@ static void logSegment(std::pair<IfcVector2,IfcVector2> segment) {
     IFCImporter::LogInfo(msg2.str().c_str());
     IFCImporter::LogInfo(msg2.str().c_str());
 }
 }
 
 
-std::vector<std::vector<IfcVector2>> GetContoursInPlane3D(std::shared_ptr<TempMesh> mesh,IfcMatrix3 planeSpace,
+std::vector<std::vector<IfcVector2>> GetContoursInPlane3D(const std::shared_ptr<TempMesh>& mesh,IfcMatrix3 planeSpace,
     IfcFloat planeOffset) {
     IfcFloat planeOffset) {
 
 
         {
         {
@@ -1676,7 +1676,7 @@ std::vector<std::vector<IfcVector2>> GetContoursInPlane3D(std::shared_ptr<TempMe
             std::stringstream msg;
             std::stringstream msg;
             msg << "GetContoursInPlane3D: found " << contours.size() << " contours:\n";
             msg << "GetContoursInPlane3D: found " << contours.size() << " contours:\n";
 
 
-            for(auto c : contours) {
+            for(const auto& c : contours) {
                 msg << " Contour: \n";
                 msg << " Contour: \n";
                 for(auto p : c) {
                 for(auto p : c) {
                     msg << "   " << p.x << " " << p.y << " \n";
                     msg << "   " << p.x << " " << p.y << " \n";
@@ -1690,7 +1690,7 @@ std::vector<std::vector<IfcVector2>> GetContoursInPlane3D(std::shared_ptr<TempMe
         return contours;
         return contours;
 }
 }
 
 
-std::vector<std::vector<IfcVector2>> GetContoursInPlane(std::shared_ptr<TempMesh> mesh,IfcMatrix3 planeSpace,
+std::vector<std::vector<IfcVector2>> GetContoursInPlane(const std::shared_ptr<TempMesh>& mesh,IfcMatrix3 planeSpace,
     IfcVector3 planeNor,IfcFloat planeOffset,
     IfcVector3 planeNor,IfcFloat planeOffset,
     IfcVector3 extrusionDir,IfcVector3& wall_extrusion,bool& first) {
     IfcVector3 extrusionDir,IfcVector3& wall_extrusion,bool& first) {
 
 

+ 1 - 1
code/AssetLib/Irr/IRRLoader.cpp

@@ -874,7 +874,7 @@ void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 
 
 	// Batch loader used to load external models
 	// Batch loader used to load external models
 	BatchLoader batch(pIOHandler);
 	BatchLoader batch(pIOHandler);
-	//  batch.SetBasePath(pFile);
+	//batch.SetBasePath(pFile);
 
 
 	cameras.reserve(5);
 	cameras.reserve(5);
 	lights.reserve(5);
 	lights.reserve(5);

+ 2 - 2
code/AssetLib/LWO/LWOLoader.cpp

@@ -287,7 +287,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
             if (UINT_MAX == iDefaultSurface) {
             if (UINT_MAX == iDefaultSurface) {
                 pSorted.erase(pSorted.end() - 1);
                 pSorted.erase(pSorted.end() - 1);
             }
             }
-            for (unsigned int p = 0, j = 0; j < mSurfaces->size(); ++j) {
+            for (unsigned int j = 0; j < mSurfaces->size(); ++j) {
                 SortedRep &sorted = pSorted[j];
                 SortedRep &sorted = pSorted[j];
                 if (sorted.empty())
                 if (sorted.empty())
                     continue;
                     continue;
@@ -425,7 +425,6 @@ void LWOImporter::InternReadFile(const std::string &pFile,
                 } else {
                 } else {
                     ASSIMP_LOG_VERBOSE_DEBUG("LWO2: No need to compute normals, they're already there");
                     ASSIMP_LOG_VERBOSE_DEBUG("LWO2: No need to compute normals, they're already there");
                 }
                 }
-                ++p;
             }
             }
         }
         }
 
 
@@ -1541,6 +1540,7 @@ void LWOImporter::LoadLWO2File() {
                     break;
                     break;
                 }
                 }
                 // --- intentionally no break here
                 // --- intentionally no break here
+                // fallthrough
             case AI_LWO_VMAP: {
             case AI_LWO_VMAP: {
                 if (skip)
                 if (skip)
                     break;
                     break;

+ 3 - 0
code/AssetLib/LWS/LWSLoader.cpp

@@ -313,6 +313,9 @@ void LWSImporter::SetupNodeName(aiNode *nd, LWS::NodeDesc &src) {
             std::string::size_type t = src.path.substr(s).find_last_of('.');
             std::string::size_type t = src.path.substr(s).find_last_of('.');
 
 
             nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)", src.path.substr(s).substr(0, t).c_str(), combined);
             nd->mName.length = ::ai_snprintf(nd->mName.data, MAXLEN, "%s_(%08X)", src.path.substr(s).substr(0, t).c_str(), combined);
+            if (nd->mName.length > MAXLEN) {
+                nd->mName.length = MAXLEN;
+            }
             return;
             return;
         }
         }
     }
     }

+ 1 - 3
code/AssetLib/M3D/M3DWrapper.h

@@ -57,9 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // Assimp specific M3D configuration. Comment out these defines to remove functionality
 // Assimp specific M3D configuration. Comment out these defines to remove functionality
 //#define ASSIMP_USE_M3D_READFILECB
 //#define ASSIMP_USE_M3D_READFILECB
 
 
-// Share stb_image's PNG loader with other importers/exporters instead of bringing our own copy.
-#define STBI_ONLY_PNG
-#include <stb/stb_image.h>
+#include "Common/StbCommon.h"
 
 
 #include "m3d.h"
 #include "m3d.h"
 
 

+ 3 - 0
code/AssetLib/MDL/MDLMaterialLoader.cpp

@@ -449,6 +449,9 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
         unsigned int iWidth,
         unsigned int iWidth,
         unsigned int iHeight) {
         unsigned int iHeight) {
     std::unique_ptr<aiTexture> pcNew;
     std::unique_ptr<aiTexture> pcNew;
+    if (szCurrent == nullptr) {
+        return;
+    }
 
 
     // get the type of the skin
     // get the type of the skin
     unsigned int iMasked = (unsigned int)(iType & 0xF);
     unsigned int iMasked = (unsigned int)(iType & 0xF);

+ 21 - 14
code/AssetLib/MMD/MMDImporter.cpp

@@ -52,9 +52,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/scene.h>
 #include <assimp/scene.h>
 #include <assimp/Importer.hpp>
 #include <assimp/Importer.hpp>
 
 
-#include <fstream>
+
 #include <iomanip>
 #include <iomanip>
 #include <memory>
 #include <memory>
+#include <sstream>
 
 
 static const aiImporterDesc desc = { "MMD Importer",
 static const aiImporterDesc desc = { "MMD Importer",
     "",
     "",
@@ -102,26 +103,32 @@ const aiImporterDesc *MMDImporter::GetInfo() const {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //  MMD import implementation
 //  MMD import implementation
 void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene,
 void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene,
-        IOSystem * /*pIOHandler*/) {
-    // Read file by istream
-    std::filebuf fb;
-    if (!fb.open(file, std::ios::in | std::ios::binary)) {
-        throw DeadlyImportError("Failed to open file ", file, ".");
-    }
+        IOSystem* pIOHandler) {
+
+    auto streamCloser = [&](IOStream *pStream) {
+        pIOHandler->Close(pStream);
+    };
 
 
-    std::istream fileStream(&fb);
+    static const std::string mode = "rb";
+    const std::unique_ptr<IOStream, decltype(streamCloser)> fileStream(pIOHandler->Open(file, mode), streamCloser);
 
 
-    // Get the file-size and validate it, throwing an exception when fails
-    fileStream.seekg(0, fileStream.end);
-    size_t fileSize = static_cast<size_t>(fileStream.tellg());
-    fileStream.seekg(0, fileStream.beg);
+    if (fileStream == nullptr) {
+        throw DeadlyImportError("Failed to open file ", file, ".");
+    }
 
 
-    if (fileSize < sizeof(pmx::PmxModel)) {
+    const size_t fileSize = fileStream->FileSize();
+    if (fileSize < sizeof(pmx::PmxModel))
+    {
         throw DeadlyImportError(file, " is too small.");
         throw DeadlyImportError(file, " is too small.");
     }
     }
 
 
+    std::vector<char> contents(fileStream->FileSize());
+    fileStream->Read(contents.data(), 1, contents.size());
+
+    std::istringstream iss(std::string(contents.begin(), contents.end()));
+
     pmx::PmxModel model;
     pmx::PmxModel model;
-    model.Read(&fileStream);
+    model.Read(&iss);
 
 
     CreateDataFromImport(&model, pScene);
     CreateDataFromImport(&model, pScene);
 }
 }

+ 2 - 0
code/AssetLib/MMD/MMDPmxParser.h

@@ -357,6 +357,8 @@ namespace pmx
 	{
 	{
 	public:
 	public:
 		void virtual Read(std::istream *stream, PmxSetting *setting) = 0;
 		void virtual Read(std::istream *stream, PmxSetting *setting) = 0;
+
+        virtual ~PmxMorphOffset() = default;
 	};
 	};
 
 
 	class PmxMorphVertexOffset : public PmxMorphOffset
 	class PmxMorphVertexOffset : public PmxMorphOffset

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

@@ -136,7 +136,9 @@ void NDOImporter::InternReadFile( const std::string& pFile,
         ASSIMP_LOG_INFO("NDO file format is 1.2");
         ASSIMP_LOG_INFO("NDO file format is 1.2");
     }
     }
     else {
     else {
-        ASSIMP_LOG_WARN( "Unrecognized nendo file format version, continuing happily ... :", (head+6));
+        char buff[4] = {0};
+        memcpy(buff, head+6, 3);
+        ASSIMP_LOG_WARN( "Unrecognized nendo file format version, continuing happily ... :", buff);
     }
     }
 
 
     reader.IncPtr(2); /* skip flags */
     reader.IncPtr(2); /* skip flags */

+ 45 - 46
code/AssetLib/Obj/ObjFileData.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2020, assimp team
+Copyright (c) 2006-2022, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 
@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/types.h>
 #include <assimp/types.h>
 #include <map>
 #include <map>
 #include <vector>
 #include <vector>
+#include "Common/Maybe.h"
 
 
 namespace Assimp {
 namespace Assimp {
 namespace ObjFile {
 namespace ObjFile {
@@ -63,7 +64,7 @@ struct Face {
     using IndexArray = std::vector<unsigned int>;
     using IndexArray = std::vector<unsigned int>;
 
 
     //! Primitive type
     //! Primitive type
-    aiPrimitiveType m_PrimitiveType;
+    aiPrimitiveType mPrimitiveType;
     //! Vertex indices
     //! Vertex indices
     IndexArray m_vertices;
     IndexArray m_vertices;
     //! Normal indices
     //! Normal indices
@@ -75,14 +76,12 @@ struct Face {
 
 
     //! \brief  Default constructor
     //! \brief  Default constructor
     Face(aiPrimitiveType pt = aiPrimitiveType_POLYGON) :
     Face(aiPrimitiveType pt = aiPrimitiveType_POLYGON) :
-            m_PrimitiveType(pt), m_vertices(), m_normals(), m_texturCoords(), m_pMaterial(0L) {
+            mPrimitiveType(pt), m_vertices(), m_normals(), m_texturCoords(), m_pMaterial(nullptr) {
         // empty
         // empty
     }
     }
 
 
     //! \brief  Destructor
     //! \brief  Destructor
-    ~Face() {
-        // empty
-    }
+    ~Face() = default;
 };
 };
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -183,15 +182,15 @@ struct Material {
     aiColor3D transparent;
     aiColor3D transparent;
 
 
     //! PBR Roughness
     //! PBR Roughness
-    ai_real roughness;
+    Maybe<ai_real> roughness;
     //! PBR Metallic
     //! PBR Metallic
-    ai_real metallic;
+    Maybe<ai_real> metallic;
     //! PBR Metallic
     //! PBR Metallic
-    aiColor3D sheen;
+    Maybe<aiColor3D> sheen;
     //! PBR Clearcoat Thickness
     //! PBR Clearcoat Thickness
-    ai_real clearcoat_thickness;
+    Maybe<ai_real> clearcoat_thickness;
     //! PBR Clearcoat Rougness
     //! PBR Clearcoat Rougness
-    ai_real clearcoat_roughness;
+    Maybe<ai_real> clearcoat_roughness;
     //! PBR Anisotropy
     //! PBR Anisotropy
     ai_real anisotropy;
     ai_real anisotropy;
 
 
@@ -206,11 +205,11 @@ struct Material {
             illumination_model(1),
             illumination_model(1),
             ior(ai_real(1.0)),
             ior(ai_real(1.0)),
             transparent(ai_real(1.0), ai_real(1.0), ai_real(1.0)),
             transparent(ai_real(1.0), ai_real(1.0), ai_real(1.0)),
-            roughness(ai_real(1.0)),
-            metallic(ai_real(0.0)),
-            sheen(ai_real(1.0), ai_real(1.0), ai_real(1.0)),
-            clearcoat_thickness(ai_real(0.0)),
-            clearcoat_roughness(ai_real(0.0)),
+            roughness(),
+            metallic(),
+            sheen(),
+            clearcoat_thickness(),
+            clearcoat_roughness(),
             anisotropy(ai_real(0.0)),
             anisotropy(ai_real(0.0)),
             bump_multiplier(ai_real(1.0)) {
             bump_multiplier(ai_real(1.0)) {
         std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false);
         std::fill_n(clamp, static_cast<unsigned int>(TextureTypeCount), false);
@@ -229,7 +228,7 @@ struct Mesh {
     /// The name for the mesh
     /// The name for the mesh
     std::string m_name;
     std::string m_name;
     /// Array with pointer to all stored faces
     /// Array with pointer to all stored faces
-    std::vector<Face *> m_Faces;
+    std::vector<Face*> m_Faces;
     /// Assigned material
     /// Assigned material
     Material *m_pMaterial;
     Material *m_pMaterial;
     /// Number of stored indices.
     /// Number of stored indices.
@@ -272,65 +271,65 @@ struct Model {
     using ConstGroupMapIt = std::map<std::string, std::vector<unsigned int> *>::const_iterator;
     using ConstGroupMapIt = std::map<std::string, std::vector<unsigned int> *>::const_iterator;
 
 
     //! Model name
     //! Model name
-    std::string m_ModelName;
+    std::string mModelName;
     //! List ob assigned objects
     //! List ob assigned objects
-    std::vector<Object *> m_Objects;
+    std::vector<Object *> mObjects;
     //! Pointer to current object
     //! Pointer to current object
-    ObjFile::Object *m_pCurrent;
+    ObjFile::Object *mCurrentObject;
     //! Pointer to current material
     //! Pointer to current material
-    ObjFile::Material *m_pCurrentMaterial;
+    ObjFile::Material *mCurrentMaterial;
     //! Pointer to default material
     //! Pointer to default material
-    ObjFile::Material *m_pDefaultMaterial;
+    ObjFile::Material *mDefaultMaterial;
     //! Vector with all generated materials
     //! Vector with all generated materials
-    std::vector<std::string> m_MaterialLib;
+    std::vector<std::string> mMaterialLib;
     //! Vector with all generated vertices
     //! Vector with all generated vertices
-    std::vector<aiVector3D> m_Vertices;
+    std::vector<aiVector3D> mVertices;
     //! vector with all generated normals
     //! vector with all generated normals
-    std::vector<aiVector3D> m_Normals;
+    std::vector<aiVector3D> mNormals;
     //! vector with all vertex colors
     //! vector with all vertex colors
-    std::vector<aiVector3D> m_VertexColors;
+    std::vector<aiVector3D> mVertexColors;
     //! Group map
     //! Group map
-    GroupMap m_Groups;
+    GroupMap mGroups;
     //! Group to face id assignment
     //! Group to face id assignment
-    std::vector<unsigned int> *m_pGroupFaceIDs;
+    std::vector<unsigned int> *mGroupFaceIDs;
     //! Active group
     //! Active group
-    std::string m_strActiveGroup;
+    std::string mActiveGroup;
     //! Vector with generated texture coordinates
     //! Vector with generated texture coordinates
-    std::vector<aiVector3D> m_TextureCoord;
+    std::vector<aiVector3D> mTextureCoord;
     //! Maximum dimension of texture coordinates
     //! Maximum dimension of texture coordinates
-    unsigned int m_TextureCoordDim;
+    unsigned int mTextureCoordDim;
     //! Current mesh instance
     //! Current mesh instance
-    Mesh *m_pCurrentMesh;
+    Mesh *mCurrentMesh;
     //! Vector with stored meshes
     //! Vector with stored meshes
-    std::vector<Mesh *> m_Meshes;
+    std::vector<Mesh *> mMeshes;
     //! Material map
     //! Material map
-    std::map<std::string, Material *> m_MaterialMap;
+    std::map<std::string, Material*> mMaterialMap;
 
 
     //! \brief  The default class constructor
     //! \brief  The default class constructor
     Model() :
     Model() :
-            m_ModelName(),
-            m_pCurrent(nullptr),
-            m_pCurrentMaterial(nullptr),
-            m_pDefaultMaterial(nullptr),
-            m_pGroupFaceIDs(nullptr),
-            m_strActiveGroup(),
-            m_TextureCoordDim(0),
-            m_pCurrentMesh(nullptr) {
+            mModelName(),
+            mCurrentObject(nullptr),
+            mCurrentMaterial(nullptr),
+            mDefaultMaterial(nullptr),
+            mGroupFaceIDs(nullptr),
+            mActiveGroup(),
+            mTextureCoordDim(0),
+            mCurrentMesh(nullptr) {
         // empty
         // empty
     }
     }
 
 
     //! \brief  The class destructor
     //! \brief  The class destructor
     ~Model() {
     ~Model() {
-        for (auto & it : m_Objects) {
+        for (auto & it : mObjects) {
             delete it;
             delete it;
         }
         }
-        for (auto & Meshe : m_Meshes) {
+        for (auto & Meshe : mMeshes) {
             delete Meshe;
             delete Meshe;
         }
         }
-        for (auto & Group : m_Groups) {
+        for (auto & Group : mGroups) {
             delete Group.second;
             delete Group.second;
         }
         }
-        for (auto & it : m_MaterialMap) {
+        for (auto & it : mMaterialMap) {
             delete it.second;
             delete it.second;
         }
         }
     }
     }

+ 57 - 52
code/AssetLib/Obj/ObjFileImporter.cpp

@@ -163,20 +163,20 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene
 
 
     // Create the root node of the scene
     // Create the root node of the scene
     pScene->mRootNode = new aiNode;
     pScene->mRootNode = new aiNode;
-    if (!pModel->m_ModelName.empty()) {
+    if (!pModel->mModelName.empty()) {
         // Set the name of the scene
         // Set the name of the scene
-        pScene->mRootNode->mName.Set(pModel->m_ModelName);
+        pScene->mRootNode->mName.Set(pModel->mModelName);
     } else {
     } else {
         // This is a fatal error, so break down the application
         // This is a fatal error, so break down the application
         ai_assert(false);
         ai_assert(false);
     }
     }
 
 
-    if (!pModel->m_Objects.empty()) {
+    if (!pModel->mObjects.empty()) {
 
 
         unsigned int meshCount = 0;
         unsigned int meshCount = 0;
         unsigned int childCount = 0;
         unsigned int childCount = 0;
 
 
-        for (auto object : pModel->m_Objects) {
+        for (auto object : pModel->mObjects) {
             if (object) {
             if (object) {
                 ++childCount;
                 ++childCount;
                 meshCount += (unsigned int)object->m_Meshes.size();
                 meshCount += (unsigned int)object->m_Meshes.size();
@@ -189,8 +189,8 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene
         // Create nodes for the whole scene
         // Create nodes for the whole scene
         std::vector<aiMesh *> MeshArray;
         std::vector<aiMesh *> MeshArray;
         MeshArray.reserve(meshCount);
         MeshArray.reserve(meshCount);
-        for (size_t index = 0; index < pModel->m_Objects.size(); ++index) {
-            createNodes(pModel, pModel->m_Objects[index], pScene->mRootNode, pScene, MeshArray);
+        for (size_t index = 0; index < pModel->mObjects.size(); ++index) {
+            createNodes(pModel, pModel->mObjects[index], pScene->mRootNode, pScene, MeshArray);
         }
         }
 
 
         ai_assert(pScene->mRootNode->mNumChildren == childCount);
         ai_assert(pScene->mRootNode->mNumChildren == childCount);
@@ -206,31 +206,31 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model *pModel, aiScene
         // Create all materials
         // Create all materials
         createMaterials(pModel, pScene);
         createMaterials(pModel, pScene);
     } else {
     } else {
-        if (pModel->m_Vertices.empty()) {
+        if (pModel->mVertices.empty()) {
             return;
             return;
         }
         }
 
 
         std::unique_ptr<aiMesh> mesh(new aiMesh);
         std::unique_ptr<aiMesh> mesh(new aiMesh);
         mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
         mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
-        unsigned int n = (unsigned int)pModel->m_Vertices.size();
+        unsigned int n = (unsigned int)pModel->mVertices.size();
         mesh->mNumVertices = n;
         mesh->mNumVertices = n;
 
 
         mesh->mVertices = new aiVector3D[n];
         mesh->mVertices = new aiVector3D[n];
-        memcpy(mesh->mVertices, pModel->m_Vertices.data(), n * sizeof(aiVector3D));
+        memcpy(mesh->mVertices, pModel->mVertices.data(), n * sizeof(aiVector3D));
 
 
-        if (!pModel->m_Normals.empty()) {
+        if (!pModel->mNormals.empty()) {
             mesh->mNormals = new aiVector3D[n];
             mesh->mNormals = new aiVector3D[n];
-            if (pModel->m_Normals.size() < n) {
+            if (pModel->mNormals.size() < n) {
                 throw DeadlyImportError("OBJ: vertex normal index out of range");
                 throw DeadlyImportError("OBJ: vertex normal index out of range");
             }
             }
-            memcpy(mesh->mNormals, pModel->m_Normals.data(), n * sizeof(aiVector3D));
+            memcpy(mesh->mNormals, pModel->mNormals.data(), n * sizeof(aiVector3D));
         }
         }
 
 
-        if (!pModel->m_VertexColors.empty()) {
+        if (!pModel->mVertexColors.empty()) {
             mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
             mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
             for (unsigned int i = 0; i < n; ++i) {
             for (unsigned int i = 0; i < n; ++i) {
-                if (i < pModel->m_VertexColors.size()) {
-                    const aiVector3D &color = pModel->m_VertexColors[i];
+                if (i < pModel->mVertexColors.size()) {
+                    const aiVector3D &color = pModel->mVertexColors[i];
                     mesh->mColors[0][i] = aiColor4D(color.x, color.y, color.z, 1.0);
                     mesh->mColors[0][i] = aiColor4D(color.x, color.y, color.z, 1.0);
                 } else {
                 } else {
                     throw DeadlyImportError("OBJ: vertex color index out of range");
                     throw DeadlyImportError("OBJ: vertex color index out of range");
@@ -315,7 +315,7 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
     }
     }
 
 
     // Create faces
     // Create faces
-    ObjFile::Mesh *pObjMesh = pModel->m_Meshes[meshIndex];
+    ObjFile::Mesh *pObjMesh = pModel->mMeshes[meshIndex];
     if (!pObjMesh) {
     if (!pObjMesh) {
         return nullptr;
         return nullptr;
     }
     }
@@ -330,13 +330,13 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
     }
     }
 
 
     for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
     for (size_t index = 0; index < pObjMesh->m_Faces.size(); index++) {
-        ObjFile::Face *const inp = pObjMesh->m_Faces[index];
-        ai_assert(nullptr != inp);
+        const ObjFile::Face *inp = pObjMesh->m_Faces[index];
+        //ai_assert(nullptr != inp);
 
 
-        if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
+        if (inp->mPrimitiveType == aiPrimitiveType_LINE) {
             pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1);
             pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size() - 1);
             pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
             pMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
-        } else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
+        } else if (inp->mPrimitiveType == aiPrimitiveType_POINT) {
             pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size());
             pMesh->mNumFaces += static_cast<unsigned int>(inp->m_vertices.size());
             pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
             pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
         } else {
         } else {
@@ -360,15 +360,15 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF
 
 
         // Copy all data from all stored meshes
         // Copy all data from all stored meshes
         for (auto &face : pObjMesh->m_Faces) {
         for (auto &face : pObjMesh->m_Faces) {
-            ObjFile::Face *const inp = face;
-            if (inp->m_PrimitiveType == aiPrimitiveType_LINE) {
+            const ObjFile::Face *inp = face;
+            if (inp->mPrimitiveType == aiPrimitiveType_LINE) {
                 for (size_t i = 0; i < inp->m_vertices.size() - 1; ++i) {
                 for (size_t i = 0; i < inp->m_vertices.size() - 1; ++i) {
                     aiFace &f = pMesh->mFaces[outIndex++];
                     aiFace &f = pMesh->mFaces[outIndex++];
                     uiIdxCount += f.mNumIndices = 2;
                     uiIdxCount += f.mNumIndices = 2;
                     f.mIndices = new unsigned int[2];
                     f.mIndices = new unsigned int[2];
                 }
                 }
                 continue;
                 continue;
-            } else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
+            } else if (inp->mPrimitiveType == aiPrimitiveType_POINT) {
                 for (size_t i = 0; i < inp->m_vertices.size(); ++i) {
                 for (size_t i = 0; i < inp->m_vertices.size(); ++i) {
                     aiFace &f = pMesh->mFaces[outIndex++];
                     aiFace &f = pMesh->mFaces[outIndex++];
                     uiIdxCount += f.mNumIndices = 1;
                     uiIdxCount += f.mNumIndices = 1;
@@ -407,7 +407,7 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
         return;
         return;
 
 
     // Get current mesh
     // Get current mesh
-    ObjFile::Mesh *pObjMesh = pModel->m_Meshes[uiMeshIndex];
+    ObjFile::Mesh *pObjMesh = pModel->mMeshes[uiMeshIndex];
     if (nullptr == pObjMesh || pObjMesh->m_uiNumIndices < 1) {
     if (nullptr == pObjMesh || pObjMesh->m_uiNumIndices < 1) {
         return;
         return;
     }
     }
@@ -422,16 +422,16 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
     pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
     pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
 
 
     // Allocate buffer for normal vectors
     // Allocate buffer for normal vectors
-    if (!pModel->m_Normals.empty() && pObjMesh->m_hasNormals)
+    if (!pModel->mNormals.empty() && pObjMesh->m_hasNormals)
         pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
         pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
 
 
     // Allocate buffer for vertex-color vectors
     // Allocate buffer for vertex-color vectors
-    if (!pModel->m_VertexColors.empty())
+    if (!pModel->mVertexColors.empty())
         pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
         pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
 
 
     // Allocate buffer for texture coordinates
     // Allocate buffer for texture coordinates
-    if (!pModel->m_TextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0]) {
-        pMesh->mNumUVComponents[0] = pModel->m_TextureCoordDim;
+    if (!pModel->mTextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0]) {
+        pMesh->mNumUVComponents[0] = pModel->mTextureCoordDim;
         pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices];
         pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices];
     }
     }
 
 
@@ -442,7 +442,7 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
         // Copy all index arrays
         // Copy all index arrays
         for (size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < sourceFace->m_vertices.size(); vertexIndex++) {
         for (size_t vertexIndex = 0, outVertexIndex = 0; vertexIndex < sourceFace->m_vertices.size(); vertexIndex++) {
             const unsigned int vertex = sourceFace->m_vertices.at(vertexIndex);
             const unsigned int vertex = sourceFace->m_vertices.at(vertexIndex);
-            if (vertex >= pModel->m_Vertices.size()) {
+            if (vertex >= pModel->mVertices.size()) {
                 throw DeadlyImportError("OBJ: vertex index out of range");
                 throw DeadlyImportError("OBJ: vertex index out of range");
             }
             }
 
 
@@ -450,32 +450,32 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
                 throw DeadlyImportError("OBJ: bad vertex index");
                 throw DeadlyImportError("OBJ: bad vertex index");
             }
             }
 
 
-            pMesh->mVertices[newIndex] = pModel->m_Vertices[vertex];
+            pMesh->mVertices[newIndex] = pModel->mVertices[vertex];
 
 
             // Copy all normals
             // Copy all normals
-            if (normalsok && !pModel->m_Normals.empty() && vertexIndex < sourceFace->m_normals.size()) {
+            if (normalsok && !pModel->mNormals.empty() && vertexIndex < sourceFace->m_normals.size()) {
                 const unsigned int normal = sourceFace->m_normals.at(vertexIndex);
                 const unsigned int normal = sourceFace->m_normals.at(vertexIndex);
-                if (normal >= pModel->m_Normals.size()) {
+                if (normal >= pModel->mNormals.size()) {
                     normalsok = false;
                     normalsok = false;
                 } else {
                 } else {
-                    pMesh->mNormals[newIndex] = pModel->m_Normals[normal];
+                    pMesh->mNormals[newIndex] = pModel->mNormals[normal];
                 }
                 }
             }
             }
 
 
             // Copy all vertex colors
             // Copy all vertex colors
-            if (vertex < pModel->m_VertexColors.size()) {
-                const aiVector3D &color = pModel->m_VertexColors[vertex];
+            if (vertex < pModel->mVertexColors.size()) {
+                const aiVector3D &color = pModel->mVertexColors[vertex];
                 pMesh->mColors[0][newIndex] = aiColor4D(color.x, color.y, color.z, 1.0);
                 pMesh->mColors[0][newIndex] = aiColor4D(color.x, color.y, color.z, 1.0);
             }
             }
 
 
             // Copy all texture coordinates
             // Copy all texture coordinates
-            if (uvok && !pModel->m_TextureCoord.empty() && vertexIndex < sourceFace->m_texturCoords.size()) {
+            if (uvok && !pModel->mTextureCoord.empty() && vertexIndex < sourceFace->m_texturCoords.size()) {
                 const unsigned int tex = sourceFace->m_texturCoords.at(vertexIndex);
                 const unsigned int tex = sourceFace->m_texturCoords.at(vertexIndex);
 
 
-                if (tex >= pModel->m_TextureCoord.size()) {
+                if (tex >= pModel->mTextureCoord.size()) {
                     uvok = false;
                     uvok = false;
                 } else {
                 } else {
-                    const aiVector3D &coord3d = pModel->m_TextureCoord[tex];
+                    const aiVector3D &coord3d = pModel->mTextureCoord[tex];
                     pMesh->mTextureCoords[0][newIndex] = aiVector3D(coord3d.x, coord3d.y, coord3d.z);
                     pMesh->mTextureCoords[0][newIndex] = aiVector3D(coord3d.x, coord3d.y, coord3d.z);
                 }
                 }
             }
             }
@@ -484,15 +484,15 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
             aiFace *pDestFace = &pMesh->mFaces[outIndex];
             aiFace *pDestFace = &pMesh->mFaces[outIndex];
 
 
             const bool last = (vertexIndex == sourceFace->m_vertices.size() - 1);
             const bool last = (vertexIndex == sourceFace->m_vertices.size() - 1);
-            if (sourceFace->m_PrimitiveType != aiPrimitiveType_LINE || !last) {
+            if (sourceFace->mPrimitiveType != aiPrimitiveType_LINE || !last) {
                 pDestFace->mIndices[outVertexIndex] = newIndex;
                 pDestFace->mIndices[outVertexIndex] = newIndex;
                 outVertexIndex++;
                 outVertexIndex++;
             }
             }
 
 
-            if (sourceFace->m_PrimitiveType == aiPrimitiveType_POINT) {
+            if (sourceFace->mPrimitiveType == aiPrimitiveType_POINT) {
                 outIndex++;
                 outIndex++;
                 outVertexIndex = 0;
                 outVertexIndex = 0;
-            } else if (sourceFace->m_PrimitiveType == aiPrimitiveType_LINE) {
+            } else if (sourceFace->mPrimitiveType == aiPrimitiveType_LINE) {
                 outVertexIndex = 0;
                 outVertexIndex = 0;
 
 
                 if (!last)
                 if (!last)
@@ -501,10 +501,10 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel,
                 if (vertexIndex) {
                 if (vertexIndex) {
                     if (!last) {
                     if (!last) {
                         pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex];
                         pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex];
-                        if (!sourceFace->m_normals.empty() && !pModel->m_Normals.empty()) {
+                        if (!sourceFace->m_normals.empty() && !pModel->mNormals.empty()) {
                             pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex];
                             pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex];
                         }
                         }
-                        if (!pModel->m_TextureCoord.empty()) {
+                        if (!pModel->mTextureCoord.empty()) {
                             for (size_t i = 0; i < pMesh->GetNumUVChannels(); i++) {
                             for (size_t i = 0; i < pMesh->GetNumUVChannels(); i++) {
                                 pMesh->mTextureCoords[i][newIndex + 1] = pMesh->mTextureCoords[i][newIndex];
                                 pMesh->mTextureCoords[i][newIndex + 1] = pMesh->mTextureCoords[i][newIndex];
                             }
                             }
@@ -565,9 +565,9 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
         return;
         return;
     }
     }
 
 
-    const unsigned int numMaterials = (unsigned int)pModel->m_MaterialLib.size();
+    const unsigned int numMaterials = (unsigned int)pModel->mMaterialLib.size();
     pScene->mNumMaterials = 0;
     pScene->mNumMaterials = 0;
-    if (pModel->m_MaterialLib.empty()) {
+    if (pModel->mMaterialLib.empty()) {
         ASSIMP_LOG_DEBUG("OBJ: no materials specified");
         ASSIMP_LOG_DEBUG("OBJ: no materials specified");
         return;
         return;
     }
     }
@@ -576,10 +576,10 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
     for (unsigned int matIndex = 0; matIndex < numMaterials; matIndex++) {
     for (unsigned int matIndex = 0; matIndex < numMaterials; matIndex++) {
         // Store material name
         // Store material name
         std::map<std::string, ObjFile::Material *>::const_iterator it;
         std::map<std::string, ObjFile::Material *>::const_iterator it;
-        it = pModel->m_MaterialMap.find(pModel->m_MaterialLib[matIndex]);
+        it = pModel->mMaterialMap.find(pModel->mMaterialLib[matIndex]);
 
 
         // No material found, use the default material
         // No material found, use the default material
-        if (pModel->m_MaterialMap.end() == it)
+        if (pModel->mMaterialMap.end() == it)
             continue;
             continue;
 
 
         aiMaterial *mat = new aiMaterial;
         aiMaterial *mat = new aiMaterial;
@@ -616,11 +616,16 @@ void ObjFileImporter::createMaterials(const ObjFile::Model *pModel, aiScene *pSc
         mat->AddProperty(&pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS);
         mat->AddProperty(&pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS);
         mat->AddProperty(&pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY);
         mat->AddProperty(&pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY);
         mat->AddProperty(&pCurrentMaterial->transparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
         mat->AddProperty(&pCurrentMaterial->transparent, 1, AI_MATKEY_COLOR_TRANSPARENT);
-        mat->AddProperty(&pCurrentMaterial->roughness, 1, AI_MATKEY_ROUGHNESS_FACTOR);
-        mat->AddProperty(&pCurrentMaterial->metallic, 1, AI_MATKEY_METALLIC_FACTOR);
-        mat->AddProperty(&pCurrentMaterial->sheen, 1, AI_MATKEY_SHEEN_COLOR_FACTOR);
-        mat->AddProperty(&pCurrentMaterial->clearcoat_thickness, 1, AI_MATKEY_CLEARCOAT_FACTOR);
-        mat->AddProperty(&pCurrentMaterial->clearcoat_roughness, 1, AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR);
+        if (pCurrentMaterial->roughness)
+            mat->AddProperty(&pCurrentMaterial->roughness.Get(), 1, AI_MATKEY_ROUGHNESS_FACTOR);
+        if (pCurrentMaterial->metallic)
+            mat->AddProperty(&pCurrentMaterial->metallic.Get(), 1, AI_MATKEY_METALLIC_FACTOR);
+        if (pCurrentMaterial->sheen)
+            mat->AddProperty(&pCurrentMaterial->sheen.Get(), 1, AI_MATKEY_SHEEN_COLOR_FACTOR);
+        if (pCurrentMaterial->clearcoat_thickness)
+            mat->AddProperty(&pCurrentMaterial->clearcoat_thickness.Get(), 1, AI_MATKEY_CLEARCOAT_FACTOR);
+        if (pCurrentMaterial->clearcoat_roughness)
+            mat->AddProperty(&pCurrentMaterial->clearcoat_roughness.Get(), 1, AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR);
         mat->AddProperty(&pCurrentMaterial->anisotropy, 1, AI_MATKEY_ANISOTROPY_FACTOR);
         mat->AddProperty(&pCurrentMaterial->anisotropy, 1, AI_MATKEY_ANISOTROPY_FACTOR);
 
 
         // Adding refraction index
         // Adding refraction index

+ 84 - 52
code/AssetLib/Obj/ObjFileMtlImporter.cpp

@@ -99,9 +99,9 @@ ObjFileMtlImporter::ObjFileMtlImporter(std::vector<char> &buffer,
     ai_assert(nullptr != m_pModel);
     ai_assert(nullptr != m_pModel);
     m_buffer.resize(BUFFERSIZE);
     m_buffer.resize(BUFFERSIZE);
     std::fill(m_buffer.begin(), m_buffer.end(), '\0');
     std::fill(m_buffer.begin(), m_buffer.end(), '\0');
-    if (nullptr == m_pModel->m_pDefaultMaterial) {
-        m_pModel->m_pDefaultMaterial = new ObjFile::Material;
-        m_pModel->m_pDefaultMaterial->MaterialName.Set("default");
+    if (nullptr == m_pModel->mDefaultMaterial) {
+        m_pModel->mDefaultMaterial = new ObjFile::Material;
+        m_pModel->mDefaultMaterial->MaterialName.Set("default");
     }
     }
     load();
     load();
 }
 }
@@ -126,17 +126,21 @@ void ObjFileMtlImporter::load() {
                 if (*m_DataIt == 'a') // Ambient color
                 if (*m_DataIt == 'a') // Ambient color
                 {
                 {
                     ++m_DataIt;
                     ++m_DataIt;
-                    getColorRGBA(&m_pModel->m_pCurrentMaterial->ambient);
+                    if (m_pModel->mCurrentMaterial != nullptr)
+                        getColorRGBA(&m_pModel->mCurrentMaterial->ambient);
                 } else if (*m_DataIt == 'd') {
                 } else if (*m_DataIt == 'd') {
                     // Diffuse color
                     // Diffuse color
                     ++m_DataIt;
                     ++m_DataIt;
-                    getColorRGBA(&m_pModel->m_pCurrentMaterial->diffuse);
+                    if (m_pModel->mCurrentMaterial != nullptr)
+                        getColorRGBA(&m_pModel->mCurrentMaterial->diffuse);
                 } else if (*m_DataIt == 's') {
                 } else if (*m_DataIt == 's') {
                     ++m_DataIt;
                     ++m_DataIt;
-                    getColorRGBA(&m_pModel->m_pCurrentMaterial->specular);
+                    if (m_pModel->mCurrentMaterial != nullptr)
+                        getColorRGBA(&m_pModel->mCurrentMaterial->specular);
                 } else if (*m_DataIt == 'e') {
                 } else if (*m_DataIt == 'e') {
                     ++m_DataIt;
                     ++m_DataIt;
-                    getColorRGBA(&m_pModel->m_pCurrentMaterial->emissive);
+                    if (m_pModel->mCurrentMaterial != nullptr)
+                        getColorRGBA(&m_pModel->mCurrentMaterial->emissive);
                 }
                 }
                 m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
                 m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
             } break;
             } break;
@@ -145,13 +149,15 @@ void ObjFileMtlImporter::load() {
                 // Material transmission color
                 // Material transmission color
                 if (*m_DataIt == 'f')  {
                 if (*m_DataIt == 'f')  {
                     ++m_DataIt;
                     ++m_DataIt;
-                    getColorRGBA(&m_pModel->m_pCurrentMaterial->transparent);
+                    if (m_pModel->mCurrentMaterial != nullptr)
+                        getColorRGBA(&m_pModel->mCurrentMaterial->transparent);
                 } else if (*m_DataIt == 'r')  {
                 } else if (*m_DataIt == 'r')  {
                     // Material transmission alpha value
                     // Material transmission alpha value
                     ++m_DataIt;
                     ++m_DataIt;
                     ai_real d;
                     ai_real d;
                     getFloatValue(d);
                     getFloatValue(d);
-                    m_pModel->m_pCurrentMaterial->alpha = static_cast<ai_real>(1.0) - d;
+                    if (m_pModel->mCurrentMaterial != nullptr)
+                        m_pModel->mCurrentMaterial->alpha = static_cast<ai_real>(1.0) - d;
                 }
                 }
                 m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
                 m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
             } break;
             } break;
@@ -162,7 +168,8 @@ void ObjFileMtlImporter::load() {
                 } else {
                 } else {
                     // Alpha value
                     // Alpha value
                     ++m_DataIt;
                     ++m_DataIt;
-                    getFloatValue(m_pModel->m_pCurrentMaterial->alpha);
+                    if (m_pModel->mCurrentMaterial != nullptr)
+                        getFloatValue(m_pModel->mCurrentMaterial->alpha);
                     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
                     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
                 }
                 }
             } break;
             } break;
@@ -173,11 +180,13 @@ void ObjFileMtlImporter::load() {
                 switch (*m_DataIt) {
                 switch (*m_DataIt) {
                     case 's': // Specular exponent
                     case 's': // Specular exponent
                         ++m_DataIt;
                         ++m_DataIt;
-                        getFloatValue(m_pModel->m_pCurrentMaterial->shineness);
+                        if (m_pModel->mCurrentMaterial != nullptr)
+                            getFloatValue(m_pModel->mCurrentMaterial->shineness);
                         break;
                         break;
                     case 'i': // Index Of refraction
                     case 'i': // Index Of refraction
                         ++m_DataIt;
                         ++m_DataIt;
-                        getFloatValue(m_pModel->m_pCurrentMaterial->ior);
+                        if (m_pModel->mCurrentMaterial != nullptr)
+                            getFloatValue(m_pModel->mCurrentMaterial->ior);
                         break;
                         break;
                     case 'e': // New material
                     case 'e': // New material
                         createMaterial();
                         createMaterial();
@@ -197,23 +206,28 @@ void ObjFileMtlImporter::load() {
                     {
                     {
                     case 'r':
                     case 'r':
                         ++m_DataIt;
                         ++m_DataIt;
-                        getFloatValue(m_pModel->m_pCurrentMaterial->roughness);
+                        if (m_pModel->mCurrentMaterial != nullptr)
+                            getFloatValue(m_pModel->mCurrentMaterial->roughness);
                         break;
                         break;
                     case 'm':
                     case 'm':
                         ++m_DataIt;
                         ++m_DataIt;
-                        getFloatValue(m_pModel->m_pCurrentMaterial->metallic);
+                        if (m_pModel->mCurrentMaterial != nullptr)
+                            getFloatValue(m_pModel->mCurrentMaterial->metallic);
                         break;
                         break;
                     case 's':
                     case 's':
                         ++m_DataIt;
                         ++m_DataIt;
-                        getColorRGBA(&m_pModel->m_pCurrentMaterial->sheen);
+                        if (m_pModel->mCurrentMaterial != nullptr)
+                            getColorRGBA(m_pModel->mCurrentMaterial->sheen);
                         break;
                         break;
                     case 'c':
                     case 'c':
                         ++m_DataIt;
                         ++m_DataIt;
                         if (*m_DataIt == 'r') {
                         if (*m_DataIt == 'r') {
                             ++m_DataIt;
                             ++m_DataIt;
-                            getFloatValue(m_pModel->m_pCurrentMaterial->clearcoat_roughness);
+                            if (m_pModel->mCurrentMaterial != nullptr)
+                                getFloatValue(m_pModel->mCurrentMaterial->clearcoat_roughness);
                         } else {
                         } else {
-                            getFloatValue(m_pModel->m_pCurrentMaterial->clearcoat_thickness);
+                            if (m_pModel->mCurrentMaterial != nullptr)
+                                getFloatValue(m_pModel->mCurrentMaterial->clearcoat_thickness);
                         }
                         }
                         break;
                         break;
                     }
                     }
@@ -232,15 +246,17 @@ void ObjFileMtlImporter::load() {
             case 'i': // Illumination model
             case 'i': // Illumination model
             {
             {
                 m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
                 m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
-                getIlluminationModel(m_pModel->m_pCurrentMaterial->illumination_model);
+                if (m_pModel->mCurrentMaterial != nullptr)
+                    getIlluminationModel(m_pModel->mCurrentMaterial->illumination_model);
                 m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
                 m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
             } break;
             } break;
 
 
             case 'a': // Anisotropy
             case 'a': // Anisotropy
             {
             {
                 ++m_DataIt;
                 ++m_DataIt;
-                getFloatValue(m_pModel->m_pCurrentMaterial->anisotropy);
-                m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
+                getFloatValue(m_pModel->mCurrentMaterial->anisotropy);
+                if (m_pModel->mCurrentMaterial != nullptr)
+                    m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
             } break;
             } break;
 
 
             default: {
             default: {
@@ -268,6 +284,12 @@ void ObjFileMtlImporter::getColorRGBA(aiColor3D *pColor) {
     pColor->b = b;
     pColor->b = b;
 }
 }
 
 
+void ObjFileMtlImporter::getColorRGBA(Maybe<aiColor3D> &value) {
+    aiColor3D v;
+    getColorRGBA(&v);
+    value = Maybe<aiColor3D>(v);
+}
+
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
 //  Loads the kind of illumination model.
 //  Loads the kind of illumination model.
 void ObjFileMtlImporter::getIlluminationModel(int &illum_model) {
 void ObjFileMtlImporter::getIlluminationModel(int &illum_model) {
@@ -275,6 +297,7 @@ void ObjFileMtlImporter::getIlluminationModel(int &illum_model) {
     illum_model = atoi(&m_buffer[0]);
     illum_model = atoi(&m_buffer[0]);
 }
 }
 
 
+
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
 //  Loads a single float value.
 //  Loads a single float value.
 void ObjFileMtlImporter::getFloatValue(ai_real &value) {
 void ObjFileMtlImporter::getFloatValue(ai_real &value) {
@@ -284,10 +307,19 @@ void ObjFileMtlImporter::getFloatValue(ai_real &value) {
         value = 0.0f;
         value = 0.0f;
         return;
         return;
     }
     }
-    
+
     value = (ai_real)fast_atof(&m_buffer[0]);
     value = (ai_real)fast_atof(&m_buffer[0]);
 }
 }
 
 
+void ObjFileMtlImporter::getFloatValue(Maybe<ai_real> &value) {
+    m_DataIt = CopyNextWord<DataArrayIt>(m_DataIt, m_DataItEnd, &m_buffer[0], BUFFERSIZE);
+    size_t len = std::strlen(&m_buffer[0]);
+    if (len)
+        value = Maybe<ai_real>(fast_atof(&m_buffer[0]));
+    else
+        value = Maybe<ai_real>();
+}
+
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
 //  Creates a material from loaded data.
 //  Creates a material from loaded data.
 void ObjFileMtlImporter::createMaterial() {
 void ObjFileMtlImporter::createMaterial() {
@@ -313,20 +345,20 @@ void ObjFileMtlImporter::createMaterial() {
 
 
     name = trim_whitespaces(name);
     name = trim_whitespaces(name);
 
 
-    std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->m_MaterialMap.find(name);
-    if (m_pModel->m_MaterialMap.end() == it) {
+    std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->mMaterialMap.find(name);
+    if (m_pModel->mMaterialMap.end() == it) {
         // New Material created
         // New Material created
-        m_pModel->m_pCurrentMaterial = new ObjFile::Material();
-        m_pModel->m_pCurrentMaterial->MaterialName.Set(name);
-        m_pModel->m_MaterialLib.push_back(name);
-        m_pModel->m_MaterialMap[name] = m_pModel->m_pCurrentMaterial;
+        m_pModel->mCurrentMaterial = new ObjFile::Material();
+        m_pModel->mCurrentMaterial->MaterialName.Set(name);
+        m_pModel->mMaterialLib.push_back(name);
+        m_pModel->mMaterialMap[name] = m_pModel->mCurrentMaterial;
 
 
-        if (m_pModel->m_pCurrentMesh) {
-            m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->m_MaterialLib.size() - 1);
+        if (m_pModel->mCurrentMesh) {
+            m_pModel->mCurrentMesh->m_uiMaterialIndex = static_cast<unsigned int>(m_pModel->mMaterialLib.size() - 1);
         }
         }
     } else {
     } else {
         // Use older material
         // Use older material
-        m_pModel->m_pCurrentMaterial = (*it).second;
+        m_pModel->mCurrentMaterial = (*it).second;
     }
     }
 }
 }
 
 
@@ -339,38 +371,38 @@ void ObjFileMtlImporter::getTexture() {
     const char *pPtr(&(*m_DataIt));
     const char *pPtr(&(*m_DataIt));
     if (!ASSIMP_strincmp(pPtr, DiffuseTexture.c_str(), static_cast<unsigned int>(DiffuseTexture.size()))) {
     if (!ASSIMP_strincmp(pPtr, DiffuseTexture.c_str(), static_cast<unsigned int>(DiffuseTexture.size()))) {
         // Diffuse texture
         // Diffuse texture
-        out = &m_pModel->m_pCurrentMaterial->texture;
+        out = &m_pModel->mCurrentMaterial->texture;
         clampIndex = ObjFile::Material::TextureDiffuseType;
         clampIndex = ObjFile::Material::TextureDiffuseType;
     } else if (!ASSIMP_strincmp(pPtr, AmbientTexture.c_str(), static_cast<unsigned int>(AmbientTexture.size()))) {
     } else if (!ASSIMP_strincmp(pPtr, AmbientTexture.c_str(), static_cast<unsigned int>(AmbientTexture.size()))) {
         // Ambient texture
         // Ambient texture
-        out = &m_pModel->m_pCurrentMaterial->textureAmbient;
+        out = &m_pModel->mCurrentMaterial->textureAmbient;
         clampIndex = ObjFile::Material::TextureAmbientType;
         clampIndex = ObjFile::Material::TextureAmbientType;
     } else if (!ASSIMP_strincmp(pPtr, SpecularTexture.c_str(), static_cast<unsigned int>(SpecularTexture.size()))) {
     } else if (!ASSIMP_strincmp(pPtr, SpecularTexture.c_str(), static_cast<unsigned int>(SpecularTexture.size()))) {
         // Specular texture
         // Specular texture
-        out = &m_pModel->m_pCurrentMaterial->textureSpecular;
+        out = &m_pModel->mCurrentMaterial->textureSpecular;
         clampIndex = ObjFile::Material::TextureSpecularType;
         clampIndex = ObjFile::Material::TextureSpecularType;
     } else if (!ASSIMP_strincmp(pPtr, DisplacementTexture1.c_str(), static_cast<unsigned int>(DisplacementTexture1.size())) ||
     } else if (!ASSIMP_strincmp(pPtr, DisplacementTexture1.c_str(), static_cast<unsigned int>(DisplacementTexture1.size())) ||
                !ASSIMP_strincmp(pPtr, DisplacementTexture2.c_str(), static_cast<unsigned int>(DisplacementTexture2.size()))) {
                !ASSIMP_strincmp(pPtr, DisplacementTexture2.c_str(), static_cast<unsigned int>(DisplacementTexture2.size()))) {
         // Displacement texture
         // Displacement texture
-        out = &m_pModel->m_pCurrentMaterial->textureDisp;
+        out = &m_pModel->mCurrentMaterial->textureDisp;
         clampIndex = ObjFile::Material::TextureDispType;
         clampIndex = ObjFile::Material::TextureDispType;
     } else if (!ASSIMP_strincmp(pPtr, OpacityTexture.c_str(), static_cast<unsigned int>(OpacityTexture.size()))) {
     } else if (!ASSIMP_strincmp(pPtr, OpacityTexture.c_str(), static_cast<unsigned int>(OpacityTexture.size()))) {
         // Opacity texture
         // Opacity texture
-        out = &m_pModel->m_pCurrentMaterial->textureOpacity;
+        out = &m_pModel->mCurrentMaterial->textureOpacity;
         clampIndex = ObjFile::Material::TextureOpacityType;
         clampIndex = ObjFile::Material::TextureOpacityType;
     } else if (!ASSIMP_strincmp(pPtr, EmissiveTexture1.c_str(), static_cast<unsigned int>(EmissiveTexture1.size())) ||
     } else if (!ASSIMP_strincmp(pPtr, EmissiveTexture1.c_str(), static_cast<unsigned int>(EmissiveTexture1.size())) ||
                !ASSIMP_strincmp(pPtr, EmissiveTexture2.c_str(), static_cast<unsigned int>(EmissiveTexture2.size()))) {
                !ASSIMP_strincmp(pPtr, EmissiveTexture2.c_str(), static_cast<unsigned int>(EmissiveTexture2.size()))) {
         // Emissive texture
         // Emissive texture
-        out = &m_pModel->m_pCurrentMaterial->textureEmissive;
+        out = &m_pModel->mCurrentMaterial->textureEmissive;
         clampIndex = ObjFile::Material::TextureEmissiveType;
         clampIndex = ObjFile::Material::TextureEmissiveType;
     } else if (!ASSIMP_strincmp(pPtr, BumpTexture1.c_str(), static_cast<unsigned int>(BumpTexture1.size())) ||
     } else if (!ASSIMP_strincmp(pPtr, BumpTexture1.c_str(), static_cast<unsigned int>(BumpTexture1.size())) ||
                !ASSIMP_strincmp(pPtr, BumpTexture2.c_str(), static_cast<unsigned int>(BumpTexture2.size()))) {
                !ASSIMP_strincmp(pPtr, BumpTexture2.c_str(), static_cast<unsigned int>(BumpTexture2.size()))) {
         // Bump texture
         // Bump texture
-        out = &m_pModel->m_pCurrentMaterial->textureBump;
+        out = &m_pModel->mCurrentMaterial->textureBump;
         clampIndex = ObjFile::Material::TextureBumpType;
         clampIndex = ObjFile::Material::TextureBumpType;
     } else if (!ASSIMP_strincmp(pPtr, NormalTextureV1.c_str(), static_cast<unsigned int>(NormalTextureV1.size())) || !ASSIMP_strincmp(pPtr, NormalTextureV2.c_str(), static_cast<unsigned int>(NormalTextureV2.size()))) {
     } else if (!ASSIMP_strincmp(pPtr, NormalTextureV1.c_str(), static_cast<unsigned int>(NormalTextureV1.size())) || !ASSIMP_strincmp(pPtr, NormalTextureV2.c_str(), static_cast<unsigned int>(NormalTextureV2.size()))) {
         // Normal map
         // Normal map
-        out = &m_pModel->m_pCurrentMaterial->textureNormal;
+        out = &m_pModel->mCurrentMaterial->textureNormal;
         clampIndex = ObjFile::Material::TextureNormalType;
         clampIndex = ObjFile::Material::TextureNormalType;
     } else if (!ASSIMP_strincmp(pPtr, ReflectionTexture.c_str(), static_cast<unsigned int>(ReflectionTexture.size()))) {
     } else if (!ASSIMP_strincmp(pPtr, ReflectionTexture.c_str(), static_cast<unsigned int>(ReflectionTexture.size()))) {
         // Reflection texture(s)
         // Reflection texture(s)
@@ -378,23 +410,23 @@ void ObjFileMtlImporter::getTexture() {
         return;
         return;
     } else if (!ASSIMP_strincmp(pPtr, SpecularityTexture.c_str(), static_cast<unsigned int>(SpecularityTexture.size()))) {
     } else if (!ASSIMP_strincmp(pPtr, SpecularityTexture.c_str(), static_cast<unsigned int>(SpecularityTexture.size()))) {
         // Specularity scaling (glossiness)
         // Specularity scaling (glossiness)
-        out = &m_pModel->m_pCurrentMaterial->textureSpecularity;
+        out = &m_pModel->mCurrentMaterial->textureSpecularity;
         clampIndex = ObjFile::Material::TextureSpecularityType;
         clampIndex = ObjFile::Material::TextureSpecularityType;
     } else if ( !ASSIMP_strincmp( pPtr, RoughnessTexture.c_str(), static_cast<unsigned int>(RoughnessTexture.size()))) {
     } else if ( !ASSIMP_strincmp( pPtr, RoughnessTexture.c_str(), static_cast<unsigned int>(RoughnessTexture.size()))) {
         // PBR Roughness texture
         // PBR Roughness texture
-        out = & m_pModel->m_pCurrentMaterial->textureRoughness;
+        out = & m_pModel->mCurrentMaterial->textureRoughness;
         clampIndex = ObjFile::Material::TextureRoughnessType;
         clampIndex = ObjFile::Material::TextureRoughnessType;
     } else if ( !ASSIMP_strincmp( pPtr, MetallicTexture.c_str(), static_cast<unsigned int>(MetallicTexture.size()))) {
     } else if ( !ASSIMP_strincmp( pPtr, MetallicTexture.c_str(), static_cast<unsigned int>(MetallicTexture.size()))) {
         // PBR Metallic texture
         // PBR Metallic texture
-        out = & m_pModel->m_pCurrentMaterial->textureMetallic;
+        out = & m_pModel->mCurrentMaterial->textureMetallic;
         clampIndex = ObjFile::Material::TextureMetallicType;
         clampIndex = ObjFile::Material::TextureMetallicType;
     } else if (!ASSIMP_strincmp( pPtr, SheenTexture.c_str(), static_cast<unsigned int>(SheenTexture.size()))) {
     } else if (!ASSIMP_strincmp( pPtr, SheenTexture.c_str(), static_cast<unsigned int>(SheenTexture.size()))) {
         // PBR Sheen (reflectance) texture
         // PBR Sheen (reflectance) texture
-        out = & m_pModel->m_pCurrentMaterial->textureSheen;
+        out = & m_pModel->mCurrentMaterial->textureSheen;
         clampIndex = ObjFile::Material::TextureSheenType;
         clampIndex = ObjFile::Material::TextureSheenType;
     } else if (!ASSIMP_strincmp( pPtr, RMATexture.c_str(), static_cast<unsigned int>(RMATexture.size()))) {
     } else if (!ASSIMP_strincmp( pPtr, RMATexture.c_str(), static_cast<unsigned int>(RMATexture.size()))) {
         // PBR Rough/Metal/AO texture
         // PBR Rough/Metal/AO texture
-        out = & m_pModel->m_pCurrentMaterial->textureRMA;
+        out = & m_pModel->mCurrentMaterial->textureRMA;
         clampIndex = ObjFile::Material::TextureRMAType;
         clampIndex = ObjFile::Material::TextureRMAType;
     } else {
     } else {
         ASSIMP_LOG_ERROR("OBJ/MTL: Encountered unknown texture type");
         ASSIMP_LOG_ERROR("OBJ/MTL: Encountered unknown texture type");
@@ -403,7 +435,7 @@ void ObjFileMtlImporter::getTexture() {
 
 
     bool clamp = false;
     bool clamp = false;
     getTextureOption(clamp, clampIndex, out);
     getTextureOption(clamp, clampIndex, out);
-    m_pModel->m_pCurrentMaterial->clamp[clampIndex] = clamp;
+    m_pModel->mCurrentMaterial->clamp[clampIndex] = clamp;
 
 
     std::string texture;
     std::string texture;
     m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, texture);
     m_DataIt = getName<DataArrayIt>(m_DataIt, m_DataItEnd, texture);
@@ -451,31 +483,31 @@ void ObjFileMtlImporter::getTextureOption(bool &clamp, int &clampIndex, aiString
             CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
             CopyNextWord(it, m_DataItEnd, value, sizeof(value) / sizeof(*value));
             if (!ASSIMP_strincmp(value, "cube_top", 8)) {
             if (!ASSIMP_strincmp(value, "cube_top", 8)) {
                 clampIndex = ObjFile::Material::TextureReflectionCubeTopType;
                 clampIndex = ObjFile::Material::TextureReflectionCubeTopType;
-                out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
+                out = &m_pModel->mCurrentMaterial->textureReflection[0];
             } else if (!ASSIMP_strincmp(value, "cube_bottom", 11)) {
             } else if (!ASSIMP_strincmp(value, "cube_bottom", 11)) {
                 clampIndex = ObjFile::Material::TextureReflectionCubeBottomType;
                 clampIndex = ObjFile::Material::TextureReflectionCubeBottomType;
-                out = &m_pModel->m_pCurrentMaterial->textureReflection[1];
+                out = &m_pModel->mCurrentMaterial->textureReflection[1];
             } else if (!ASSIMP_strincmp(value, "cube_front", 10)) {
             } else if (!ASSIMP_strincmp(value, "cube_front", 10)) {
                 clampIndex = ObjFile::Material::TextureReflectionCubeFrontType;
                 clampIndex = ObjFile::Material::TextureReflectionCubeFrontType;
-                out = &m_pModel->m_pCurrentMaterial->textureReflection[2];
+                out = &m_pModel->mCurrentMaterial->textureReflection[2];
             } else if (!ASSIMP_strincmp(value, "cube_back", 9)) {
             } else if (!ASSIMP_strincmp(value, "cube_back", 9)) {
                 clampIndex = ObjFile::Material::TextureReflectionCubeBackType;
                 clampIndex = ObjFile::Material::TextureReflectionCubeBackType;
-                out = &m_pModel->m_pCurrentMaterial->textureReflection[3];
+                out = &m_pModel->mCurrentMaterial->textureReflection[3];
             } else if (!ASSIMP_strincmp(value, "cube_left", 9)) {
             } else if (!ASSIMP_strincmp(value, "cube_left", 9)) {
                 clampIndex = ObjFile::Material::TextureReflectionCubeLeftType;
                 clampIndex = ObjFile::Material::TextureReflectionCubeLeftType;
-                out = &m_pModel->m_pCurrentMaterial->textureReflection[4];
+                out = &m_pModel->mCurrentMaterial->textureReflection[4];
             } else if (!ASSIMP_strincmp(value, "cube_right", 10)) {
             } else if (!ASSIMP_strincmp(value, "cube_right", 10)) {
                 clampIndex = ObjFile::Material::TextureReflectionCubeRightType;
                 clampIndex = ObjFile::Material::TextureReflectionCubeRightType;
-                out = &m_pModel->m_pCurrentMaterial->textureReflection[5];
+                out = &m_pModel->mCurrentMaterial->textureReflection[5];
             } else if (!ASSIMP_strincmp(value, "sphere", 6)) {
             } else if (!ASSIMP_strincmp(value, "sphere", 6)) {
                 clampIndex = ObjFile::Material::TextureReflectionSphereType;
                 clampIndex = ObjFile::Material::TextureReflectionSphereType;
-                out = &m_pModel->m_pCurrentMaterial->textureReflection[0];
+                out = &m_pModel->mCurrentMaterial->textureReflection[0];
             }
             }
 
 
             skipToken = 2;
             skipToken = 2;
         } else if (!ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size()))) {
         } else if (!ASSIMP_strincmp(pPtr, BumpOption.c_str(), static_cast<unsigned int>(BumpOption.size()))) {
             DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
             DataArrayIt it = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
-            getFloat(it, m_DataItEnd, m_pModel->m_pCurrentMaterial->bump_multiplier);
+            getFloat(it, m_DataItEnd, m_pModel->mCurrentMaterial->bump_multiplier);
             skipToken = 2;
             skipToken = 2;
         } else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size()))) {
         } else if (!ASSIMP_strincmp(pPtr, BlendUOption.c_str(), static_cast<unsigned int>(BlendUOption.size())) || !ASSIMP_strincmp(pPtr, BlendVOption.c_str(), static_cast<unsigned int>(BlendVOption.size())) || !ASSIMP_strincmp(pPtr, BoostOption.c_str(), static_cast<unsigned int>(BoostOption.size())) || !ASSIMP_strincmp(pPtr, ResolutionOption.c_str(), static_cast<unsigned int>(ResolutionOption.size())) || !ASSIMP_strincmp(pPtr, ChannelOption.c_str(), static_cast<unsigned int>(ChannelOption.size()))) {
             skipToken = 2;
             skipToken = 2;

+ 3 - 0
code/AssetLib/Obj/ObjFileMtlImporter.h

@@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/defs.h>
 #include <assimp/defs.h>
 #include <string>
 #include <string>
 #include <vector>
 #include <vector>
+#include "Common/Maybe.h"
 
 
 struct aiColor3D;
 struct aiColor3D;
 struct aiString;
 struct aiString;
@@ -81,10 +82,12 @@ private:
     void load();
     void load();
     /// Get color data.
     /// Get color data.
     void getColorRGBA(aiColor3D *pColor);
     void getColorRGBA(aiColor3D *pColor);
+    void getColorRGBA(Maybe<aiColor3D> &value);
     /// Get illumination model from loaded data
     /// Get illumination model from loaded data
     void getIlluminationModel(int &illum_model);
     void getIlluminationModel(int &illum_model);
     /// Gets a float value from data.
     /// Gets a float value from data.
     void getFloatValue(ai_real &value);
     void getFloatValue(ai_real &value);
+    void getFloatValue(Maybe<ai_real> &value);
     /// Creates a new material from loaded data.
     /// Creates a new material from loaded data.
     void createMaterial();
     void createMaterial();
     /// Get texture name from loaded data.
     /// Get texture name from loaded data.

+ 76 - 74
code/AssetLib/Obj/ObjFileParser.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2020, assimp team
+Copyright (c) 2006-2022, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 
@@ -52,10 +52,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <cstdlib>
 #include <cstdlib>
 #include <memory>
 #include <memory>
 #include <utility>
 #include <utility>
+#include <string_view>
 
 
 namespace Assimp {
 namespace Assimp {
 
 
-constexpr char ObjFileParser::DEFAULT_MATERIAL[];
+constexpr const char ObjFileParser::DEFAULT_MATERIAL[];
 
 
 ObjFileParser::ObjFileParser() :
 ObjFileParser::ObjFileParser() :
         m_DataIt(),
         m_DataIt(),
@@ -84,13 +85,13 @@ ObjFileParser::ObjFileParser(IOStreamBuffer<char> &streamBuffer, const std::stri
 
 
     // Create the model instance to store all the data
     // Create the model instance to store all the data
     m_pModel.reset(new ObjFile::Model());
     m_pModel.reset(new ObjFile::Model());
-    m_pModel->m_ModelName = modelName;
+    m_pModel->mModelName = modelName;
 
 
     // create default material and store it
     // create default material and store it
-    m_pModel->m_pDefaultMaterial = new ObjFile::Material;
-    m_pModel->m_pDefaultMaterial->MaterialName.Set(DEFAULT_MATERIAL);
-    m_pModel->m_MaterialLib.push_back(DEFAULT_MATERIAL);
-    m_pModel->m_MaterialMap[DEFAULT_MATERIAL] = m_pModel->m_pDefaultMaterial;
+    m_pModel->mDefaultMaterial = new ObjFile::Material;
+    m_pModel->mDefaultMaterial->MaterialName.Set(DEFAULT_MATERIAL);
+    m_pModel->mMaterialLib.push_back(DEFAULT_MATERIAL);
+    m_pModel->mMaterialMap[DEFAULT_MATERIAL] = m_pModel->mDefaultMaterial;
 
 
     // Start parsing the file
     // Start parsing the file
     parseFile(streamBuffer);
     parseFile(streamBuffer);
@@ -153,23 +154,23 @@ void ObjFileParser::parseFile(IOStreamBuffer<char> &streamBuffer) {
                 size_t numComponents = getNumComponentsInDataDefinition();
                 size_t numComponents = getNumComponentsInDataDefinition();
                 if (numComponents == 3) {
                 if (numComponents == 3) {
                     // read in vertex definition
                     // read in vertex definition
-                    getVector3(m_pModel->m_Vertices);
+                    getVector3(m_pModel->mVertices);
                 } else if (numComponents == 4) {
                 } else if (numComponents == 4) {
                     // read in vertex definition (homogeneous coords)
                     // read in vertex definition (homogeneous coords)
-                    getHomogeneousVector3(m_pModel->m_Vertices);
+                    getHomogeneousVector3(m_pModel->mVertices);
                 } else if (numComponents == 6) {
                 } else if (numComponents == 6) {
                     // read vertex and vertex-color
                     // read vertex and vertex-color
-                    getTwoVectors3(m_pModel->m_Vertices, m_pModel->m_VertexColors);
+                    getTwoVectors3(m_pModel->mVertices, m_pModel->mVertexColors);
                 }
                 }
             } else if (*m_DataIt == 't') {
             } else if (*m_DataIt == 't') {
                 // read in texture coordinate ( 2D or 3D )
                 // read in texture coordinate ( 2D or 3D )
                 ++m_DataIt;
                 ++m_DataIt;
-                size_t dim = getTexCoordVector(m_pModel->m_TextureCoord);
-                m_pModel->m_TextureCoordDim = std::max(m_pModel->m_TextureCoordDim, (unsigned int)dim);
+                size_t dim = getTexCoordVector(m_pModel->mTextureCoord);
+                m_pModel->mTextureCoordDim = std::max(m_pModel->mTextureCoordDim, (unsigned int)dim);
             } else if (*m_DataIt == 'n') {
             } else if (*m_DataIt == 'n') {
                 // Read in normal vector definition
                 // Read in normal vector definition
                 ++m_DataIt;
                 ++m_DataIt;
-                getVector3(m_pModel->m_Normals);
+                getVector3(m_pModel->mNormals);
             }
             }
         } break;
         } break;
 
 
@@ -424,7 +425,7 @@ void ObjFileParser::getVector2(std::vector<aiVector2D> &point2d_array) {
     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
 }
 }
 
 
-static const std::string DefaultObjName = "defaultobject";
+static constexpr char DefaultObjName[] = "defaultobject";
 
 
 void ObjFileParser::getFace(aiPrimitiveType type) {
 void ObjFileParser::getFace(aiPrimitiveType type) {
     m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
     m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
@@ -435,12 +436,12 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
     ObjFile::Face *face = new ObjFile::Face(type);
     ObjFile::Face *face = new ObjFile::Face(type);
     bool hasNormal = false;
     bool hasNormal = false;
 
 
-    const int vSize = static_cast<unsigned int>(m_pModel->m_Vertices.size());
-    const int vtSize = static_cast<unsigned int>(m_pModel->m_TextureCoord.size());
-    const int vnSize = static_cast<unsigned int>(m_pModel->m_Normals.size());
+    const int vSize = static_cast<unsigned int>(m_pModel->mVertices.size());
+    const int vtSize = static_cast<unsigned int>(m_pModel->mTextureCoord.size());
+    const int vnSize = static_cast<unsigned int>(m_pModel->mNormals.size());
 
 
-    const bool vt = (!m_pModel->m_TextureCoord.empty());
-    const bool vn = (!m_pModel->m_Normals.empty());
+    const bool vt = (!m_pModel->mTextureCoord.empty());
+    const bool vn = (!m_pModel->mNormals.empty());
     int iPos = 0;
     int iPos = 0;
     while (m_DataIt != m_DataItEnd) {
     while (m_DataIt != m_DataItEnd) {
         int iStep = 1;
         int iStep = 1;
@@ -458,8 +459,9 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
             iPos = 0;
             iPos = 0;
         } else {
         } else {
             //OBJ USES 1 Base ARRAYS!!!!
             //OBJ USES 1 Base ARRAYS!!!!
-            const int iVal(::atoi(&(*m_DataIt)));
-
+            const char *token = &(*m_DataIt);
+            const int iVal = ::atoi(token);
+            
             // increment iStep position based off of the sign and # of digits
             // increment iStep position based off of the sign and # of digits
             int tmp = iVal;
             int tmp = iVal;
             if (iVal < 0) {
             if (iVal < 0) {
@@ -499,7 +501,7 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
             } else {
             } else {
                 //On error, std::atoi will return 0 which is not a valid value
                 //On error, std::atoi will return 0 which is not a valid value
                 delete face;
                 delete face;
-                throw DeadlyImportError("OBJ: Invalid face indice");
+                throw DeadlyImportError("OBJ: Invalid face index.");
             }
             }
         }
         }
         m_DataIt += iStep;
         m_DataIt += iStep;
@@ -514,28 +516,28 @@ void ObjFileParser::getFace(aiPrimitiveType type) {
     }
     }
 
 
     // Set active material, if one set
     // Set active material, if one set
-    if (nullptr != m_pModel->m_pCurrentMaterial) {
-        face->m_pMaterial = m_pModel->m_pCurrentMaterial;
+    if (nullptr != m_pModel->mCurrentMaterial) {
+        face->m_pMaterial = m_pModel->mCurrentMaterial;
     } else {
     } else {
-        face->m_pMaterial = m_pModel->m_pDefaultMaterial;
+        face->m_pMaterial = m_pModel->mDefaultMaterial;
     }
     }
 
 
     // Create a default object, if nothing is there
     // Create a default object, if nothing is there
-    if (nullptr == m_pModel->m_pCurrent) {
+    if (nullptr == m_pModel->mCurrentObject) {
         createObject(DefaultObjName);
         createObject(DefaultObjName);
     }
     }
 
 
     // Assign face to mesh
     // Assign face to mesh
-    if (nullptr == m_pModel->m_pCurrentMesh) {
+    if (nullptr == m_pModel->mCurrentMesh) {
         createMesh(DefaultObjName);
         createMesh(DefaultObjName);
     }
     }
 
 
     // Store the face
     // Store the face
-    m_pModel->m_pCurrentMesh->m_Faces.push_back(face);
-    m_pModel->m_pCurrentMesh->m_uiNumIndices += (unsigned int)face->m_vertices.size();
-    m_pModel->m_pCurrentMesh->m_uiUVCoordinates[0] += (unsigned int)face->m_texturCoords.size();
-    if (!m_pModel->m_pCurrentMesh->m_hasNormals && hasNormal) {
-        m_pModel->m_pCurrentMesh->m_hasNormals = true;
+    m_pModel->mCurrentMesh->m_Faces.emplace_back(face);
+    m_pModel->mCurrentMesh->m_uiNumIndices += static_cast<unsigned int>(face->m_vertices.size());
+    m_pModel->mCurrentMesh->m_uiUVCoordinates[0] += static_cast<unsigned int>(face->m_texturCoords.size());
+    if (!m_pModel->mCurrentMesh->m_hasNormals && hasNormal) {
+        m_pModel->mCurrentMesh->m_hasNormals = true;
     }
     }
     // Skip the rest of the line
     // Skip the rest of the line
     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
@@ -564,33 +566,33 @@ void ObjFileParser::getMaterialDesc() {
 
 
     // If the current mesh has the same material, we simply ignore that 'usemtl' command
     // If the current mesh has the same material, we simply ignore that 'usemtl' command
     // There is no need to create another object or even mesh here
     // There is no need to create another object or even mesh here
-    if (m_pModel->m_pCurrentMaterial && m_pModel->m_pCurrentMaterial->MaterialName == aiString(strName)) {
+    if (m_pModel->mCurrentMaterial && m_pModel->mCurrentMaterial->MaterialName == aiString(strName)) {
         skip = true;
         skip = true;
     }
     }
 
 
     if (!skip) {
     if (!skip) {
         // Search for material
         // Search for material
-        std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->m_MaterialMap.find(strName);
-        if (it == m_pModel->m_MaterialMap.end()) {
+        std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->mMaterialMap.find(strName);
+        if (it == m_pModel->mMaterialMap.end()) {
             // Not found, so we don't know anything about the material except for its name.
             // Not found, so we don't know anything about the material except for its name.
             // This may be the case if the material library is missing. We don't want to lose all
             // This may be the case if the material library is missing. We don't want to lose all
             // materials if that happens, so create a new named material instead of discarding it
             // materials if that happens, so create a new named material instead of discarding it
             // completely.
             // completely.
             ASSIMP_LOG_ERROR("OBJ: failed to locate material ", strName, ", creating new material");
             ASSIMP_LOG_ERROR("OBJ: failed to locate material ", strName, ", creating new material");
-            m_pModel->m_pCurrentMaterial = new ObjFile::Material();
-            m_pModel->m_pCurrentMaterial->MaterialName.Set(strName);
-            m_pModel->m_MaterialLib.push_back(strName);
-            m_pModel->m_MaterialMap[strName] = m_pModel->m_pCurrentMaterial;
+            m_pModel->mCurrentMaterial = new ObjFile::Material();
+            m_pModel->mCurrentMaterial->MaterialName.Set(strName);
+            m_pModel->mMaterialLib.push_back(strName);
+            m_pModel->mMaterialMap[strName] = m_pModel->mCurrentMaterial;
         } else {
         } else {
             // Found, using detected material
             // Found, using detected material
-            m_pModel->m_pCurrentMaterial = (*it).second;
+            m_pModel->mCurrentMaterial = (*it).second;
         }
         }
 
 
         if (needsNewMesh(strName)) {
         if (needsNewMesh(strName)) {
             createMesh(strName);
             createMesh(strName);
         }
         }
 
 
-        m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
+        m_pModel->mCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strName);
     }
     }
 
 
     // Skip rest of line
     // Skip rest of line
@@ -677,17 +679,17 @@ void ObjFileParser::getNewMaterial() {
     while (m_DataIt != m_DataItEnd && IsSpaceOrNewLine(*m_DataIt)) {
     while (m_DataIt != m_DataItEnd && IsSpaceOrNewLine(*m_DataIt)) {
         ++m_DataIt;
         ++m_DataIt;
     }
     }
-    std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->m_MaterialMap.find(strMat);
-    if (it == m_pModel->m_MaterialMap.end()) {
+    std::map<std::string, ObjFile::Material *>::iterator it = m_pModel->mMaterialMap.find(strMat);
+    if (it == m_pModel->mMaterialMap.end()) {
         // Show a warning, if material was not found
         // Show a warning, if material was not found
         ASSIMP_LOG_WARN("OBJ: Unsupported material requested: ", strMat);
         ASSIMP_LOG_WARN("OBJ: Unsupported material requested: ", strMat);
-        m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial;
+        m_pModel->mCurrentMaterial = m_pModel->mDefaultMaterial;
     } else {
     } else {
         // Set new material
         // Set new material
         if (needsNewMesh(strMat)) {
         if (needsNewMesh(strMat)) {
             createMesh(strMat);
             createMesh(strMat);
         }
         }
-        m_pModel->m_pCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strMat);
+        m_pModel->mCurrentMesh->m_uiMaterialIndex = getMaterialIndex(strMat);
     }
     }
 
 
     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
@@ -699,8 +701,8 @@ int ObjFileParser::getMaterialIndex(const std::string &strMaterialName) {
     if (strMaterialName.empty()) {
     if (strMaterialName.empty()) {
         return mat_index;
         return mat_index;
     }
     }
-    for (size_t index = 0; index < m_pModel->m_MaterialLib.size(); ++index) {
-        if (strMaterialName == m_pModel->m_MaterialLib[index]) {
+    for (size_t index = 0; index < m_pModel->mMaterialLib.size(); ++index) {
+        if (strMaterialName == m_pModel->mMaterialLib[index]) {
             mat_index = (int)index;
             mat_index = (int)index;
             break;
             break;
         }
         }
@@ -721,22 +723,22 @@ void ObjFileParser::getGroupName() {
     }
     }
 
 
     // Change active group, if necessary
     // Change active group, if necessary
-    if (m_pModel->m_strActiveGroup != groupName) {
+    if (m_pModel->mActiveGroup != groupName) {
         // Search for already existing entry
         // Search for already existing entry
-        ObjFile::Model::ConstGroupMapIt it = m_pModel->m_Groups.find(groupName);
+        ObjFile::Model::ConstGroupMapIt it = m_pModel->mGroups.find(groupName);
 
 
         // We are mapping groups into the object structure
         // We are mapping groups into the object structure
         createObject(groupName);
         createObject(groupName);
 
 
         // New group name, creating a new entry
         // New group name, creating a new entry
-        if (it == m_pModel->m_Groups.end()) {
+        if (it == m_pModel->mGroups.end()) {
             std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
             std::vector<unsigned int> *pFaceIDArray = new std::vector<unsigned int>;
-            m_pModel->m_Groups[groupName] = pFaceIDArray;
-            m_pModel->m_pGroupFaceIDs = (pFaceIDArray);
+            m_pModel->mGroups[groupName] = pFaceIDArray;
+            m_pModel->mGroupFaceIDs = (pFaceIDArray);
         } else {
         } else {
-            m_pModel->m_pGroupFaceIDs = (*it).second;
+            m_pModel->mGroupFaceIDs = (*it).second;
         }
         }
-        m_pModel->m_strActiveGroup = groupName;
+        m_pModel->mActiveGroup = groupName;
     }
     }
     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
     m_DataIt = skipLine<DataArrayIt>(m_DataIt, m_DataItEnd, m_uiLine);
 }
 }
@@ -773,20 +775,20 @@ void ObjFileParser::getObjectName() {
     std::string strObjectName(pStart, &(*m_DataIt));
     std::string strObjectName(pStart, &(*m_DataIt));
     if (!strObjectName.empty()) {
     if (!strObjectName.empty()) {
         // Reset current object
         // Reset current object
-        m_pModel->m_pCurrent = nullptr;
+        m_pModel->mCurrentObject = nullptr;
 
 
         // Search for actual object
         // Search for actual object
-        for (std::vector<ObjFile::Object *>::const_iterator it = m_pModel->m_Objects.begin();
-                it != m_pModel->m_Objects.end();
+        for (std::vector<ObjFile::Object *>::const_iterator it = m_pModel->mObjects.begin();
+                it != m_pModel->mObjects.end();
                 ++it) {
                 ++it) {
             if ((*it)->m_strObjName == strObjectName) {
             if ((*it)->m_strObjName == strObjectName) {
-                m_pModel->m_pCurrent = *it;
+                m_pModel->mCurrentObject = *it;
                 break;
                 break;
             }
             }
         }
         }
 
 
         // Allocate a new object, if current one was not found before
         // Allocate a new object, if current one was not found before
-        if (nullptr == m_pModel->m_pCurrent) {
+        if (nullptr == m_pModel->mCurrentObject) {
             createObject(strObjectName);
             createObject(strObjectName);
         }
         }
     }
     }
@@ -797,16 +799,16 @@ void ObjFileParser::getObjectName() {
 void ObjFileParser::createObject(const std::string &objName) {
 void ObjFileParser::createObject(const std::string &objName) {
     ai_assert(nullptr != m_pModel);
     ai_assert(nullptr != m_pModel);
 
 
-    m_pModel->m_pCurrent = new ObjFile::Object;
-    m_pModel->m_pCurrent->m_strObjName = objName;
-    m_pModel->m_Objects.push_back(m_pModel->m_pCurrent);
+    m_pModel->mCurrentObject = new ObjFile::Object;
+    m_pModel->mCurrentObject->m_strObjName = objName;
+    m_pModel->mObjects.push_back(m_pModel->mCurrentObject);
 
 
     createMesh(objName);
     createMesh(objName);
 
 
-    if (m_pModel->m_pCurrentMaterial) {
-        m_pModel->m_pCurrentMesh->m_uiMaterialIndex =
-                getMaterialIndex(m_pModel->m_pCurrentMaterial->MaterialName.data);
-        m_pModel->m_pCurrentMesh->m_pMaterial = m_pModel->m_pCurrentMaterial;
+    if (m_pModel->mCurrentMaterial) {
+        m_pModel->mCurrentMesh->m_uiMaterialIndex =
+                getMaterialIndex(m_pModel->mCurrentMaterial->MaterialName.data);
+        m_pModel->mCurrentMesh->m_pMaterial = m_pModel->mCurrentMaterial;
     }
     }
 }
 }
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
@@ -814,11 +816,11 @@ void ObjFileParser::createObject(const std::string &objName) {
 void ObjFileParser::createMesh(const std::string &meshName) {
 void ObjFileParser::createMesh(const std::string &meshName) {
     ai_assert(nullptr != m_pModel);
     ai_assert(nullptr != m_pModel);
 
 
-    m_pModel->m_pCurrentMesh = new ObjFile::Mesh(meshName);
-    m_pModel->m_Meshes.push_back(m_pModel->m_pCurrentMesh);
-    unsigned int meshId = static_cast<unsigned int>(m_pModel->m_Meshes.size() - 1);
-    if (nullptr != m_pModel->m_pCurrent) {
-        m_pModel->m_pCurrent->m_Meshes.push_back(meshId);
+    m_pModel->mCurrentMesh = new ObjFile::Mesh(meshName);
+    m_pModel->mMeshes.push_back(m_pModel->mCurrentMesh);
+    unsigned int meshId = static_cast<unsigned int>(m_pModel->mMeshes.size() - 1);
+    if (nullptr != m_pModel->mCurrentObject) {
+        m_pModel->mCurrentObject->m_Meshes.push_back(meshId);
     } else {
     } else {
         ASSIMP_LOG_ERROR("OBJ: No object detected to attach a new mesh instance.");
         ASSIMP_LOG_ERROR("OBJ: No object detected to attach a new mesh instance.");
     }
     }
@@ -828,16 +830,16 @@ void ObjFileParser::createMesh(const std::string &meshName) {
 //  Returns true, if a new mesh must be created.
 //  Returns true, if a new mesh must be created.
 bool ObjFileParser::needsNewMesh(const std::string &materialName) {
 bool ObjFileParser::needsNewMesh(const std::string &materialName) {
     // If no mesh data yet
     // If no mesh data yet
-    if (m_pModel->m_pCurrentMesh == nullptr) {
+    if (m_pModel->mCurrentMesh == nullptr) {
         return true;
         return true;
     }
     }
     bool newMat = false;
     bool newMat = false;
     int matIdx = getMaterialIndex(materialName);
     int matIdx = getMaterialIndex(materialName);
-    int curMatIdx = m_pModel->m_pCurrentMesh->m_uiMaterialIndex;
+    int curMatIdx = m_pModel->mCurrentMesh->m_uiMaterialIndex;
     if (curMatIdx != int(ObjFile::Mesh::NoMaterial) && curMatIdx != matIdx
     if (curMatIdx != int(ObjFile::Mesh::NoMaterial) && curMatIdx != matIdx
             // no need create a new mesh if no faces in current
             // no need create a new mesh if no faces in current
             // lets say 'usemtl' goes straight after 'g'
             // lets say 'usemtl' goes straight after 'g'
-            && !m_pModel->m_pCurrentMesh->m_Faces.empty()) {
+            && !m_pModel->mCurrentMesh->m_Faces.empty()) {
         // New material -> only one material per mesh, so we need to create a new
         // New material -> only one material per mesh, so we need to create a new
         // material
         // material
         newMat = true;
         newMat = true;

+ 1 - 4
code/AssetLib/Obj/ObjFileParser.h

@@ -137,11 +137,8 @@ protected:
     void reportErrorTokenInFace();
     void reportErrorTokenInFace();
 
 
 private:
 private:
-    // Copy and assignment constructor should be private
-    // because the class contains pointer to allocated memory
-
     /// Default material name
     /// Default material name
-    static constexpr char DEFAULT_MATERIAL[] = AI_DEFAULT_MATERIAL_NAME;
+    static constexpr const char DEFAULT_MATERIAL[] = AI_DEFAULT_MATERIAL_NAME;
     //! Iterator to current position in buffer
     //! Iterator to current position in buffer
     DataArrayIt m_DataIt;
     DataArrayIt m_DataIt;
     //! Iterator to end position of buffer
     //! Iterator to end position of buffer

+ 1 - 1
code/AssetLib/Obj/ObjTools.h

@@ -236,7 +236,7 @@ inline char_t CopyNextWord(char_t it, char_t end, char *pBuffer, size_t length)
 template <class char_t>
 template <class char_t>
 inline char_t getFloat(char_t it, char_t end, ai_real &value) {
 inline char_t getFloat(char_t it, char_t end, ai_real &value) {
     static const size_t BUFFERSIZE = 1024;
     static const size_t BUFFERSIZE = 1024;
-    char buffer[BUFFERSIZE];
+    char buffer[BUFFERSIZE] = {};
     it = CopyNextWord<char_t>(it, end, buffer, BUFFERSIZE);
     it = CopyNextWord<char_t>(it, end, buffer, BUFFERSIZE);
     value = (ai_real)fast_atof(buffer);
     value = (ai_real)fast_atof(buffer);
 
 

+ 21 - 11
code/AssetLib/Ogre/OgreXmlSerializer.cpp

@@ -248,6 +248,7 @@ void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
         } else if (currentName == nnBoneAssignments) {
         } else if (currentName == nnBoneAssignments) {
             ReadBoneAssignments(currentNode, mesh->sharedVertexData);
             ReadBoneAssignments(currentNode, mesh->sharedVertexData);
         } else if (currentName == nnSkeletonLink) {
         } else if (currentName == nnSkeletonLink) {
+            mesh->skeletonRef = currentNode.attribute("name").as_string();
         }
         }
     }
     }
 
 
@@ -488,6 +489,15 @@ bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *me
     Skeleton *skeleton = new Skeleton();
     Skeleton *skeleton = new Skeleton();
     OgreXmlSerializer serializer(xmlParser.get());
     OgreXmlSerializer serializer(xmlParser.get());
     XmlNode root = xmlParser->getRootNode();
     XmlNode root = xmlParser->getRootNode();
+    if (std::string(root.name()) != nnSkeleton) {
+        printf("\nSkeleton is not a valid root: %s\n", root.name());
+        for (auto &a : root.children()) {
+            if (std::string(a.name()) == nnSkeleton) {
+                root = a;
+                break;
+            }
+        }
+    }
     serializer.ReadSkeleton(root, skeleton);
     serializer.ReadSkeleton(root, skeleton);
     mesh->skeleton = skeleton;
     mesh->skeleton = skeleton;
     return true;
     return true;
@@ -537,7 +547,7 @@ XmlParserPtr OgreXmlSerializer::OpenXmlParser(Assimp::IOSystem *pIOHandler, cons
 }
 }
 
 
 void OgreXmlSerializer::ReadSkeleton(XmlNode &node, Skeleton *skeleton) {
 void OgreXmlSerializer::ReadSkeleton(XmlNode &node, Skeleton *skeleton) {
-    if (node.name() != nnSkeleton) {
+    if (std::string(node.name()) != nnSkeleton) {
         throw DeadlyImportError("Root node is <" + std::string(node.name()) + "> expecting <skeleton>");
         throw DeadlyImportError("Root node is <" + std::string(node.name()) + "> expecting <skeleton>");
     }
     }
 
 
@@ -574,14 +584,14 @@ void OgreXmlSerializer::ReadAnimations(XmlNode &node, Skeleton *skeleton) {
             anim->name = ReadAttribute<std::string>(currentNode, "name");
             anim->name = ReadAttribute<std::string>(currentNode, "name");
             anim->length = ReadAttribute<float>(currentNode, "length");
             anim->length = ReadAttribute<float>(currentNode, "length");
             for (XmlNode &currentChildNode : currentNode.children()) {
             for (XmlNode &currentChildNode : currentNode.children()) {
-                const std::string currentChildName = currentNode.name();
+                const std::string currentChildName = currentChildNode.name();
                 if (currentChildName == nnTracks) {
                 if (currentChildName == nnTracks) {
                     ReadAnimationTracks(currentChildNode, anim);
                     ReadAnimationTracks(currentChildNode, anim);
-                    skeleton->animations.push_back(anim);
                 } else {
                 } else {
                     throw DeadlyImportError("No <tracks> found in <animation> ", anim->name);
                     throw DeadlyImportError("No <tracks> found in <animation> ", anim->name);
                 }
                 }
             }
             }
+            skeleton->animations.push_back(anim);
         }
         }
     }
     }
 }
 }
@@ -594,14 +604,14 @@ void OgreXmlSerializer::ReadAnimationTracks(XmlNode &node, Animation *dest) {
             track.type = VertexAnimationTrack::VAT_TRANSFORM;
             track.type = VertexAnimationTrack::VAT_TRANSFORM;
             track.boneName = ReadAttribute<std::string>(currentNode, "bone");
             track.boneName = ReadAttribute<std::string>(currentNode, "bone");
             for (XmlNode &currentChildNode : currentNode.children()) {
             for (XmlNode &currentChildNode : currentNode.children()) {
-                const std::string currentChildName = currentNode.name();
+                const std::string currentChildName = currentChildNode.name();
                 if (currentChildName == nnKeyFrames) {
                 if (currentChildName == nnKeyFrames) {
                     ReadAnimationKeyFrames(currentChildNode, dest, &track);
                     ReadAnimationKeyFrames(currentChildNode, dest, &track);
-                    dest->tracks.push_back(track);
                 } else {
                 } else {
                     throw DeadlyImportError("No <keyframes> found in <track> ", dest->name);
                     throw DeadlyImportError("No <keyframes> found in <track> ", dest->name);
                 }
                 }
             }
             }
+            dest->tracks.push_back(track);
         }
         }
     }
     }
 }
 }
@@ -614,15 +624,15 @@ void OgreXmlSerializer::ReadAnimationKeyFrames(XmlNode &node, Animation *anim, V
         if (currentName == nnKeyFrame) {
         if (currentName == nnKeyFrame) {
             keyframe.timePos = ReadAttribute<float>(currentNode, "time");
             keyframe.timePos = ReadAttribute<float>(currentNode, "time");
             for (XmlNode &currentChildNode : currentNode.children()) {
             for (XmlNode &currentChildNode : currentNode.children()) {
-                const std::string currentChildName = currentNode.name();
+                const std::string currentChildName = currentChildNode.name();
                 if (currentChildName == nnTranslate) {
                 if (currentChildName == nnTranslate) {
                     keyframe.position.x = ReadAttribute<float>(currentChildNode, anX);
                     keyframe.position.x = ReadAttribute<float>(currentChildNode, anX);
                     keyframe.position.y = ReadAttribute<float>(currentChildNode, anY);
                     keyframe.position.y = ReadAttribute<float>(currentChildNode, anY);
                     keyframe.position.z = ReadAttribute<float>(currentChildNode, anZ);
                     keyframe.position.z = ReadAttribute<float>(currentChildNode, anZ);
                 } else if (currentChildName == nnRotate) {
                 } else if (currentChildName == nnRotate) {
                     float angle = ReadAttribute<float>(currentChildNode, "angle");
                     float angle = ReadAttribute<float>(currentChildNode, "angle");
-                    for (XmlNode &currentChildChildNode : currentNode.children()) {
-                        const std::string currentChildChildName = currentNode.name();
+                    for (XmlNode &currentChildChildNode : currentChildNode.children()) {
+                        const std::string currentChildChildName = currentChildChildNode.name();
                         if (currentChildChildName == nnAxis) {
                         if (currentChildChildName == nnAxis) {
                             aiVector3D axis;
                             aiVector3D axis;
                             axis.x = ReadAttribute<float>(currentChildChildNode, anX);
                             axis.x = ReadAttribute<float>(currentChildChildNode, anX);
@@ -695,12 +705,12 @@ void OgreXmlSerializer::ReadBones(XmlNode &node, Skeleton *skeleton) {
             bone->id = ReadAttribute<uint16_t>(currentNode, "id");
             bone->id = ReadAttribute<uint16_t>(currentNode, "id");
             bone->name = ReadAttribute<std::string>(currentNode, "name");
             bone->name = ReadAttribute<std::string>(currentNode, "name");
             for (XmlNode &currentChildNode : currentNode.children()) {
             for (XmlNode &currentChildNode : currentNode.children()) {
-                const std::string currentChildName = currentNode.name();
-                if (currentChildName == nnRotation) {
+                const std::string currentChildName = currentChildNode.name();
+                if (currentChildName == nnPosition) {
                     bone->position.x = ReadAttribute<float>(currentChildNode, anX);
                     bone->position.x = ReadAttribute<float>(currentChildNode, anX);
                     bone->position.y = ReadAttribute<float>(currentChildNode, anY);
                     bone->position.y = ReadAttribute<float>(currentChildNode, anY);
                     bone->position.z = ReadAttribute<float>(currentChildNode, anZ);
                     bone->position.z = ReadAttribute<float>(currentChildNode, anZ);
-                } else if (currentChildName == nnScale) {
+                } else if (currentChildName == nnRotation) {
                     float angle = ReadAttribute<float>(currentChildNode, "angle");
                     float angle = ReadAttribute<float>(currentChildNode, "angle");
                     for (XmlNode currentChildChildNode : currentChildNode.children()) {
                     for (XmlNode currentChildChildNode : currentChildNode.children()) {
                         const std::string &currentChildChildName = currentChildChildNode.name();
                         const std::string &currentChildChildName = currentChildChildNode.name();

+ 21 - 29
code/AssetLib/OpenGEX/OpenGEXImporter.cpp

@@ -151,45 +151,46 @@ namespace Grammar {
     }
     }
 
 
     static TokenType matchTokenType(const char *tokenType) {
     static TokenType matchTokenType(const char *tokenType) {
-        if (MetricType == tokenType) {
+        const size_t len = std::strlen(tokenType);
+        if (0 == strncmp(MetricType, tokenType, len)) {
             return MetricToken;
             return MetricToken;
-        } else if (NameType == tokenType) {
+        } else if (0 == strncmp(NameType, tokenType, len)) {
             return NameToken;
             return NameToken;
-        } else if (ObjectRefType == tokenType) {
+        } else if (0 == strncmp(ObjectRefType, tokenType, len)) {
             return ObjectRefToken;
             return ObjectRefToken;
-        } else if (MaterialRefType == tokenType) {
+        } else if (0 == strncmp(MaterialRefType, tokenType, len)) {
             return MaterialRefToken;
             return MaterialRefToken;
-        } else if (MetricKeyType == tokenType) {
+        } else if (0 == strncmp(MetricKeyType, tokenType, len)) {
             return MetricKeyToken;
             return MetricKeyToken;
-        } else if (GeometryNodeType == tokenType) {
+        } else if (0 == strncmp(GeometryNodeType, tokenType, len)) {
             return GeometryNodeToken;
             return GeometryNodeToken;
-        } else if (CameraNodeType == tokenType) {
+        } else if (0 == strncmp(CameraNodeType, tokenType, len)) {
             return CameraNodeToken;
             return CameraNodeToken;
-        } else if (LightNodeType == tokenType) {
+        } else if (0 == strncmp(LightNodeType, tokenType, len)) {
             return LightNodeToken;
             return LightNodeToken;
-        } else if (GeometryObjectType == tokenType) {
+        } else if (0 == strncmp(GeometryObjectType, tokenType, len)) {
             return GeometryObjectToken;
             return GeometryObjectToken;
-        } else if (CameraObjectType == tokenType) {
+        } else if (0 == strncmp(CameraObjectType, tokenType, len)) {
             return CameraObjectToken;
             return CameraObjectToken;
-        } else if (LightObjectType == tokenType) {
+        } else if (0 == strncmp(LightObjectType, tokenType, len)) {
             return LightObjectToken;
             return LightObjectToken;
-        } else if (TransformType == tokenType) {
+        } else if (0 == strncmp(TransformType, tokenType, len)) {
             return TransformToken;
             return TransformToken;
-        } else if (MeshType == tokenType) {
+        } else if (0 == strncmp(MeshType, tokenType, len)) {
             return MeshToken;
             return MeshToken;
-        } else if (VertexArrayType == tokenType) {
+        } else if (0 == strncmp(VertexArrayType, tokenType, len)) {
             return VertexArrayToken;
             return VertexArrayToken;
-        } else if (IndexArrayType == tokenType) {
+        } else if (0 == strncmp(IndexArrayType, tokenType, len)) {
             return IndexArrayToken;
             return IndexArrayToken;
-        } else if (MaterialType == tokenType) {
+        } else if (0 == strncmp(MaterialType, tokenType, len)) {
             return MaterialToken;
             return MaterialToken;
-        } else if (ColorType == tokenType) {
+        } else if (0 == strncmp(ColorType, tokenType, len)) {
             return ColorToken;
             return ColorToken;
-        } else if (ParamType == tokenType) {
+        } else if (0 == strncmp(ParamType, tokenType, len)) {
             return ParamToken;
             return ParamToken;
-        } else if (TextureType == tokenType) {
+        } else if (0 == strncmp(TextureType, tokenType, len)) {
             return TextureToken;
             return TextureToken;
-        } else if (AttenType == tokenType) {
+        } else if (0 == strncmp(AttenType, tokenType, len)) {
             return AttenToken;
             return AttenToken;
         }
         }
 
 
@@ -256,11 +257,6 @@ OpenGEXImporter::RefInfo::RefInfo(aiNode *node, Type type, std::vector<std::stri
     // empty
     // empty
 }
 }
 
 
-//------------------------------------------------------------------------------------------------
-OpenGEXImporter::RefInfo::~RefInfo() {
-    // empty
-}
-
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
 OpenGEXImporter::OpenGEXImporter() :
 OpenGEXImporter::OpenGEXImporter() :
         m_root(nullptr),
         m_root(nullptr),
@@ -285,10 +281,6 @@ OpenGEXImporter::OpenGEXImporter() :
     // empty
     // empty
 }
 }
 
 
-//------------------------------------------------------------------------------------------------
-OpenGEXImporter::~OpenGEXImporter() {
-}
-
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
 bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
 bool OpenGEXImporter::CanRead(const std::string &file, IOSystem *pIOHandler, bool /*checkSig*/) const {
     static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };
     static const char *tokens[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" };

+ 3 - 8
code/AssetLib/OpenGEX/OpenGEXImporter.h

@@ -79,12 +79,7 @@ struct MetricInfo {
     float m_floatValue;
     float m_floatValue;
     int m_intValue;
     int m_intValue;
 
 
-    MetricInfo()
-    : m_stringValue( )
-    , m_floatValue( 0.0f )
-    , m_intValue( -1 ) {
-        // empty
-    }
+    MetricInfo(): m_stringValue( ), m_floatValue( 0.0f ), m_intValue( -1 ) {}
 };
 };
 
 
 /** @brief  This class is used to implement the OpenGEX importer
 /** @brief  This class is used to implement the OpenGEX importer
@@ -97,7 +92,7 @@ public:
     OpenGEXImporter();
     OpenGEXImporter();
 
 
     /// The class destructor.
     /// The class destructor.
-    ~OpenGEXImporter() override;
+    ~OpenGEXImporter() override = default;
 
 
     /// BaseImporter override.
     /// BaseImporter override.
     bool CanRead( const std::string &file, IOSystem *pIOHandler, bool checkSig ) const override;
     bool CanRead( const std::string &file, IOSystem *pIOHandler, bool checkSig ) const override;
@@ -170,7 +165,7 @@ private:
         std::vector<std::string> m_Names;
         std::vector<std::string> m_Names;
 
 
         RefInfo( aiNode *node, Type type, std::vector<std::string> &names );
         RefInfo( aiNode *node, Type type, std::vector<std::string> &names );
-        ~RefInfo();
+        ~RefInfo() = default;
 
 
         RefInfo( const RefInfo & ) = delete;
         RefInfo( const RefInfo & ) = delete;
         RefInfo &operator = ( const RefInfo & ) = delete;
         RefInfo &operator = ( const RefInfo & ) = delete;

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

@@ -129,10 +129,20 @@ void Q3DImporter::InternReadFile(const std::string &pFile,
     unsigned int numTextures = (unsigned int)stream.GetI4();
     unsigned int numTextures = (unsigned int)stream.GetI4();
 
 
     std::vector<Material> materials;
     std::vector<Material> materials;
-    materials.reserve(numMats);
+    try {
+        materials.reserve(numMats);
+    } catch(const std::bad_alloc&) {
+        ASSIMP_LOG_ERROR("Invalid alloc for materials.");
+        throw DeadlyImportError("Invalid Quick3D-file, material allocation failed.");
+    }
 
 
     std::vector<Mesh> meshes;
     std::vector<Mesh> meshes;
-    meshes.reserve(numMeshes);
+    try {
+        meshes.reserve(numMeshes);
+    } catch(const std::bad_alloc&) {
+        ASSIMP_LOG_ERROR("Invalid alloc for meshes.");
+        throw DeadlyImportError("Invalid Quick3D-file, mesh allocation failed.");
+    }
 
 
     // Allocate the scene root node
     // Allocate the scene root node
     pScene->mRootNode = new aiNode();
     pScene->mRootNode = new aiNode();

+ 19 - 19
code/AssetLib/STL/STLLoader.cpp

@@ -73,7 +73,7 @@ static const aiImporterDesc desc = {
 // 1) 80 byte header
 // 1) 80 byte header
 // 2) 4 byte face count
 // 2) 4 byte face count
 // 3) 50 bytes per face
 // 3) 50 bytes per face
-static bool IsBinarySTL(const char *buffer, unsigned int fileSize) {
+static bool IsBinarySTL(const char *buffer, size_t fileSize) {
     if (fileSize < 84) {
     if (fileSize < 84) {
         return false;
         return false;
     }
     }
@@ -92,7 +92,7 @@ static const char UnicodeBoundary = 127;
 // An ascii STL buffer will begin with "solid NAME", where NAME is optional.
 // An ascii STL buffer will begin with "solid NAME", where NAME is optional.
 // Note: The "solid NAME" check is necessary, but not sufficient, to determine
 // Note: The "solid NAME" check is necessary, but not sufficient, to determine
 // if the buffer is ASCII; a binary header could also begin with "solid NAME".
 // if the buffer is ASCII; a binary header could also begin with "solid NAME".
-static bool IsAsciiSTL(const char *buffer, unsigned int fileSize) {
+static bool IsAsciiSTL(const char *buffer, size_t fileSize) {
     if (IsBinarySTL(buffer, fileSize))
     if (IsBinarySTL(buffer, fileSize))
         return false;
         return false;
 
 
@@ -172,7 +172,7 @@ void STLImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
         throw DeadlyImportError("Failed to open STL file ", pFile, ".");
         throw DeadlyImportError("Failed to open STL file ", pFile, ".");
     }
     }
 
 
-    mFileSize = (unsigned int)file->FileSize();
+    mFileSize = file->FileSize();
 
 
     // allocate storage and copy the contents of the file to a memory buffer
     // allocate storage and copy the contents of the file to a memory buffer
     // (terminate it with zero)
     // (terminate it with zero)
@@ -233,7 +233,7 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
 
 
     // try to guess how many vertices we could have
     // try to guess how many vertices we could have
     // assume we'll need 160 bytes for each face
     // assume we'll need 160 bytes for each face
-    size_t sizeEstimate = std::max(1u, mFileSize / 160u) * 3;
+    size_t sizeEstimate = std::max(1ull, mFileSize / 160ull) * 3ull;
     positionBuffer.reserve(sizeEstimate);
     positionBuffer.reserve(sizeEstimate);
     normalBuffer.reserve(sizeEstimate);
     normalBuffer.reserve(sizeEstimate);
 
 
@@ -284,8 +284,6 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
                     ASSIMP_LOG_WARN("STL: A new facet begins but the old is not yet complete");
                     ASSIMP_LOG_WARN("STL: A new facet begins but the old is not yet complete");
                 }
                 }
                 faceVertexCounter = 0;
                 faceVertexCounter = 0;
-                normalBuffer.push_back(aiVector3D());
-                aiVector3D *vn = &normalBuffer.back();
 
 
                 sz += 6;
                 sz += 6;
                 SkipSpaces(&sz);
                 SkipSpaces(&sz);
@@ -295,15 +293,17 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
                     if (sz[6] == '\0') {
                     if (sz[6] == '\0') {
                         throw DeadlyImportError("STL: unexpected EOF while parsing facet");
                         throw DeadlyImportError("STL: unexpected EOF while parsing facet");
                     }
                     }
+                    aiVector3D vn;
                     sz += 7;
                     sz += 7;
                     SkipSpaces(&sz);
                     SkipSpaces(&sz);
-                    sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->x);
+                    sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.x);
                     SkipSpaces(&sz);
                     SkipSpaces(&sz);
-                    sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->y);
+                    sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.y);
                     SkipSpaces(&sz);
                     SkipSpaces(&sz);
-                    sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->z);
-                    normalBuffer.push_back(*vn);
-                    normalBuffer.push_back(*vn);
+                    sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn.z);
+                    normalBuffer.emplace_back(vn);
+                    normalBuffer.emplace_back(vn);
+                    normalBuffer.emplace_back(vn);
                 }
                 }
             } else if (!strncmp(sz, "vertex", 6) && ::IsSpaceOrNewLine(*(sz + 6))) { // vertex 1.50000 1.50000 0.00000
             } else if (!strncmp(sz, "vertex", 6) && ::IsSpaceOrNewLine(*(sz + 6))) { // vertex 1.50000 1.50000 0.00000
                 if (faceVertexCounter >= 3) {
                 if (faceVertexCounter >= 3) {
@@ -315,7 +315,7 @@ void STLImporter::LoadASCIIFile(aiNode *root) {
                     }
                     }
                     sz += 7;
                     sz += 7;
                     SkipSpaces(&sz);
                     SkipSpaces(&sz);
-                    positionBuffer.push_back(aiVector3D());
+                    positionBuffer.emplace_back();
                     aiVector3D *vn = &positionBuffer.back();
                     aiVector3D *vn = &positionBuffer.back();
                     sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->x);
                     sz = fast_atoreal_move<ai_real>(sz, (ai_real &)vn->x);
                     SkipSpaces(&sz);
                     SkipSpaces(&sz);
@@ -439,7 +439,7 @@ bool STLImporter::LoadBinaryFile() {
     pMesh->mNumFaces = *((uint32_t *)sz);
     pMesh->mNumFaces = *((uint32_t *)sz);
     sz += 4;
     sz += 4;
 
 
-    if (mFileSize < 84 + pMesh->mNumFaces * 50) {
+    if (mFileSize < 84ull + pMesh->mNumFaces * 50ull) {
         throw DeadlyImportError("STL: file is too small to hold all facets");
         throw DeadlyImportError("STL: file is too small to hold all facets");
     }
     }
 
 
@@ -517,13 +517,13 @@ bool STLImporter::LoadBinaryFile() {
             const ai_real invVal((ai_real)1.0 / (ai_real)31.0);
             const ai_real invVal((ai_real)1.0 / (ai_real)31.0);
             if (bIsMaterialise) // this is reversed
             if (bIsMaterialise) // this is reversed
             {
             {
-                clr->r = (color & 0x31u) * invVal;
-                clr->g = ((color & (0x31u << 5)) >> 5u) * invVal;
-                clr->b = ((color & (0x31u << 10)) >> 10u) * invVal;
+                clr->r = (color & 0x1fu) * invVal;
+                clr->g = ((color & (0x1fu << 5)) >> 5u) * invVal;
+                clr->b = ((color & (0x1fu << 10)) >> 10u) * invVal;
             } else {
             } else {
-                clr->b = (color & 0x31u) * invVal;
-                clr->g = ((color & (0x31u << 5)) >> 5u) * invVal;
-                clr->r = ((color & (0x31u << 10)) >> 10u) * invVal;
+                clr->b = (color & 0x1fu) * invVal;
+                clr->g = ((color & (0x1fu << 5)) >> 5u) * invVal;
+                clr->r = ((color & (0x1fu << 10)) >> 10u) * invVal;
             }
             }
             // assign the color to all vertices of the face
             // assign the color to all vertices of the face
             *(clr + 1) = *clr;
             *(clr + 1) = *clr;

+ 1 - 1
code/AssetLib/STL/STLLoader.h

@@ -109,7 +109,7 @@ protected:
     const char* mBuffer;
     const char* mBuffer;
 
 
     /** Size of the file, in bytes */
     /** Size of the file, in bytes */
-    unsigned int mFileSize;
+    size_t mFileSize;
 
 
     /** Output scene */
     /** Output scene */
     aiScene* mScene;
     aiScene* mScene;

+ 47 - 95
code/AssetLib/Step/STEPFile.h

@@ -2,8 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2020, assimp team
-
+Copyright (c) 2006-2022, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 
@@ -59,7 +58,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #    pragma warning(disable : 4127 4456 4245 4512 )
 #    pragma warning(disable : 4127 4456 4245 4512 )
 #endif // _MSC_VER
 #endif // _MSC_VER
 
 
-//
 #if _MSC_VER > 1500 || (defined __GNUC___)
 #if _MSC_VER > 1500 || (defined __GNUC___)
 #    define ASSIMP_STEP_USE_UNORDERED_MULTIMAP
 #    define ASSIMP_STEP_USE_UNORDERED_MULTIMAP
 #else
 #else
@@ -99,13 +97,9 @@ namespace EXPRESS {
 class DataType;
 class DataType;
 class UNSET; /*: public DataType */
 class UNSET; /*: public DataType */
 class ISDERIVED; /*: public DataType */
 class ISDERIVED; /*: public DataType */
-//  class REAL;         /*: public DataType */
 class ENUM; /*: public DataType */
 class ENUM; /*: public DataType */
-//  class STRING;       /*: public DataType */
-//  class INTEGER;      /*: public DataType */
 class ENTITY; /*: public DataType */
 class ENTITY; /*: public DataType */
 class LIST; /*: public DataType */
 class LIST; /*: public DataType */
-//  class SELECT;       /*: public DataType */
 
 
 // a conversion schema is not exactly an EXPRESS schema, rather it
 // a conversion schema is not exactly an EXPRESS schema, rather it
 // is a list of pointers to conversion functions to build up the
 // is a list of pointers to conversion functions to build up the
@@ -127,7 +121,8 @@ namespace STEP {
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 /** Exception class used by the STEP loading & parsing code. It is typically
 /** Exception class used by the STEP loading & parsing code. It is typically
-     *  coupled with a line number. */
+ *  coupled with a line number. 
+ */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct SyntaxError : DeadlyImportError {
 struct SyntaxError : DeadlyImportError {
     enum : uint64_t {
     enum : uint64_t {
@@ -139,8 +134,9 @@ struct SyntaxError : DeadlyImportError {
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 /** Exception class used by the STEP loading & parsing code when a type
 /** Exception class used by the STEP loading & parsing code when a type
-     *  error (i.e. an entity expects a string but receives a bool) occurs.
-     *  It is typically coupled with both an entity id and a line number.*/
+ *  error (i.e. an entity expects a string but receives a bool) occurs.
+ *  It is typically coupled with both an entity id and a line number.
+ */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct TypeError : DeadlyImportError {
 struct TypeError : DeadlyImportError {
     enum : uint64_t {
     enum : uint64_t {
@@ -167,10 +163,8 @@ public:
     typedef std::shared_ptr<const DataType> Out;
     typedef std::shared_ptr<const DataType> Out;
 
 
 public:
 public:
-    virtual ~DataType() {
-    }
+    virtual ~DataType() = default;
 
 
-public:
     template <typename T>
     template <typename T>
     const T &To() const {
     const T &To() const {
         return dynamic_cast<const T &>(*this);
         return dynamic_cast<const T &>(*this);
@@ -206,16 +200,14 @@ public:
 
 
 public:
 public:
     /** parse a variable from a string and set 'inout' to the character
     /** parse a variable from a string and set 'inout' to the character
-             *  behind the last consumed character. An optional schema enables,
-             *  if specified, automatic conversion of custom data types.
-             *
-             *  @throw SyntaxError
-             */
+     *  behind the last consumed character. An optional schema enables,
+     *  if specified, automatic conversion of custom data types.
+     *
+     *  @throw SyntaxError
+     */
     static std::shared_ptr<const EXPRESS::DataType> Parse(const char *&inout,
     static std::shared_ptr<const EXPRESS::DataType> Parse(const char *&inout,
             uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
             uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
             const EXPRESS::ConversionSchema *schema = NULL);
             const EXPRESS::ConversionSchema *schema = NULL);
-
-public:
 };
 };
 
 
 typedef DataType SELECT;
 typedef DataType SELECT;
@@ -238,7 +230,8 @@ private:
 };
 };
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
-/** Shared implementation for some of the primitive data type, i.e. int, float */
+/** Shared implementation for some of the primitive data type, i.e. int, float 
+ */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 template <typename T>
 template <typename T>
 class PrimitiveDataType : public DataType {
 class PrimitiveDataType : public DataType {
@@ -247,7 +240,7 @@ public:
     // expose this data type to the user.
     // expose this data type to the user.
     typedef T Out;
     typedef T Out;
 
 
-    PrimitiveDataType() {}
+    PrimitiveDataType() = default;
     PrimitiveDataType(const T &val) :
     PrimitiveDataType(const T &val) :
             val(val) {}
             val(val) {}
 
 
@@ -280,28 +273,18 @@ class ENUMERATION : public STRING {
 public:
 public:
     ENUMERATION(const std::string &val) :
     ENUMERATION(const std::string &val) :
             STRING(val) {}
             STRING(val) {}
-
-private:
 };
 };
 
 
 typedef ENUMERATION BOOLEAN;
 typedef ENUMERATION BOOLEAN;
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
-/** This is just a reference to an entity/object somewhere else */
+/** This is just a reference to an entity/object somewhere else 
+ */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 class ENTITY : public PrimitiveDataType<uint64_t> {
 class ENTITY : public PrimitiveDataType<uint64_t> {
 public:
 public:
-    ENTITY(uint64_t val) :
-            PrimitiveDataType<uint64_t>(val) {
-        ai_assert(val != 0);
-    }
-
-    ENTITY() :
-            PrimitiveDataType<uint64_t>(TypeError::ENTITY_NOT_SPECIFIED) {
-        // empty
-    }
-
-private:
+    ENTITY(uint64_t val) : PrimitiveDataType<uint64_t>(val) {}
+    ENTITY() : PrimitiveDataType<uint64_t>(TypeError::ENTITY_NOT_SPECIFIED) {}
 };
 };
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
@@ -319,7 +302,8 @@ public:
     }
     }
 
 
 public:
 public:
-    /** @see DaraType::Parse */
+    /** @see DaraType::Parse 
+     */
     static std::shared_ptr<const EXPRESS::LIST> Parse(const char *&inout,
     static std::shared_ptr<const EXPRESS::LIST> Parse(const char *&inout,
             uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
             uint64_t line = SyntaxError::LINE_NOT_SPECIFIED,
             const EXPRESS::ConversionSchema *schema = NULL);
             const EXPRESS::ConversionSchema *schema = NULL);
@@ -331,29 +315,20 @@ private:
 
 
 class BINARY : public PrimitiveDataType<uint32_t> {
 class BINARY : public PrimitiveDataType<uint32_t> {
 public:
 public:
-    BINARY(uint32_t val) :
-            PrimitiveDataType<uint32_t>(val) {
-        // empty
-    }
-
-    BINARY() :
-            PrimitiveDataType<uint32_t>(TypeError::ENTITY_NOT_SPECIFIED_32) {
-        // empty
-    }
+    BINARY(uint32_t val) : PrimitiveDataType<uint32_t>(val) {}
+    BINARY() : PrimitiveDataType<uint32_t>(TypeError::ENTITY_NOT_SPECIFIED_32) {}
 };
 };
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 /* Not exactly a full EXPRESS schema but rather a list of conversion functions
 /* Not exactly a full EXPRESS schema but rather a list of conversion functions
-         * to extract valid C++ objects out of a STEP file. Those conversion functions
-         * may, however, perform further schema validations. */
+ * to extract valid C++ objects out of a STEP file. Those conversion functions
+ * may, however, perform further schema validations. 
+ */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 class ConversionSchema {
 class ConversionSchema {
 public:
 public:
     struct SchemaEntry {
     struct SchemaEntry {
-        SchemaEntry(const char *name, ConvertObjectProc func) :
-                mName(name), mFunc(func) {
-            // empty
-        }
+        SchemaEntry(const char *name, ConvertObjectProc func) : mName(name), mFunc(func) {}
 
 
         const char *mName;
         const char *mName;
         ConvertObjectProc mFunc;
         ConvertObjectProc mFunc;
@@ -366,8 +341,7 @@ public:
         *this = schemas;
         *this = schemas;
     }
     }
 
 
-    ConversionSchema() {
-    }
+    ConversionSchema() = default;
 
 
     ConvertObjectProc GetConverterProc(const std::string &name) const {
     ConvertObjectProc GetConverterProc(const std::string &name) const {
         ConverterMap::const_iterator it = converters.find(name);
         ConverterMap::const_iterator it = converters.find(name);
@@ -399,8 +373,9 @@ private:
 
 
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
 /** Bundle all the relevant info from a STEP header, parts of which may later
 /** Bundle all the relevant info from a STEP header, parts of which may later
-     *  be plainly dumped to the logfile, whereas others may help the caller pick an
-     *  appropriate loading strategy.*/
+ *  be plainly dumped to the logfile, whereas others may help the caller pick an
+ *  appropriate loading strategy.
+ */
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
 struct HeaderInfo {
 struct HeaderInfo {
     std::string timestamp;
     std::string timestamp;
@@ -409,18 +384,14 @@ struct HeaderInfo {
 };
 };
 
 
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
-/** Base class for all concrete object instances */
+/** Base class for all concrete object instances 
+ */
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
 class Object {
 class Object {
 public:
 public:
-    Object(const char *classname = "unknown") :
-            id(0), classname(classname) {
-        // empty
-    }
+    Object(const char *classname = "unknown") : id(0), classname(classname) {}
 
 
-    virtual ~Object() {
-        // empty
-    }
+    virtual ~Object() = default;
 
 
     // utilities to simplify casting to concrete types
     // utilities to simplify casting to concrete types
     template <typename T>
     template <typename T>
@@ -469,26 +440,15 @@ size_t GenericFill(const STEP::DB &db, const EXPRESS::LIST &params, T *in);
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
 template <typename TDerived, size_t arg_count>
 template <typename TDerived, size_t arg_count>
 struct ObjectHelper : virtual Object {
 struct ObjectHelper : virtual Object {
-    ObjectHelper() :
-            aux_is_derived(0) {
-        // empty
-    }
+    ObjectHelper() : aux_is_derived(0) {}
 
 
     static Object *Construct(const STEP::DB &db, const EXPRESS::LIST &params) {
     static Object *Construct(const STEP::DB &db, const EXPRESS::LIST &params) {
         // make sure we don't leak if Fill() throws an exception
         // make sure we don't leak if Fill() throws an exception
         std::unique_ptr<TDerived> impl(new TDerived());
         std::unique_ptr<TDerived> impl(new TDerived());
 
 
         // GenericFill<T> is undefined so we need to have a specialization
         // GenericFill<T> is undefined so we need to have a specialization
-        const size_t num_args = GenericFill<TDerived>(db, params, &*impl);
-        (void)num_args;
-
-        // the following check is commented because it will always trigger if
-        // parts of the entities are generated with dummy wrapper code.
-        // This is currently done to reduce the size of the loader
-        // code.
-        //if (num_args != params.GetSize() && impl->GetClassName() != "NotImplemented") {
-        //  DefaultLogger::get()->debug("STEP: not all parameters consumed");
-        //}
+        static_cast<void>(GenericFill<TDerived>(db, params, &*impl));
+
         return impl.release();
         return impl.release();
     }
     }
 
 
@@ -502,15 +462,9 @@ struct ObjectHelper : virtual Object {
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
 template <typename T>
 template <typename T>
 struct Maybe {
 struct Maybe {
-    Maybe() :
-            have() {
-        // empty
-    }
+    Maybe() : have() {}
 
 
-    explicit Maybe(const T &ptr) :
-            ptr(ptr), have(true) {
-        // empty
-    }
+    explicit Maybe(const T &ptr) : ptr(ptr), have(true) {}
 
 
     void flag_invalid() {
     void flag_invalid() {
         have = false;
         have = false;
@@ -557,7 +511,8 @@ private:
 
 
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
 /** A LazyObject is created when needed. Before this happens, we just keep
 /** A LazyObject is created when needed. Before this happens, we just keep
-       the text line that contains the object definition. */
+ *  the text line that contains the object definition. 
+ */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 class LazyObject {
 class LazyObject {
     friend class DB;
     friend class DB;
@@ -649,10 +604,7 @@ inline bool operator==(const std::pair<uint64_t, std::shared_ptr<LazyObject>> &l
 template <typename T>
 template <typename T>
 struct Lazy {
 struct Lazy {
     typedef Lazy Out;
     typedef Lazy Out;
-    Lazy(const LazyObject *obj = nullptr) :
-            obj(obj) {
-        // empty
-    }
+    Lazy(const LazyObject *obj = nullptr) : obj(obj) {}
 
 
     operator const T *() const {
     operator const T *() const {
         return obj->ToPtr<T>();
         return obj->ToPtr<T>();
@@ -785,8 +737,9 @@ inline void GenericConvert(ListOf<T1, N1, N2> &a, const std::shared_ptr<const EX
 
 
 // ------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------
 /** Lightweight manager class that holds the map of all objects in a
 /** Lightweight manager class that holds the map of all objects in a
-     *  STEP file. DB's are exclusively maintained by the functions in
-     *  STEPFileReader.h*/
+ *  STEP file. DB's are exclusively maintained by the functions in
+ *  STEPFileReader.h
+ */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 class DB {
 class DB {
     friend DB *ReadFileHeader(std::shared_ptr<IOStream> stream);
     friend DB *ReadFileHeader(std::shared_ptr<IOStream> stream);
@@ -873,7 +826,7 @@ public:
         if (it != objects_bytype.end() && (*it).second.size()) {
         if (it != objects_bytype.end() && (*it).second.size()) {
             return *(*it).second.begin();
             return *(*it).second.begin();
         }
         }
-        return NULL;
+        return nullptr;
     }
     }
 
 
     // same, but raise an exception if the object doesn't exist and return a reference
     // same, but raise an exception if the object doesn't exist and return a reference
@@ -965,7 +918,6 @@ private:
 #endif // _MSC_VER
 #endif // _MSC_VER
 
 
 } // namespace STEP
 } // namespace STEP
-
 } // namespace Assimp
 } // namespace Assimp
 
 
 #endif // INCLUDED_AI_STEPFILE_H
 #endif // INCLUDED_AI_STEPFILE_H

+ 1 - 1
code/AssetLib/X3D/X3DImporter.cpp

@@ -333,7 +333,7 @@ void X3DImporter::readHead(XmlNode &node) {
     }
     }
     mScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metaArray.size()));
     mScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metaArray.size()));
     unsigned int i = 0;
     unsigned int i = 0;
-    for (auto currentMeta : metaArray) {
+    for (const auto& currentMeta : metaArray) {
         mScene->mMetaData->Set(i, currentMeta.name, aiString(currentMeta.value));
         mScene->mMetaData->Set(i, currentMeta.name, aiString(currentMeta.value));
         ++i;
         ++i;
     }
     }

+ 5 - 5
code/AssetLib/glTF/glTFAsset.inl

@@ -53,9 +53,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endif
 #endif
 
 
 using namespace Assimp;
 using namespace Assimp;
-using namespace glTFCommon;
 
 
 namespace glTF {
 namespace glTF {
+using namespace glTFCommon;
 
 
 #if _MSC_VER
 #if _MSC_VER
 #pragma warning(push)
 #pragma warning(push)
@@ -891,12 +891,12 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
     auto get_buf_offset = [](Ref<Accessor> &pAccessor) -> size_t { return pAccessor->byteOffset + pAccessor->bufferView->byteOffset; };
     auto get_buf_offset = [](Ref<Accessor> &pAccessor) -> size_t { return pAccessor->byteOffset + pAccessor->bufferView->byteOffset; };
 
 
     // Indices
     // Indices
-    ifs.SetCoordIndex((IndicesType *const)(decoded_data + get_buf_offset(primitives[0].indices)));
+    ifs.SetCoordIndex((IndicesType *)(decoded_data + get_buf_offset(primitives[0].indices)));
     // Coordinates
     // Coordinates
-    ifs.SetCoord((o3dgc::Real *const)(decoded_data + get_buf_offset(primitives[0].attributes.position[0])));
+    ifs.SetCoord((o3dgc::Real *)(decoded_data + get_buf_offset(primitives[0].attributes.position[0])));
     // Normals
     // Normals
     if (size_normal) {
     if (size_normal) {
-        ifs.SetNormal((o3dgc::Real *const)(decoded_data + get_buf_offset(primitives[0].attributes.normal[0])));
+        ifs.SetNormal((o3dgc::Real *)(decoded_data + get_buf_offset(primitives[0].attributes.normal[0])));
     }
     }
 
 
     for (size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) {
     for (size_t idx = 0, idx_end = size_floatattr.size(), idx_texcoord = 0; idx < idx_end; idx++) {
@@ -904,7 +904,7 @@ inline void Mesh::Decode_O3DGC(const SCompression_Open3DGC &pCompression_Open3DG
         case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
         case o3dgc::O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD:
             if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
             if (idx_texcoord < primitives[0].attributes.texcoord.size()) {
                 // See above about absent attributes.
                 // See above about absent attributes.
-                ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real *const)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
+                ifs.SetFloatAttribute(static_cast<unsigned long>(idx), (o3dgc::Real *)(decoded_data + get_buf_offset(primitives[0].attributes.texcoord[idx])));
                 idx_texcoord++;
                 idx_texcoord++;
             }
             }
 
 

+ 2 - 0
code/AssetLib/glTF2/glTF2Asset.h

@@ -374,6 +374,8 @@ struct CustomExtension {
             mValues(other.mValues) {
             mValues(other.mValues) {
         // empty
         // empty
     }
     }
+
+    CustomExtension& operator=(const CustomExtension&) = default;
 };
 };
 
 
 //! Base class for all glTF top-level objects
 //! Base class for all glTF top-level objects

+ 13 - 1
code/AssetLib/glTF2/glTF2Asset.inl

@@ -82,9 +82,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // clang-format on
 // clang-format on
 
 
 using namespace Assimp;
 using namespace Assimp;
-using namespace glTFCommon;
 
 
 namespace glTF2 {
 namespace glTF2 {
+using glTFCommon::FindStringInContext;
+using glTFCommon::FindNumberInContext;
+using glTFCommon::FindUIntInContext;
+using glTFCommon::FindArrayInContext;
+using glTFCommon::FindObjectInContext;
+using glTFCommon::FindExtensionInContext;
+using glTFCommon::MemberOrDefault;
+using glTFCommon::ReadMember;
+using glTFCommon::FindMember;
+using glTFCommon::FindObject;
+using glTFCommon::FindUInt;
+using glTFCommon::FindArray;
+using glTFCommon::FindArray;
 
 
 namespace {
 namespace {
 
 

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

@@ -683,7 +683,7 @@ bool glTF2Exporter::GetMatSheen(const aiMaterial &mat, glTF2::MaterialSheen &she
     }
     }
 
 
     // Default Sheen color factor {0,0,0} disables Sheen, so do not export
     // Default Sheen color factor {0,0,0} disables Sheen, so do not export
-    if (sheen.sheenColorFactor == defaultSheenFactor) {
+    if (sheen.sheenColorFactor[0] == defaultSheenFactor[0] && sheen.sheenColorFactor[1] == defaultSheenFactor[1] && sheen.sheenColorFactor[2] == defaultSheenFactor[2]) {
         return false;
         return false;
     }
     }
 
 
@@ -908,7 +908,7 @@ Ref<Node> FindSkeletonRootJoint(Ref<Skin> &skinRef) {
     do {
     do {
         startNodeRef = parentNodeRef;
         startNodeRef = parentNodeRef;
         parentNodeRef = startNodeRef->parent;
         parentNodeRef = startNodeRef->parent;
-    } while (!parentNodeRef->jointName.empty());
+    } while (parentNodeRef && !parentNodeRef->jointName.empty());
 
 
     return parentNodeRef;
     return parentNodeRef;
 }
 }

+ 23 - 20
code/AssetLib/glTF2/glTF2Importer.cpp

@@ -284,7 +284,7 @@ static aiMaterial *ImportMaterial(std::vector<int> &embeddedTexIdxs, Asset &r, M
         aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE);
         aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE);
         aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF);
         aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF);
 
 
-        //pbrSpecularGlossiness
+        // pbrSpecularGlossiness
         if (mat.pbrSpecularGlossiness.isPresent) {
         if (mat.pbrSpecularGlossiness.isPresent) {
             PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
             PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value;
 
 
@@ -606,7 +606,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
                         }
                         }
                     }
                     }
                     if (needTangents) {
                     if (needTangents) {
-                        if (target.tangent[0]->count != aim->mNumVertices) {
+                        if (!aiAnimMesh.HasNormals()) {
+                            // prevent nullptr access to aiAnimMesh.mNormals below when no normals are available
+                            ASSIMP_LOG_WARN("Bitangents of target ", i, " in mesh \"", mesh.name, "\" can't be computed, because mesh has no normals.");
+                        } else if (target.tangent[0]->count != aim->mNumVertices) {
                             ASSIMP_LOG_WARN("Tangents of target ", i, " in mesh \"", mesh.name, "\" does not match the vertex count");
                             ASSIMP_LOG_WARN("Tangents of target ", i, " in mesh \"", mesh.name, "\" does not match the vertex count");
                         } else {
                         } else {
                             Tangent *tangent = nullptr;
                             Tangent *tangent = nullptr;
@@ -698,12 +701,12 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
                     nFaces = count - 2;
                     nFaces = count - 2;
                     facePtr = faces = new aiFace[nFaces];
                     facePtr = faces = new aiFace[nFaces];
                     for (unsigned int i = 0; i < nFaces; ++i) {
                     for (unsigned int i = 0; i < nFaces; ++i) {
-                        //The ordering is to ensure that the triangles are all drawn with the same orientation
+                        // The ordering is to ensure that the triangles are all drawn with the same orientation
                         if ((i + 1) % 2 == 0) {
                         if ((i + 1) % 2 == 0) {
-                            //For even n, vertices n + 1, n, and n + 2 define triangle n
+                            // For even n, vertices n + 1, n, and n + 2 define triangle n
                             SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
                             SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
                         } else {
                         } else {
-                            //For odd n, vertices n, n+1, and n+2 define triangle n
+                            // For odd n, vertices n, n+1, and n+2 define triangle n
                             SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
                             SetFaceAndAdvance3(facePtr, aim->mNumVertices, data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
                         }
                         }
                     }
                     }
@@ -776,12 +779,12 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
                     nFaces = count - 2;
                     nFaces = count - 2;
                     facePtr = faces = new aiFace[nFaces];
                     facePtr = faces = new aiFace[nFaces];
                     for (unsigned int i = 0; i < nFaces; ++i) {
                     for (unsigned int i = 0; i < nFaces; ++i) {
-                        //The ordering is to ensure that the triangles are all drawn with the same orientation
+                        // The ordering is to ensure that the triangles are all drawn with the same orientation
                         if ((i + 1) % 2 == 0) {
                         if ((i + 1) % 2 == 0) {
-                            //For even n, vertices n + 1, n, and n + 2 define triangle n
+                            // For even n, vertices n + 1, n, and n + 2 define triangle n
                             SetFaceAndAdvance3(facePtr, aim->mNumVertices, i + 1, i, i + 2);
                             SetFaceAndAdvance3(facePtr, aim->mNumVertices, i + 1, i, i + 2);
                         } else {
                         } else {
-                            //For odd n, vertices n, n+1, and n+2 define triangle n
+                            // For odd n, vertices n, n+1, and n+2 define triangle n
                             SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2);
                             SetFaceAndAdvance3(facePtr, aim->mNumVertices, i, i + 1, i + 2);
                         }
                         }
                     }
                     }
@@ -904,14 +907,14 @@ void glTF2Importer::ImportLights(glTF2::Asset &r) {
             ail->mAttenuationLinear = 0.0;
             ail->mAttenuationLinear = 0.0;
             ail->mAttenuationQuadratic = 0.0;
             ail->mAttenuationQuadratic = 0.0;
         } else {
         } else {
-            //in PBR attenuation is calculated using inverse square law which can be expressed
-            //using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters
-            //this is correct equation for the case when range (see
-            //https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual)
-            //is not present. When range is not present it is assumed that it is infinite and so numerator is 1.
-            //When range is present then numerator might be any value in range [0,1] and then assimps equation
-            //will not suffice. In this case range is added into metadata in ImportNode function
-            //and its up to implementation to read it when it wants to
+            // in PBR attenuation is calculated using inverse square law which can be expressed
+            // using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters
+            // this is correct equation for the case when range (see
+            // https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual)
+            // is not present. When range is not present it is assumed that it is infinite and so numerator is 1.
+            // When range is present then numerator might be any value in range [0,1] and then assimps equation
+            // will not suffice. In this case range is added into metadata in ImportNode function
+            // and its up to implementation to read it when it wants to
             ail->mAttenuationConstant = 0.0;
             ail->mAttenuationConstant = 0.0;
             ail->mAttenuationLinear = 0.0;
             ail->mAttenuationLinear = 0.0;
             ail->mAttenuationQuadratic = 1.0;
             ail->mAttenuationQuadratic = 1.0;
@@ -1178,8 +1181,8 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
         if (node.light) {
         if (node.light) {
             pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
             pScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
 
 
-            //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
-            //it is added to meta data of parent node, because there is no other place to put it
+            // range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
+            // it is added to meta data of parent node, because there is no other place to put it
             if (node.light->range.isPresent) {
             if (node.light->range.isPresent) {
                 if (!ainode->mMetaData) {
                 if (!ainode->mMetaData) {
                     ainode->mMetaData = aiMetadata::Alloc(1);
                     ainode->mMetaData = aiMetadata::Alloc(1);
@@ -1573,9 +1576,9 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) {
             if (ext) {
             if (ext) {
                 if (strcmp(ext, "jpeg") == 0) {
                 if (strcmp(ext, "jpeg") == 0) {
                     ext = "jpg";
                     ext = "jpg";
-                } else if (strcmp(ext, "ktx2") == 0) { //basisu: ktx remains
+                } else if (strcmp(ext, "ktx2") == 0) { // basisu: ktx remains
                     ext = "kx2";
                     ext = "kx2";
-                } else if (strcmp(ext, "basis") == 0) { //basisu
+                } else if (strcmp(ext, "basis") == 0) { // basisu
                     ext = "bu";
                     ext = "bu";
                 }
                 }
 
 

+ 30 - 15
code/CMakeLists.txt

@@ -150,7 +150,7 @@ SET( Core_SRCS
   Common/Assimp.cpp
   Common/Assimp.cpp
 )
 )
 
 
-IF(MSVC)
+IF(MSVC OR (MINGW AND BUILD_SHARED_LIBS))
   list(APPEND Core_SRCS "res/assimp.rc")
   list(APPEND Core_SRCS "res/assimp.rc")
 ENDIF()
 ENDIF()
 
 
@@ -167,6 +167,7 @@ SET( Logging_SRCS
 SOURCE_GROUP(Logging FILES ${Logging_SRCS})
 SOURCE_GROUP(Logging FILES ${Logging_SRCS})
 
 
 SET( Common_SRCS
 SET( Common_SRCS
+  Common/StbCommon.h
   Common/Compression.cpp
   Common/Compression.cpp
   Common/Compression.h
   Common/Compression.h
   Common/BaseImporter.cpp
   Common/BaseImporter.cpp
@@ -182,6 +183,7 @@ SET( Common_SRCS
   Common/DefaultIOSystem.cpp
   Common/DefaultIOSystem.cpp
   Common/ZipArchiveIOSystem.cpp
   Common/ZipArchiveIOSystem.cpp
   Common/PolyTools.h
   Common/PolyTools.h
+  Common/Maybe.h
   Common/Importer.cpp
   Common/Importer.cpp
   Common/IFF.h
   Common/IFF.h
   Common/SGSpatialSort.cpp
   Common/SGSpatialSort.cpp
@@ -1053,7 +1055,9 @@ ENDIF()
 # Check dependencies for glTF importer with Open3DGC-compression.
 # Check dependencies for glTF importer with Open3DGC-compression.
 # RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file
 # RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file
 # has implementation for different platforms: WIN32, __MACH__ and other ("else" block).
 # has implementation for different platforms: WIN32, __MACH__ and other ("else" block).
-FIND_PACKAGE(RT QUIET)
+IF (NOT WIN32)
+  FIND_PACKAGE(RT QUIET)
+ENDIF ()
 IF (NOT ASSIMP_HUNTER_ENABLED AND (RT_FOUND OR WIN32))
 IF (NOT ASSIMP_HUNTER_ENABLED AND (RT_FOUND OR WIN32))
   SET( ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC 1 )
   SET( ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC 1 )
   ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC=1 )
   ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC=1 )
@@ -1096,8 +1100,6 @@ if(MSVC10)
   endif()
   endif()
 endif()
 endif()
 
 
-ADD_DEFINITIONS( -DASSIMP_BUILD_DLL_EXPORT )
-
 IF( MSVC OR "${CMAKE_CXX_SIMULATE_ID}" MATCHES "MSVC") # clang with MSVC ABI
 IF( MSVC OR "${CMAKE_CXX_SIMULATE_ID}" MATCHES "MSVC") # clang with MSVC ABI
   ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
   ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS )
   ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
   ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS )
@@ -1174,13 +1176,22 @@ ENDIF()
 ADD_LIBRARY( assimp ${assimp_src} )
 ADD_LIBRARY( assimp ${assimp_src} )
 ADD_LIBRARY(assimp::assimp ALIAS assimp)
 ADD_LIBRARY(assimp::assimp ALIAS assimp)
 
 
+# Add or remove dllexport tags depending on the library type.
+IF (BUILD_SHARED_LIBS)
+  TARGET_COMPILE_DEFINITIONS(assimp PRIVATE ASSIMP_BUILD_DLL_EXPORT)
+ELSE ()
+  TARGET_COMPILE_DEFINITIONS(assimp PRIVATE OPENDDL_STATIC_LIBARY)
+ENDIF ()
+
 TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
 TARGET_USE_COMMON_OUTPUT_DIRECTORY(assimp)
 
 
-# enable warnings as errors ########################################
-IF (MSVC)
-  TARGET_COMPILE_OPTIONS(assimp PRIVATE /WX)
-ELSE()
-  TARGET_COMPILE_OPTIONS(assimp PRIVATE -Werror)
+IF (ASSIMP_WARNINGS_AS_ERRORS)
+  MESSAGE(STATUS "Treating all warnings as errors (for assimp library only)")
+  IF (MSVC)
+    TARGET_COMPILE_OPTIONS(assimp PRIVATE /W4 /WX)
+  ELSE()
+    TARGET_COMPILE_OPTIONS(assimp PRIVATE -Wall -Werror)
+  ENDIF()
 ENDIF()
 ENDIF()
 
 
 # adds C_FLAGS required to compile zip.c on old GCC 4.x compiler
 # adds C_FLAGS required to compile zip.c on old GCC 4.x compiler
@@ -1263,6 +1274,16 @@ if( MSVC )
   set(LIBRARY_SUFFIX "${ASSIMP_LIBRARY_SUFFIX}-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library")
   set(LIBRARY_SUFFIX "${ASSIMP_LIBRARY_SUFFIX}-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library")
 endif()
 endif()
 
 
+if (MINGW)
+  set(LIBRARY_SUFFIX "-${ASSIMP_SOVERSION}" CACHE STRING "the suffix for the assimp MinGW shared library")
+  SET_TARGET_PROPERTIES( assimp PROPERTIES
+    ARCHIVE_OUTPUT_NAME assimp
+  )
+  if (NOT BUILD_SHARED_LIBS)
+    TARGET_LINK_LIBRARIES ( assimp -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lwinpthread ) # winpthread is for libminizip.
+  endif ()
+endif()
+
 if (${CMAKE_SYSTEM_NAME} MATCHES "WindowsStore")
 if (${CMAKE_SYSTEM_NAME} MATCHES "WindowsStore")
     target_compile_definitions(assimp PUBLIC WindowsStore)
     target_compile_definitions(assimp PUBLIC WindowsStore)
     TARGET_LINK_LIBRARIES(assimp advapi32)
     TARGET_LINK_LIBRARIES(assimp advapi32)
@@ -1274,12 +1295,6 @@ SET_TARGET_PROPERTIES( assimp PROPERTIES
   OUTPUT_NAME assimp${LIBRARY_SUFFIX}
   OUTPUT_NAME assimp${LIBRARY_SUFFIX}
 )
 )
 
 
-if (WIN32 AND CMAKE_COMPILER_IS_GNUCXX AND BUILD_SHARED_LIBS)
-  set_target_properties(assimp PROPERTIES
-    SUFFIX "-${ASSIMP_SOVERSION}${CMAKE_SHARED_LIBRARY_SUFFIX}"
-  )
-endif()
-
 if (APPLE)
 if (APPLE)
   if (ASSIMP_BUILD_FRAMEWORK)
   if (ASSIMP_BUILD_FRAMEWORK)
     SET_TARGET_PROPERTIES( assimp PROPERTIES
     SET_TARGET_PROPERTIES( assimp PROPERTIES

+ 6 - 13
code/Common/Assimp.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,
@@ -1282,18 +1280,13 @@ ASSIMP_API void aiQuaternionInterpolate(
 #   define STBI_ONLY_PNG
 #   define STBI_ONLY_PNG
 #endif
 #endif
 
 
+// Ensure all symbols are linked correctly
 #if ASSIMP_NEEDS_STB_IMAGE
 #if ASSIMP_NEEDS_STB_IMAGE
-
-#   if _MSC_VER // "unreferenced function has been removed" (SSE2 detection routine in x64 builds)
-#       pragma warning(push)
-#       pragma warning(disable: 4505)
+    // Share stb_image's PNG loader with other importers/exporters instead of bringing our own copy.
+#   define STBI_ONLY_PNG
+#   ifdef ASSIMP_USE_STB_IMAGE_STATIC
+#       define STB_IMAGE_STATIC
 #   endif
 #   endif
-
 #   define STB_IMAGE_IMPLEMENTATION
 #   define STB_IMAGE_IMPLEMENTATION
-#   include "stb/stb_image.h"
-
-#   if _MSC_VER
-#       pragma warning(pop)
-#   endif
-
+#   include "Common/StbCommon.h"
 #endif
 #endif

+ 10 - 3
code/Common/DefaultIOStream.cpp

@@ -63,7 +63,7 @@ inline int select_fseek(FILE *file, int64_t offset, int origin) {
 
 
 
 
 
 
-#if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601)
+#if defined _WIN32 && (!defined __GNUC__ || !defined __CLANG__ && __MSVCRT_VERSION__ >= 0x0601)
 template <>
 template <>
 inline size_t select_ftell<8>(FILE *file) {
 inline size_t select_ftell<8>(FILE *file) {
     return (size_t)::_ftelli64(file);
     return (size_t)::_ftelli64(file);
@@ -74,7 +74,7 @@ inline int select_fseek<8>(FILE *file, int64_t offset, int origin) {
     return ::_fseeki64(file, offset, origin);
     return ::_fseeki64(file, offset, origin);
 }
 }
 
 
-#endif // #if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601)
+#endif
 
 
 } // namespace
 } // namespace
 
 
@@ -149,13 +149,20 @@ size_t DefaultIOStream::FileSize() const {
         //
         //
         // See here for details:
         // See here for details:
         // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
         // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
-#if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601)
+#if defined _WIN32 && (!defined __GNUC__ || !defined __CLANG__ && __MSVCRT_VERSION__ >= 0x0601)
         struct __stat64 fileStat;
         struct __stat64 fileStat;
         //using fileno + fstat avoids having to handle the filename
         //using fileno + fstat avoids having to handle the filename
         int err = _fstat64(_fileno(mFile), &fileStat);
         int err = _fstat64(_fileno(mFile), &fileStat);
         if (0 != err)
         if (0 != err)
             return 0;
             return 0;
         mCachedSize = (size_t)(fileStat.st_size);
         mCachedSize = (size_t)(fileStat.st_size);
+#elif defined _WIN32
+        struct _stat32 fileStat;
+        //using fileno + fstat avoids having to handle the filename
+        int err = _fstat32(_fileno(mFile), &fileStat);
+        if (0 != err)
+            return 0;
+        mCachedSize = (size_t)(fileStat.st_size);
 #elif defined __GNUC__ || defined __APPLE__ || defined __MACH__ || defined __FreeBSD__
 #elif defined __GNUC__ || defined __APPLE__ || defined __MACH__ || defined __FreeBSD__
         struct stat fileStat;
         struct stat fileStat;
         int err = stat(mFilename.c_str(), &fileStat);
         int err = stat(mFilename.c_str(), &fileStat);

+ 2 - 2
code/Common/FileSystemFilter.h

@@ -300,10 +300,10 @@ private:
 
 
         const char separator = getOsSeparator();
         const char separator = getOsSeparator();
         for (it = in.begin(); it != in.end(); ++it) {
         for (it = in.begin(); it != in.end(); ++it) {
-            int remaining = std::distance(in.end(), it);
+            const size_t remaining = std::distance(in.end(), it);
             // Exclude :// and \\, which remain untouched.
             // Exclude :// and \\, which remain untouched.
             // https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
             // https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
-            if (remaining >= 3 && !strncmp(&*it, "://", 3 )) {
+            if (remaining >= 3u && !strncmp(&*it, "://", 3 )) {
                 it += 3;
                 it += 3;
                 continue;
                 continue;
             }
             }

+ 29 - 0
code/Common/Maybe.h

@@ -0,0 +1,29 @@
+#pragma once
+#include <assimp/ai_assert.h>
+
+template <typename T>
+struct Maybe {
+private:
+    T _val;
+    bool _valid;
+
+public:
+    Maybe() :
+            _valid(false) {}
+
+    explicit Maybe(const T &val) :
+            _val(val), _valid(true) {
+    }
+
+    operator bool() const {
+        return _valid;
+    }
+
+    const T &Get() const {
+        ai_assert(_valid);
+        return _val;
+    }
+
+private:
+    Maybe &operator&() = delete;
+};

+ 29 - 26
code/Common/ScenePreprocessor.cpp

@@ -105,36 +105,39 @@ void ScenePreprocessor::ProcessMesh(aiMesh *mesh) {
     for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
     for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
         if (!mesh->mTextureCoords[i]) {
         if (!mesh->mTextureCoords[i]) {
             mesh->mNumUVComponents[i] = 0;
             mesh->mNumUVComponents[i] = 0;
-        } else {
-            if (!mesh->mNumUVComponents[i]) {
-                mesh->mNumUVComponents[i] = 2;
-            }
+            continue;
+        } 
 
 
-            aiVector3D *p = mesh->mTextureCoords[i], *end = p + mesh->mNumVertices;
+        if (!mesh->mNumUVComponents[i]) {
+            mesh->mNumUVComponents[i] = 2;
+        }
 
 
-            // Ensure unused components are zeroed. This will make 1D texture channels work
-            // as if they were 2D channels .. just in case an application doesn't handle
-            // this case
-            if (2 == mesh->mNumUVComponents[i]) {
-                for (; p != end; ++p) {
-                    p->z = 0.f;
-                }
-            } else if (1 == mesh->mNumUVComponents[i]) {
-                for (; p != end; ++p) {
-                    p->z = p->y = 0.f;
-                }
-            } else if (3 == mesh->mNumUVComponents[i]) {
-                // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
-                for (; p != end; ++p) {
-                    if (p->z != 0) {
-                        break;
-                    }
-                }
-                if (p == end) {
-                    ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
-                    mesh->mNumUVComponents[i] = 2;
+        aiVector3D *p = mesh->mTextureCoords[i], *end = p + mesh->mNumVertices;
+
+        // Ensure unused components are zeroed. This will make 1D texture channels work
+        // as if they were 2D channels .. just in case an application doesn't handle
+        // this case
+        if (2 == mesh->mNumUVComponents[i]) {
+            size_t num = 0;
+            for (; p != end; ++p) {
+                p->z = 0.f;
+                num++;
+            }
+        } else if (1 == mesh->mNumUVComponents[i]) {
+            for (; p != end; ++p) {
+                p->z = p->y = 0.f;
+            }
+        } else if (3 == mesh->mNumUVComponents[i]) {
+            // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element
+            for (; p != end; ++p) {
+                if (p->z != 0) {
+                    break;
                 }
                 }
             }
             }
+            if (p == end) {
+                ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D.");
+                mesh->mNumUVComponents[i] = 2;
+            }
         }
         }
     }
     }
 
 

+ 8 - 6
code/Common/SkeletonMeshBuilder.cpp

@@ -4,7 +4,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,
@@ -97,13 +96,14 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
             const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation;
             const aiMatrix4x4 &childTransform = pNode->mChildren[a]->mTransformation;
             aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
             aiVector3D childpos(childTransform.a4, childTransform.b4, childTransform.c4);
             ai_real distanceToChild = childpos.Length();
             ai_real distanceToChild = childpos.Length();
-            if (distanceToChild < 0.0001)
+            if (distanceToChild < ai_epsilon) {
                 continue;
                 continue;
+            }
             aiVector3D up = aiVector3D(childpos).Normalize();
             aiVector3D up = aiVector3D(childpos).Normalize();
-
             aiVector3D orth(1.0, 0.0, 0.0);
             aiVector3D orth(1.0, 0.0, 0.0);
-            if (std::fabs(orth * up) > 0.99)
+            if (std::fabs(orth * up) > 0.99) {
                 orth.Set(0.0, 1.0, 0.0);
                 orth.Set(0.0, 1.0, 0.0);
+            }
 
 
             aiVector3D front = (up ^ orth).Normalize();
             aiVector3D front = (up ^ orth).Normalize();
             aiVector3D side = (front ^ up).Normalize();
             aiVector3D side = (front ^ up).Normalize();
@@ -183,8 +183,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
         // add all the vertices to the bone's influences
         // add all the vertices to the bone's influences
         bone->mNumWeights = numVertices;
         bone->mNumWeights = numVertices;
         bone->mWeights = new aiVertexWeight[numVertices];
         bone->mWeights = new aiVertexWeight[numVertices];
-        for (unsigned int a = 0; a < numVertices; a++)
+        for (unsigned int a = 0; a < numVertices; ++a) {
             bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0);
             bone->mWeights[a] = aiVertexWeight(vertexStartIndex + a, 1.0);
+        }
 
 
         // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
         // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding
         // them to the array, but I'm tired now and I'm annoyed.
         // them to the array, but I'm tired now and I'm annoyed.
@@ -194,8 +195,9 @@ void SkeletonMeshBuilder::CreateGeometry(const aiNode *pNode) {
     }
     }
 
 
     // and finally recurse into the children list
     // and finally recurse into the children list
-    for (unsigned int a = 0; a < pNode->mNumChildren; a++)
+    for (unsigned int a = 0; a < pNode->mNumChildren; ++a) {
         CreateGeometry(pNode->mChildren[a]);
         CreateGeometry(pNode->mChildren[a]);
+    }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 58 - 0
code/Common/StbCommon.h

@@ -0,0 +1,58 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2022, 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.
+
+----------------------------------------------------------------------
+*/
+#pragma once
+
+#if _MSC_VER // "unreferenced function has been removed" (SSE2 detection routine in x64 builds)
+#pragma warning(push)
+#pragma warning(disable : 4505)
+#else
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+#include "stb/stb_image.h"
+
+#if _MSC_VER
+#pragma warning(pop)
+#else
+#pragma GCC diagnostic pop
+#endif
+

+ 5 - 1
code/Common/Version.cpp

@@ -135,6 +135,9 @@ ASSIMP_API aiScene::aiScene() :
         mNumCameras(0),
         mNumCameras(0),
         mCameras(nullptr),
         mCameras(nullptr),
         mMetaData(nullptr),
         mMetaData(nullptr),
+        mName(),
+        mNumSkeletons(0),
+        mSkeletons(nullptr),
         mPrivate(new Assimp::ScenePrivateData()) {
         mPrivate(new Assimp::ScenePrivateData()) {
     // empty
     // empty
 }
 }
@@ -180,7 +183,8 @@ ASSIMP_API aiScene::~aiScene() {
     delete[] mCameras;
     delete[] mCameras;
 
 
     aiMetadata::Dealloc(mMetaData);
     aiMetadata::Dealloc(mMetaData);
-    mMetaData = nullptr;
 
 
+    delete[] mSkeletons;
+    
     delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
     delete static_cast<Assimp::ScenePrivateData *>(mPrivate);
 }
 }

+ 2 - 0
code/Common/ZipArchiveIOSystem.cpp

@@ -196,7 +196,9 @@ zlib_filefunc_def IOSystem2Unzip::get(IOSystem *pIOHandler) {
     zlib_filefunc_def mapping;
     zlib_filefunc_def mapping;
 
 
     mapping.zopen_file = (open_file_func)open;
     mapping.zopen_file = (open_file_func)open;
+#ifdef _UNZ_H
     mapping.zopendisk_file = (opendisk_file_func)opendisk;
     mapping.zopendisk_file = (opendisk_file_func)opendisk;
+#endif
     mapping.zread_file = (read_file_func)read;
     mapping.zread_file = (read_file_func)read;
     mapping.zwrite_file = (write_file_func)write;
     mapping.zwrite_file = (write_file_func)write;
     mapping.ztell_file = (tell_file_func)tell;
     mapping.ztell_file = (tell_file_func)tell;

+ 1 - 1
code/Common/material.cpp

@@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/material.h>
 #include <assimp/material.h>
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
-const char *TextureTypeToString(aiTextureType in) {
+const char *aiTextureTypeToString(aiTextureType in) {
     switch (in) {
     switch (in) {
     case aiTextureType_NONE:
     case aiTextureType_NONE:
         return "n/a";
         return "n/a";

+ 2 - 2
code/Pbrt/PbrtExporter.cpp

@@ -83,7 +83,7 @@ Other:
 #include <sstream>
 #include <sstream>
 #include <string>
 #include <string>
 
 
-#include "stb/stb_image.h"
+#include "Common/StbCommon.h"
 
 
 using namespace Assimp;
 using namespace Assimp;
 
 
@@ -590,7 +590,7 @@ void PbrtExporter::WriteMaterial(int m) {
     for (int i = 1; i <= aiTextureType_UNKNOWN; i++) {
     for (int i = 1; i <= aiTextureType_UNKNOWN; i++) {
         int count = material->GetTextureCount(aiTextureType(i));
         int count = material->GetTextureCount(aiTextureType(i));
         if (count > 0)
         if (count > 0)
-            mOutput << TextureTypeToString(aiTextureType(i)) << ": " <<  count << " ";
+            mOutput << aiTextureTypeToString(aiTextureType(i)) << ": " <<  count << " ";
     }
     }
     mOutput << "\n";
     mOutput << "\n";
 
 

+ 1 - 1
code/PostProcessing/ComputeUVMappingProcess.cpp

@@ -415,7 +415,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
                     if (!DefaultLogger::isNullLogger())
                     if (!DefaultLogger::isNullLogger())
                     {
                     {
                         ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
                         ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s",
-                            TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
+                            aiTextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
                             MappingTypeToString(mapping));
                             MappingTypeToString(mapping));
 
 
                         ASSIMP_LOG_INFO(buffer);
                         ASSIMP_LOG_INFO(buffer);

+ 1 - 1
code/PostProcessing/EmbedTexturesProcess.cpp

@@ -128,7 +128,7 @@ bool EmbedTexturesProcess::addTexture(aiScene *pScene, const std::string &path)
 
 
     aiTexel* imageContent = new aiTexel[ 1ul + static_cast<unsigned long>( imageSize ) / sizeof(aiTexel)];
     aiTexel* imageContent = new aiTexel[ 1ul + static_cast<unsigned long>( imageSize ) / sizeof(aiTexel)];
     pFile->Seek(0, aiOrigin_SET);
     pFile->Seek(0, aiOrigin_SET);
-    pFile->Read(reinterpret_cast<char*>(imageContent), imageSize, 1);
+    pFile->Read(reinterpret_cast<char*>(imageContent), static_cast<size_t>(imageSize), 1);
     mIOHandler->Close(pFile);
     mIOHandler->Close(pFile);
 
 
     // Enlarging the textures table
     // Enlarging the textures table

+ 75 - 93
code/PostProcessing/JoinVerticesProcess.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,
@@ -45,41 +43,38 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * for all imported meshes
  * for all imported meshes
  */
  */
 
 
-
 #ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS
 #ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS
 
 
 #include "JoinVerticesProcess.h"
 #include "JoinVerticesProcess.h"
 #include "ProcessHelper.h"
 #include "ProcessHelper.h"
 #include <assimp/Vertex.h>
 #include <assimp/Vertex.h>
 #include <assimp/TinyFormatter.h>
 #include <assimp/TinyFormatter.h>
+
 #include <stdio.h>
 #include <stdio.h>
 #include <unordered_set>
 #include <unordered_set>
+#include <unordered_map>
 
 
 using namespace Assimp;
 using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
-JoinVerticesProcess::JoinVerticesProcess()
-{
+JoinVerticesProcess::JoinVerticesProcess() {
     // nothing to do here
     // nothing to do here
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 // Destructor, private as well
-JoinVerticesProcess::~JoinVerticesProcess()
-{
+JoinVerticesProcess::~JoinVerticesProcess() {
     // nothing to do here
     // nothing to do here
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 // Returns whether the processing step is present in the given flag field.
-bool JoinVerticesProcess::IsActive( unsigned int pFlags) const
-{
+bool JoinVerticesProcess::IsActive( unsigned int pFlags) const {
     return (pFlags & aiProcess_JoinIdenticalVertices) != 0;
     return (pFlags & aiProcess_JoinIdenticalVertices) != 0;
 }
 }
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 // Executes the post processing step on the given imported data.
-void JoinVerticesProcess::Execute( aiScene* pScene)
-{
+void JoinVerticesProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("JoinVerticesProcess begin");
     ASSIMP_LOG_DEBUG("JoinVerticesProcess begin");
 
 
     // get the total number of vertices BEFORE the step is executed
     // get the total number of vertices BEFORE the step is executed
@@ -92,27 +87,29 @@ void JoinVerticesProcess::Execute( aiScene* pScene)
 
 
     // execute the step
     // execute the step
     int iNumVertices = 0;
     int iNumVertices = 0;
-    for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
+    for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
         iNumVertices += ProcessMesh( pScene->mMeshes[a],a);
         iNumVertices += ProcessMesh( pScene->mMeshes[a],a);
+    }
+
+    pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
 
 
     // if logging is active, print detailed statistics
     // if logging is active, print detailed statistics
     if (!DefaultLogger::isNullLogger()) {
     if (!DefaultLogger::isNullLogger()) {
         if (iNumOldVertices == iNumVertices) {
         if (iNumOldVertices == iNumVertices) {
             ASSIMP_LOG_DEBUG("JoinVerticesProcess finished ");
             ASSIMP_LOG_DEBUG("JoinVerticesProcess finished ");
-        } else {
-            ASSIMP_LOG_INFO("JoinVerticesProcess finished | Verts in: ", iNumOldVertices,
-                " out: ", iNumVertices, " | ~",
-                ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f );
+            return;
         }
         }
+        
+        // Show statistics
+        ASSIMP_LOG_INFO("JoinVerticesProcess finished | Verts in: ", iNumOldVertices,
+            " out: ", iNumVertices, " | ~",
+            ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f );
     }
     }
-
-    pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
 }
 }
 
 
 namespace {
 namespace {
 
 
-bool areVerticesEqual(const Vertex &lhs, const Vertex &rhs, bool complex)
-{
+bool areVerticesEqual(const Vertex &lhs, const Vertex &rhs, bool complex) {
     // A little helper to find locally close vertices faster.
     // A little helper to find locally close vertices faster.
     // Try to reuse the lookup table from the last step.
     // Try to reuse the lookup table from the last step.
     const static float epsilon = 1e-5f;
     const static float epsilon = 1e-5f;
@@ -171,8 +168,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
     // ----------------------------------------------------------------------------
     // ----------------------------------------------------------------------------
 
 
     // Position, if present (check made for aiAnimMesh)
     // Position, if present (check made for aiAnimMesh)
-    if (pMesh->mVertices)
-    {
+    if (pMesh->mVertices) {
         delete [] pMesh->mVertices;
         delete [] pMesh->mVertices;
         pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
         pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
         for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
         for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
@@ -181,8 +177,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
     }
     }
 
 
     // Normals, if present
     // Normals, if present
-    if (pMesh->mNormals)
-    {
+    if (pMesh->mNormals) {
         delete [] pMesh->mNormals;
         delete [] pMesh->mNormals;
         pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
         pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
         for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
         for( unsigned int a = 0; a < pMesh->mNumVertices; a++) {
@@ -190,8 +185,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
         }
         }
     }
     }
     // Tangents, if present
     // Tangents, if present
-    if (pMesh->mTangents)
-    {
+    if (pMesh->mTangents) {
         delete [] pMesh->mTangents;
         delete [] pMesh->mTangents;
         pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
         pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
         for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
         for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
@@ -199,8 +193,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
         }
         }
     }
     }
     // Bitangents as well
     // Bitangents as well
-    if (pMesh->mBitangents)
-    {
+    if (pMesh->mBitangents) {
         delete [] pMesh->mBitangents;
         delete [] pMesh->mBitangents;
         pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
         pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
         for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
         for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
@@ -208,8 +201,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
         }
         }
     }
     }
     // Vertex colors
     // Vertex colors
-    for (unsigned int a = 0; pMesh->HasVertexColors(a); a++)
-    {
+    for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) {
         delete [] pMesh->mColors[a];
         delete [] pMesh->mColors[a];
         pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
         pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices];
         for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
         for( unsigned int b = 0; b < pMesh->mNumVertices; b++) {
@@ -217,8 +209,7 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
         }
         }
     }
     }
     // Texture coords
     // Texture coords
-    for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++)
-    {
+    for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) {
         delete [] pMesh->mTextureCoords[a];
         delete [] pMesh->mTextureCoords[a];
         pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
         pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices];
         for (unsigned int b = 0; b < pMesh->mNumVertices; b++) {
         for (unsigned int b = 0; b < pMesh->mNumVertices; b++) {
@@ -226,12 +217,40 @@ void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) {
         }
         }
     }
     }
 }
 }
+
 } // namespace
 } // namespace
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Unites identical vertices in the given mesh
 // Unites identical vertices in the given mesh
-int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
-{
+// combine hashes
+inline void hash_combine(std::size_t &) {
+    // empty
+}
+
+template <typename T, typename... Rest>
+inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
+    std::hash<T> hasher;
+    seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
+    hash_combine(seed, rest...);
+}
+//template specialization for std::hash for Vertex
+template<>
+struct std::hash<Vertex> {
+    std::size_t operator()(Vertex const& v) const noexcept {
+        size_t seed = 0;
+        hash_combine(seed, v.position.x ,v.position.y,v.position.z);
+        return seed; 
+    }
+};
+//template specialization for std::equal_to for Vertex
+template<>
+struct std::equal_to<Vertex> {
+    bool operator()(const Vertex &lhs, const Vertex &rhs) const {
+        return areVerticesEqual(lhs, rhs, false);
+    }
+};
+// now start the JoinVerticesProcess
+int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) {
     static_assert( AI_MAX_NUMBER_OF_COLOR_SETS    == 8, "AI_MAX_NUMBER_OF_COLOR_SETS    == 8");
     static_assert( AI_MAX_NUMBER_OF_COLOR_SETS    == 8, "AI_MAX_NUMBER_OF_COLOR_SETS    == 8");
 	static_assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 8, "AI_MAX_NUMBER_OF_TEXTURECOORDS == 8");
 	static_assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 8, "AI_MAX_NUMBER_OF_TEXTURECOORDS == 8");
 
 
@@ -245,8 +264,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
     // multiple meshes)
     // multiple meshes)
     std::unordered_set<unsigned int> usedVertexIndices;
     std::unordered_set<unsigned int> usedVertexIndices;
     usedVertexIndices.reserve(pMesh->mNumVertices);
     usedVertexIndices.reserve(pMesh->mNumVertices);
-    for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
-    {
+    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
         aiFace& face = pMesh->mFaces[a];
         aiFace& face = pMesh->mFaces[a];
         for( unsigned int b = 0; b < face.mNumIndices; b++) {
         for( unsigned int b = 0; b < face.mNumIndices; b++) {
             usedVertexIndices.insert(face.mIndices[b]);
             usedVertexIndices.insert(face.mIndices[b]);
@@ -292,7 +310,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
 
 
     // Run an optimized code path if we don't have multiple UVs or vertex colors.
     // Run an optimized code path if we don't have multiple UVs or vertex colors.
     // This should yield false in more than 99% of all imports ...
     // This should yield false in more than 99% of all imports ...
-    const bool complex = ( pMesh->GetNumColorChannels() > 0 || pMesh->GetNumUVChannels() > 1);
     const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
     const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0;
 
 
     // We'll never have more vertices afterwards.
     // We'll never have more vertices afterwards.
@@ -303,72 +320,38 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
             uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices);
             uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices);
         }
         }
     }
     }
-
+    // a map that maps a vertix to its new index
+    std::unordered_map<Vertex,int> vertex2Index;
+    // we can not end up with more vertices than we started with
+    vertex2Index.reserve(pMesh->mNumVertices);
     // Now check each vertex if it brings something new to the table
     // Now check each vertex if it brings something new to the table
+    int newIndex = 0;
     for( unsigned int a = 0; a < pMesh->mNumVertices; a++)  {
     for( unsigned int a = 0; a < pMesh->mNumVertices; a++)  {
+        // if the vertex is unused Do nothing
         if (usedVertexIndices.find(a) == usedVertexIndices.end()) {
         if (usedVertexIndices.find(a) == usedVertexIndices.end()) {
             continue;
             continue;
         }
         }
-
         // collect the vertex data
         // collect the vertex data
         Vertex v(pMesh,a);
         Vertex v(pMesh,a);
-
-        // collect all vertices that are close enough to the given position
-        vertexFinder->FindIdenticalPositions( v.position, verticesFound);
-        unsigned int matchIndex = 0xffffffff;
-
-        // check all unique vertices close to the position if this vertex is already present among them
-        for( unsigned int b = 0; b < verticesFound.size(); b++) {
-            const unsigned int vidx = verticesFound[b];
-            const unsigned int uidx = replaceIndex[ vidx];
-            if( uidx & 0x80000000)
-                continue;
-
-            const Vertex& uv = uniqueVertices[ uidx];
-
-            if (!areVerticesEqual(v, uv, complex)) {
-                continue;
-            }
-
-            if (hasAnimMeshes) {
-                // If given vertex is animated, then it has to be preserver 1 to 1 (base mesh and animated mesh require same topology)
-                // NOTE: not doing this totaly breaks anim meshes as they don't have their own faces (they use pMesh->mFaces)
-                bool breaksAnimMesh = false;
-                for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
-                    const Vertex& animatedUV = uniqueAnimatedVertices[animMeshIndex][ uidx];
-                    Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a);
-                    if (!areVerticesEqual(aniMeshVertex, animatedUV, complex)) {
-                        breaksAnimMesh = true;
-                        break;
-                    }
-                }
-                if (breaksAnimMesh) {
-                    continue;
-                }
-            }
-
-            // we're still here -> this vertex perfectly matches our given vertex
-            matchIndex = uidx;
-            break;
-        }
-
-        // found a replacement vertex among the uniques?
-        if( matchIndex != 0xffffffff)
-        {
-            // store where to found the matching unique vertex
-            replaceIndex[a] = matchIndex | 0x80000000;
-        }
-        else
-        {
-            // no unique vertex matches it up to now -> so add it
-            replaceIndex[a] = (unsigned int)uniqueVertices.size();
-            uniqueVertices.push_back( v);
+        // is the vertex already in the map?
+        auto it = vertex2Index.find(v);
+        // if the vertex is not in the map then it is a new vertex add it.
+        if (it == vertex2Index.end()) {
+            // this is a new vertex give it a new index
+            vertex2Index[v] = newIndex;
+            //keep track of its index and increment 1
+            replaceIndex[a] = newIndex++;
+            // add the vertex to the unique vertices
+            uniqueVertices.push_back(v);
             if (hasAnimMeshes) {
             if (hasAnimMeshes) {
                 for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
                 for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) {
                     Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a);
                     Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a);
-                    uniqueAnimatedVertices[animMeshIndex].push_back(aniMeshVertex);
+                    uniqueAnimatedVertices[animMeshIndex].push_back(v);
                 }
                 }
             }
             }
+        } else{
+            // if the vertex is already there just find the replace index that is appropriate to it
+            replaceIndex[a] = it->second;
         }
         }
     }
     }
 
 
@@ -394,8 +377,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
     }
     }
 
 
     // adjust the indices in all faces
     // adjust the indices in all faces
-    for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
-    {
+    for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
         aiFace& face = pMesh->mFaces[a];
         aiFace& face = pMesh->mFaces[a];
         for( unsigned int b = 0; b < face.mNumIndices; b++) {
         for( unsigned int b = 0; b < face.mNumIndices; b++) {
             face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~0x80000000;
             face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~0x80000000;

+ 1 - 1
code/PostProcessing/ValidateDataStructure.cpp

@@ -521,7 +521,7 @@ void ValidateDSProcess::Validate(const aiAnimation *pAnimation) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial *pMaterial,
 void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial *pMaterial,
         aiTextureType type) {
         aiTextureType type) {
-    const char *szType = TextureTypeToString(type);
+    const char *szType = aiTextureTypeToString(type);
 
 
     // ****************************************************************************
     // ****************************************************************************
     // Search all keys of the material ...
     // Search all keys of the material ...

+ 16 - 55
code/res/assimp.rc

@@ -1,80 +1,41 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
 #include "revision.h"
 #include "revision.h"
+#ifdef __GNUC__
+#include "winresrc.h"
+#else
+#include "winres.h"
+#endif
 
 
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#define APSTUDIO_HIDDEN_SYMBOLS
-#include "windows.h"
-#undef APSTUDIO_HIDDEN_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// Deutsch (Deutschland) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
-#ifdef _WIN32
-LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
 #pragma code_page(1252)
 #pragma code_page(1252)
-#endif //_WIN32
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
 
 
 VS_VERSION_INFO VERSIONINFO
 VS_VERSION_INFO VERSIONINFO
  FILEVERSION VER_FILEVERSION
  FILEVERSION VER_FILEVERSION
  PRODUCTVERSION VER_FILEVERSION
  PRODUCTVERSION VER_FILEVERSION
- FILEFLAGSMASK 0x17L
+ FILEFLAGSMASK VS_FF_DEBUG
 #ifdef _DEBUG
 #ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
+ FILEFLAGS VS_FF_DEBUG
 #endif
 #endif
- FILEOS 0x4L
- FILETYPE 0x7L
- FILESUBTYPE 0x0L
+ FILEOS VOS_NT
+ FILETYPE VFT_DLL
 BEGIN
 BEGIN
     BLOCK "StringFileInfo"
     BLOCK "StringFileInfo"
     BEGIN
     BEGIN
-        BLOCK "040704b0"
+        BLOCK "000004B0"
         BEGIN
         BEGIN
             VALUE "Comments", "Licensed under a 3-clause BSD license"
             VALUE "Comments", "Licensed under a 3-clause BSD license"
-            VALUE "CompanyName", "assimp team"
+            VALUE "CompanyName", "ASSIMP Team"
             VALUE "FileDescription", "Open Asset Import Library"
             VALUE "FileDescription", "Open Asset Import Library"
-            VALUE "FileVersion", VER_FILEVERSION
-            VALUE "InternalName", "assimp "
-            VALUE "LegalCopyright", "Copyright (C) 2006-2020"
+            VALUE "FileVersion", VER_FILEVERSION_STR
+            VALUE "InternalName", "assimp"
+            VALUE "LegalCopyright", VER_COPYRIGHT_STR
             VALUE "OriginalFilename", VER_ORIGINAL_FILENAME_STR
             VALUE "OriginalFilename", VER_ORIGINAL_FILENAME_STR
             VALUE "ProductName", "Open Asset Import Library"
             VALUE "ProductName", "Open Asset Import Library"
             VALUE "ProductVersion", VER_FILEVERSION_STR
             VALUE "ProductVersion", VER_FILEVERSION_STR
-		,0
         END
         END
     END
     END
     BLOCK "VarFileInfo"
     BLOCK "VarFileInfo"
     BEGIN
     BEGIN
-        VALUE "Translation", 0x407, 1200
+        VALUE "Translation", 0x0, 65001
     END
     END
 END
 END
 
 
-#endif    // Deutsch (Deutschland) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-

+ 0 - 14
code/res/resource.h

@@ -1,14 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by assimp.rc
-
-// Next standard values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        101
-#define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1001
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif

+ 7 - 0
contrib/clipper/clipper.cpp

@@ -86,6 +86,13 @@ class Int128
 
 
     Int128(const Int128 &val): hi(val.hi), lo(val.lo){}
     Int128(const Int128 &val): hi(val.hi), lo(val.lo){}
 
 
+    Int128 operator = (const Int128 &val)
+    {
+        lo = val.lo;
+        hi = val.hi;
+        return val;
+    }
+
     long64 operator = (const long64 &val)
     long64 operator = (const long64 &val)
     {
     {
       lo = val;
       lo = val;

+ 1 - 1
contrib/draco/CMakeLists.txt

@@ -10,7 +10,7 @@ endif()
 
 
 set(draco_root "${CMAKE_CURRENT_SOURCE_DIR}")
 set(draco_root "${CMAKE_CURRENT_SOURCE_DIR}")
 set(draco_src_root "${draco_root}/src/draco")
 set(draco_src_root "${draco_root}/src/draco")
-set(draco_build "${CMAKE_BINARY_DIR}")
+set(draco_build "${Assimp_BINARY_DIR}")
 
 
 if("${draco_root}" STREQUAL "${draco_build}")
 if("${draco_root}" STREQUAL "${draco_build}")
   message(
   message(

+ 120 - 83
contrib/gtest/CMakeLists.txt

@@ -1,14 +1,13 @@
 ########################################################################
 ########################################################################
+# Note: CMake support is community-based. The maintainers do not use CMake
+# internally.
+#
 # CMake build script for Google Test.
 # CMake build script for Google Test.
 #
 #
 # To run the tests for Google Test itself on Linux, use 'make test' or
 # To run the tests for Google Test itself on Linux, use 'make test' or
 # ctest.  You can select which tests to run using 'ctest -R regex'.
 # ctest.  You can select which tests to run using 'ctest -R regex'.
 # For more options, run 'ctest --help'.
 # For more options, run 'ctest --help'.
 
 
-# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
-# make it prominent in the GUI.
-option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
-
 # When other libraries are using a shared version of runtime libraries,
 # When other libraries are using a shared version of runtime libraries,
 # Google Test also has to use one.
 # Google Test also has to use one.
 option(
 option(
@@ -44,13 +43,45 @@ endif()
 # as ${gtest_SOURCE_DIR} and to the root binary directory as
 # as ${gtest_SOURCE_DIR} and to the root binary directory as
 # ${gtest_BINARY_DIR}.
 # ${gtest_BINARY_DIR}.
 # Language "C" is required for find_package(Threads).
 # Language "C" is required for find_package(Threads).
-project(gtest CXX C)
-cmake_minimum_required(VERSION 3.10)
+
+# Project version:
+
+if (CMAKE_VERSION VERSION_LESS 3.0)
+  project(gtest CXX C)
+  set(PROJECT_VERSION ${GOOGLETEST_VERSION})
+else()
+  cmake_policy(SET CMP0048 NEW)
+  project(gtest VERSION ${GOOGLETEST_VERSION} LANGUAGES CXX C)
+endif()
+cmake_minimum_required(VERSION 2.8.12)
+
+if (POLICY CMP0063) # Visibility
+  cmake_policy(SET CMP0063 NEW)
+endif (POLICY CMP0063)
 
 
 if (COMMAND set_up_hermetic_build)
 if (COMMAND set_up_hermetic_build)
   set_up_hermetic_build()
   set_up_hermetic_build()
 endif()
 endif()
 
 
+# These commands only run if this is the main project
+if(CMAKE_PROJECT_NAME STREQUAL "gtest" OR CMAKE_PROJECT_NAME STREQUAL "googletest-distribution")
+
+  # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
+  # make it prominent in the GUI.
+  option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
+
+else()
+
+  mark_as_advanced(
+    gtest_force_shared_crt
+    gtest_build_tests
+    gtest_build_samples
+    gtest_disable_pthreads
+    gtest_hide_internal_symbols)
+
+endif()
+
+
 if (gtest_hide_internal_symbols)
 if (gtest_hide_internal_symbols)
   set(CMAKE_CXX_VISIBILITY_PRESET hidden)
   set(CMAKE_CXX_VISIBILITY_PRESET hidden)
   set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
   set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
@@ -61,24 +92,34 @@ include(cmake/internal_utils.cmake)
 
 
 config_compiler_and_linker()  # Defined in internal_utils.cmake.
 config_compiler_and_linker()  # Defined in internal_utils.cmake.
 
 
-# Where Google Test's .h files can be found.
-include_directories(
-  ${gtest_SOURCE_DIR}/include
-  ${gtest_SOURCE_DIR})
-
-# Where Google Test's libraries can be found.
-link_directories(${gtest_BINARY_DIR}/src)
-
-# Summary of tuple support for Microsoft Visual Studio:
-# Compiler    version(MS)  version(cmake)  Support
-# ----------  -----------  --------------  -----------------------------
-# <= VS 2010  <= 10        <= 1600         Use Google Tests's own tuple.
-# VS 2012     11           1700            std::tr1::tuple + _VARIADIC_MAX=10
-# VS 2013     12           1800            std::tr1::tuple
-if (MSVC AND MSVC_VERSION EQUAL 1700)
-  add_definitions(/D _VARIADIC_MAX=10)
+# Needed to set the namespace for both the export targets and the
+# alias libraries
+set(cmake_package_name GTest CACHE INTERNAL "")
+
+# Create the CMake package file descriptors.
+if (INSTALL_GTEST)
+  include(CMakePackageConfigHelpers)
+  set(targets_export_name ${cmake_package_name}Targets CACHE INTERNAL "")
+  set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated" CACHE INTERNAL "")
+  set(cmake_files_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${cmake_package_name}")
+  set(version_file "${generated_dir}/${cmake_package_name}ConfigVersion.cmake")
+  write_basic_package_version_file(${version_file} VERSION ${GOOGLETEST_VERSION} COMPATIBILITY AnyNewerVersion)
+  install(EXPORT ${targets_export_name}
+    NAMESPACE ${cmake_package_name}::
+    DESTINATION ${cmake_files_install_dir})
+  set(config_file "${generated_dir}/${cmake_package_name}Config.cmake")
+  configure_package_config_file("${gtest_SOURCE_DIR}/cmake/Config.cmake.in"
+    "${config_file}" INSTALL_DESTINATION ${cmake_files_install_dir})
+  install(FILES ${version_file} ${config_file}
+    DESTINATION ${cmake_files_install_dir})
 endif()
 endif()
 
 
+# Where Google Test's .h files can be found.
+set(gtest_build_include_dirs
+  "${gtest_SOURCE_DIR}/include"
+  "${gtest_SOURCE_DIR}")
+include_directories(${gtest_build_include_dirs})
+
 ########################################################################
 ########################################################################
 #
 #
 # Defines the gtest & gtest_main libraries.  User tests should link
 # Defines the gtest & gtest_main libraries.  User tests should link
@@ -88,24 +129,26 @@ endif()
 # are used for other targets, to ensure that gtest can be compiled by a user
 # are used for other targets, to ensure that gtest can be compiled by a user
 # aggressive about warnings.
 # aggressive about warnings.
 cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)
 cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)
+set_target_properties(gtest PROPERTIES VERSION ${GOOGLETEST_VERSION})
 cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
 cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
-target_link_libraries(gtest_main gtest)
-
+set_target_properties(gtest_main PROPERTIES VERSION ${GOOGLETEST_VERSION})
 # If the CMake version supports it, attach header directory information
 # If the CMake version supports it, attach header directory information
 # to the targets for when we are part of a parent build (ie being pulled
 # to the targets for when we are part of a parent build (ie being pulled
 # in via add_subdirectory() rather than being a standalone build).
 # in via add_subdirectory() rather than being a standalone build).
 if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
 if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
-  target_include_directories(gtest      INTERFACE "${gtest_SOURCE_DIR}/include")
-  target_include_directories(gtest_main INTERFACE "${gtest_SOURCE_DIR}/include")
+  target_include_directories(gtest SYSTEM INTERFACE
+    "$<BUILD_INTERFACE:${gtest_build_include_dirs}>"
+    "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
+  target_include_directories(gtest_main SYSTEM INTERFACE
+    "$<BUILD_INTERFACE:${gtest_build_include_dirs}>"
+    "$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${CMAKE_INSTALL_INCLUDEDIR}>")
 endif()
 endif()
+target_link_libraries(gtest_main PUBLIC gtest)
 
 
 ########################################################################
 ########################################################################
 #
 #
 # Install rules
 # Install rules
-install(TARGETS gtest gtest_main
-  DESTINATION lib)
-install(DIRECTORY ${gtest_SOURCE_DIR}/include/gtest
-  DESTINATION include)
+install_project(gtest gtest_main)
 
 
 ########################################################################
 ########################################################################
 #
 #
@@ -147,33 +190,34 @@ if (gtest_build_tests)
   ############################################################
   ############################################################
   # C++ tests built with standard compiler flags.
   # C++ tests built with standard compiler flags.
 
 
-  cxx_test(gtest-death-test_test gtest_main)
+  cxx_test(googletest-death-test-test gtest_main)
   cxx_test(gtest_environment_test gtest)
   cxx_test(gtest_environment_test gtest)
-  cxx_test(gtest-filepath_test gtest_main)
-  cxx_test(gtest-linked_ptr_test gtest_main)
-  cxx_test(gtest-listener_test gtest_main)
+  cxx_test(googletest-filepath-test gtest_main)
+  cxx_test(googletest-listener-test gtest_main)
   cxx_test(gtest_main_unittest gtest_main)
   cxx_test(gtest_main_unittest gtest_main)
-  cxx_test(gtest-message_test gtest_main)
+  cxx_test(googletest-message-test gtest_main)
   cxx_test(gtest_no_test_unittest gtest)
   cxx_test(gtest_no_test_unittest gtest)
-  cxx_test(gtest-options_test gtest_main)
-  cxx_test(gtest-param-test_test gtest
-    test/gtest-param-test2_test.cc)
-  cxx_test(gtest-port_test gtest_main)
+  cxx_test(googletest-options-test gtest_main)
+  cxx_test(googletest-param-test-test gtest
+    test/googletest-param-test2-test.cc)
+  cxx_test(googletest-port-test gtest_main)
   cxx_test(gtest_pred_impl_unittest gtest_main)
   cxx_test(gtest_pred_impl_unittest gtest_main)
   cxx_test(gtest_premature_exit_test gtest
   cxx_test(gtest_premature_exit_test gtest
     test/gtest_premature_exit_test.cc)
     test/gtest_premature_exit_test.cc)
-  cxx_test(gtest-printers_test gtest_main)
+  cxx_test(googletest-printers-test gtest_main)
   cxx_test(gtest_prod_test gtest_main
   cxx_test(gtest_prod_test gtest_main
     test/production.cc)
     test/production.cc)
   cxx_test(gtest_repeat_test gtest)
   cxx_test(gtest_repeat_test gtest)
   cxx_test(gtest_sole_header_test gtest_main)
   cxx_test(gtest_sole_header_test gtest_main)
   cxx_test(gtest_stress_test gtest)
   cxx_test(gtest_stress_test gtest)
-  cxx_test(gtest-test-part_test gtest_main)
+  cxx_test(googletest-test-part-test gtest_main)
   cxx_test(gtest_throw_on_failure_ex_test gtest)
   cxx_test(gtest_throw_on_failure_ex_test gtest)
   cxx_test(gtest-typed-test_test gtest_main
   cxx_test(gtest-typed-test_test gtest_main
     test/gtest-typed-test2_test.cc)
     test/gtest-typed-test2_test.cc)
   cxx_test(gtest_unittest gtest_main)
   cxx_test(gtest_unittest gtest_main)
   cxx_test(gtest-unittest-api_test gtest)
   cxx_test(gtest-unittest-api_test gtest)
+  cxx_test(gtest_skip_in_environment_setup_test gtest_main)
+  cxx_test(gtest_skip_test gtest_main)
 
 
   ############################################################
   ############################################################
   # C++ tests built with non-standard compiler flags.
   # C++ tests built with non-standard compiler flags.
@@ -190,10 +234,10 @@ if (gtest_build_tests)
 
 
   cxx_test_with_flags(gtest-death-test_ex_nocatch_test
   cxx_test_with_flags(gtest-death-test_ex_nocatch_test
     "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0"
     "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0"
-    gtest test/gtest-death-test_ex_test.cc)
+    gtest test/googletest-death-test_ex_test.cc)
   cxx_test_with_flags(gtest-death-test_ex_catch_test
   cxx_test_with_flags(gtest-death-test_ex_catch_test
     "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1"
     "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1"
-    gtest test/gtest-death-test_ex_test.cc)
+    gtest test/googletest-death-test_ex_test.cc)
 
 
   cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
   cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
     gtest_main_no_rtti test/gtest_unittest.cc)
     gtest_main_no_rtti test/gtest_unittest.cc)
@@ -207,80 +251,73 @@ if (gtest_build_tests)
                         PROPERTIES
                         PROPERTIES
                         COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
                         COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
 
 
-  if (NOT MSVC OR MSVC_VERSION LESS 1600)  # 1600 is Visual Studio 2010.
-    # Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that
-    # conflict with our own definitions. Therefore using our own tuple does not
-    # work on those compilers.
-    cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}"
-      src/gtest-all.cc src/gtest_main.cc)
-
-    cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}"
-      gtest_main_use_own_tuple test/gtest-tuple_test.cc)
-
-    cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}"
-      gtest_main_use_own_tuple
-      test/gtest-param-test_test.cc test/gtest-param-test2_test.cc)
-  endif()
-
   ############################################################
   ############################################################
   # Python tests.
   # Python tests.
 
 
-  cxx_executable(gtest_break_on_failure_unittest_ test gtest)
-  py_test(gtest_break_on_failure_unittest)
+  cxx_executable(googletest-break-on-failure-unittest_ test gtest)
+  py_test(googletest-break-on-failure-unittest)
+
+  py_test(gtest_skip_check_output_test)
+  py_test(gtest_skip_environment_check_output_test)
 
 
   # Visual Studio .NET 2003 does not support STL with exceptions disabled.
   # Visual Studio .NET 2003 does not support STL with exceptions disabled.
   if (NOT MSVC OR MSVC_VERSION GREATER 1310)  # 1310 is Visual Studio .NET 2003
   if (NOT MSVC OR MSVC_VERSION GREATER 1310)  # 1310 is Visual Studio .NET 2003
     cxx_executable_with_flags(
     cxx_executable_with_flags(
-      gtest_catch_exceptions_no_ex_test_
+      googletest-catch-exceptions-no-ex-test_
       "${cxx_no_exception}"
       "${cxx_no_exception}"
       gtest_main_no_exception
       gtest_main_no_exception
-      test/gtest_catch_exceptions_test_.cc)
+      test/googletest-catch-exceptions-test_.cc)
   endif()
   endif()
 
 
   cxx_executable_with_flags(
   cxx_executable_with_flags(
-    gtest_catch_exceptions_ex_test_
+    googletest-catch-exceptions-ex-test_
     "${cxx_exception}"
     "${cxx_exception}"
     gtest_main
     gtest_main
-    test/gtest_catch_exceptions_test_.cc)
-  py_test(gtest_catch_exceptions_test)
+    test/googletest-catch-exceptions-test_.cc)
+  py_test(googletest-catch-exceptions-test)
 
 
-  cxx_executable(gtest_color_test_ test gtest)
-  py_test(gtest_color_test)
+  cxx_executable(googletest-color-test_ test gtest)
+  py_test(googletest-color-test)
 
 
-  cxx_executable(gtest_env_var_test_ test gtest)
-  py_test(gtest_env_var_test)
+  cxx_executable(googletest-env-var-test_ test gtest)
+  py_test(googletest-env-var-test)
 
 
-  cxx_executable(gtest_filter_unittest_ test gtest)
-  py_test(gtest_filter_unittest)
+  cxx_executable(googletest-filter-unittest_ test gtest)
+  py_test(googletest-filter-unittest)
 
 
   cxx_executable(gtest_help_test_ test gtest_main)
   cxx_executable(gtest_help_test_ test gtest_main)
   py_test(gtest_help_test)
   py_test(gtest_help_test)
 
 
-  cxx_executable(gtest_list_tests_unittest_ test gtest)
-  py_test(gtest_list_tests_unittest)
+  cxx_executable(googletest-list-tests-unittest_ test gtest)
+  py_test(googletest-list-tests-unittest)
 
 
-  cxx_executable(gtest_output_test_ test gtest)
-  py_test(gtest_output_test)
+  cxx_executable(googletest-output-test_ test gtest)
+  py_test(googletest-output-test --no_stacktrace_support)
 
 
-  cxx_executable(gtest_shuffle_test_ test gtest)
-  py_test(gtest_shuffle_test)
+  cxx_executable(googletest-shuffle-test_ test gtest)
+  py_test(googletest-shuffle-test)
 
 
   # MSVC 7.1 does not support STL with exceptions disabled.
   # MSVC 7.1 does not support STL with exceptions disabled.
   if (NOT MSVC OR MSVC_VERSION GREATER 1310)
   if (NOT MSVC OR MSVC_VERSION GREATER 1310)
-    cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception)
-    set_target_properties(gtest_throw_on_failure_test_
+    cxx_executable(googletest-throw-on-failure-test_ test gtest_no_exception)
+    set_target_properties(googletest-throw-on-failure-test_
       PROPERTIES
       PROPERTIES
       COMPILE_FLAGS "${cxx_no_exception}")
       COMPILE_FLAGS "${cxx_no_exception}")
-    py_test(gtest_throw_on_failure_test)
+    py_test(googletest-throw-on-failure-test)
   endif()
   endif()
 
 
-  cxx_executable(gtest_uninitialized_test_ test gtest)
-  py_test(gtest_uninitialized_test)
+  cxx_executable(googletest-uninitialized-test_ test gtest)
+  py_test(googletest-uninitialized-test)
+
+  cxx_executable(gtest_list_output_unittest_ test gtest)
+  py_test(gtest_list_output_unittest)
 
 
   cxx_executable(gtest_xml_outfile1_test_ test gtest_main)
   cxx_executable(gtest_xml_outfile1_test_ test gtest_main)
   cxx_executable(gtest_xml_outfile2_test_ test gtest_main)
   cxx_executable(gtest_xml_outfile2_test_ test gtest_main)
   py_test(gtest_xml_outfiles_test)
   py_test(gtest_xml_outfiles_test)
+  py_test(googletest-json-outfiles-test)
 
 
   cxx_executable(gtest_xml_output_unittest_ test gtest)
   cxx_executable(gtest_xml_output_unittest_ test gtest)
-  py_test(gtest_xml_output_unittest)
+  py_test(gtest_xml_output_unittest --no_stacktrace_support)
+  py_test(googletest-json-output-unittest --no_stacktrace_support)
 endif()
 endif()

+ 164 - 229
contrib/gtest/README.md

@@ -1,181 +1,156 @@
+### Generic Build Instructions
 
 
-### Generic Build Instructions ###
+#### Setup
 
 
-#### Setup ####
+To build GoogleTest and your tests that use it, you need to tell your build
+system where to find its headers and source files. The exact way to do it
+depends on which build system you use, and is usually straightforward.
 
 
-To build Google Test and your tests that use it, you need to tell your
-build system where to find its headers and source files.  The exact
-way to do it depends on which build system you use, and is usually
-straightforward.
+### Build with CMake
 
 
-#### Build ####
+GoogleTest comes with a CMake build script
+([CMakeLists.txt](https://github.com/google/googletest/blob/master/CMakeLists.txt))
+that can be used on a wide range of platforms ("C" stands for cross-platform.).
+If you don't have CMake installed already, you can download it for free from
+<http://www.cmake.org/>.
 
 
-Suppose you put Google Test in directory `${GTEST_DIR}`.  To build it,
-create a library build target (or a project as called by Visual Studio
-and Xcode) to compile
+CMake works by generating native makefiles or build projects that can be used in
+the compiler environment of your choice. You can either build GoogleTest as a
+standalone project or it can be incorporated into an existing CMake build for
+another project.
 
 
-    ${GTEST_DIR}/src/gtest-all.cc
+#### Standalone CMake Project
 
 
-with `${GTEST_DIR}/include` in the system header search path and `${GTEST_DIR}`
-in the normal header search path.  Assuming a Linux-like system and gcc,
-something like the following will do:
+When building GoogleTest as a standalone project, the typical workflow starts
+with
 
 
-    g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
-        -pthread -c ${GTEST_DIR}/src/gtest-all.cc
-    ar -rv libgtest.a gtest-all.o
+```
+git clone https://github.com/google/googletest.git -b release-1.10.0
+cd googletest        # Main directory of the cloned repository.
+mkdir build          # Create a directory to hold the build output.
+cd build
+cmake ..             # Generate native build scripts for GoogleTest.
+```
 
 
-(We need `-pthread` as Google Test uses threads.)
+The above command also includes GoogleMock by default. And so, if you want to
+build only GoogleTest, you should replace the last command with
 
 
-Next, you should compile your test source file with
-`${GTEST_DIR}/include` in the system header search path, and link it
-with gtest and any other necessary libraries:
+```
+cmake .. -DBUILD_GMOCK=OFF
+```
 
 
-    g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \
-        -o your_test
+If you are on a \*nix system, you should now see a Makefile in the current
+directory. Just type `make` to build GoogleTest. And then you can simply install
+GoogleTest if you are a system administrator.
 
 
-As an example, the make/ directory contains a Makefile that you can
-use to build Google Test on systems where GNU make is available
-(e.g. Linux, Mac OS X, and Cygwin).  It doesn't try to build Google
-Test's own tests.  Instead, it just builds the Google Test library and
-a sample test.  You can use it as a starting point for your own build
-script.
+```
+make
+sudo make install    # Install in /usr/local/ by default
+```
 
 
-If the default settings are correct for your environment, the
-following commands should succeed:
-
-    cd ${GTEST_DIR}/make
-    make
-    ./sample1_unittest
-
-If you see errors, try to tweak the contents of `make/Makefile` to make
-them go away.  There are instructions in `make/Makefile` on how to do
-it.
-
-### Using CMake ###
-
-Google Test comes with a CMake build script (
-[CMakeLists.txt](CMakeLists.txt)) that can be used on a wide range of platforms ("C" stands for
-cross-platform.). If you don't have CMake installed already, you can
-download it for free from <http://www.cmake.org/>.
-
-CMake works by generating native makefiles or build projects that can
-be used in the compiler environment of your choice.  The typical
-workflow starts with:
-
-    mkdir mybuild       # Create a directory to hold the build output.
-    cd mybuild
-    cmake ${GTEST_DIR}  # Generate native build scripts.
-
-If you want to build Google Test's samples, you should replace the
-last command with
-
-    cmake -Dgtest_build_samples=ON ${GTEST_DIR}
-
-If you are on a \*nix system, you should now see a Makefile in the
-current directory.  Just type 'make' to build gtest.
-
-If you use Windows and have Visual Studio installed, a `gtest.sln` file
-and several `.vcproj` files will be created.  You can then build them
-using Visual Studio.
+If you use Windows and have Visual Studio installed, a `gtest.sln` file and
+several `.vcproj` files will be created. You can then build them using Visual
+Studio.
 
 
 On Mac OS X with Xcode installed, a `.xcodeproj` file will be generated.
 On Mac OS X with Xcode installed, a `.xcodeproj` file will be generated.
 
 
-### Legacy Build Scripts ###
-
-Before settling on CMake, we have been providing hand-maintained build
-projects/scripts for Visual Studio, Xcode, and Autotools.  While we
-continue to provide them for convenience, they are not actively
-maintained any more.  We highly recommend that you follow the
-instructions in the previous two sections to integrate Google Test
-with your existing build system.
-
-If you still need to use the legacy build scripts, here's how:
-
-The msvc\ folder contains two solutions with Visual C++ projects.
-Open the `gtest.sln` or `gtest-md.sln` file using Visual Studio, and you
-are ready to build Google Test the same way you build any Visual
-Studio project.  Files that have names ending with -md use DLL
-versions of Microsoft runtime libraries (the /MD or the /MDd compiler
-option).  Files without that suffix use static versions of the runtime
-libraries (the /MT or the /MTd option).  Please note that one must use
-the same option to compile both gtest and the test code.  If you use
-Visual Studio 2005 or above, we recommend the -md version as /MD is
-the default for new projects in these versions of Visual Studio.
-
-On Mac OS X, open the `gtest.xcodeproj` in the `xcode/` folder using
-Xcode.  Build the "gtest" target.  The universal binary framework will
-end up in your selected build directory (selected in the Xcode
-"Preferences..." -> "Building" pane and defaults to xcode/build).
-Alternatively, at the command line, enter:
-
-    xcodebuild
-
-This will build the "Release" configuration of gtest.framework in your
-default build location.  See the "xcodebuild" man page for more
-information about building different configurations and building in
-different locations.
-
-If you wish to use the Google Test Xcode project with Xcode 4.x and
-above, you need to either:
-
- * update the SDK configuration options in xcode/Config/General.xconfig.
-   Comment options `SDKROOT`, `MACOS_DEPLOYMENT_TARGET`, and `GCC_VERSION`. If
-   you choose this route you lose the ability to target earlier versions
-   of MacOS X.
- * Install an SDK for an earlier version. This doesn't appear to be
-   supported by Apple, but has been reported to work
-   (http://stackoverflow.com/questions/5378518).
-
-### Tweaking Google Test ###
-
-Google Test can be used in diverse environments.  The default
-configuration may not work (or may not work well) out of the box in
-some environments.  However, you can easily tweak Google Test by
-defining control macros on the compiler command line.  Generally,
-these macros are named like `GTEST_XYZ` and you define them to either 1
-or 0 to enable or disable a certain feature.
-
-We list the most frequently used macros below.  For a complete list,
-see file [include/gtest/internal/gtest-port.h](include/gtest/internal/gtest-port.h).
-
-### Choosing a TR1 Tuple Library ###
-
-Some Google Test features require the C++ Technical Report 1 (TR1)
-tuple library, which is not yet available with all compilers.  The
-good news is that Google Test implements a subset of TR1 tuple that's
-enough for its own need, and will automatically use this when the
-compiler doesn't provide TR1 tuple.
-
-Usually you don't need to care about which tuple library Google Test
-uses.  However, if your project already uses TR1 tuple, you need to
-tell Google Test to use the same TR1 tuple library the rest of your
-project uses, or the two tuple implementations will clash.  To do
-that, add
-
-    -DGTEST_USE_OWN_TR1_TUPLE=0
-
-to the compiler flags while compiling Google Test and your tests.  If
-you want to force Google Test to use its own tuple library, just add
-
-    -DGTEST_USE_OWN_TR1_TUPLE=1
-
-to the compiler flags instead.
-
-If you don't want Google Test to use tuple at all, add
-
-    -DGTEST_HAS_TR1_TUPLE=0
-
-and all features using tuple will be disabled.
-
-### Multi-threaded Tests ###
-
-Google Test is thread-safe where the pthread library is available.
-After `#include "gtest/gtest.h"`, you can check the `GTEST_IS_THREADSAFE`
-macro to see whether this is the case (yes if the macro is `#defined` to
-1, no if it's undefined.).
-
-If Google Test doesn't correctly detect whether pthread is available
-in your environment, you can force it with
+#### Incorporating Into An Existing CMake Project
+
+If you want to use GoogleTest in a project which already uses CMake, the easiest
+way is to get installed libraries and headers.
+
+*   Import GoogleTest by using `find_package` (or `pkg_check_modules`). For
+    example, if `find_package(GTest CONFIG REQUIRED)` succeeds, you can use the
+    libraries as `GTest::gtest`, `GTest::gmock`.
+
+And a more robust and flexible approach is to build GoogleTest as part of that
+project directly. This is done by making the GoogleTest source code available to
+the main build and adding it using CMake's `add_subdirectory()` command. This
+has the significant advantage that the same compiler and linker settings are
+used between GoogleTest and the rest of your project, so issues associated with
+using incompatible libraries (eg debug/release), etc. are avoided. This is
+particularly useful on Windows. Making GoogleTest's source code available to the
+main build can be done a few different ways:
+
+*   Download the GoogleTest source code manually and place it at a known
+    location. This is the least flexible approach and can make it more difficult
+    to use with continuous integration systems, etc.
+*   Embed the GoogleTest source code as a direct copy in the main project's
+    source tree. This is often the simplest approach, but is also the hardest to
+    keep up to date. Some organizations may not permit this method.
+*   Add GoogleTest as a git submodule or equivalent. This may not always be
+    possible or appropriate. Git submodules, for example, have their own set of
+    advantages and drawbacks.
+*   Use CMake to download GoogleTest as part of the build's configure step. This
+    approach doesn't have the limitations of the other methods.
+
+The last of the above methods is implemented with a small piece of CMake code
+that downloads and pulls the GoogleTest code into the main build.
+
+Just add to your `CMakeLists.txt`:
+
+```cmake
+include(FetchContent)
+FetchContent_Declare(
+  googletest
+  # Specify the commit you depend on and update it regularly.
+  URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
+)
+# For Windows: Prevent overriding the parent project's compiler/linker settings
+set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+FetchContent_MakeAvailable(googletest)
+
+# Now simply link against gtest or gtest_main as needed. Eg
+add_executable(example example.cpp)
+target_link_libraries(example gtest_main)
+add_test(NAME example_test COMMAND example)
+```
+
+Note that this approach requires CMake 3.14 or later due to its use of the
+`FetchContent_MakeAvailable()` command.
+
+##### Visual Studio Dynamic vs Static Runtimes
+
+By default, new Visual Studio projects link the C runtimes dynamically but
+GoogleTest links them statically. This will generate an error that looks
+something like the following: gtest.lib(gtest-all.obj) : error LNK2038: mismatch
+detected for 'RuntimeLibrary': value 'MTd_StaticDebug' doesn't match value
+'MDd_DynamicDebug' in main.obj
+
+GoogleTest already has a CMake option for this: `gtest_force_shared_crt`
+
+Enabling this option will make gtest link the runtimes dynamically too, and
+match the project in which it is included.
+
+#### C++ Standard Version
+
+An environment that supports C++11 is required in order to successfully build
+GoogleTest. One way to ensure this is to specify the standard in the top-level
+project, for example by using the `set(CMAKE_CXX_STANDARD 11)` command. If this
+is not feasible, for example in a C project using GoogleTest for validation,
+then it can be specified by adding it to the options for cmake via the
+`DCMAKE_CXX_FLAGS` option.
+
+### Tweaking GoogleTest
+
+GoogleTest can be used in diverse environments. The default configuration may
+not work (or may not work well) out of the box in some environments. However,
+you can easily tweak GoogleTest by defining control macros on the compiler
+command line. Generally, these macros are named like `GTEST_XYZ` and you define
+them to either 1 or 0 to enable or disable a certain feature.
+
+We list the most frequently used macros below. For a complete list, see file
+[include/gtest/internal/gtest-port.h](https://github.com/google/googletest/blob/master/googletest/include/gtest/internal/gtest-port.h).
+
+### Multi-threaded Tests
+
+GoogleTest is thread-safe where the pthread library is available. After
+`#include "gtest/gtest.h"`, you can check the
+`GTEST_IS_THREADSAFE` macro to see whether this is the case (yes if the macro is
+`#defined` to 1, no if it's undefined.).
+
+If GoogleTest doesn't correctly detect whether pthread is available in your
+environment, you can force it with
 
 
     -DGTEST_HAS_PTHREAD=1
     -DGTEST_HAS_PTHREAD=1
 
 
@@ -183,26 +158,24 @@ or
 
 
     -DGTEST_HAS_PTHREAD=0
     -DGTEST_HAS_PTHREAD=0
 
 
-When Google Test uses pthread, you may need to add flags to your
-compiler and/or linker to select the pthread library, or you'll get
-link errors.  If you use the CMake script or the deprecated Autotools
-script, this is taken care of for you.  If you use your own build
-script, you'll need to read your compiler and linker's manual to
-figure out what flags to add.
+When GoogleTest uses pthread, you may need to add flags to your compiler and/or
+linker to select the pthread library, or you'll get link errors. If you use the
+CMake script, this is taken care of for you. If you use your own build script,
+you'll need to read your compiler and linker's manual to figure out what flags
+to add.
 
 
-### As a Shared Library (DLL) ###
+### As a Shared Library (DLL)
 
 
-Google Test is compact, so most users can build and link it as a
-static library for the simplicity.  You can choose to use Google Test
-as a shared library (known as a DLL on Windows) if you prefer.
+GoogleTest is compact, so most users can build and link it as a static library
+for the simplicity. You can choose to use GoogleTest as a shared library (known
+as a DLL on Windows) if you prefer.
 
 
 To compile *gtest* as a shared library, add
 To compile *gtest* as a shared library, add
 
 
     -DGTEST_CREATE_SHARED_LIBRARY=1
     -DGTEST_CREATE_SHARED_LIBRARY=1
 
 
-to the compiler flags.  You'll also need to tell the linker to produce
-a shared library instead - consult your linker's manual for how to do
-it.
+to the compiler flags. You'll also need to tell the linker to produce a shared
+library instead - consult your linker's manual for how to do it.
 
 
 To compile your *tests* that use the gtest shared library, add
 To compile your *tests* that use the gtest shared library, add
 
 
@@ -210,31 +183,28 @@ To compile your *tests* that use the gtest shared library, add
 
 
 to the compiler flags.
 to the compiler flags.
 
 
-Note: while the above steps aren't technically necessary today when
-using some compilers (e.g. GCC), they may become necessary in the
-future, if we decide to improve the speed of loading the library (see
-<http://gcc.gnu.org/wiki/Visibility> for details).  Therefore you are
-recommended to always add the above flags when using Google Test as a
-shared library.  Otherwise a future release of Google Test may break
-your build script.
+Note: while the above steps aren't technically necessary today when using some
+compilers (e.g. GCC), they may become necessary in the future, if we decide to
+improve the speed of loading the library (see
+<http://gcc.gnu.org/wiki/Visibility> for details). Therefore you are recommended
+to always add the above flags when using GoogleTest as a shared library.
+Otherwise a future release of GoogleTest may break your build script.
 
 
-### Avoiding Macro Name Clashes ###
+### Avoiding Macro Name Clashes
 
 
-In C++, macros don't obey namespaces.  Therefore two libraries that
-both define a macro of the same name will clash if you `#include` both
-definitions.  In case a Google Test macro clashes with another
-library, you can force Google Test to rename its macro to avoid the
-conflict.
+In C++, macros don't obey namespaces. Therefore two libraries that both define a
+macro of the same name will clash if you `#include` both definitions. In case a
+GoogleTest macro clashes with another library, you can force GoogleTest to
+rename its macro to avoid the conflict.
 
 
-Specifically, if both Google Test and some other code define macro
-FOO, you can add
+Specifically, if both GoogleTest and some other code define macro FOO, you can
+add
 
 
     -DGTEST_DONT_DEFINE_FOO=1
     -DGTEST_DONT_DEFINE_FOO=1
 
 
-to the compiler flags to tell Google Test to change the macro's name
-from `FOO` to `GTEST_FOO`.  Currently `FOO` can be `FAIL`, `SUCCEED`,
-or `TEST`.  For example, with `-DGTEST_DONT_DEFINE_TEST=1`, you'll
-need to write
+to the compiler flags to tell GoogleTest to change the macro's name from `FOO`
+to `GTEST_FOO`. Currently `FOO` can be `FAIL`, `SUCCEED`, or `TEST`. For
+example, with `-DGTEST_DONT_DEFINE_TEST=1`, you'll need to write
 
 
     GTEST_TEST(SomeTest, DoesThis) { ... }
     GTEST_TEST(SomeTest, DoesThis) { ... }
 
 
@@ -243,38 +213,3 @@ instead of
     TEST(SomeTest, DoesThis) { ... }
     TEST(SomeTest, DoesThis) { ... }
 
 
 in order to define a test.
 in order to define a test.
-
-## Developing Google Test ##
-
-This section discusses how to make your own changes to Google Test.
-
-### Testing Google Test Itself ###
-
-To make sure your changes work as intended and don't break existing
-functionality, you'll want to compile and run Google Test's own tests.
-For that you can use CMake:
-
-    mkdir mybuild
-    cd mybuild
-    cmake -Dgtest_build_tests=ON ${GTEST_DIR}
-
-Make sure you have Python installed, as some of Google Test's tests
-are written in Python.  If the cmake command complains about not being
-able to find Python (`Could NOT find PythonInterp (missing:
-PYTHON_EXECUTABLE)`), try telling it explicitly where your Python
-executable can be found:
-
-    cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR}
-
-Next, you can build Google Test and all of its own tests.  On \*nix,
-this is usually done by 'make'.  To run the tests, do
-
-    make test
-
-All tests should pass.
-
-Normally you don't need to worry about regenerating the source files,
-unless you need to modify them.  In that case, you should modify the
-corresponding .pump files instead and run the pump.py Python script to
-regenerate them.  You can find pump.py in the [scripts/](scripts/) directory.
-Read the [Pump manual](docs/PumpManual.md) for how to use it.

+ 9 - 0
contrib/gtest/cmake/Config.cmake.in

@@ -0,0 +1,9 @@
+@PACKAGE_INIT@
+include(CMakeFindDependencyMacro)
+if (@GTEST_HAS_PTHREAD@)
+  set(THREADS_PREFER_PTHREAD_FLAG @THREADS_PREFER_PTHREAD_FLAG@)
+  find_dependency(Threads)
+endif()
+
+include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
+check_required_components("@project_name@")

部分文件因文件數量過多而無法顯示