Kaynağa Gözat

Merge branch 'master' into master

thomasbiang 4 yıl önce
ebeveyn
işleme
d7cf7847ba
100 değiştirilmiş dosya ile 5714 ekleme ve 7391 silme
  1. 0 1
      .github/FUNDING.yml
  2. 74 10
      .github/workflows/ccpp.yml
  3. 1 1
      .github/workflows/sanitizer.yml
  4. 0 3
      AssimpBuildTreeSettings.cmake.in
  5. 0 11
      AssimpConfigVersion.cmake.in
  6. 104 118
      CMakeLists.txt
  7. 8 7
      Readme.md
  8. 0 48
      assimp-config-version.cmake.in
  9. 0 1
      assimp-config.cmake.in
  10. 0 126
      assimpTargets-debug.cmake.in
  11. 0 127
      assimpTargets-release.cmake.in
  12. 0 91
      assimpTargets.cmake.in
  13. 1 1
      cmake-modules/FindRT.cmake
  14. 15 16
      cmake/HunterGate.cmake
  15. 2 2
      cmake/assimp-hunter-config.cmake.in
  16. 9 0
      cmake/assimp-plain-config.cmake.in
  17. 0 707
      code/AMF/AMFImporter.cpp
  18. 7 2
      code/AssetLib/3DS/3DSExporter.cpp
  19. 7 2
      code/AssetLib/3DS/3DSHelper.h
  20. 2 2
      code/AssetLib/3DS/3DSLoader.cpp
  21. 3 1
      code/AssetLib/3MF/3MFXmlTags.h
  22. 14 30
      code/AssetLib/3MF/D3MFExporter.cpp
  23. 6 4
      code/AssetLib/3MF/D3MFExporter.h
  24. 353 208
      code/AssetLib/3MF/D3MFImporter.cpp
  25. 35 29
      code/AssetLib/3MF/D3MFOpcPackage.cpp
  26. 2 7
      code/AssetLib/3MF/D3MFOpcPackage.h
  27. 78 13
      code/AssetLib/AC/ACLoader.cpp
  28. 31 4
      code/AssetLib/AC/ACLoader.h
  29. 165 298
      code/AssetLib/AMF/AMFImporter.cpp
  30. 177 298
      code/AssetLib/AMF/AMFImporter.hpp
  31. 179 247
      code/AssetLib/AMF/AMFImporter_Geometry.cpp
  32. 0 2
      code/AssetLib/AMF/AMFImporter_Macro.hpp
  33. 149 148
      code/AssetLib/AMF/AMFImporter_Material.cpp
  34. 116 150
      code/AssetLib/AMF/AMFImporter_Node.hpp
  35. 176 156
      code/AssetLib/AMF/AMFImporter_Postprocess.cpp
  36. 1 1
      code/AssetLib/ASE/ASELoader.cpp
  37. 4 4
      code/AssetLib/Assbin/AssbinFileWriter.cpp
  38. 9 5
      code/AssetLib/Assjson/cencode.c
  39. 2 2
      code/AssetLib/Assjson/cencode.h
  40. 2 2
      code/AssetLib/B3D/B3DImporter.cpp
  41. 19 18
      code/AssetLib/BVH/BVHLoader.cpp
  42. 2 1
      code/AssetLib/BVH/BVHLoader.h
  43. 1 1
      code/AssetLib/Blender/BlenderCustomData.cpp
  44. 4 13
      code/AssetLib/Blender/BlenderDNA.cpp
  45. 6 6
      code/AssetLib/Blender/BlenderDNA.h
  46. 22 34
      code/AssetLib/Blender/BlenderDNA.inl
  47. 2 3
      code/AssetLib/Blender/BlenderLoader.cpp
  48. 5 38
      code/AssetLib/Blender/BlenderLoader.h
  49. 5 2
      code/AssetLib/Blender/BlenderScene.h
  50. 7 1
      code/AssetLib/Blender/BlenderTessellator.cpp
  51. 1 1
      code/AssetLib/COB/COBLoader.cpp
  52. 1 1
      code/AssetLib/CSM/CSMLoader.cpp
  53. 1 1
      code/AssetLib/Collada/ColladaExporter.cpp
  54. 3 4
      code/AssetLib/Collada/ColladaHelper.cpp
  55. 109 119
      code/AssetLib/Collada/ColladaHelper.h
  56. 49 52
      code/AssetLib/Collada/ColladaLoader.cpp
  57. 890 1320
      code/AssetLib/Collada/ColladaParser.cpp
  58. 66 111
      code/AssetLib/Collada/ColladaParser.h
  59. 1 1
      code/AssetLib/DXF/DXFLoader.cpp
  60. 20 4
      code/AssetLib/FBX/FBXBinaryTokenizer.cpp
  61. 158 125
      code/AssetLib/FBX/FBXConverter.cpp
  62. 4 3
      code/AssetLib/FBX/FBXConverter.h
  63. 0 35
      code/AssetLib/FBX/FBXDocument.h
  64. 3 3
      code/AssetLib/FBX/FBXDocumentUtil.cpp
  65. 76 17
      code/AssetLib/FBX/FBXExporter.cpp
  66. 10 1
      code/AssetLib/FBX/FBXImporter.cpp
  67. 1 1
      code/AssetLib/FBX/FBXMaterial.cpp
  68. 42 10
      code/AssetLib/FBX/FBXParser.cpp
  69. 34 2
      code/AssetLib/FBX/FBXProperties.cpp
  70. 1 1
      code/AssetLib/FBX/FBXTokenizer.cpp
  71. 9 11
      code/AssetLib/FBX/FBXUtil.cpp
  72. 7 14
      code/AssetLib/FBX/FBXUtil.h
  73. 3 3
      code/AssetLib/HMP/HMPLoader.cpp
  74. 9 0
      code/AssetLib/IFC/IFCReaderGen1_2x3.cpp
  75. 9 0
      code/AssetLib/IFC/IFCReaderGen2_2x3.cpp
  76. 7 2
      code/AssetLib/IFC/IFCReaderGen_2x3.h
  77. 1212 1226
      code/AssetLib/Irr/IRRLoader.cpp
  78. 11 22
      code/AssetLib/Irr/IRRLoader.h
  79. 426 446
      code/AssetLib/Irr/IRRMeshLoader.cpp
  80. 8 15
      code/AssetLib/Irr/IRRMeshLoader.h
  81. 215 329
      code/AssetLib/Irr/IRRShared.cpp
  82. 45 44
      code/AssetLib/Irr/IRRShared.h
  83. 3 3
      code/AssetLib/LWO/LWOLoader.cpp
  84. 11 6
      code/AssetLib/LWS/LWSLoader.cpp
  85. 5 2
      code/AssetLib/M3D/M3DExporter.cpp
  86. 5 5
      code/AssetLib/M3D/M3DImporter.cpp
  87. 3 0
      code/AssetLib/M3D/M3DWrapper.cpp
  88. 423 421
      code/AssetLib/M3D/m3d.h
  89. 1 1
      code/AssetLib/MD2/MD2Loader.cpp
  90. 1 1
      code/AssetLib/MD3/MD3Loader.cpp
  91. 1 1
      code/AssetLib/MD5/MD5Loader.cpp
  92. 1 1
      code/AssetLib/MDC/MDCLoader.cpp
  93. 4 4
      code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp
  94. 2 2
      code/AssetLib/MDL/HalfLife/HL1MDLLoader.h
  95. 3 3
      code/AssetLib/MDL/MDLLoader.cpp
  96. 2 2
      code/AssetLib/MMD/MMDImporter.cpp
  97. 2 2
      code/AssetLib/MMD/MMDPmxParser.cpp
  98. 1 1
      code/AssetLib/MS3D/MS3DLoader.cpp
  99. 7 7
      code/AssetLib/NFF/NFFLoader.cpp
  100. 3 3
      code/AssetLib/NFF/NFFLoader.h

+ 0 - 1
.github/FUNDING.yml

@@ -1,3 +1,2 @@
 patreon: assimp
 patreon: assimp
 custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4
 custom: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4
-open_collective: assimp

+ 74 - 10
.github/workflows/ccpp.yml

@@ -8,30 +8,39 @@ on:
 
 
 jobs:
 jobs:
   job:
   job:
-    name: ${{ matrix.os }}-${{ matrix.cxx }}-build-and-test
+    name: ${{ matrix.name }}-build-and-test
     runs-on: ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
     strategy:
     strategy:
       fail-fast: false
       fail-fast: false
       matrix:
       matrix:
-        name: [ubuntu-gcc, macos-clang, windows-msvc, ubuntu-clang]
+        name: [ubuntu-latest-g++, macos-latest-clang++, windows-latest-cl.exe, ubuntu-latest-clang++, ubuntu-gcc-hunter, macos-clang-hunter, windows-msvc-hunter]
         # For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
         # For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
         include:
         include:
-          - name: windows-msvc
+          - name: windows-latest-cl.exe
             os: windows-latest
             os: windows-latest
             cxx: cl.exe
             cxx: cl.exe
             cc: cl.exe
             cc: cl.exe
-          - name: ubuntu-clang
+          - name: ubuntu-latest-clang++
             os: ubuntu-latest
             os: ubuntu-latest
             cxx: clang++
             cxx: clang++
             cc: clang
             cc: clang
-          - name: macos-clang
+          - name: macos-latest-clang++
             os: macos-latest
             os: macos-latest
             cxx: clang++
             cxx: clang++
             cc: clang
             cc: clang
-          - name: ubuntu-gcc
+          - name: ubuntu-latest-g++
             os: ubuntu-latest
             os: ubuntu-latest
             cxx: g++
             cxx: g++
             cc: gcc
             cc: gcc
+          - name: ubuntu-gcc-hunter
+            os: ubuntu-latest
+            toolchain: ninja-gcc-cxx17-fpic
+          - name: macos-clang-hunter
+            os: macos-latest
+            toolchain: ninja-clang-cxx17-fpic
+          - name: windows-msvc-hunter
+            os: windows-latest
+            toolchain: ninja-vs-win64-cxx17
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
@@ -40,20 +49,75 @@ jobs:
     
     
     - uses: ilammy/msvc-dev-cmd@v1
     - uses: ilammy/msvc-dev-cmd@v1
     
     
-    - uses: lukka/set-shell-env@v1
+    - name: Set Compiler Environment
+      if: "!endsWith(matrix.name, 'hunter')"
+      uses: lukka/set-shell-env@v1
       with:
       with:
         CXX: ${{ matrix.cxx }}
         CXX: ${{ matrix.cxx }}
         CC: ${{ matrix.cc }}
         CC: ${{ matrix.cc }}
+
+    - name: Set Compiler Environment for Hunter on Windows
+      if: startsWith(matrix.name, 'windows') && endsWith(matrix.name, 'hunter')
+      uses: lukka/set-shell-env@v1
+      with:
+        VS160COMNTOOLS: C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools
+
+    - name: Checkout Hunter toolchains
+      if: endsWith(matrix.name, 'hunter')
+      uses: actions/checkout@v2
+      with:
+        repository: cpp-pm/polly
+        path: cmake/polly     
+
+    - name: Cache DX SDK
+      id: dxcache
+      if: contains(matrix.name, 'windows')
+      uses: actions/cache@v2
+      with:
+        path: '${{ github.workspace }}/DX_SDK'
+        key: ${{ runner.os }}-DX_SDK
+        restore-keys: |
+          ${{ runner.os }}-DX_SDK
+
+    - name: Download DXSetup
+      if: contains(matrix.name, 'windows') && steps.dxcache.outputs.cache-hit != 'true'
+      run: |
+        curl -s -o DXSDK_Jun10.exe --location https://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe
+        cmd.exe /c start /wait .\DXSDK_Jun10.exe /U /O /F /S /P "${{ github.workspace }}\DX_SDK"
+
+    - name: Set Windows specific CMake arguments
+      if: contains(matrix.name, 'windows')
+      id: windows_extra_cmake_args
+      run: echo "::set-output name=args::-DASSIMP_BUILD_ASSIMP_TOOLS=1 -DASSIMP_BUILD_ASSIMP_VIEW=1"
     
     
+    - name: Set Hunter specific CMake arguments
+      if: contains(matrix.name, 'hunter')
+      id: hunter_extra_cmake_args
+      run: echo "::set-output name=args::-DBUILD_SHARED_LIBS=OFF -DASSIMP_HUNTER_ENABLED=ON -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/cmake/polly/${{ matrix.toolchain }}.cmake"
+
     - name: configure and build
     - name: configure and build
-      uses: lukka/run-cmake@v2
+      uses: lukka/run-cmake@v3
+      env:
+        DXSDK_DIR: '${{ github.workspace }}/DX_SDK'
+
       with:
       with:
         cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
         cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
         cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
         cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
-        cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release'
+        cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release ${{ steps.windows_extra_cmake_args.outputs.args }} ${{ steps.hunter_extra_cmake_args.outputs.args }}'
         buildWithCMakeArgs: '-- -v'
         buildWithCMakeArgs: '-- -v'
         buildDirectory: '${{ github.workspace }}/build/'
         buildDirectory: '${{ github.workspace }}/build/'
         
         
+    - name: Exclude certain tests in Hunter specific builds
+      if: contains(matrix.name, 'hunter')
+      id: hunter_extra_test_args
+      run: echo "::set-output name=args::--gtest_filter=-utOpenGEXImportExport.Importissue1340_EmptyCameraObject:utColladaZaeImportExport.importBlenFromFileTest"
+
     - name: test
     - name: test
-      run: cd build/bin && ./unit
+      run: cd build/bin && ./unit ${{ steps.hunter_extra_test_args.outputs.args }}
       shell: bash
       shell: bash
+
+    - uses: actions/upload-artifact@v2
+      if: matrix.name == 'windows-msvc'
+      with:
+        name: 'assimp-bins-${{ matrix.name }}-${{ github.sha }}'
+        path: build/bin

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

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

+ 0 - 3
AssimpBuildTreeSettings.cmake.in

@@ -1,3 +0,0 @@
-set(ASSIMP_INCLUDE_DIRS
-  "@PROJECT_SOURCE_DIR@"
-  "@PROJECT_BINARY_DIR@")

+ 0 - 11
AssimpConfigVersion.cmake.in

@@ -1,11 +0,0 @@
-set(ASSIMP_PACKAGE_VERSION "@ASSIMP_SOVERSION@")
-
-# Check whether the requested PACKAGE_FIND_VERSION is compatible
-if("${ASSIMP_PACKAGE_VERSION}" VERSION_LESS "${ASSIMP_PACKAGE_FIND_VERSION}")
-  set(ASSIMP_PACKAGE_VERSION_COMPATIBLE FALSE)
-else()
-  set(ASSIMP_PACKAGE_VERSION_COMPATIBLE TRUE)
-  if ("${ASSIMP_PACKAGE_VERSION}" VERSION_EQUAL "${ASSIMP_PACKAGE_FIND_VERSION}")
-    set(ASSIMP_PACKAGE_VERSION_EXACT TRUE)
-  endif()
-endif()

+ 104 - 118
CMakeLists.txt

@@ -34,7 +34,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #----------------------------------------------------------------------
 #----------------------------------------------------------------------
+SET(CMAKE_POLICY_DEFAULT_CMP0012 NEW)
 SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW)
 SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW)
+SET(CMAKE_POLICY_DEFAULT_CMP0092 NEW)
 
 
 CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
 CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
 
 
@@ -44,8 +46,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
 IF(ASSIMP_HUNTER_ENABLED)
 IF(ASSIMP_HUNTER_ENABLED)
   include("cmake/HunterGate.cmake")
   include("cmake/HunterGate.cmake")
   HunterGate(
   HunterGate(
-    URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz"
-    SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a"
+    URL "https://github.com/cpp-pm/hunter/archive/v0.23.269.tar.gz"
+    SHA1 "64024b7b95b4c86d50ae05b926814448c93a70a0"
   )
   )
 
 
   add_definitions(-DASSIMP_USE_HUNTER)
   add_definitions(-DASSIMP_USE_HUNTER)
@@ -116,10 +118,6 @@ OPTION ( ASSIMP_UBSAN
   "Enable Undefined Behavior sanitizer."
   "Enable Undefined Behavior sanitizer."
   OFF
   OFF
 )
 )
-OPTION ( ASSIMP_SYSTEM_IRRXML
-  "Use system installed Irrlicht/IrrXML library."
-  OFF
-)
 OPTION ( ASSIMP_BUILD_DOCS
 OPTION ( ASSIMP_BUILD_DOCS
   "Build documentation using Doxygen."
   "Build documentation using Doxygen."
   OFF
   OFF
@@ -135,8 +133,8 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
 )
 )
 
 
 IF ( WIN32 )
 IF ( WIN32 )
-    OPTION ( ASSIMP_BUILD_ASSIMP_VIEW 
-      "If the Assimp view tool is built. (requires DirectX)" 
+    OPTION ( ASSIMP_BUILD_ASSIMP_VIEW
+      "If the Assimp view tool is built. (requires DirectX)"
       OFF )
       OFF )
 ENDIF()
 ENDIF()
 
 
@@ -213,7 +211,7 @@ IF(NOT GIT_COMMIT_HASH)
 ENDIF()
 ENDIF()
 
 
 IF(ASSIMP_DOUBLE_PRECISION)
 IF(ASSIMP_DOUBLE_PRECISION)
-    ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
+  ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
 ENDIF()
 ENDIF()
 
 
 CONFIGURE_FILE(
 CONFIGURE_FILE(
@@ -252,18 +250,28 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
   ENDIF()
   ENDIF()
   # hide all not-exported symbols
   # hide all not-exported symbols
-  SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
-  SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
-  SET(LIBSTDC++_LIBRARIES -lstdc++)
+  IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" )
+	SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
+	SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
+	SET(LIBSTDC++_LIBRARIES -lstdc++)
+  ELSE()
+	SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
+	SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
+	SET(LIBSTDC++_LIBRARIES -lstdc++)
+  ENDIF()
 ELSEIF(MSVC)
 ELSEIF(MSVC)
   # enable multi-core compilation with MSVC
   # enable multi-core compilation with MSVC
-  ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX ) 
+  IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) # clang-cl
+    ADD_COMPILE_OPTIONS(/bigobj /W4 /WX )
+  ELSE() # msvc
+    ADD_COMPILE_OPTIONS(/MP /bigobj /W4 /WX)
+  ENDIF()
   # disable "elements of array '' will be default initialized" warning on MSVC2013
   # disable "elements of array '' will be default initialized" warning on MSVC2013
   IF(MSVC12)
   IF(MSVC12)
     ADD_COMPILE_OPTIONS(/wd4351)
     ADD_COMPILE_OPTIONS(/wd4351)
   ENDIF()
   ENDIF()
   SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
   SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
-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 11)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
@@ -321,26 +329,27 @@ ENDIF()
 
 
 IF (ASSIMP_UBSAN)
 IF (ASSIMP_UBSAN)
   MESSAGE(STATUS "Undefined Behavior sanitizer enabled")
   MESSAGE(STATUS "Undefined Behavior sanitizer enabled")
-  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
-  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all")
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin -fno-sanitize-recover=all")
 ENDIF()
 ENDIF()
 
 
 INCLUDE (FindPkgMacros)
 INCLUDE (FindPkgMacros)
 INCLUDE (PrecompiledHeader)
 INCLUDE (PrecompiledHeader)
 
 
-# If this is an in-source build (CMAKE_SOURCE_DIR == CMAKE_BINARY_DIR),
-# write the library/executable files to the respective directories in the
-# source tree. During an out-of-source build, however, do not litter this
-# directory, since that is probably what the user wanted to avoid.
-IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
-  SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
-  SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
-  SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
-ELSE()
-  SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
-  SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
-  SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
-ENDIF ()
+# Set Assimp project output directory variables.
+SET(ASSIMP_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
+SET(ASSIMP_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
+SET(ASSIMP_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
+
+# Macro used to set the output directories of a target to the
+# respective Assimp output directories.
+MACRO(TARGET_USE_COMMON_OUTPUT_DIRECTORY target)
+  set_target_properties(${target} PROPERTIES
+      RUNTIME_OUTPUT_DIRECTORY ${ASSIMP_RUNTIME_OUTPUT_DIRECTORY}
+      LIBRARY_OUTPUT_DIRECTORY ${ASSIMP_LIBRARY_OUTPUT_DIRECTORY}
+      ARCHIVE_OUTPUT_DIRECTORY ${ASSIMP_ARCHIVE_OUTPUT_DIRECTORY}
+  )
+ENDMACRO()
 
 
 get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
 get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
 
 
@@ -351,110 +360,90 @@ ELSE()
 ENDIF()
 ENDIF()
 
 
 # Only generate this target if no higher-level project already has
 # Only generate this target if no higher-level project already has
-IF (NOT TARGET uninstall)
+IF (NOT TARGET uninstall AND ASSIMP_INSTALL)
   # add make uninstall capability
   # add make uninstall capability
   CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
   CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
   ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
   ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
 ENDIF()
 ENDIF()
 
 
-IF(ASSIMP_HUNTER_ENABLED)
-  set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
-  set(INCLUDE_INSTALL_DIR "include")
+# cmake configuration files
+if(${BUILD_SHARED_LIBS})
+  set(BUILD_LIB_TYPE SHARED)
+else()
+  set(BUILD_LIB_TYPE STATIC)
+endif()
 
 
-  set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
+IF( UNIX )
+  # Use GNUInstallDirs for Unix predefined directories
+  INCLUDE(GNUInstallDirs)
 
 
-  # Configuration
-  set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
-  set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
-  set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
-  set(NAMESPACE "${PROJECT_NAME}::")
+  SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
+  SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
+  SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
+ELSE()
+  # Cache these to allow the user to override them on non-Unix platforms
+  SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
+    "Path the built library files are installed to." )
+  SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
+    "Path the header files are installed to." )
+  SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
+    "Path the tool executables are installed to." )
+
+  SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR})
+  SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR})
+  SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR})
+ENDIF()
 
 
-  # Include module with fuction 'write_basic_package_version_file'
-  include(CMakePackageConfigHelpers)
+set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
 
 
-  # Note: PROJECT_VERSION is used as a VERSION
-  write_basic_package_version_file("${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion)
+IF(ASSIMP_HUNTER_ENABLED)
+  set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
+  set(CMAKE_CONFIG_TEMPLATE_FILE "cmake/assimp-hunter-config.cmake.in")
+  set(NAMESPACE "${PROJECT_NAME}::")
+  set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
+  set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
+  set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
+ELSE()
+  set(CONFIG_INSTALL_DIR "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
+  set(CMAKE_CONFIG_TEMPLATE_FILE "cmake/assimp-plain-config.cmake.in")
+  string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWERCASE)
+  set(NAMESPACE "${PROJECT_NAME_LOWERCASE}::")
+  set(TARGETS_EXPORT_NAME "${PROJECT_NAME_LOWERCASE}Targets")
+  set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME_LOWERCASE}ConfigVersion.cmake")
+  set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME_LOWERCASE}Config.cmake")
+ENDIF()
 
 
-  # Use variables:
-  #   * TARGETS_EXPORT_NAME
-  #   * PROJECT_NAME
-  configure_package_config_file(
-      "cmake/assimp-hunter-config.cmake.in"
-      "${PROJECT_CONFIG}"
-      INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
-  )
+set(INCLUDE_INSTALL_DIR "include")
 
 
-  install(
-      FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
-      DESTINATION "${CONFIG_INSTALL_DIR}"
-  )
+# Include module with fuction 'write_basic_package_version_file'
+include(CMakePackageConfigHelpers)
 
 
-  install(
-      EXPORT "${TARGETS_EXPORT_NAME}"
-      NAMESPACE "${NAMESPACE}"
-      DESTINATION "${CONFIG_INSTALL_DIR}"
-  )
-ELSE()
-  # cmake configuration files
-  if(${BUILD_SHARED_LIBS})
-    set(BUILD_LIB_TYPE SHARED)
-  else()
-    set(BUILD_LIB_TYPE STATIC)
-  endif()
+# Note: PROJECT_VERSION is used as a VERSION
+write_basic_package_version_file("${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion)
 
 
-  IF( UNIX )
-    # Use GNUInstallDirs for Unix predefined directories
-    INCLUDE(GNUInstallDirs)
+configure_package_config_file(
+    ${CMAKE_CONFIG_TEMPLATE_FILE}
+    "${PROJECT_CONFIG}"
+    INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
+)
 
 
-    SET( ASSIMP_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR})
-    SET( ASSIMP_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR})
-    SET( ASSIMP_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR})
-  ELSE()
-    # Cache these to allow the user to override them on non-Unix platforms
-    SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE STRING
-      "Path the built library files are installed to." )
-    SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
-      "Path the header files are installed to." )
-    SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
-      "Path the tool executables are installed to." )
-
-    SET(CMAKE_INSTALL_FULL_INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_INCLUDE_INSTALL_DIR})
-    SET(CMAKE_INSTALL_FULL_LIBDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR})
-    SET(CMAKE_INSTALL_FULL_BINDIR ${CMAKE_INSTALL_PREFIX}/${ASSIMP_BIN_INSTALL_DIR})
-  ENDIF()
+install(
+    FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
+    DESTINATION "${CONFIG_INSTALL_DIR}"
+    COMPONENT ${LIBASSIMP-DEV_COMPONENT}
+)
 
 
-  CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
-  CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
-  IF (is_multi_config)
-    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in"   "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
-    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
-    SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake")
-  ELSEIF (CMAKE_BUILD_TYPE STREQUAL Debug)
-    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in"   "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
-    SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake")
-  ELSE()
-    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
-    SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake")
-  ENDIF()
-  CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
-  #we should generated these scripts after CMake VERSION 3.0.2 using export(EXPORT ...) and write_basic_package_version_file(...)
-  INSTALL(FILES
-    "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake"
-    "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake"
-    "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake"
-    ${PACKAGE_TARGETS_FILE}
-    DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
-ENDIF()
+install(
+    EXPORT "${TARGETS_EXPORT_NAME}"
+    NAMESPACE "${NAMESPACE}"
+    DESTINATION "${CONFIG_INSTALL_DIR}"
+    COMPONENT ${LIBASSIMP-DEV_COMPONENT}
+)
 
 
 IF( ASSIMP_BUILD_DOCS )
 IF( ASSIMP_BUILD_DOCS )
   ADD_SUBDIRECTORY(doc)
   ADD_SUBDIRECTORY(doc)
 ENDIF()
 ENDIF()
 
 
-# Look for system installed irrXML
-IF ( ASSIMP_SYSTEM_IRRXML )
-  FIND_PACKAGE( IrrXML REQUIRED )
-ENDIF()
-
 # Search for external dependencies, and build them from source if not found
 # Search for external dependencies, and build them from source if not found
 # Search for zlib
 # Search for zlib
 IF(ASSIMP_HUNTER_ENABLED)
 IF(ASSIMP_HUNTER_ENABLED)
@@ -581,10 +570,6 @@ ELSE ()
   ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
   ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER )
 ENDIF ()
 ENDIF ()
 
 
-IF(NOT ASSIMP_HUNTER_ENABLED)
-  ADD_SUBDIRECTORY(contrib)
-ENDIF()
-
 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
@@ -679,7 +664,8 @@ if(WIN32)
   ENDIF()
   ENDIF()
 
 
   IF(MSVC_TOOLSET_VERSION)
   IF(MSVC_TOOLSET_VERSION)
-    set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
+    SET(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
+    SET(ASSIMP_MSVC_VERSION ${MCVS_PREFIX})
   ELSE()
   ELSE()
     IF(MSVC12)
     IF(MSVC12)
       SET(ASSIMP_MSVC_VERSION "vc120")
       SET(ASSIMP_MSVC_VERSION "vc120")

+ 8 - 7
Readme.md

@@ -4,8 +4,6 @@ A library to import and export various 3d-model-formats including scene-post-pro
 ### Current project status ###
 ### Current project status ###
 [![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp) 
 [![Financial Contributors on Open Collective](https://opencollective.com/assimp/all/badge.svg?label=financial+contributors)](https://opencollective.com/assimp) 
 ![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg)
 ![C/C++ CI](https://github.com/assimp/assimp/workflows/C/C++%20CI/badge.svg)
-[![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp)
-[![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
 <a href="https://scan.coverity.com/projects/5607">
 <a href="https://scan.coverity.com/projects/5607">
   <img alt="Coverity Scan Build Status"
   <img alt="Coverity Scan Build Status"
        src="https://scan.coverity.com/projects/5607/badge.svg"/>
        src="https://scan.coverity.com/projects/5607/badge.svg"/>
@@ -18,13 +16,16 @@ A library to import and export various 3d-model-formats including scene-post-pro
 <br>
 <br>
 
 
 APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
 APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
-
-[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/).
-
 Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
 Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
 
 
-This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
+### Latest Doc's ###
+Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/). 
 
 
+### Get involved ###
+This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
+<br>
+You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs).
+<br>
 Please check our Wiki as well: https://github.com/assimp/assimp/wiki
 Please check our Wiki as well: https://github.com/assimp/assimp/wiki
 
 
 If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
 If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
@@ -72,7 +73,7 @@ The source code is organized in the following way:
 For more information, visit [our website](http://assimp.org/). Or check out the `./doc`- folder, which contains the official documentation in HTML format.
 For more information, visit [our website](http://assimp.org/). Or check out the `./doc`- folder, which contains the official documentation in HTML format.
 (CHMs for Windows are included in some release packages and should be located right here in the root folder).
 (CHMs for Windows are included in some release packages and should be located right here in the root folder).
 
 
-If the docs don't solve your problem, ask on [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
+If the docs don't solve your problem, ask on [StackOverflow with the assimp-tag](http://stackoverflow.com/questions/tagged/assimp?sort=newest). If you think you found a bug, please open an issue on Github.
 
 
 For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
 For development discussions, there is also a (very low-volume) mailing list, _assimp-discussions_
   [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions)
   [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions)

+ 0 - 48
assimp-config-version.cmake.in

@@ -1,48 +0,0 @@
-# Open Asset Import Library (assimp)
-# ----------------------------------------------------------------------
-# Copyright (c) 2006-2020, 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.
-#----------------------------------------------------------------------
-set( PACKAGE_VERSION "@ASSIMP_VERSION@" )
-if( "${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@ASSIMP_VERSION@")
-  set(PACKAGE_VERSION_EXACT 1)
-endif()
-if( "${PACKAGE_FIND_VERSION_MAJOR}.${PACKAGE_FIND_VERSION_MINOR}" EQUAL "@ASSIMP_VERSION@" )
-  set(PACKAGE_VERSION_COMPATIBLE 1)
-elseif( "${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@ASSIMP_VERSION_MAJOR@" )
-  # for now backward compatible if minor version is less
-  if( ${PACKAGE_FIND_VERSION_MINOR}  LESS @ASSIMP_VERSION_MINOR@ )
-    set(PACKAGE_VERSION_COMPATIBLE 1)
-  endif()
-endif()
-set( ASSIMP_STATIC_LIB "@ASSIMP_BUILD_STATIC_LIB@")

+ 0 - 1
assimp-config.cmake.in

@@ -1 +0,0 @@
-include(${CMAKE_CURRENT_LIST_DIR}/assimpTargets.cmake)

+ 0 - 126
assimpTargets-debug.cmake.in

@@ -1,126 +0,0 @@
-#----------------------------------------------------------------
-# Generated CMake target import file for configuration "Debug".
-#----------------------------------------------------------------
-
-# Commands may need to know the format version.
-set(CMAKE_IMPORT_FILE_VERSION 1)
-
-set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
-
-get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
-
-if(MSVC)
-  if(MSVC_TOOLSET_VERSION)
-    set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
-  else()
-    if( MSVC70 OR MSVC71 )
-      set(MSVC_PREFIX "vc70")
-    elseif( MSVC80 )
-      set(MSVC_PREFIX "vc80")
-    elseif( MSVC90 )
-      set(MSVC_PREFIX "vc90")
-    elseif( MSVC10 )
-      set(MSVC_PREFIX "vc100")
-    elseif( MSVC11 )
-      set(MSVC_PREFIX "vc110")
-    elseif( MSVC12 )
-      set(MSVC_PREFIX "vc120")
-    elseif( MSVC_VERSION LESS 1910)
-      set(MSVC_PREFIX "vc140")
-    elseif( MSVC_VERSION LESS 1920)
-      set(MSVC_PREFIX "vc141")
-    elseif( MSVC_VERSION LESS 1930)
-      set(MSVC_PREFIX "vc142")
-    else()
-      set(MSVC_PREFIX "vc150")
-    endif()
-  endif()
-  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
-
-  if(ASSIMP_BUILD_SHARED_LIBS)
-    set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
-    set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
-
-    # Import target "assimp::assimp" for configuration "Debug"
-    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
-    set_target_properties(assimp::assimp PROPERTIES
-      IMPORTED_IMPLIB_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}"
-      IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}"
-    )
-    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}")
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}" )
-  else()
-    set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
-
-    # Import target "assimp::assimp" for configuration "Debug"
-    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
-    set_target_properties(assimp::assimp PROPERTIES
-      IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
-    )
-    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}")
-  endif()
-
-else()
-  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
-  if(ASSIMP_BUILD_SHARED_LIBS)
-    if(WIN32)
-      # Handle MinGW compiler.
-      set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
-    elseif(APPLE)
-      set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
-    else()
-      set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
-    endif()
-
-    # Import target "assimp::assimp" for configuration "Debug"
-    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
-    set_target_properties(assimp::assimp PROPERTIES
-      IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
-      IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}"
-    )
-    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" )
-  else()
-    set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
-
-    # Import target "assimp::assimp" for configuration "Debug"
-    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
-    set_target_properties(assimp::assimp PROPERTIES
-      IMPORTED_LOCATION_DEBUG "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
-    )
-    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" )
-  endif()
-endif()
-
-# Commands beyond this point should not need to know the version.
-set(CMAKE_IMPORT_FILE_VERSION)
-
-get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
-set( ASSIMP_CXX_FLAGS ) # dynamically linked library
-set( ASSIMP_LINK_FLAGS "" )
-set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
-set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
-if(ASSIMP_BUILD_SHARED_LIBS)
-  set( ASSIMP_LIBRARIES ${sharedLibraryName})
-else()
-  set( ASSIMP_LIBRARIES ${staticLibraryName})
-endif()
-
-# for compatibility with pkg-config
-set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
-set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
-
-MARK_AS_ADVANCED(
-  ASSIMP_ROOT_DIR
-  ASSIMP_CXX_FLAGS
-  ASSIMP_LINK_FLAGS
-  ASSIMP_INCLUDE_DIRS
-  ASSIMP_LIBRARIES
-  ASSIMP_CFLAGS_OTHER
-  ASSIMP_LDFLAGS_OTHER
-  ASSIMP_LIBRARY_SUFFIX
-  ASSIMP_BUILD_SHARED_LIBS
-)

+ 0 - 127
assimpTargets-release.cmake.in

@@ -1,127 +0,0 @@
-#----------------------------------------------------------------
-# Generated CMake target import file for configuration "Release".
-#----------------------------------------------------------------
-
-# Commands may need to know the format version.
-set(CMAKE_IMPORT_FILE_VERSION 1)
-
-set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
-
-get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS)
-
-if(MSVC)
-  if(MSVC_TOOLSET_VERSION)
-    set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
-  else()
-    if( MSVC70 OR MSVC71 )
-      set(MSVC_PREFIX "vc70")
-    elseif( MSVC80 )
-      set(MSVC_PREFIX "vc80")
-    elseif( MSVC90 )
-      set(MSVC_PREFIX "vc90")
-    elseif( MSVC10 )
-      set(MSVC_PREFIX "vc100")
-    elseif( MSVC11 )
-      set(MSVC_PREFIX "vc110")
-    elseif( MSVC12 )
-      set(MSVC_PREFIX "vc120")
-    elseif( MSVC_VERSION LESS 1910)
-      set(MSVC_PREFIX "vc140")
-    elseif( MSVC_VERSION LESS 1920)
-      set(MSVC_PREFIX "vc141")
-    elseif( MSVC_VERSION LESS 1930)
-      set(MSVC_PREFIX "vc142")
-    else()
-      set(MSVC_PREFIX "vc150")
-    endif()
-  endif()
-  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
-
-  if(ASSIMP_BUILD_SHARED_LIBS)
-    set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
-    set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@")
-
-    # Import target "assimp::assimp" for configuration "Release"
-    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
-    set_target_properties(assimp::assimp PROPERTIES
-      IMPORTED_IMPLIB_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}"
-      IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}"
-    )
-    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${importLibraryName}")
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_BINDIR@/${sharedLibraryName}" )
-  else()
-    set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
-
-    # Import target "assimp::assimp" for configuration "Release"
-    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
-    set_target_properties(assimp::assimp PROPERTIES
-      IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
-    )
-    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}")
-  endif()
-
-else()
-  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
-  if(ASSIMP_BUILD_SHARED_LIBS)
-    if(WIN32)
-      # Handle MinGW compiler.
-      set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
-    elseif(APPLE)
-      set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
-    else()
-      set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
-    endif()
-
-    # Import target "assimp::assimp" for configuration "Release"
-    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
-    set_target_properties(assimp::assimp PROPERTIES
-      IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
-      IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}"
-    )
-    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${sharedLibraryName}" )
-  else()
-    set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@")
-
-    # Import target "assimp::assimp" for configuration "Release"
-    set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
-    set_target_properties(assimp::assimp PROPERTIES
-      IMPORTED_LOCATION_RELEASE "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}"
-    )
-    list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
-    list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "@CMAKE_INSTALL_FULL_LIBDIR@/${staticLibraryName}" )
-  endif()
-endif()
-
-# Commands beyond this point should not need to know the version.
-set(CMAKE_IMPORT_FILE_VERSION)
-
-get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
-
-set( ASSIMP_CXX_FLAGS ) # dynamically linked library
-set( ASSIMP_LINK_FLAGS "" )
-set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
-set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
-if(ASSIMP_BUILD_SHARED_LIBS)
-  set( ASSIMP_LIBRARIES ${sharedLibraryName})
-else()
-  set( ASSIMP_LIBRARIES ${staticLibraryName})
-endif()
-
-# for compatibility with pkg-config
-set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
-set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
-
-MARK_AS_ADVANCED(
-  ASSIMP_ROOT_DIR
-  ASSIMP_CXX_FLAGS
-  ASSIMP_LINK_FLAGS
-  ASSIMP_INCLUDE_DIRS
-  ASSIMP_LIBRARIES
-  ASSIMP_CFLAGS_OTHER
-  ASSIMP_LDFLAGS_OTHER
-  ASSIMP_LIBRARY_SUFFIX
-  ASSIMP_BUILD_SHARED_LIBS
-)

+ 0 - 91
assimpTargets.cmake.in

@@ -1,91 +0,0 @@
-# Generated by CMake
-
-if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
-   message(FATAL_ERROR "CMake >= 2.6.0 required")
-endif()
-cmake_policy(PUSH)
-cmake_policy(VERSION 2.6)
-# Required for the evaluation of "if(@BUILD_SHARED_LIBS@)" below to function
-cmake_policy(SET CMP0012 NEW)
-
-#----------------------------------------------------------------
-# Generated CMake target import file.
-#----------------------------------------------------------------
-
-# Commands may need to know the format version.
-set(CMAKE_IMPORT_FILE_VERSION 1)
-
-# Protect against multiple inclusion, which would fail when already imported targets are added once more.
-set(_targetsDefined)
-set(_targetsNotDefined)
-set(_expectedTargets)
-foreach(_expectedTarget assimp::assimp)
-  list(APPEND _expectedTargets ${_expectedTarget})
-  if(NOT TARGET ${_expectedTarget})
-    list(APPEND _targetsNotDefined ${_expectedTarget})
-  endif()
-  if(TARGET ${_expectedTarget})
-    list(APPEND _targetsDefined ${_expectedTarget})
-  endif()
-endforeach()
-if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
-  unset(_targetsDefined)
-  unset(_targetsNotDefined)
-  unset(_expectedTargets)
-  set(CMAKE_IMPORT_FILE_VERSION)
-  cmake_policy(POP)
-  return()
-endif()
-if(NOT "${_targetsDefined}" STREQUAL "")
-  message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
-endif()
-unset(_targetsDefined)
-unset(_targetsNotDefined)
-unset(_expectedTargets)
-
-# Create imported target assimp::assimp
-add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED)
-
-set_target_properties(assimp::assimp PROPERTIES
-  COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"
-  INTERFACE_assimp_MAJOR_VERSION "1"
-  INTERFACE_INCLUDE_DIRECTORIES "@CMAKE_INSTALL_FULL_INCLUDEDIR@"
-  #INTERFACE_LINK_LIBRARIES "TxtUtils::TxtUtils;MealyMachine::MealyMachine"
-)
-
-if(CMAKE_VERSION VERSION_LESS 2.8.12)
-  message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.")
-endif()
-
-# Load information for each installed configuration.
-get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-file(GLOB CONFIG_FILES "${_DIR}/assimpTargets-*.cmake")
-foreach(f ${CONFIG_FILES})
-  include(${f})
-endforeach()
-
-# Loop over all imported files and verify that they actually exist
-foreach(target ${_IMPORT_CHECK_TARGETS} )
-  foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
-    if(NOT EXISTS "${file}" )
-      message(FATAL_ERROR "The imported target \"${target}\" references the file
-   \"${file}\"
-but this file does not exist.  Possible reasons include:
-* The file was deleted, renamed, or moved to another location.
-* An install or uninstall procedure did not complete successfully.
-* The installation package was faulty and contained
-   \"${CMAKE_CURRENT_LIST_FILE}\"
-but not all the files it references.
-")
-    endif()
-  endforeach()
-  unset(_IMPORT_CHECK_FILES_FOR_${target})
-endforeach()
-unset(_IMPORT_CHECK_TARGETS)
-
-# This file does not depend on other imported targets which have
-# been exported from the same project but in a separate export set.
-
-# Commands beyond this point should not need to know the version.
-set(CMAKE_IMPORT_FILE_VERSION)
-cmake_policy(POP)

+ 1 - 1
cmake-modules/FindRT.cmake

@@ -16,5 +16,5 @@ set(RT_LIBRARIES ${RT_LIBRARY})
 # handle the QUIETLY and REQUIRED arguments and set
 # handle the QUIETLY and REQUIRED arguments and set
 # RT_FOUND to TRUE if all listed variables are TRUE
 # RT_FOUND to TRUE if all listed variables are TRUE
 include(FindPackageHandleStandardArgs)
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(rt DEFAULT_MSG RT_LIBRARY)
+find_package_handle_standard_args(RT DEFAULT_MSG RT_LIBRARY)
 mark_as_advanced(RT_LIBRARY)
 mark_as_advanced(RT_LIBRARY)

+ 15 - 16
cmake/HunterGate.cmake

@@ -1,4 +1,4 @@
-# Copyright (c) 2013-2018, Ruslan Baratov
+# Copyright (c) 2013-2019, Ruslan Baratov
 # All rights reserved.
 # All rights reserved.
 #
 #
 # Redistribution and use in source and binary forms, with or without
 # Redistribution and use in source and binary forms, with or without
@@ -60,7 +60,7 @@ option(HUNTER_STATUS_PRINT "Print working status" ON)
 option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
 option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
 option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
 option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
 
 
-set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki")
+set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors")
 
 
 function(hunter_gate_status_print)
 function(hunter_gate_status_print)
   if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
   if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
@@ -79,9 +79,9 @@ function(hunter_gate_status_debug)
   endif()
   endif()
 endfunction()
 endfunction()
 
 
-function(hunter_gate_wiki wiki_page)
-  message("------------------------------ WIKI -------------------------------")
-  message("    ${HUNTER_WIKI}/${wiki_page}")
+function(hunter_gate_error_page error_page)
+  message("------------------------------ ERROR ------------------------------")
+  message("    ${HUNTER_ERROR_PAGE}/${error_page}.html")
   message("-------------------------------------------------------------------")
   message("-------------------------------------------------------------------")
   message("")
   message("")
   message(FATAL_ERROR "")
   message(FATAL_ERROR "")
@@ -94,14 +94,13 @@ function(hunter_gate_internal_error)
   endforeach()
   endforeach()
   message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
   message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
   message("")
   message("")
-  hunter_gate_wiki("error.internal")
+  hunter_gate_error_page("error.internal")
 endfunction()
 endfunction()
 
 
 function(hunter_gate_fatal_error)
 function(hunter_gate_fatal_error)
-  cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}")
-  string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki)
-  if(have_no_wiki)
-    hunter_gate_internal_error("Expected wiki")
+  cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}")
+  if("${hunter_ERROR_PAGE}" STREQUAL "")
+    hunter_gate_internal_error("Expected ERROR_PAGE")
   endif()
   endif()
   message("")
   message("")
   foreach(x ${hunter_UNPARSED_ARGUMENTS})
   foreach(x ${hunter_UNPARSED_ARGUMENTS})
@@ -109,11 +108,11 @@ function(hunter_gate_fatal_error)
   endforeach()
   endforeach()
   message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
   message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
   message("")
   message("")
-  hunter_gate_wiki("${hunter_WIKI}")
+  hunter_gate_error_page("${hunter_ERROR_PAGE}")
 endfunction()
 endfunction()
 
 
 function(hunter_gate_user_error)
 function(hunter_gate_user_error)
-  hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data")
+  hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data")
 endfunction()
 endfunction()
 
 
 function(hunter_gate_self root version sha1 result)
 function(hunter_gate_self root version sha1 result)
@@ -195,7 +194,7 @@ function(hunter_gate_detect_root)
 
 
   hunter_gate_fatal_error(
   hunter_gate_fatal_error(
       "Can't detect HUNTER_ROOT"
       "Can't detect HUNTER_ROOT"
-      WIKI "error.detect.hunter.root"
+      ERROR_PAGE "error.detect.hunter.root"
   )
   )
 endfunction()
 endfunction()
 
 
@@ -214,7 +213,7 @@ function(hunter_gate_download dir)
         "Settings:"
         "Settings:"
         "  HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
         "  HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
         "  HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
         "  HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
-        WIKI "error.run.install"
+        ERROR_PAGE "error.run.install"
     )
     )
   endif()
   endif()
   string(COMPARE EQUAL "${dir}" "" is_bad)
   string(COMPARE EQUAL "${dir}" "" is_bad)
@@ -400,7 +399,7 @@ macro(HunterGate)
       hunter_gate_fatal_error(
       hunter_gate_fatal_error(
           "Please set HunterGate *before* 'project' command. "
           "Please set HunterGate *before* 'project' command. "
           "Detected project: ${PROJECT_NAME}"
           "Detected project: ${PROJECT_NAME}"
-          WIKI "error.huntergate.before.project"
+          ERROR_PAGE "error.huntergate.before.project"
       )
       )
     endif()
     endif()
 
 
@@ -470,7 +469,7 @@ macro(HunterGate)
             "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
             "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
             "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
             "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
             "(Use at your own risk!)"
             "(Use at your own risk!)"
-            WIKI "error.spaces.in.hunter.root"
+            ERROR_PAGE "error.spaces.in.hunter.root"
         )
         )
       endif()
       endif()
     endif()
     endif()

+ 2 - 2
cmake/assimp-hunter-config.cmake.in

@@ -2,13 +2,13 @@
 
 
 find_package(RapidJSON CONFIG REQUIRED)
 find_package(RapidJSON CONFIG REQUIRED)
 find_package(ZLIB CONFIG REQUIRED)
 find_package(ZLIB CONFIG REQUIRED)
-find_package(utf8 CONFIG REQUIRED)
-find_package(irrXML CONFIG REQUIRED)
+find_package(utf8cpp CONFIG REQUIRED)
 find_package(minizip CONFIG REQUIRED)
 find_package(minizip CONFIG REQUIRED)
 find_package(openddlparser CONFIG REQUIRED)
 find_package(openddlparser CONFIG REQUIRED)
 find_package(poly2tri CONFIG REQUIRED)
 find_package(poly2tri CONFIG REQUIRED)
 find_package(polyclipping CONFIG REQUIRED)
 find_package(polyclipping CONFIG REQUIRED)
 find_package(zip CONFIG REQUIRED)
 find_package(zip CONFIG REQUIRED)
+find_package(pugixml CONFIG REQUIRED)
 
 
 include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
 include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
 check_required_components("@PROJECT_NAME@")
 check_required_components("@PROJECT_NAME@")

+ 9 - 0
cmake/assimp-plain-config.cmake.in

@@ -0,0 +1,9 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
+
+set(ASSIMP_ROOT_DIR ${PACKAGE_PREFIX_DIR})
+set(ASSIMP_LIBRARIES assimp::assimp)
+set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@)
+get_property(ASSIMP_INCLUDE_DIRS TARGET assimp::assimp PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
+set(ASSIMP_LIBRARY_DIRS "")

+ 0 - 707
code/AMF/AMFImporter.cpp

@@ -1,707 +0,0 @@
-/*
----------------------------------------------------------------------------
-Open Asset Import Library (assimp)
----------------------------------------------------------------------------
-
-Copyright (c) 2006-2020, assimp team
-
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the following
-conditions are met:
-
-* Redistributions of source code must retain the above
-copyright notice, this list of conditions and the
-following disclaimer.
-
-* Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the
-following disclaimer in the documentation and/or other
-materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
-contributors may be used to endorse or promote products
-derived from this software without specific prior
-written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------------
-*/
-
-/// \file AMFImporter.cpp
-/// \brief AMF-format files importer for Assimp: main algorithm implementation.
-/// \date 2016
-/// \author [email protected]
-
-#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
-
-// Header files, Assimp.
-#include "AMFImporter.hpp"
-#include "AMFImporter_Macro.hpp"
-
-#include <assimp/fast_atof.h>
-#include <assimp/DefaultIOSystem.h>
-
-// Header files, stdlib.
-#include <memory>
-
-namespace Assimp
-{
-
-/// \var aiImporterDesc AMFImporter::Description
-/// Conastant which hold importer description
-const aiImporterDesc AMFImporter::Description = {
-	"Additive manufacturing file format(AMF) Importer",
-	"smalcom",
-	"",
-	"See documentation in source code. Chapter: Limitations.",
-	aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental,
-	0,
-	0,
-	0,
-	0,
-	"amf"
-};
-
-void AMFImporter::Clear()
-{
-	mNodeElement_Cur = nullptr;
-	mUnit.clear();
-	mMaterial_Converted.clear();
-	mTexture_Converted.clear();
-	// Delete all elements
-	if(!mNodeElement_List.empty())
-	{
-		for(CAMFImporter_NodeElement* ne: mNodeElement_List) { delete ne; }
-
-		mNodeElement_List.clear();
-	}
-}
-
-AMFImporter::~AMFImporter()
-{
-	if(mReader != nullptr) delete mReader;
-	// Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
-	Clear();
-}
-
-/*********************************************************************************************************************************************/
-/************************************************************ Functions: find set ************************************************************/
-/*********************************************************************************************************************************************/
-
-bool AMFImporter::Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const
-{
-	for(CAMFImporter_NodeElement* ne: mNodeElement_List)
-	{
-		if((ne->ID == pID) && (ne->Type == pType))
-		{
-			if(pNodeElement != nullptr) *pNodeElement = ne;
-
-			return true;
-		}
-	}// for(CAMFImporter_NodeElement* ne: mNodeElement_List)
-
-	return false;
-}
-
-bool AMFImporter::Find_ConvertedNode(const std::string& pID, std::list<aiNode*>& pNodeList, aiNode** pNode) const
-{
-aiString node_name(pID.c_str());
-
-	for(aiNode* node: pNodeList)
-	{
-		if(node->mName == node_name)
-		{
-			if(pNode != nullptr) *pNode = node;
-
-			return true;
-		}
-	}// for(aiNode* node: pNodeList)
-
-	return false;
-}
-
-bool AMFImporter::Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const
-{
-	for(const SPP_Material& mat: mMaterial_Converted)
-	{
-		if(mat.ID == pID)
-		{
-			if(pConvertedMaterial != nullptr) *pConvertedMaterial = &mat;
-
-			return true;
-		}
-	}// for(const SPP_Material& mat: mMaterial_Converted)
-
-	return false;
-}
-
-/*********************************************************************************************************************************************/
-/************************************************************ Functions: throw set ***********************************************************/
-/*********************************************************************************************************************************************/
-
-void AMFImporter::Throw_CloseNotFound(const std::string& pNode)
-{
-	throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt.");
-}
-
-void AMFImporter::Throw_IncorrectAttr(const std::string& pAttrName)
-{
-	throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\".");
-}
-
-void AMFImporter::Throw_IncorrectAttrValue(const std::string& pAttrName)
-{
-	throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value.");
-}
-
-void AMFImporter::Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription)
-{
-	throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription);
-}
-
-void AMFImporter::Throw_ID_NotFound(const std::string& pID) const
-{
-	throw DeadlyImportError("Not found node with name \"" + pID + "\".");
-}
-
-/*********************************************************************************************************************************************/
-/************************************************************* Functions: XML set ************************************************************/
-/*********************************************************************************************************************************************/
-
-void AMFImporter::XML_CheckNode_MustHaveChildren()
-{
-	if(mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must have children.");
-}
-
-void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName)
-{
-    static const size_t Uns_Skip_Len = 3;
-    const char* Uns_Skip[Uns_Skip_Len] = { "composite", "edge", "normal" };
-
-    static bool skipped_before[Uns_Skip_Len] = { false, false, false };
-
-    std::string nn(mReader->getNodeName());
-    bool found = false;
-    bool close_found = false;
-    size_t sk_idx;
-
-	for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++)
-	{
-		if(nn != Uns_Skip[sk_idx]) continue;
-
-		found = true;
-		if(mReader->isEmptyElement())
-		{
-			close_found = true;
-
-			goto casu_cres;
-		}
-
-		while(mReader->read())
-		{
-			if((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName()))
-			{
-				close_found = true;
-
-				goto casu_cres;
-			}
-		}
-	}// for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++)
-
-casu_cres:
-
-	if(!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
-	if(!close_found) Throw_CloseNotFound(nn);
-
-	if(!skipped_before[sk_idx])
-	{
-		skipped_before[sk_idx] = true;
-        ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, ".");
-	}
-}
-
-bool AMFImporter::XML_SearchNode(const std::string& pNodeName)
-{
-	while(mReader->read())
-	{
-		if((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true;
-	}
-
-	return false;
-}
-
-bool AMFImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx)
-{
-    std::string val(mReader->getAttributeValue(pAttrIdx));
-
-	if((val == "false") || (val == "0"))
-		return false;
-	else if((val == "true") || (val == "1"))
-		return true;
-	else
-		throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"" + val + "\"");
-}
-
-float AMFImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx)
-{
-    std::string val;
-    float tvalf;
-
-	ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val);
-	fast_atoreal_move(val.c_str(), tvalf, false);
-
-	return tvalf;
-}
-
-uint32_t AMFImporter::XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx)
-{
-	return strtoul10(mReader->getAttributeValue(pAttrIdx));
-}
-
-float AMFImporter::XML_ReadNode_GetVal_AsFloat()
-{
-    std::string val;
-    float tvalf;
-
-	if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. No data, seems file is corrupt.");
-	if(mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. Invalid type of XML element, seems file is corrupt.");
-
-	ParseHelper_FixTruncatedFloatString(mReader->getNodeData(), val);
-	fast_atoreal_move(val.c_str(), tvalf, false);
-
-	return tvalf;
-}
-
-uint32_t AMFImporter::XML_ReadNode_GetVal_AsU32()
-{
-	if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. No data, seems file is corrupt.");
-	if(mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. Invalid type of XML element, seems file is corrupt.");
-
-	return strtoul10(mReader->getNodeData());
-}
-
-void AMFImporter::XML_ReadNode_GetVal_AsString(std::string& pValue)
-{
-	if(!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsString. No data, seems file is corrupt.");
-	if(mReader->getNodeType() != irr::io::EXN_TEXT)
-		throw DeadlyImportError("XML_ReadNode_GetVal_AsString. Invalid type of XML element, seems file is corrupt.");
-
-	pValue = mReader->getNodeData();
-}
-
-/*********************************************************************************************************************************************/
-/************************************************************ Functions: parse set ***********************************************************/
-/*********************************************************************************************************************************************/
-
-void AMFImporter::ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode)
-{
-	mNodeElement_Cur->Child.push_back(pNode);// add new element to current element child list.
-	mNodeElement_Cur = pNode;// switch current element to new one.
-}
-
-void AMFImporter::ParseHelper_Node_Exit()
-{
-	// check if we can walk up.
-	if(mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
-}
-
-void AMFImporter::ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString)
-{
-    size_t instr_len;
-
-	pOutString.clear();
-	instr_len = strlen(pInStr);
-	if(!instr_len) return;
-
-	pOutString.reserve(instr_len * 3 / 2);
-	// check and correct floats in format ".x". Must be "x.y".
-	if(pInStr[0] == '.') pOutString.push_back('0');
-
-	pOutString.push_back(pInStr[0]);
-	for(size_t ci = 1; ci < instr_len; ci++)
-	{
-		if((pInStr[ci] == '.') && ((pInStr[ci - 1] == ' ') || (pInStr[ci - 1] == '-') || (pInStr[ci - 1] == '+') || (pInStr[ci - 1] == '\t')))
-		{
-			pOutString.push_back('0');
-			pOutString.push_back('.');
-		}
-		else
-		{
-			pOutString.push_back(pInStr[ci]);
-		}
-	}
-}
-
-static bool ParseHelper_Decode_Base64_IsBase64(const char pChar)
-{
-	return (isalnum(pChar) || (pChar == '+') || (pChar == '/'));
-}
-
-void AMFImporter::ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const
-{
-    // With help from
-    // René Nyffenegger http://www.adp-gmbh.ch/cpp/common/base64.html
-    const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-    uint8_t tidx = 0;
-    uint8_t arr4[4], arr3[3];
-
-	// check input data
-	if(pInputBase64.size() % 4) throw DeadlyImportError("Base64-encoded data must have size multiply of four.");
-	// prepare output place
-	pOutputData.clear();
-	pOutputData.reserve(pInputBase64.size() / 4 * 3);
-
-	for(size_t in_len = pInputBase64.size(), in_idx = 0; (in_len > 0) && (pInputBase64[in_idx] != '='); in_len--)
-	{
-		if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx]))
-		{
-			arr4[tidx++] = pInputBase64[in_idx++];
-			if(tidx == 4)
-			{
-				for(tidx = 0; tidx < 4; tidx++) arr4[tidx] = (uint8_t)base64_chars.find(arr4[tidx]);
-
-				arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
-				arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2);
-				arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3];
-				for(tidx = 0; tidx < 3; tidx++) pOutputData.push_back(arr3[tidx]);
-
-				tidx = 0;
-			}// if(tidx == 4)
-		}// if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx]))
-		else
-		{
-			in_idx++;
-		}// if(ParseHelper_Decode_Base64_IsBase64(pInputBase64[in_idx])) else
-	}
-
-	if(tidx)
-	{
-		for(uint8_t i = tidx; i < 4; i++) arr4[i] = 0;
-		for(uint8_t i = 0; i < 4; i++) arr4[i] = (uint8_t)(base64_chars.find(arr4[i]));
-
-		arr3[0] = (arr4[0] << 2) + ((arr4[1] & 0x30) >> 4);
-		arr3[1] = ((arr4[1] & 0x0F) << 4) + ((arr4[2] & 0x3C) >> 2);
-		arr3[2] = ((arr4[2] & 0x03) << 6) + arr4[3];
-		for(uint8_t i = 0; i < (tidx - 1); i++) pOutputData.push_back(arr3[i]);
-	}
-}
-
-void AMFImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler)
-{
-    irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader.
-    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
-
-	// Check whether we can read from the file
-    if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open AMF file " + pFile + ".");
-    }
-
-	// generate a XML reader for it
-	std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
-	mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
-	if(!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
-	//
-	// start reading
-	// search for root tag <amf>
-	if(XML_SearchNode("amf"))
-		ParseNode_Root();
-	else
-		throw DeadlyImportError("Root node \"amf\" not found.");
-
-	delete mReader;
-	// restore old XMLreader
-	mReader = OldReader;
-}
-
-// <amf
-// unit="" - The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
-// version="" - Version of file format.
-// >
-// </amf>
-// Root XML element.
-// Multi elements - No.
-void AMFImporter::ParseNode_Root()
-{
-    std::string unit, version;
-    CAMFImporter_NodeElement *ne( nullptr );
-
-	// Read attributes for node <amf>.
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("unit", unit, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_RET("version", version, mReader->getAttributeValue);
-	MACRO_ATTRREAD_LOOPEND_WSKIP;
-
-	// Check attributes
-	if(!mUnit.empty())
-	{
-		if((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) Throw_IncorrectAttrValue("unit");
-	}
-
-	// create root node element.
-	ne = new CAMFImporter_NodeElement_Root(nullptr);
-	mNodeElement_Cur = ne;// set first "current" element
-	// and assign attribute's values
-	((CAMFImporter_NodeElement_Root*)ne)->Unit = unit;
-	((CAMFImporter_NodeElement_Root*)ne)->Version = version;
-
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		MACRO_NODECHECK_LOOPBEGIN("amf");
-			if(XML_CheckNode_NameEqual("object")) { ParseNode_Object(); continue; }
-			if(XML_CheckNode_NameEqual("material")) { ParseNode_Material(); continue; }
-			if(XML_CheckNode_NameEqual("texture")) { ParseNode_Texture(); continue; }
-			if(XML_CheckNode_NameEqual("constellation")) { ParseNode_Constellation(); continue; }
-			if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
-		MACRO_NODECHECK_LOOPEND("amf");
-		mNodeElement_Cur = ne;// force restore "current" element
-	}// if(!mReader->isEmptyElement())
-
-	mNodeElement_List.push_back(ne);// add to node element list because its a new object in graph.
-}
-
-// <constellation
-// id="" - The Object ID of the new constellation being defined.
-// >
-// </constellation>
-// A collection of objects or constellations with specific relative locations.
-// Multi elements - Yes.
-// Parent element - <amf>.
-void AMFImporter::ParseNode_Constellation()
-{
-    std::string id;
-    CAMFImporter_NodeElement* ne( nullptr );
-
-	// Read attributes for node <constellation>.
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
-	MACRO_ATTRREAD_LOOPEND;
-
-	// create and if needed - define new grouping object.
-	ne = new CAMFImporter_NodeElement_Constellation(mNodeElement_Cur);
-
-	CAMFImporter_NodeElement_Constellation& als = *((CAMFImporter_NodeElement_Constellation*)ne);// alias for convenience
-
-	if(!id.empty()) als.ID = id;
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("constellation");
-			if(XML_CheckNode_NameEqual("instance")) { ParseNode_Instance(); continue; }
-			if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
-		MACRO_NODECHECK_LOOPEND("constellation");
-		ParseHelper_Node_Exit();
-	}// if(!mReader->isEmptyElement())
-	else
-	{
-		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
-
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
-}
-
-// <instance
-// objectid="" - The Object ID of the new constellation being defined.
-// >
-// </instance>
-// A collection of objects or constellations with specific relative locations.
-// Multi elements - Yes.
-// Parent element - <amf>.
-void AMFImporter::ParseNode_Instance()
-{
-    std::string objectid;
-    CAMFImporter_NodeElement* ne( nullptr );
-
-	// Read attributes for node <constellation>.
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("objectid", objectid, mReader->getAttributeValue);
-	MACRO_ATTRREAD_LOOPEND;
-
-	// used object id must be defined, check that.
-	if(objectid.empty()) throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
-	// create and define new grouping object.
-	ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur);
-
-	CAMFImporter_NodeElement_Instance& als = *((CAMFImporter_NodeElement_Instance*)ne);// alias for convenience
-
-	als.ObjectID = objectid;
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		bool read_flag[6] = { false, false, false, false, false, false };
-
-		als.Delta.Set(0, 0, 0);
-		als.Rotation.Set(0, 0, 0);
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("instance");
-			MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x);
-			MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y);
-			MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z);
-			MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x);
-			MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y);
-			MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z);
-		MACRO_NODECHECK_LOOPEND("instance");
-		ParseHelper_Node_Exit();
-		// also convert degrees to radians.
-		als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f;
-		als.Rotation.y = AI_MATH_PI_F * als.Rotation.y / 180.0f;
-		als.Rotation.z = AI_MATH_PI_F * als.Rotation.z / 180.0f;
-	}// if(!mReader->isEmptyElement())
-	else
-	{
-		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
-
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
-}
-
-// <object
-// id="" - A unique ObjectID for the new object being defined.
-// >
-// </object>
-// An object definition.
-// Multi elements - Yes.
-// Parent element - <amf>.
-void AMFImporter::ParseNode_Object()
-{
-    std::string id;
-    CAMFImporter_NodeElement* ne( nullptr );
-
-	// Read attributes for node <object>.
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
-	MACRO_ATTRREAD_LOOPEND;
-
-	// create and if needed - define new geometry object.
-	ne = new CAMFImporter_NodeElement_Object(mNodeElement_Cur);
-
-	CAMFImporter_NodeElement_Object& als = *((CAMFImporter_NodeElement_Object*)ne);// alias for convenience
-
-	if(!id.empty()) als.ID = id;
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		bool col_read = false;
-
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("object");
-			if(XML_CheckNode_NameEqual("color"))
-			{
-				// Check if color already defined for object.
-				if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <object>.");
-				// read data and set flag about it
-				ParseNode_Color();
-				col_read = true;
-
-				continue;
-			}
-
-			if(XML_CheckNode_NameEqual("mesh")) { ParseNode_Mesh(); continue; }
-			if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
-		MACRO_NODECHECK_LOOPEND("object");
-		ParseHelper_Node_Exit();
-	}// if(!mReader->isEmptyElement())
-	else
-	{
-		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
-
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
-}
-
-// <metadata
-// type="" - The type of the attribute.
-// >
-// </metadata>
-// Specify additional information about an entity.
-// Multi elements - Yes.
-// Parent element - <amf>, <object>, <volume>, <material>, <vertex>.
-//
-// Reserved types are:
-// "Name" - The alphanumeric label of the entity, to be used by the interpreter if interacting with the user.
-// "Description" - A description of the content of the entity
-// "URL" - A link to an external resource relating to the entity
-// "Author" - Specifies the name(s) of the author(s) of the entity
-// "Company" - Specifying the company generating the entity
-// "CAD" - specifies the name of the originating CAD software and version
-// "Revision" - specifies the revision of the entity
-// "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system
-// "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only)
-void AMFImporter::ParseNode_Metadata()
-{
-    std::string type, value;
-    CAMFImporter_NodeElement* ne( nullptr );
-
-	// read attribute
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
-	MACRO_ATTRREAD_LOOPEND;
-	// and value of node.
-	value = mReader->getNodeData();
-	// Create node element and assign read data.
-	ne = new CAMFImporter_NodeElement_Metadata(mNodeElement_Cur);
-	((CAMFImporter_NodeElement_Metadata*)ne)->Type = type;
-	((CAMFImporter_NodeElement_Metadata*)ne)->Value = value;
-	mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
-}
-
-/*********************************************************************************************************************************************/
-/******************************************************** Functions: BaseImporter set ********************************************************/
-/*********************************************************************************************************************************************/
-
-bool AMFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const
-{
-    const std::string extension = GetExtension(pFile);
-
-    if ( extension == "amf" ) {
-        return true;
-    }
-
-	if(!extension.length() || pCheckSig)
-	{
-		const char* tokens[] = { "<amf" };
-
-		return SearchFileHeaderForToken( pIOHandler, pFile, tokens, 1 );
-	}
-
-	return false;
-}
-
-void AMFImporter::GetExtensionList(std::set<std::string>& pExtensionList)
-{
-	pExtensionList.insert("amf");
-}
-
-const aiImporterDesc* AMFImporter::GetInfo () const
-{
-	return &Description;
-}
-
-void AMFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
-{
-	Clear();// delete old graph.
-	ParseFile(pFile, pIOHandler);
-	Postprocess_BuildScene(pScene);
-	// scene graph is ready, exit.
-}
-
-}// namespace Assimp
-
-#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

+ 7 - 2
code/AssetLib/3DS/3DSExporter.cpp

@@ -290,12 +290,18 @@ void Discreet3DSExporter::WriteMaterials() {
             ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
             ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SPECULAR);
             WriteColor(color);
             WriteColor(color);
         }
         }
-
+                
         if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
         if (mat.Get(AI_MATKEY_COLOR_AMBIENT, color) == AI_SUCCESS) {
             ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
             ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_AMBIENT);
             WriteColor(color);
             WriteColor(color);
         }
         }
 
 
+        float f;
+        if (mat.Get(AI_MATKEY_OPACITY, f) == AI_SUCCESS) {
+            ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_TRANSPARENCY);
+            WritePercentChunk(1.0f - f);
+        }
+
         if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
         if (mat.Get(AI_MATKEY_COLOR_EMISSIVE, color) == AI_SUCCESS) {
             ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
             ChunkWriter curChunk(writer, Discreet3DS::CHUNK_MAT_SELF_ILLUM);
             WriteColor(color);
             WriteColor(color);
@@ -333,7 +339,6 @@ void Discreet3DSExporter::WriteMaterials() {
             writer.PutU2(static_cast<uint16_t>(shading_mode_out));
             writer.PutU2(static_cast<uint16_t>(shading_mode_out));
         }
         }
 
 
-        float f;
         if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
         if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
             ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
             ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
             WritePercentChunk(f);
             WritePercentChunk(f);

+ 7 - 2
code/AssetLib/3DS/3DSHelper.h

@@ -321,9 +321,10 @@ public:
 struct Face : public FaceWithSmoothingGroup {
 struct Face : public FaceWithSmoothingGroup {
 };
 };
 
 
-#ifdef _WIN32
+#ifdef _MSC_VER
+#pragma warning(push)
 #pragma warning(disable : 4315)
 #pragma warning(disable : 4315)
-#endif
+#endif // _MSC_VER
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Helper structure representing a texture */
 /** Helper structure representing a texture */
@@ -412,6 +413,10 @@ struct Texture {
 
 
 #include <assimp/Compiler/poppack1.h>
 #include <assimp/Compiler/poppack1.h>
 
 
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Helper structure representing a 3ds material */
 /** Helper structure representing a 3ds material */
 struct Material {
 struct Material {

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

@@ -147,7 +147,7 @@ void Discreet3DSImporter::InternReadFile(const std::string &pFile,
 
 
     // We should have at least one chunk
     // We should have at least one chunk
     if (theStream.GetRemainingSize() < 16) {
     if (theStream.GetRemainingSize() < 16) {
-        throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile);
+        throw DeadlyImportError("3DS file is either empty or corrupt: ", pFile);
     }
     }
     this->stream = &theStream;
     this->stream = &theStream;
 
 
@@ -178,7 +178,7 @@ void Discreet3DSImporter::InternReadFile(const std::string &pFile,
     // file.
     // file.
     for (auto &mesh : mScene->mMeshes) {
     for (auto &mesh : mScene->mMeshes) {
         if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) {
         if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0) {
-            throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile);
+            throw DeadlyImportError("3DS file contains faces but no vertices: ", pFile);
         }
         }
         CheckIndices(mesh);
         CheckIndices(mesh);
         MakeUnique(mesh);
         MakeUnique(mesh);

+ 3 - 1
code/AssetLib/3MF/3MFXmlTags.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -56,6 +55,8 @@ namespace XmlTag {
     static const std::string resources = "resources";
     static const std::string resources = "resources";
     static const std::string object = "object";
     static const std::string object = "object";
     static const std::string mesh = "mesh";
     static const std::string mesh = "mesh";
+    static const std::string components = "components";
+    static const std::string component = "component";
     static const std::string vertices = "vertices";
     static const std::string vertices = "vertices";
     static const std::string vertex = "vertex";
     static const std::string vertex = "vertex";
     static const std::string triangles = "triangles";
     static const std::string triangles = "triangles";
@@ -68,6 +69,7 @@ namespace XmlTag {
     static const std::string v3 = "v3";
     static const std::string v3 = "v3";
     static const std::string id = "id";
     static const std::string id = "id";
     static const std::string pid = "pid";
     static const std::string pid = "pid";
+    static const std::string pindex = "pindex";
     static const std::string p1 = "p1";
     static const std::string p1 = "p1";
     static const std::string name = "name";
     static const std::string name = "name";
     static const std::string type = "type";
     static const std::string type = "type";

+ 14 - 30
code/AssetLib/3MF/D3MFExporter.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -138,7 +137,7 @@ bool D3MFExporter::exportContentTypes() {
     mContentOutput << std::endl;
     mContentOutput << std::endl;
     mContentOutput << "</Types>";
     mContentOutput << "</Types>";
     mContentOutput << std::endl;
     mContentOutput << std::endl;
-    exportContentTyp(XmlTag::CONTENT_TYPES_ARCHIVE);
+    zipContentType(XmlTag::CONTENT_TYPES_ARCHIVE);
 
 
     return true;
     return true;
 }
 }
@@ -163,7 +162,7 @@ bool D3MFExporter::exportRelations() {
     mRelOutput << "</Relationships>";
     mRelOutput << "</Relationships>";
     mRelOutput << std::endl;
     mRelOutput << std::endl;
 
 
-    writeRelInfoToFile("_rels", ".rels");
+    zipRelInfo("_rels", ".rels");
     mRelOutput.flush();
     mRelOutput.flush();
 
 
     return true;
     return true;
@@ -197,7 +196,7 @@ bool D3MFExporter::export3DModel() {
     info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
     info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
     mRelations.push_back(info);
     mRelations.push_back(info);
 
 
-    writeModelToArchive("3D", "3DModel.model");
+    zipModel("3D", "3DModel.model");
     mModelOutput.flush();
     mModelOutput.flush();
 
 
     return true;
     return true;
@@ -358,42 +357,27 @@ void D3MFExporter::writeBuild() {
     mModelOutput << std::endl;
     mModelOutput << std::endl;
 }
 }
 
 
-void D3MFExporter::exportContentTyp(const std::string &filename) {
-    if (nullptr == m_zipArchive) {
-        throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
-    }
-    const std::string entry = filename;
-    zip_entry_open(m_zipArchive, entry.c_str());
-
-    const std::string &exportTxt(mContentOutput.str());
-    zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
-
-    zip_entry_close(m_zipArchive);
+void D3MFExporter::zipContentType(const std::string &filename) {
+    addFileInZip(filename, mContentOutput.str());
 }
 }
 
 
-void D3MFExporter::writeModelToArchive(const std::string &folder, const std::string &modelName) {
-    if (nullptr == m_zipArchive) {
-        throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
-    }
+void D3MFExporter::zipModel(const std::string &folder, const std::string &modelName) {
     const std::string entry = folder + "/" + modelName;
     const std::string entry = folder + "/" + modelName;
-    zip_entry_open(m_zipArchive, entry.c_str());
-
-    const std::string &exportTxt(mModelOutput.str());
-    zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
+    addFileInZip(entry, mModelOutput.str());
+}
 
 
-    zip_entry_close(m_zipArchive);
+void D3MFExporter::zipRelInfo(const std::string &folder, const std::string &relName) {
+    const std::string entry = folder + "/" + relName;
+    addFileInZip(entry, mRelOutput.str());
 }
 }
 
 
-void D3MFExporter::writeRelInfoToFile(const std::string &folder, const std::string &relName) {
+void D3MFExporter::addFileInZip(const std::string& entry, const std::string& content) {
     if (nullptr == m_zipArchive) {
     if (nullptr == m_zipArchive) {
         throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
         throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
     }
     }
-    const std::string entry = folder + "/" + relName;
-    zip_entry_open(m_zipArchive, entry.c_str());
-
-    const std::string &exportTxt(mRelOutput.str());
-    zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
 
 
+    zip_entry_open(m_zipArchive, entry.c_str());
+    zip_entry_write(m_zipArchive, content.c_str(), content.size());
     zip_entry_close(m_zipArchive);
     zip_entry_close(m_zipArchive);
 }
 }
 
 

+ 6 - 4
code/AssetLib/3MF/D3MFExporter.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, assimp team
 
 
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,
@@ -83,9 +82,12 @@ protected:
     void writeVertex( const aiVector3D &pos );
     void writeVertex( const aiVector3D &pos );
     void writeFaces( aiMesh *mesh, unsigned int matIdx );
     void writeFaces( aiMesh *mesh, unsigned int matIdx );
     void writeBuild();
     void writeBuild();
-    void exportContentTyp( const std::string &filename );
-    void writeModelToArchive( const std::string &folder, const std::string &modelName );
-    void writeRelInfoToFile( const std::string &folder, const std::string &relName );
+
+    // Zip the data
+    void zipContentType( const std::string &filename );
+    void zipModel( const std::string &folder, const std::string &modelName );
+    void zipRelInfo( const std::string &folder, const std::string &relName );
+    void addFileInZip( const std::string &entry, const std::string &content );
 
 
 private:
 private:
     std::string mArchiveName;
     std::string mArchiveName;

+ 353 - 208
code/AssetLib/3MF/D3MFImporter.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -46,12 +45,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include <assimp/StringComparison.h>
 #include <assimp/StringComparison.h>
 #include <assimp/StringUtils.h>
 #include <assimp/StringUtils.h>
+#include <assimp/XmlParser.h>
 #include <assimp/ZipArchiveIOSystem.h>
 #include <assimp/ZipArchiveIOSystem.h>
 #include <assimp/importerdesc.h>
 #include <assimp/importerdesc.h>
 #include <assimp/scene.h>
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/IOSystem.hpp>
-
 #include <cassert>
 #include <cassert>
 #include <map>
 #include <map>
 #include <memory>
 #include <memory>
@@ -61,29 +60,85 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "3MFXmlTags.h"
 #include "3MFXmlTags.h"
 #include "D3MFOpcPackage.h"
 #include "D3MFOpcPackage.h"
 #include <assimp/fast_atof.h>
 #include <assimp/fast_atof.h>
-#include <assimp/irrXMLWrapper.h>
 
 
 #include <iomanip>
 #include <iomanip>
 
 
 namespace Assimp {
 namespace Assimp {
 namespace D3MF {
 namespace D3MF {
 
 
+enum class ResourceType {
+    RT_Object,
+    RT_BaseMaterials,
+    RT_Unknown
+}; // To be extended with other resource types (eg. material extension resources like Texture2d, Texture2dGroup...)
+
+class Resource
+{
+public:
+    Resource(int id) :
+            mId(id) {}
+
+    virtual ~Resource() {}
+
+    int mId;
+
+    virtual ResourceType getType() {
+        return ResourceType::RT_Unknown;
+    }
+};
+
+class BaseMaterials : public Resource {
+public:
+    BaseMaterials(int id) :
+            Resource(id),
+            mMaterials(),
+            mMaterialIndex() {}
+
+    std::vector<aiMaterial *> mMaterials;
+    std::vector<unsigned int> mMaterialIndex;
+
+    virtual ResourceType getType() {
+        return ResourceType::RT_BaseMaterials;
+    }
+};
+
+struct Component {
+    int mObjectId;
+    aiMatrix4x4 mTransformation;
+};
+
+class Object : public Resource {
+public:
+    std::vector<aiMesh*> mMeshes;
+    std::vector<unsigned int> mMeshIndex;
+    std::vector<Component> mComponents;
+    std::string mName;
+
+    Object(int id) :
+            Resource(id),
+            mName (std::string("Object_") + to_string(id)){}
+
+    virtual ResourceType getType() {
+        return ResourceType::RT_Object;
+    }
+};
+
+
 class XmlSerializer {
 class XmlSerializer {
 public:
 public:
-    using MatArray = std::vector<aiMaterial *>;
-    using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
-
-    XmlSerializer(XmlReader *xmlReader) :
-            mMeshes(),
-            mMatArray(),
-            mActiveMatGroup(99999999),
-            mMatId2MatArray(),
-            xmlReader(xmlReader) {
+
+    XmlSerializer(XmlParser *xmlParser) :
+            mResourcesDictionnary(),
+            mMaterialCount(0),
+            mMeshCount(0),
+            mXmlParser(xmlParser) {
         // empty
         // empty
     }
     }
 
 
     ~XmlSerializer() {
     ~XmlSerializer() {
-        // empty
+        for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
+            delete it->second;
+        }
     }
     }
 
 
     void ImportXml(aiScene *scene) {
     void ImportXml(aiScene *scene) {
@@ -91,27 +146,47 @@ public:
             return;
             return;
         }
         }
 
 
-        scene->mRootNode = new aiNode();
-        std::vector<aiNode *> children;
-
-        std::string nodeName;
-        while (ReadToEndElement(D3MF::XmlTag::model)) {
-            nodeName = xmlReader->getNodeName();
-            if (nodeName == D3MF::XmlTag::object) {
-                children.push_back(ReadObject(scene));
-            } else if (nodeName == D3MF::XmlTag::build) {
-                //
-            } else if (nodeName == D3MF::XmlTag::basematerials) {
-                ReadBaseMaterials();
-            } else if (nodeName == D3MF::XmlTag::meta) {
-                ReadMetadata();
+        scene->mRootNode = new aiNode("3MF");
+
+        XmlNode node = mXmlParser->getRootNode().child("model");
+        if (node.empty()) {
+            return;
+        }
+        XmlNode resNode = node.child("resources");
+        for (XmlNode currentNode = resNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string &currentNodeName = currentNode.name();
+            if (currentNodeName == D3MF::XmlTag::object) {
+                ReadObject(currentNode);;
+            } else if (currentNodeName == D3MF::XmlTag::basematerials) {
+                ReadBaseMaterials(currentNode);
+            } else if (currentNodeName == D3MF::XmlTag::meta) {
+                ReadMetadata(currentNode);
             }
             }
         }
         }
 
 
-        if (scene->mRootNode->mName.length == 0) {
-            scene->mRootNode->mName.Set("3MF");
+        XmlNode buildNode = node.child("build");
+        for (XmlNode currentNode = buildNode.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string &currentNodeName = currentNode.name();
+            if (currentNodeName == D3MF::XmlTag::item) {
+                int objectId = -1;
+                std::string transformationMatrixStr;
+                aiMatrix4x4 transformationMatrix;
+                getNodeAttribute(currentNode, D3MF::XmlTag::objectid, objectId);
+                bool hasTransform = getNodeAttribute(currentNode, D3MF::XmlTag::transform, transformationMatrixStr);
+
+                auto it = mResourcesDictionnary.find(objectId);
+                if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
+                    Object *obj = static_cast<Object *>(it->second);
+                    if (hasTransform) {
+                        transformationMatrix = parseTransformMatrix(transformationMatrixStr);
+                    }
+
+                    addObjectToNode(scene->mRootNode, obj, transformationMatrix);
+                }
+            }
         }
         }
 
 
+
         // import the metadata
         // import the metadata
         if (!mMetaData.empty()) {
         if (!mMetaData.empty()) {
             const size_t numMeta(mMetaData.size());
             const size_t numMeta(mMetaData.size());
@@ -123,83 +198,194 @@ public:
         }
         }
 
 
         // import the meshes
         // import the meshes
-        scene->mNumMeshes = static_cast<unsigned int>(mMeshes.size());
-        scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
-        std::copy(mMeshes.begin(), mMeshes.end(), scene->mMeshes);
+        scene->mNumMeshes = static_cast<unsigned int>(mMeshCount);
+        if (scene->mNumMeshes != 0) {
+            scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
+            for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
+                if (it->second->getType() == ResourceType::RT_Object) {
+                    Object *obj = static_cast<Object*>(it->second);
+                    for (unsigned int i = 0; i < obj->mMeshes.size(); ++i) {
+                        scene->mMeshes[obj->mMeshIndex[i]] = obj->mMeshes[i];
+                    }
+                }
+            }
+        }
+        
 
 
         // import the materials
         // import the materials
-        scene->mNumMaterials = static_cast<unsigned int>(mMatArray.size());
-        if (0 != scene->mNumMaterials) {
+        scene->mNumMaterials = static_cast<unsigned int>(mMaterialCount);
+        if (scene->mNumMaterials != 0) {
             scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
             scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
-            std::copy(mMatArray.begin(), mMatArray.end(), scene->mMaterials);
+            for (auto it = mResourcesDictionnary.begin(); it != mResourcesDictionnary.end(); it++) {
+                if (it->second->getType() == ResourceType::RT_BaseMaterials) {
+                    BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
+                    for (unsigned int i = 0; i < baseMaterials->mMaterials.size(); ++i) {
+                        scene->mMaterials[baseMaterials->mMaterialIndex[i]] = baseMaterials->mMaterials[i];
+                    }
+                }
+            }
         }
         }
-
-        // create the scenegraph
-        scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
-        scene->mRootNode->mChildren = new aiNode *[scene->mRootNode->mNumChildren]();
-        std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
     }
     }
 
 
 private:
 private:
-    aiNode *ReadObject(aiScene *scene) {
-        std::unique_ptr<aiNode> node(new aiNode());
 
 
-        std::vector<unsigned long> meshIds;
+    void addObjectToNode(aiNode* parent, Object* obj, aiMatrix4x4 nodeTransform) {
+        aiNode *sceneNode = new aiNode(obj->mName);
+        sceneNode->mNumMeshes = static_cast<unsigned int>(obj->mMeshes.size());
+        sceneNode->mMeshes = new unsigned int[sceneNode->mNumMeshes];
+        std::copy(obj->mMeshIndex.begin(), obj->mMeshIndex.end(), sceneNode->mMeshes);
+
+        sceneNode->mTransformation = nodeTransform;
+
+        parent->addChildren(1, &sceneNode);
 
 
-        const char *attrib(nullptr);
-        std::string name, type;
-        attrib = xmlReader->getAttributeValue(D3MF::XmlTag::id.c_str());
-        if (nullptr != attrib) {
-            name = attrib;
+        for (size_t i = 0; i < obj->mComponents.size(); ++i) {
+            Component c = obj->mComponents[i];
+            auto it = mResourcesDictionnary.find(c.mObjectId);
+            if (it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_Object) {
+                addObjectToNode(sceneNode, static_cast<Object*>(it->second), c.mTransformation);
+            }
+            
         }
         }
-        attrib = xmlReader->getAttributeValue(D3MF::XmlTag::type.c_str());
-        if (nullptr != attrib) {
-            type = attrib;
+    }
+
+    bool getNodeAttribute(const XmlNode& node, const std::string& attribute, std::string& value) {
+        pugi::xml_attribute objectAttribute = node.attribute(attribute.c_str());
+        if (!objectAttribute.empty()) {
+            value = objectAttribute.as_string();
+            return true;
+        } else {
+            return false;
         }
         }
+    }
 
 
-        node->mParent = scene->mRootNode;
-        node->mName.Set(name);
+    bool getNodeAttribute(const XmlNode &node, const std::string &attribute, int &value) {
+        std::string strValue;
+        bool ret = getNodeAttribute(node, attribute, strValue);
+        if (ret) {
+            value = std::atoi(strValue.c_str());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    aiMatrix4x4 parseTransformMatrix(std::string matrixStr) {
+        // split the string
+        std::vector<float> numbers;
+        std::string currentNumber;
+        for (size_t i = 0; i < matrixStr.size(); ++i) {
+            const char c = matrixStr[i];
+            if (c == ' ') {
+                if (currentNumber.size() > 0) {
+                    float f = std::stof(currentNumber);
+                    numbers.push_back(f);
+                    currentNumber.clear();
+                }
+            } else {
+                currentNumber.push_back(c);
+            }
+        }
+        if (currentNumber.size() > 0) {
+            float f = std::stof(currentNumber);
+            numbers.push_back(f);
+        }
 
 
-        size_t meshIdx = mMeshes.size();
+        aiMatrix4x4 transformMatrix;
+        transformMatrix.a1 = numbers[0];
+        transformMatrix.b1 = numbers[1];
+        transformMatrix.c1 = numbers[2];
+        transformMatrix.d1 = 0;
+
+        transformMatrix.a2 = numbers[3];
+        transformMatrix.b2 = numbers[4];
+        transformMatrix.c2 = numbers[5];
+        transformMatrix.d2 = 0;
+
+        transformMatrix.a3 = numbers[6];
+        transformMatrix.b3 = numbers[7];
+        transformMatrix.c3 = numbers[8];
+        transformMatrix.d3 = 0;
+
+        transformMatrix.a4 = numbers[9];
+        transformMatrix.b4 = numbers[10];
+        transformMatrix.c4 = numbers[11];
+        transformMatrix.d4 = 1;
+        return transformMatrix;
+    }
 
 
-        while (ReadToEndElement(D3MF::XmlTag::object)) {
-            if (xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
-                auto mesh = ReadMesh();
+    void ReadObject(XmlNode &node) {
+        int id = -1, pid = -1, pindex = -1;
+        bool hasId = getNodeAttribute(node, D3MF::XmlTag::id, id);
+        //bool hasType = getNodeAttribute(node, D3MF::XmlTag::type, type); not used currently
+        bool hasPid = getNodeAttribute(node, D3MF::XmlTag::pid, pid);
+        bool hasPindex = getNodeAttribute(node, D3MF::XmlTag::pindex, pindex);
 
 
-                mesh->mName.Set(name);
-                mMeshes.push_back(mesh);
-                meshIds.push_back(static_cast<unsigned long>(meshIdx));
-                ++meshIdx;
-            }
+        std::string idStr = to_string(id);
+
+        if (!hasId) {
+            return;
         }
         }
 
 
-        node->mNumMeshes = static_cast<unsigned int>(meshIds.size());
+        Object *obj = new Object(id);
+
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string &currentName = currentNode.name();
+            if (currentName == D3MF::XmlTag::mesh) {
+                auto mesh = ReadMesh(currentNode);
+                mesh->mName.Set(idStr);
 
 
-        node->mMeshes = new unsigned int[node->mNumMeshes];
+                if (hasPid) {
+                    auto it = mResourcesDictionnary.find(pid);
+                    if (hasPindex && it != mResourcesDictionnary.end() && it->second->getType() == ResourceType::RT_BaseMaterials) {
+                        BaseMaterials *materials = static_cast<BaseMaterials *>(it->second);
+                        mesh->mMaterialIndex = materials->mMaterialIndex[pindex];
+                    }
+                }
 
 
-        std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
+                obj->mMeshes.push_back(mesh);
+                obj->mMeshIndex.push_back(mMeshCount);
+                mMeshCount++;
+            } else if (currentName == D3MF::XmlTag::components) {
+                for (XmlNode currentSubNode = currentNode.first_child(); currentSubNode; currentSubNode = currentSubNode.next_sibling()) {
+                    if (currentSubNode.name() == D3MF::XmlTag::component) {
+                        int objectId = -1;
+                        std::string componentTransformStr;
+                        aiMatrix4x4 componentTransform;
+                        if (getNodeAttribute(currentSubNode, D3MF::XmlTag::transform, componentTransformStr)) {
+                            componentTransform = parseTransformMatrix(componentTransformStr);
+                        }
+
+                        if (getNodeAttribute(currentSubNode, D3MF::XmlTag::objectid, objectId))
+                            obj->mComponents.push_back({ objectId, componentTransform });
+                    }
+                }
+            }
+        }
 
 
-        return node.release();
+        mResourcesDictionnary.insert(std::make_pair(id, obj));
     }
     }
 
 
-    aiMesh *ReadMesh() {
+    aiMesh *ReadMesh(XmlNode &node) {
         aiMesh *mesh = new aiMesh();
         aiMesh *mesh = new aiMesh();
-        while (ReadToEndElement(D3MF::XmlTag::mesh)) {
-            if (xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
-                ImportVertices(mesh);
-            } else if (xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
-                ImportTriangles(mesh);
+
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string &currentName = currentNode.name();
+            if (currentName == D3MF::XmlTag::vertices) {
+                ImportVertices(currentNode, mesh);
+            } else if (currentName == D3MF::XmlTag::triangles) {
+                ImportTriangles(currentNode, mesh);
             }
             }
+
         }
         }
 
 
         return mesh;
         return mesh;
     }
     }
 
 
-    void ReadMetadata() {
-        const std::string name = xmlReader->getAttributeValue(D3MF::XmlTag::meta_name.c_str());
-        xmlReader->read();
-        const std::string value = xmlReader->getNodeData();
-
+    void ReadMetadata(XmlNode &node) {
+        pugi::xml_attribute attribute = node.attribute(D3MF::XmlTag::meta_name.c_str());
+        const std::string name = attribute.as_string();
+        const std::string value = node.value();
         if (name.empty()) {
         if (name.empty()) {
             return;
             return;
         }
         }
@@ -210,40 +396,51 @@ private:
         mMetaData.push_back(entry);
         mMetaData.push_back(entry);
     }
     }
 
 
-    void ImportVertices(aiMesh *mesh) {
+    void ImportVertices(XmlNode &node, aiMesh *mesh) {
         std::vector<aiVector3D> vertices;
         std::vector<aiVector3D> vertices;
-        while (ReadToEndElement(D3MF::XmlTag::vertices)) {
-            if (xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
-                vertices.push_back(ReadVertex());
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string &currentName = currentNode.name();
+            if (currentName == D3MF::XmlTag::vertex) {
+                vertices.push_back(ReadVertex(currentNode));
             }
             }
         }
         }
+
         mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
         mesh->mNumVertices = static_cast<unsigned int>(vertices.size());
         mesh->mVertices = new aiVector3D[mesh->mNumVertices];
         mesh->mVertices = new aiVector3D[mesh->mNumVertices];
-
         std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
         std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
     }
     }
 
 
-    aiVector3D ReadVertex() {
+    aiVector3D ReadVertex(XmlNode &node) {
         aiVector3D vertex;
         aiVector3D vertex;
-
-        vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
-        vertex.y = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::y.c_str()), nullptr);
-        vertex.z = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::z.c_str()), nullptr);
+        vertex.x = ai_strtof(node.attribute(D3MF::XmlTag::x.c_str()).as_string(), nullptr);
+        vertex.y = ai_strtof(node.attribute(D3MF::XmlTag::y.c_str()).as_string(), nullptr);
+        vertex.z = ai_strtof(node.attribute(D3MF::XmlTag::z.c_str()).as_string(), nullptr);
 
 
         return vertex;
         return vertex;
     }
     }
 
 
-    void ImportTriangles(aiMesh *mesh) {
+    void ImportTriangles(XmlNode &node, aiMesh *mesh) {
         std::vector<aiFace> faces;
         std::vector<aiFace> faces;
-
-        while (ReadToEndElement(D3MF::XmlTag::triangles)) {
-            const std::string nodeName(xmlReader->getNodeName());
-            if (xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
-                faces.push_back(ReadTriangle());
-                const char *pidToken(xmlReader->getAttributeValue(D3MF::XmlTag::p1.c_str()));
-                if (nullptr != pidToken) {
-                    int matIdx(std::atoi(pidToken));
-                    mesh->mMaterialIndex = matIdx;
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string &currentName = currentNode.name();
+            if (currentName == D3MF::XmlTag::triangle) {
+                aiFace face = ReadTriangle(currentNode);
+                faces.push_back(face);
+
+                int pid, p1;
+                bool hasPid = getNodeAttribute(currentNode, D3MF::XmlTag::pid, pid);
+                bool hasP1 = getNodeAttribute(currentNode, D3MF::XmlTag::p1, p1);
+
+                if (hasPid && hasP1) {
+                    auto it = mResourcesDictionnary.find(pid);
+                    if (it != mResourcesDictionnary.end())
+                    {
+                        if (it->second->getType() == ResourceType::RT_BaseMaterials) {
+                            BaseMaterials *baseMaterials = static_cast<BaseMaterials *>(it->second);
+                            mesh->mMaterialIndex = baseMaterials->mMaterialIndex[p1];
+                        }
+                        // TODO: manage the separation into several meshes if the triangles of the mesh do not all refer to the same material
+                    }
                 }
                 }
             }
             }
         }
         }
@@ -255,40 +452,33 @@ private:
         std::copy(faces.begin(), faces.end(), mesh->mFaces);
         std::copy(faces.begin(), faces.end(), mesh->mFaces);
     }
     }
 
 
-    aiFace ReadTriangle() {
+    aiFace ReadTriangle(XmlNode &node) {
         aiFace face;
         aiFace face;
 
 
         face.mNumIndices = 3;
         face.mNumIndices = 3;
         face.mIndices = new unsigned int[face.mNumIndices];
         face.mIndices = new unsigned int[face.mNumIndices];
-        face.mIndices[0] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v1.c_str())));
-        face.mIndices[1] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v2.c_str())));
-        face.mIndices[2] = static_cast<unsigned int>(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v3.c_str())));
+        face.mIndices[0] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v1.c_str()).as_string()));
+        face.mIndices[1] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v2.c_str()).as_string()));
+        face.mIndices[2] = static_cast<unsigned int>(std::atoi(node.attribute(D3MF::XmlTag::v3.c_str()).as_string()));
 
 
         return face;
         return face;
     }
     }
 
 
-    void ReadBaseMaterials() {
-        std::vector<unsigned int> MatIdArray;
-        const char *baseMaterialId(xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_id.c_str()));
-        if (nullptr != baseMaterialId) {
-            unsigned int id = std::atoi(baseMaterialId);
-            const size_t newMatIdx(mMatArray.size());
-            if (id != mActiveMatGroup) {
-                mActiveMatGroup = id;
-                MatId2MatArray::const_iterator it(mMatId2MatArray.find(id));
-                if (mMatId2MatArray.end() == it) {
-                    MatIdArray.clear();
-                    mMatId2MatArray[id] = MatIdArray;
-                } else {
-                    MatIdArray = it->second;
+    void ReadBaseMaterials(XmlNode &node) {
+        int id = -1;
+        if (getNodeAttribute(node, D3MF::XmlTag::basematerials_id, id)) {
+            BaseMaterials* baseMaterials = new BaseMaterials(id);
+
+            for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling())
+            {
+                if (currentNode.name() == D3MF::XmlTag::basematerials_base) {
+                    baseMaterials->mMaterialIndex.push_back(mMaterialCount);
+                    baseMaterials->mMaterials.push_back(readMaterialDef(currentNode, id));
+                    mMaterialCount++;
                 }
                 }
             }
             }
-            MatIdArray.push_back(static_cast<unsigned int>(newMatIdx));
-            mMatId2MatArray[mActiveMatGroup] = MatIdArray;
-        }
 
 
-        while (ReadToEndElement(D3MF::XmlTag::basematerials)) {
-            mMatArray.push_back(readMaterialDef());
+            mResourcesDictionnary.insert(std::make_pair(id, baseMaterials));
         }
         }
     }
     }
 
 
@@ -304,102 +494,60 @@ private:
         }
         }
 
 
         const char *buf(color);
         const char *buf(color);
-        if ('#' != *buf) {
+        if ('#' != buf[0]) {
             return false;
             return false;
         }
         }
-        ++buf;
-        char comp[3] = { 0, 0, '\0' };
-
-        comp[0] = *buf;
-        ++buf;
-        comp[1] = *buf;
-        ++buf;
-        diffuse.r = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
-
-        comp[0] = *buf;
-        ++buf;
-        comp[1] = *buf;
-        ++buf;
-        diffuse.g = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
-
-        comp[0] = *buf;
-        ++buf;
-        comp[1] = *buf;
-        ++buf;
-        diffuse.b = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
+
+        char r[3] = { buf[1], buf[2], '\0' };
+        diffuse.r = static_cast<ai_real>(strtol(r, nullptr, 16)) / ai_real(255.0);
+
+        char g[3] = { buf[3], buf[4], '\0' };
+        diffuse.g = static_cast<ai_real>(strtol(g, nullptr, 16)) / ai_real(255.0);
+
+        char b[3] = { buf[5], buf[6], '\0' };
+        diffuse.b = static_cast<ai_real>(strtol(b, nullptr, 16)) / ai_real(255.0);
 
 
         if (7 == len)
         if (7 == len)
             return true;
             return true;
-        comp[0] = *buf;
-        ++buf;
-        comp[1] = *buf;
-        ++buf;
-        diffuse.a = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
+
+        char a[3] = { buf[7], buf[8], '\0' };
+        diffuse.a = static_cast<ai_real>(strtol(a, nullptr, 16)) / ai_real(255.0);
 
 
         return true;
         return true;
     }
     }
 
 
-    void assignDiffuseColor(aiMaterial *mat) {
-        const char *color = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_displaycolor.c_str());
+    void assignDiffuseColor(XmlNode &node, aiMaterial *mat) {
+        const char *color = node.attribute(D3MF::XmlTag::basematerials_displaycolor.c_str()).as_string();
         aiColor4D diffuse;
         aiColor4D diffuse;
         if (parseColor(color, diffuse)) {
         if (parseColor(color, diffuse)) {
             mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
             mat->AddProperty<aiColor4D>(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE);
         }
         }
     }
     }
-    aiMaterial *readMaterialDef() {
-        aiMaterial *mat(nullptr);
-        const char *name(nullptr);
-        const std::string nodeName(xmlReader->getNodeName());
-        if (nodeName == D3MF::XmlTag::basematerials_base) {
-            name = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_name.c_str());
-            std::string stdMatName;
-            aiString matName;
-            std::string strId(to_string(mActiveMatGroup));
-            stdMatName += "id";
-            stdMatName += strId;
-            stdMatName += "_";
-            if (nullptr != name) {
-                stdMatName += std::string(name);
-            } else {
-                stdMatName += "basemat";
-            }
-            matName.Set(stdMatName);
-
-            mat = new aiMaterial;
-            mat->AddProperty(&matName, AI_MATKEY_NAME);
-
-            assignDiffuseColor(mat);
-        }
 
 
-        return mat;
-    }
-
-private:
-    bool ReadToStartElement(const std::string &startTag) {
-        while (xmlReader->read()) {
-            const std::string &nodeName(xmlReader->getNodeName());
-            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
-                return true;
-            } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
-                return false;
-            }
+    aiMaterial *readMaterialDef(XmlNode &node, unsigned int basematerialsId) {
+        aiMaterial *material = new aiMaterial();
+        material->mNumProperties = 0;
+        std::string name;
+        bool hasName = getNodeAttribute(node, D3MF::XmlTag::basematerials_name, name);
+
+        std::string stdMaterialName;
+        std::string strId(to_string(basematerialsId));
+        stdMaterialName += "id";
+        stdMaterialName += strId;
+        stdMaterialName += "_";
+        if (hasName) {
+            stdMaterialName += std::string(name);
+        } else {
+            stdMaterialName += "basemat_";
+            stdMaterialName += to_string(mMaterialCount - basematerialsId);
         }
         }
 
 
-        return false;
-    }
+        aiString assimpMaterialName(stdMaterialName);
+        material->AddProperty(&assimpMaterialName, AI_MATKEY_NAME);
 
 
-    bool ReadToEndElement(const std::string &closeTag) {
-        while (xmlReader->read()) {
-            const std::string &nodeName(xmlReader->getNodeName());
-            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
-                return true;
-            } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
-                return false;
-            }
-        }
-        ASSIMP_LOG_ERROR("unexpected EOF, expected closing <" + closeTag + "> tag");
+        assignDiffuseColor(node, material);
 
 
-        return false;
+        return material;
     }
     }
 
 
 private:
 private:
@@ -408,11 +556,9 @@ private:
         std::string value;
         std::string value;
     };
     };
     std::vector<MetaEntry> mMetaData;
     std::vector<MetaEntry> mMetaData;
-    std::vector<aiMesh *> mMeshes;
-    MatArray mMatArray;
-    unsigned int mActiveMatGroup;
-    MatId2MatArray mMatId2MatArray;
-    XmlReader *xmlReader;
+    std::map<unsigned int, Resource*> mResourcesDictionnary;
+    unsigned int mMaterialCount, mMeshCount;
+    XmlParser *mXmlParser;
 };
 };
 
 
 } //namespace D3MF
 } //namespace D3MF
@@ -468,12 +614,11 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
 void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
 void D3MFImporter::InternReadFile(const std::string &filename, aiScene *pScene, IOSystem *pIOHandler) {
     D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
     D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
 
 
-    std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
-    std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get()));
-
-    D3MF::XmlSerializer xmlSerializer(xmlReader.get());
-
-    xmlSerializer.ImportXml(pScene);
+    XmlParser xmlParser;
+    if (xmlParser.parse(opcPackage.RootStream())) {
+        D3MF::XmlSerializer xmlSerializer(&xmlParser);
+        xmlSerializer.ImportXml(pScene);
+    }
 }
 }
 
 
 } // Namespace Assimp
 } // Namespace Assimp

+ 35 - 29
code/AssetLib/3MF/D3MFOpcPackage.cpp

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "D3MFOpcPackage.h"
 #include "D3MFOpcPackage.h"
 #include <assimp/Exceptional.h>
 #include <assimp/Exceptional.h>
 
 
+#include <assimp/XmlParser.h>
 #include <assimp/ZipArchiveIOSystem.h>
 #include <assimp/ZipArchiveIOSystem.h>
 #include <assimp/ai_assert.h>
 #include <assimp/ai_assert.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/DefaultLogger.hpp>
@@ -68,27 +68,22 @@ typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
 
 
 class OpcPackageRelationshipReader {
 class OpcPackageRelationshipReader {
 public:
 public:
-    OpcPackageRelationshipReader(XmlReader *xmlReader) {
-        while (xmlReader->read()) {
-            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
-                    xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) {
-                ParseRootNode(xmlReader);
-            }
-        }
+    OpcPackageRelationshipReader(XmlParser &parser) {
+        XmlNode root = parser.getRootNode();
+        ParseRootNode(root);
     }
     }
 
 
-    void ParseRootNode(XmlReader *xmlReader) {
-        ParseAttributes(xmlReader);
-
-        while (xmlReader->read()) {
-            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
-                    xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) {
-                ParseChildNode(xmlReader);
+    void ParseRootNode(XmlNode &node) {
+        ParseAttributes(node);
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            std::string name = currentNode.name();
+            if (name == "Relationships") {
+                ParseRelationsNode(currentNode);
             }
             }
         }
         }
     }
     }
 
 
-    void ParseAttributes(XmlReader *) {
+    void ParseAttributes(XmlNode & /*node*/) {
         // empty
         // empty
     }
     }
 
 
@@ -99,14 +94,22 @@ public:
         return true;
         return true;
     }
     }
 
 
-    void ParseChildNode(XmlReader *xmlReader) {
-        OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
+    void ParseRelationsNode(XmlNode &node) {
+        if (node.empty()) {
+            return;
+        }
 
 
-        relPtr->id = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_ID.c_str());
-        relPtr->type = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TYPE.c_str());
-        relPtr->target = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TARGET.c_str());
-        if (validateRels(relPtr)) {
-            m_relationShips.push_back(relPtr);
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            std::string name = currentNode.name();
+            if (name == "Relationship") {
+                OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
+                relPtr->id = currentNode.attribute(XmlTag::RELS_ATTRIB_ID.c_str()).as_string();
+                relPtr->type = currentNode.attribute(XmlTag::RELS_ATTRIB_TYPE.c_str()).as_string();
+                relPtr->target = currentNode.attribute(XmlTag::RELS_ATTRIB_TARGET.c_str()).as_string();
+                if (validateRels(relPtr)) {
+                    m_relationShips.push_back(relPtr);
+                }
+            }
         }
         }
     }
     }
 
 
@@ -115,10 +118,11 @@ public:
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
 D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
-        mRootStream(nullptr), mZipArchive() {
+        mRootStream(nullptr),
+        mZipArchive() {
     mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile));
     mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile));
     if (!mZipArchive->isOpen()) {
     if (!mZipArchive->isOpen()) {
-        throw DeadlyImportError("Failed to open file " + rFile + ".");
+        throw DeadlyImportError("Failed to open file ", rFile, ".");
     }
     }
 
 
     std::vector<std::string> fileList;
     std::vector<std::string> fileList;
@@ -182,17 +186,19 @@ bool D3MFOpcPackage::validate() {
 }
 }
 
 
 std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
 std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream *stream) {
-    std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
-    std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
+    XmlParser xmlParser;
+    if (!xmlParser.parse(stream)) {
+        return "";
+    }
 
 
-    OpcPackageRelationshipReader reader(xml.get());
+    OpcPackageRelationshipReader reader(xmlParser);
 
 
     auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr &rel) {
     auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr &rel) {
         return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
         return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
     });
     });
 
 
     if (itr == reader.m_relationShips.end()) {
     if (itr == reader.m_relationShips.end()) {
-        throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
+        throw DeadlyImportError("Cannot find ", XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
     }
     }
 
 
     return (*itr)->target;
     return (*itr)->target;

+ 2 - 7
code/AssetLib/3MF/D3MFOpcPackage.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -44,18 +43,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define D3MFOPCPACKAGE_H
 #define D3MFOPCPACKAGE_H
 
 
 #include <memory>
 #include <memory>
-
+#include <string>
 #include <assimp/IOSystem.hpp>
 #include <assimp/IOSystem.hpp>
-#include <assimp/irrXMLWrapper.h>
 
 
 namespace Assimp {
 namespace Assimp {
     class ZipArchiveIOSystem;
     class ZipArchiveIOSystem;
 
 
 namespace D3MF {
 namespace D3MF {
 
 
-using XmlReader = irr::io::IrrXMLReader ;
-using XmlReaderPtr = std::shared_ptr<XmlReader> ;
-
 struct OpcPackageRelationship {
 struct OpcPackageRelationship {
     std::string id;
     std::string id;
     std::string type;
     std::string type;
@@ -64,7 +59,7 @@ struct OpcPackageRelationship {
 
 
 class D3MFOpcPackage {
 class D3MFOpcPackage {
 public:
 public:
-    D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile );
+    D3MFOpcPackage( IOSystem* pIOHandler, const std::string& file );
     ~D3MFOpcPackage();
     ~D3MFOpcPackage();
     IOStream* RootStream() const;
     IOStream* RootStream() const;
     bool validate();
     bool validate();

+ 78 - 13
code/AssetLib/AC/ACLoader.cpp

@@ -471,26 +471,33 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
                     ++node->mNumMeshes;
                     ++node->mNumMeshes;
                 }
                 }
 
 
-                switch ((*it).flags & 0xf) {
+                switch ((*it).GetType()) {
                     // closed line
                     // closed line
-                case 0x1:
+                case Surface::ClosedLine:
                     needMat[idx].first += (unsigned int)(*it).entries.size();
                     needMat[idx].first += (unsigned int)(*it).entries.size();
                     needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
                     needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
                     break;
                     break;
 
 
                     // unclosed line
                     // unclosed line
-                case 0x2:
+                case Surface::OpenLine:
                     needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
                     needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
                     needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
                     needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
                     break;
                     break;
 
 
-                    // 0 == polygon, else unknown
+                    // triangle strip
+                case Surface::TriangleStrip:
+                    needMat[idx].first += (unsigned int)(*it).entries.size() - 2;
+                    needMat[idx].second += ((unsigned int)(*it).entries.size() - 2) * 3;
+                    break;
+
                 default:
                 default:
-                    if ((*it).flags & 0xf) {
-                        ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
-                        (*it).flags &= ~(0xf);
-                    }
+                    // Coerce unknowns to a polygon and warn
+                    ASSIMP_LOG_WARN_F("AC3D: The type flag of a surface is unknown: ", (*it).flags);
+                    (*it).flags &= ~(Surface::Mask);
+                    // fallthrough
 
 
+                    // polygon
+                case Surface::Polygon:
                     // the number of faces increments by one, the number
                     // the number of faces increments by one, the number
                     // of vertices by surface.numref.
                     // of vertices by surface.numref.
                     needMat[idx].first++;
                     needMat[idx].first++;
@@ -546,8 +553,8 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
                         const Surface &src = *it;
                         const Surface &src = *it;
 
 
                         // closed polygon
                         // closed polygon
-                        unsigned int type = (*it).flags & 0xf;
-                        if (!type) {
+                        uint8_t type = (*it).GetType();
+                        if (type == Surface::Polygon) {
                             aiFace &face = *faces++;
                             aiFace &face = *faces++;
                             face.mNumIndices = (unsigned int)src.entries.size();
                             face.mNumIndices = (unsigned int)src.entries.size();
                             if (0 != face.mNumIndices) {
                             if (0 != face.mNumIndices) {
@@ -570,13 +577,71 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
                                     }
                                     }
                                 }
                                 }
                             }
                             }
+                        } else if (type == Surface::TriangleStrip) {
+                            for (unsigned int i = 0; i < (unsigned int)src.entries.size() - 2; ++i) {
+                                const Surface::SurfaceEntry &entry1 = src.entries[i];
+                                const Surface::SurfaceEntry &entry2 = src.entries[i + 1];
+                                const Surface::SurfaceEntry &entry3 = src.entries[i + 2];
+
+                                // skip degenerate triangles
+                                if (object.vertices[entry1.first] == object.vertices[entry2.first] ||
+                                        object.vertices[entry1.first] == object.vertices[entry3.first] ||
+                                        object.vertices[entry2.first] == object.vertices[entry3.first]) {
+                                    mesh->mNumFaces--;
+                                    mesh->mNumVertices -= 3;
+                                    continue;
+                                }
+
+                                aiFace &face = *faces++;
+                                face.mNumIndices = 3;
+                                face.mIndices = new unsigned int[face.mNumIndices];
+                                face.mIndices[0] = cur++;
+                                face.mIndices[1] = cur++;
+                                face.mIndices[2] = cur++;
+                                if (!(i & 1)) {
+                                    *vertices++ = object.vertices[entry1.first] + object.translation;
+                                    if (uv) {
+                                        uv->x = entry1.second.x;
+                                        uv->y = entry1.second.y;
+                                        ++uv;
+                                    }
+                                    *vertices++ = object.vertices[entry2.first] + object.translation;
+                                    if (uv) {
+                                        uv->x = entry2.second.x;
+                                        uv->y = entry2.second.y;
+                                        ++uv;
+                                    }
+                                } else {
+                                    *vertices++ = object.vertices[entry2.first] + object.translation;
+                                    if (uv) {
+                                        uv->x = entry2.second.x;
+                                        uv->y = entry2.second.y;
+                                        ++uv;
+                                    }
+                                    *vertices++ = object.vertices[entry1.first] + object.translation;
+                                    if (uv) {
+                                        uv->x = entry1.second.x;
+                                        uv->y = entry1.second.y;
+                                        ++uv;
+                                    }
+                                }
+                                if (static_cast<unsigned>(vertices - mesh->mVertices) >= mesh->mNumVertices) {
+                                    throw DeadlyImportError("AC3D: Invalid number of vertices");
+                                }
+                                *vertices++ = object.vertices[entry3.first] + object.translation;
+                                if (uv) {
+                                    uv->x = entry3.second.x;
+                                    uv->y = entry3.second.y;
+                                    ++uv;
+                                }
+                            }
                         } else {
                         } else {
 
 
                             it2 = (*it).entries.begin();
                             it2 = (*it).entries.begin();
 
 
                             // either a closed or an unclosed line
                             // either a closed or an unclosed line
                             unsigned int tmp = (unsigned int)(*it).entries.size();
                             unsigned int tmp = (unsigned int)(*it).entries.size();
-                            if (0x2 == type) --tmp;
+                            if (Surface::OpenLine == type) --tmp;
                             for (unsigned int m = 0; m < tmp; ++m) {
                             for (unsigned int m = 0; m < tmp; ++m) {
                                 aiFace &face = *faces++;
                                 aiFace &face = *faces++;
 
 
@@ -599,7 +664,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
                                     ++uv;
                                     ++uv;
                                 }
                                 }
 
 
-                                if (0x1 == type && tmp - 1 == m) {
+                                if (Surface::ClosedLine == type && tmp - 1 == m) {
                                     // if this is a closed line repeat its beginning now
                                     // if this is a closed line repeat its beginning now
                                     it2 = (*it).entries.begin();
                                     it2 = (*it).entries.begin();
                                 } else
                                 } else
@@ -697,7 +762,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open AC3D file " + pFile + ".");
+        throw DeadlyImportError("Failed to open AC3D file ", pFile, ".");
     }
     }
 
 
     // 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

+ 31 - 4
code/AssetLib/AC/ACLoader.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -69,7 +68,10 @@ public:
     // Represents an AC3D material
     // Represents an AC3D material
     struct Material {
     struct Material {
         Material() :
         Material() :
-                rgb(0.6f, 0.6f, 0.6f), spec(1.f, 1.f, 1.f), shin(0.f), trans(0.f) {}
+                rgb(0.6f, 0.6f, 0.6f),
+                spec(1.f, 1.f, 1.f),
+                shin(0.f),
+                trans(0.f) {}
 
 
         // base color of the material
         // base color of the material
         aiColor3D rgb;
         aiColor3D rgb;
@@ -96,18 +98,43 @@ public:
     // Represents an AC3D surface
     // Represents an AC3D surface
     struct Surface {
     struct Surface {
         Surface() :
         Surface() :
-                mat(0), flags(0) {}
+                mat(0),
+                flags(0) {}
 
 
         unsigned int mat, flags;
         unsigned int mat, flags;
 
 
         typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
         typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
         std::vector<SurfaceEntry> entries;
         std::vector<SurfaceEntry> entries;
+
+        // Type is low nibble of flags
+        enum Type : uint8_t {
+            Polygon = 0x0,
+            ClosedLine = 0x1,
+            OpenLine = 0x2,
+            TriangleStrip = 0x4, // ACC extension (TORCS and Speed Dreams)
+
+            Mask = 0xf,
+        };
+
+        inline const uint8_t GetType() const { return (flags & Mask); }
     };
     };
 
 
     // Represents an AC3D object
     // Represents an AC3D object
     struct Object {
     struct Object {
         Object() :
         Object() :
-                type(World), name(""), children(), texture(""), texRepeat(1.f, 1.f), texOffset(0.0f, 0.0f), rotation(), translation(), vertices(), surfaces(), numRefs(0), subDiv(0), crease() {}
+                type(World),
+                name(""),
+                children(),
+                texture(""),
+                texRepeat(1.f, 1.f),
+                texOffset(0.0f, 0.0f),
+                rotation(),
+                translation(),
+                vertices(),
+                surfaces(),
+                numRefs(0),
+                subDiv(0),
+                crease() {}
 
 
         // Type description
         // Type description
         enum Type {
         enum Type {

+ 165 - 298
code/AssetLib/AMF/AMFImporter.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -60,8 +58,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 namespace Assimp {
 namespace Assimp {
 
 
-/// \var aiImporterDesc AMFImporter::Description
-/// Conastant which hold importer description
 const aiImporterDesc AMFImporter::Description = {
 const aiImporterDesc AMFImporter::Description = {
     "Additive manufacturing file format(AMF) Importer",
     "Additive manufacturing file format(AMF) Importer",
     "smalcom",
     "smalcom",
@@ -82,7 +78,7 @@ void AMFImporter::Clear() {
     mTexture_Converted.clear();
     mTexture_Converted.clear();
     // Delete all elements
     // Delete all elements
     if (!mNodeElement_List.empty()) {
     if (!mNodeElement_List.empty()) {
-        for (CAMFImporter_NodeElement *ne : mNodeElement_List) {
+        for (AMFNodeElementBase *ne : mNodeElement_List) {
             delete ne;
             delete ne;
         }
         }
 
 
@@ -90,8 +86,18 @@ void AMFImporter::Clear() {
     }
     }
 }
 }
 
 
+AMFImporter::AMFImporter() AI_NO_EXCEPT :
+        mNodeElement_Cur(nullptr),
+        mXmlParser(nullptr),
+        mUnit(),
+        mVersion(),
+        mMaterial_Converted(),
+        mTexture_Converted() {
+    // empty
+}
+
 AMFImporter::~AMFImporter() {
 AMFImporter::~AMFImporter() {
-    if (mReader != nullptr) delete mReader;
+    delete mXmlParser;
     // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
     // Clear() is accounting if data already is deleted. So, just check again if all data is deleted.
     Clear();
     Clear();
 }
 }
@@ -100,10 +106,12 @@ AMFImporter::~AMFImporter() {
 /************************************************************ Functions: find set ************************************************************/
 /************************************************************ Functions: find set ************************************************************/
 /*********************************************************************************************************************************************/
 /*********************************************************************************************************************************************/
 
 
-bool AMFImporter::Find_NodeElement(const std::string &pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement **pNodeElement) const {
-    for (CAMFImporter_NodeElement *ne : mNodeElement_List) {
+bool AMFImporter::Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const {
+    for (AMFNodeElementBase *ne : mNodeElement_List) {
         if ((ne->ID == pID) && (ne->Type == pType)) {
         if ((ne->ID == pID) && (ne->Type == pType)) {
-            if (pNodeElement != nullptr) *pNodeElement = ne;
+            if (pNodeElement != nullptr) {
+                *pNodeElement = ne;
+            }
 
 
             return true;
             return true;
         }
         }
@@ -112,12 +120,13 @@ bool AMFImporter::Find_NodeElement(const std::string &pID, const CAMFImporter_No
     return false;
     return false;
 }
 }
 
 
-bool AMFImporter::Find_ConvertedNode(const std::string &pID, std::list<aiNode *> &pNodeList, aiNode **pNode) const {
+bool AMFImporter::Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const {
     aiString node_name(pID.c_str());
     aiString node_name(pID.c_str());
-
-    for (aiNode *node : pNodeList) {
+    for (aiNode *node : nodeArray) {
         if (node->mName == node_name) {
         if (node->mName == node_name) {
-            if (pNode != nullptr) *pNode = node;
+            if (pNode != nullptr) {
+                *pNode = node;
+            }
 
 
             return true;
             return true;
         }
         }
@@ -129,7 +138,9 @@ bool AMFImporter::Find_ConvertedNode(const std::string &pID, std::list<aiNode *>
 bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const {
 bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const {
     for (const SPP_Material &mat : mMaterial_Converted) {
     for (const SPP_Material &mat : mMaterial_Converted) {
         if (mat.ID == pID) {
         if (mat.ID == pID) {
-            if (pConvertedMaterial != nullptr) *pConvertedMaterial = &mat;
+            if (pConvertedMaterial != nullptr) {
+                *pConvertedMaterial = &mat;
+            }
 
 
             return true;
             return true;
         }
         }
@@ -142,148 +153,38 @@ bool AMFImporter::Find_ConvertedMaterial(const std::string &pID, const SPP_Mater
 /************************************************************ Functions: throw set ***********************************************************/
 /************************************************************ Functions: throw set ***********************************************************/
 /*********************************************************************************************************************************************/
 /*********************************************************************************************************************************************/
 
 
-void AMFImporter::Throw_CloseNotFound(const std::string &pNode) {
-    throw DeadlyImportError("Close tag for node <" + pNode + "> not found. Seems file is corrupt.");
+void AMFImporter::Throw_CloseNotFound(const std::string &nodeName) {
+    throw DeadlyImportError("Close tag for node <" + nodeName + "> not found. Seems file is corrupt.");
 }
 }
 
 
-void AMFImporter::Throw_IncorrectAttr(const std::string &pAttrName) {
-    throw DeadlyImportError("Node <" + std::string(mReader->getNodeName()) + "> has incorrect attribute \"" + pAttrName + "\".");
+void AMFImporter::Throw_IncorrectAttr(const std::string &nodeName, const std::string &attrName) {
+    throw DeadlyImportError("Node <" + nodeName + "> has incorrect attribute \"" + attrName + "\".");
 }
 }
 
 
-void AMFImporter::Throw_IncorrectAttrValue(const std::string &pAttrName) {
-    throw DeadlyImportError("Attribute \"" + pAttrName + "\" in node <" + std::string(mReader->getNodeName()) + "> has incorrect value.");
+void AMFImporter::Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &attrName) {
+    throw DeadlyImportError("Attribute \"" + attrName + "\" in node <" + nodeName + "> has incorrect value.");
 }
 }
 
 
-void AMFImporter::Throw_MoreThanOnceDefined(const std::string &pNodeType, const std::string &pDescription) {
-    throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + mReader->getNodeName() + ". Description: " + pDescription);
+void AMFImporter::Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription) {
+    throw DeadlyImportError("\"" + pNodeType + "\" node can be used only once in " + nodeName + ". Description: " + pDescription);
 }
 }
 
 
 void AMFImporter::Throw_ID_NotFound(const std::string &pID) const {
 void AMFImporter::Throw_ID_NotFound(const std::string &pID) const {
-    throw DeadlyImportError("Not found node with name \"" + pID + "\".");
+    throw DeadlyImportError("Not found node with name \"", pID, "\".");
 }
 }
 
 
 /*********************************************************************************************************************************************/
 /*********************************************************************************************************************************************/
 /************************************************************* Functions: XML set ************************************************************/
 /************************************************************* Functions: XML set ************************************************************/
 /*********************************************************************************************************************************************/
 /*********************************************************************************************************************************************/
 
 
-void AMFImporter::XML_CheckNode_MustHaveChildren() {
-    if (mReader->isEmptyElement()) throw DeadlyImportError(std::string("Node <") + mReader->getNodeName() + "> must have children.");
-}
-
-void AMFImporter::XML_CheckNode_SkipUnsupported(const std::string &pParentNodeName) {
-    static const size_t Uns_Skip_Len = 3;
-    const char *Uns_Skip[Uns_Skip_Len] = { "composite", "edge", "normal" };
-
-    static bool skipped_before[Uns_Skip_Len] = { false, false, false };
-
-    std::string nn(mReader->getNodeName());
-    bool found = false;
-    bool close_found = false;
-    size_t sk_idx;
-
-    for (sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++) {
-        if (nn != Uns_Skip[sk_idx]) continue;
-
-        found = true;
-        if (mReader->isEmptyElement()) {
-            close_found = true;
-
-            goto casu_cres;
-        }
-
-        while (mReader->read()) {
-            if ((mReader->getNodeType() == irr::io::EXN_ELEMENT_END) && (nn == mReader->getNodeName())) {
-                close_found = true;
-
-                goto casu_cres;
-            }
-        }
-    } // for(sk_idx = 0; sk_idx < Uns_Skip_Len; sk_idx++)
-
-casu_cres:
-
-    if (!found) throw DeadlyImportError("Unknown node \"" + nn + "\" in " + pParentNodeName + ".");
-    if (!close_found) Throw_CloseNotFound(nn);
-
-    if (!skipped_before[sk_idx]) {
-        skipped_before[sk_idx] = true;
-        ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, ".");
-    }
-}
-
-bool AMFImporter::XML_SearchNode(const std::string &pNodeName) {
-    while (mReader->read()) {
-        if ((mReader->getNodeType() == irr::io::EXN_ELEMENT) && XML_CheckNode_NameEqual(pNodeName)) return true;
+void AMFImporter::XML_CheckNode_MustHaveChildren(pugi::xml_node &node) {
+    if (node.children().begin() == node.children().end()) {
+        throw DeadlyImportError(std::string("Node <") + node.name() + "> must have children.");
     }
     }
-
-    return false;
-}
-
-bool AMFImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) {
-    std::string val(mReader->getAttributeValue(pAttrIdx));
-
-    if ((val == "false") || (val == "0"))
-        return false;
-    else if ((val == "true") || (val == "1"))
-        return true;
-    else
-        throw DeadlyImportError("Bool attribute value can contain \"false\"/\"0\" or \"true\"/\"1\" not the \"" + val + "\"");
-}
-
-float AMFImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) {
-    std::string val;
-    float tvalf;
-
-    ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val);
-    fast_atoreal_move(val.c_str(), tvalf, false);
-
-    return tvalf;
-}
-
-uint32_t AMFImporter::XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx) {
-    return strtoul10(mReader->getAttributeValue(pAttrIdx));
-}
-
-float AMFImporter::XML_ReadNode_GetVal_AsFloat() {
-    std::string val;
-    float tvalf;
-
-    if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. No data, seems file is corrupt.");
-    if (mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsFloat. Invalid type of XML element, seems file is corrupt.");
-
-    ParseHelper_FixTruncatedFloatString(mReader->getNodeData(), val);
-    fast_atoreal_move(val.c_str(), tvalf, false);
-
-    return tvalf;
-}
-
-uint32_t AMFImporter::XML_ReadNode_GetVal_AsU32() {
-    if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. No data, seems file is corrupt.");
-    if (mReader->getNodeType() != irr::io::EXN_TEXT) throw DeadlyImportError("XML_ReadNode_GetVal_AsU32. Invalid type of XML element, seems file is corrupt.");
-
-    return strtoul10(mReader->getNodeData());
-}
-
-void AMFImporter::XML_ReadNode_GetVal_AsString(std::string &pValue) {
-    if (!mReader->read()) throw DeadlyImportError("XML_ReadNode_GetVal_AsString. No data, seems file is corrupt.");
-    if (mReader->getNodeType() != irr::io::EXN_TEXT)
-        throw DeadlyImportError("XML_ReadNode_GetVal_AsString. Invalid type of XML element, seems file is corrupt.");
-
-    pValue = mReader->getNodeData();
-}
-
-/*********************************************************************************************************************************************/
-/************************************************************ Functions: parse set ***********************************************************/
-/*********************************************************************************************************************************************/
-
-void AMFImporter::ParseHelper_Node_Enter(CAMFImporter_NodeElement *pNode) {
-    mNodeElement_Cur->Child.push_back(pNode); // add new element to current element child list.
-    mNodeElement_Cur = pNode; // switch current element to new one.
 }
 }
 
 
-void AMFImporter::ParseHelper_Node_Exit() {
-    // check if we can walk up.
-    if (mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
+bool AMFImporter::XML_SearchNode(const std::string &nodeName) {
+    return nullptr != mXmlParser->findNode(nodeName);
 }
 }
 
 
 void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) {
 void AMFImporter::ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString) {
@@ -362,29 +263,33 @@ void AMFImporter::ParseHelper_Decode_Base64(const std::string &pInputBase64, std
 }
 }
 
 
 void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
 void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
-    irr::io::IrrXMLReader *OldReader = mReader; // store current XMLreader.
     std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
     std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open AMF file " + pFile + ".");
+        throw DeadlyImportError("Failed to open AMF file ", pFile, ".");
     }
     }
 
 
-    // generate a XML reader for it
-    std::unique_ptr<CIrrXML_IOStreamReader> mIOWrapper(new CIrrXML_IOStreamReader(file.get()));
-    mReader = irr::io::createIrrXMLReader(mIOWrapper.get());
-    if (!mReader) throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
-    //
-    // start reading
-    // search for root tag <amf>
-    if (XML_SearchNode("amf"))
-        ParseNode_Root();
-    else
+    mXmlParser = new XmlParser();
+    if (!mXmlParser->parse(file.get())) {
+        delete mXmlParser;
+        throw DeadlyImportError("Failed to create XML reader for file" + pFile + ".");
+    }
+
+    // Start reading, search for root tag <amf>
+    if (!mXmlParser->hasNode("amf")) {
         throw DeadlyImportError("Root node \"amf\" not found.");
         throw DeadlyImportError("Root node \"amf\" not found.");
+    }
+    ParseNode_Root();
+} // namespace Assimp
 
 
-    delete mReader;
-    // restore old XMLreader
-    mReader = OldReader;
+void AMFImporter::ParseHelper_Node_Enter(AMFNodeElementBase *node) {
+    mNodeElement_Cur->Child.push_back(node); // add new element to current element child list.
+    mNodeElement_Cur = node;
+}
+
+void AMFImporter::ParseHelper_Node_Exit() {
+    if (mNodeElement_Cur != nullptr) mNodeElement_Cur = mNodeElement_Cur->Parent;
 }
 }
 
 
 // <amf
 // <amf
@@ -395,54 +300,48 @@ void AMFImporter::ParseFile(const std::string &pFile, IOSystem *pIOHandler) {
 // Root XML element.
 // Root XML element.
 // Multi elements - No.
 // Multi elements - No.
 void AMFImporter::ParseNode_Root() {
 void AMFImporter::ParseNode_Root() {
-    std::string unit, version;
-    CAMFImporter_NodeElement *ne(nullptr);
+    AMFNodeElementBase *ne = nullptr;
+    XmlNode *root = mXmlParser->findNode("amf");
+    if (nullptr == root) {
+        throw DeadlyImportError("Root node \"amf\" not found.");
+    }
+    XmlNode node = *root;
+    mUnit = node.attribute("unit").as_string();
+    mVersion = node.attribute("version").as_string();
 
 
     // Read attributes for node <amf>.
     // Read attributes for node <amf>.
-    MACRO_ATTRREAD_LOOPBEG;
-    MACRO_ATTRREAD_CHECK_RET("unit", unit, mReader->getAttributeValue);
-    MACRO_ATTRREAD_CHECK_RET("version", version, mReader->getAttributeValue);
-    MACRO_ATTRREAD_LOOPEND_WSKIP;
-
     // Check attributes
     // Check attributes
     if (!mUnit.empty()) {
     if (!mUnit.empty()) {
-        if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) Throw_IncorrectAttrValue("unit");
+        if ((mUnit != "inch") && (mUnit != "millimeter") && (mUnit != "meter") && (mUnit != "feet") && (mUnit != "micron")) {
+            Throw_IncorrectAttrValue("unit", mUnit);
+        }
     }
     }
 
 
     // create root node element.
     // create root node element.
-    ne = new CAMFImporter_NodeElement_Root(nullptr);
+    ne = new AMFRoot(nullptr);
+
     mNodeElement_Cur = ne; // set first "current" element
     mNodeElement_Cur = ne; // set first "current" element
     // and assign attribute's values
     // and assign attribute's values
-    ((CAMFImporter_NodeElement_Root *)ne)->Unit = unit;
-    ((CAMFImporter_NodeElement_Root *)ne)->Version = version;
+    ((AMFRoot *)ne)->Unit = mUnit;
+    ((AMFRoot *)ne)->Version = mVersion;
 
 
     // Check for child nodes
     // Check for child nodes
-    if (!mReader->isEmptyElement()) {
-        MACRO_NODECHECK_LOOPBEGIN("amf");
-        if (XML_CheckNode_NameEqual("object")) {
-            ParseNode_Object();
-            continue;
-        }
-        if (XML_CheckNode_NameEqual("material")) {
-            ParseNode_Material();
-            continue;
-        }
-        if (XML_CheckNode_NameEqual("texture")) {
-            ParseNode_Texture();
-            continue;
+    for (XmlNode &currentNode : node.children() ) {
+        const std::string currentName = currentNode.name();
+        if (currentName == "object") {
+            ParseNode_Object(currentNode);
+        } else if (currentName == "material") {
+            ParseNode_Material(currentNode);
+        } else if (currentName == "texture") {
+            ParseNode_Texture(currentNode);
+        } else if (currentName == "constellation") {
+            ParseNode_Constellation(currentNode);
+        } else if (currentName == "metadata") {
+            ParseNode_Metadata(currentNode);
         }
         }
-        if (XML_CheckNode_NameEqual("constellation")) {
-            ParseNode_Constellation();
-            continue;
-        }
-        if (XML_CheckNode_NameEqual("metadata")) {
-            ParseNode_Metadata();
-            continue;
-        }
-        MACRO_NODECHECK_LOOPEND("amf");
-        mNodeElement_Cur = ne; // force restore "current" element
-    } // if(!mReader->isEmptyElement())
-
+        mNodeElement_Cur = ne;
+    }
+    mNodeElement_Cur = ne; // force restore "current" element
     mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph.
     mNodeElement_List.push_back(ne); // add to node element list because its a new object in graph.
 }
 }
 
 
@@ -453,40 +352,34 @@ void AMFImporter::ParseNode_Root() {
 // A collection of objects or constellations with specific relative locations.
 // A collection of objects or constellations with specific relative locations.
 // Multi elements - Yes.
 // Multi elements - Yes.
 // Parent element - <amf>.
 // Parent element - <amf>.
-void AMFImporter::ParseNode_Constellation() {
+void AMFImporter::ParseNode_Constellation(XmlNode &node) {
     std::string id;
     std::string id;
-    CAMFImporter_NodeElement *ne(nullptr);
-
-    // Read attributes for node <constellation>.
-    MACRO_ATTRREAD_LOOPBEG;
-    MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
-    MACRO_ATTRREAD_LOOPEND;
+    id = node.attribute("id").as_string();
 
 
     // create and if needed - define new grouping object.
     // create and if needed - define new grouping object.
-    ne = new CAMFImporter_NodeElement_Constellation(mNodeElement_Cur);
+    AMFNodeElementBase *ne = new AMFConstellation(mNodeElement_Cur);
 
 
-    CAMFImporter_NodeElement_Constellation &als = *((CAMFImporter_NodeElement_Constellation *)ne); // alias for convenience
+    AMFConstellation &als = *((AMFConstellation *)ne); // alias for convenience
+
+    if (!id.empty()) {
+        als.ID = id;
+    }
 
 
-    if (!id.empty()) als.ID = id;
     // Check for child nodes
     // Check for child nodes
-    if (!mReader->isEmptyElement()) {
+    if (!node.empty()) {
         ParseHelper_Node_Enter(ne);
         ParseHelper_Node_Enter(ne);
-        MACRO_NODECHECK_LOOPBEGIN("constellation");
-        if (XML_CheckNode_NameEqual("instance")) {
-            ParseNode_Instance();
-            continue;
-        }
-        if (XML_CheckNode_NameEqual("metadata")) {
-            ParseNode_Metadata();
-            continue;
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            std::string name = currentNode.name();
+            if (name == "instance") {
+                ParseNode_Instance(currentNode);
+            } else if (name == "metadata") {
+                ParseNode_Metadata(currentNode);
+            }
         }
         }
-        MACRO_NODECHECK_LOOPEND("constellation");
         ParseHelper_Node_Exit();
         ParseHelper_Node_Exit();
-    } // if(!mReader->isEmptyElement())
-    else {
-        mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
-    } // if(!mReader->isEmptyElement()) else
-
+    } else {
+        mNodeElement_Cur->Child.push_back(ne);
+    }
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
 
 
@@ -497,47 +390,43 @@ void AMFImporter::ParseNode_Constellation() {
 // A collection of objects or constellations with specific relative locations.
 // A collection of objects or constellations with specific relative locations.
 // Multi elements - Yes.
 // Multi elements - Yes.
 // Parent element - <amf>.
 // Parent element - <amf>.
-void AMFImporter::ParseNode_Instance() {
-    std::string objectid;
-    CAMFImporter_NodeElement *ne(nullptr);
+void AMFImporter::ParseNode_Instance(XmlNode &node) {
+    AMFNodeElementBase *ne(nullptr);
 
 
     // Read attributes for node <constellation>.
     // Read attributes for node <constellation>.
-    MACRO_ATTRREAD_LOOPBEG;
-    MACRO_ATTRREAD_CHECK_RET("objectid", objectid, mReader->getAttributeValue);
-    MACRO_ATTRREAD_LOOPEND;
+    std::string objectid = node.attribute("objectid").as_string();
 
 
     // used object id must be defined, check that.
     // used object id must be defined, check that.
-    if (objectid.empty()) throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
+    if (objectid.empty()) {
+        throw DeadlyImportError("\"objectid\" in <instance> must be defined.");
+    }
     // create and define new grouping object.
     // create and define new grouping object.
-    ne = new CAMFImporter_NodeElement_Instance(mNodeElement_Cur);
-
-    CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne); // alias for convenience
-
+    ne = new AMFInstance(mNodeElement_Cur);
+    AMFInstance &als = *((AMFInstance *)ne);
     als.ObjectID = objectid;
     als.ObjectID = objectid;
-    // Check for child nodes
-    if (!mReader->isEmptyElement()) {
-        bool read_flag[6] = { false, false, false, false, false, false };
 
 
-        als.Delta.Set(0, 0, 0);
-        als.Rotation.Set(0, 0, 0);
+    if (!node.empty()) {
         ParseHelper_Node_Enter(ne);
         ParseHelper_Node_Enter(ne);
-        MACRO_NODECHECK_LOOPBEGIN("instance");
-        MACRO_NODECHECK_READCOMP_F("deltax", read_flag[0], als.Delta.x);
-        MACRO_NODECHECK_READCOMP_F("deltay", read_flag[1], als.Delta.y);
-        MACRO_NODECHECK_READCOMP_F("deltaz", read_flag[2], als.Delta.z);
-        MACRO_NODECHECK_READCOMP_F("rx", read_flag[3], als.Rotation.x);
-        MACRO_NODECHECK_READCOMP_F("ry", read_flag[4], als.Rotation.y);
-        MACRO_NODECHECK_READCOMP_F("rz", read_flag[5], als.Rotation.z);
-        MACRO_NODECHECK_LOOPEND("instance");
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string &currentName = currentNode.name();
+            if (currentName == "deltax") {
+                als.Delta.x = (ai_real)std::atof(currentNode.value());
+            } else if (currentName == "deltay") {
+                als.Delta.y = (ai_real)std::atof(currentNode.value());
+            } else if (currentName == "deltaz") {
+                als.Delta.z = (ai_real)std::atof(currentNode.value());
+            } else if (currentName == "rx") {
+                als.Delta.x = (ai_real)std::atof(currentNode.value());
+            } else if (currentName == "ry") {
+                als.Delta.y = (ai_real)std::atof(currentNode.value());
+            } else if (currentName == "rz") {
+                als.Delta.z = (ai_real)std::atof(currentNode.value());
+            }
+        }
         ParseHelper_Node_Exit();
         ParseHelper_Node_Exit();
-        // also convert degrees to radians.
-        als.Rotation.x = AI_MATH_PI_F * als.Rotation.x / 180.0f;
-        als.Rotation.y = AI_MATH_PI_F * als.Rotation.y / 180.0f;
-        als.Rotation.z = AI_MATH_PI_F * als.Rotation.z / 180.0f;
-    } // if(!mReader->isEmptyElement())
-    else {
-        mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
-    } // if(!mReader->isEmptyElement()) else
+    } else {
+        mNodeElement_Cur->Child.push_back(ne);
+    }
 
 
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
@@ -549,51 +438,38 @@ void AMFImporter::ParseNode_Instance() {
 // An object definition.
 // An object definition.
 // Multi elements - Yes.
 // Multi elements - Yes.
 // Parent element - <amf>.
 // Parent element - <amf>.
-void AMFImporter::ParseNode_Object() {
-    std::string id;
-    CAMFImporter_NodeElement *ne(nullptr);
+void AMFImporter::ParseNode_Object(XmlNode &node) {
+    AMFNodeElementBase *ne = nullptr;
 
 
     // Read attributes for node <object>.
     // Read attributes for node <object>.
-    MACRO_ATTRREAD_LOOPBEG;
-    MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
-    MACRO_ATTRREAD_LOOPEND;
+    std::string id = node.attribute("id").as_string();
 
 
     // create and if needed - define new geometry object.
     // create and if needed - define new geometry object.
-    ne = new CAMFImporter_NodeElement_Object(mNodeElement_Cur);
+    ne = new AMFObject(mNodeElement_Cur);
 
 
-    CAMFImporter_NodeElement_Object &als = *((CAMFImporter_NodeElement_Object *)ne); // alias for convenience
+    AMFObject &als = *((AMFObject *)ne); // alias for convenience
 
 
-    if (!id.empty()) als.ID = id;
-    // Check for child nodes
-    if (!mReader->isEmptyElement()) {
-        bool col_read = false;
+    if (!id.empty()) {
+        als.ID = id;
+    }
 
 
+    // Check for child nodes
+    if (!node.empty()) {
         ParseHelper_Node_Enter(ne);
         ParseHelper_Node_Enter(ne);
-        MACRO_NODECHECK_LOOPBEGIN("object");
-        if (XML_CheckNode_NameEqual("color")) {
-            // Check if color already defined for object.
-            if (col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <object>.");
-            // read data and set flag about it
-            ParseNode_Color();
-            col_read = true;
-
-            continue;
-        }
-
-        if (XML_CheckNode_NameEqual("mesh")) {
-            ParseNode_Mesh();
-            continue;
-        }
-        if (XML_CheckNode_NameEqual("metadata")) {
-            ParseNode_Metadata();
-            continue;
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string &currentName = currentNode.name();
+            if (currentName == "color") {
+                ParseNode_Color(currentNode);
+            } else if (currentName == "mesh") {
+                ParseNode_Mesh(currentNode);
+            } else if (currentName == "metadata") {
+                ParseNode_Metadata(currentNode);
+            }
         }
         }
-        MACRO_NODECHECK_LOOPEND("object");
         ParseHelper_Node_Exit();
         ParseHelper_Node_Exit();
-    } // if(!mReader->isEmptyElement())
-    else {
+    } else {
         mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
         mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
-    } // if(!mReader->isEmptyElement()) else
+    }
 
 
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
@@ -616,28 +492,20 @@ void AMFImporter::ParseNode_Object() {
 // "Revision" - specifies the revision of the entity
 // "Revision" - specifies the revision of the entity
 // "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system
 // "Tolerance" - specifies the desired manufacturing tolerance of the entity in entity's unit system
 // "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only)
 // "Volume" - specifies the total volume of the entity, in the entity's unit system, to be used for verification (object and volume only)
-void AMFImporter::ParseNode_Metadata() {
-    std::string type, value;
-    CAMFImporter_NodeElement *ne(nullptr);
+void AMFImporter::ParseNode_Metadata(XmlNode &node) {
+    AMFNodeElementBase *ne = nullptr;
+
+    std::string type = node.attribute("type").as_string(), value;
+    XmlParser::getValueAsString(node, value);
 
 
     // read attribute
     // read attribute
-    MACRO_ATTRREAD_LOOPBEG;
-    MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
-    MACRO_ATTRREAD_LOOPEND;
-    // and value of node.
-    value = mReader->getNodeData();
-    // Create node element and assign read data.
-    ne = new CAMFImporter_NodeElement_Metadata(mNodeElement_Cur);
-    ((CAMFImporter_NodeElement_Metadata *)ne)->Type = type;
-    ((CAMFImporter_NodeElement_Metadata *)ne)->Value = value;
+    ne = new AMFMetadata(mNodeElement_Cur);
+    ((AMFMetadata *)ne)->Type = type;
+    ((AMFMetadata *)ne)->Value = value;
     mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
     mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
     mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
 
 
-/*********************************************************************************************************************************************/
-/******************************************************** Functions: BaseImporter set ********************************************************/
-/*********************************************************************************************************************************************/
-
 bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
 bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const {
     const std::string extension = GetExtension(pFile);
     const std::string extension = GetExtension(pFile);
 
 
@@ -645,9 +513,8 @@ bool AMFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool p
         return true;
         return true;
     }
     }
 
 
-    if (!extension.length() || pCheckSig) {
+    if (extension.empty() || pCheckSig) {
         const char *tokens[] = { "<amf" };
         const char *tokens[] = { "<amf" };
-
         return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
         return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
     }
     }
 
 

+ 177 - 298
code/AssetLib/AMF/AMFImporter.hpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,11 +52,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AMFImporter_Node.hpp"
 #include "AMFImporter_Node.hpp"
 
 
 // Header files, Assimp.
 // Header files, Assimp.
-#include <assimp/DefaultLogger.hpp>
-#include <assimp/importerdesc.h>
 #include "assimp/types.h"
 #include "assimp/types.h"
 #include <assimp/BaseImporter.h>
 #include <assimp/BaseImporter.h>
-#include <assimp/irrXMLWrapper.h>
+#include <assimp/XmlParser.h>
+#include <assimp/importerdesc.h>
+#include <assimp/DefaultLogger.hpp>
 
 
 // Header files, stdlib.
 // Header files, stdlib.
 #include <set>
 #include <set>
@@ -101,22 +99,21 @@ namespace Assimp {
 ///
 ///
 class AMFImporter : public BaseImporter {
 class AMFImporter : public BaseImporter {
 private:
 private:
-    struct SPP_Material;// forward declaration
+    struct SPP_Material; // forward declaration
 
 
-                        /// \struct SPP_Composite
-                        /// Data type for post-processing step. More suitable container for part of material's composition.
+    /// Data type for post-processing step. More suitable container for part of material's composition.
     struct SPP_Composite {
     struct SPP_Composite {
-        SPP_Material* Material;///< Pointer to material - part of composition.
-        std::string Formula;///< Formula for calculating ratio of \ref Material.
+        SPP_Material *Material; ///< Pointer to material - part of composition.
+        std::string Formula; ///< Formula for calculating ratio of \ref Material.
     };
     };
 
 
     /// \struct SPP_Material
     /// \struct SPP_Material
     /// Data type for post-processing step. More suitable container for material.
     /// Data type for post-processing step. More suitable container for material.
     struct SPP_Material {
     struct SPP_Material {
-        std::string ID;///< Material ID.
-        std::list<CAMFImporter_NodeElement_Metadata*> Metadata;///< Metadata of material.
-        CAMFImporter_NodeElement_Color* Color;///< Color of material.
-        std::list<SPP_Composite> Composition;///< List of child materials if current material is composition of few another.
+        std::string ID; ///< Material ID.
+        std::list<AMFMetadata *> Metadata; ///< Metadata of material.
+        AMFColor *Color; ///< Color of material.
+        std::list<SPP_Composite> Composition; ///< List of child materials if current material is composition of few another.
 
 
         /// Return color calculated for specified coordinate.
         /// Return color calculated for specified coordinate.
         /// \param [in] pX - "x" coordinate.
         /// \param [in] pX - "x" coordinate.
@@ -129,304 +126,186 @@ private:
     /// Data type for post-processing step. More suitable container for texture.
     /// Data type for post-processing step. More suitable container for texture.
     struct SPP_Texture {
     struct SPP_Texture {
         std::string ID;
         std::string ID;
-        size_t      Width, Height, Depth;
-        bool        Tiled;
-        char        FormatHint[9];// 8 for string + 1 for terminator.
-        uint8_t    *Data;
+        size_t Width, Height, Depth;
+        bool Tiled;
+        char FormatHint[9]; // 8 for string + 1 for terminator.
+        uint8_t *Data;
     };
     };
 
 
     /// Data type for post-processing step. Contain face data.
     /// Data type for post-processing step. Contain face data.
     struct SComplexFace {
     struct SComplexFace {
-        aiFace Face;///< Face vertices.
-        const CAMFImporter_NodeElement_Color* Color;///< Face color. Equal to nullptr if color is not set for the face.
-        const CAMFImporter_NodeElement_TexMap* TexMap;///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face.
+        aiFace Face; ///< Face vertices.
+        const AMFColor *Color; ///< Face color. Equal to nullptr if color is not set for the face.
+        const AMFTexMap *TexMap; ///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face.
     };
     };
 
 
-	/// Clear all temporary data.
-	void Clear();
-
-	/***********************************************/
-	/************* Functions: find set *************/
-	/***********************************************/
-
-	/// Find specified node element in node elements list ( \ref mNodeElement_List).
-	/// \param [in] pID - ID(name) of requested node element.
-	/// \param [in] pType - type of node element.
-	/// \param [out] pNode - pointer to pointer to item found.
-	/// \return true - if the node element is found, else - false.
-	bool Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const;
-
-	/// Find requested aiNode in node list.
-	/// \param [in] pID - ID(name) of requested node.
-	/// \param [in] pNodeList - list of nodes where to find the node.
-	/// \param [out] pNode - pointer to pointer to item found.
-	/// \return true - if the node is found, else - false.
-	bool Find_ConvertedNode(const std::string& pID, std::list<aiNode*>& pNodeList, aiNode** pNode) const;
-
-	/// Find material in list for converted materials. Use at postprocessing step.
-	/// \param [in] pID - material ID.
-	/// \param [out] pConvertedMaterial - pointer to found converted material (\ref SPP_Material).
-	/// \return true - if the material is found, else - false.
-	bool Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const;
-
-    /// Find texture in list of converted textures. Use at postprocessing step,
-	/// \param [in] pID_R - ID of source "red" texture.
-	/// \param [in] pID_G - ID of source "green" texture.
-	/// \param [in] pID_B - ID of source "blue" texture.
-	/// \param [in] pID_A - ID of source "alpha" texture. Use empty string to find RGB-texture.
-	/// \param [out] pConvertedTextureIndex - pointer where index in list of found texture will be written. If equivalent to nullptr then nothing will be
-	/// written.
-	/// \return true - if the texture is found, else - false.
-	bool Find_ConvertedTexture(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A,
-								uint32_t* pConvertedTextureIndex = nullptr) const;
-
-
-	/// Get data stored in <vertices> and place it to arrays.
-	/// \param [in] pNodeElement - reference to node element which kept <object> data.
-	/// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in <vertices>.
-	/// \param [in] pVertexColorArray - reference to vertices colors for all <vertex's. If color for vertex is not set then corresponding member of array
-	/// contain nullptr.
-	void PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector<aiVector3D>& pVertexCoordinateArray,
-												std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray) const;
-
-	/// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new
-	/// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
-	/// to converted textures list.
-	/// Any of source ID's can be absent(empty string) or even one ID only specified. But at least one ID must be specified.
-	/// \param [in] pID_R - ID of source "red" texture.
-	/// \param [in] pID_G - ID of source "green" texture.
-	/// \param [in] pID_B - ID of source "blue" texture.
-	/// \param [in] pID_A - ID of source "alpha" texture.
-	/// \return index of the texture in array of the converted textures.
-	size_t PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A);
-
-	/// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc).
-	/// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after
-	/// processing.
-	/// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing.
-	void PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace>& pInputList, std::list<std::list<SComplexFace> >& pOutputList_Separated);
-
-	/// Check if child elements of node element is metadata and add it to scene node.
-	/// \param [in] pMetadataList - reference to list with collected metadata.
-	/// \param [out] pSceneNode - scene node in which metadata will be added.
-	void Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& pMetadataList, aiNode& pSceneNode) const;
-
-	/// To create aiMesh and aiNode for it from <object>.
-	/// \param [in] pNodeElement - reference to node element which kept <object> data.
-	/// \param [out] pMeshList - reference to a list with all aiMesh of the scene.
-	/// \param [out] pSceneNode - pointer to place where new aiNode will be created.
-	void Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list<aiMesh*>& pMeshList, aiNode** pSceneNode);
-
-	/// Create mesh for every <volume> in <mesh>.
-	/// \param [in] pNodeElement - reference to node element which kept <mesh> data.
-	/// \param [in] pVertexCoordinateArray - reference to vertices coordinates for all <volume>'s.
-	/// \param [in] pVertexColorArray - reference to vertices colors for all <volume>'s. If color for vertex is not set then corresponding member of array
-	/// contain nullptr.
-	/// \param [in] pObjectColor - pointer to colors for <object>. If color is not set then argument contain nullptr.
-	/// \param [in] pMaterialList - reference to a list with defined materials.
-	/// \param [out] pMeshList - reference to a list with all aiMesh of the scene.
-	/// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's.
-	void Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector<aiVector3D>& pVertexCoordinateArray,
-									const std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray, const CAMFImporter_NodeElement_Color* pObjectColor,
-									std::list<aiMesh*>& pMeshList, aiNode& pSceneNode);
-
-	/// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material.
-	/// \param [in] pMaterial - source CAMFImporter_NodeElement_Material.
-	void Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial);
-
-	/// Create and add to aiNode's list new part of scene graph defined by <constellation>.
-	/// \param [in] pConstellation - reference to <constellation> node.
-	/// \param [out] pNodeList - reference to aiNode's list.
-	void Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list<aiNode*>& pNodeList) const;
-
-	/// Build Assimp scene graph in aiScene from collected data.
-	/// \param [out] pScene - pointer to aiScene where tree will be built.
-	void Postprocess_BuildScene(aiScene* pScene);
-
-
-	/// Call that function when close tag of node not found and exception must be raised.
-	/// E.g.:
-	/// <amf>
-	///     <object>
-	/// </amf> <!--- object not closed --->
-	/// \throw DeadlyImportError.
-	/// \param [in] pNode - node name in which exception happened.
-	void Throw_CloseNotFound(const std::string& pNode);
-
-	/// Call that function when attribute name is incorrect and exception must be raised.
-	/// \param [in] pAttrName - attribute name.
-	/// \throw DeadlyImportError.
-	void Throw_IncorrectAttr(const std::string& pAttrName);
-
-	/// Call that function when attribute value is incorrect and exception must be raised.
-	/// \param [in] pAttrName - attribute name.
-	/// \throw DeadlyImportError.
-	void Throw_IncorrectAttrValue(const std::string& pAttrName);
-
-	/// Call that function when some type of nodes are defined twice or more when must be used only once and exception must be raised.
-	/// E.g.:
-	/// <object>
-	///     <color>...    <!--- color defined --->
-	///     <color>...    <!--- color defined again --->
-	/// </object>
-	/// \throw DeadlyImportError.
-	/// \param [in] pNodeType - type of node which defined one more time.
-	/// \param [in] pDescription - message about error. E.g. what the node defined while exception raised.
-	void Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription);
-
-	/// Call that function when referenced element ID are not found in graph and exception must be raised.
-	/// \param [in] pID - ID of of element which not found.
-	/// \throw DeadlyImportError.
-	void Throw_ID_NotFound(const std::string& pID) const;
-
-	/// Check if current node have children: <node>...</node>. If not then exception will throwed.
-	void XML_CheckNode_MustHaveChildren();
-
-	/// Check if current node name is equal to pNodeName.
-	/// \param [in] pNodeName - name for checking.
-	/// return true if current node name is equal to pNodeName, else - false.
-	bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }
-
-	/// Skip unsupported node and report about that. Depend on node name can be skipped begin tag of node all whole node.
-	/// \param [in] pParentNodeName - parent node name. Used for reporting.
-	void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName);
-
-	/// Search for specified node in file. XML file read pointer(mReader) will point to found node or file end after search is end.
-	/// \param [in] pNodeName - requested node name.
-	/// return true - if node is found, else - false.
-	bool XML_SearchNode(const std::string& pNodeName);
-
-	/// Read attribute value.
-	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
-	/// \return read data.
-	bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx);
-
-	/// Read attribute value.
-	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
-	/// \return read data.
-	float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx);
-
-	/// Read attribute value.
-	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
-	/// \return read data.
-	uint32_t XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx);
-
-	/// Read node value.
-	/// \return read data.
-	float XML_ReadNode_GetVal_AsFloat();
-
-	/// Read node value.
-	/// \return read data.
-	uint32_t XML_ReadNode_GetVal_AsU32();
-
-	/// Read node value.
-	/// \return read data.
-	void XML_ReadNode_GetVal_AsString(std::string& pValue);
-
-	/// Make pNode as current and enter deeper for parsing child nodes. At end \ref ParseHelper_Node_Exit must be called.
-	/// \param [in] pNode - new current node.
-	void ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode);
-
-	/// This function must be called when exiting from grouping node. \ref ParseHelper_Group_Begin.
-	void ParseHelper_Node_Exit();
-
-	/// Attribute values of floating point types can take form ".x"(without leading zero). irrXMLReader can not read this form of values and it
-	/// must be converted to right form - "0.xxx".
-	/// \param [in] pInStr - pointer to input string which can contain incorrect form of values.
-	/// \param [out[ pOutString - output string with right form of values.
-	void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString);
-
-	/// Decode Base64-encoded data.
-	/// \param [in] pInputBase64 - reference to input Base64-encoded string.
-	/// \param [out] pOutputData - reference to output array for decoded data.
-	void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const;
-
-	/// Parse <AMF> node of the file.
-	void ParseNode_Root();
-
-	/// Parse <constellation> node of the file.
-	void ParseNode_Constellation();
-
-	/// Parse <instance> node of the file.
-	void ParseNode_Instance();
-
-	/// Parse <material> node of the file.
-	void ParseNode_Material();
-
-	/// Parse <metadata> node.
-	void ParseNode_Metadata();
-
-	/// Parse <object> node of the file.
-	void ParseNode_Object();
-
-	/// Parse <texture> node of the file.
-	void ParseNode_Texture();
-
-	/// Parse <coordinates> node of the file.
-	void ParseNode_Coordinates();
-
-	/// Parse <edge> node of the file.
-	void ParseNode_Edge();
-
-	/// Parse <mesh> node of the file.
-	void ParseNode_Mesh();
-
-	/// Parse <triangle> node of the file.
-	void ParseNode_Triangle();
-
-	/// Parse <vertex> node of the file.
-	void ParseNode_Vertex();
-
-	/// Parse <vertices> node of the file.
-	void ParseNode_Vertices();
-
-	/// Parse <volume> node of the file.
-	void ParseNode_Volume();
-
-	/// Parse <color> node of the file.
-	void ParseNode_Color();
-
-	/// Parse <texmap> of <map> node of the file.
-	/// \param [in] pUseOldName - if true then use old name of node(and children) - <map>, instead of new name - <texmap>.
-	void ParseNode_TexMap(const bool pUseOldName = false);
+    using AMFMetaDataArray = std::vector<AMFMetadata*>;
+    using MeshArray = std::vector<aiMesh*>;
+    using NodeArray = std::vector<aiNode*>;
+
+    /// Clear all temporary data.
+    void Clear();
+
+    /// Get data stored in <vertices> and place it to arrays.
+    /// \param [in] pNodeElement - reference to node element which kept <object> data.
+    /// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in <vertices>.
+    /// \param [in] pVertexColorArray - reference to vertices colors for all <vertex's. If color for vertex is not set then corresponding member of array
+    /// contain nullptr.
+    void PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray,
+            std::vector<AMFColor *> &pVertexColorArray) const;
+
+    /// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new
+    /// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
+    /// to converted textures list.
+    /// Any of source ID's can be absent(empty string) or even one ID only specified. But at least one ID must be specified.
+    /// \param [in] pID_R - ID of source "red" texture.
+    /// \param [in] pID_G - ID of source "green" texture.
+    /// \param [in] pID_B - ID of source "blue" texture.
+    /// \param [in] pID_A - ID of source "alpha" texture.
+    /// \return index of the texture in array of the converted textures.
+    size_t PostprocessHelper_GetTextureID_Or_Create(const std::string &pID_R, const std::string &pID_G, const std::string &pID_B, const std::string &pID_A);
+
+    /// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc).
+    /// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after
+    /// processing.
+    /// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing.
+    void PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated);
+
+    /// Check if child elements of node element is metadata and add it to scene node.
+    /// \param [in] pMetadataList - reference to list with collected metadata.
+    /// \param [out] pSceneNode - scene node in which metadata will be added.
+    void Postprocess_AddMetadata(const AMFMetaDataArray &pMetadataList, aiNode &pSceneNode) const;
+
+    /// To create aiMesh and aiNode for it from <object>.
+    /// \param [in] pNodeElement - reference to node element which kept <object> data.
+    /// \param [out] meshList    - reference to a list with all aiMesh of the scene.
+    /// \param [out] pSceneNode  - pointer to place where new aiNode will be created.
+    void Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, aiNode **pSceneNode);
+
+    /// Create mesh for every <volume> in <mesh>.
+    /// \param [in] pNodeElement - reference to node element which kept <mesh> data.
+    /// \param [in] pVertexCoordinateArray - reference to vertices coordinates for all <volume>'s.
+    /// \param [in] pVertexColorArray - reference to vertices colors for all <volume>'s. If color for vertex is not set then corresponding member of array
+    /// contain nullptr.
+    /// \param [in] pObjectColor - pointer to colors for <object>. If color is not set then argument contain nullptr.
+    /// \param [in] pMaterialList - reference to a list with defined materials.
+    /// \param [out] pMeshList - reference to a list with all aiMesh of the scene.
+    /// \param [out] pSceneNode - reference to aiNode which will own new aiMesh's.
+    void Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray,
+            const std::vector<AMFColor *> &pVertexColorArray, const AMFColor *pObjectColor,
+            MeshArray &pMeshList, aiNode &pSceneNode);
+
+    /// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material.
+    /// \param [in] pMaterial - source CAMFImporter_NodeElement_Material.
+    void Postprocess_BuildMaterial(const AMFMaterial &pMaterial);
+
+    /// Create and add to aiNode's list new part of scene graph defined by <constellation>.
+    /// \param [in] pConstellation - reference to <constellation> node.
+    /// \param [out] nodeArray     - reference to aiNode's list.
+    void Postprocess_BuildConstellation(AMFConstellation &pConstellation, NodeArray &nodeArray) const;
+
+    /// Build Assimp scene graph in aiScene from collected data.
+    /// \param [out] pScene - pointer to aiScene where tree will be built.
+    void Postprocess_BuildScene(aiScene *pScene);
+
+    /// Decode Base64-encoded data.
+    /// \param [in] pInputBase64 - reference to input Base64-encoded string.
+    /// \param [out] pOutputData - reference to output array for decoded data.
+    void ParseHelper_Decode_Base64(const std::string &pInputBase64, std::vector<uint8_t> &pOutputData) const;
+
+    /// Parse <AMF> node of the file.
+    void ParseNode_Root();
+
+    /// Parse <constellation> node of the file.
+    void ParseNode_Constellation(XmlNode &node);
+
+    /// Parse <instance> node of the file.
+    void ParseNode_Instance(XmlNode &node);
+
+    /// Parse <material> node of the file.
+    void ParseNode_Material(XmlNode &node);
+
+    /// Parse <metadata> node.
+    void ParseNode_Metadata(XmlNode &node);
+
+    /// Parse <object> node of the file.
+    void ParseNode_Object(XmlNode &node);
+
+    /// Parse <texture> node of the file.
+    void ParseNode_Texture(XmlNode &node);
+
+    /// Parse <coordinates> node of the file.
+    void ParseNode_Coordinates(XmlNode &node);
+
+    /// Parse <edge> node of the file.
+    void ParseNode_Edge(XmlNode &node);
+
+    /// Parse <mesh> node of the file.
+    void ParseNode_Mesh(XmlNode &node);
+
+    /// Parse <triangle> node of the file.
+    void ParseNode_Triangle(XmlNode &node);
+
+    /// Parse <vertex> node of the file.
+    void ParseNode_Vertex(XmlNode &node);
+
+    /// Parse <vertices> node of the file.
+    void ParseNode_Vertices(XmlNode &node);
+
+    /// Parse <volume> node of the file.
+    void ParseNode_Volume(XmlNode &node);
+
+    /// Parse <color> node of the file.
+    void ParseNode_Color(XmlNode &node);
+
+    /// Parse <texmap> of <map> node of the file.
+    /// \param [in] pUseOldName - if true then use old name of node(and children) - <map>, instead of new name - <texmap>.
+    void ParseNode_TexMap(XmlNode &node, const bool pUseOldName = false);
 
 
 public:
 public:
-	/// Default constructor.
-	AMFImporter() AI_NO_EXCEPT
-    : mNodeElement_Cur(nullptr)
-    , mReader(nullptr) {
-        // empty
-    }
-
-	/// Default destructor.
-	~AMFImporter();
-
-	/// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph.
-	/// Also exception can be thrown if trouble will found.
-	/// \param [in] pFile - name of file to be parsed.
-	/// \param [in] pIOHandler - pointer to IO helper object.
-	void ParseFile(const std::string& pFile, IOSystem* pIOHandler);
-
-	bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const;
-	void GetExtensionList(std::set<std::string>& pExtensionList);
-	void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
-	const aiImporterDesc* GetInfo ()const;
-
-    AMFImporter(const AMFImporter& pScene) = delete;
-    AMFImporter& operator=(const AMFImporter& pScene) = delete;
+    /// Default constructor.
+    AMFImporter() AI_NO_EXCEPT;
+
+    /// Default destructor.
+    ~AMFImporter();
+
+    /// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph.
+    /// Also exception can be thrown if trouble will found.
+    /// \param [in] pFile - name of file to be parsed.
+    /// \param [in] pIOHandler - pointer to IO helper object.
+    void ParseFile(const std::string &pFile, IOSystem *pIOHandler);
+    void ParseHelper_Node_Enter(AMFNodeElementBase *child);
+    void ParseHelper_Node_Exit();
+    bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool pCheckSig) const;
+    void GetExtensionList(std::set<std::string> &pExtensionList);
+    void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
+    const aiImporterDesc *GetInfo() const;
+    bool Find_NodeElement(const std::string &pID, const AMFNodeElementBase::EType pType, AMFNodeElementBase **pNodeElement) const;
+    bool Find_ConvertedNode(const std::string &pID, NodeArray &nodeArray, aiNode **pNode) const;
+    bool Find_ConvertedMaterial(const std::string &pID, const SPP_Material **pConvertedMaterial) const;
+    void Throw_CloseNotFound(const std::string &nodeName);
+    void Throw_IncorrectAttr(const std::string &nodeName, const std::string &pAttrName);
+    void Throw_IncorrectAttrValue(const std::string &nodeName, const std::string &pAttrName);
+    void Throw_MoreThanOnceDefined(const std::string &nodeName, const std::string &pNodeType, const std::string &pDescription);
+    void Throw_ID_NotFound(const std::string &pID) const;
+    void XML_CheckNode_MustHaveChildren(pugi::xml_node &node);
+    bool XML_SearchNode(const std::string &nodeName);
+    void ParseHelper_FixTruncatedFloatString(const char *pInStr, std::string &pOutString);
+    AMFImporter(const AMFImporter &pScene) = delete;
+    AMFImporter &operator=(const AMFImporter &pScene) = delete;
 
 
 private:
 private:
     static const aiImporterDesc Description;
     static const aiImporterDesc Description;
 
 
-    CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element.
-    std::list<CAMFImporter_NodeElement*> mNodeElement_List;///< All elements of scene graph.
-    irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object
+    AMFNodeElementBase *mNodeElement_Cur; ///< Current element.
+    std::list<AMFNodeElementBase *> mNodeElement_List; ///< All elements of scene graph.
+    XmlParser *mXmlParser;
     std::string mUnit;
     std::string mUnit;
-    std::list<SPP_Material> mMaterial_Converted;///< List of converted materials for postprocessing step.
-    std::list<SPP_Texture> mTexture_Converted;///< List of converted textures for postprocessing step.
-
+    std::string mVersion;
+    std::list<SPP_Material> mMaterial_Converted; ///< List of converted materials for postprocessing step.
+    std::list<SPP_Texture> mTexture_Converted; ///< List of converted textures for postprocessing step.
 };
 };
 
 
-}// namespace Assimp
+} // namespace Assimp
 
 
 #endif // INCLUDED_AI_AMF_IMPORTER_H
 #endif // INCLUDED_AI_AMF_IMPORTER_H

+ 179 - 247
code/AssetLib/AMF/AMFImporter_Geometry.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,48 +49,47 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AMFImporter.hpp"
 #include "AMFImporter.hpp"
 #include "AMFImporter_Macro.hpp"
 #include "AMFImporter_Macro.hpp"
 
 
-namespace Assimp
-{
+#include <assimp/ParsingUtils.h>
+
+namespace Assimp {
 
 
 // <mesh>
 // <mesh>
 // </mesh>
 // </mesh>
 // A 3D mesh hull.
 // A 3D mesh hull.
 // Multi elements - Yes.
 // Multi elements - Yes.
 // Parent element - <object>.
 // Parent element - <object>.
-void AMFImporter::ParseNode_Mesh()
-{
-CAMFImporter_NodeElement* ne;
-
-	// create new mesh object.
-	ne = new CAMFImporter_NodeElement_Mesh(mNodeElement_Cur);
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		bool vert_read = false;
-
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("mesh");
-			if(XML_CheckNode_NameEqual("vertices"))
-			{
-				// Check if data already defined.
-				if(vert_read) Throw_MoreThanOnceDefined("vertices", "Only one vertices set can be defined for <mesh>.");
-				// read data and set flag about it
-				ParseNode_Vertices();
-				vert_read = true;
-
-				continue;
-			}
-
-			if(XML_CheckNode_NameEqual("volume")) { ParseNode_Volume(); continue; }
-		MACRO_NODECHECK_LOOPEND("mesh");
-		ParseHelper_Node_Exit();
-	}// if(!mReader->isEmptyElement())
-	else
-	{
-		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
-
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
+void AMFImporter::ParseNode_Mesh(XmlNode &node) {
+    AMFNodeElementBase *ne = nullptr;
+
+    // Check for child nodes
+    if (0 != ASSIMP_stricmp(node.name(), "mesh")) {
+        return;
+    }
+    // create new mesh object.
+    ne = new AMFMesh(mNodeElement_Cur);
+    bool found_verts = false, found_volumes = false;
+    if (!node.empty()) {
+        ParseHelper_Node_Enter(ne);
+        pugi::xml_node vertNode = node.child("vertices");
+        if (!vertNode.empty()) {
+            ParseNode_Vertices(vertNode);
+            found_verts = true;
+        }
+
+        pugi::xml_node volumeNode = node.child("volume");
+        if (!volumeNode.empty()) {
+            ParseNode_Volume(volumeNode);
+            found_volumes = true;
+        }
+        ParseHelper_Node_Exit();
+    } 
+
+    if (!found_verts && !found_volumes) {
+        mNodeElement_Cur->Child.push_back(ne);
+    } // if(!mReader->isEmptyElement()) else
+
+    // and to node element list because its a new object in graph.
+    mNodeElement_List.push_back(ne);
 }
 }
 
 
 // <vertices>
 // <vertices>
@@ -100,27 +97,25 @@ CAMFImporter_NodeElement* ne;
 // The list of vertices to be used in defining triangles.
 // The list of vertices to be used in defining triangles.
 // Multi elements - No.
 // Multi elements - No.
 // Parent element - <mesh>.
 // Parent element - <mesh>.
-void AMFImporter::ParseNode_Vertices()
-{
-CAMFImporter_NodeElement* ne;
-
-	// create new mesh object.
-	ne = new CAMFImporter_NodeElement_Vertices(mNodeElement_Cur);
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("vertices");
-			if(XML_CheckNode_NameEqual("vertex")) { ParseNode_Vertex(); continue; }
-		MACRO_NODECHECK_LOOPEND("vertices");
-		ParseHelper_Node_Exit();
-	}// if(!mReader->isEmptyElement())
-	else
-	{
-		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
-
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
+void AMFImporter::ParseNode_Vertices(XmlNode &node) {
+    AMFNodeElementBase *ne = nullptr;
+
+    // create new mesh object.
+    ne = new AMFVertices(mNodeElement_Cur);
+    // Check for child nodes
+    pugi::xml_node vertexNode = node.child("vertex");
+    if (!vertexNode.empty()) {
+        ParseHelper_Node_Enter(ne);
+
+        ParseNode_Vertex(vertexNode);
+
+        ParseHelper_Node_Exit();
+
+    } else {
+        mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
+    } // if(!mReader->isEmptyElement()) else
+
+    mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
 
 
 // <vertex>
 // <vertex>
@@ -128,52 +123,35 @@ CAMFImporter_NodeElement* ne;
 // A vertex to be referenced in triangles.
 // A vertex to be referenced in triangles.
 // Multi elements - Yes.
 // Multi elements - Yes.
 // Parent element - <vertices>.
 // Parent element - <vertices>.
-void AMFImporter::ParseNode_Vertex()
-{
-CAMFImporter_NodeElement* ne;
-
-	// create new mesh object.
-	ne = new CAMFImporter_NodeElement_Vertex(mNodeElement_Cur);
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		bool col_read = false;
-		bool coord_read = false;
-
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("vertex");
-			if(XML_CheckNode_NameEqual("color"))
-			{
-				// Check if data already defined.
-				if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <vertex>.");
-				// read data and set flag about it
-				ParseNode_Color();
-				col_read = true;
-
-				continue;
-			}
-
-			if(XML_CheckNode_NameEqual("coordinates"))
-			{
-				// Check if data already defined.
-				if(coord_read) Throw_MoreThanOnceDefined("coordinates", "Only one coordinates set can be defined for <vertex>.");
-				// read data and set flag about it
-				ParseNode_Coordinates();
-				coord_read = true;
-
-				continue;
-			}
-
-			if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
-		MACRO_NODECHECK_LOOPEND("vertex");
-		ParseHelper_Node_Exit();
-	}// if(!mReader->isEmptyElement())
-	else
-	{
-		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
-
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
+void AMFImporter::ParseNode_Vertex(XmlNode &node) {
+    AMFNodeElementBase *ne = nullptr;
+
+    // create new mesh object.
+    ne = new AMFVertex(mNodeElement_Cur);
+
+    // Check for child nodes
+    pugi::xml_node colorNode = node.child("color");
+    bool col_read = false;
+    bool coord_read = false;
+    if (!node.empty()) {
+        ParseHelper_Node_Enter(ne);
+        if (!colorNode.empty()) {
+            ParseNode_Color(colorNode);
+            col_read = true;
+        }
+        pugi::xml_node coordNode = node.child("coordinates");
+        if (!coordNode.empty()) {
+            ParseNode_Coordinates(coordNode);
+            coord_read = true;
+        }
+        ParseHelper_Node_Exit();
+    }
+
+    if (!coord_read && !col_read) {
+        mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
+    }
+
+    mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
 
 
 // <coordinates>
 // <coordinates>
@@ -186,37 +164,32 @@ CAMFImporter_NodeElement* ne;
 //   <x>, <y>, <z>
 //   <x>, <y>, <z>
 //   Multi elements - No.
 //   Multi elements - No.
 //   X, Y, or Z coordinate, respectively, of a vertex position in space.
 //   X, Y, or Z coordinate, respectively, of a vertex position in space.
-void AMFImporter::ParseNode_Coordinates()
-{
-CAMFImporter_NodeElement* ne;
-
-	// create new color object.
-	ne = new CAMFImporter_NodeElement_Coordinates(mNodeElement_Cur);
-
-	CAMFImporter_NodeElement_Coordinates& als = *((CAMFImporter_NodeElement_Coordinates*)ne);// alias for convenience
-
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		bool read_flag[3] = { false, false, false };
-
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("coordinates");
-			MACRO_NODECHECK_READCOMP_F("x", read_flag[0], als.Coordinate.x);
-			MACRO_NODECHECK_READCOMP_F("y", read_flag[1], als.Coordinate.y);
-			MACRO_NODECHECK_READCOMP_F("z", read_flag[2], als.Coordinate.z);
-		MACRO_NODECHECK_LOOPEND("coordinates");
-		ParseHelper_Node_Exit();
-		// check that all components was defined
-		if((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all coordinate's components are defined.");
-
-	}// if(!mReader->isEmptyElement())
-	else
-	{
-		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
-
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
+void AMFImporter::ParseNode_Coordinates(XmlNode &node) {
+    AMFNodeElementBase *ne = nullptr;
+
+    // create new color object.
+    ne = new AMFCoordinates(mNodeElement_Cur);
+
+    AMFCoordinates &als = *((AMFCoordinates *)ne); // alias for convenience
+    if (!node.empty()) {
+        ParseHelper_Node_Enter(ne);
+        for (XmlNode &currentNode : node.children()) {
+            const std::string &currentName = currentNode.name();
+            if (currentName == "X") {
+                XmlParser::getValueAsFloat(currentNode, als.Coordinate.x);
+            } else if (currentName == "Y") {
+                XmlParser::getValueAsFloat(currentNode, als.Coordinate.y);
+            } else if (currentName == "Z") {
+                XmlParser::getValueAsFloat(currentNode, als.Coordinate.z);
+            }
+        }
+
+        ParseHelper_Node_Exit();
+    } else {
+        mNodeElement_Cur->Child.push_back(ne);
+    }
+
+    mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
 
 
 // <volume
 // <volume
@@ -228,52 +201,41 @@ CAMFImporter_NodeElement* ne;
 // Defines a volume from the established vertex list.
 // Defines a volume from the established vertex list.
 // Multi elements - Yes.
 // Multi elements - Yes.
 // Parent element - <mesh>.
 // Parent element - <mesh>.
-void AMFImporter::ParseNode_Volume()
-{
-std::string materialid;
-std::string type;
-CAMFImporter_NodeElement* ne;
-
-	// Read attributes for node <color>.
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("materialid", materialid, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
-	MACRO_ATTRREAD_LOOPEND;
-
-	// create new object.
-	ne = new CAMFImporter_NodeElement_Volume(mNodeElement_Cur);
-	// and assign read data
-	((CAMFImporter_NodeElement_Volume*)ne)->MaterialID = materialid;
-	((CAMFImporter_NodeElement_Volume*)ne)->Type = type;
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		bool col_read = false;
-
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("volume");
-			if(XML_CheckNode_NameEqual("color"))
-			{
-				// Check if data already defined.
-				if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <volume>.");
-				// read data and set flag about it
-				ParseNode_Color();
-				col_read = true;
-
-				continue;
-			}
-
-			if(XML_CheckNode_NameEqual("triangle")) { ParseNode_Triangle(); continue; }
-			if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
-		MACRO_NODECHECK_LOOPEND("volume");
-		ParseHelper_Node_Exit();
-	}// if(!mReader->isEmptyElement())
-	else
-	{
-		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
-
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
+void AMFImporter::ParseNode_Volume(XmlNode &node) {
+    std::string materialid;
+    std::string type;
+    AMFNodeElementBase *ne = new AMFVolume(mNodeElement_Cur);
+
+    // Read attributes for node <color>.
+    // and assign read data
+   
+    ((AMFVolume *)ne)->MaterialID = node.attribute("materialid").as_string();
+     
+    ((AMFVolume *)ne)->Type = type;
+    // Check for child nodes
+    bool col_read = false;
+    if (!node.empty()) {
+        ParseHelper_Node_Enter(ne);
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string currentName = currentNode.name();
+            if (currentName == "color") {
+                if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for <volume>.");
+                ParseNode_Color(currentNode);
+                col_read = true;
+            } else if (currentName == "triangle") {
+                ParseNode_Triangle(currentNode);
+            } else if (currentName == "metadata") {
+                ParseNode_Metadata(currentNode);
+            } else if (currentName == "volume") {
+                ParseNode_Metadata(currentNode);
+            }
+        }
+        ParseHelper_Node_Exit();
+    } else {
+        mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
+    }
+
+    mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
 
 
 // <triangle>
 // <triangle>
@@ -286,72 +248,42 @@ CAMFImporter_NodeElement* ne;
 //   <v1>, <v2>, <v3>
 //   <v1>, <v2>, <v3>
 //   Multi elements - No.
 //   Multi elements - No.
 //   Index of the desired vertices in a triangle or edge.
 //   Index of the desired vertices in a triangle or edge.
-void AMFImporter::ParseNode_Triangle()
-{
-CAMFImporter_NodeElement* ne;
-
-	// create new color object.
-	ne = new CAMFImporter_NodeElement_Triangle(mNodeElement_Cur);
-
-	CAMFImporter_NodeElement_Triangle& als = *((CAMFImporter_NodeElement_Triangle*)ne);// alias for convenience
-
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		bool col_read = false, tex_read = false;
-		bool read_flag[3] = { false, false, false };
-
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("triangle");
-			if(XML_CheckNode_NameEqual("color"))
-			{
-				// Check if data already defined.
-				if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <triangle>.");
-				// read data and set flag about it
-				ParseNode_Color();
-				col_read = true;
-
-				continue;
-			}
-
-			if(XML_CheckNode_NameEqual("texmap"))// new name of node: "texmap".
-			{
-				// Check if data already defined.
-				if(tex_read) Throw_MoreThanOnceDefined("texmap", "Only one texture coordinate can be defined for <triangle>.");
-				// read data and set flag about it
-				ParseNode_TexMap();
-				tex_read = true;
-
-				continue;
-			}
-			else if(XML_CheckNode_NameEqual("map"))// old name of node: "map".
-			{
-				// Check if data already defined.
-				if(tex_read) Throw_MoreThanOnceDefined("map", "Only one texture coordinate can be defined for <triangle>.");
-				// read data and set flag about it
-				ParseNode_TexMap(true);
-				tex_read = true;
-
-				continue;
-			}
-
-			MACRO_NODECHECK_READCOMP_U32("v1", read_flag[0], als.V[0]);
-			MACRO_NODECHECK_READCOMP_U32("v2", read_flag[1], als.V[1]);
-			MACRO_NODECHECK_READCOMP_U32("v3", read_flag[2], als.V[2]);
-		MACRO_NODECHECK_LOOPEND("triangle");
-		ParseHelper_Node_Exit();
-		// check that all components was defined
-		if((read_flag[0] && read_flag[1] && read_flag[2]) == 0) throw DeadlyImportError("Not all vertices of the triangle are defined.");
-
-	}// if(!mReader->isEmptyElement())
-	else
-	{
-		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
-
-	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
+void AMFImporter::ParseNode_Triangle(XmlNode &node) {
+    AMFNodeElementBase *ne = new AMFTriangle(mNodeElement_Cur);
+
+    // create new triangle object.
+
+    AMFTriangle &als = *((AMFTriangle *)ne); // alias for convenience
+
+    bool col_read = false;
+    if (!node.empty()) {
+        ParseHelper_Node_Enter(ne);
+        for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
+            const std::string currentName = currentNode.name();
+            if (currentName == "color") {
+                if (col_read) Throw_MoreThanOnceDefined(currentName, "color", "Only one color can be defined for <triangle>.");
+                ParseNode_Color(currentNode);
+                col_read = true;
+            } else if (currentName == "texmap") {
+                ParseNode_TexMap(currentNode);
+            } else if (currentName == "map") {
+                ParseNode_TexMap(currentNode, true);
+            } else if (currentName == "v1") {
+                als.V[0] = std::atoi(currentNode.value());
+            } else if (currentName == "v2") {
+                als.V[1] = std::atoi(currentNode.value());
+            } else if (currentName == "v3") {
+                als.V[2] = std::atoi(currentNode.value());
+            }
+        }
+        ParseHelper_Node_Exit();
+    } else {
+        mNodeElement_Cur->Child.push_back(ne); // Add element to child list of current element
+    }
+
+    mNodeElement_List.push_back(ne); // and to node element list because its a new object in graph.
 }
 }
 
 
-}// namespace Assimp
+} // namespace Assimp
 
 
 #endif // !ASSIMP_BUILD_NO_AMF_IMPORTER
 #endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

+ 0 - 2
code/AssetLib/AMF/AMFImporter_Macro.hpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,

+ 149 - 148
code/AssetLib/AMF/AMFImporter_Material.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -49,10 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
 #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
 
 
 #include "AMFImporter.hpp"
 #include "AMFImporter.hpp"
-#include "AMFImporter_Macro.hpp"
 
 
-namespace Assimp
-{
+namespace Assimp {
 
 
 // <color
 // <color
 // profile="" - The ICC color space used to interpret the three color channels <r>, <g> and <b>.
 // profile="" - The ICC color space used to interpret the three color channels <r>, <g> and <b>.
@@ -68,46 +64,44 @@ namespace Assimp
 //   Multi elements - No.
 //   Multi elements - No.
 //   Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The
 //   Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The
 //   values can be specified as constants, or as a formula depending on the coordinates.
 //   values can be specified as constants, or as a formula depending on the coordinates.
-void AMFImporter::ParseNode_Color() {
-    std::string profile;
-    CAMFImporter_NodeElement* ne;
-
-	// Read attributes for node <color>.
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("profile", profile, mReader->getAttributeValue);
-	MACRO_ATTRREAD_LOOPEND;
-
+void AMFImporter::ParseNode_Color(XmlNode &node) {
+    std::string profile = node.attribute("profile").as_string();
+    
 	// create new color object.
 	// create new color object.
-	ne = new CAMFImporter_NodeElement_Color(mNodeElement_Cur);
-
-	CAMFImporter_NodeElement_Color& als = *((CAMFImporter_NodeElement_Color*)ne);// alias for convenience
+	AMFNodeElementBase *ne = new AMFColor(mNodeElement_Cur);
+	AMFColor& als = *((AMFColor*)ne);// alias for convenience
 
 
 	als.Profile = profile;
 	als.Profile = profile;
-	// Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
+	if (!node.empty()) {
+        ParseHelper_Node_Enter(ne);
 		bool read_flag[4] = { false, false, false, false };
 		bool read_flag[4] = { false, false, false, false };
-
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("color");
-			MACRO_NODECHECK_READCOMP_F("r", read_flag[0], als.Color.r);
-			MACRO_NODECHECK_READCOMP_F("g", read_flag[1], als.Color.g);
-			MACRO_NODECHECK_READCOMP_F("b", read_flag[2], als.Color.b);
-			MACRO_NODECHECK_READCOMP_F("a", read_flag[3], als.Color.a);
-		MACRO_NODECHECK_LOOPEND("color");
-		ParseHelper_Node_Exit();
-		// check that all components was defined
-        if (!(read_flag[0] && read_flag[1] && read_flag[2])) {
-            throw DeadlyImportError("Not all color components are defined.");
+		for (pugi::xml_node &child : node.children()) {
+            std::string name = child.name();
+            if ( name == "r") {
+				read_flag[0] = true;
+                XmlParser::getValueAsFloat(child, als.Color.r);
+            } else if (name == "g") {
+				read_flag[1] = true;
+                XmlParser::getValueAsFloat(child, als.Color.g);
+            } else if (name == "b") {
+				read_flag[2] = true;
+                XmlParser::getValueAsFloat(child, als.Color.b);
+            } else if (name == "a") {
+			    read_flag[3] = true;
+                XmlParser::getValueAsFloat(child, als.Color.a);
+            }
+            ParseHelper_Node_Exit();
         }
         }
-
-        // check if <a> is absent. Then manually add "a == 1".
-        if (!read_flag[3]) {
-            als.Color.a = 1;
-        }
-	}
-	else
-	{
+		// check that all components was defined
+		if (!(read_flag[0] && read_flag[1] && read_flag[2])) {
+			throw DeadlyImportError("Not all color components are defined.");
+		}
+
+		// check if <a> is absent. Then manually add "a == 1".
+		if (!read_flag[3]) {
+			als.Color.a = 1;
+		}
+	} else {
 		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
 		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
 	}
 	}
 
 
@@ -122,45 +116,25 @@ void AMFImporter::ParseNode_Color() {
 // An available material.
 // An available material.
 // Multi elements - Yes.
 // Multi elements - Yes.
 // Parent element - <amf>.
 // Parent element - <amf>.
-void AMFImporter::ParseNode_Material() {
-    std::string id;
-    CAMFImporter_NodeElement* ne;
-
-	// Read attributes for node <color>.
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
-	MACRO_ATTRREAD_LOOPEND;
-
-	// create new object.
-	ne = new CAMFImporter_NodeElement_Material(mNodeElement_Cur);
-
-    // and assign read data
-	((CAMFImporter_NodeElement_Material*)ne)->ID = id;
+void AMFImporter::ParseNode_Material(XmlNode &node) {
+    // create new object and assign read data
+	std::string id = node.attribute("id").as_string();
+	AMFNodeElementBase *ne = new AMFMaterial(mNodeElement_Cur);
+	((AMFMaterial*)ne)->ID = id;
 
 
     // Check for child nodes
     // Check for child nodes
-	if(!mReader->isEmptyElement())
-	{
-		bool col_read = false;
-
-		ParseHelper_Node_Enter(ne);
-		MACRO_NODECHECK_LOOPBEGIN("material");
-			if(XML_CheckNode_NameEqual("color"))
-			{
-				// Check if data already defined.
-				if(col_read) Throw_MoreThanOnceDefined("color", "Only one color can be defined for <material>.");
-				// read data and set flag about it
-				ParseNode_Color();
-				col_read = true;
-
-				continue;
+	if (!node.empty()) {
+        ParseHelper_Node_Enter(ne);
+        for (pugi::xml_node &child : node.children()) {
+            const std::string name = child.name();
+            if (name == "color") {
+				ParseNode_Color(child);
+            } else if (name == "metadata") {
+				ParseNode_Metadata(child);
 			}
 			}
-
-			if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
-		MACRO_NODECHECK_LOOPEND("material");
-		ParseHelper_Node_Exit();
-	}
-	else
-	{
+		}
+        ParseHelper_Node_Exit();
+	} else {
 		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
 		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
 	}
 	}
 
 
@@ -183,51 +157,41 @@ void AMFImporter::ParseNode_Material() {
 // then layer by layer.
 // then layer by layer.
 // Multi elements - Yes.
 // Multi elements - Yes.
 // Parent element - <amf>.
 // Parent element - <amf>.
-void AMFImporter::ParseNode_Texture()
-{
-    std::string id;
-    uint32_t width = 0;
-    uint32_t height = 0;
-    uint32_t depth = 1;
-    std::string type;
-    bool tiled = false;
-    std::string enc64_data;
-
-	// Read attributes for node <color>.
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("id", id, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_RET("width", width, XML_ReadNode_GetAttrVal_AsU32);
-		MACRO_ATTRREAD_CHECK_RET("height", height, XML_ReadNode_GetAttrVal_AsU32);
-		MACRO_ATTRREAD_CHECK_RET("depth", depth, XML_ReadNode_GetAttrVal_AsU32);
-		MACRO_ATTRREAD_CHECK_RET("type", type, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_RET("tiled", tiled, XML_ReadNode_GetAttrVal_AsBool);
-	MACRO_ATTRREAD_LOOPEND;
+void AMFImporter::ParseNode_Texture(XmlNode &node) {
+    std::string id = node.attribute("id").as_string();
+	uint32_t width = node.attribute("width").as_uint();
+	uint32_t height = node.attribute("height").as_uint();
+	uint32_t depth = node.attribute("depth").as_uint();
+	std::string type = node.attribute("type").as_string();
+	bool tiled = node.attribute("tiled").as_bool();
+
+    if (node.empty()) {
+		return;
+    }
 
 
-	// create new texture object.
-    CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_Texture(mNodeElement_Cur);
+    // create new texture object.
+    AMFNodeElementBase *ne = new AMFTexture(mNodeElement_Cur);
 
 
-	CAMFImporter_NodeElement_Texture& als = *((CAMFImporter_NodeElement_Texture*)ne);// alias for convenience
+	AMFTexture& als = *((AMFTexture*)ne);// alias for convenience
 
 
+    std::string enc64_data = node.value();
 	// Check for child nodes
 	// Check for child nodes
-    if (!mReader->isEmptyElement()) {
-        XML_ReadNode_GetVal_AsString(enc64_data);
-    }
 
 
 	// check that all components was defined
 	// check that all components was defined
     if (id.empty()) {
     if (id.empty()) {
-        throw DeadlyImportError("ID for texture must be defined.");
+		throw DeadlyImportError("ID for texture must be defined.");
     }
     }
     if (width < 1) {
     if (width < 1) {
-        Throw_IncorrectAttrValue("width");
+		throw DeadlyImportError("INvalid width for texture.");
     }
     }
     if (height < 1) {
     if (height < 1) {
-        Throw_IncorrectAttrValue("height");
-    }
+		throw DeadlyImportError("Invalid height for texture.");
+	}
     if (depth < 1) {
     if (depth < 1) {
-        Throw_IncorrectAttrValue("depth");
+		throw DeadlyImportError("Invalid depth for texture.");
     }
     }
     if (type != "grayscale") {
     if (type != "grayscale") {
-        Throw_IncorrectAttrValue("type");
+		throw DeadlyImportError("Invalid type for texture.");
     }
     }
     if (enc64_data.empty()) {
     if (enc64_data.empty()) {
         throw DeadlyImportError("Texture data not defined.");
         throw DeadlyImportError("Texture data not defined.");
@@ -263,57 +227,94 @@ void AMFImporter::ParseNode_Texture()
 //   <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>. Old name: <u1>, <u2>, <u3>, <v1>, <v2>, <v3>.
 //   <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>. Old name: <u1>, <u2>, <u3>, <v1>, <v2>, <v3>.
 //   Multi elements - No.
 //   Multi elements - No.
 //   Texture coordinates for every vertex of triangle.
 //   Texture coordinates for every vertex of triangle.
-void AMFImporter::ParseNode_TexMap(const bool pUseOldName) {
-    std::string rtexid, gtexid, btexid, atexid;
-
+void AMFImporter::ParseNode_TexMap(XmlNode &node, const bool pUseOldName) {
 	// Read attributes for node <color>.
 	// Read attributes for node <color>.
-	MACRO_ATTRREAD_LOOPBEG;
-		MACRO_ATTRREAD_CHECK_RET("rtexid", rtexid, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_RET("gtexid", gtexid, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_RET("btexid", btexid, mReader->getAttributeValue);
-		MACRO_ATTRREAD_CHECK_RET("atexid", atexid, mReader->getAttributeValue);
-	MACRO_ATTRREAD_LOOPEND;
-
-	// create new texture coordinates object.
-    CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_TexMap(mNodeElement_Cur);
+    AMFNodeElementBase *ne = new AMFTexMap(mNodeElement_Cur);
+    AMFTexMap &als = *((AMFTexMap *)ne); //
+    std::string rtexid, gtexid, btexid, atexid;
+    if (!node.empty()) {
+        ParseHelper_Node_Enter(ne);
+        for (XmlNode &currentNode : node.children()) {
+            const std::string &currentName = currentNode.name();
+            if (currentName == "rtexid") {
+                XmlParser::getValueAsString(node, rtexid);
+            } else if (currentName == "gtexid") {
+                XmlParser::getValueAsString(node, gtexid);
+            } else if (currentName == "btexid") {
+                XmlParser::getValueAsString(node, btexid);
+            } else if (currentName == "atexid") {
+                XmlParser::getValueAsString(node, atexid);
+            }
+        }
+        ParseHelper_Node_Exit();
+    }
 
 
-	CAMFImporter_NodeElement_TexMap& als = *((CAMFImporter_NodeElement_TexMap*)ne);// alias for convenience
+	// create new texture coordinates object, alias for convenience
 	// check data
 	// check data
-	if(rtexid.empty() && gtexid.empty() && btexid.empty()) throw DeadlyImportError("ParseNode_TexMap. At least one texture ID must be defined.");
+	if (rtexid.empty() && gtexid.empty() && btexid.empty()) {
+		throw DeadlyImportError("ParseNode_TexMap. At least one texture ID must be defined.");
+	}
+
 	// Check for children nodes
 	// Check for children nodes
-	XML_CheckNode_MustHaveChildren();
+	//XML_CheckNode_MustHaveChildren();
+	if (node.children().begin() == node.children().end()) {
+		throw DeadlyImportError("Invalid children definition.");
+	}
 	// read children nodes
 	// read children nodes
 	bool read_flag[6] = { false, false, false, false, false, false };
 	bool read_flag[6] = { false, false, false, false, false, false };
 
 
-	ParseHelper_Node_Enter(ne);
-	if(!pUseOldName)
-	{
-		MACRO_NODECHECK_LOOPBEGIN("texmap");
-			MACRO_NODECHECK_READCOMP_F("utex1", read_flag[0], als.TextureCoordinate[0].x);
-			MACRO_NODECHECK_READCOMP_F("utex2", read_flag[1], als.TextureCoordinate[1].x);
-			MACRO_NODECHECK_READCOMP_F("utex3", read_flag[2], als.TextureCoordinate[2].x);
-			MACRO_NODECHECK_READCOMP_F("vtex1", read_flag[3], als.TextureCoordinate[0].y);
-			MACRO_NODECHECK_READCOMP_F("vtex2", read_flag[4], als.TextureCoordinate[1].y);
-			MACRO_NODECHECK_READCOMP_F("vtex3", read_flag[5], als.TextureCoordinate[2].y);
-		MACRO_NODECHECK_LOOPEND("texmap");
+	if (!pUseOldName) {
+		for (pugi::xml_attribute &attr : node.attributes()) {
+            const std::string name = attr.name();
+            if (name == "utex1") {
+				read_flag[0] = true;
+				als.TextureCoordinate[0].x = attr.as_float();
+            } else if (name == "utex2") {
+				read_flag[1] = true;
+				als.TextureCoordinate[1].x = attr.as_float();
+            } else if (name == "utex3") {
+				read_flag[2] = true;
+				als.TextureCoordinate[2].x = attr.as_float();
+            } else if (name == "vtex1") {
+				read_flag[3] = true;
+				als.TextureCoordinate[0].y = attr.as_float();
+            } else if (name == "vtex2") {
+				read_flag[4] = true;
+				als.TextureCoordinate[1].y = attr.as_float();
+            } else if (name == "vtex3") {
+				read_flag[5] = true;
+				als.TextureCoordinate[0].y = attr.as_float();
+			}
+		}
+	} else {
+		for (pugi::xml_attribute &attr : node.attributes()) {
+            const std::string name = attr.name();
+            if (name == "u") {
+				read_flag[0] = true;
+				als.TextureCoordinate[0].x = attr.as_float();
+            } else if (name == "u2") {
+				read_flag[1] = true;
+				als.TextureCoordinate[1].x = attr.as_float();
+            } else if (name == "u3") {
+				read_flag[2] = true;
+				als.TextureCoordinate[2].x = attr.as_float();
+            } else if (name == "v1") {
+				read_flag[3] = true;
+				als.TextureCoordinate[0].y = attr.as_float();
+            } else if (name == "v2") {
+				read_flag[4] = true;
+				als.TextureCoordinate[1].y = attr.as_float();
+            } else if (name == "v3") {
+				read_flag[5] = true;
+				als.TextureCoordinate[0].y = attr.as_float();
+			}
+		}
 	}
 	}
-	else
-	{
-		MACRO_NODECHECK_LOOPBEGIN("map");
-			MACRO_NODECHECK_READCOMP_F("u1", read_flag[0], als.TextureCoordinate[0].x);
-			MACRO_NODECHECK_READCOMP_F("u2", read_flag[1], als.TextureCoordinate[1].x);
-			MACRO_NODECHECK_READCOMP_F("u3", read_flag[2], als.TextureCoordinate[2].x);
-			MACRO_NODECHECK_READCOMP_F("v1", read_flag[3], als.TextureCoordinate[0].y);
-			MACRO_NODECHECK_READCOMP_F("v2", read_flag[4], als.TextureCoordinate[1].y);
-			MACRO_NODECHECK_READCOMP_F("v3", read_flag[5], als.TextureCoordinate[2].y);
-		MACRO_NODECHECK_LOOPEND("map");
-	}// if(!pUseOldName) else
-
-	ParseHelper_Node_Exit();
 
 
 	// check that all components was defined
 	// check that all components was defined
-	if(!(read_flag[0] && read_flag[1] && read_flag[2] && read_flag[3] && read_flag[4] && read_flag[5]))
+	if (!(read_flag[0] && read_flag[1] && read_flag[2] && read_flag[3] && read_flag[4] && read_flag[5])) {
 		throw DeadlyImportError("Not all texture coordinates are defined.");
 		throw DeadlyImportError("Not all texture coordinates are defined.");
+	}
 
 
 	// copy attributes data
 	// copy attributes data
 	als.TextureID_R = rtexid;
 	als.TextureID_R = rtexid;
@@ -321,7 +322,7 @@ void AMFImporter::ParseNode_TexMap(const bool pUseOldName) {
 	als.TextureID_B = btexid;
 	als.TextureID_B = btexid;
 	als.TextureID_A = atexid;
 	als.TextureID_A = atexid;
 
 
-	mNodeElement_List.push_back(ne);// add to node element list because its a new object in graph.
+	mNodeElement_List.push_back(ne);
 }
 }
 
 
 }// namespace Assimp
 }// namespace Assimp

+ 116 - 150
code/AssetLib/AMF/AMFImporter_Node.hpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -56,80 +54,76 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <vector>
 #include <vector>
 
 
 // Header files, Assimp.
 // Header files, Assimp.
-#include "assimp/types.h"
 #include "assimp/scene.h"
 #include "assimp/scene.h"
+#include "assimp/types.h"
 
 
 /// \class CAMFImporter_NodeElement
 /// \class CAMFImporter_NodeElement
 /// Base class for elements of nodes.
 /// Base class for elements of nodes.
-class CAMFImporter_NodeElement {
+class AMFNodeElementBase {
 public:
 public:
 	/// Define what data type contain node element.
 	/// Define what data type contain node element.
 	enum EType {
 	enum EType {
-		ENET_Color,        ///< Color element: <color>.
-		ENET_Constellation,///< Grouping element: <constellation>.
-		ENET_Coordinates,  ///< Coordinates element: <coordinates>.
-		ENET_Edge,         ///< Edge element: <edge>.
-		ENET_Instance,     ///< Grouping element: <constellation>.
-		ENET_Material,     ///< Material element: <material>.
-		ENET_Metadata,     ///< Metadata element: <metadata>.
-		ENET_Mesh,         ///< Metadata element: <mesh>.
-		ENET_Object,       ///< Element which hold object: <object>.
-		ENET_Root,         ///< Root element: <amf>.
-		ENET_Triangle,     ///< Triangle element: <triangle>.
-		ENET_TexMap,       ///< Texture coordinates element: <texmap> or <map>.
-		ENET_Texture,      ///< Texture element: <texture>.
-		ENET_Vertex,       ///< Vertex element: <vertex>.
-		ENET_Vertices,     ///< Vertex element: <vertices>.
-		ENET_Volume,       ///< Volume element: <volume>.
-
-		ENET_Invalid       ///< Element has invalid type and possible contain invalid data.
+		ENET_Color, ///< Color element: <color>.
+		ENET_Constellation, ///< Grouping element: <constellation>.
+		ENET_Coordinates, ///< Coordinates element: <coordinates>.
+		ENET_Edge, ///< Edge element: <edge>.
+		ENET_Instance, ///< Grouping element: <constellation>.
+		ENET_Material, ///< Material element: <material>.
+		ENET_Metadata, ///< Metadata element: <metadata>.
+		ENET_Mesh, ///< Metadata element: <mesh>.
+		ENET_Object, ///< Element which hold object: <object>.
+		ENET_Root, ///< Root element: <amf>.
+		ENET_Triangle, ///< Triangle element: <triangle>.
+		ENET_TexMap, ///< Texture coordinates element: <texmap> or <map>.
+		ENET_Texture, ///< Texture element: <texture>.
+		ENET_Vertex, ///< Vertex element: <vertex>.
+		ENET_Vertices, ///< Vertex element: <vertices>.
+		ENET_Volume, ///< Volume element: <volume>.
+
+		ENET_Invalid ///< Element has invalid type and possible contain invalid data.
 	};
 	};
 
 
-	const EType Type;///< Type of element.
-	std::string ID;///< ID of element.
-	CAMFImporter_NodeElement* Parent;///< Parent element. If nullptr then this node is root.
-	std::list<CAMFImporter_NodeElement*> Child;///< Child elements.
+	const EType Type; ///< Type of element.
+	std::string ID; ///< ID of element.
+	AMFNodeElementBase *Parent; ///< Parent element. If nullptr then this node is root.
+	std::list<AMFNodeElementBase *> Child; ///< Child elements.
 
 
-public:                                               /// Destructor, virtual..
-    virtual ~CAMFImporter_NodeElement() {
-        // empty
-    }
+public: /// Destructor, virtual..
+	virtual ~AMFNodeElementBase() {
+		// empty
+	}
 
 
 	/// Disabled copy constructor and co.
 	/// Disabled copy constructor and co.
-	CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement) = delete;
-    CAMFImporter_NodeElement(CAMFImporter_NodeElement&&) = delete;
-    CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement) = delete;
-	CAMFImporter_NodeElement() = delete;
+	AMFNodeElementBase(const AMFNodeElementBase &pNodeElement) = delete;
+	AMFNodeElementBase(AMFNodeElementBase &&) = delete;
+	AMFNodeElementBase &operator=(const AMFNodeElementBase &pNodeElement) = delete;
+	AMFNodeElementBase() = delete;
 
 
 protected:
 protected:
 	/// In constructor inheritor must set element type.
 	/// In constructor inheritor must set element type.
 	/// \param [in] pType - element type.
 	/// \param [in] pType - element type.
 	/// \param [in] pParent - parent element.
 	/// \param [in] pParent - parent element.
-	CAMFImporter_NodeElement(const EType pType, CAMFImporter_NodeElement* pParent)
-	: Type(pType)
-    , ID()
-    , Parent(pParent)
-    , Child() {
-        // empty
-    }
-};// class IAMFImporter_NodeElement
+	AMFNodeElementBase(const EType pType, AMFNodeElementBase *pParent) :
+			Type(pType), ID(), Parent(pParent), Child() {
+		// empty
+	}
+}; // class IAMFImporter_NodeElement
 
 
 /// \struct CAMFImporter_NodeElement_Constellation
 /// \struct CAMFImporter_NodeElement_Constellation
 /// A collection of objects or constellations with specific relative locations.
 /// A collection of objects or constellations with specific relative locations.
-struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement {
+struct AMFConstellation : public AMFNodeElementBase {
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Constellation(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Constellation, pParent)
-	{}
+	AMFConstellation(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Constellation, pParent) {}
 
 
-};// struct CAMFImporter_NodeElement_Constellation
+}; // struct CAMFImporter_NodeElement_Constellation
 
 
 /// \struct CAMFImporter_NodeElement_Instance
 /// \struct CAMFImporter_NodeElement_Instance
 /// Part of constellation.
 /// Part of constellation.
-struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement {
+struct AMFInstance : public AMFNodeElementBase {
 
 
-	std::string ObjectID;///< ID of object for instantiation.
+	std::string ObjectID; ///< ID of object for instantiation.
 	/// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to
 	/// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to
 	/// create an instance of the object in the current constellation.
 	/// create an instance of the object in the current constellation.
 	aiVector3D Delta;
 	aiVector3D Delta;
@@ -140,201 +134,173 @@ struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement {
 
 
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Instance(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Instance, pParent)
-	{}
+	AMFInstance(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Instance, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Metadata
 /// \struct CAMFImporter_NodeElement_Metadata
 /// Structure that define metadata node.
 /// Structure that define metadata node.
-struct CAMFImporter_NodeElement_Metadata : public CAMFImporter_NodeElement {
+struct AMFMetadata : public AMFNodeElementBase {
 
 
-	std::string Type;///< Type of "Value". 
-	std::string Value;///< Value.
+	std::string Type; ///< Type of "Value".
+	std::string Value; ///< Value.
 
 
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Metadata(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Metadata, pParent)
-	{}
+	AMFMetadata(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Metadata, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Root
 /// \struct CAMFImporter_NodeElement_Root
 /// Structure that define root node.
 /// Structure that define root node.
-struct CAMFImporter_NodeElement_Root : public CAMFImporter_NodeElement {
+struct AMFRoot : public AMFNodeElementBase {
 
 
-	std::string Unit;///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
-	std::string Version;///< Version of format.
+	std::string Unit; ///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
+	std::string Version; ///< Version of format.
 
 
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Root(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Root, pParent)
-	{}
+	AMFRoot(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Root, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Color
 /// \struct CAMFImporter_NodeElement_Color
 /// Structure that define object node.
 /// Structure that define object node.
-struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement {
-	bool Composed;                  ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color.
-	std::string Color_Composed[4];  ///< By components formulas of composed color. [0..3] - RGBA.
-	aiColor4D Color;                ///< Constant color.
-	std::string Profile;            ///< The ICC color space used to interpret the three color channels r, g and b..
+struct AMFColor : public AMFNodeElementBase {
+	bool Composed; ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color.
+	std::string Color_Composed[4]; ///< By components formulas of composed color. [0..3] - RGBA.
+	aiColor4D Color; ///< Constant color.
+	std::string Profile; ///< The ICC color space used to interpret the three color channels r, g and b..
 
 
 	/// @brief  Constructor.
 	/// @brief  Constructor.
 	/// @param [in] pParent - pointer to parent node.
 	/// @param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Color(CAMFImporter_NodeElement* pParent)
-	: CAMFImporter_NodeElement(ENET_Color, pParent)
-    , Composed( false )
-    , Color()
-    , Profile() {
-        // empty
-    }
+	AMFColor(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Color, pParent), Composed(false), Color(), Profile() {
+		// empty
+	}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Material
 /// \struct CAMFImporter_NodeElement_Material
 /// Structure that define material node.
 /// Structure that define material node.
-struct CAMFImporter_NodeElement_Material : public CAMFImporter_NodeElement {
-	
+struct AMFMaterial : public AMFNodeElementBase {
+
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Material(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Material, pParent)
-	{}
-
+	AMFMaterial(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Material, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Object
 /// \struct CAMFImporter_NodeElement_Object
 /// Structure that define object node.
 /// Structure that define object node.
-struct CAMFImporter_NodeElement_Object : public CAMFImporter_NodeElement {
+struct AMFObject : public AMFNodeElementBase {
 
 
-    /// Constructor.
+	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Object(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Object, pParent)
-	{}
+	AMFObject(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Object, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Mesh
 /// \struct CAMFImporter_NodeElement_Mesh
 /// Structure that define mesh node.
 /// Structure that define mesh node.
-struct CAMFImporter_NodeElement_Mesh : public CAMFImporter_NodeElement {
+struct AMFMesh : public AMFNodeElementBase {
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Mesh(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Mesh, pParent)
-	{}
+	AMFMesh(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Mesh, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Vertex
 /// \struct CAMFImporter_NodeElement_Vertex
 /// Structure that define vertex node.
 /// Structure that define vertex node.
-struct CAMFImporter_NodeElement_Vertex : public CAMFImporter_NodeElement {
+struct AMFVertex : public AMFNodeElementBase {
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Vertex(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Vertex, pParent)
-	{}
+	AMFVertex(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Vertex, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Edge
 /// \struct CAMFImporter_NodeElement_Edge
 /// Structure that define edge node.
 /// Structure that define edge node.
-struct CAMFImporter_NodeElement_Edge : public CAMFImporter_NodeElement {
+struct AMFEdge : public AMFNodeElementBase {
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Edge(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Edge, pParent)
-	{}
-
+	AMFEdge(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Edge, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Vertices
 /// \struct CAMFImporter_NodeElement_Vertices
 /// Structure that define vertices node.
 /// Structure that define vertices node.
-struct CAMFImporter_NodeElement_Vertices : public CAMFImporter_NodeElement {
+struct AMFVertices : public AMFNodeElementBase {
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Vertices(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Vertices, pParent)
-	{}
+	AMFVertices(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Vertices, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Volume
 /// \struct CAMFImporter_NodeElement_Volume
 /// Structure that define volume node.
 /// Structure that define volume node.
-struct CAMFImporter_NodeElement_Volume : public CAMFImporter_NodeElement {
-	std::string MaterialID;///< Which material to use.
-	std::string Type;///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed.
+struct AMFVolume : public AMFNodeElementBase {
+	std::string MaterialID; ///< Which material to use.
+	std::string Type; ///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed.
 
 
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Volume(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Volume, pParent)
-	{}
+	AMFVolume(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Volume, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Coordinates
 /// \struct CAMFImporter_NodeElement_Coordinates
 /// Structure that define coordinates node.
 /// Structure that define coordinates node.
-struct CAMFImporter_NodeElement_Coordinates : public CAMFImporter_NodeElement
-{
-	aiVector3D Coordinate;///< Coordinate.
+struct AMFCoordinates : public AMFNodeElementBase {
+	aiVector3D Coordinate; ///< Coordinate.
 
 
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Coordinates(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Coordinates, pParent)
-	{}
-
+	AMFCoordinates(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Coordinates, pParent) {}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_TexMap
 /// \struct CAMFImporter_NodeElement_TexMap
 /// Structure that define texture coordinates node.
 /// Structure that define texture coordinates node.
-struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement {
-	aiVector3D TextureCoordinate[3];///< Texture coordinates.
-	std::string TextureID_R;///< Texture ID for red color component.
-	std::string TextureID_G;///< Texture ID for green color component.
-	std::string TextureID_B;///< Texture ID for blue color component.
-	std::string TextureID_A;///< Texture ID for alpha color component.
+struct AMFTexMap : public AMFNodeElementBase {
+	aiVector3D TextureCoordinate[3]; ///< Texture coordinates.
+	std::string TextureID_R; ///< Texture ID for red color component.
+	std::string TextureID_G; ///< Texture ID for green color component.
+	std::string TextureID_B; ///< Texture ID for blue color component.
+	std::string TextureID_A; ///< Texture ID for alpha color component.
 
 
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_TexMap(CAMFImporter_NodeElement* pParent)
-	: CAMFImporter_NodeElement(ENET_TexMap, pParent)
-    , TextureCoordinate{}
-    , TextureID_R()
-    , TextureID_G()
-    , TextureID_B()
-    , TextureID_A()	{
-        // empty
-    }
+	AMFTexMap(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_TexMap, pParent), TextureCoordinate{}, TextureID_R(), TextureID_G(), TextureID_B(), TextureID_A() {
+		// empty
+	}
 };
 };
 
 
 /// \struct CAMFImporter_NodeElement_Triangle
 /// \struct CAMFImporter_NodeElement_Triangle
 /// Structure that define triangle node.
 /// Structure that define triangle node.
-struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement {
-	size_t V[3];///< Triangle vertices.
+struct AMFTriangle : public AMFNodeElementBase {
+	size_t V[3]; ///< Triangle vertices.
 
 
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Triangle(CAMFImporter_NodeElement* pParent)
-	: CAMFImporter_NodeElement(ENET_Triangle, pParent) {
-        // empty
-    }
+	AMFTriangle(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Triangle, pParent) {
+		// empty
+	}
 };
 };
 
 
 /// Structure that define texture node.
 /// Structure that define texture node.
-struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement {
-	size_t Width, Height, Depth;///< Size of the texture.
-	std::vector<uint8_t> Data;///< Data of the texture.
+struct AMFTexture : public AMFNodeElementBase {
+	size_t Width, Height, Depth; ///< Size of the texture.
+	std::vector<uint8_t> Data; ///< Data of the texture.
 	bool Tiled;
 	bool Tiled;
 
 
 	/// Constructor.
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	/// \param [in] pParent - pointer to parent node.
-	CAMFImporter_NodeElement_Texture(CAMFImporter_NodeElement* pParent)
-	: CAMFImporter_NodeElement(ENET_Texture, pParent)
-    , Width( 0 )
-    , Height( 0 )
-    , Depth( 0 )
-    , Data()
-    , Tiled( false ){
-        // empty
-    }
+	AMFTexture(AMFNodeElementBase *pParent) :
+			AMFNodeElementBase(ENET_Texture, pParent), Width(0), Height(0), Depth(0), Data(), Tiled(false) {
+		// empty
+	}
 };
 };
 
 
 #endif // INCLUDED_AI_AMF_IMPORTER_NODE_H
 #endif // INCLUDED_AI_AMF_IMPORTER_NODE_H

+ 176 - 156
code/AssetLib/AMF/AMFImporter_Postprocess.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -50,12 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "AMFImporter.hpp"
 #include "AMFImporter.hpp"
 
 
-// Header files, Assimp.
 #include <assimp/SceneCombiner.h>
 #include <assimp/SceneCombiner.h>
 #include <assimp/StandardShapes.h>
 #include <assimp/StandardShapes.h>
 #include <assimp/StringUtils.h>
 #include <assimp/StringUtils.h>
 
 
-// Header files, stdlib.
 #include <iterator>
 #include <iterator>
 
 
 namespace Assimp {
 namespace Assimp {
@@ -83,61 +79,61 @@ aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*
     return tcol;
     return tcol;
 }
 }
 
 
-void AMFImporter::PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray,
-        std::vector<CAMFImporter_NodeElement_Color *> &pVertexColorArray) const {
-    CAMFImporter_NodeElement_Vertices *vn = nullptr;
+void AMFImporter::PostprocessHelper_CreateMeshDataArray(const AMFMesh &pNodeElement, std::vector<aiVector3D> &pVertexCoordinateArray,
+        std::vector<AMFColor *> &pVertexColorArray) const {
+    AMFVertices  *vn = nullptr;
     size_t col_idx;
     size_t col_idx;
 
 
     // All data stored in "vertices", search for it.
     // All data stored in "vertices", search for it.
-    for (CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
-        if (ne_child->Type == CAMFImporter_NodeElement::ENET_Vertices) vn = (CAMFImporter_NodeElement_Vertices *)ne_child;
+    for (AMFNodeElementBase *ne_child : pNodeElement.Child) {
+        if (ne_child->Type == AMFNodeElementBase::ENET_Vertices) {
+            vn = (AMFVertices*)ne_child;
+        }
     }
     }
 
 
     // If "vertices" not found then no work for us.
     // If "vertices" not found then no work for us.
-    if (vn == nullptr) return;
+    if (vn == nullptr) {
+        return;
+    }
+
+    // all coordinates stored as child and we need to reserve space for future push_back's.
+    pVertexCoordinateArray.reserve(vn->Child.size()); 
 
 
-    pVertexCoordinateArray.reserve(vn->Child.size()); // all coordinates stored as child and we need to reserve space for future push_back's.
-    pVertexColorArray.resize(vn->Child.size()); // colors count equal vertices count.
+    // colors count equal vertices count.
+    pVertexColorArray.resize(vn->Child.size()); 
     col_idx = 0;
     col_idx = 0;
+
     // Inside vertices collect all data and place to arrays
     // Inside vertices collect all data and place to arrays
-    for (CAMFImporter_NodeElement *vn_child : vn->Child) {
+    for (AMFNodeElementBase *vn_child : vn->Child) {
         // vertices, colors
         // vertices, colors
-        if (vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex) {
+        if (vn_child->Type == AMFNodeElementBase::ENET_Vertex) {
             // by default clear color for current vertex
             // by default clear color for current vertex
             pVertexColorArray[col_idx] = nullptr;
             pVertexColorArray[col_idx] = nullptr;
 
 
-            for (CAMFImporter_NodeElement *vtx : vn_child->Child) {
-                if (vtx->Type == CAMFImporter_NodeElement::ENET_Coordinates) {
-                    pVertexCoordinateArray.push_back(((CAMFImporter_NodeElement_Coordinates *)vtx)->Coordinate);
-
+            for (AMFNodeElementBase *vtx : vn_child->Child) {
+                if (vtx->Type == AMFNodeElementBase::ENET_Coordinates) {
+                    pVertexCoordinateArray.push_back(((AMFCoordinates *)vtx)->Coordinate);
                     continue;
                     continue;
                 }
                 }
 
 
-                if (vtx->Type == CAMFImporter_NodeElement::ENET_Color) {
-                    pVertexColorArray[col_idx] = (CAMFImporter_NodeElement_Color *)vtx;
-
+                if (vtx->Type == AMFNodeElementBase::ENET_Color) {
+                    pVertexColorArray[col_idx] = (AMFColor *)vtx;
                     continue;
                     continue;
                 }
                 }
-            } // for(CAMFImporter_NodeElement* vtx: vn_child->Child)
+            }
 
 
-            col_idx++;
-        } // if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex)
-    } // for(CAMFImporter_NodeElement* vn_child: vn->Child)
+            ++col_idx;
+        }
+    }
 }
 }
 
 
-size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &pID_R, const std::string &pID_G, const std::string &pID_B,
-        const std::string &pID_A) {
-    size_t TextureConverted_Index;
-    std::string TextureConverted_ID;
-
-    // check input data
-    if (pID_R.empty() && pID_G.empty() && pID_B.empty() && pID_A.empty())
+size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &r, const std::string &g, const std::string &b, const std::string &a) {
+    if (r.empty() && g.empty() && b.empty() && a.empty()) {
         throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined.");
         throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. At least one texture ID must be defined.");
+    }
 
 
-    // Create ID
-    TextureConverted_ID = pID_R + "_" + pID_G + "_" + pID_B + "_" + pID_A;
-    // Check if texture specified by set of IDs is converted already.
-    TextureConverted_Index = 0;
+    std::string TextureConverted_ID = r + "_" + g + "_" + b + "_" + a;
+    size_t TextureConverted_Index = 0;
     for (const SPP_Texture &tex_convd : mTexture_Converted) {
     for (const SPP_Texture &tex_convd : mTexture_Converted) {
         if (tex_convd.ID == TextureConverted_ID) {
         if (tex_convd.ID == TextureConverted_ID) {
             return TextureConverted_Index;
             return TextureConverted_Index;
@@ -146,52 +142,60 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
         }
         }
     }
     }
 
 
-    //
     // Converted texture not found, create it.
     // Converted texture not found, create it.
-    //
-    CAMFImporter_NodeElement_Texture *src_texture[4]{ nullptr };
-    std::vector<CAMFImporter_NodeElement_Texture *> src_texture_4check;
+    AMFTexture *src_texture[4] {
+        nullptr
+    };
+    std::vector<AMFTexture *> src_texture_4check;
     SPP_Texture converted_texture;
     SPP_Texture converted_texture;
 
 
     { // find all specified source textures
     { // find all specified source textures
-        CAMFImporter_NodeElement *t_tex;
+        AMFNodeElementBase *t_tex = nullptr;
 
 
         // R
         // R
-        if (!pID_R.empty()) {
-            if (!Find_NodeElement(pID_R, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
+        if (!r.empty()) {
+            if (!Find_NodeElement(r, AMFNodeElementBase::EType::ENET_Texture, &t_tex)) {
+                Throw_ID_NotFound(r);
+            }
 
 
-            src_texture[0] = (CAMFImporter_NodeElement_Texture *)t_tex;
-            src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
+            src_texture[0] = (AMFTexture *)t_tex;
+            src_texture_4check.push_back((AMFTexture *)t_tex);
         } else {
         } else {
             src_texture[0] = nullptr;
             src_texture[0] = nullptr;
         }
         }
 
 
         // G
         // G
-        if (!pID_G.empty()) {
-            if (!Find_NodeElement(pID_G, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
+        if (!g.empty()) {
+            if (!Find_NodeElement(g, AMFNodeElementBase::ENET_Texture, &t_tex)) {
+                Throw_ID_NotFound(g);
+            }
 
 
-            src_texture[1] = (CAMFImporter_NodeElement_Texture *)t_tex;
-            src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
+            src_texture[1] = (AMFTexture *)t_tex;
+            src_texture_4check.push_back((AMFTexture *)t_tex);
         } else {
         } else {
             src_texture[1] = nullptr;
             src_texture[1] = nullptr;
         }
         }
 
 
         // B
         // B
-        if (!pID_B.empty()) {
-            if (!Find_NodeElement(pID_B, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
+        if (!b.empty()) {
+            if (!Find_NodeElement(b, AMFNodeElementBase::ENET_Texture, &t_tex)) {
+                Throw_ID_NotFound(b);
+            }
 
 
-            src_texture[2] = (CAMFImporter_NodeElement_Texture *)t_tex;
-            src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
+            src_texture[2] = (AMFTexture *)t_tex;
+            src_texture_4check.push_back((AMFTexture *)t_tex);
         } else {
         } else {
             src_texture[2] = nullptr;
             src_texture[2] = nullptr;
         }
         }
 
 
         // A
         // A
-        if (!pID_A.empty()) {
-            if (!Find_NodeElement(pID_A, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
+        if (!a.empty()) {
+            if (!Find_NodeElement(a, AMFNodeElementBase::ENET_Texture, &t_tex)) {
+                Throw_ID_NotFound(a);
+            }
 
 
-            src_texture[3] = (CAMFImporter_NodeElement_Texture *)t_tex;
-            src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
+            src_texture[3] = (AMFTexture *)t_tex;
+            src_texture_4check.push_back((AMFTexture *)t_tex);
         } else {
         } else {
             src_texture[3] = nullptr;
             src_texture[3] = nullptr;
         }
         }
@@ -213,38 +217,37 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
     converted_texture.Depth = src_texture_4check[0]->Depth;
     converted_texture.Depth = src_texture_4check[0]->Depth;
     // if one of source texture is tiled then converted texture is tiled too.
     // if one of source texture is tiled then converted texture is tiled too.
     converted_texture.Tiled = false;
     converted_texture.Tiled = false;
-    for (uint8_t i = 0; i < src_texture_4check.size(); i++)
+    for (uint8_t i = 0; i < src_texture_4check.size(); ++i) {
         converted_texture.Tiled |= src_texture_4check[i]->Tiled;
         converted_texture.Tiled |= src_texture_4check[i]->Tiled;
+    }
 
 
     // Create format hint.
     // Create format hint.
     strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string.
     strcpy(converted_texture.FormatHint, "rgba0000"); // copy initial string.
-    if (!pID_R.empty()) converted_texture.FormatHint[4] = '8';
-    if (!pID_G.empty()) converted_texture.FormatHint[5] = '8';
-    if (!pID_B.empty()) converted_texture.FormatHint[6] = '8';
-    if (!pID_A.empty()) converted_texture.FormatHint[7] = '8';
+    if (!r.empty()) converted_texture.FormatHint[4] = '8';
+    if (!g.empty()) converted_texture.FormatHint[5] = '8';
+    if (!b.empty()) converted_texture.FormatHint[6] = '8';
+    if (!a.empty()) converted_texture.FormatHint[7] = '8';
 
 
-    //
     // Сopy data of textures.
     // Сopy data of textures.
-    //
     size_t tex_size = 0;
     size_t tex_size = 0;
     size_t step = 0;
     size_t step = 0;
     size_t off_g = 0;
     size_t off_g = 0;
     size_t off_b = 0;
     size_t off_b = 0;
 
 
     // Calculate size of the target array and rule how data will be copied.
     // Calculate size of the target array and rule how data will be copied.
-    if (!pID_R.empty() && nullptr != src_texture[0]) {
+    if (!r.empty() && nullptr != src_texture[0]) {
         tex_size += src_texture[0]->Data.size();
         tex_size += src_texture[0]->Data.size();
         step++, off_g++, off_b++;
         step++, off_g++, off_b++;
     }
     }
-    if (!pID_G.empty() && nullptr != src_texture[1]) {
+    if (!g.empty() && nullptr != src_texture[1]) {
         tex_size += src_texture[1]->Data.size();
         tex_size += src_texture[1]->Data.size();
         step++, off_b++;
         step++, off_b++;
     }
     }
-    if (!pID_B.empty() && nullptr != src_texture[2]) {
+    if (!b.empty() && nullptr != src_texture[2]) {
         tex_size += src_texture[2]->Data.size();
         tex_size += src_texture[2]->Data.size();
         step++;
         step++;
     }
     }
-    if (!pID_A.empty() && nullptr != src_texture[3]) {
+    if (!a.empty() && nullptr != src_texture[3]) {
         tex_size += src_texture[3]->Data.size();
         tex_size += src_texture[3]->Data.size();
         step++;
         step++;
     }
     }
@@ -255,17 +258,17 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
     auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void {
     auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void {
         if (!pID.empty()) {
         if (!pID.empty()) {
             for (size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) {
             for (size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) {
-                CAMFImporter_NodeElement_Texture *tex = src_texture[pSrcTexNum];
+                AMFTexture *tex = src_texture[pSrcTexNum];
                 ai_assert(tex);
                 ai_assert(tex);
                 converted_texture.Data[idx_target] = tex->Data.at(idx_src);
                 converted_texture.Data[idx_target] = tex->Data.at(idx_src);
             }
             }
         }
         }
     }; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
     }; // auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
 
 
-    CopyTextureData(pID_R, 0, step, 0);
-    CopyTextureData(pID_G, off_g, step, 1);
-    CopyTextureData(pID_B, off_b, step, 2);
-    CopyTextureData(pID_A, step - 1, step, 3);
+    CopyTextureData(r, 0, step, 0);
+    CopyTextureData(g, off_g, step, 1);
+    CopyTextureData(b, off_b, step, 2);
+    CopyTextureData(a, step - 1, step, 3);
 
 
     // Store new converted texture ID
     // Store new converted texture ID
     converted_texture.ID = TextureConverted_ID;
     converted_texture.ID = TextureConverted_ID;
@@ -276,7 +279,7 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string &
 }
 }
 
 
 void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated) {
 void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace> &pInputList, std::list<std::list<SComplexFace>> &pOutputList_Separated) {
-    auto texmap_is_equal = [](const CAMFImporter_NodeElement_TexMap *pTexMap1, const CAMFImporter_NodeElement_TexMap *pTexMap2) -> bool {
+    auto texmap_is_equal = [](const AMFTexMap *pTexMap1, const AMFTexMap *pTexMap2) -> bool {
         if ((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true;
         if ((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true;
         if (pTexMap1 == nullptr) return false;
         if (pTexMap1 == nullptr) return false;
         if (pTexMap2 == nullptr) return false;
         if (pTexMap2 == nullptr) return false;
@@ -313,73 +316,80 @@ void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace
     } while (!pInputList.empty());
     } while (!pInputList.empty());
 }
 }
 
 
-void AMFImporter::Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata *> &metadataList, aiNode &sceneNode) const {
-    if (!metadataList.empty()) {
-        if (sceneNode.mMetaData != nullptr) throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong.");
+void AMFImporter::Postprocess_AddMetadata(const AMFMetaDataArray &metadataList, aiNode &sceneNode) const {
+    if (metadataList.empty()) {
+        return;
+    }
+
+    if (sceneNode.mMetaData != nullptr) {
+        throw DeadlyImportError("Postprocess. MetaData member in node are not nullptr. Something went wrong.");
+    }
 
 
-        // copy collected metadata to output node.
-        sceneNode.mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metadataList.size()));
-        size_t meta_idx(0);
+    // copy collected metadata to output node.
+    sceneNode.mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(metadataList.size()));
+    size_t meta_idx(0);
 
 
-        for (const CAMFImporter_NodeElement_Metadata &metadata : metadataList) {
-            sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata.Type, aiString(metadata.Value));
-        }
-    } // if(!metadataList.empty())
+    for (const AMFMetadata &metadata : metadataList) {
+        sceneNode.mMetaData->Set(static_cast<unsigned int>(meta_idx++), metadata.Type, aiString(metadata.Value));
+    }
 }
 }
 
 
-void AMFImporter::Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object &pNodeElement, std::list<aiMesh *> &pMeshList, aiNode **pSceneNode) {
-    CAMFImporter_NodeElement_Color *object_color = nullptr;
+void AMFImporter::Postprocess_BuildNodeAndObject(const AMFObject &pNodeElement, MeshArray &meshList, aiNode **pSceneNode) {
+    AMFColor *object_color = nullptr;
 
 
     // create new aiNode and set name as <object> has.
     // create new aiNode and set name as <object> has.
     *pSceneNode = new aiNode;
     *pSceneNode = new aiNode;
     (*pSceneNode)->mName = pNodeElement.ID;
     (*pSceneNode)->mName = pNodeElement.ID;
     // read mesh and color
     // read mesh and color
-    for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
+    for (const AMFNodeElementBase *ne_child : pNodeElement.Child) {
         std::vector<aiVector3D> vertex_arr;
         std::vector<aiVector3D> vertex_arr;
-        std::vector<CAMFImporter_NodeElement_Color *> color_arr;
+        std::vector<AMFColor *> color_arr;
 
 
         // color for object
         // color for object
-        if (ne_child->Type == CAMFImporter_NodeElement::ENET_Color) object_color = (CAMFImporter_NodeElement_Color *)ne_child;
+        if (ne_child->Type == AMFNodeElementBase::ENET_Color) {
+            object_color = (AMFColor *) ne_child;
+        }
 
 
-        if (ne_child->Type == CAMFImporter_NodeElement::ENET_Mesh) {
+        if (ne_child->Type == AMFNodeElementBase::ENET_Mesh) {
             // Create arrays from children of mesh: vertices.
             // Create arrays from children of mesh: vertices.
-            PostprocessHelper_CreateMeshDataArray(*((CAMFImporter_NodeElement_Mesh *)ne_child), vertex_arr, color_arr);
+            PostprocessHelper_CreateMeshDataArray(*((AMFMesh *)ne_child), vertex_arr, color_arr);
             // Use this arrays as a source when creating every aiMesh
             // Use this arrays as a source when creating every aiMesh
-            Postprocess_BuildMeshSet(*((CAMFImporter_NodeElement_Mesh *)ne_child), vertex_arr, color_arr, object_color, pMeshList, **pSceneNode);
+            Postprocess_BuildMeshSet(*((AMFMesh *)ne_child), vertex_arr, color_arr, object_color, meshList, **pSceneNode);
         }
         }
     } // for(const CAMFImporter_NodeElement* ne_child: pNodeElement)
     } // for(const CAMFImporter_NodeElement* ne_child: pNodeElement)
 }
 }
 
 
-void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray,
-        const std::vector<CAMFImporter_NodeElement_Color *> &pVertexColorArray,
-        const CAMFImporter_NodeElement_Color *pObjectColor, std::list<aiMesh *> &pMeshList, aiNode &pSceneNode) {
+void AMFImporter::Postprocess_BuildMeshSet(const AMFMesh &pNodeElement, const std::vector<aiVector3D> &pVertexCoordinateArray,
+        const std::vector<AMFColor *> &pVertexColorArray, const AMFColor *pObjectColor, MeshArray &pMeshList, aiNode &pSceneNode) {
     std::list<unsigned int> mesh_idx;
     std::list<unsigned int> mesh_idx;
 
 
     // all data stored in "volume", search for it.
     // all data stored in "volume", search for it.
-    for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
-        const CAMFImporter_NodeElement_Color *ne_volume_color = nullptr;
+    for (const AMFNodeElementBase *ne_child : pNodeElement.Child) {
+        const AMFColor *ne_volume_color = nullptr;
         const SPP_Material *cur_mat = nullptr;
         const SPP_Material *cur_mat = nullptr;
 
 
-        if (ne_child->Type == CAMFImporter_NodeElement::ENET_Volume) {
+        if (ne_child->Type == AMFNodeElementBase::ENET_Volume) {
             /******************* Get faces *******************/
             /******************* Get faces *******************/
-            const CAMFImporter_NodeElement_Volume *ne_volume = reinterpret_cast<const CAMFImporter_NodeElement_Volume *>(ne_child);
+            const AMFVolume *ne_volume = reinterpret_cast<const AMFVolume *>(ne_child);
 
 
             std::list<SComplexFace> complex_faces_list; // List of the faces of the volume.
             std::list<SComplexFace> complex_faces_list; // List of the faces of the volume.
             std::list<std::list<SComplexFace>> complex_faces_toplist; // List of the face list for every mesh.
             std::list<std::list<SComplexFace>> complex_faces_toplist; // List of the face list for every mesh.
 
 
             // check if volume use material
             // check if volume use material
             if (!ne_volume->MaterialID.empty()) {
             if (!ne_volume->MaterialID.empty()) {
-                if (!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) Throw_ID_NotFound(ne_volume->MaterialID);
+                if (!Find_ConvertedMaterial(ne_volume->MaterialID, &cur_mat)) {
+                    Throw_ID_NotFound(ne_volume->MaterialID);
+                }
             }
             }
 
 
             // inside "volume" collect all data and place to arrays or create new objects
             // inside "volume" collect all data and place to arrays or create new objects
-            for (const CAMFImporter_NodeElement *ne_volume_child : ne_volume->Child) {
+            for (const AMFNodeElementBase *ne_volume_child : ne_volume->Child) {
                 // color for volume
                 // color for volume
-                if (ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Color) {
-                    ne_volume_color = reinterpret_cast<const CAMFImporter_NodeElement_Color *>(ne_volume_child);
-                } else if (ne_volume_child->Type == CAMFImporter_NodeElement::ENET_Triangle) // triangles, triangles colors
+                if (ne_volume_child->Type == AMFNodeElementBase::ENET_Color) {
+                    ne_volume_color = reinterpret_cast<const AMFColor *>(ne_volume_child);
+                } else if (ne_volume_child->Type == AMFNodeElementBase::ENET_Triangle) // triangles, triangles colors
                 {
                 {
-                    const CAMFImporter_NodeElement_Triangle &tri_al = *reinterpret_cast<const CAMFImporter_NodeElement_Triangle *>(ne_volume_child);
+                    const AMFTriangle &tri_al = *reinterpret_cast<const AMFTriangle *>(ne_volume_child);
 
 
                     SComplexFace complex_face;
                     SComplexFace complex_face;
 
 
@@ -388,11 +398,11 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
                     complex_face.TexMap = nullptr;
                     complex_face.TexMap = nullptr;
                     // get data from triangle children: color, texture coordinates.
                     // get data from triangle children: color, texture coordinates.
                     if (tri_al.Child.size()) {
                     if (tri_al.Child.size()) {
-                        for (const CAMFImporter_NodeElement *ne_triangle_child : tri_al.Child) {
-                            if (ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_Color)
-                                complex_face.Color = reinterpret_cast<const CAMFImporter_NodeElement_Color *>(ne_triangle_child);
-                            else if (ne_triangle_child->Type == CAMFImporter_NodeElement::ENET_TexMap)
-                                complex_face.TexMap = reinterpret_cast<const CAMFImporter_NodeElement_TexMap *>(ne_triangle_child);
+                        for (const AMFNodeElementBase *ne_triangle_child : tri_al.Child) {
+                            if (ne_triangle_child->Type == AMFNodeElementBase::ENET_Color)
+                                complex_face.Color = reinterpret_cast<const AMFColor *>(ne_triangle_child);
+                            else if (ne_triangle_child->Type == AMFNodeElementBase::ENET_TexMap)
+                                complex_face.TexMap = reinterpret_cast<const AMFTexMap *>(ne_triangle_child);
                         }
                         }
                     } // if(tri_al.Child.size())
                     } // if(tri_al.Child.size())
 
 
@@ -422,15 +432,18 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
                                 if (face.Face.mIndices[idx_vert] > *pBiggerThan) {
                                 if (face.Face.mIndices[idx_vert] > *pBiggerThan) {
                                     rv = face.Face.mIndices[idx_vert];
                                     rv = face.Face.mIndices[idx_vert];
                                     found = true;
                                     found = true;
-
                                     break;
                                     break;
                                 }
                                 }
                             }
                             }
 
 
-                            if (found) break;
+                            if (found) {
+                                break;
+                            }
                         }
                         }
 
 
-                        if (!found) return *pBiggerThan;
+                        if (!found) {
+                            return *pBiggerThan;
+                        }
                     } else {
                     } else {
                         rv = pFaceList.front().Face.mIndices[0];
                         rv = pFaceList.front().Face.mIndices[0];
                     } // if(pBiggerThan != nullptr) else
                     } // if(pBiggerThan != nullptr) else
@@ -505,9 +518,9 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
                 tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size());
                 tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size());
                 tmesh->mFaces = new aiFace[tmesh->mNumFaces];
                 tmesh->mFaces = new aiFace[tmesh->mNumFaces];
 
 
-                // Create vertices list and optimize indices. Optimisation mean following.In AMF all volumes use one big list of vertices. And one volume
+                // Create vertices list and optimize indices. Optimization mean following.In AMF all volumes use one big list of vertices. And one volume
                 // can use only part of vertices list, for example: vertices list contain few thousands of vertices and volume use vertices 1, 3, 10.
                 // can use only part of vertices list, for example: vertices list contain few thousands of vertices and volume use vertices 1, 3, 10.
-                // Do you need all this thousands of garbage? Of course no. So, optimisation step transformate sparse indices set to continuous.
+                // Do you need all this thousands of garbage? Of course no. So, optimization step transform sparse indices set to continuous.
                 size_t VertexCount_Max = tmesh->mNumFaces * 3; // 3 - triangles.
                 size_t VertexCount_Max = tmesh->mNumFaces * 3; // 3 - triangles.
                 std::vector<aiVector3D> vert_arr, texcoord_arr;
                 std::vector<aiVector3D> vert_arr, texcoord_arr;
                 std::vector<aiColor4D> col_arr;
                 std::vector<aiColor4D> col_arr;
@@ -566,7 +579,7 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
                     size_t idx_vert_new = vert_arr.size();
                     size_t idx_vert_new = vert_arr.size();
                     ///TODO: clean unused vertices. "* 2": in certain cases - mesh full of triangle colors - vert_arr will contain duplicated vertices for
                     ///TODO: clean unused vertices. "* 2": in certain cases - mesh full of triangle colors - vert_arr will contain duplicated vertices for
                     /// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about
                     /// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about
-                    /// optimisation.
+                    /// optimization.
                     bool *idx_vert_used;
                     bool *idx_vert_used;
 
 
                     idx_vert_used = new bool[VertexCount_Max * 2];
                     idx_vert_used = new bool[VertexCount_Max * 2];
@@ -639,15 +652,15 @@ void AMFImporter::Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh &
     } // if(mesh_idx.size() > 0)
     } // if(mesh_idx.size() > 0)
 }
 }
 
 
-void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material &pMaterial) {
+void AMFImporter::Postprocess_BuildMaterial(const AMFMaterial &pMaterial) {
     SPP_Material new_mat;
     SPP_Material new_mat;
 
 
     new_mat.ID = pMaterial.ID;
     new_mat.ID = pMaterial.ID;
-    for (const CAMFImporter_NodeElement *mat_child : pMaterial.Child) {
-        if (mat_child->Type == CAMFImporter_NodeElement::ENET_Color) {
-            new_mat.Color = (CAMFImporter_NodeElement_Color *)mat_child;
-        } else if (mat_child->Type == CAMFImporter_NodeElement::ENET_Metadata) {
-            new_mat.Metadata.push_back((CAMFImporter_NodeElement_Metadata *)mat_child);
+    for (const AMFNodeElementBase *mat_child : pMaterial.Child) {
+        if (mat_child->Type == AMFNodeElementBase::ENET_Color) {
+            new_mat.Color = (AMFColor*)mat_child;
+        } else if (mat_child->Type == AMFNodeElementBase::ENET_Metadata) {
+            new_mat.Metadata.push_back((AMFMetadata *)mat_child);
         }
         }
     } // for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child)
     } // for(const CAMFImporter_NodeElement* mat_child; pMaterial.Child)
 
 
@@ -655,7 +668,7 @@ void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Mater
     mMaterial_Converted.push_back(new_mat);
     mMaterial_Converted.push_back(new_mat);
 }
 }
 
 
-void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation &pConstellation, std::list<aiNode *> &pNodeList) const {
+void AMFImporter::Postprocess_BuildConstellation(AMFConstellation &pConstellation, NodeArray &nodeArray) const {
     aiNode *con_node;
     aiNode *con_node;
     std::list<aiNode *> ch_node;
     std::list<aiNode *> ch_node;
 
 
@@ -667,18 +680,18 @@ void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Conste
     con_node = new aiNode;
     con_node = new aiNode;
     con_node->mName = pConstellation.ID;
     con_node->mName = pConstellation.ID;
     // Walk through children and search for instances of another objects, constellations.
     // Walk through children and search for instances of another objects, constellations.
-    for (const CAMFImporter_NodeElement *ne : pConstellation.Child) {
+    for (const AMFNodeElementBase *ne : pConstellation.Child) {
         aiMatrix4x4 tmat;
         aiMatrix4x4 tmat;
         aiNode *t_node;
         aiNode *t_node;
         aiNode *found_node;
         aiNode *found_node;
 
 
-        if (ne->Type == CAMFImporter_NodeElement::ENET_Metadata) continue;
-        if (ne->Type != CAMFImporter_NodeElement::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>.");
+        if (ne->Type == AMFNodeElementBase::ENET_Metadata) continue;
+        if (ne->Type != AMFNodeElementBase::ENET_Instance) throw DeadlyImportError("Only <instance> nodes can be in <constellation>.");
 
 
         // create alias for conveniance
         // create alias for conveniance
-        CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne);
+        AMFInstance &als = *((AMFInstance *)ne);
         // find referenced object
         // find referenced object
-        if (!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID);
+        if (!Find_ConvertedNode(als.ObjectID, nodeArray, &found_node)) Throw_ID_NotFound(als.ObjectID);
 
 
         // create node for applying transformation
         // create node for applying transformation
         t_node = new aiNode;
         t_node = new aiNode;
@@ -707,13 +720,13 @@ void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Conste
         con_node->mChildren[ch_idx++] = node;
         con_node->mChildren[ch_idx++] = node;
 
 
     // and place "root" of <constellation> node to node list
     // and place "root" of <constellation> node to node list
-    pNodeList.push_back(con_node);
+    nodeArray.push_back(con_node);
 }
 }
 
 
 void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
 void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
-    std::list<aiNode *> node_list;
-    std::list<aiMesh *> mesh_list;
-    std::list<CAMFImporter_NodeElement_Metadata *> meta_list;
+    NodeArray nodeArray;
+    MeshArray mesh_list;
+    AMFMetaDataArray meta_list;
 
 
     //
     //
     // Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
     // Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
@@ -723,18 +736,21 @@ void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
     pScene->mRootNode->mParent = nullptr;
     pScene->mRootNode->mParent = nullptr;
     pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
     pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
     // search for root(<amf>) element
     // search for root(<amf>) element
-    CAMFImporter_NodeElement *root_el = nullptr;
+    AMFNodeElementBase *root_el = nullptr;
 
 
-    for (CAMFImporter_NodeElement *ne : mNodeElement_List) {
-        if (ne->Type != CAMFImporter_NodeElement::ENET_Root) continue;
+    for (AMFNodeElementBase *ne : mNodeElement_List) {
+        if (ne->Type != AMFNodeElementBase::ENET_Root) {
+            continue;
+        }
 
 
         root_el = ne;
         root_el = ne;
-
         break;
         break;
     } // for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
     } // for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
 
 
     // Check if root element are found.
     // Check if root element are found.
-    if (root_el == nullptr) throw DeadlyImportError("Root(<amf>) element not found.");
+    if (root_el == nullptr) {
+        throw DeadlyImportError("Root(<amf>) element not found.");
+    }
 
 
     // after that walk through children of root and collect data. Five types of nodes can be placed at top level - in <amf>: <object>, <material>, <texture>,
     // after that walk through children of root and collect data. Five types of nodes can be placed at top level - in <amf>: <object>, <material>, <texture>,
     // <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
     // <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
@@ -742,34 +758,38 @@ void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
     //
     //
     // 1. <material>
     // 1. <material>
     // 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet
     // 2. <texture> will be converted later when processing triangles list. \sa Postprocess_BuildMeshSet
-    for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
-        if (root_child->Type == CAMFImporter_NodeElement::ENET_Material) Postprocess_BuildMaterial(*((CAMFImporter_NodeElement_Material *)root_child));
+    for (const AMFNodeElementBase *root_child : root_el->Child) {
+        if (root_child->Type == AMFNodeElementBase::ENET_Material) {
+            Postprocess_BuildMaterial(*((AMFMaterial *)root_child));
+        }
     }
     }
 
 
     // After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
     // After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
     //
     //
     // 3. <object>
     // 3. <object>
-    for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
-        if (root_child->Type == CAMFImporter_NodeElement::ENET_Object) {
+    for (const AMFNodeElementBase *root_child : root_el->Child) {
+        if (root_child->Type == AMFNodeElementBase::ENET_Object) {
             aiNode *tnode = nullptr;
             aiNode *tnode = nullptr;
 
 
             // for <object> mesh and node must be built: object ID assigned to aiNode name and will be used in future for <instance>
             // for <object> mesh and node must be built: object ID assigned to aiNode name and will be used in future for <instance>
-            Postprocess_BuildNodeAndObject(*((CAMFImporter_NodeElement_Object *)root_child), mesh_list, &tnode);
-            if (tnode != nullptr) node_list.push_back(tnode);
+            Postprocess_BuildNodeAndObject(*((AMFObject *)root_child), mesh_list, &tnode);
+            if (tnode != nullptr) {
+                nodeArray.push_back(tnode);
+            }
         }
         }
     } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
     } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
 
 
     // And finally read rest of nodes.
     // And finally read rest of nodes.
     //
     //
-    for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
+    for (const AMFNodeElementBase *root_child : root_el->Child) {
         // 4. <constellation>
         // 4. <constellation>
-        if (root_child->Type == CAMFImporter_NodeElement::ENET_Constellation) {
+        if (root_child->Type == AMFNodeElementBase::ENET_Constellation) {
             // <object> and <constellation> at top of self abstraction use aiNode. So we can use only aiNode list for creating new aiNode's.
             // <object> and <constellation> at top of self abstraction use aiNode. So we can use only aiNode list for creating new aiNode's.
-            Postprocess_BuildConstellation(*((CAMFImporter_NodeElement_Constellation *)root_child), node_list);
+            Postprocess_BuildConstellation(*((AMFConstellation *)root_child), nodeArray);
         }
         }
 
 
         // 5, <metadata>
         // 5, <metadata>
-        if (root_child->Type == CAMFImporter_NodeElement::ENET_Metadata) meta_list.push_back((CAMFImporter_NodeElement_Metadata *)root_child);
+        if (root_child->Type == AMFNodeElementBase::ENET_Metadata) meta_list.push_back((AMFMetadata *)root_child);
     } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
     } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
 
 
     // at now we can add collected metadata to root node
     // at now we can add collected metadata to root node
@@ -783,17 +803,17 @@ void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
     // And at this step we are checking that relations.
     // And at this step we are checking that relations.
 nl_clean_loop:
 nl_clean_loop:
 
 
-    if (node_list.size() > 1) {
+    if (nodeArray.size() > 1) {
         // walk through all nodes
         // walk through all nodes
-        for (std::list<aiNode *>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it) {
+        for (NodeArray::iterator nl_it = nodeArray.begin(); nl_it != nodeArray.end(); ++nl_it) {
             // and try to find them in another top nodes.
             // and try to find them in another top nodes.
-            std::list<aiNode *>::const_iterator next_it = nl_it;
+            NodeArray::const_iterator next_it = nl_it;
 
 
             ++next_it;
             ++next_it;
-            for (; next_it != node_list.end(); ++next_it) {
+            for (; next_it != nodeArray.end(); ++next_it) {
                 if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) {
                 if ((*next_it)->FindNode((*nl_it)->mName) != nullptr) {
                     // if current top node(nl_it) found in another top node then erase it from node_list and restart search loop.
                     // if current top node(nl_it) found in another top node then erase it from node_list and restart search loop.
-                    node_list.erase(nl_it);
+                    nodeArray.erase(nl_it);
 
 
                     goto nl_clean_loop;
                     goto nl_clean_loop;
                 }
                 }
@@ -806,10 +826,10 @@ nl_clean_loop:
     //
     //
     //
     //
     // Nodes
     // Nodes
-    if (!node_list.empty()) {
-        std::list<aiNode *>::const_iterator nl_it = node_list.begin();
+    if (!nodeArray.empty()) {
+        NodeArray::const_iterator nl_it = nodeArray.begin();
 
 
-        pScene->mRootNode->mNumChildren = static_cast<unsigned int>(node_list.size());
+        pScene->mRootNode->mNumChildren = static_cast<unsigned int>(nodeArray.size());
         pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
         pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
         for (size_t i = 0; i < pScene->mRootNode->mNumChildren; i++) {
         for (size_t i = 0; i < pScene->mRootNode->mNumChildren; i++) {
             // Objects and constellation that must be showed placed at top of hierarchy in <amf> node. So all aiNode's in node_list must have
             // Objects and constellation that must be showed placed at top of hierarchy in <amf> node. So all aiNode's in node_list must have
@@ -822,7 +842,7 @@ nl_clean_loop:
     //
     //
     // Meshes
     // Meshes
     if (!mesh_list.empty()) {
     if (!mesh_list.empty()) {
-        std::list<aiMesh *>::const_iterator ml_it = mesh_list.begin();
+        MeshArray::const_iterator ml_it = mesh_list.begin();
 
 
         pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
         pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
         pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
         pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];

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

@@ -137,7 +137,7 @@ void ASEImporter::InternReadFile(const std::string &pFile,
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open ASE file " + pFile + ".");
+        throw DeadlyImportError("Failed to open ASE file ", pFile, ".");
     }
     }
 
 
     // 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

+ 4 - 4
code/AssetLib/Assbin/AssbinFileWriter.cpp

@@ -60,10 +60,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include <time.h>
 #include <time.h>
 
 
-#ifdef _WIN32
+#if _MSC_VER
 #pragma warning(push)
 #pragma warning(push)
 #pragma warning(disable : 4706)
 #pragma warning(disable : 4706)
-#endif // _WIN32
+#endif // _MSC_VER
 
 
 namespace Assimp {
 namespace Assimp {
 
 
@@ -825,8 +825,8 @@ void DumpSceneToAssbin(
     AssbinFileWriter fileWriter(shortened, compressed);
     AssbinFileWriter fileWriter(shortened, compressed);
     fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene);
     fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene);
 }
 }
-#ifdef _WIN32
+#if _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
-#endif // _WIN32
+#endif // _MSC_VER
 
 
 } // end of namespace Assimp
 } // end of namespace Assimp

+ 9 - 5
code/AssetLib/Assjson/cencode.c

@@ -9,8 +9,10 @@ For details, see http://sourceforge.net/projects/libb64
 
 
 const int CHARS_PER_LINE = 72;
 const int CHARS_PER_LINE = 72;
 
 
+#ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(push)
 #pragma warning(disable : 4244)
 #pragma warning(disable : 4244)
+#endif // _MSC_VER
 
 
 void base64_init_encodestate(base64_encodestate* state_in)
 void base64_init_encodestate(base64_encodestate* state_in)
 {
 {
@@ -33,9 +35,9 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 	char* codechar = code_out;
 	char* codechar = code_out;
 	char result;
 	char result;
 	char fragment;
 	char fragment;
-	
+
 	result = state_in->result;
 	result = state_in->result;
-	
+
 	switch (state_in->step)
 	switch (state_in->step)
 	{
 	{
 		while (1)
 		while (1)
@@ -74,7 +76,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 			*codechar++ = base64_encode_value(result);
 			*codechar++ = base64_encode_value(result);
 			result  = (fragment & 0x03f) >> 0;
 			result  = (fragment & 0x03f) >> 0;
 			*codechar++ = base64_encode_value(result);
 			*codechar++ = base64_encode_value(result);
-			
+
 			++(state_in->stepcount);
 			++(state_in->stepcount);
 			if (state_in->stepcount == CHARS_PER_LINE/4)
 			if (state_in->stepcount == CHARS_PER_LINE/4)
 			{
 			{
@@ -90,7 +92,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 {
 {
 	char* codechar = code_out;
 	char* codechar = code_out;
-	
+
 	switch (state_in->step)
 	switch (state_in->step)
 	{
 	{
 	case step_B:
 	case step_B:
@@ -106,8 +108,10 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 		break;
 		break;
 	}
 	}
 	*codechar++ = '\n';
 	*codechar++ = '\n';
-	
+
 	return (int)(codechar - code_out);
 	return (int)(codechar - code_out);
 }
 }
 
 
+#ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
+#endif // _MSC_VER

+ 2 - 2
code/AssetLib/Assjson/cencode.h

@@ -8,9 +8,9 @@ For details, see http://sourceforge.net/projects/libb64
 #ifndef BASE64_CENCODE_H
 #ifndef BASE64_CENCODE_H
 #define BASE64_CENCODE_H
 #define BASE64_CENCODE_H
 
 
-#ifdef _WIN32
+#ifdef _MSC_VER
 #pragma warning(disable : 4127 )
 #pragma warning(disable : 4127 )
-#endif // _WIN32
+#endif // _MSC_VER
 
 
 typedef enum
 typedef enum
 {
 {

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

@@ -119,7 +119,7 @@ void B3DImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open B3D file " + pFile + ".");
+        throw DeadlyImportError("Failed to open B3D file ", pFile, ".");
     }
     }
 
 
     // check whether the .b3d file is large enough to contain
     // check whether the .b3d file is large enough to contain
@@ -147,7 +147,7 @@ AI_WONT_RETURN void B3DImporter::Fail(string str) {
 #ifdef DEBUG_B3D
 #ifdef DEBUG_B3D
     ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
     ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
 #endif
 #endif
-    throw DeadlyImportError("B3D Importer - error in B3D file data: " + str);
+    throw DeadlyImportError("B3D Importer - error in B3D file data: ", str);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 19 - 18
code/AssetLib/BVH/BVHLoader.cpp

@@ -71,6 +71,13 @@ static const aiImporterDesc desc = {
     "bvh"
     "bvh"
 };
 };
 
 
+// ------------------------------------------------------------------------------------------------
+// Aborts the file reading with an exception
+template<typename... T>
+AI_WONT_RETURN void BVHLoader::ThrowException(T&&... args) {
+    throw DeadlyImportError(mFileName, ":", mLine, " - ", args...);
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 BVHLoader::BVHLoader() :
 BVHLoader::BVHLoader() :
@@ -118,7 +125,7 @@ void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSyst
     // read file into memory
     // read file into memory
     std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
     std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open file " + pFile + ".");
+        throw DeadlyImportError("Failed to open file ", pFile, ".");
     }
     }
 
 
     size_t fileSize = file->FileSize();
     size_t fileSize = file->FileSize();
@@ -176,12 +183,12 @@ aiNode *BVHLoader::ReadNode() {
     // first token is name
     // first token is name
     std::string nodeName = GetNextToken();
     std::string nodeName = GetNextToken();
     if (nodeName.empty() || nodeName == "{")
     if (nodeName.empty() || nodeName == "{")
-        ThrowException(format() << "Expected node name, but found \"" << nodeName << "\".");
+        ThrowException("Expected node name, but found \"", nodeName, "\".");
 
 
     // then an opening brace should follow
     // then an opening brace should follow
     std::string openBrace = GetNextToken();
     std::string openBrace = GetNextToken();
     if (openBrace != "{")
     if (openBrace != "{")
-        ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
+        ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\".");
 
 
     // Create a node
     // Create a node
     aiNode *node = new aiNode(nodeName);
     aiNode *node = new aiNode(nodeName);
@@ -211,7 +218,7 @@ aiNode *BVHLoader::ReadNode() {
             siteToken.clear();
             siteToken.clear();
             siteToken = GetNextToken();
             siteToken = GetNextToken();
             if (siteToken != "Site")
             if (siteToken != "Site")
-                ThrowException(format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\".");
+                ThrowException("Expected \"End Site\" keyword, but found \"", token, " ", siteToken, "\".");
 
 
             aiNode *child = ReadEndSite(nodeName);
             aiNode *child = ReadEndSite(nodeName);
             child->mParent = node;
             child->mParent = node;
@@ -221,7 +228,7 @@ aiNode *BVHLoader::ReadNode() {
             break;
             break;
         } else {
         } else {
             // everything else is a parse error
             // everything else is a parse error
-            ThrowException(format() << "Unknown keyword \"" << token << "\".");
+            ThrowException("Unknown keyword \"", token, "\".");
         }
         }
     }
     }
 
 
@@ -242,7 +249,7 @@ aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
     // check opening brace
     // check opening brace
     std::string openBrace = GetNextToken();
     std::string openBrace = GetNextToken();
     if (openBrace != "{")
     if (openBrace != "{")
-        ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
+        ThrowException("Expected opening brace \"{\", but found \"", openBrace, "\".");
 
 
     // Create a node
     // Create a node
     aiNode *node = new aiNode("EndSite_" + pParentName);
     aiNode *node = new aiNode("EndSite_" + pParentName);
@@ -261,7 +268,7 @@ aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
             break;
             break;
         } else {
         } else {
             // everything else is a parse error
             // everything else is a parse error
-            ThrowException(format() << "Unknown keyword \"" << token << "\".");
+            ThrowException("Unknown keyword \"", token, "\".");
         }
         }
     }
     }
 
 
@@ -307,7 +314,7 @@ void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) {
         else if (channelToken == "Zrotation")
         else if (channelToken == "Zrotation")
             pNode.mChannels.push_back(Channel_RotationZ);
             pNode.mChannels.push_back(Channel_RotationZ);
         else
         else
-            ThrowException(format() << "Invalid channel specifier \"" << channelToken << "\".");
+            ThrowException("Invalid channel specifier \"", channelToken, "\".");
     }
     }
 }
 }
 
 
@@ -317,7 +324,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
     // Read number of frames
     // Read number of frames
     std::string tokenFrames = GetNextToken();
     std::string tokenFrames = GetNextToken();
     if (tokenFrames != "Frames:")
     if (tokenFrames != "Frames:")
-        ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
+        ThrowException("Expected frame count \"Frames:\", but found \"", tokenFrames, "\".");
 
 
     float numFramesFloat = GetNextTokenAsFloat();
     float numFramesFloat = GetNextTokenAsFloat();
     mAnimNumFrames = (unsigned int)numFramesFloat;
     mAnimNumFrames = (unsigned int)numFramesFloat;
@@ -326,7 +333,7 @@ void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
     std::string tokenDuration1 = GetNextToken();
     std::string tokenDuration1 = GetNextToken();
     std::string tokenDuration2 = GetNextToken();
     std::string tokenDuration2 = GetNextToken();
     if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
     if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
-        ThrowException(format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\".");
+        ThrowException("Expected frame duration \"Frame Time:\", but found \"", tokenDuration1, " ", tokenDuration2, "\".");
 
 
     mAnimTickDuration = GetNextTokenAsFloat();
     mAnimTickDuration = GetNextTokenAsFloat();
 
 
@@ -393,17 +400,11 @@ float BVHLoader::GetNextTokenAsFloat() {
     ctoken = fast_atoreal_move<float>(ctoken, result);
     ctoken = fast_atoreal_move<float>(ctoken, result);
 
 
     if (ctoken != token.c_str() + token.length())
     if (ctoken != token.c_str() + token.length())
-        ThrowException(format() << "Expected a floating point number, but found \"" << token << "\".");
+        ThrowException("Expected a floating point number, but found \"", token, "\".");
 
 
     return result;
     return result;
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-// Aborts the file reading with an exception
-AI_WONT_RETURN void BVHLoader::ThrowException(const std::string &pError) {
-    throw DeadlyImportError(format() << mFileName << ":" << mLine << " - " << pError);
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructs an animation for the motion data and stores it in the given scene
 // Constructs an animation for the motion data and stores it in the given scene
 void BVHLoader::CreateAnimation(aiScene *pScene) {
 void BVHLoader::CreateAnimation(aiScene *pScene) {
@@ -453,7 +454,7 @@ void BVHLoader::CreateAnimation(aiScene *pScene) {
                     std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
                     std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
 
 
                     if (mapIter == channelMap.end())
                     if (mapIter == channelMap.end())
-                        throw DeadlyImportError("Missing position channel in node " + nodeName);
+                        throw DeadlyImportError("Missing position channel in node ", nodeName);
                     else {
                     else {
                         int channelIdx = mapIter->second;
                         int channelIdx = mapIter->second;
                         switch (channel) {
                         switch (channel) {

+ 2 - 1
code/AssetLib/BVH/BVHLoader.h

@@ -134,7 +134,8 @@ protected:
     float GetNextTokenAsFloat();
     float GetNextTokenAsFloat();
 
 
     /** Aborts the file reading with an exception */
     /** Aborts the file reading with an exception */
-    AI_WONT_RETURN void ThrowException(const std::string &pError) AI_WONT_RETURN_SUFFIX;
+    template<typename... T>
+    AI_WONT_RETURN void ThrowException(T&&... args) AI_WONT_RETURN_SUFFIX;
 
 
     /** Constructs an animation for the motion data and stores it in the given scene */
     /** Constructs an animation for the motion data and stores it in the given scene */
     void CreateAnimation(aiScene *pScene);
     void CreateAnimation(aiScene *pScene);

+ 1 - 1
code/AssetLib/Blender/BlenderCustomData.cpp

@@ -149,7 +149,7 @@ bool isValidCustomDataType(const int cdtype) {
 
 
 bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
 bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
     if (!isValidCustomDataType(cdtype)) {
     if (!isValidCustomDataType(cdtype)) {
-        throw Error((Formatter::format(), "CustomData.type ", cdtype, " out of index"));
+        throw Error("CustomData.type ", cdtype, " out of index");
     }
     }
 
 
     const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];
     const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];

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

@@ -130,9 +130,7 @@ void DNAParser::Parse() {
 
 
         uint16_t n = stream.GetI2();
         uint16_t n = stream.GetI2();
         if (n >= types.size()) {
         if (n >= types.size()) {
-            throw DeadlyImportError((format(),
-                    "BlenderDNA: Invalid type index in structure name", n,
-                    " (there are only ", types.size(), " entries)"));
+            throw DeadlyImportError("BlenderDNA: Invalid type index in structure name", n, " (there are only ", types.size(), " entries)");
         }
         }
 
 
         // maintain separate indexes
         // maintain separate indexes
@@ -141,7 +139,6 @@ void DNAParser::Parse() {
         dna.structures.push_back(Structure());
         dna.structures.push_back(Structure());
         Structure &s = dna.structures.back();
         Structure &s = dna.structures.back();
         s.name = types[n].name;
         s.name = types[n].name;
-        //s.index = dna.structures.size()-1;
 
 
         n = stream.GetI2();
         n = stream.GetI2();
         s.fields.reserve(n);
         s.fields.reserve(n);
@@ -151,9 +148,7 @@ void DNAParser::Parse() {
 
 
             uint16_t j = stream.GetI2();
             uint16_t j = stream.GetI2();
             if (j >= types.size()) {
             if (j >= types.size()) {
-                throw DeadlyImportError((format(),
-                        "BlenderDNA: Invalid type index in structure field ", j,
-                        " (there are only ", types.size(), " entries)"));
+                throw DeadlyImportError("BlenderDNA: Invalid type index in structure field ", j, " (there are only ", types.size(), " entries)");
             }
             }
             s.fields.push_back(Field());
             s.fields.push_back(Field());
             Field &f = s.fields.back();
             Field &f = s.fields.back();
@@ -164,9 +159,7 @@ void DNAParser::Parse() {
 
 
             j = stream.GetI2();
             j = stream.GetI2();
             if (j >= names.size()) {
             if (j >= names.size()) {
-                throw DeadlyImportError((format(),
-                        "BlenderDNA: Invalid name index in structure field ", j,
-                        " (there are only ", names.size(), " entries)"));
+                throw DeadlyImportError("BlenderDNA: Invalid name index in structure field ", j, " (there are only ", names.size(), " entries)");
             }
             }
 
 
             f.name = names[j];
             f.name = names[j];
@@ -188,9 +181,7 @@ void DNAParser::Parse() {
             if (*f.name.rbegin() == ']') {
             if (*f.name.rbegin() == ']') {
                 const std::string::size_type rb = f.name.find('[');
                 const std::string::size_type rb = f.name.find('[');
                 if (rb == std::string::npos) {
                 if (rb == std::string::npos) {
-                    throw DeadlyImportError((format(),
-                            "BlenderDNA: Encountered invalid array declaration ",
-                            f.name));
+                    throw DeadlyImportError("BlenderDNA: Encountered invalid array declaration ", f.name);
                 }
                 }
 
 
                 f.flags |= FieldFlag_Array;
                 f.flags |= FieldFlag_Array;

+ 6 - 6
code/AssetLib/Blender/BlenderDNA.h

@@ -83,9 +83,9 @@ class ObjectCache;
  *  ancestry. */
  *  ancestry. */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct Error : DeadlyImportError {
 struct Error : DeadlyImportError {
-    Error(const std::string &s) :
-            DeadlyImportError(s) {
-        // empty
+    template <typename... T>
+    explicit Error(T &&...args) :
+            DeadlyImportError(args...) {
     }
     }
 };
 };
 
 
@@ -186,7 +186,7 @@ struct Field {
 };
 };
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
-/** Range of possible behaviours for fields absend in the input file. Some are
+/** Range of possible behaviors for fields absence in the input file. Some are
  *  mission critical so we need them, while others can silently be default
  *  mission critical so we need them, while others can silently be default
  *  initialized and no animations are harmed. */
  *  initialized and no animations are harmed. */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
@@ -394,7 +394,7 @@ private:
 
 
 // --------------------------------------------------------
 // --------------------------------------------------------
 template <>
 template <>
-struct Structure ::_defaultInitializer<ErrorPolicy_Warn> {
+struct Structure::_defaultInitializer<ErrorPolicy_Warn> {
 
 
     template <typename T>
     template <typename T>
     void operator()(T &out, const char *reason = "<add reason>") {
     void operator()(T &out, const char *reason = "<add reason>") {
@@ -406,7 +406,7 @@ struct Structure ::_defaultInitializer<ErrorPolicy_Warn> {
 };
 };
 
 
 template <>
 template <>
-struct Structure ::_defaultInitializer<ErrorPolicy_Fail> {
+struct Structure::_defaultInitializer<ErrorPolicy_Fail> {
 
 
     template <typename T>
     template <typename T>
     void operator()(T & /*out*/, const char * = "") {
     void operator()(T & /*out*/, const char * = "") {

+ 22 - 34
code/AssetLib/Blender/BlenderDNA.inl

@@ -57,9 +57,7 @@ const Field& Structure :: operator [] (const std::string& ss) const
 {
 {
     std::map<std::string, size_t>::const_iterator it = indices.find(ss);
     std::map<std::string, size_t>::const_iterator it = indices.find(ss);
     if (it == indices.end()) {
     if (it == indices.end()) {
-        throw Error((Formatter::format(),
-            "BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`"
-            ));
+        throw Error("BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`");
     }
     }
 
 
     return fields[(*it).second];
     return fields[(*it).second];
@@ -76,9 +74,7 @@ const Field* Structure :: Get (const std::string& ss) const
 const Field& Structure :: operator [] (const size_t i) const
 const Field& Structure :: operator [] (const size_t i) const
 {
 {
     if (i >= fields.size()) {
     if (i >= fields.size()) {
-        throw Error((Formatter::format(),
-            "BlendDNA: There is no field with index `",i,"` in structure `",name,"`"
-            ));
+        throw Error("BlendDNA: There is no field with index `",i,"` in structure `",name,"`");
     }
     }
 
 
     return fields[i];
     return fields[i];
@@ -109,9 +105,7 @@ void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatab
 
 
         // is the input actually an array?
         // is the input actually an array?
         if (!(f.flags & FieldFlag_Array)) {
         if (!(f.flags & FieldFlag_Array)) {
-            throw Error((Formatter::format(),"Field `",name,"` of structure `",
-                this->name,"` ought to be an array of size ",M
-                ));
+            throw Error("Field `",name,"` of structure `",this->name,"` ought to be an array of size ",M);
         }
         }
 
 
         db.reader->IncPtr(f.offset);
         db.reader->IncPtr(f.offset);
@@ -148,9 +142,9 @@ void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileD
 
 
         // is the input actually an array?
         // is the input actually an array?
         if (!(f.flags & FieldFlag_Array)) {
         if (!(f.flags & FieldFlag_Array)) {
-            throw Error((Formatter::format(),"Field `",name,"` of structure `",
+            throw Error("Field `",name,"` of structure `",
                 this->name,"` ought to be an array of size ",M,"*",N
                 this->name,"` ought to be an array of size ",M,"*",N
-                ));
+                );
         }
         }
 
 
         db.reader->IncPtr(f.offset);
         db.reader->IncPtr(f.offset);
@@ -195,8 +189,8 @@ bool Structure :: ReadFieldPtr(TOUT<T>& out, const char* name, const FileDatabas
 
 
         // sanity check, should never happen if the genblenddna script is right
         // sanity check, should never happen if the genblenddna script is right
         if (!(f->flags & FieldFlag_Pointer)) {
         if (!(f->flags & FieldFlag_Pointer)) {
-            throw Error((Formatter::format(),"Field `",name,"` of structure `",
-                this->name,"` ought to be a pointer"));
+            throw Error("Field `",name,"` of structure `",
+                this->name,"` ought to be a pointer");
         }
         }
 
 
         db.reader->IncPtr(f->offset);
         db.reader->IncPtr(f->offset);
@@ -241,8 +235,8 @@ bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
 #ifdef _DEBUG
 #ifdef _DEBUG
         // sanity check, should never happen if the genblenddna script is right
         // sanity check, should never happen if the genblenddna script is right
         if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
         if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) {
-            throw Error((Formatter::format(),"Field `",name,"` of structure `",
-                this->name,"` ought to be a pointer AND an array"));
+            throw Error("Field `",name,"` of structure `",
+                this->name,"` ought to be a pointer AND an array");
         }
         }
 #endif // _DEBUG
 #endif // _DEBUG
 
 
@@ -322,8 +316,8 @@ bool Structure::ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, con
 
 
 		// sanity check, should never happen if the genblenddna script is right
 		// sanity check, should never happen if the genblenddna script is right
 		if (!(f->flags & FieldFlag_Pointer)) {
 		if (!(f->flags & FieldFlag_Pointer)) {
-			throw Error((Formatter::format(), "Field `", name, "` of structure `",
-				this->name, "` ought to be a pointer"));
+			throw Error("Field `", name, "` of structure `",
+				this->name, "` ought to be a pointer");
 		}
 		}
 
 
 		db.reader->IncPtr(f->offset);
 		db.reader->IncPtr(f->offset);
@@ -369,8 +363,8 @@ bool Structure::ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const
 
 
 		// sanity check, should never happen if the genblenddna script is right
 		// sanity check, should never happen if the genblenddna script is right
 		if (!(f->flags & FieldFlag_Pointer)) {
 		if (!(f->flags & FieldFlag_Pointer)) {
-			throw Error((Formatter::format(), "Field `", name, "` of structure `",
-				this->name, "` ought to be a pointer"));
+			throw Error("Field `", name, "` of structure `",
+				this->name, "` ought to be a pointer");
 		}
 		}
 
 
 		db.reader->IncPtr(f->offset);
 		db.reader->IncPtr(f->offset);
@@ -428,9 +422,9 @@ bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const Fil
     // and check if it matches the type which we expect.
     // and check if it matches the type which we expect.
     const Structure& ss = db.dna[block->dna_index];
     const Structure& ss = db.dna[block->dna_index];
     if (ss != s) {
     if (ss != s) {
-        throw Error((Formatter::format(),"Expected target to be of type `",s.name,
+        throw Error("Expected target to be of type `",s.name,
             "` but seemingly it is a `",ss.name,"` instead"
             "` but seemingly it is a `",ss.name,"` instead"
-            ));
+            );
     }
     }
 
 
     // try to retrieve the object from the cache
     // try to retrieve the object from the cache
@@ -614,16 +608,14 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
     if (it == db.entries.end()) {
     if (it == db.entries.end()) {
         // this is crucial, pointers may not be invalid.
         // this is crucial, pointers may not be invalid.
         // this is either a corrupted file or an attempted attack.
         // this is either a corrupted file or an attempted attack.
-        throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
-            std::hex,ptrval.val,", no file block falls into this address range"
-            ));
+        throw DeadlyImportError("Failure resolving pointer 0x",
+            std::hex,ptrval.val,", no file block falls into this address range");
     }
     }
     if (ptrval.val >= (*it).address.val + (*it).size) {
     if (ptrval.val >= (*it).address.val + (*it).size) {
-        throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x",
+        throw DeadlyImportError("Failure resolving pointer 0x",
             std::hex,ptrval.val,", nearest file block starting at 0x",
             std::hex,ptrval.val,", nearest file block starting at 0x",
             (*it).address.val," ends at 0x",
             (*it).address.val," ends at 0x",
-            (*it).address.val + (*it).size
-            ));
+            (*it).address.val + (*it).size);
     }
     }
     return &*it;
     return &*it;
 }
 }
@@ -676,7 +668,7 @@ template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,
         out = static_cast<T>(db.reader->GetF8());
         out = static_cast<T>(db.reader->GetF8());
     }
     }
     else {
     else {
-        throw DeadlyImportError("Unknown source for conversion to primitive data type: "+in.name);
+        throw DeadlyImportError("Unknown source for conversion to primitive data type: ", in.name);
     }
     }
 }
 }
 
 
@@ -784,9 +776,7 @@ const Structure& DNA :: operator [] (const std::string& ss) const
 {
 {
     std::map<std::string, size_t>::const_iterator it = indices.find(ss);
     std::map<std::string, size_t>::const_iterator it = indices.find(ss);
     if (it == indices.end()) {
     if (it == indices.end()) {
-        throw Error((Formatter::format(),
-            "BlendDNA: Did not find a structure named `",ss,"`"
-            ));
+        throw Error("BlendDNA: Did not find a structure named `",ss,"`");
     }
     }
 
 
     return structures[(*it).second];
     return structures[(*it).second];
@@ -803,9 +793,7 @@ const Structure* DNA :: Get (const std::string& ss) const
 const Structure& DNA :: operator [] (const size_t i) const
 const Structure& DNA :: operator [] (const size_t i) const
 {
 {
     if (i >= structures.size()) {
     if (i >= structures.size()) {
-        throw Error((Formatter::format(),
-            "BlendDNA: There is no structure with index `",i,"`"
-            ));
+        throw Error("BlendDNA: There is no structure with index `",i,"`");
     }
     }
 
 
     return structures[i];
     return structures[i];

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

@@ -748,9 +748,8 @@ void BlenderImporter::BuildMaterials(ConversionData &conv_data) {
 void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) {
 void BlenderImporter::CheckActualType(const ElemBase *dt, const char *check) {
     ai_assert(dt);
     ai_assert(dt);
     if (strcmp(dt->dna_type, check)) {
     if (strcmp(dt->dna_type, check)) {
-        ThrowException((format(),
-                "Expected object at ", std::hex, dt, " to be of type `", check,
-                "`, but it claims to be a `", dt->dna_type, "`instead"));
+        ThrowException("Expected object at ", std::hex, dt, " to be of type `", check,
+                "`, but it claims to be a `", dt->dna_type, "`instead");
     }
     }
 }
 }
 
 

+ 5 - 38
code/AssetLib/Blender/BlenderLoader.h

@@ -106,51 +106,18 @@ class BlenderImporter : public BaseImporter, public LogFunctions<BlenderImporter
 public:
 public:
     BlenderImporter();
     BlenderImporter();
     ~BlenderImporter();
     ~BlenderImporter();
-
-public:
-
-    // --------------------
-    bool CanRead( const std::string& pFile,
-        IOSystem* pIOHandler,
-        bool checkSig
-    ) const;
+    bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
 
 
 protected:
 protected:
-
-    // --------------------
     const aiImporterDesc* GetInfo () const;
     const aiImporterDesc* GetInfo () const;
-
-    // --------------------
     void GetExtensionList(std::set<std::string>& app);
     void GetExtensionList(std::set<std::string>& app);
-
-    // --------------------
     void SetupProperties(const Importer* pImp);
     void SetupProperties(const Importer* pImp);
-
-    // --------------------
-    void InternReadFile( const std::string& pFile,
-        aiScene* pScene,
-        IOSystem* pIOHandler
-    );
-
-    // --------------------
-    void ParseBlendFile(Blender::FileDatabase& out,
-        std::shared_ptr<IOStream> stream
-    );
-
-    // --------------------
-    void ExtractScene(Blender::Scene& out,
-        const Blender::FileDatabase& file
-    );
-
-    // --------------------
-    void ConvertBlendFile(aiScene* out,
-        const Blender::Scene& in,
-        const Blender::FileDatabase& file
-    );
+    void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
+    void ParseBlendFile(Blender::FileDatabase& out, std::shared_ptr<IOStream> stream);
+    void ExtractScene(Blender::Scene& out, const Blender::FileDatabase& file);
+    void ConvertBlendFile(aiScene* out, const Blender::Scene& in, const Blender::FileDatabase& file);
 
 
 private:
 private:
-
-    // --------------------
     aiNode* ConvertNode(const Blender::Scene& in,
     aiNode* ConvertNode(const Blender::Scene& in,
         const Blender::Object* obj,
         const Blender::Object* obj,
         Blender::ConversionData& conv_info,
         Blender::ConversionData& conv_info,

+ 5 - 2
code/AssetLib/Blender/BlenderScene.h

@@ -155,7 +155,7 @@ struct World : ElemBase {
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct MVert : ElemBase {
 struct MVert : ElemBase {
     float co[3] FAIL;
     float co[3] FAIL;
-    float no[3] FAIL; // readed as short and divided through / 32767.f
+    float no[3] FAIL; // read as short and divided through / 32767.f
     char flag;
     char flag;
     int mat_nr WARN;
     int mat_nr WARN;
     int bweight;
     int bweight;
@@ -228,7 +228,10 @@ struct TFace : ElemBase {
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct MTFace : ElemBase {
 struct MTFace : ElemBase {
     MTFace() :
     MTFace() :
-            flag(0), mode(0), tile(0), unwrap(0) {
+            flag(0),
+            mode(0),
+            tile(0),
+            unwrap(0) {
     }
     }
 
 
     float uv[4][2] FAIL;
     float uv[4][2] FAIL;

+ 7 - 1
code/AssetLib/Blender/BlenderTessellator.cpp

@@ -386,7 +386,14 @@ void BlenderTessellatorP2T::ReferencePoints( std::vector< Blender::PointP2T >& p
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const
 inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const
 {
 {
+#if defined __clang__
+#    pragma clang diagnostic push
+#    pragma clang diagnostic ignored "-Winvalid-offsetof"
+#endif // __clang__
     unsigned int pointOffset = offsetof( PointP2T, point2D );
     unsigned int pointOffset = offsetof( PointP2T, point2D );
+#if defined __clang__
+#    pragma clang diagnostic pop
+#endif
     PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
     PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
     if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
     if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
     {
     {
@@ -394,7 +401,6 @@ inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& poi
     }
     }
     return pointStruct;
     return pointStruct;
 }
 }
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const
 void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const
 {
 {

+ 1 - 1
code/AssetLib/COB/COBLoader.cpp

@@ -125,7 +125,7 @@ void COBImporter::SetupProperties(const Importer * /*pImp*/) {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 /*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string &msg) {
 /*static*/ AI_WONT_RETURN void COBImporter::ThrowException(const std::string &msg) {
-    throw DeadlyImportError("COB: " + msg);
+    throw DeadlyImportError("COB: ", msg);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 1 - 1
code/AssetLib/CSM/CSMLoader.cpp

@@ -128,7 +128,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if( file.get() == nullptr) {
     if( file.get() == nullptr) {
-        throw DeadlyImportError( "Failed to open CSM file " + pFile + ".");
+        throw DeadlyImportError( "Failed to open CSM file ", pFile, ".");
     }
     }
 
 
     // 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

+ 1 - 1
code/AssetLib/Collada/ColladaExporter.cpp

@@ -573,7 +573,7 @@ bool ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial &
             index_str = index_str.substr(1, std::string::npos);
             index_str = index_str.substr(1, std::string::npos);
 
 
             try {
             try {
-                index = (unsigned int)strtoul10_64(index_str.c_str());
+                index = (unsigned int)strtoul10_64<DeadlyExportError>(index_str.c_str());
             } catch (std::exception &error) {
             } catch (std::exception &error) {
                 throw DeadlyExportError(error.what());
                 throw DeadlyExportError(error.what());
             }
             }

+ 3 - 4
code/AssetLib/Collada/ColladaHelper.cpp

@@ -1,5 +1,3 @@
-/** Helper structures for the Collada loader */
-
 /*
 /*
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
@@ -40,6 +38,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
+/** Helper structures for the Collada loader */
 
 
 #include "ColladaHelper.h"
 #include "ColladaHelper.h"
 
 
@@ -54,7 +53,7 @@ const MetaKeyPairVector MakeColladaAssimpMetaKeys() {
     result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR);
     result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR);
     result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT);
     result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT);
     return result;
     return result;
-};
+}
 
 
 const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
 const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
     static const MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
     static const MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
@@ -67,7 +66,7 @@ const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
         ToCamelCase(val.first);
         ToCamelCase(val.first);
     }
     }
     return result;
     return result;
-};
+}
 
 
 const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() {
 const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() {
     static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
     static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();

+ 109 - 119
code/AssetLib/Collada/ColladaHelper.h

@@ -1,12 +1,9 @@
-/** Helper structures for the Collada loader */
-
 /*
 /*
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -42,12 +39,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
+/** Helper structures for the Collada loader */
+
 #ifndef AI_COLLADAHELPER_H_INC
 #ifndef AI_COLLADAHELPER_H_INC
 #define AI_COLLADAHELPER_H_INC
 #define AI_COLLADAHELPER_H_INC
 
 
 #include <assimp/light.h>
 #include <assimp/light.h>
 #include <assimp/material.h>
 #include <assimp/material.h>
 #include <assimp/mesh.h>
 #include <assimp/mesh.h>
+
 #include <stdint.h>
 #include <stdint.h>
 #include <map>
 #include <map>
 #include <set>
 #include <set>
@@ -58,14 +58,14 @@ struct aiMaterial;
 namespace Assimp {
 namespace Assimp {
 namespace Collada {
 namespace Collada {
 
 
-/** Collada file versions which evolved during the years ... */
+/// Collada file versions which evolved during the years ...
 enum FormatVersion {
 enum FormatVersion {
     FV_1_5_n,
     FV_1_5_n,
     FV_1_4_n,
     FV_1_4_n,
     FV_1_3_n
     FV_1_3_n
 };
 };
 
 
-/** Transformation types that can be applied to a node */
+/// Transformation types that can be applied to a node
 enum TransformType {
 enum TransformType {
     TF_LOOKAT,
     TF_LOOKAT,
     TF_ROTATE,
     TF_ROTATE,
@@ -75,7 +75,7 @@ enum TransformType {
     TF_MATRIX
     TF_MATRIX
 };
 };
 
 
-/** Different types of input data to a vertex or face */
+/// Different types of input data to a vertex or face
 enum InputType {
 enum InputType {
     IT_Invalid,
     IT_Invalid,
     IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
     IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data.
@@ -87,38 +87,39 @@ enum InputType {
     IT_Bitangent
     IT_Bitangent
 };
 };
 
 
-/** Supported controller types */
+/// Supported controller types
 enum ControllerType {
 enum ControllerType {
     Skin,
     Skin,
     Morph
     Morph
 };
 };
 
 
-/** Supported morph methods */
+/// Supported morph methods
 enum MorphMethod {
 enum MorphMethod {
     Normalized,
     Normalized,
     Relative
     Relative
 };
 };
 
 
-/** Common metadata keys as <Collada, Assimp> */
-typedef std::pair<std::string, std::string> MetaKeyPair;
-typedef std::vector<MetaKeyPair> MetaKeyPairVector;
+/// Common metadata keys as <Collada, Assimp>
+using MetaKeyPair = std::pair<std::string, std::string>;
+using MetaKeyPairVector = std::vector<MetaKeyPair>;
 
 
-// Collada as lower_case (native)
+/// Collada as lower_case (native)
 const MetaKeyPairVector &GetColladaAssimpMetaKeys();
 const MetaKeyPairVector &GetColladaAssimpMetaKeys();
+
 // Collada as CamelCase (used by Assimp for consistency)
 // Collada as CamelCase (used by Assimp for consistency)
 const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
 const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
 
 
-/** Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool" */
+/// Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool"
 void ToCamelCase(std::string &text);
 void ToCamelCase(std::string &text);
 
 
-/** Contains all data for one of the different transformation types */
+/// Contains all data for one of the different transformation types
 struct Transform {
 struct Transform {
     std::string mID; ///< SID of the transform step, by which anim channels address their target node
     std::string mID; ///< SID of the transform step, by which anim channels address their target node
     TransformType mType;
     TransformType mType;
     ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
     ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
 };
 };
 
 
-/** A collada camera. */
+/// A collada camera.
 struct Camera {
 struct Camera {
     Camera() :
     Camera() :
             mOrtho(false),
             mOrtho(false),
@@ -128,22 +129,22 @@ struct Camera {
             mZNear(0.1f),
             mZNear(0.1f),
             mZFar(1000.f) {}
             mZFar(1000.f) {}
 
 
-    // Name of camera
+    /// Name of camera
     std::string mName;
     std::string mName;
 
 
-    // True if it is an orthografic camera
+    /// True if it is an orthographic camera
     bool mOrtho;
     bool mOrtho;
 
 
-    //! Horizontal field of view in degrees
+    /// Horizontal field of view in degrees
     ai_real mHorFov;
     ai_real mHorFov;
 
 
-    //! Vertical field of view in degrees
+    /// Vertical field of view in degrees
     ai_real mVerFov;
     ai_real mVerFov;
 
 
-    //! Screen aspect
+    /// Screen aspect
     ai_real mAspect;
     ai_real mAspect;
 
 
-    //! Near& far z
+    /// Near& far z
     ai_real mZNear, mZFar;
     ai_real mZNear, mZFar;
 };
 };
 
 
@@ -162,27 +163,27 @@ struct Light {
             mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
             mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
             mIntensity(1.f) {}
             mIntensity(1.f) {}
 
 
-    //! Type of the light source aiLightSourceType + ambient
+    /// Type of the light source aiLightSourceType + ambient
     unsigned int mType;
     unsigned int mType;
 
 
-    //! Color of the light
+    /// Color of the light
     aiColor3D mColor;
     aiColor3D mColor;
 
 
-    //! Light attenuation
+    /// Light attenuation
     ai_real mAttConstant, mAttLinear, mAttQuadratic;
     ai_real mAttConstant, mAttLinear, mAttQuadratic;
 
 
-    //! Spot light falloff
+    /// Spot light falloff
     ai_real mFalloffAngle;
     ai_real mFalloffAngle;
     ai_real mFalloffExponent;
     ai_real mFalloffExponent;
 
 
     // -----------------------------------------------------
     // -----------------------------------------------------
     // FCOLLADA extension from here
     // FCOLLADA extension from here
 
 
-    //! ... related stuff from maja and max extensions
+    /// ... related stuff from maja and max extensions
     ai_real mPenumbraAngle;
     ai_real mPenumbraAngle;
     ai_real mOuterAngle;
     ai_real mOuterAngle;
 
 
-    //! Common light intensity
+    /// Common light intensity
     ai_real mIntensity;
     ai_real mIntensity;
 };
 };
 
 
@@ -192,30 +193,29 @@ struct InputSemanticMapEntry {
             mSet(0),
             mSet(0),
             mType(IT_Invalid) {}
             mType(IT_Invalid) {}
 
 
-    //! Index of set, optional
+    /// Index of set, optional
     unsigned int mSet;
     unsigned int mSet;
 
 
-    //! Type of referenced vertex input
+    /// Type of referenced vertex input
     InputType mType;
     InputType mType;
 };
 };
 
 
-/** Table to map from effect to vertex input semantics */
+/// Table to map from effect to vertex input semantics
 struct SemanticMappingTable {
 struct SemanticMappingTable {
-    //! Name of material
+    /// Name of material
     std::string mMatName;
     std::string mMatName;
 
 
-    //! List of semantic map commands, grouped by effect semantic name
+    /// List of semantic map commands, grouped by effect semantic name
     std::map<std::string, InputSemanticMapEntry> mMap;
     std::map<std::string, InputSemanticMapEntry> mMap;
 
 
-    //! For std::find
+    /// For std::find
     bool operator==(const std::string &s) const {
     bool operator==(const std::string &s) const {
         return s == mMatName;
         return s == mMatName;
     }
     }
 };
 };
 
 
-/** A reference to a mesh inside a node, including materials assigned to the various subgroups.
- * The ID refers to either a mesh or a controller which specifies the mesh
- */
+/// A reference to a mesh inside a node, including materials assigned to the various subgroups.
+/// The ID refers to either a mesh or a controller which specifies the mesh
 struct MeshInstance {
 struct MeshInstance {
     ///< ID of the mesh or controller to be instanced
     ///< ID of the mesh or controller to be instanced
     std::string mMeshOrController;
     std::string mMeshOrController;
@@ -224,25 +224,25 @@ struct MeshInstance {
     std::map<std::string, SemanticMappingTable> mMaterials;
     std::map<std::string, SemanticMappingTable> mMaterials;
 };
 };
 
 
-/** A reference to a camera inside a node*/
+/// A reference to a camera inside a node
 struct CameraInstance {
 struct CameraInstance {
     ///< ID of the camera
     ///< ID of the camera
     std::string mCamera;
     std::string mCamera;
 };
 };
 
 
-/** A reference to a light inside a node*/
+/// A reference to a light inside a node
 struct LightInstance {
 struct LightInstance {
     ///< ID of the camera
     ///< ID of the camera
     std::string mLight;
     std::string mLight;
 };
 };
 
 
-/** A reference to a node inside a node*/
+/// A reference to a node inside a node
 struct NodeInstance {
 struct NodeInstance {
     ///< ID of the node
     ///< ID of the node
     std::string mNode;
     std::string mNode;
 };
 };
 
 
-/** A node in a scene hierarchy */
+/// A node in a scene hierarchy
 struct Node {
 struct Node {
     std::string mName;
     std::string mName;
     std::string mID;
     std::string mID;
@@ -250,52 +250,53 @@ struct Node {
     Node *mParent;
     Node *mParent;
     std::vector<Node *> mChildren;
     std::vector<Node *> mChildren;
 
 
-    /** Operations in order to calculate the resulting transformation to parent. */
+    /// Operations in order to calculate the resulting transformation to parent.
     std::vector<Transform> mTransforms;
     std::vector<Transform> mTransforms;
 
 
-    /** Meshes at this node */
+    /// Meshes at this node
     std::vector<MeshInstance> mMeshes;
     std::vector<MeshInstance> mMeshes;
 
 
-    /** Lights at this node */
+    /// Lights at this node
     std::vector<LightInstance> mLights;
     std::vector<LightInstance> mLights;
 
 
-    /** Cameras at this node */
+    /// Cameras at this node
     std::vector<CameraInstance> mCameras;
     std::vector<CameraInstance> mCameras;
 
 
-    /** Node instances at this node */
+    /// Node instances at this node
     std::vector<NodeInstance> mNodeInstances;
     std::vector<NodeInstance> mNodeInstances;
 
 
-    /** Root-nodes: Name of primary camera, if any */
+    /// Root-nodes: Name of primary camera, if any
     std::string mPrimaryCamera;
     std::string mPrimaryCamera;
 
 
-    //! Constructor. Begin with a zero parent
+    /// Constructor. Begin with a zero parent
     Node() :
     Node() :
             mParent(nullptr) {
             mParent(nullptr) {
         // empty
         // empty
     }
     }
 
 
-    //! Destructor: delete all children subsequently
+    /// Destructor: delete all children subsequently
     ~Node() {
     ~Node() {
-        for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it)
+        for (std::vector<Node *>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) {
             delete *it;
             delete *it;
+        }
     }
     }
 };
 };
 
 
-/** Data source array: either floats or strings */
+/// Data source array: either floats or strings
 struct Data {
 struct Data {
     bool mIsStringArray;
     bool mIsStringArray;
     std::vector<ai_real> mValues;
     std::vector<ai_real> mValues;
     std::vector<std::string> mStrings;
     std::vector<std::string> mStrings;
 };
 };
 
 
-/** Accessor to a data array */
+/// Accessor to a data array
 struct Accessor {
 struct Accessor {
     size_t mCount; // in number of objects
     size_t mCount; // in number of objects
     size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
     size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
     size_t mOffset; // in number of values
     size_t mOffset; // in number of values
     size_t mStride; // Stride in number of values
     size_t mStride; // Stride in number of values
     std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
     std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
-    size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on.
+    size_t mSubOffset[4]; // Sub-offset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on.
             // For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
             // For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
     std::string mSource; // URL of the source array
     std::string mSource; // URL of the source array
     mutable const Data *mData; // Pointer to the source array, if resolved. nullptr else
     mutable const Data *mData; // Pointer to the source array, if resolved. nullptr else
@@ -310,12 +311,12 @@ struct Accessor {
     }
     }
 };
 };
 
 
-/** A single face in a mesh */
+/// A single face in a mesh
 struct Face {
 struct Face {
     std::vector<size_t> mIndices;
     std::vector<size_t> mIndices;
 };
 };
 
 
-/** An input channel for mesh data, referring to a single accessor */
+/// An input channel for mesh data, referring to a single accessor
 struct InputChannel {
 struct InputChannel {
     InputType mType; // Type of the data
     InputType mType; // Type of the data
     size_t mIndex; // Optional index, if multiple sets of the same data type are given
     size_t mIndex; // Optional index, if multiple sets of the same data type are given
@@ -331,18 +332,19 @@ struct InputChannel {
     }
     }
 };
 };
 
 
-/** Subset of a mesh with a certain material */
+/// Subset of a mesh with a certain material
 struct SubMesh {
 struct SubMesh {
     std::string mMaterial; ///< subgroup identifier
     std::string mMaterial; ///< subgroup identifier
-    size_t mNumFaces; ///< number of faces in this submesh
+    size_t mNumFaces; ///< number of faces in this sub-mesh
 };
 };
 
 
-/** Contains data for a single mesh */
+/// Contains data for a single mesh
 struct Mesh {
 struct Mesh {
     Mesh(const std::string &id) :
     Mesh(const std::string &id) :
             mId(id) {
             mId(id) {
-        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i)
+        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
             mNumUVComponents[i] = 2;
             mNumUVComponents[i] = 2;
+        }
     }
     }
 
 
     const std::string mId;
     const std::string mId;
@@ -373,11 +375,11 @@ struct Mesh {
     // necessary for bone weight assignment
     // necessary for bone weight assignment
     std::vector<size_t> mFacePosIndices;
     std::vector<size_t> mFacePosIndices;
 
 
-    // Submeshes in this mesh, each with a given material
+    // Sub-meshes in this mesh, each with a given material
     std::vector<SubMesh> mSubMeshes;
     std::vector<SubMesh> mSubMeshes;
 };
 };
 
 
-/** Which type of primitives the ReadPrimitives() function is going to read */
+/// Which type of primitives the ReadPrimitives() function is going to read
 enum PrimitiveType {
 enum PrimitiveType {
     Prim_Invalid,
     Prim_Invalid,
     Prim_Lines,
     Prim_Lines,
@@ -389,7 +391,7 @@ enum PrimitiveType {
     Prim_Polygon
     Prim_Polygon
 };
 };
 
 
-/** A skeleton controller to deform a mesh with the use of joints */
+/// A skeleton controller to deform a mesh with the use of joints
 struct Controller {
 struct Controller {
     // controller type
     // controller type
     ControllerType mType;
     ControllerType mType;
@@ -424,25 +426,25 @@ struct Controller {
     std::string mMorphWeight;
     std::string mMorphWeight;
 };
 };
 
 
-/** A collada material. Pretty much the only member is a reference to an effect. */
+/// A collada material. Pretty much the only member is a reference to an effect.
 struct Material {
 struct Material {
     std::string mName;
     std::string mName;
     std::string mEffect;
     std::string mEffect;
 };
 };
 
 
-/** Type of the effect param */
+/// Type of the effect param
 enum ParamType {
 enum ParamType {
     Param_Sampler,
     Param_Sampler,
     Param_Surface
     Param_Surface
 };
 };
 
 
-/** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */
+/// A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them
 struct EffectParam {
 struct EffectParam {
     ParamType mType;
     ParamType mType;
     std::string mReference; // to which other thing the param is referring to.
     std::string mReference; // to which other thing the param is referring to.
 };
 };
 
 
-/** Shading type supported by the standard effect spec of Collada */
+/// Shading type supported by the standard effect spec of Collada
 enum ShadeType {
 enum ShadeType {
     Shade_Invalid,
     Shade_Invalid,
     Shade_Constant,
     Shade_Constant,
@@ -451,7 +453,7 @@ enum ShadeType {
     Shade_Blinn
     Shade_Blinn
 };
 };
 
 
-/** Represents a texture sampler in collada */
+/// Represents a texture sampler in collada
 struct Sampler {
 struct Sampler {
     Sampler() :
     Sampler() :
             mWrapU(true),
             mWrapU(true),
@@ -463,77 +465,66 @@ struct Sampler {
             mWeighting(1.f),
             mWeighting(1.f),
             mMixWithPrevious(1.f) {}
             mMixWithPrevious(1.f) {}
 
 
-    /** Name of image reference
-     */
+    /// Name of image reference
     std::string mName;
     std::string mName;
 
 
-    /** Wrap U?
-     */
+    /// Wrap U?
     bool mWrapU;
     bool mWrapU;
 
 
-    /** Wrap V?
-     */
+    /// Wrap V?
     bool mWrapV;
     bool mWrapV;
 
 
-    /** Mirror U?
-     */
+    /// Mirror U?
     bool mMirrorU;
     bool mMirrorU;
 
 
-    /** Mirror V?
-     */
+    /// Mirror V?
     bool mMirrorV;
     bool mMirrorV;
 
 
-    /** Blend mode
-     */
+    /// Blend mode
     aiTextureOp mOp;
     aiTextureOp mOp;
 
 
-    /** UV transformation
-     */
+    /// UV transformation
     aiUVTransform mTransform;
     aiUVTransform mTransform;
 
 
-    /** Name of source UV channel
-     */
+    /// Name of source UV channel
     std::string mUVChannel;
     std::string mUVChannel;
 
 
-    /** Resolved UV channel index or UINT_MAX if not known
-     */
+    /// Resolved UV channel index or UINT_MAX if not known
     unsigned int mUVId;
     unsigned int mUVId;
 
 
     // OKINO/MAX3D extensions from here
     // OKINO/MAX3D extensions from here
     // -------------------------------------------------------
     // -------------------------------------------------------
 
 
-    /** Weighting factor
-     */
+    /// Weighting factor
     ai_real mWeighting;
     ai_real mWeighting;
 
 
-    /** Mixing factor from OKINO
-     */
+    /// Mixing factor from OKINO
     ai_real mMixWithPrevious;
     ai_real mMixWithPrevious;
 };
 };
 
 
-/** A collada effect. Can contain about anything according to the Collada spec,
-    but we limit our version to a reasonable subset. */
+/// A collada effect. Can contain about anything according to the Collada spec,
+/// but we limit our version to a reasonable subset.
 struct Effect {
 struct Effect {
-    // Shading mode
+    /// Shading mode
     ShadeType mShadeType;
     ShadeType mShadeType;
 
 
-    // Colors
+    /// Colors
     aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
     aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
             mTransparent, mReflective;
             mTransparent, mReflective;
 
 
-    // Textures
+    /// Textures
     Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
     Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
             mTexTransparent, mTexBump, mTexReflective;
             mTexTransparent, mTexBump, mTexReflective;
 
 
-    // Scalar factory
+    /// Scalar factory
     ai_real mShininess, mRefractIndex, mReflectivity;
     ai_real mShininess, mRefractIndex, mReflectivity;
     ai_real mTransparency;
     ai_real mTransparency;
     bool mHasTransparency;
     bool mHasTransparency;
     bool mRGBTransparency;
     bool mRGBTransparency;
     bool mInvertTransparency;
     bool mInvertTransparency;
 
 
-    // local params referring to each other by their SID
-    typedef std::map<std::string, Collada::EffectParam> ParamLibrary;
+    /// local params referring to each other by their SID
+    using ParamLibrary = std::map<std::string, Collada::EffectParam>;
     ParamLibrary mParams;
     ParamLibrary mParams;
 
 
     // MAX3D extensions
     // MAX3D extensions
@@ -561,65 +552,64 @@ struct Effect {
     }
     }
 };
 };
 
 
-/** An image, meaning texture */
+/// An image, meaning texture
 struct Image {
 struct Image {
     std::string mFileName;
     std::string mFileName;
 
 
-    /** Embedded image data */
+    /// Embedded image data
     std::vector<uint8_t> mImageData;
     std::vector<uint8_t> mImageData;
 
 
-    /** File format hint of embedded image data */
+    /// File format hint of embedded image data
     std::string mEmbeddedFormat;
     std::string mEmbeddedFormat;
 };
 };
 
 
-/** An animation channel. */
+/// An animation channel.
 struct AnimationChannel {
 struct AnimationChannel {
-    /** URL of the data to animate. Could be about anything, but we support only the
-     * "NodeID/TransformID.SubElement" notation
-     */
+    /// URL of the data to animate. Could be about anything, but we support only the
+    /// "NodeID/TransformID.SubElement" notation
     std::string mTarget;
     std::string mTarget;
 
 
-    /** Source URL of the time values. Collada calls them "input". Meh. */
+    /// Source URL of the time values. Collada calls them "input". Meh.
     std::string mSourceTimes;
     std::string mSourceTimes;
-    /** Source URL of the value values. Collada calls them "output". */
+    /// Source URL of the value values. Collada calls them "output".
     std::string mSourceValues;
     std::string mSourceValues;
-    /** Source URL of the IN_TANGENT semantic values. */
+    /// Source URL of the IN_TANGENT semantic values.
     std::string mInTanValues;
     std::string mInTanValues;
-    /** Source URL of the OUT_TANGENT semantic values. */
+    /// Source URL of the OUT_TANGENT semantic values.
     std::string mOutTanValues;
     std::string mOutTanValues;
-    /** Source URL of the INTERPOLATION semantic values. */
+    /// Source URL of the INTERPOLATION semantic values.
     std::string mInterpolationValues;
     std::string mInterpolationValues;
 };
 };
 
 
-/** An animation. Container for 0-x animation channels or 0-x animations */
+/// An animation. Container for 0-x animation channels or 0-x animations
 struct Animation {
 struct Animation {
-    /** Anim name */
+    /// Anim name
     std::string mName;
     std::string mName;
 
 
-    /** the animation channels, if any */
+    /// the animation channels, if any
     std::vector<AnimationChannel> mChannels;
     std::vector<AnimationChannel> mChannels;
 
 
-    /** the sub-animations, if any */
+    /// the sub-animations, if any
     std::vector<Animation *> mSubAnims;
     std::vector<Animation *> mSubAnims;
 
 
-    /** Destructor */
+    /// Destructor
     ~Animation() {
     ~Animation() {
-        for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
+        for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
             delete *it;
             delete *it;
+        }
     }
     }
 
 
-    /** Collect all channels in the animation hierarchy into a single channel list. */
+    /// Collect all channels in the animation hierarchy into a single channel list.
     void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) {
     void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) {
         channels.insert(channels.end(), mChannels.begin(), mChannels.end());
         channels.insert(channels.end(), mChannels.begin(), mChannels.end());
 
 
         for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
         for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
             Animation *pAnim = (*it);
             Animation *pAnim = (*it);
-
             pAnim->CollectChannelsRecursively(channels);
             pAnim->CollectChannelsRecursively(channels);
         }
         }
     }
     }
 
 
-    /** Combine all single-channel animations' channel into the same (parent) animation channel list. */
+    /// Combine all single-channel animations' channel into the same (parent) animation channel list.
     void CombineSingleChannelAnimations() {
     void CombineSingleChannelAnimations() {
         CombineSingleChannelAnimationsRecursively(this);
         CombineSingleChannelAnimationsRecursively(this);
     }
     }
@@ -658,9 +648,9 @@ struct Animation {
     }
     }
 };
 };
 
 
-/** Description of a collada animation channel which has been determined to affect the current node */
+/// Description of a collada animation channel which has been determined to affect the current node
 struct ChannelEntry {
 struct ChannelEntry {
-    const Collada::AnimationChannel *mChannel; ///> the source channel
+    const Collada::AnimationChannel *mChannel; ///< the source channel
     std::string mTargetId;
     std::string mTargetId;
     std::string mTransformId; // the ID of the transformation step of the node which is influenced
     std::string mTransformId; // the ID of the transformation step of the node which is influenced
     size_t mTransformIndex; // Index into the node's transform chain to apply the channel to
     size_t mTransformIndex; // Index into the node's transform chain to apply the channel to

+ 49 - 52
code/AssetLib/Collada/ColladaLoader.cpp

@@ -45,25 +45,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "ColladaLoader.h"
 #include "ColladaLoader.h"
 #include "ColladaParser.h"
 #include "ColladaParser.h"
-
 #include <assimp/ColladaMetaData.h>
 #include <assimp/ColladaMetaData.h>
+#include <assimp/CreateAnimMesh.h>
 #include <assimp/Defines.h>
 #include <assimp/Defines.h>
+#include <assimp/ParsingUtils.h>
+#include <assimp/SkeletonMeshBuilder.h>
+#include <assimp/ZipArchiveIOSystem.h>
 #include <assimp/anim.h>
 #include <assimp/anim.h>
+#include <assimp/fast_atof.h>
 #include <assimp/importerdesc.h>
 #include <assimp/importerdesc.h>
 #include <assimp/scene.h>
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Importer.hpp>
 #include <assimp/Importer.hpp>
 
 
-#include <assimp/CreateAnimMesh.h>
-#include <assimp/ParsingUtils.h>
-#include <assimp/SkeletonMeshBuilder.h>
-#include <assimp/ZipArchiveIOSystem.h>
-#include <assimp/fast_atof.h>
-
-#include "math.h"
-#include "time.h"
-#include <algorithm>
-#include <memory>
 #include <numeric>
 #include <numeric>
 
 
 namespace Assimp {
 namespace Assimp {
@@ -125,20 +119,17 @@ ColladaLoader::~ColladaLoader() {
 bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
 bool ColladaLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
     // check file extension
     // check file extension
     const std::string extension = GetExtension(pFile);
     const std::string extension = GetExtension(pFile);
-
-    bool readSig = checkSig && (pIOHandler != nullptr);
-
+    const bool readSig = checkSig && (pIOHandler != nullptr);
     if (!readSig) {
     if (!readSig) {
         if (extension == "dae" || extension == "zae") {
         if (extension == "dae" || extension == "zae") {
             return true;
             return true;
         }
         }
-    }
-
-    if (readSig) {
+    } else {
         // Look for a DAE file inside, but don't extract it
         // Look for a DAE file inside, but don't extract it
         ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
         ZipArchiveIOSystem zip_archive(pIOHandler, pFile);
-        if (zip_archive.isOpen())
+        if (zip_archive.isOpen()) {
             return !ColladaParser::ReadZaeManifest(zip_archive).empty();
             return !ColladaParser::ReadZaeManifest(zip_archive).empty();
+        }
     }
     }
 
 
     // XML - too generic, we need to open the file and search for typical keywords
     // XML - too generic, we need to open the file and search for typical keywords
@@ -337,13 +328,15 @@ void ColladaLoader::ResolveNodeInstances(const ColladaParser &pParser, const Col
 // Resolve UV channels
 // Resolve UV channels
 void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) {
 void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler &sampler, const Collada::SemanticMappingTable &table) {
     std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
     std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
-    if (it != table.mMap.end()) {
-        if (it->second.mType != Collada::IT_Texcoord) {
-            ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
-        }
+    if (it == table.mMap.end()) {
+        return;
+    }
 
 
-        sampler.mUVId = it->second.mSet;
+    if (it->second.mType != Collada::IT_Texcoord) {
+        ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
     }
     }
+
+    sampler.mUVId = it->second.mSet;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -390,7 +383,11 @@ void ColladaLoader::BuildLightsForNode(const ColladaParser &pParser, const Colla
                 if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) {
                 if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) {
                     // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
                     // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess ....
                     // epsilon chosen to be 0.1
                     // epsilon chosen to be 0.1
-                    out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) +
+                    float f = 1.0f;
+                    if ( 0.0f != srcLight->mFalloffExponent ) {
+                        f = 1.f / srcLight->mFalloffExponent;
+                    }
+                    out->mAngleOuterCone = std::acos(std::pow(0.1f, f)) +
                                            out->mAngleInnerCone;
                                            out->mAngleInnerCone;
                 } else {
                 } else {
                     out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle);
                     out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle);
@@ -585,10 +582,10 @@ void ColladaLoader::BuildMeshesForNode(const ColladaParser &pParser, const Colla
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Find mesh from either meshes or morph target meshes
 // Find mesh from either meshes or morph target meshes
 aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
 aiMesh *ColladaLoader::findMesh(const std::string &meshid) {
-    if ( meshid.empty()) {
+    if (meshid.empty()) {
         return nullptr;
         return nullptr;
     }
     }
-    
+
     for (unsigned int i = 0; i < mMeshes.size(); ++i) {
     for (unsigned int i = 0; i < mMeshes.size(); ++i) {
         if (std::string(mMeshes[i]->mName.data) == meshid) {
         if (std::string(mMeshes[i]->mName.data) == meshid) {
             return mMeshes[i];
             return mMeshes[i];
@@ -1251,7 +1248,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
 
 
             // time count and value count must match
             // time count and value count must match
             if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
             if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount)
-                throw DeadlyImportError(format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\".");
+                throw DeadlyImportError("Time count / value count mismatch in animation channel \"", e.mChannel->mTarget, "\".");
 
 
             if (e.mTimeAccessor->mCount > 0) {
             if (e.mTimeAccessor->mCount > 0) {
                 // find bounding times
                 // find bounding times
@@ -1377,9 +1374,9 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
                 double time = double(mat.d4); // remember? time is stored in mat.d4
                 double time = double(mat.d4); // remember? time is stored in mat.d4
                 mat.d4 = 1.0f;
                 mat.d4 = 1.0f;
 
 
-                dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds ;
-                dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds ;
-                dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds ;
+                dstAnim->mPositionKeys[a].mTime = time * kMillisecondsFromSeconds;
+                dstAnim->mRotationKeys[a].mTime = time * kMillisecondsFromSeconds;
+                dstAnim->mScalingKeys[a].mTime = time * kMillisecondsFromSeconds;
                 mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
                 mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue);
             }
             }
 
 
@@ -1400,7 +1397,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
                 if (e.mTargetId.find("morph-weights") != std::string::npos)
                 if (e.mTargetId.find("morph-weights") != std::string::npos)
                     morphChannels.push_back(e);
                     morphChannels.push_back(e);
             }
             }
-            if (!morphChannels.empty() ) {
+            if (!morphChannels.empty()) {
                 // either 1) morph weight animation count should contain morph target count channels
                 // either 1) morph weight animation count should contain morph target count channels
                 // or     2) one channel with morph target count arrays
                 // or     2) one channel with morph target count arrays
                 // assume first
                 // assume first
@@ -1434,8 +1431,8 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
                     morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()];
                     morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()];
                     morphAnim->mKeys[key].mWeights = new double[morphChannels.size()];
                     morphAnim->mKeys[key].mWeights = new double[morphChannels.size()];
 
 
-                    morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds ;
-                    for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex ) {
+                    morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime * kMillisecondsFromSeconds;
+                    for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); ++valueIndex) {
                         morphAnim->mKeys[key].mValues[valueIndex] = valueIndex;
                         morphAnim->mKeys[key].mValues[valueIndex] = valueIndex;
                         morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex);
                         morphAnim->mKeys[key].mWeights[valueIndex] = getWeightAtKey(morphTimeValues, key, valueIndex);
                     }
                     }
@@ -1468,7 +1465,7 @@ void ColladaLoader::CreateAnimation(aiScene *pScene, const ColladaParser &pParse
         for (size_t a = 0; a < morphAnims.size(); ++a) {
         for (size_t a = 0; a < morphAnims.size(); ++a) {
             anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime);
             anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime);
         }
         }
-        anim->mTicksPerSecond = 1;
+        anim->mTicksPerSecond = 1000.0;
         mAnims.push_back(anim);
         mAnims.push_back(anim);
     }
     }
 }
 }
@@ -1552,23 +1549,23 @@ void ColladaLoader::FillMaterials(const ColladaParser &pParser, aiScene * /*pSce
             shadeMode = aiShadingMode_Flat;
             shadeMode = aiShadingMode_Flat;
         } else {
         } else {
             switch (effect.mShadeType) {
             switch (effect.mShadeType) {
-                case Collada::Shade_Constant:
-                    shadeMode = aiShadingMode_NoShading;
-                    break;
-                case Collada::Shade_Lambert:
-                    shadeMode = aiShadingMode_Gouraud;
-                    break;
-                case Collada::Shade_Blinn:
-                    shadeMode = aiShadingMode_Blinn;
-                    break;
-                case Collada::Shade_Phong:
-                    shadeMode = aiShadingMode_Phong;
-                    break;
+            case Collada::Shade_Constant:
+                shadeMode = aiShadingMode_NoShading;
+                break;
+            case Collada::Shade_Lambert:
+                shadeMode = aiShadingMode_Gouraud;
+                break;
+            case Collada::Shade_Blinn:
+                shadeMode = aiShadingMode_Blinn;
+                break;
+            case Collada::Shade_Phong:
+                shadeMode = aiShadingMode_Phong;
+                break;
 
 
-                default:
-                    ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading");
-                    shadeMode = aiShadingMode_Gouraud;
-                    break;
+            default:
+                ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading");
+                shadeMode = aiShadingMode_Gouraud;
+                break;
             }
             }
         }
         }
         mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
         mat.AddProperty<int>(&shadeMode, 1, AI_MATKEY_SHADING_MODEL);
@@ -1658,7 +1655,7 @@ void ColladaLoader::BuildMaterials(ColladaParser &pParser, aiScene * /*pScene*/)
         const Collada::Material &material = matIt->second;
         const Collada::Material &material = matIt->second;
         // a material is only a reference to an effect
         // a material is only a reference to an effect
         ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find(material.mEffect);
         ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find(material.mEffect);
-        if (effIt == pParser.mEffectLibrary.end())
+        if (effIt == pParser.mEffectLibrary.end())  
             continue;
             continue;
         Collada::Effect &effect = effIt->second;
         Collada::Effect &effect = effIt->second;
 
 
@@ -1734,7 +1731,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser &pParse
         // and add this texture to the list
         // and add this texture to the list
         mTextures.push_back(tex);
         mTextures.push_back(tex);
         return result;
         return result;
-    } 
+    }
 
 
     if (imIt->second.mFileName.empty()) {
     if (imIt->second.mFileName.empty()) {
         throw DeadlyImportError("Collada: Invalid texture, no data or file reference given");
         throw DeadlyImportError("Collada: Invalid texture, no data or file reference given");

Dosya farkı çok büyük olduğundan ihmal edildi
+ 890 - 1320
code/AssetLib/Collada/ColladaParser.cpp


+ 66 - 111
code/AssetLib/Collada/ColladaParser.h

@@ -4,7 +4,6 @@
 
 
  Copyright (c) 2006-2020, assimp team
  Copyright (c) 2006-2020, 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,
@@ -50,9 +49,12 @@
 #include "ColladaHelper.h"
 #include "ColladaHelper.h"
 #include <assimp/TinyFormatter.h>
 #include <assimp/TinyFormatter.h>
 #include <assimp/ai_assert.h>
 #include <assimp/ai_assert.h>
-#include <assimp/irrXMLWrapper.h>
+#include <assimp/XmlParser.h>
+
+#include <map>
 
 
 namespace Assimp {
 namespace Assimp {
+
 class ZipArchiveIOSystem;
 class ZipArchiveIOSystem;
 
 
 // ------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------
@@ -81,25 +83,25 @@ protected:
     static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
     static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
 
 
     /** Reads the contents of the file */
     /** Reads the contents of the file */
-    void ReadContents();
+    void ReadContents(XmlNode &node);
 
 
     /** Reads the structure of the file */
     /** Reads the structure of the file */
-    void ReadStructure();
+    void ReadStructure(XmlNode &node);
 
 
     /** Reads asset information such as coordinate system information and legal blah */
     /** Reads asset information such as coordinate system information and legal blah */
-    void ReadAssetInfo();
+    void ReadAssetInfo(XmlNode &node);
 
 
     /** Reads contributor information such as author and legal blah */
     /** Reads contributor information such as author and legal blah */
-    void ReadContributorInfo();
+    void ReadContributorInfo(XmlNode &node);
 
 
     /** Reads generic metadata into provided map and renames keys for Assimp */
     /** Reads generic metadata into provided map and renames keys for Assimp */
-    void ReadMetaDataItem(StringMetaData &metadata);
+    void ReadMetaDataItem(XmlNode &node, StringMetaData &metadata);
 
 
     /** Reads the animation library */
     /** Reads the animation library */
-    void ReadAnimationLibrary();
+    void ReadAnimationLibrary(XmlNode &node);
 
 
     /** Reads the animation clip library */
     /** Reads the animation clip library */
-    void ReadAnimationClipLibrary();
+    void ReadAnimationClipLibrary(XmlNode &node);
 
 
     /** Unwrap controllers dependency hierarchy */
     /** Unwrap controllers dependency hierarchy */
     void PostProcessControllers();
     void PostProcessControllers();
@@ -108,103 +110,103 @@ protected:
     void PostProcessRootAnimations();
     void PostProcessRootAnimations();
 
 
     /** Reads an animation into the given parent structure */
     /** Reads an animation into the given parent structure */
-    void ReadAnimation(Collada::Animation *pParent);
+    void ReadAnimation(XmlNode &node, Collada::Animation *pParent);
 
 
     /** Reads an animation sampler into the given anim channel */
     /** Reads an animation sampler into the given anim channel */
-    void ReadAnimationSampler(Collada::AnimationChannel &pChannel);
+    void ReadAnimationSampler(XmlNode &node, Collada::AnimationChannel &pChannel);
 
 
     /** Reads the skeleton controller library */
     /** Reads the skeleton controller library */
-    void ReadControllerLibrary();
+    void ReadControllerLibrary(XmlNode &node);
 
 
     /** Reads a controller into the given mesh structure */
     /** Reads a controller into the given mesh structure */
-    void ReadController(Collada::Controller &pController);
+    void ReadController(XmlNode &node, Collada::Controller &pController);
 
 
     /** Reads the joint definitions for the given controller */
     /** Reads the joint definitions for the given controller */
-    void ReadControllerJoints(Collada::Controller &pController);
+    void ReadControllerJoints(XmlNode &node, Collada::Controller &pController);
 
 
     /** Reads the joint weights for the given controller */
     /** Reads the joint weights for the given controller */
-    void ReadControllerWeights(Collada::Controller &pController);
+    void ReadControllerWeights(XmlNode &node, Collada::Controller &pController);
 
 
     /** Reads the image library contents */
     /** Reads the image library contents */
-    void ReadImageLibrary();
+    void ReadImageLibrary(XmlNode &node);
 
 
     /** Reads an image entry into the given image */
     /** Reads an image entry into the given image */
-    void ReadImage(Collada::Image &pImage);
+    void ReadImage(XmlNode &node, Collada::Image &pImage);
 
 
     /** Reads the material library */
     /** Reads the material library */
-    void ReadMaterialLibrary();
+    void ReadMaterialLibrary(XmlNode &node);
 
 
     /** Reads a material entry into the given material */
     /** Reads a material entry into the given material */
-    void ReadMaterial(Collada::Material &pMaterial);
+    void ReadMaterial(XmlNode &node, Collada::Material &pMaterial);
 
 
     /** Reads the camera library */
     /** Reads the camera library */
-    void ReadCameraLibrary();
+    void ReadCameraLibrary(XmlNode &node);
 
 
     /** Reads a camera entry into the given camera */
     /** Reads a camera entry into the given camera */
-    void ReadCamera(Collada::Camera &pCamera);
+    void ReadCamera(XmlNode &node, Collada::Camera &pCamera);
 
 
     /** Reads the light library */
     /** Reads the light library */
-    void ReadLightLibrary();
+    void ReadLightLibrary(XmlNode &node);
 
 
     /** Reads a light entry into the given light */
     /** Reads a light entry into the given light */
-    void ReadLight(Collada::Light &pLight);
+    void ReadLight(XmlNode &node, Collada::Light &pLight);
 
 
     /** Reads the effect library */
     /** Reads the effect library */
-    void ReadEffectLibrary();
+    void ReadEffectLibrary(XmlNode &node);
 
 
     /** Reads an effect entry into the given effect*/
     /** Reads an effect entry into the given effect*/
-    void ReadEffect(Collada::Effect &pEffect);
+    void ReadEffect(XmlNode &node, Collada::Effect &pEffect);
 
 
     /** Reads an COMMON effect profile */
     /** Reads an COMMON effect profile */
-    void ReadEffectProfileCommon(Collada::Effect &pEffect);
+    void ReadEffectProfileCommon(XmlNode &node, Collada::Effect &pEffect);
 
 
     /** Read sampler properties */
     /** Read sampler properties */
-    void ReadSamplerProperties(Collada::Sampler &pSampler);
+    void ReadSamplerProperties(XmlNode &node, Collada::Sampler &pSampler);
 
 
     /** Reads an effect entry containing a color or a texture defining that color */
     /** Reads an effect entry containing a color or a texture defining that color */
-    void ReadEffectColor(aiColor4D &pColor, Collada::Sampler &pSampler);
+    void ReadEffectColor(XmlNode &node, aiColor4D &pColor, Collada::Sampler &pSampler);
 
 
     /** Reads an effect entry containing a float */
     /** Reads an effect entry containing a float */
-    void ReadEffectFloat(ai_real &pFloat);
+    void ReadEffectFloat(XmlNode &node, ai_real &pFloat);
 
 
     /** Reads an effect parameter specification of any kind */
     /** Reads an effect parameter specification of any kind */
-    void ReadEffectParam(Collada::EffectParam &pParam);
+    void ReadEffectParam(XmlNode &node, Collada::EffectParam &pParam);
 
 
     /** Reads the geometry library contents */
     /** Reads the geometry library contents */
-    void ReadGeometryLibrary();
+    void ReadGeometryLibrary(XmlNode &node);
 
 
     /** Reads a geometry from the geometry library. */
     /** Reads a geometry from the geometry library. */
-    void ReadGeometry(Collada::Mesh &pMesh);
+    void ReadGeometry(XmlNode &node, Collada::Mesh &pMesh);
 
 
     /** Reads a mesh from the geometry library */
     /** Reads a mesh from the geometry library */
-    void ReadMesh(Collada::Mesh &pMesh);
+    void ReadMesh(XmlNode &node, Collada::Mesh &pMesh);
 
 
     /** Reads a source element - a combination of raw data and an accessor defining
     /** Reads a source element - a combination of raw data and an accessor defining
          * things that should not be redefinable. Yes, that's another rant.
          * things that should not be redefinable. Yes, that's another rant.
          */
          */
-    void ReadSource();
+    void ReadSource(XmlNode &node);
 
 
     /** Reads a data array holding a number of elements, and stores it in the global library.
     /** Reads a data array holding a number of elements, and stores it in the global library.
          * Currently supported are array of floats and arrays of strings.
          * Currently supported are array of floats and arrays of strings.
          */
          */
-    void ReadDataArray();
+    void ReadDataArray(XmlNode &node);
 
 
     /** Reads an accessor and stores it in the global library under the given ID -
     /** Reads an accessor and stores it in the global library under the given ID -
          * accessors use the ID of the parent <source> element
          * accessors use the ID of the parent <source> element
          */
          */
-    void ReadAccessor(const std::string &pID);
+    void ReadAccessor(XmlNode &node, const std::string &pID);
 
 
     /** Reads input declarations of per-vertex mesh data into the given mesh */
     /** Reads input declarations of per-vertex mesh data into the given mesh */
-    void ReadVertexData(Collada::Mesh &pMesh);
+    void ReadVertexData(XmlNode &node, Collada::Mesh &pMesh);
 
 
     /** Reads input declarations of per-index mesh data into the given mesh */
     /** Reads input declarations of per-index mesh data into the given mesh */
-    void ReadIndexData(Collada::Mesh &pMesh);
+    void ReadIndexData(XmlNode &node, Collada::Mesh &pMesh);
 
 
     /** Reads a single input channel element and stores it in the given array, if valid */
     /** Reads a single input channel element and stores it in the given array, if valid */
-    void ReadInputChannel(std::vector<Collada::InputChannel> &poChannels);
+    void ReadInputChannel(XmlNode &node, std::vector<Collada::InputChannel> &poChannels);
 
 
     /** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
     /** Reads a <p> primitive index list and assembles the mesh data into the given mesh */
-    size_t ReadPrimitives(Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
+    size_t ReadPrimitives(XmlNode &node, Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
             size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType);
             size_t pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType);
 
 
     /** Copies the data for a single primitive into the mesh, based on the InputChannels */
     /** Copies the data for a single primitive into the mesh, based on the InputChannels */
@@ -220,68 +222,27 @@ protected:
     void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh);
     void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh);
 
 
     /** Reads the library of node hierarchies and scene parts */
     /** Reads the library of node hierarchies and scene parts */
-    void ReadSceneLibrary();
+    void ReadSceneLibrary(XmlNode &node);
 
 
     /** Reads a scene node's contents including children and stores it in the given node */
     /** Reads a scene node's contents including children and stores it in the given node */
-    void ReadSceneNode(Collada::Node *pNode);
+    void ReadSceneNode(XmlNode &node, Collada::Node *pNode);
 
 
     /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
     /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */
-    void ReadNodeTransformation(Collada::Node *pNode, Collada::TransformType pType);
+    void ReadNodeTransformation(XmlNode &node, Collada::Node *pNode, Collada::TransformType pType);
 
 
     /** Reads a mesh reference in a node and adds it to the node's mesh list */
     /** Reads a mesh reference in a node and adds it to the node's mesh list */
-    void ReadNodeGeometry(Collada::Node *pNode);
+    void ReadNodeGeometry(XmlNode &node, Collada::Node *pNode);
 
 
     /** Reads the collada scene */
     /** Reads the collada scene */
-    void ReadScene();
+    void ReadScene(XmlNode &node);
 
 
     // Processes bind_vertex_input and bind elements
     // Processes bind_vertex_input and bind elements
-    void ReadMaterialVertexInputBinding(Collada::SemanticMappingTable &tbl);
+    void ReadMaterialVertexInputBinding(XmlNode &node, Collada::SemanticMappingTable &tbl);
 
 
     /** Reads embedded textures from a ZAE archive*/
     /** Reads embedded textures from a ZAE archive*/
     void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
     void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
 
 
 protected:
 protected:
-    /** Aborts the file reading with an exception */
-    AI_WONT_RETURN void ThrowException(const std::string &pError) const AI_WONT_RETURN_SUFFIX;
-    void ReportWarning(const char *msg, ...);
-
-    /** Skips all data until the end node of the current element */
-    void SkipElement();
-
-    /** Skips all data until the end node of the given element */
-    void SkipElement(const char *pElement);
-
-    /** Compares the current xml element name to the given string and returns true if equal */
-    bool IsElement(const char *pName) const;
-
-    /** Tests for the opening tag of the given element, throws an exception if not found */
-    void TestOpening(const char *pName);
-
-    /** Tests for the closing tag of the given element, throws an exception if not found */
-    void TestClosing(const char *pName);
-
-    /** Checks the present element for the presence of the attribute, returns its index
-         or throws an exception if not found */
-    int GetAttribute(const char *pAttr) const;
-
-    /** Returns the index of the named attribute or -1 if not found. Does not throw,
-         therefore useful for optional attributes */
-    int TestAttribute(const char *pAttr) const;
-
-    /** Reads the text contents of an element, throws an exception if not given.
-         Skips leading whitespace. */
-    const char *GetTextContent();
-
-    /** Reads the text contents of an element, returns nullptr if not given.
-         Skips leading whitespace. */
-    const char *TestTextContent();
-
-    /** Reads a single bool from current text content */
-    bool ReadBoolFromTextContent();
-
-    /** Reads a single float from current text content */
-    ai_real ReadFloatFromTextContent();
-
     /** Calculates the resulting transformation from all the given transform steps */
     /** Calculates the resulting transformation from all the given transform steps */
     aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const;
     aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const;
 
 
@@ -293,59 +254,59 @@ protected:
     const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const;
     const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const;
 
 
 protected:
 protected:
-    /** Filename, for a verbose error message */
+    // Filename, for a verbose error message
     std::string mFileName;
     std::string mFileName;
 
 
-    /** XML reader, member for everyday use */
-    irr::io::IrrXMLReader *mReader;
+    // XML reader, member for everyday use
+    XmlParser mXmlParser;
 
 
     /** All data arrays found in the file by ID. Might be referred to by actually
     /** All data arrays found in the file by ID. Might be referred to by actually
          everyone. Collada, you are a steaming pile of indirection. */
          everyone. Collada, you are a steaming pile of indirection. */
-    typedef std::map<std::string, Collada::Data> DataLibrary;
+    using DataLibrary = std::map<std::string, Collada::Data> ;
     DataLibrary mDataLibrary;
     DataLibrary mDataLibrary;
 
 
     /** Same for accessors which define how the data in a data array is accessed. */
     /** Same for accessors which define how the data in a data array is accessed. */
-    typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
+    using AccessorLibrary = std::map<std::string, Collada::Accessor> ;
     AccessorLibrary mAccessorLibrary;
     AccessorLibrary mAccessorLibrary;
 
 
     /** Mesh library: mesh by ID */
     /** Mesh library: mesh by ID */
-    typedef std::map<std::string, Collada::Mesh *> MeshLibrary;
+    using MeshLibrary = std::map<std::string, Collada::Mesh *>;
     MeshLibrary mMeshLibrary;
     MeshLibrary mMeshLibrary;
 
 
     /** node library: root node of the hierarchy part by ID */
     /** node library: root node of the hierarchy part by ID */
-    typedef std::map<std::string, Collada::Node *> NodeLibrary;
+    using NodeLibrary = std::map<std::string, Collada::Node *>;
     NodeLibrary mNodeLibrary;
     NodeLibrary mNodeLibrary;
 
 
     /** Image library: stores texture properties by ID */
     /** Image library: stores texture properties by ID */
-    typedef std::map<std::string, Collada::Image> ImageLibrary;
+    using ImageLibrary = std::map<std::string, Collada::Image> ;
     ImageLibrary mImageLibrary;
     ImageLibrary mImageLibrary;
 
 
     /** Effect library: surface attributes by ID */
     /** Effect library: surface attributes by ID */
-    typedef std::map<std::string, Collada::Effect> EffectLibrary;
+    using EffectLibrary = std::map<std::string, Collada::Effect> ;
     EffectLibrary mEffectLibrary;
     EffectLibrary mEffectLibrary;
 
 
     /** Material library: surface material by ID */
     /** Material library: surface material by ID */
-    typedef std::map<std::string, Collada::Material> MaterialLibrary;
+    using MaterialLibrary = std::map<std::string, Collada::Material> ;
     MaterialLibrary mMaterialLibrary;
     MaterialLibrary mMaterialLibrary;
 
 
     /** Light library: surface light by ID */
     /** Light library: surface light by ID */
-    typedef std::map<std::string, Collada::Light> LightLibrary;
+    using LightLibrary = std::map<std::string, Collada::Light> ;
     LightLibrary mLightLibrary;
     LightLibrary mLightLibrary;
 
 
     /** Camera library: surface material by ID */
     /** Camera library: surface material by ID */
-    typedef std::map<std::string, Collada::Camera> CameraLibrary;
+    using CameraLibrary = std::map<std::string, Collada::Camera> ;
     CameraLibrary mCameraLibrary;
     CameraLibrary mCameraLibrary;
 
 
     /** Controller library: joint controllers by ID */
     /** Controller library: joint controllers by ID */
-    typedef std::map<std::string, Collada::Controller> ControllerLibrary;
+    using ControllerLibrary = std::map<std::string, Collada::Controller> ;
     ControllerLibrary mControllerLibrary;
     ControllerLibrary mControllerLibrary;
 
 
     /** Animation library: animation references by ID */
     /** Animation library: animation references by ID */
-    typedef std::map<std::string, Collada::Animation *> AnimationLibrary;
+    using AnimationLibrary = std::map<std::string, Collada::Animation *> ;
     AnimationLibrary mAnimationLibrary;
     AnimationLibrary mAnimationLibrary;
 
 
     /** Animation clip library: clip animation references by ID */
     /** Animation clip library: clip animation references by ID */
-    typedef std::vector<std::pair<std::string, std::vector<std::string>>> AnimationClipLibrary;
+    using AnimationClipLibrary = std::vector<std::pair<std::string, std::vector<std::string>>> ;
     AnimationClipLibrary mAnimationClipLibrary;
     AnimationClipLibrary mAnimationClipLibrary;
 
 
     /** Pointer to the root node. Don't delete, it just points to one of
     /** Pointer to the root node. Don't delete, it just points to one of
@@ -370,20 +331,14 @@ protected:
     Collada::FormatVersion mFormat;
     Collada::FormatVersion mFormat;
 };
 };
 
 
-// ------------------------------------------------------------------------------------------------
-// Check for element match
-inline bool ColladaParser::IsElement(const char *pName) const {
-    ai_assert(mReader->getNodeType() == irr::io::EXN_ELEMENT);
-    return ::strcmp(mReader->getNodeName(), pName) == 0;
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Finds the item in the given library by its reference, throws if not found
 // Finds the item in the given library by its reference, throws if not found
 template <typename Type>
 template <typename Type>
 const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
 const Type &ColladaParser::ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const {
     typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
     typename std::map<std::string, Type>::const_iterator it = pLibrary.find(pURL);
-    if (it == pLibrary.end())
-        ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\".");
+    if (it == pLibrary.end()) {
+        throw DeadlyImportError("Unable to resolve library reference \"", pURL, "\".");
+    }
     return it->second;
     return it->second;
 }
 }
 
 

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

@@ -152,7 +152,7 @@ void DXFImporter::InternReadFile( const std::string& filename, aiScene* pScene,
 
 
     // Check whether we can read the file
     // Check whether we can read the file
     if( file.get() == nullptr ) {
     if( file.get() == nullptr ) {
-        throw DeadlyImportError( "Failed to open DXF file " + filename + "");
+        throw DeadlyImportError( "Failed to open DXF file ", filename, "");
     }
     }
 
 
     // Check whether this is a binary DXF file - we can't read binary DXF files :-(
     // Check whether this is a binary DXF file - we can't read binary DXF files :-(

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

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Exceptional.h>
 #include <assimp/Exceptional.h>
 #include <assimp/ByteSwapper.h>
 #include <assimp/ByteSwapper.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/DefaultLogger.hpp>
+#include <assimp/StringUtils.h>
 
 
 namespace Assimp {
 namespace Assimp {
 namespace FBX {
 namespace FBX {
@@ -126,7 +127,7 @@ namespace {
 AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX;
 AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX;
 AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset)
 AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset)
 {
 {
-    throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
+    throw DeadlyImportError("FBX-Tokenize", Util::GetOffsetText(offset), message);
 }
 }
 
 
 
 
@@ -374,6 +375,11 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
 
 
     // now come the individual properties
     // now come the individual properties
     const char* begin_cursor = cursor;
     const char* begin_cursor = cursor;
+
+    if ((begin_cursor + prop_length) > end) {
+        TokenizeError("property length out of bounds reading length ", input, cursor);
+    }
+
     for (unsigned int i = 0; i < prop_count; ++i) {
     for (unsigned int i = 0; i < prop_count; ++i) {
         ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
         ReadData(sbeg, send, input, cursor, begin_cursor + prop_length);
 
 
@@ -456,10 +462,20 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
 	ASSIMP_LOG_DEBUG_F("FBX version: ", version);
 	ASSIMP_LOG_DEBUG_F("FBX version: ", version);
 	const bool is64bits = version >= 7500;
 	const bool is64bits = version >= 7500;
     const char *end = input + length;
     const char *end = input + length;
-    while (cursor < end ) {
-		if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
-            break;
+    try
+    {
+        while (cursor < end ) {
+		    if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
+                break;
+            }
+        }
+    }
+    catch (const DeadlyImportError& e)
+    {
+        if (!is64bits && (length > std::numeric_limits<std::uint32_t>::max())) {
+            throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (", to_string(version), ") of the FBX format. (", e.what(), ")");
         }
         }
+        throw;
     }
     }
 }
 }
 
 

+ 158 - 125
code/AssetLib/FBX/FBXConverter.cpp

@@ -79,7 +79,7 @@ using namespace Util;
 
 
 #define MAGIC_NODE_TAG "_$AssimpFbx$"
 #define MAGIC_NODE_TAG "_$AssimpFbx$"
 
 
-#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
+#define CONVERT_FBX_TIME(time) (static_cast<double>(time) * 1000.0 / 46186158000LL)
 
 
 FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBones) :
 FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBones) :
         defaultMaterialIndex(),
         defaultMaterialIndex(),
@@ -185,6 +185,17 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
     return unique_name;
     return unique_name;
 }
 }
 
 
+/// 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.
+struct FBXConverter::PotentialNode
+{
+    PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
+    PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
+    aiNode* operator->() { return mNode; }
+    std::unique_ptr<aiNode> mOwnership;
+    aiNode* mNode;
+};
+
 /// todo: pre-build node hierarchy
 /// todo: pre-build node hierarchy
 /// todo: get bone from stack
 /// todo: get bone from stack
 /// todo: make map of aiBone* to aiNode*
 /// todo: make map of aiBone* to aiNode*
@@ -192,137 +203,129 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
 void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
 void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
     const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
     const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
 
 
-    std::vector<aiNode *> nodes;
+    std::vector<PotentialNode> nodes;
     nodes.reserve(conns.size());
     nodes.reserve(conns.size());
 
 
-    std::vector<aiNode *> nodes_chain;
-    std::vector<aiNode *> post_nodes_chain;
-
-    try {
-        for (const Connection *con : conns) {
-            // ignore object-property links
-            if (con->PropertyName().length()) {
-                // really important we document why this is ignored.
-                FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
-                continue; //?
-            }
+    std::vector<PotentialNode> nodes_chain;
+    std::vector<PotentialNode> post_nodes_chain;
 
 
-            // convert connection source object into Object base class
-            const Object *const object = con->SourceObject();
-            if (nullptr == object) {
-                FBXImporter::LogError("failed to convert source object for Model link");
-                continue;
-            }
+    for (const Connection *con : conns) {
+        // ignore object-property links
+        if (con->PropertyName().length()) {
+            // really important we document why this is ignored.
+            FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
+            continue; //?
+        }
 
 
-            // FBX Model::Cube, Model::Bone001, etc elements
-            // This detects if we can cast the object into this model structure.
-            const Model *const model = dynamic_cast<const Model *>(object);
+        // convert connection source object into Object base class
+        const Object *const object = con->SourceObject();
+        if (nullptr == object) {
+            FBXImporter::LogError("failed to convert source object for Model link");
+            continue;
+        }
 
 
-            if (nullptr != model) {
-                nodes_chain.clear();
-                post_nodes_chain.clear();
+        // FBX Model::Cube, Model::Bone001, etc elements
+        // This detects if we can cast the object into this model structure.
+        const Model *const model = dynamic_cast<const Model *>(object);
 
 
-                aiMatrix4x4 new_abs_transform = parent->mTransformation;
-                std::string node_name = FixNodeName(model->Name());
-                // even though there is only a single input node, the design of
-                // assimp (or rather: the complicated transformation chain that
-                // is employed by fbx) means that we may need multiple aiNode's
-                // to represent a fbx node's transformation.
+        if (nullptr != model) {
+            nodes_chain.clear();
+            post_nodes_chain.clear();
 
 
-                // generate node transforms - this includes pivot data
-                // if need_additional_node is true then you t
-                const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
+            aiMatrix4x4 new_abs_transform = parent->mTransformation;
+            std::string node_name = FixNodeName(model->Name());
+            // even though there is only a single input node, the design of
+            // assimp (or rather: the complicated transformation chain that
+            // is employed by fbx) means that we may need multiple aiNode's
+            // to represent a fbx node's transformation.
 
 
-                // assert that for the current node we must have at least a single transform
-                ai_assert(nodes_chain.size());
+            // generate node transforms - this includes pivot data
+            // if need_additional_node is true then you t
+            const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
 
 
-                if (need_additional_node) {
-                    nodes_chain.push_back(new aiNode(node_name));
-                }
+            // assert that for the current node we must have at least a single transform
+            ai_assert(nodes_chain.size());
 
 
-                //setup metadata on newest node
-                SetupNodeMetadata(*model, *nodes_chain.back());
-
-                // link all nodes in a row
-                aiNode *last_parent = parent;
-                for (aiNode *child : nodes_chain) {
-                    ai_assert(child);
+            if (need_additional_node) {
+                nodes_chain.emplace_back(PotentialNode(node_name));
+            }
 
 
-                    if (last_parent != parent) {
-                        last_parent->mNumChildren = 1;
-                        last_parent->mChildren = new aiNode *[1];
-                        last_parent->mChildren[0] = child;
-                    }
+            //setup metadata on newest node
+            SetupNodeMetadata(*model, *nodes_chain.back().mNode);
 
 
-                    child->mParent = last_parent;
-                    last_parent = child;
+            // link all nodes in a row
+            aiNode *last_parent = parent;
+            for (PotentialNode& child : nodes_chain) {
+                ai_assert(child.mNode);
 
 
-                    new_abs_transform *= child->mTransformation;
+                if (last_parent != parent) {
+                    last_parent->mNumChildren = 1;
+                    last_parent->mChildren = new aiNode *[1];
+                    last_parent->mChildren[0] = child.mOwnership.release();
                 }
                 }
 
 
-                // attach geometry
-                ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform);
+                child->mParent = last_parent;
+                last_parent = child.mNode;
 
 
-                // check if there will be any child nodes
-                const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
+                new_abs_transform *= child->mTransformation;
+            }
 
 
-                // if so, link the geometric transform inverse nodes
-                // before we attach any child nodes
-                if (child_conns.size()) {
-                    for (aiNode *postnode : post_nodes_chain) {
-                        ai_assert(postnode);
+            // attach geometry
+            ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform);
 
 
-                        if (last_parent != parent) {
-                            last_parent->mNumChildren = 1;
-                            last_parent->mChildren = new aiNode *[1];
-                            last_parent->mChildren[0] = postnode;
-                        }
+            // check if there will be any child nodes
+            const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
 
 
-                        postnode->mParent = last_parent;
-                        last_parent = postnode;
+            // if so, link the geometric transform inverse nodes
+            // before we attach any child nodes
+            if (child_conns.size()) {
+                for (PotentialNode& postnode : post_nodes_chain) {
+                    ai_assert(postnode.mNode);
 
 
-                        new_abs_transform *= postnode->mTransformation;
+                    if (last_parent != parent) {
+                        last_parent->mNumChildren = 1;
+                        last_parent->mChildren = new aiNode *[1];
+                        last_parent->mChildren[0] = postnode.mOwnership.release();
                     }
                     }
-                } else {
-                    // free the nodes we allocated as we don't need them
-                    Util::delete_fun<aiNode> deleter;
-                    std::for_each(
-                            post_nodes_chain.begin(),
-                            post_nodes_chain.end(),
-                            deleter);
-                }
 
 
-                // recursion call - child nodes
-                ConvertNodes(model->ID(), last_parent, root_node);
+                    postnode->mParent = last_parent;
+                    last_parent = postnode.mNode;
 
 
-                if (doc.Settings().readLights) {
-                    ConvertLights(*model, node_name);
+                    new_abs_transform *= postnode->mTransformation;
                 }
                 }
+            } else {
+                // free the nodes we allocated as we don't need them
+                post_nodes_chain.clear();
+            }
 
 
-                if (doc.Settings().readCameras) {
-                    ConvertCameras(*model, node_name);
-                }
+            // recursion call - child nodes
+            ConvertNodes(model->ID(), last_parent, root_node);
 
 
-                nodes.push_back(nodes_chain.front());
-                nodes_chain.clear();
+            if (doc.Settings().readLights) {
+                ConvertLights(*model, node_name);
             }
             }
-        }
 
 
-        if (nodes.size()) {
-            parent->mChildren = new aiNode *[nodes.size()]();
-            parent->mNumChildren = static_cast<unsigned int>(nodes.size());
+            if (doc.Settings().readCameras) {
+                ConvertCameras(*model, node_name);
+            }
 
 
-            std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren);
-        } else {
-            parent->mNumChildren = 0;
-            parent->mChildren = nullptr;
+            nodes.push_back(std::move(nodes_chain.front()));
+            nodes_chain.clear();
         }
         }
+    }
 
 
-    } catch (std::exception &) {
-        Util::delete_fun<aiNode> deleter;
-        std::for_each(nodes.begin(), nodes.end(), deleter);
-        std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter);
-        std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter);
+    if (nodes.size()) {
+        parent->mChildren = new aiNode *[nodes.size()]();
+        parent->mNumChildren = static_cast<unsigned int>(nodes.size());
+
+        for (unsigned int i = 0; i < nodes.size(); ++i)
+        {
+            parent->mChildren[i] = nodes[i].mOwnership.release();
+        }
+        nodes.clear();
+    } else {
+        parent->mNumChildren = 0;
+        parent->mChildren = nullptr;
     }
     }
 }
 }
 
 
@@ -681,8 +684,8 @@ std::string FBXConverter::NameTransformationChainNode(const std::string &name, T
     return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
     return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
 }
 }
 
 
-bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<aiNode *> &output_nodes,
-        std::vector<aiNode *> &post_output_nodes) {
+bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<PotentialNode> &output_nodes,
+        std::vector<PotentialNode> &post_output_nodes) {
     const PropertyTable &props = model.Props();
     const PropertyTable &props = model.Props();
     const Model::RotOrder rot = model.RotationOrder();
     const Model::RotOrder rot = model.RotationOrder();
 
 
@@ -828,7 +831,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
                 chain[i] = chain[i].Inverse();
                 chain[i] = chain[i].Inverse();
             }
             }
 
 
-            aiNode *nd = new aiNode();
+            PotentialNode nd;
             nd->mName.Set(NameTransformationChainNode(name, comp));
             nd->mName.Set(NameTransformationChainNode(name, comp));
             nd->mTransformation = chain[i];
             nd->mTransformation = chain[i];
 
 
@@ -836,9 +839,9 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
             if (comp == TransformationComp_GeometricScalingInverse ||
             if (comp == TransformationComp_GeometricScalingInverse ||
                     comp == TransformationComp_GeometricRotationInverse ||
                     comp == TransformationComp_GeometricRotationInverse ||
                     comp == TransformationComp_GeometricTranslationInverse) {
                     comp == TransformationComp_GeometricTranslationInverse) {
-                post_output_nodes.push_back(nd);
+                post_output_nodes.emplace_back(std::move(nd));
             } else {
             } else {
-                output_nodes.push_back(nd);
+                output_nodes.emplace_back(std::move(nd));
             }
             }
         }
         }
 
 
@@ -847,8 +850,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
     }
     }
 
 
     // else, we can just multiply the matrices together
     // else, we can just multiply the matrices together
-    aiNode *nd = new aiNode();
-    output_nodes.push_back(nd);
+    PotentialNode nd;
 
 
     // name passed to the method is already unique
     // name passed to the method is already unique
     nd->mName.Set(name);
     nd->mName.Set(name);
@@ -857,6 +859,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
     for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) {
     for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) {
       nd->mTransformation = nd->mTransformation * chain[i];
       nd->mTransformation = nd->mTransformation * chain[i];
     }
     }
+    output_nodes.push_back(std::move(nd));
     return false;
     return false;
 }
 }
   
   
@@ -1715,14 +1718,14 @@ aiString FBXConverter::GetTexturePath(const Texture *tex) {
         bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
         bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
         unsigned int index=0;
         unsigned int index=0;
 
 
-        VideoMap::const_iterator it = textures_converted.find(*media);
+        VideoMap::const_iterator it = textures_converted.find(media);
         if (it != textures_converted.end()) {
         if (it != textures_converted.end()) {
             index = (*it).second;
             index = (*it).second;
             textureReady = true;
             textureReady = true;
         } else {
         } else {
             if (media->ContentLength() > 0) {
             if (media->ContentLength() > 0) {
                 index = ConvertVideo(*media);
                 index = ConvertVideo(*media);
-                textures_converted[*media] = index;
+                textures_converted[media] = index;
                 textureReady = true;
                 textureReady = true;
             }
             }
         }
         }
@@ -1988,6 +1991,7 @@ void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const TextureMap &_
     TrySetTextureProperties(out_mat, _textures, "ShininessExponent", aiTextureType_SHININESS, mesh);
     TrySetTextureProperties(out_mat, _textures, "ShininessExponent", aiTextureType_SHININESS, mesh);
     TrySetTextureProperties(out_mat, _textures, "TransparencyFactor", aiTextureType_OPACITY, mesh);
     TrySetTextureProperties(out_mat, _textures, "TransparencyFactor", aiTextureType_OPACITY, mesh);
     TrySetTextureProperties(out_mat, _textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh);
     TrySetTextureProperties(out_mat, _textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh);
+    TrySetTextureProperties(out_mat, _textures, "ReflectionFactor", aiTextureType_METALNESS, mesh);
     //Maya counterparts
     //Maya counterparts
     TrySetTextureProperties(out_mat, _textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh);
     TrySetTextureProperties(out_mat, _textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh);
     TrySetTextureProperties(out_mat, _textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh);
     TrySetTextureProperties(out_mat, _textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh);
@@ -2010,12 +2014,40 @@ void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const TextureMap &_
     TrySetTextureProperties(out_mat, _textures, "Maya|TEX_roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
     TrySetTextureProperties(out_mat, _textures, "Maya|TEX_roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
     TrySetTextureProperties(out_mat, _textures, "Maya|TEX_ao_map", aiTextureType_AMBIENT_OCCLUSION, mesh);
     TrySetTextureProperties(out_mat, _textures, "Maya|TEX_ao_map", aiTextureType_AMBIENT_OCCLUSION, mesh);
 
 
-    // 3DSMax PBR
+    // 3DSMax Physical material
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh);
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh);
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh);
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh);
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh);
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh);
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh);
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh);
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
     TrySetTextureProperties(out_mat, _textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
+
+    // 3DSMax PBR materials
+    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|base_color_map", aiTextureType_BASE_COLOR, mesh);
+    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|norm_map", aiTextureType_NORMAL_CAMERA, mesh);
+    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|emit_color_map", aiTextureType_EMISSION_COLOR, mesh);
+    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|ao_map", aiTextureType_AMBIENT_OCCLUSION, mesh);
+    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|opacity_map", aiTextureType_OPACITY, mesh);
+    // Metalness/Roughness material type
+    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|metalness_map", aiTextureType_METALNESS, mesh);
+    // Specular/Gloss material type
+    TrySetTextureProperties(out_mat, _textures, "3dsMax|main|specular_map", aiTextureType_SPECULAR, mesh);
+
+    // Glossiness vs roughness in 3ds Max Pbr Materials
+    int useGlossiness;
+    if (out_mat->Get("$raw.3dsMax|main|useGlossiness", aiTextureType_NONE, 0, useGlossiness) == aiReturn_SUCCESS) {
+        // These textures swap meaning if ((useGlossiness == 1) != (material type is Specular/Gloss))
+        if (useGlossiness == 1) {
+            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|roughness_map", aiTextureType_SHININESS, mesh);
+            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|glossiness_map", aiTextureType_SHININESS, mesh);
+        }
+        else if (useGlossiness == 2) {
+            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
+            TrySetTextureProperties(out_mat, _textures, "3dsMax|main|glossiness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
+        }
+        else {
+            FBXImporter::LogWarn("A 3dsMax Pbr Material must have a useGlossiness value to correctly interpret roughness and glossiness textures.");
+        }
+    }
 }
 }
 
 
 void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const LayeredTextureMap &layeredTextures, const MeshGeometry *const mesh) {
 void FBXConverter::SetTextureProperties(aiMaterial *out_mat, const LayeredTextureMap &layeredTextures, const MeshGeometry *const mesh) {
@@ -2220,12 +2252,12 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial *out_mat, const PropertyTa
             if (media != nullptr && media->ContentLength() > 0) {
             if (media != nullptr && media->ContentLength() > 0) {
                 unsigned int index;
                 unsigned int index;
 
 
-                VideoMap::const_iterator videoIt = textures_converted.find(*media);
+                VideoMap::const_iterator videoIt = textures_converted.find(media);
                 if (videoIt != textures_converted.end()) {
                 if (videoIt != textures_converted.end()) {
                     index = videoIt->second;
                     index = videoIt->second;
                 } else {
                 } else {
                     index = ConvertVideo(*media);
                     index = ConvertVideo(*media);
-                    textures_converted[*media] = index;
+                    textures_converted[media] = index;
                 }
                 }
 
 
                 // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
                 // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
@@ -2528,7 +2560,7 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
                     meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
                     meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights;
                     meshMorphAnim->mKeys[j].mValues = new unsigned int[numValuesAndWeights];
                     meshMorphAnim->mKeys[j].mValues = new unsigned int[numValuesAndWeights];
                     meshMorphAnim->mKeys[j].mWeights = new double[numValuesAndWeights];
                     meshMorphAnim->mKeys[j].mWeights = new double[numValuesAndWeights];
-                    meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first) * anim_fps;
+                    meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first);
                     for (unsigned int k = 0; k < numValuesAndWeights; k++) {
                     for (unsigned int k = 0; k < numValuesAndWeights; k++) {
                         meshMorphAnim->mKeys[j].mValues[k] = keyData->values.at(k);
                         meshMorphAnim->mKeys[j].mValues[k] = keyData->values.at(k);
                         meshMorphAnim->mKeys[j].mWeights[k] = keyData->weights.at(k);
                         meshMorphAnim->mKeys[j].mWeights[k] = keyData->weights.at(k);
@@ -2546,8 +2578,8 @@ void FBXConverter::ConvertAnimationStack(const AnimationStack &st) {
         return;
         return;
     }
     }
 
 
-    double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time;
-    double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time;
+    double start_time_fps = has_local_startstop ? CONVERT_FBX_TIME(start_time) : min_time;
+    double stop_time_fps = has_local_startstop ? CONVERT_FBX_TIME(stop_time) : max_time;
 
 
     // adjust relative timing for animation
     // adjust relative timing for animation
     for (unsigned int c = 0; c < anim->mNumChannels; c++) {
     for (unsigned int c = 0; c < anim->mNumChannels; c++) {
@@ -3067,7 +3099,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
         InterpolateKeys(outTranslations, keytimes, keyframeLists[TransformationComp_Translation], defTranslate, maxTime, minTime);
         InterpolateKeys(outTranslations, keytimes, keyframeLists[TransformationComp_Translation], defTranslate, maxTime, minTime);
     } else {
     } else {
         for (size_t i = 0; i < keyCount; ++i) {
         for (size_t i = 0; i < keyCount; ++i) {
-            outTranslations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
+            outTranslations[i].mTime = CONVERT_FBX_TIME(keytimes[i]);
             outTranslations[i].mValue = defTranslate;
             outTranslations[i].mValue = defTranslate;
         }
         }
     }
     }
@@ -3076,7 +3108,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
         InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], defRotation, maxTime, minTime, rotOrder);
         InterpolateKeys(outRotations, keytimes, keyframeLists[TransformationComp_Rotation], defRotation, maxTime, minTime, rotOrder);
     } else {
     } else {
         for (size_t i = 0; i < keyCount; ++i) {
         for (size_t i = 0; i < keyCount; ++i) {
-            outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
+            outRotations[i].mTime = CONVERT_FBX_TIME(keytimes[i]);
             outRotations[i].mValue = defQuat;
             outRotations[i].mValue = defQuat;
         }
         }
     }
     }
@@ -3085,7 +3117,7 @@ aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name,
         InterpolateKeys(outScales, keytimes, keyframeLists[TransformationComp_Scaling], defScale, maxTime, minTime);
         InterpolateKeys(outScales, keytimes, keyframeLists[TransformationComp_Scaling], defScale, maxTime, minTime);
     } else {
     } else {
         for (size_t i = 0; i < keyCount; ++i) {
         for (size_t i = 0; i < keyCount; ++i) {
-            outScales[i].mTime = CONVERT_FBX_TIME(keytimes[i]) * anim_fps;
+            outScales[i].mTime = CONVERT_FBX_TIME(keytimes[i]);
             outScales[i].mValue = defScale;
             outScales[i].mValue = defScale;
         }
         }
     }
     }
@@ -3274,7 +3306,7 @@ void FBXConverter::InterpolateKeys(aiVectorKey *valOut, const KeyTimeList &keys,
         }
         }
 
 
         // magic value to convert fbx times to seconds
         // magic value to convert fbx times to seconds
-        valOut->mTime = CONVERT_FBX_TIME(time) * anim_fps;
+        valOut->mTime = CONVERT_FBX_TIME(time);
 
 
         min_time = std::min(min_time, valOut->mTime);
         min_time = std::min(min_time, valOut->mTime);
         max_time = std::max(max_time, valOut->mTime);
         max_time = std::max(max_time, valOut->mTime);
@@ -3480,10 +3512,11 @@ void FBXConverter::ConvertOrphanedEmbeddedTextures() {
                 const char *obtype = key.begin();
                 const char *obtype = key.begin();
                 const size_t length = static_cast<size_t>(key.end() - key.begin());
                 const size_t length = static_cast<size_t>(key.end() - key.begin());
                 if (strncmp(obtype, "Texture", length) == 0) {
                 if (strncmp(obtype, "Texture", length) == 0) {
-                    const Texture *texture = static_cast<const Texture *>(object->Get());
-                    if (texture->Media() && texture->Media()->ContentLength() > 0) {
-                        realTexture = texture;
-                    }
+                    if (const Texture *texture = static_cast<const Texture *>(object->Get())) {
+                        if (texture->Media() && texture->Media()->ContentLength() > 0) {
+                            realTexture = texture;
+                        }
+                    }    
                 }
                 }
             } catch (...) {
             } catch (...) {
                 // do nothing
                 // do nothing
@@ -3491,7 +3524,7 @@ void FBXConverter::ConvertOrphanedEmbeddedTextures() {
             if (realTexture) {
             if (realTexture) {
                 const Video *media = realTexture->Media();
                 const Video *media = realTexture->Media();
                 unsigned int index = ConvertVideo(*media);
                 unsigned int index = ConvertVideo(*media);
-                textures_converted[*media] = index;
+                textures_converted[media] = index;
             }
             }
         }
         }
     }
     }

+ 4 - 3
code/AssetLib/FBX/FBXConverter.h

@@ -171,9 +171,10 @@ private:
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     /**
     /**
-    *  note: memory for output_nodes will be managed by the caller
+    *  note: memory for output_nodes is managed by the caller, via the PotentialNode struct.
     */
     */
-    bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
+    struct PotentialNode;
+    bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<PotentialNode>& output_nodes, std::vector<PotentialNode>& post_output_nodes);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     void SetupNodeMetadata(const Model& model, aiNode& nd);
     void SetupNodeMetadata(const Model& model, aiNode& nd);
@@ -428,7 +429,7 @@ private:
     using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>;
     using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>;
     MaterialMap materials_converted;
     MaterialMap materials_converted;
 
 
-    using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
+    using VideoMap = std::fbx_unordered_map<const Video*, unsigned int>;
     VideoMap textures_converted;
     VideoMap textures_converted;
 
 
     using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >;
     using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >;

+ 0 - 35
code/AssetLib/FBX/FBXDocument.h

@@ -638,20 +638,6 @@ public:
         return ptr;
         return ptr;
     }
     }
 
 
-    bool operator==(const Video& other) const
-    {
-        return (
-               type == other.type
-            && relativeFileName == other.relativeFileName
-            && fileName == other.fileName
-        );
-    }
-
-    bool operator<(const Video& other) const
-    {
-        return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName);
-    }
-
 private:
 private:
     std::string type;
     std::string type;
     std::string relativeFileName;
     std::string relativeFileName;
@@ -1192,25 +1178,4 @@ private:
 } // Namespace FBX
 } // Namespace FBX
 } // Namespace Assimp
 } // Namespace Assimp
 
 
-namespace std
-{
-    template <>
-    struct hash<const Assimp::FBX::Video>
-    {
-        std::size_t operator()(const Assimp::FBX::Video& video) const
-        {
-            using std::size_t;
-            using std::hash;
-            using std::string;
-
-            size_t res = 17;
-            res = res * 31 + hash<string>()(video.Name());
-            res = res * 31 + hash<string>()(video.RelativeFilename());
-            res = res * 31 + hash<string>()(video.Type());
-
-            return res;
-        }
-    };
-}
-
 #endif // INCLUDED_AI_FBX_DOCUMENT_H
 #endif // INCLUDED_AI_FBX_DOCUMENT_H

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

@@ -61,7 +61,7 @@ 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(Util::AddTokenText("FBX-DOM",message,&token));
+    throw DeadlyImportError("FBX-DOM", Util::GetTokenText(&token), message);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -70,7 +70,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/)
     if(element) {
     if(element) {
         DOMError(message,element->KeyToken());
         DOMError(message,element->KeyToken());
     }
     }
-    throw DeadlyImportError("FBX-DOM " + message);
+    throw DeadlyImportError("FBX-DOM ", message);
 }
 }
 
 
 
 
@@ -79,7 +79,7 @@ void DOMError(const std::string& message, const Element* element /*= nullptr*/)
 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(Util::AddTokenText("FBX-DOM",message,&token));
+        ASSIMP_LOG_WARN_F("FBX-DOM", Util::GetTokenText(&token), message);
     }
     }
 }
 }
 
 

+ 76 - 17
code/AssetLib/FBX/FBXExporter.cpp

@@ -400,6 +400,65 @@ void FBXExporter::WriteHeaderExtension ()
     );
     );
 }
 }
 
 
+// WriteGlobalSettings helpers
+
+void WritePropInt(const aiScene* scene, FBX::Node& p, const std::string& key, int defaultValue)
+{
+    int value;
+    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
+        p.AddP70int(key, value);
+    } else {
+        p.AddP70int(key, defaultValue);
+    }
+}
+
+void WritePropDouble(const aiScene* scene, FBX::Node& p, const std::string& key, double defaultValue)
+{
+    double value;
+    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
+        p.AddP70double(key, value);
+    } else {
+        // fallback lookup float instead
+        float floatValue;
+        if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, floatValue)) {
+            p.AddP70double(key, (double)floatValue);
+        } else {
+            p.AddP70double(key, defaultValue);
+        }
+    }
+}
+
+void WritePropEnum(const aiScene* scene, FBX::Node& p, const std::string& key, int defaultValue)
+{
+    int value;
+    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
+        p.AddP70enum(key, value);
+    } else {
+        p.AddP70enum(key, defaultValue);
+    }
+}
+
+void WritePropColor(const aiScene* scene, FBX::Node& p, const std::string& key, const aiVector3D& defaultValue)
+{
+    aiVector3D value;
+    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
+        // ai_real can be float or double, cast to avoid warnings
+        p.AddP70color(key, (double)value.x, (double)value.y, (double)value.z);
+    } else {
+        p.AddP70color(key, (double)defaultValue.x, (double)defaultValue.y, (double)defaultValue.z);
+    }
+}
+
+void WritePropString(const aiScene* scene, FBX::Node& p, const std::string& key, const std::string& defaultValue)
+{
+    aiString value; // MetaData doesn't hold std::string
+    if (scene->mMetaData != nullptr && scene->mMetaData->Get(key, value)) {
+        p.AddP70string(key, value.C_Str());
+    } else {
+        p.AddP70string(key, defaultValue);
+    }
+}
+
 void FBXExporter::WriteGlobalSettings ()
 void FBXExporter::WriteGlobalSettings ()
 {
 {
     if (!binary) {
     if (!binary) {
@@ -409,26 +468,26 @@ void FBXExporter::WriteGlobalSettings ()
     gs.AddChild("Version", int32_t(1000));
     gs.AddChild("Version", int32_t(1000));
 
 
     FBX::Node p("Properties70");
     FBX::Node p("Properties70");
-    p.AddP70int("UpAxis", 1);
-    p.AddP70int("UpAxisSign", 1);
-    p.AddP70int("FrontAxis", 2);
-    p.AddP70int("FrontAxisSign", 1);
-    p.AddP70int("CoordAxis", 0);
-    p.AddP70int("CoordAxisSign", 1);
-    p.AddP70int("OriginalUpAxis", 1);
-    p.AddP70int("OriginalUpAxisSign", 1);
-    p.AddP70double("UnitScaleFactor", 1.0);
-    p.AddP70double("OriginalUnitScaleFactor", 1.0);
-    p.AddP70color("AmbientColor", 0.0, 0.0, 0.0);
-    p.AddP70string("DefaultCamera", "Producer Perspective");
-    p.AddP70enum("TimeMode", 11);
-    p.AddP70enum("TimeProtocol", 2);
-    p.AddP70enum("SnapOnFrameMode", 0);
+    WritePropInt(mScene, p, "UpAxis", 1);
+    WritePropInt(mScene, p, "UpAxisSign", 1);
+    WritePropInt(mScene, p, "FrontAxis", 2);
+    WritePropInt(mScene, p, "FrontAxisSign", 1);
+    WritePropInt(mScene, p, "CoordAxis", 0);
+    WritePropInt(mScene, p, "CoordAxisSign", 1);
+    WritePropInt(mScene, p, "OriginalUpAxis", 1);
+    WritePropInt(mScene, p, "OriginalUpAxisSign", 1);
+    WritePropDouble(mScene, p, "UnitScaleFactor", 1.0);
+    WritePropDouble(mScene, p, "OriginalUnitScaleFactor", 1.0);
+    WritePropColor(mScene, p, "AmbientColor", aiVector3D((ai_real)0.0, (ai_real)0.0, (ai_real)0.0));
+    WritePropString(mScene, p,"DefaultCamera", "Producer Perspective");
+    WritePropEnum(mScene, p, "TimeMode", 11);
+    WritePropEnum(mScene, p, "TimeProtocol", 2);
+    WritePropEnum(mScene, p, "SnapOnFrameMode", 0);
     p.AddP70time("TimeSpanStart", 0); // TODO: animation support
     p.AddP70time("TimeSpanStart", 0); // TODO: animation support
     p.AddP70time("TimeSpanStop", FBX::SECOND); // TODO: animation support
     p.AddP70time("TimeSpanStop", FBX::SECOND); // TODO: animation support
-    p.AddP70double("CustomFrameRate", -1.0);
+    WritePropDouble(mScene, p, "CustomFrameRate", -1.0);
     p.AddP70("TimeMarker", "Compound", "", ""); // not sure what this is
     p.AddP70("TimeMarker", "Compound", "", ""); // not sure what this is
-    p.AddP70int("CurrentTimeMarker", -1);
+    WritePropInt(mScene, p, "CurrentTimeMarker", -1);
     gs.AddChild(p);
     gs.AddChild(p);
 
 
     gs.Dump(outfile, binary, 0);
     gs.Dump(outfile, binary, 0);

+ 10 - 1
code/AssetLib/FBX/FBXImporter.cpp

@@ -130,6 +130,7 @@ void FBXImporter::SetupProperties(const Importer *pImp) {
 	settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
 	settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
 	settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
 	settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
 	settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, 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.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
 	settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
 	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.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
@@ -141,7 +142,10 @@ void FBXImporter::SetupProperties(const Importer *pImp) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 // Imports the given file into the given scene structure.
 void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
 void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
-	std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
+	auto streamCloser = [&](IOStream *pStream) {
+		pIOHandler->Close(pStream);
+	};
+	std::unique_ptr<IOStream, decltype(streamCloser)> stream(pIOHandler->Open(pFile, "rb"), streamCloser);
 	if (!stream) {
 	if (!stream) {
 		ThrowException("Could not open file for reading");
 		ThrowException("Could not open file for reading");
 	}
 	}
@@ -184,6 +188,11 @@ void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 
 
 		// 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)
+        {
+			// BaseImporter later asserts that fileScale is non-zero.
+			ThrowException("The UnitScaleFactor must be non-zero");
+        }
 
 
 		// Set FBX file scale is relative to CM must be converted to M for
 		// Set FBX file scale is relative to CM must be converted to M for
 		// assimp universal format (M)
 		// assimp universal format (M)

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

@@ -86,7 +86,7 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
     std::string templateName;
     std::string templateName;
 
 
     // lower-case shading because Blender (for example) writes "Phong"
     // lower-case shading because Blender (for example) writes "Phong"
-    std::transform(shading.begin(), shading.end(), shading.begin(), Assimp::ToLower<char>);
+    std::transform(shading.data(), shading.data() + shading.size(), std::addressof(shading[0]), Assimp::ToLower<char>);
     if(shading == "phong") {
     if(shading == "phong") {
         templateName = "Material.FbxSurfacePhong";
         templateName = "Material.FbxSurfacePhong";
     }
     }

+ 42 - 10
code/AssetLib/FBX/FBXParser.cpp

@@ -73,7 +73,7 @@ namespace {
     AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
     AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX;
     AI_WONT_RETURN void ParseError(const std::string& message, const Token& token)
     AI_WONT_RETURN void ParseError(const std::string& message, const Token& token)
     {
     {
-        throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token));
+        throw DeadlyImportError("FBX-Parser", Util::GetTokenText(&token), message);
     }
     }
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
@@ -83,7 +83,7 @@ namespace {
         if(element) {
         if(element) {
             ParseError(message,element->KeyToken());
             ParseError(message,element->KeyToken());
         }
         }
-        throw DeadlyImportError("FBX-Parser " + message);
+        throw DeadlyImportError("FBX-Parser ", message);
     }
     }
 
 
 
 
@@ -641,7 +641,11 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
 
         ai_assert(data == end);
         ai_assert(data == end);
-        ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
+        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
 
         const uint32_t count3 = count / 3;
         const uint32_t count3 = count / 3;
         out.reserve(count3);
         out.reserve(count3);
@@ -728,7 +732,11 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
 
         ai_assert(data == end);
         ai_assert(data == end);
-        ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
+        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
 
         const uint32_t count4 = count / 4;
         const uint32_t count4 = count / 4;
         out.reserve(count4);
         out.reserve(count4);
@@ -807,7 +815,11 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
 
         ai_assert(data == end);
         ai_assert(data == end);
-        ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
+        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
 
         const uint32_t count2 = count / 2;
         const uint32_t count2 = count / 2;
         out.reserve(count2);
         out.reserve(count2);
@@ -879,7 +891,11 @@ void ParseVectorDataArray(std::vector<int>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
 
         ai_assert(data == end);
         ai_assert(data == end);
-        ai_assert(buff.size() == count * 4);
+        uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
 
         out.reserve(count);
         out.reserve(count);
 
 
@@ -937,7 +953,11 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
 
         ai_assert(data == end);
         ai_assert(data == end);
-        ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
+        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
 
         if (type == 'd') {
         if (type == 'd') {
             const double* d = reinterpret_cast<const double*>(&buff[0]);
             const double* d = reinterpret_cast<const double*>(&buff[0]);
@@ -998,7 +1018,11 @@ void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
 
         ai_assert(data == end);
         ai_assert(data == end);
-        ai_assert(buff.size() == count * 4);
+        uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
 
         out.reserve(count);
         out.reserve(count);
 
 
@@ -1063,7 +1087,11 @@ void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
 
         ai_assert(data == end);
         ai_assert(data == end);
-        ai_assert(buff.size() == count * 8);
+        uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
 
         out.reserve(count);
         out.reserve(count);
 
 
@@ -1121,7 +1149,11 @@ void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
 
         ai_assert(data == end);
         ai_assert(data == end);
-        ai_assert(buff.size() == count * 8);
+        uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
 
         out.reserve(count);
         out.reserve(count);
 
 

+ 34 - 2
code/AssetLib/FBX/FBXProperties.cpp

@@ -69,6 +69,20 @@ Property::~Property()
 
 
 namespace {
 namespace {
 
 
+void checkTokenCount(const TokenList& tok, unsigned int expectedCount)
+{
+    ai_assert(expectedCount >= 2);
+    if (tok.size() < expectedCount) {
+        const std::string& s = ParseTokenAsString(*tok[1]);
+        if (tok[1]->IsBinary()) {
+            throw DeadlyImportError("Not enough tokens for property of type ", s, " at offset ", tok[1]->Offset());
+        }
+        else {
+            throw DeadlyImportError("Not enough tokens for property of type ", s, " at line ", tok[1]->Line());
+        }
+    }
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // read a typed property out of a FBX element. The return value is nullptr if the property cannot be read.
 // read a typed property out of a FBX element. The return value is nullptr if the property cannot be read.
 Property* ReadTypedProperty(const Element& element)
 Property* ReadTypedProperty(const Element& element)
@@ -76,23 +90,30 @@ Property* ReadTypedProperty(const Element& element)
     ai_assert(element.KeyToken().StringContents() == "P");
     ai_assert(element.KeyToken().StringContents() == "P");
 
 
     const TokenList& tok = element.Tokens();
     const TokenList& tok = element.Tokens();
-    ai_assert(tok.size() >= 5);
+    if (tok.size() < 2) {
+        return nullptr;
+    }
 
 
     const std::string& s = ParseTokenAsString(*tok[1]);
     const std::string& s = ParseTokenAsString(*tok[1]);
     const char* const cs = s.c_str();
     const char* const cs = s.c_str();
     if (!strcmp(cs,"KString")) {
     if (!strcmp(cs,"KString")) {
+        checkTokenCount(tok, 5);
         return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
         return new TypedProperty<std::string>(ParseTokenAsString(*tok[4]));
     }
     }
     else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
     else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) {
+        checkTokenCount(tok, 5);
         return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
         return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0);
     }
     }
-    else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) {
+    else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum") || !strcmp(cs, "Integer")) {
+        checkTokenCount(tok, 5);
         return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
         return new TypedProperty<int>(ParseTokenAsInt(*tok[4]));
     }
     }
     else if (!strcmp(cs, "ULongLong")) {
     else if (!strcmp(cs, "ULongLong")) {
+        checkTokenCount(tok, 5);
         return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
         return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4]));
     }
     }
     else if (!strcmp(cs, "KTime")) {
     else if (!strcmp(cs, "KTime")) {
+        checkTokenCount(tok, 5);
         return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
         return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4]));
     }
     }
     else if (!strcmp(cs,"Vector3D") ||
     else if (!strcmp(cs,"Vector3D") ||
@@ -103,6 +124,7 @@ Property* ReadTypedProperty(const Element& element)
         !strcmp(cs,"Lcl Rotation") ||
         !strcmp(cs,"Lcl Rotation") ||
         !strcmp(cs,"Lcl Scaling")
         !strcmp(cs,"Lcl Scaling")
         ) {
         ) {
+        checkTokenCount(tok, 7);
         return new TypedProperty<aiVector3D>(aiVector3D(
         return new TypedProperty<aiVector3D>(aiVector3D(
             ParseTokenAsFloat(*tok[4]),
             ParseTokenAsFloat(*tok[4]),
             ParseTokenAsFloat(*tok[5]),
             ParseTokenAsFloat(*tok[5]),
@@ -110,8 +132,18 @@ Property* ReadTypedProperty(const Element& element)
         );
         );
     }
     }
     else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) {
     else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) {
+        checkTokenCount(tok, 5);
         return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
         return new TypedProperty<float>(ParseTokenAsFloat(*tok[4]));
     }
     }
+    else if (!strcmp(cs, "ColorAndAlpha")) {
+        checkTokenCount(tok, 8);
+        return new TypedProperty<aiColor4D>(aiColor4D(
+            ParseTokenAsFloat(*tok[4]),
+            ParseTokenAsFloat(*tok[5]),
+            ParseTokenAsFloat(*tok[6]),
+            ParseTokenAsFloat(*tok[7]))
+        );
+    }
     return nullptr;
     return nullptr;
 }
 }
 
 

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

@@ -90,7 +90,7 @@ namespace {
 AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX;
 AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX;
 AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column)
 AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column)
 {
 {
-    throw DeadlyImportError(Util::AddLineAndColumn("FBX-Tokenize",message,line,column));
+    throw DeadlyImportError("FBX-Tokenize", Util::GetLineAndColumnText(line,column), message);
 }
 }
 
 
 
 

+ 9 - 11
code/AssetLib/FBX/FBXUtil.cpp

@@ -86,32 +86,30 @@ const char* TokenTypeString(TokenType t)
 
 
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset)
+std::string GetOffsetText(size_t offset)
 {
 {
-    return static_cast<std::string>( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) );
+    return static_cast<std::string>( Formatter::format() << " (offset 0x" << std::hex << offset << ") " );
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column)
+std::string GetLineAndColumnText(unsigned int line, unsigned int column)
 {
 {
-    return static_cast<std::string>( (Formatter::format() << prefix << " (line " << line << " <<  col " << column << ") " << text) );
+    return static_cast<std::string>( Formatter::format() << " (line " << line << " <<  col " << column << ") " );
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok)
+std::string GetTokenText(const Token* tok)
 {
 {
     if(tok->IsBinary()) {
     if(tok->IsBinary()) {
-        return static_cast<std::string>( (Formatter::format() << prefix <<
+        return static_cast<std::string>( Formatter::format() << 
             " (" << TokenTypeString(tok->Type()) <<
             " (" << TokenTypeString(tok->Type()) <<
-            ", offset 0x" << std::hex << tok->Offset() << ") " <<
-            text) );
+            ", offset 0x" << std::hex << tok->Offset() << ") " );
     }
     }
 
 
-    return static_cast<std::string>( (Formatter::format() << prefix <<
+    return static_cast<std::string>( Formatter::format() <<
         " (" << TokenTypeString(tok->Type()) <<
         " (" << TokenTypeString(tok->Type()) <<
         ", line " << tok->Line() <<
         ", line " << tok->Line() <<
-        ", col " << tok->Column() << ") " <<
-        text) );
+        ", col " << tok->Column() << ") " );
 }
 }
 
 
 // Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
 // Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;

+ 7 - 14
code/AssetLib/FBX/FBXUtil.h

@@ -73,31 +73,24 @@ const char* TokenTypeString(TokenType t);
 
 
 /** Format log/error messages using a given offset in the source binary file
 /** Format log/error messages using a given offset in the source binary file
  *
  *
- *  @param prefix Message prefix to be preprended to the location info.
- *  @param text Message text
- *  @param line Line index, 1-based
- *  @param column Column index, 1-based
- *  @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/
-std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset);
+ *  @param offset offset within the file
+ *  @return A string of the following format: " (offset 0x{offset}) "*/
+std::string GetOffsetText(size_t offset);
 
 
 
 
 /** Format log/error messages using a given line location in the source file.
 /** Format log/error messages using a given line location in the source file.
  *
  *
- *  @param prefix Message prefix to be preprended to the location info.
- *  @param text Message text
  *  @param line Line index, 1-based
  *  @param line Line index, 1-based
  *  @param column Column index, 1-based
  *  @param column Column index, 1-based
- *  @return A string of the following format: {prefix} (line {line}, col {column}) {text}*/
-std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column);
+ *  @return A string of the following format: " (line {line}, col {column}) "*/
+std::string GetLineAndColumnText(unsigned int line, unsigned int column);
 
 
 
 
 /** Format log/error messages using a given cursor token.
 /** Format log/error messages using a given cursor token.
  *
  *
- *  @param prefix Message prefix to be preprended to the location info.
- *  @param text Message text
  *  @param tok Token where parsing/processing stopped
  *  @param tok Token where parsing/processing stopped
- *  @return A string of the following format: {prefix} ({token-type}, line {line}, col {column}) {text}*/
-std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok);
+ *  @return A string of the following format: " ({token-type}, line {line}, col {column}) "*/
+std::string GetTokenText(const Token* tok);
 
 
 /** Decode a single Base64-encoded character.
 /** Decode a single Base64-encoded character.
 *
 *

+ 3 - 3
code/AssetLib/HMP/HMPLoader.cpp

@@ -115,7 +115,7 @@ void HMPImporter::InternReadFile(const std::string &pFile,
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open HMP file " + pFile + ".");
+        throw DeadlyImportError("Failed to open HMP file ", pFile, ".");
     }
     }
 
 
     // Check whether the HMP file is large enough to contain
     // Check whether the HMP file is large enough to contain
@@ -159,8 +159,8 @@ void HMPImporter::InternReadFile(const std::string &pFile,
         szBuffer[4] = '\0';
         szBuffer[4] = '\0';
 
 
         // We're definitely unable to load this file
         // We're definitely unable to load this file
-        throw DeadlyImportError("Unknown HMP subformat " + pFile +
-                                ". Magic word (" + szBuffer + ") is not known");
+        throw DeadlyImportError("Unknown HMP subformat ", pFile,
+                                ". Magic word (", szBuffer, ") is not known");
     }
     }
 
 
     // Set the AI_SCENE_FLAGS_TERRAIN bit
     // Set the AI_SCENE_FLAGS_TERRAIN bit

+ 9 - 0
code/AssetLib/IFC/IFCReaderGen1_2x3.cpp

@@ -45,6 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "IFCReaderGen_2x3.h"
 #include "IFCReaderGen_2x3.h"
 
 
+#if _MSC_VER
+#    pragma warning(push)
+#    pragma warning(disable : 4702)
+#endif // _MSC_VER
+
 namespace Assimp {
 namespace Assimp {
 
 
 using namespace ::Assimp::IFC;
 using namespace ::Assimp::IFC;
@@ -3165,4 +3170,8 @@ template <> size_t GenericFill<IfcLightSourceDirectional>(const DB& db, const LI
 } // ! STEP
 } // ! STEP
 } // ! Assimp
 } // ! Assimp
 
 
+#if _MSC_VER
+#    pragma warning(pop)
+#endif // _MSC_VER
+
 #endif
 #endif

+ 9 - 0
code/AssetLib/IFC/IFCReaderGen2_2x3.cpp

@@ -43,6 +43,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "IFCReaderGen_2x3.h"
 #include "IFCReaderGen_2x3.h"
 
 
+#if _MSC_VER
+#    pragma warning(push)
+#    pragma warning(disable : 4702)
+#endif // _MSC_VER
+
 namespace Assimp {
 namespace Assimp {
 using namespace IFC;
 using namespace IFC;
 using namespace ::Assimp::IFC::Schema_2x3;
 using namespace ::Assimp::IFC::Schema_2x3;
@@ -1915,4 +1920,8 @@ template <> size_t GenericFill<IfcConditionCriterion>(const DB& db, const LIST&
 } // ! STEP
 } // ! STEP
 } // ! Assimp
 } // ! Assimp
 
 
+#if _MSC_VER
+#    pragma warning(pop)
+#endif // _MSC_VER
+
 #endif
 #endif

+ 7 - 2
code/AssetLib/IFC/IFCReaderGen_2x3.h

@@ -45,9 +45,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "AssetLib/Step/STEPFile.h"
 #include "AssetLib/Step/STEPFile.h"
 
 
-#ifdef _WIN32
+#ifdef _MSC_VER
+#    pragma warning(push)
 #    pragma warning( disable : 4512 )
 #    pragma warning( disable : 4512 )
-#endif // _WIN32
+#endif // _MSC_VER
 
 
 namespace Assimp {
 namespace Assimp {
 namespace IFC {
 namespace IFC {
@@ -4372,4 +4373,8 @@ namespace STEP {
 } //! STEP
 } //! STEP
 } //! Assimp
 } //! Assimp
 
 
+#ifdef _MSC_VER
+#    pragma warning(pop)
+#endif // _MSC_VER
+
 #endif // INCLUDED_IFC_READER_GEN_H
 #endif // INCLUDED_IFC_READER_GEN_H

+ 1212 - 1226
code/AssetLib/Irr/IRRLoader.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -67,200 +65,198 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <memory>
 #include <memory>
 
 
 using namespace Assimp;
 using namespace Assimp;
-using namespace irr;
-using namespace irr::io;
 
 
 static const aiImporterDesc desc = {
 static const aiImporterDesc desc = {
-    "Irrlicht Scene Reader",
-    "",
-    "",
-    "http://irrlicht.sourceforge.net/",
-    aiImporterFlags_SupportTextFlavour,
-    0,
-    0,
-    0,
-    0,
-    "irr xml"
+	"Irrlicht Scene Reader",
+	"",
+	"",
+	"http://irrlicht.sourceforge.net/",
+	aiImporterFlags_SupportTextFlavour,
+	0,
+	0,
+	0,
+	0,
+	"irr xml"
 };
 };
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 IRRImporter::IRRImporter() :
 IRRImporter::IRRImporter() :
-        fps(), configSpeedFlag() {
-    // empty
+		fps(), configSpeedFlag() {
+	// empty
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 // Destructor, private as well
 IRRImporter::~IRRImporter() {
 IRRImporter::~IRRImporter() {
-    // empty
+	// empty
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
 bool IRRImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
 bool IRRImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension = GetExtension(pFile);
-    if (extension == "irr") {
-        return true;
-    } else if (extension == "xml" || checkSig) {
-        /*  If CanRead() is called in order to check whether we
+	const std::string extension = GetExtension(pFile);
+	if (extension == "irr") {
+		return true;
+	} else if (extension == "xml" || checkSig) {
+		/*  If CanRead() is called in order to check whether we
          *  support a specific file extension in general pIOHandler
          *  support a specific file extension in general pIOHandler
          *  might be nullptr and it's our duty to return true here.
          *  might be nullptr and it's our duty to return true here.
          */
          */
-        if (nullptr == pIOHandler) {
-            return true;
-        }
-        const char *tokens[] = { "irr_scene" };
-        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-    }
-
-    return false;
+		if (nullptr == pIOHandler) {
+			return true;
+		}
+		const char *tokens[] = { "irr_scene" };
+		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+	}
+
+	return false;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 const aiImporterDesc *IRRImporter::GetInfo() const {
 const aiImporterDesc *IRRImporter::GetInfo() const {
-    return &desc;
+	return &desc;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void IRRImporter::SetupProperties(const Importer *pImp) {
 void IRRImporter::SetupProperties(const Importer *pImp) {
-    // read the output frame rate of all node animation channels
-    fps = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IRR_ANIM_FPS, 100);
-    if (fps < 10.) {
-        ASSIMP_LOG_ERROR("IRR: Invalid FPS configuration");
-        fps = 100;
-    }
-
-    // AI_CONFIG_FAVOUR_SPEED
-    configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED, 0));
+	// read the output frame rate of all node animation channels
+	fps = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IRR_ANIM_FPS, 100);
+	if (fps < 10.) {
+		ASSIMP_LOG_ERROR("IRR: Invalid FPS configuration");
+		fps = 100;
+	}
+
+	// AI_CONFIG_FAVOUR_SPEED
+	configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED, 0));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Build a mesh tha consists of a single squad (a side of a skybox)
 // Build a mesh tha consists of a single squad (a side of a skybox)
 aiMesh *IRRImporter::BuildSingleQuadMesh(const SkyboxVertex &v1,
 aiMesh *IRRImporter::BuildSingleQuadMesh(const SkyboxVertex &v1,
-        const SkyboxVertex &v2,
-        const SkyboxVertex &v3,
-        const SkyboxVertex &v4) {
-    // allocate and prepare the mesh
-    aiMesh *out = new aiMesh();
-
-    out->mPrimitiveTypes = aiPrimitiveType_POLYGON;
-    out->mNumFaces = 1;
-
-    // build the face
-    out->mFaces = new aiFace[1];
-    aiFace &face = out->mFaces[0];
-
-    face.mNumIndices = 4;
-    face.mIndices = new unsigned int[4];
-    for (unsigned int i = 0; i < 4; ++i)
-        face.mIndices[i] = i;
-
-    out->mNumVertices = 4;
-
-    // copy vertex positions
-    aiVector3D *vec = out->mVertices = new aiVector3D[4];
-    *vec++ = v1.position;
-    *vec++ = v2.position;
-    *vec++ = v3.position;
-    *vec = v4.position;
-
-    // copy vertex normals
-    vec = out->mNormals = new aiVector3D[4];
-    *vec++ = v1.normal;
-    *vec++ = v2.normal;
-    *vec++ = v3.normal;
-    *vec = v4.normal;
-
-    // copy texture coordinates
-    vec = out->mTextureCoords[0] = new aiVector3D[4];
-    *vec++ = v1.uv;
-    *vec++ = v2.uv;
-    *vec++ = v3.uv;
-    *vec = v4.uv;
-    return out;
+		const SkyboxVertex &v2,
+		const SkyboxVertex &v3,
+		const SkyboxVertex &v4) {
+	// allocate and prepare the mesh
+	aiMesh *out = new aiMesh();
+
+	out->mPrimitiveTypes = aiPrimitiveType_POLYGON;
+	out->mNumFaces = 1;
+
+	// build the face
+	out->mFaces = new aiFace[1];
+	aiFace &face = out->mFaces[0];
+
+	face.mNumIndices = 4;
+	face.mIndices = new unsigned int[4];
+	for (unsigned int i = 0; i < 4; ++i)
+		face.mIndices[i] = i;
+
+	out->mNumVertices = 4;
+
+	// copy vertex positions
+	aiVector3D *vec = out->mVertices = new aiVector3D[4];
+	*vec++ = v1.position;
+	*vec++ = v2.position;
+	*vec++ = v3.position;
+	*vec = v4.position;
+
+	// copy vertex normals
+	vec = out->mNormals = new aiVector3D[4];
+	*vec++ = v1.normal;
+	*vec++ = v2.normal;
+	*vec++ = v3.normal;
+	*vec = v4.normal;
+
+	// copy texture coordinates
+	vec = out->mTextureCoords[0] = new aiVector3D[4];
+	*vec++ = v1.uv;
+	*vec++ = v2.uv;
+	*vec++ = v3.uv;
+	*vec = v4.uv;
+	return out;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void IRRImporter::BuildSkybox(std::vector<aiMesh *> &meshes, std::vector<aiMaterial *> materials) {
 void IRRImporter::BuildSkybox(std::vector<aiMesh *> &meshes, std::vector<aiMaterial *> materials) {
-    // Update the material of the skybox - replace the name and disable shading for skyboxes.
-    for (unsigned int i = 0; i < 6; ++i) {
-        aiMaterial *out = (aiMaterial *)(*(materials.end() - (6 - i)));
-
-        aiString s;
-        s.length = ::ai_snprintf(s.data, MAXLEN, "SkyboxSide_%u", i);
-        out->AddProperty(&s, AI_MATKEY_NAME);
-
-        int shading = aiShadingMode_NoShading;
-        out->AddProperty(&shading, 1, AI_MATKEY_SHADING_MODEL);
-    }
-
-    // Skyboxes are much more difficult. They are represented
-    // by six single planes with different textures, so we'll
-    // need to build six meshes.
-
-    const ai_real l = 10.0; // the size used by Irrlicht
-
-    // FRONT SIDE
-    meshes.push_back(BuildSingleQuadMesh(
-            SkyboxVertex(-l, -l, -l, 0, 0, 1, 1.0, 1.0),
-            SkyboxVertex(l, -l, -l, 0, 0, 1, 0.0, 1.0),
-            SkyboxVertex(l, l, -l, 0, 0, 1, 0.0, 0.0),
-            SkyboxVertex(-l, l, -l, 0, 0, 1, 1.0, 0.0)));
-    meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 6u);
-
-    // LEFT SIDE
-    meshes.push_back(BuildSingleQuadMesh(
-            SkyboxVertex(l, -l, -l, -1, 0, 0, 1.0, 1.0),
-            SkyboxVertex(l, -l, l, -1, 0, 0, 0.0, 1.0),
-            SkyboxVertex(l, l, l, -1, 0, 0, 0.0, 0.0),
-            SkyboxVertex(l, l, -l, -1, 0, 0, 1.0, 0.0)));
-    meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 5u);
-
-    // BACK SIDE
-    meshes.push_back(BuildSingleQuadMesh(
-            SkyboxVertex(l, -l, l, 0, 0, -1, 1.0, 1.0),
-            SkyboxVertex(-l, -l, l, 0, 0, -1, 0.0, 1.0),
-            SkyboxVertex(-l, l, l, 0, 0, -1, 0.0, 0.0),
-            SkyboxVertex(l, l, l, 0, 0, -1, 1.0, 0.0)));
-    meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 4u);
-
-    // RIGHT SIDE
-    meshes.push_back(BuildSingleQuadMesh(
-            SkyboxVertex(-l, -l, l, 1, 0, 0, 1.0, 1.0),
-            SkyboxVertex(-l, -l, -l, 1, 0, 0, 0.0, 1.0),
-            SkyboxVertex(-l, l, -l, 1, 0, 0, 0.0, 0.0),
-            SkyboxVertex(-l, l, l, 1, 0, 0, 1.0, 0.0)));
-    meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 3u);
-
-    // TOP SIDE
-    meshes.push_back(BuildSingleQuadMesh(
-            SkyboxVertex(l, l, -l, 0, -1, 0, 1.0, 1.0),
-            SkyboxVertex(l, l, l, 0, -1, 0, 0.0, 1.0),
-            SkyboxVertex(-l, l, l, 0, -1, 0, 0.0, 0.0),
-            SkyboxVertex(-l, l, -l, 0, -1, 0, 1.0, 0.0)));
-    meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 2u);
-
-    // BOTTOM SIDE
-    meshes.push_back(BuildSingleQuadMesh(
-            SkyboxVertex(l, -l, l, 0, 1, 0, 0.0, 0.0),
-            SkyboxVertex(l, -l, -l, 0, 1, 0, 1.0, 0.0),
-            SkyboxVertex(-l, -l, -l, 0, 1, 0, 1.0, 1.0),
-            SkyboxVertex(-l, -l, l, 0, 1, 0, 0.0, 1.0)));
-    meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 1u);
+	// Update the material of the skybox - replace the name and disable shading for skyboxes.
+	for (unsigned int i = 0; i < 6; ++i) {
+		aiMaterial *out = (aiMaterial *)(*(materials.end() - (6 - i)));
+
+		aiString s;
+		s.length = ::ai_snprintf(s.data, MAXLEN, "SkyboxSide_%u", i);
+		out->AddProperty(&s, AI_MATKEY_NAME);
+
+		int shading = aiShadingMode_NoShading;
+		out->AddProperty(&shading, 1, AI_MATKEY_SHADING_MODEL);
+	}
+
+	// Skyboxes are much more difficult. They are represented
+	// by six single planes with different textures, so we'll
+	// need to build six meshes.
+
+	const ai_real l = 10.0; // the size used by Irrlicht
+
+	// FRONT SIDE
+	meshes.push_back(BuildSingleQuadMesh(
+			SkyboxVertex(-l, -l, -l, 0, 0, 1, 1.0, 1.0),
+			SkyboxVertex(l, -l, -l, 0, 0, 1, 0.0, 1.0),
+			SkyboxVertex(l, l, -l, 0, 0, 1, 0.0, 0.0),
+			SkyboxVertex(-l, l, -l, 0, 0, 1, 1.0, 0.0)));
+	meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 6u);
+
+	// LEFT SIDE
+	meshes.push_back(BuildSingleQuadMesh(
+			SkyboxVertex(l, -l, -l, -1, 0, 0, 1.0, 1.0),
+			SkyboxVertex(l, -l, l, -1, 0, 0, 0.0, 1.0),
+			SkyboxVertex(l, l, l, -1, 0, 0, 0.0, 0.0),
+			SkyboxVertex(l, l, -l, -1, 0, 0, 1.0, 0.0)));
+	meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 5u);
+
+	// BACK SIDE
+	meshes.push_back(BuildSingleQuadMesh(
+			SkyboxVertex(l, -l, l, 0, 0, -1, 1.0, 1.0),
+			SkyboxVertex(-l, -l, l, 0, 0, -1, 0.0, 1.0),
+			SkyboxVertex(-l, l, l, 0, 0, -1, 0.0, 0.0),
+			SkyboxVertex(l, l, l, 0, 0, -1, 1.0, 0.0)));
+	meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 4u);
+
+	// RIGHT SIDE
+	meshes.push_back(BuildSingleQuadMesh(
+			SkyboxVertex(-l, -l, l, 1, 0, 0, 1.0, 1.0),
+			SkyboxVertex(-l, -l, -l, 1, 0, 0, 0.0, 1.0),
+			SkyboxVertex(-l, l, -l, 1, 0, 0, 0.0, 0.0),
+			SkyboxVertex(-l, l, l, 1, 0, 0, 1.0, 0.0)));
+	meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 3u);
+
+	// TOP SIDE
+	meshes.push_back(BuildSingleQuadMesh(
+			SkyboxVertex(l, l, -l, 0, -1, 0, 1.0, 1.0),
+			SkyboxVertex(l, l, l, 0, -1, 0, 0.0, 1.0),
+			SkyboxVertex(-l, l, l, 0, -1, 0, 0.0, 0.0),
+			SkyboxVertex(-l, l, -l, 0, -1, 0, 1.0, 0.0)));
+	meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 2u);
+
+	// BOTTOM SIDE
+	meshes.push_back(BuildSingleQuadMesh(
+			SkyboxVertex(l, -l, l, 0, 1, 0, 0.0, 0.0),
+			SkyboxVertex(l, -l, -l, 0, 1, 0, 1.0, 0.0),
+			SkyboxVertex(-l, -l, -l, 0, 1, 0, 1.0, 1.0),
+			SkyboxVertex(-l, -l, l, 0, 1, 0, 0.0, 1.0)));
+	meshes.back()->mMaterialIndex = static_cast<unsigned int>(materials.size() - 1u);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void IRRImporter::CopyMaterial(std::vector<aiMaterial *> &materials,
 void IRRImporter::CopyMaterial(std::vector<aiMaterial *> &materials,
-        std::vector<std::pair<aiMaterial *, unsigned int>> &inmaterials,
-        unsigned int &defMatIdx,
-        aiMesh *mesh) {
-    if (inmaterials.empty()) {
-        // Do we have a default material? If not we need to create one
-        if (UINT_MAX == defMatIdx) {
-            defMatIdx = (unsigned int)materials.size();
-            //TODO: add this materials to someone?
-            /*aiMaterial* mat = new aiMaterial();
+		std::vector<std::pair<aiMaterial *, unsigned int>> &inmaterials,
+		unsigned int &defMatIdx,
+		aiMesh *mesh) {
+	if (inmaterials.empty()) {
+		// Do we have a default material? If not we need to create one
+		if (UINT_MAX == defMatIdx) {
+			defMatIdx = (unsigned int)materials.size();
+			//TODO: add this materials to someone?
+			/*aiMaterial* mat = new aiMaterial();
 
 
             aiString s;
             aiString s;
             s.Set(AI_DEFAULT_MATERIAL_NAME);
             s.Set(AI_DEFAULT_MATERIAL_NAME);
@@ -268,1120 +264,1110 @@ void IRRImporter::CopyMaterial(std::vector<aiMaterial *> &materials,
 
 
             aiColor3D c(0.6f,0.6f,0.6f);
             aiColor3D c(0.6f,0.6f,0.6f);
             mat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);*/
             mat->AddProperty(&c,1,AI_MATKEY_COLOR_DIFFUSE);*/
-        }
-        mesh->mMaterialIndex = defMatIdx;
-        return;
-    } else if (inmaterials.size() > 1) {
-        ASSIMP_LOG_INFO("IRR: Skipping additional materials");
-    }
-
-    mesh->mMaterialIndex = (unsigned int)materials.size();
-    materials.push_back(inmaterials[0].first);
+		}
+		mesh->mMaterialIndex = defMatIdx;
+		return;
+	} else if (inmaterials.size() > 1) {
+		ASSIMP_LOG_INFO("IRR: Skipping additional materials");
+	}
+
+	mesh->mMaterialIndex = (unsigned int)materials.size();
+	materials.push_back(inmaterials[0].first);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 inline int ClampSpline(int idx, int size) {
 inline int ClampSpline(int idx, int size) {
-    return (idx < 0 ? size + idx : (idx >= size ? idx - size : idx));
+	return (idx < 0 ? size + idx : (idx >= size ? idx - size : idx));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 inline void FindSuitableMultiple(int &angle) {
 inline void FindSuitableMultiple(int &angle) {
-    if (angle < 3)
-        angle = 3;
-    else if (angle < 10)
-        angle = 10;
-    else if (angle < 20)
-        angle = 20;
-    else if (angle < 30)
-        angle = 30;
+	if (angle < 3)
+		angle = 3;
+	else if (angle < 10)
+		angle = 10;
+	else if (angle < 20)
+		angle = 20;
+	else if (angle < 30)
+		angle = 30;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNodeAnim *> &anims) {
 void IRRImporter::ComputeAnimations(Node *root, aiNode *real, std::vector<aiNodeAnim *> &anims) {
-    ai_assert(nullptr != root);
-    ai_assert(nullptr != real);
-
-    // XXX totally WIP - doesn't produce proper results, need to evaluate
-    // whether there's any use for Irrlicht's proprietary scene format
-    // outside Irrlicht ...
-    // This also applies to the above function of FindSuitableMultiple and ClampSpline which are
-    // solely used in this function
-
-    if (root->animators.empty()) {
-        return;
-    }
-    unsigned int total(0);
-    for (std::list<Animator>::iterator it = root->animators.begin(); it != root->animators.end(); ++it) {
-        if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) {
-            ASSIMP_LOG_WARN("IRR: Skipping unknown or unsupported animator");
-            continue;
-        }
-        ++total;
-    }
-    if (!total) {
-        return;
-    } else if (1 == total) {
-        ASSIMP_LOG_WARN("IRR: Adding dummy nodes to simulate multiple animators");
-    }
-
-    // NOTE: 1 tick == i millisecond
-
-    unsigned int cur = 0;
-    for (std::list<Animator>::iterator it = root->animators.begin();
-            it != root->animators.end(); ++it) {
-        if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) continue;
-
-        Animator &in = *it;
-        aiNodeAnim *anim = new aiNodeAnim();
-
-        if (cur != total - 1) {
-            // Build a new name - a prefix instead of a suffix because it is
-            // easier to check against
-            anim->mNodeName.length = ::ai_snprintf(anim->mNodeName.data, MAXLEN,
-                    "$INST_DUMMY_%i_%s", total - 1,
-                    (root->name.length() ? root->name.c_str() : ""));
-
-            // we'll also need to insert a dummy in the node hierarchy.
-            aiNode *dummy = new aiNode();
-
-            for (unsigned int i = 0; i < real->mParent->mNumChildren; ++i)
-                if (real->mParent->mChildren[i] == real)
-                    real->mParent->mChildren[i] = dummy;
-
-            dummy->mParent = real->mParent;
-            dummy->mName = anim->mNodeName;
-
-            dummy->mNumChildren = 1;
-            dummy->mChildren = new aiNode *[dummy->mNumChildren];
-            dummy->mChildren[0] = real;
-
-            // the transformation matrix of the dummy node is the identity
-
-            real->mParent = dummy;
-        } else
-            anim->mNodeName.Set(root->name);
-        ++cur;
-
-        switch (in.type) {
-        case Animator::ROTATION: {
-            // -----------------------------------------------------
-            // find out how long a full rotation will take
-            // This is the least common multiple of 360.f and all
-            // three euler angles. Although we'll surely find a
-            // possible multiple (haha) it could be somewhat large
-            // for our purposes. So we need to modify the angles
-            // here in order to get good results.
-            // -----------------------------------------------------
-            int angles[3];
-            angles[0] = (int)(in.direction.x * 100);
-            angles[1] = (int)(in.direction.y * 100);
-            angles[2] = (int)(in.direction.z * 100);
-
-            angles[0] %= 360;
-            angles[1] %= 360;
-            angles[2] %= 360;
-
-            if ((angles[0] * angles[1]) != 0 && (angles[1] * angles[2]) != 0) {
-                FindSuitableMultiple(angles[0]);
-                FindSuitableMultiple(angles[1]);
-                FindSuitableMultiple(angles[2]);
-            }
-
-            int lcm = 360;
-
-            if (angles[0])
-                lcm = Math::lcm(lcm, angles[0]);
-
-            if (angles[1])
-                lcm = Math::lcm(lcm, angles[1]);
-
-            if (angles[2])
-                lcm = Math::lcm(lcm, angles[2]);
-
-            if (360 == lcm)
-                break;
-
-#if 0
-                // This can be a division through zero, but we don't care
-                float f1 = (float)lcm / angles[0];
-                float f2 = (float)lcm / angles[1];
-                float f3 = (float)lcm / angles[2];
-#endif
-
-            // find out how many time units we'll need for the finest
-            // track (in seconds) - this defines the number of output
-            // keys (fps * seconds)
-            float max = 0.f;
-            if (angles[0])
-                max = (float)lcm / angles[0];
-            if (angles[1])
-                max = std::max(max, (float)lcm / angles[1]);
-            if (angles[2])
-                max = std::max(max, (float)lcm / angles[2]);
-
-            anim->mNumRotationKeys = (unsigned int)(max * fps);
-            anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
-
-            // begin with a zero angle
-            aiVector3D angle;
-            for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
-                // build the quaternion for the given euler angles
-                aiQuatKey &q = anim->mRotationKeys[i];
-
-                q.mValue = aiQuaternion(angle.x, angle.y, angle.z);
-                q.mTime = (double)i;
-
-                // increase the angle
-                angle += in.direction;
-            }
-
-            // This animation is repeated and repeated ...
-            anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
-        } break;
-
-        case Animator::FLY_CIRCLE: {
-            // -----------------------------------------------------
-            // Find out how much time we'll need to perform a
-            // full circle.
-            // -----------------------------------------------------
-            const double seconds = (1. / in.speed) / 1000.;
-            const double tdelta = 1000. / fps;
-
-            anim->mNumPositionKeys = (unsigned int)(fps * seconds);
-            anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
-
-            // from Irrlicht, what else should we do than copying it?
-            aiVector3D vecU, vecV;
-            if (in.direction.y) {
-                vecV = aiVector3D(50, 0, 0) ^ in.direction;
-            } else
-                vecV = aiVector3D(0, 50, 00) ^ in.direction;
-            vecV.Normalize();
-            vecU = (vecV ^ in.direction).Normalize();
-
-            // build the output keys
-            for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
-                aiVectorKey &key = anim->mPositionKeys[i];
-                key.mTime = i * tdelta;
-
-                const ai_real t = (ai_real)(in.speed * key.mTime);
-                key.mValue = in.circleCenter + in.circleRadius * ((vecU * std::cos(t)) + (vecV * std::sin(t)));
-            }
-
-            // This animation is repeated and repeated ...
-            anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
-        } break;
-
-        case Animator::FLY_STRAIGHT: {
-            anim->mPostState = anim->mPreState = (in.loop ? aiAnimBehaviour_REPEAT : aiAnimBehaviour_CONSTANT);
-            const double seconds = in.timeForWay / 1000.;
-            const double tdelta = 1000. / fps;
-
-            anim->mNumPositionKeys = (unsigned int)(fps * seconds);
-            anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
-
-            aiVector3D diff = in.direction - in.circleCenter;
-            const ai_real lengthOfWay = diff.Length();
-            diff.Normalize();
-
-            const double timeFactor = lengthOfWay / in.timeForWay;
-
-            // build the output keys
-            for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
-                aiVectorKey &key = anim->mPositionKeys[i];
-                key.mTime = i * tdelta;
-                key.mValue = in.circleCenter + diff * ai_real(timeFactor * key.mTime);
-            }
-        } break;
-
-        case Animator::FOLLOW_SPLINE: {
-            // repeat outside the defined time range
-            anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
-            const int size = (int)in.splineKeys.size();
-            if (!size) {
-                // We have no point in the spline. That's bad. Really bad.
-                ASSIMP_LOG_WARN("IRR: Spline animators with no points defined");
-
-                delete anim;
-                anim = nullptr;
-                break;
-            } else if (size == 1) {
-                // We have just one point in the spline so we don't need the full calculation
-                anim->mNumPositionKeys = 1;
-                anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
-
-                anim->mPositionKeys[0].mValue = in.splineKeys[0].mValue;
-                anim->mPositionKeys[0].mTime = 0.f;
-                break;
-            }
-
-            unsigned int ticksPerFull = 15;
-            anim->mNumPositionKeys = (unsigned int)(ticksPerFull * fps);
-            anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
-
-            for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
-                aiVectorKey &key = anim->mPositionKeys[i];
-
-                const ai_real dt = (i * in.speed * ai_real(0.001));
-                const ai_real u = dt - std::floor(dt);
-                const int idx = (int)std::floor(dt) % size;
-
-                // get the 4 current points to evaluate the spline
-                const aiVector3D &p0 = in.splineKeys[ClampSpline(idx - 1, size)].mValue;
-                const aiVector3D &p1 = in.splineKeys[ClampSpline(idx + 0, size)].mValue;
-                const aiVector3D &p2 = in.splineKeys[ClampSpline(idx + 1, size)].mValue;
-                const aiVector3D &p3 = in.splineKeys[ClampSpline(idx + 2, size)].mValue;
-
-                // compute polynomials
-                const ai_real u2 = u * u;
-                const ai_real u3 = u2 * 2;
-
-                const ai_real h1 = ai_real(2.0) * u3 - ai_real(3.0) * u2 + ai_real(1.0);
-                const ai_real h2 = ai_real(-2.0) * u3 + ai_real(3.0) * u3;
-                const ai_real h3 = u3 - ai_real(2.0) * u3;
-                const ai_real h4 = u3 - u2;
-
-                // compute the spline tangents
-                const aiVector3D t1 = (p2 - p0) * in.tightness;
-                aiVector3D t2 = (p3 - p1) * in.tightness;
-
-                // and use them to get the interpolated point
-                t2 = (h1 * p1 + p2 * h2 + t1 * h3 + h4 * t2);
-
-                // build a simple translation matrix from it
-                key.mValue = t2;
-                key.mTime = (double)i;
-            }
-        } break;
-        default:
-            // UNKNOWN , OTHER
-            break;
-        };
-        if (anim) {
-            anims.push_back(anim);
-            ++total;
-        }
-    }
+	ai_assert(nullptr != root && nullptr != real);
+
+	// XXX totally WIP - doesn't produce proper results, need to evaluate
+	// whether there's any use for Irrlicht's proprietary scene format
+	// outside Irrlicht ...
+	// This also applies to the above function of FindSuitableMultiple and ClampSpline which are
+	// solely used in this function
+
+	if (root->animators.empty()) {
+		return;
+	}
+	unsigned int total(0);
+	for (std::list<Animator>::iterator it = root->animators.begin(); it != root->animators.end(); ++it) {
+		if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) {
+			ASSIMP_LOG_WARN("IRR: Skipping unknown or unsupported animator");
+			continue;
+		}
+		++total;
+	}
+	if (!total) {
+		return;
+	} else if (1 == total) {
+		ASSIMP_LOG_WARN("IRR: Adding dummy nodes to simulate multiple animators");
+	}
+
+	// NOTE: 1 tick == i millisecond
+
+	unsigned int cur = 0;
+	for (std::list<Animator>::iterator it = root->animators.begin();
+			it != root->animators.end(); ++it) {
+		if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) continue;
+
+		Animator &in = *it;
+		aiNodeAnim *anim = new aiNodeAnim();
+
+		if (cur != total - 1) {
+			// Build a new name - a prefix instead of a suffix because it is
+			// easier to check against
+			anim->mNodeName.length = ::ai_snprintf(anim->mNodeName.data, MAXLEN,
+					"$INST_DUMMY_%i_%s", total - 1,
+					(root->name.length() ? root->name.c_str() : ""));
+
+			// we'll also need to insert a dummy in the node hierarchy.
+			aiNode *dummy = new aiNode();
+
+			for (unsigned int i = 0; i < real->mParent->mNumChildren; ++i)
+				if (real->mParent->mChildren[i] == real)
+					real->mParent->mChildren[i] = dummy;
+
+			dummy->mParent = real->mParent;
+			dummy->mName = anim->mNodeName;
+
+			dummy->mNumChildren = 1;
+			dummy->mChildren = new aiNode *[dummy->mNumChildren];
+			dummy->mChildren[0] = real;
+
+			// the transformation matrix of the dummy node is the identity
+
+			real->mParent = dummy;
+		} else
+			anim->mNodeName.Set(root->name);
+		++cur;
+
+		switch (in.type) {
+			case Animator::ROTATION: {
+				// -----------------------------------------------------
+				// find out how long a full rotation will take
+				// This is the least common multiple of 360.f and all
+				// three euler angles. Although we'll surely find a
+				// possible multiple (haha) it could be somewhat large
+				// for our purposes. So we need to modify the angles
+				// here in order to get good results.
+				// -----------------------------------------------------
+				int angles[3];
+				angles[0] = (int)(in.direction.x * 100);
+				angles[1] = (int)(in.direction.y * 100);
+				angles[2] = (int)(in.direction.z * 100);
+
+				angles[0] %= 360;
+				angles[1] %= 360;
+				angles[2] %= 360;
+
+				if ((angles[0] * angles[1]) != 0 && (angles[1] * angles[2]) != 0) {
+					FindSuitableMultiple(angles[0]);
+					FindSuitableMultiple(angles[1]);
+					FindSuitableMultiple(angles[2]);
+				}
+
+				int lcm = 360;
+
+				if (angles[0])
+					lcm = Math::lcm(lcm, angles[0]);
+
+				if (angles[1])
+					lcm = Math::lcm(lcm, angles[1]);
+
+				if (angles[2])
+					lcm = Math::lcm(lcm, angles[2]);
+
+				if (360 == lcm)
+					break;
+
+
+				// find out how many time units we'll need for the finest
+				// track (in seconds) - this defines the number of output
+				// keys (fps * seconds)
+				float max = 0.f;
+				if (angles[0])
+					max = (float)lcm / angles[0];
+				if (angles[1])
+					max = std::max(max, (float)lcm / angles[1]);
+				if (angles[2])
+					max = std::max(max, (float)lcm / angles[2]);
+
+				anim->mNumRotationKeys = (unsigned int)(max * fps);
+				anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
+
+				// begin with a zero angle
+				aiVector3D angle;
+				for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
+					// build the quaternion for the given euler angles
+					aiQuatKey &q = anim->mRotationKeys[i];
+
+					q.mValue = aiQuaternion(angle.x, angle.y, angle.z);
+					q.mTime = (double)i;
+
+					// increase the angle
+					angle += in.direction;
+				}
+
+				// This animation is repeated and repeated ...
+				anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
+			} break;
+
+			case Animator::FLY_CIRCLE: {
+				// -----------------------------------------------------
+				// Find out how much time we'll need to perform a
+				// full circle.
+				// -----------------------------------------------------
+				const double seconds = (1. / in.speed) / 1000.;
+				const double tdelta = 1000. / fps;
+
+				anim->mNumPositionKeys = (unsigned int)(fps * seconds);
+				anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
+
+				// from Irrlicht, what else should we do than copying it?
+				aiVector3D vecU, vecV;
+				if (in.direction.y) {
+					vecV = aiVector3D(50, 0, 0) ^ in.direction;
+				} else
+					vecV = aiVector3D(0, 50, 00) ^ in.direction;
+				vecV.Normalize();
+				vecU = (vecV ^ in.direction).Normalize();
+
+				// build the output keys
+				for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
+					aiVectorKey &key = anim->mPositionKeys[i];
+					key.mTime = i * tdelta;
+
+					const ai_real t = (ai_real)(in.speed * key.mTime);
+					key.mValue = in.circleCenter + in.circleRadius * ((vecU * std::cos(t)) + (vecV * std::sin(t)));
+				}
+
+				// This animation is repeated and repeated ...
+				anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
+			} break;
+
+			case Animator::FLY_STRAIGHT: {
+				anim->mPostState = anim->mPreState = (in.loop ? aiAnimBehaviour_REPEAT : aiAnimBehaviour_CONSTANT);
+				const double seconds = in.timeForWay / 1000.;
+				const double tdelta = 1000. / fps;
+
+				anim->mNumPositionKeys = (unsigned int)(fps * seconds);
+				anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
+
+				aiVector3D diff = in.direction - in.circleCenter;
+				const ai_real lengthOfWay = diff.Length();
+				diff.Normalize();
+
+				const double timeFactor = lengthOfWay / in.timeForWay;
+
+				// build the output keys
+				for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
+					aiVectorKey &key = anim->mPositionKeys[i];
+					key.mTime = i * tdelta;
+					key.mValue = in.circleCenter + diff * ai_real(timeFactor * key.mTime);
+				}
+			} break;
+
+			case Animator::FOLLOW_SPLINE: {
+				// repeat outside the defined time range
+				anim->mPostState = anim->mPreState = aiAnimBehaviour_REPEAT;
+				const int size = (int)in.splineKeys.size();
+				if (!size) {
+					// We have no point in the spline. That's bad. Really bad.
+					ASSIMP_LOG_WARN("IRR: Spline animators with no points defined");
+
+					delete anim;
+					anim = nullptr;
+					break;
+				} else if (size == 1) {
+					// We have just one point in the spline so we don't need the full calculation
+					anim->mNumPositionKeys = 1;
+					anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
+
+					anim->mPositionKeys[0].mValue = in.splineKeys[0].mValue;
+					anim->mPositionKeys[0].mTime = 0.f;
+					break;
+				}
+
+				unsigned int ticksPerFull = 15;
+				anim->mNumPositionKeys = (unsigned int)(ticksPerFull * fps);
+				anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
+
+				for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
+					aiVectorKey &key = anim->mPositionKeys[i];
+
+					const ai_real dt = (i * in.speed * ai_real(0.001));
+					const ai_real u = dt - std::floor(dt);
+					const int idx = (int)std::floor(dt) % size;
+
+					// get the 4 current points to evaluate the spline
+					const aiVector3D &p0 = in.splineKeys[ClampSpline(idx - 1, size)].mValue;
+					const aiVector3D &p1 = in.splineKeys[ClampSpline(idx + 0, size)].mValue;
+					const aiVector3D &p2 = in.splineKeys[ClampSpline(idx + 1, size)].mValue;
+					const aiVector3D &p3 = in.splineKeys[ClampSpline(idx + 2, size)].mValue;
+
+					// compute polynomials
+					const ai_real u2 = u * u;
+					const ai_real u3 = u2 * 2;
+
+					const ai_real h1 = ai_real(2.0) * u3 - ai_real(3.0) * u2 + ai_real(1.0);
+					const ai_real h2 = ai_real(-2.0) * u3 + ai_real(3.0) * u3;
+					const ai_real h3 = u3 - ai_real(2.0) * u3;
+					const ai_real h4 = u3 - u2;
+
+					// compute the spline tangents
+					const aiVector3D t1 = (p2 - p0) * in.tightness;
+					aiVector3D t2 = (p3 - p1) * in.tightness;
+
+					// and use them to get the interpolated point
+					t2 = (h1 * p1 + p2 * h2 + t1 * h3 + h4 * t2);
+
+					// build a simple translation matrix from it
+					key.mValue = t2;
+					key.mTime = (double)i;
+				}
+			} break;
+			default:
+				// UNKNOWN , OTHER
+				break;
+		};
+		if (anim) {
+			anims.push_back(anim);
+			++total;
+		}
+	}
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // This function is maybe more generic than we'd need it here
 // This function is maybe more generic than we'd need it here
 void SetupMapping(aiMaterial *mat, aiTextureMapping mode, const aiVector3D &axis = aiVector3D(0.f, 0.f, -1.f)) {
 void SetupMapping(aiMaterial *mat, aiTextureMapping mode, const aiVector3D &axis = aiVector3D(0.f, 0.f, -1.f)) {
-    // Check whether there are texture properties defined - setup
-    // the desired texture mapping mode for all of them and ignore
-    // all UV settings we might encounter. WE HAVE NO UVS!
-
-    std::vector<aiMaterialProperty *> p;
-    p.reserve(mat->mNumProperties + 1);
-
-    for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
-        aiMaterialProperty *prop = mat->mProperties[i];
-        if (!::strcmp(prop->mKey.data, "$tex.file")) {
-            // Setup the mapping key
-            aiMaterialProperty *m = new aiMaterialProperty();
-            m->mKey.Set("$tex.mapping");
-            m->mIndex = prop->mIndex;
-            m->mSemantic = prop->mSemantic;
-            m->mType = aiPTI_Integer;
-
-            m->mDataLength = 4;
-            m->mData = new char[4];
-            *((int *)m->mData) = mode;
-
-            p.push_back(prop);
-            p.push_back(m);
-
-            // Setup the mapping axis
-            if (mode == aiTextureMapping_CYLINDER || mode == aiTextureMapping_PLANE || mode == aiTextureMapping_SPHERE) {
-                m = new aiMaterialProperty();
-                m->mKey.Set("$tex.mapaxis");
-                m->mIndex = prop->mIndex;
-                m->mSemantic = prop->mSemantic;
-                m->mType = aiPTI_Float;
-
-                m->mDataLength = 12;
-                m->mData = new char[12];
-                *((aiVector3D *)m->mData) = axis;
-                p.push_back(m);
-            }
-        } else if (!::strcmp(prop->mKey.data, "$tex.uvwsrc")) {
-            delete mat->mProperties[i];
-        } else
-            p.push_back(prop);
-    }
-
-    if (p.empty()) return;
+	if (nullptr == mat) {
+		return;
+	}
 
 
-    // rebuild the output array
-    if (p.size() > mat->mNumAllocated) {
-        delete[] mat->mProperties;
-        mat->mProperties = new aiMaterialProperty *[p.size() * 2];
-
-        mat->mNumAllocated = static_cast<unsigned int>(p.size() * 2);
-    }
-    mat->mNumProperties = (unsigned int)p.size();
-    ::memcpy(mat->mProperties, &p[0], sizeof(void *) * mat->mNumProperties);
+    // Check whether there are texture properties defined - setup
+	// the desired texture mapping mode for all of them and ignore
+	// all UV settings we might encounter. WE HAVE NO UVS!
+
+	std::vector<aiMaterialProperty *> p;
+	p.reserve(mat->mNumProperties + 1);
+
+	for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
+		aiMaterialProperty *prop = mat->mProperties[i];
+		if (!::strcmp(prop->mKey.data, "$tex.file")) {
+			// Setup the mapping key
+			aiMaterialProperty *m = new aiMaterialProperty();
+			m->mKey.Set("$tex.mapping");
+			m->mIndex = prop->mIndex;
+			m->mSemantic = prop->mSemantic;
+			m->mType = aiPTI_Integer;
+
+			m->mDataLength = 4;
+			m->mData = new char[4];
+			*((int *)m->mData) = mode;
+
+			p.push_back(prop);
+			p.push_back(m);
+
+			// Setup the mapping axis
+			if (mode == aiTextureMapping_CYLINDER || mode == aiTextureMapping_PLANE || mode == aiTextureMapping_SPHERE) {
+				m = new aiMaterialProperty();
+				m->mKey.Set("$tex.mapaxis");
+				m->mIndex = prop->mIndex;
+				m->mSemantic = prop->mSemantic;
+				m->mType = aiPTI_Float;
+
+				m->mDataLength = 12;
+				m->mData = new char[12];
+				*((aiVector3D *)m->mData) = axis;
+				p.push_back(m);
+			}
+		} else if (!::strcmp(prop->mKey.data, "$tex.uvwsrc")) {
+			delete mat->mProperties[i];
+		} else
+			p.push_back(prop);
+	}
+
+	if (p.empty()) return;
+
+	// rebuild the output array
+	if (p.size() > mat->mNumAllocated) {
+		delete[] mat->mProperties;
+		mat->mProperties = new aiMaterialProperty *[p.size() * 2];
+
+		mat->mNumAllocated = static_cast<unsigned int>(p.size() * 2);
+	}
+	mat->mNumProperties = (unsigned int)p.size();
+	::memcpy(mat->mProperties, &p[0], sizeof(void *) * mat->mNumProperties);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
 void IRRImporter::GenerateGraph(Node *root, aiNode *rootOut, aiScene *scene,
-        BatchLoader &batch,
-        std::vector<aiMesh *> &meshes,
-        std::vector<aiNodeAnim *> &anims,
-        std::vector<AttachmentInfo> &attach,
-        std::vector<aiMaterial *> &materials,
-        unsigned int &defMatIdx) {
-    unsigned int oldMeshSize = (unsigned int)meshes.size();
-    //unsigned int meshTrafoAssign = 0;
-
-    // Now determine the type of the node
-    switch (root->type) {
-    case Node::ANIMMESH:
-    case Node::MESH: {
-        if (!root->meshPath.length())
-            break;
-
-        // Get the loaded mesh from the scene and add it to
-        // the list of all scenes to be attached to the
-        // graph we're currently building
-        aiScene *localScene = batch.GetImport(root->id);
-        if (!localScene) {
-            ASSIMP_LOG_ERROR("IRR: Unable to load external file: " + root->meshPath);
-            break;
-        }
-        attach.push_back(AttachmentInfo(localScene, rootOut));
-
-        // Now combine the material we've loaded for this mesh
-        // with the real materials we got from the file. As we
-        // don't execute any pp-steps on the file, the numbers
-        // should be equal. If they are not, we can impossibly
-        // do this  ...
-        if (root->materials.size() != (unsigned int)localScene->mNumMaterials) {
-            ASSIMP_LOG_WARN("IRR: Failed to match imported materials "
-                            "with the materials found in the IRR scene file");
-
-            break;
-        }
-        for (unsigned int i = 0; i < localScene->mNumMaterials; ++i) {
-            // Delete the old material, we don't need it anymore
-            delete localScene->mMaterials[i];
-
-            std::pair<aiMaterial *, unsigned int> &src = root->materials[i];
-            localScene->mMaterials[i] = src.first;
-        }
-
-        // NOTE: Each mesh should have exactly one material assigned,
-        // but we do it in a separate loop if this behaviour changes
-        // in future.
-        for (unsigned int i = 0; i < localScene->mNumMeshes; ++i) {
-            // Process material flags
-            aiMesh *mesh = localScene->mMeshes[i];
-
-            // If "trans_vertex_alpha" mode is enabled, search all vertex colors
-            // and check whether they have a common alpha value. This is quite
-            // often the case so we can simply extract it to a shared oacity
-            // value.
-            std::pair<aiMaterial *, unsigned int> &src = root->materials[mesh->mMaterialIndex];
-            aiMaterial *mat = (aiMaterial *)src.first;
-
-            if (mesh->HasVertexColors(0) && src.second & AI_IRRMESH_MAT_trans_vertex_alpha) {
-                bool bdo = true;
-                for (unsigned int a = 1; a < mesh->mNumVertices; ++a) {
-
-                    if (mesh->mColors[0][a].a != mesh->mColors[0][a - 1].a) {
-                        bdo = false;
-                        break;
-                    }
-                }
-                if (bdo) {
-                    ASSIMP_LOG_INFO("IRR: Replacing mesh vertex alpha with common opacity");
-
-                    for (unsigned int a = 0; a < mesh->mNumVertices; ++a)
-                        mesh->mColors[0][a].a = 1.f;
-
-                    mat->AddProperty(&mesh->mColors[0][0].a, 1, AI_MATKEY_OPACITY);
-                }
-            }
-
-            // If we have a second texture coordinate set and a second texture
-            // (either lightmap, normalmap, 2layered material) we need to
-            // setup the correct UV index for it. The texture can either
-            // be diffuse (lightmap & 2layer) or a normal map (normal & parallax)
-            if (mesh->HasTextureCoords(1)) {
-
-                int idx = 1;
-                if (src.second & (AI_IRRMESH_MAT_solid_2layer | AI_IRRMESH_MAT_lightmap)) {
-                    mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(0));
-                } else if (src.second & AI_IRRMESH_MAT_normalmap_solid) {
-                    mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
-                }
-            }
-        }
-    } break;
-
-    case Node::LIGHT:
-    case Node::CAMERA:
-
-        // We're already finished with lights and cameras
-        break;
-
-    case Node::SPHERE: {
-        // Generate the sphere model. Our input parameter to
-        // the sphere generation algorithm is the number of
-        // subdivisions of each triangle - but here we have
-        // the number of poylgons on a specific axis. Just
-        // use some hardcoded limits to approximate this ...
-        unsigned int mul = root->spherePolyCountX * root->spherePolyCountY;
-        if (mul < 100)
-            mul = 2;
-        else if (mul < 300)
-            mul = 3;
-        else
-            mul = 4;
-
-        meshes.push_back(StandardShapes::MakeMesh(mul,
-                &StandardShapes::MakeSphere));
-
-        // Adjust scaling
-        root->scaling *= root->sphereRadius / 2;
-
-        // Copy one output material
-        CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
-
-        // Now adjust this output material - if there is a first texture
-        // set, setup spherical UV mapping around the Y axis.
-        SetupMapping((aiMaterial *)materials.back(), aiTextureMapping_SPHERE);
-    } break;
-
-    case Node::CUBE: {
-        // Generate an unit cube first
-        meshes.push_back(StandardShapes::MakeMesh(
-                &StandardShapes::MakeHexahedron));
-
-        // Adjust scaling
-        root->scaling *= root->sphereRadius;
-
-        // Copy one output material
-        CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
-
-        // Now adjust this output material - if there is a first texture
-        // set, setup cubic UV mapping
-        SetupMapping((aiMaterial *)materials.back(), aiTextureMapping_BOX);
-    } break;
-
-    case Node::SKYBOX: {
-        // A skybox is defined by six materials
-        if (root->materials.size() < 6) {
-            ASSIMP_LOG_ERROR("IRR: There should be six materials for a skybox");
-            break;
-        }
-
-        // copy those materials and generate 6 meshes for our new skybox
-        materials.reserve(materials.size() + 6);
-        for (unsigned int i = 0; i < 6; ++i)
-            materials.insert(materials.end(), root->materials[i].first);
-
-        BuildSkybox(meshes, materials);
-
-        // *************************************************************
-        // Skyboxes will require a different code path for rendering,
-        // so there must be a way for the user to add special support
-        // for IRR skyboxes. We add a 'IRR.SkyBox_' prefix to the node.
-        // *************************************************************
-        root->name = "IRR.SkyBox_" + root->name;
-        ASSIMP_LOG_INFO("IRR: Loading skybox, this will "
-                        "require special handling to be displayed correctly");
-    } break;
-
-    case Node::TERRAIN: {
-        // to support terrains, we'd need to have a texture decoder
-        ASSIMP_LOG_ERROR("IRR: Unsupported node - TERRAIN");
-    } break;
-    default:
-        // DUMMY
-        break;
-    };
-
-    // Check whether we added a mesh (or more than one ...). In this case
-    // we'll also need to attach it to the node
-    if (oldMeshSize != (unsigned int)meshes.size()) {
-
-        rootOut->mNumMeshes = (unsigned int)meshes.size() - oldMeshSize;
-        rootOut->mMeshes = new unsigned int[rootOut->mNumMeshes];
-
-        for (unsigned int a = 0; a < rootOut->mNumMeshes; ++a) {
-            rootOut->mMeshes[a] = oldMeshSize + a;
-        }
-    }
-
-    // Setup the name of this node
-    rootOut->mName.Set(root->name);
-
-    // Now compute the final local transformation matrix of the
-    // node from the given translation, rotation and scaling values.
-    // (the rotation is given in Euler angles, XYZ order)
-    //std::swap((float&)root->rotation.z,(float&)root->rotation.y);
-    rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation));
-
-    // apply scaling
-    aiMatrix4x4 &mat = rootOut->mTransformation;
-    mat.a1 *= root->scaling.x;
-    mat.b1 *= root->scaling.x;
-    mat.c1 *= root->scaling.x;
-    mat.a2 *= root->scaling.y;
-    mat.b2 *= root->scaling.y;
-    mat.c2 *= root->scaling.y;
-    mat.a3 *= root->scaling.z;
-    mat.b3 *= root->scaling.z;
-    mat.c3 *= root->scaling.z;
-
-    // apply translation
-    mat.a4 += root->position.x;
-    mat.b4 += root->position.y;
-    mat.c4 += root->position.z;
-
-    // now compute animations for the node
-    ComputeAnimations(root, rootOut, anims);
-
-    // Add all children recursively. First allocate enough storage
-    // for them, then call us again
-    rootOut->mNumChildren = (unsigned int)root->children.size();
-    if (rootOut->mNumChildren) {
-
-        rootOut->mChildren = new aiNode *[rootOut->mNumChildren];
-        for (unsigned int i = 0; i < rootOut->mNumChildren; ++i) {
-
-            aiNode *node = rootOut->mChildren[i] = new aiNode();
-            node->mParent = rootOut;
-            GenerateGraph(root->children[i], node, scene, batch, meshes,
-                    anims, attach, materials, defMatIdx);
-        }
-    }
+		BatchLoader &batch,
+		std::vector<aiMesh *> &meshes,
+		std::vector<aiNodeAnim *> &anims,
+		std::vector<AttachmentInfo> &attach,
+		std::vector<aiMaterial *> &materials,
+		unsigned int &defMatIdx) {
+	unsigned int oldMeshSize = (unsigned int)meshes.size();
+	//unsigned int meshTrafoAssign = 0;
+
+	// Now determine the type of the node
+	switch (root->type) {
+		case Node::ANIMMESH:
+		case Node::MESH: {
+			if (!root->meshPath.length())
+				break;
+
+			// Get the loaded mesh from the scene and add it to
+			// the list of all scenes to be attached to the
+			// graph we're currently building
+			aiScene *localScene = batch.GetImport(root->id);
+			if (!localScene) {
+				ASSIMP_LOG_ERROR("IRR: Unable to load external file: " + root->meshPath);
+				break;
+			}
+			attach.push_back(AttachmentInfo(localScene, rootOut));
+
+			// Now combine the material we've loaded for this mesh
+			// with the real materials we got from the file. As we
+			// don't execute any pp-steps on the file, the numbers
+			// should be equal. If they are not, we can impossibly
+			// do this  ...
+			if (root->materials.size() != (unsigned int)localScene->mNumMaterials) {
+				ASSIMP_LOG_WARN("IRR: Failed to match imported materials "
+								"with the materials found in the IRR scene file");
+
+				break;
+			}
+			for (unsigned int i = 0; i < localScene->mNumMaterials; ++i) {
+				// Delete the old material, we don't need it anymore
+				delete localScene->mMaterials[i];
+
+				std::pair<aiMaterial *, unsigned int> &src = root->materials[i];
+				localScene->mMaterials[i] = src.first;
+			}
+
+			// NOTE: Each mesh should have exactly one material assigned,
+			// but we do it in a separate loop if this behavior changes
+			// in future.
+			for (unsigned int i = 0; i < localScene->mNumMeshes; ++i) {
+				// Process material flags
+				aiMesh *mesh = localScene->mMeshes[i];
+
+				// If "trans_vertex_alpha" mode is enabled, search all vertex colors
+				// and check whether they have a common alpha value. This is quite
+				// often the case so we can simply extract it to a shared oacity
+				// value.
+				std::pair<aiMaterial *, unsigned int> &src = root->materials[mesh->mMaterialIndex];
+				aiMaterial *mat = (aiMaterial *)src.first;
+
+				if (mesh->HasVertexColors(0) && src.second & AI_IRRMESH_MAT_trans_vertex_alpha) {
+					bool bdo = true;
+					for (unsigned int a = 1; a < mesh->mNumVertices; ++a) {
+
+						if (mesh->mColors[0][a].a != mesh->mColors[0][a - 1].a) {
+							bdo = false;
+							break;
+						}
+					}
+					if (bdo) {
+						ASSIMP_LOG_INFO("IRR: Replacing mesh vertex alpha with common opacity");
+
+						for (unsigned int a = 0; a < mesh->mNumVertices; ++a)
+							mesh->mColors[0][a].a = 1.f;
+
+						mat->AddProperty(&mesh->mColors[0][0].a, 1, AI_MATKEY_OPACITY);
+					}
+				}
+
+				// If we have a second texture coordinate set and a second texture
+				// (either light-map, normal-map, 2layered material) we need to
+				// setup the correct UV index for it. The texture can either
+				// be diffuse (light-map & 2layer) or a normal map (normal & parallax)
+				if (mesh->HasTextureCoords(1)) {
+
+					int idx = 1;
+					if (src.second & (AI_IRRMESH_MAT_solid_2layer | AI_IRRMESH_MAT_lightmap)) {
+						mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(0));
+					} else if (src.second & AI_IRRMESH_MAT_normalmap_solid) {
+						mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
+					}
+				}
+			}
+		} break;
+
+		case Node::LIGHT:
+		case Node::CAMERA:
+
+			// We're already finished with lights and cameras
+			break;
+
+		case Node::SPHERE: {
+			// Generate the sphere model. Our input parameter to
+			// the sphere generation algorithm is the number of
+			// subdivisions of each triangle - but here we have
+			// the number of polygons on a specific axis. Just
+			// use some hard-coded limits to approximate this ...
+			unsigned int mul = root->spherePolyCountX * root->spherePolyCountY;
+			if (mul < 100)
+				mul = 2;
+			else if (mul < 300)
+				mul = 3;
+			else
+				mul = 4;
+
+			meshes.push_back(StandardShapes::MakeMesh(mul,
+					&StandardShapes::MakeSphere));
+
+			// Adjust scaling
+			root->scaling *= root->sphereRadius / 2;
+
+			// Copy one output material
+			CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
+
+			// Now adjust this output material - if there is a first texture
+			// set, setup spherical UV mapping around the Y axis.
+			SetupMapping((aiMaterial *)materials.back(), aiTextureMapping_SPHERE);
+		} break;
+
+		case Node::CUBE: {
+			// Generate an unit cube first
+			meshes.push_back(StandardShapes::MakeMesh(
+					&StandardShapes::MakeHexahedron));
+
+			// Adjust scaling
+			root->scaling *= root->sphereRadius;
+
+			// Copy one output material
+			CopyMaterial(materials, root->materials, defMatIdx, meshes.back());
+
+			// Now adjust this output material - if there is a first texture
+			// set, setup cubic UV mapping
+			SetupMapping((aiMaterial *)materials.back(), aiTextureMapping_BOX);
+		} break;
+
+		case Node::SKYBOX: {
+			// A sky-box is defined by six materials
+			if (root->materials.size() < 6) {
+				ASSIMP_LOG_ERROR("IRR: There should be six materials for a skybox");
+				break;
+			}
+
+			// copy those materials and generate 6 meshes for our new sky-box
+			materials.reserve(materials.size() + 6);
+			for (unsigned int i = 0; i < 6; ++i)
+				materials.insert(materials.end(), root->materials[i].first);
+
+			BuildSkybox(meshes, materials);
+
+			// *************************************************************
+			// Skyboxes will require a different code path for rendering,
+			// so there must be a way for the user to add special support
+			// for IRR skyboxes. We add a 'IRR.SkyBox_' prefix to the node.
+			// *************************************************************
+			root->name = "IRR.SkyBox_" + root->name;
+			ASSIMP_LOG_INFO("IRR: Loading skybox, this will "
+							"require special handling to be displayed correctly");
+		} break;
+
+		case Node::TERRAIN: {
+			// to support terrains, we'd need to have a texture decoder
+			ASSIMP_LOG_ERROR("IRR: Unsupported node - TERRAIN");
+		} break;
+		default:
+			// DUMMY
+			break;
+	};
+
+	// Check whether we added a mesh (or more than one ...). In this case
+	// we'll also need to attach it to the node
+	if (oldMeshSize != (unsigned int)meshes.size()) {
+
+		rootOut->mNumMeshes = (unsigned int)meshes.size() - oldMeshSize;
+		rootOut->mMeshes = new unsigned int[rootOut->mNumMeshes];
+
+		for (unsigned int a = 0; a < rootOut->mNumMeshes; ++a) {
+			rootOut->mMeshes[a] = oldMeshSize + a;
+		}
+	}
+
+	// Setup the name of this node
+	rootOut->mName.Set(root->name);
+
+	// Now compute the final local transformation matrix of the
+	// node from the given translation, rotation and scaling values.
+	// (the rotation is given in Euler angles, XYZ order)
+	//std::swap((float&)root->rotation.z,(float&)root->rotation.y);
+	rootOut->mTransformation.FromEulerAnglesXYZ(AI_DEG_TO_RAD(root->rotation));
+
+	// apply scaling
+	aiMatrix4x4 &mat = rootOut->mTransformation;
+	mat.a1 *= root->scaling.x;
+	mat.b1 *= root->scaling.x;
+	mat.c1 *= root->scaling.x;
+	mat.a2 *= root->scaling.y;
+	mat.b2 *= root->scaling.y;
+	mat.c2 *= root->scaling.y;
+	mat.a3 *= root->scaling.z;
+	mat.b3 *= root->scaling.z;
+	mat.c3 *= root->scaling.z;
+
+	// apply translation
+	mat.a4 += root->position.x;
+	mat.b4 += root->position.y;
+	mat.c4 += root->position.z;
+
+	// now compute animations for the node
+	ComputeAnimations(root, rootOut, anims);
+
+	// Add all children recursively. First allocate enough storage
+	// for them, then call us again
+	rootOut->mNumChildren = (unsigned int)root->children.size();
+	if (rootOut->mNumChildren) {
+
+		rootOut->mChildren = new aiNode *[rootOut->mNumChildren];
+		for (unsigned int i = 0; i < rootOut->mNumChildren; ++i) {
+
+			aiNode *node = rootOut->mChildren[i] = new aiNode();
+			node->mParent = rootOut;
+			GenerateGraph(root->children[i], node, scene, batch, meshes,
+					anims, attach, materials, defMatIdx);
+		}
+	}
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 // Imports the given file into the given scene structure.
-void IRRImporter::InternReadFile(const std::string &pFile,
-        aiScene *pScene, IOSystem *pIOHandler) {
-    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
+void IRRImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
+	std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
 
 
-    // Check whether we can read from the file
-    if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open IRR file " + pFile + "");
-    }
+	// Check whether we can read from the file
+	if (file.get() == nullptr) {
+		throw DeadlyImportError("Failed to open IRR file " + pFile + "");
+	}
 
 
-    // Construct the irrXML parser
-    CIrrXML_IOStreamReader st(file.get());
-    reader = createIrrXMLReader((IFileReadCallBack *)&st);
-
-    // The root node of the scene
-    Node *root = new Node(Node::DUMMY);
-    root->parent = nullptr;
-    root->name = "<IRRSceneRoot>";
-
-    // Current node parent
-    Node *curParent = root;
-
-    // Scenegraph node we're currently working on
-    Node *curNode = nullptr;
-
-    // List of output cameras
-    std::vector<aiCamera *> cameras;
-
-    // List of output lights
-    std::vector<aiLight *> lights;
-
-    // Batch loader used to load external models
-    BatchLoader batch(pIOHandler);
-    //  batch.SetBasePath(pFile);
-
-    cameras.reserve(5);
-    lights.reserve(5);
-
-    bool inMaterials = false, inAnimator = false;
-    unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0;
-
-    // Parse the XML file
-    while (reader->read()) {
-        switch (reader->getNodeType()) {
-        case EXN_ELEMENT:
-
-            if (!ASSIMP_stricmp(reader->getNodeName(), "node")) {
-                // ***********************************************************************
-                /*  What we're going to do with the node depends
-                 *  on its type:
-                 *
-                 *  "mesh" - Load a mesh from an external file
-                 *  "cube" - Generate a cube
-                 *  "skybox" - Generate a skybox
-                 *  "light" - A light source
-                 *  "sphere" - Generate a sphere mesh
-                 *  "animatedMesh" - Load an animated mesh from an external file
-                 *    and join its animation channels with ours.
-                 *  "empty" - A dummy node
-                 *  "camera" - A camera
-                 *  "terrain" - a terrain node (data comes from a heightmap)
-                 *  "billboard", ""
-                 *
-                 *  Each of these nodes can be animated and all can have multiple
-                 *  materials assigned (except lights, cameras and dummies, of course).
-                 */
-                // ***********************************************************************
-                const char *sz = reader->getAttributeValueSafe("type");
-                Node *nd;
-                if (!ASSIMP_stricmp(sz, "mesh") || !ASSIMP_stricmp(sz, "octTree")) {
-                    // OctTree's and meshes are treated equally
-                    nd = new Node(Node::MESH);
-                } else if (!ASSIMP_stricmp(sz, "cube")) {
-                    nd = new Node(Node::CUBE);
-                    ++guessedMeshCnt;
-                    // meshes.push_back(StandardShapes::MakeMesh(&StandardShapes::MakeHexahedron));
-                } else if (!ASSIMP_stricmp(sz, "skybox")) {
-                    nd = new Node(Node::SKYBOX);
-                    guessedMeshCnt += 6;
-                } else if (!ASSIMP_stricmp(sz, "camera")) {
-                    nd = new Node(Node::CAMERA);
-
-                    // Setup a temporary name for the camera
-                    aiCamera *cam = new aiCamera();
-                    cam->mName.Set(nd->name);
-                    cameras.push_back(cam);
-                } else if (!ASSIMP_stricmp(sz, "light")) {
-                    nd = new Node(Node::LIGHT);
-
-                    // Setup a temporary name for the light
-                    aiLight *cam = new aiLight();
-                    cam->mName.Set(nd->name);
-                    lights.push_back(cam);
-                } else if (!ASSIMP_stricmp(sz, "sphere")) {
-                    nd = new Node(Node::SPHERE);
-                    ++guessedMeshCnt;
-                } else if (!ASSIMP_stricmp(sz, "animatedMesh")) {
-                    nd = new Node(Node::ANIMMESH);
-                } else if (!ASSIMP_stricmp(sz, "empty")) {
-                    nd = new Node(Node::DUMMY);
-                } else if (!ASSIMP_stricmp(sz, "terrain")) {
-                    nd = new Node(Node::TERRAIN);
-                } else if (!ASSIMP_stricmp(sz, "billBoard")) {
-                    // We don't support billboards, so ignore them
-                    ASSIMP_LOG_ERROR("IRR: Billboards are not supported by Assimp");
-                    nd = new Node(Node::DUMMY);
-                } else {
-                    ASSIMP_LOG_WARN("IRR: Found unknown node: " + std::string(sz));
-
-                    /*  We skip the contents of nodes we don't know.
-                     *  We parse the transformation and all animators
-                     *  and skip the rest.
+	// Construct the irrXML parser
+	XmlParser st;
+    if (!st.parse( file.get() )) {
+        return;
+    }
+    pugi::xml_node rootElement = st.getRootNode();
+
+	// The root node of the scene
+	Node *root = new Node(Node::DUMMY);
+	root->parent = nullptr;
+	root->name = "<IRRSceneRoot>";
+
+	// Current node parent
+	Node *curParent = root;
+
+	// Scene-graph node we're currently working on
+	Node *curNode = nullptr;
+
+	// List of output cameras
+	std::vector<aiCamera *> cameras;
+
+	// List of output lights
+	std::vector<aiLight *> lights;
+
+	// Batch loader used to load external models
+	BatchLoader batch(pIOHandler);
+	//  batch.SetBasePath(pFile);
+
+	cameras.reserve(5);
+	lights.reserve(5);
+
+	bool inMaterials = false, inAnimator = false;
+	unsigned int guessedAnimCnt = 0, guessedMeshCnt = 0, guessedMatCnt = 0;
+
+	// Parse the XML file
+
+	//while (reader->read())  {
+	for (pugi::xml_node child : rootElement.children())
+		switch (child.type()) {
+			case pugi::node_element:
+				if (!ASSIMP_stricmp(child.name(), "node")) {
+					// ***********************************************************************
+					/*  What we're going to do with the node depends
+                     *  on its type:
+                     *
+                     *  "mesh" - Load a mesh from an external file
+                     *  "cube" - Generate a cube
+                     *  "skybox" - Generate a skybox
+                     *  "light" - A light source
+                     *  "sphere" - Generate a sphere mesh
+                     *  "animatedMesh" - Load an animated mesh from an external file
+                     *    and join its animation channels with ours.
+                     *  "empty" - A dummy node
+                     *  "camera" - A camera
+                     *  "terrain" - a terrain node (data comes from a heightmap)
+                     *  "billboard", ""
+                     *
+                     *  Each of these nodes can be animated and all can have multiple
+                     *  materials assigned (except lights, cameras and dummies, of course).
                      */
                      */
-                    nd = new Node(Node::DUMMY);
-                }
-
-                /* Attach the newly created node to the scenegraph
-                 */
-                curNode = nd;
-                nd->parent = curParent;
-                curParent->children.push_back(nd);
-            } else if (!ASSIMP_stricmp(reader->getNodeName(), "materials")) {
-                inMaterials = true;
-            } else if (!ASSIMP_stricmp(reader->getNodeName(), "animators")) {
-                inAnimator = true;
-            } else if (!ASSIMP_stricmp(reader->getNodeName(), "attributes")) {
-                /*  We should have a valid node here
-                 *  FIX: no ... the scene root node is also contained in an attributes block
-                 */
-                if (!curNode) {
-#if 0
-                    ASSIMP_LOG_ERROR("IRR: Encountered <attributes> element, but "
-                        "there is no node active");
-#endif
-                    continue;
-                }
-
-                Animator *curAnim = nullptr;
-
-                // Materials can occur for nearly any type of node
-                if (inMaterials && curNode->type != Node::DUMMY) {
-                    /*  This is a material description - parse it!
+					// ***********************************************************************
+					//const char *sz = reader->getAttributeValueSafe("type");
+					pugi::xml_attribute attrib = child.attribute("type");
+					Node *nd;
+					if (!ASSIMP_stricmp(attrib.name(), "mesh") || !ASSIMP_stricmp(attrib.name(), "octTree")) {
+						// OctTree's and meshes are treated equally
+						nd = new Node(Node::MESH);
+					} else if (!ASSIMP_stricmp(attrib.name(), "cube")) {
+						nd = new Node(Node::CUBE);
+						++guessedMeshCnt;
+					} else if (!ASSIMP_stricmp(attrib.name(), "skybox")) {
+						nd = new Node(Node::SKYBOX);
+						guessedMeshCnt += 6;
+					} else if (!ASSIMP_stricmp(attrib.name(), "camera")) {
+						nd = new Node(Node::CAMERA);
+
+						// Setup a temporary name for the camera
+						aiCamera *cam = new aiCamera();
+						cam->mName.Set(nd->name);
+						cameras.push_back(cam);
+					} else if (!ASSIMP_stricmp(attrib.name(), "light")) {
+						nd = new Node(Node::LIGHT);
+
+						// Setup a temporary name for the light
+						aiLight *cam = new aiLight();
+						cam->mName.Set(nd->name);
+						lights.push_back(cam);
+					} else if (!ASSIMP_stricmp(attrib.name(), "sphere")) {
+						nd = new Node(Node::SPHERE);
+						++guessedMeshCnt;
+					} else if (!ASSIMP_stricmp(attrib.name(), "animatedMesh")) {
+						nd = new Node(Node::ANIMMESH);
+					} else if (!ASSIMP_stricmp(attrib.name(), "empty")) {
+						nd = new Node(Node::DUMMY);
+					} else if (!ASSIMP_stricmp(attrib.name(), "terrain")) {
+						nd = new Node(Node::TERRAIN);
+					} else if (!ASSIMP_stricmp(attrib.name(), "billBoard")) {
+						// We don't support billboards, so ignore them
+						ASSIMP_LOG_ERROR("IRR: Billboards are not supported by Assimp");
+						nd = new Node(Node::DUMMY);
+					} else {
+						ASSIMP_LOG_WARN("IRR: Found unknown node: " + std::string(attrib.name()));
+
+						/*  We skip the contents of nodes we don't know.
+                         *  We parse the transformation and all animators
+                         *  and skip the rest.
+                         */
+						nd = new Node(Node::DUMMY);
+					}
+
+					/* Attach the newly created node to the scene-graph
                      */
                      */
-                    curNode->materials.push_back(std::pair<aiMaterial *, unsigned int>());
-                    std::pair<aiMaterial *, unsigned int> &p = curNode->materials.back();
-
-                    p.first = ParseMaterial(p.second);
-
-                    ++guessedMatCnt;
-                    continue;
-                } else if (inAnimator) {
-                    /*  This is an animation path - add a new animator
-                     *  to the list.
+					curNode = nd;
+					nd->parent = curParent;
+					curParent->children.push_back(nd);
+				} else if (!ASSIMP_stricmp(child.name(), "materials")) {
+					inMaterials = true;
+				} else if (!ASSIMP_stricmp(child.name(), "animators")) {
+					inAnimator = true;
+				} else if (!ASSIMP_stricmp(child.name(), "attributes")) {
+					//  We should have a valid node here
+					//  FIX: no ... the scene root node is also contained in an attributes block
+					if (!curNode) {
+						continue;
+					}
+
+					Animator *curAnim = nullptr;
+
+					// Materials can occur for nearly any type of node
+					if (inMaterials && curNode->type != Node::DUMMY) {
+						//  This is a material description - parse it!
+						curNode->materials.push_back(std::pair<aiMaterial *, unsigned int>());
+						std::pair<aiMaterial *, unsigned int> &p = curNode->materials.back();
+
+						p.first = ParseMaterial(p.second);
+						++guessedMatCnt;
+						continue;
+					} else if (inAnimator) {
+						//  This is an animation path - add a new animator
+						//  to the list.
+						curNode->animators.push_back(Animator());
+						curAnim = &curNode->animators.back();
+
+						++guessedAnimCnt;
+					}
+
+					/*  Parse all elements in the attributes block
+                     *  and process them.
                      */
                      */
-                    curNode->animators.push_back(Animator());
-                    curAnim = &curNode->animators.back();
-
-                    ++guessedAnimCnt;
-                }
-
-                /*  Parse all elements in the attributes block
-                 *  and process them.
-                 */
-                while (reader->read()) {
-                    if (reader->getNodeType() == EXN_ELEMENT) {
-                        if (!ASSIMP_stricmp(reader->getNodeName(), "vector3d")) {
-                            VectorProperty prop;
-                            ReadVectorProperty(prop);
-
-                            if (inAnimator) {
-                                if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") {
-                                    // We store the rotation euler angles in 'direction'
-                                    curAnim->direction = prop.value;
-                                } else if (curAnim->type == Animator::FOLLOW_SPLINE) {
-                                    // Check whether the vector follows the PointN naming scheme,
-                                    // here N is the ONE-based index of the point
-                                    if (prop.name.length() >= 6 && prop.name.substr(0, 5) == "Point") {
-                                        // Add a new key to the list
-                                        curAnim->splineKeys.push_back(aiVectorKey());
-                                        aiVectorKey &key = curAnim->splineKeys.back();
-
-                                        // and parse its properties
-                                        key.mValue = prop.value;
-                                        key.mTime = strtoul10(&prop.name[5]);
-                                    }
-                                } else if (curAnim->type == Animator::FLY_CIRCLE) {
-                                    if (prop.name == "Center") {
-                                        curAnim->circleCenter = prop.value;
-                                    } else if (prop.name == "Direction") {
-                                        curAnim->direction = prop.value;
-
-                                        // From Irrlicht's source - a workaround for backward compatibility with Irrlicht 1.1
-                                        if (curAnim->direction == aiVector3D()) {
-                                            curAnim->direction = aiVector3D(0.f, 1.f, 0.f);
-                                        } else
-                                            curAnim->direction.Normalize();
-                                    }
-                                } else if (curAnim->type == Animator::FLY_STRAIGHT) {
-                                    if (prop.name == "Start") {
-                                        // We reuse the field here
-                                        curAnim->circleCenter = prop.value;
-                                    } else if (prop.name == "End") {
-                                        // We reuse the field here
-                                        curAnim->direction = prop.value;
-                                    }
-                                }
-                            } else {
-                                if (prop.name == "Position") {
-                                    curNode->position = prop.value;
-                                } else if (prop.name == "Rotation") {
-                                    curNode->rotation = prop.value;
-                                } else if (prop.name == "Scale") {
-                                    curNode->scaling = prop.value;
-                                } else if (Node::CAMERA == curNode->type) {
-                                    aiCamera *cam = cameras.back();
-                                    if (prop.name == "Target") {
-                                        cam->mLookAt = prop.value;
-                                    } else if (prop.name == "UpVector") {
-                                        cam->mUp = prop.value;
-                                    }
-                                }
-                            }
-                        } else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) {
-                            BoolProperty prop;
-                            ReadBoolProperty(prop);
-
-                            if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
-                                curAnim->loop = prop.value;
-                            }
-                        } else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) {
-                            FloatProperty prop;
-                            ReadFloatProperty(prop);
-
-                            if (inAnimator) {
-                                // The speed property exists for several animators
-                                if (prop.name == "Speed") {
-                                    curAnim->speed = prop.value;
-                                } else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius") {
-                                    curAnim->circleRadius = prop.value;
-                                } else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") {
-                                    curAnim->tightness = prop.value;
-                                }
-                            } else {
-                                if (prop.name == "FramesPerSecond" && Node::ANIMMESH == curNode->type) {
-                                    curNode->framesPerSecond = prop.value;
-                                } else if (Node::CAMERA == curNode->type) {
-                                    /*  This is the vertical, not the horizontal FOV.
+					//					while (reader->read()) {
+					for (pugi::xml_node attrib : child.children()) {
+						if (attrib.type() == pugi::node_element) {
+							//if (reader->getNodeType() == EXN_ELEMENT) {
+							//if (!ASSIMP_stricmp(reader->getNodeName(), "vector3d")) {
+							if (!ASSIMP_stricmp(attrib.name(), "vector3d")) {
+								VectorProperty prop;
+								ReadVectorProperty(prop);
+
+								if (inAnimator) {
+									if (curAnim->type == Animator::ROTATION && prop.name == "Rotation") {
+										// We store the rotation euler angles in 'direction'
+										curAnim->direction = prop.value;
+									} else if (curAnim->type == Animator::FOLLOW_SPLINE) {
+										// Check whether the vector follows the PointN naming scheme,
+										// here N is the ONE-based index of the point
+										if (prop.name.length() >= 6 && prop.name.substr(0, 5) == "Point") {
+											// Add a new key to the list
+											curAnim->splineKeys.push_back(aiVectorKey());
+											aiVectorKey &key = curAnim->splineKeys.back();
+
+											// and parse its properties
+											key.mValue = prop.value;
+											key.mTime = strtoul10(&prop.name[5]);
+										}
+									} else if (curAnim->type == Animator::FLY_CIRCLE) {
+										if (prop.name == "Center") {
+											curAnim->circleCenter = prop.value;
+										} else if (prop.name == "Direction") {
+											curAnim->direction = prop.value;
+
+											// From Irrlicht's source - a workaround for backward compatibility with Irrlicht 1.1
+											if (curAnim->direction == aiVector3D()) {
+												curAnim->direction = aiVector3D(0.f, 1.f, 0.f);
+											} else
+												curAnim->direction.Normalize();
+										}
+									} else if (curAnim->type == Animator::FLY_STRAIGHT) {
+										if (prop.name == "Start") {
+											// We reuse the field here
+											curAnim->circleCenter = prop.value;
+										} else if (prop.name == "End") {
+											// We reuse the field here
+											curAnim->direction = prop.value;
+										}
+									}
+								} else {
+									if (prop.name == "Position") {
+										curNode->position = prop.value;
+									} else if (prop.name == "Rotation") {
+										curNode->rotation = prop.value;
+									} else if (prop.name == "Scale") {
+										curNode->scaling = prop.value;
+									} else if (Node::CAMERA == curNode->type) {
+										aiCamera *cam = cameras.back();
+										if (prop.name == "Target") {
+											cam->mLookAt = prop.value;
+										} else if (prop.name == "UpVector") {
+											cam->mUp = prop.value;
+										}
+									}
+								}
+								//} else if (!ASSIMP_stricmp(reader->getNodeName(), "bool")) {
+							} else if (!ASSIMP_stricmp(attrib.name(), "bool")) {
+								BoolProperty prop;
+								ReadBoolProperty(prop);
+
+								if (inAnimator && curAnim->type == Animator::FLY_CIRCLE && prop.name == "Loop") {
+									curAnim->loop = prop.value;
+								}
+								//} else if (!ASSIMP_stricmp(reader->getNodeName(), "float")) {
+							} else if (!ASSIMP_stricmp(attrib.name(), "float")) {
+								FloatProperty prop;
+								ReadFloatProperty(prop);
+
+								if (inAnimator) {
+									// The speed property exists for several animators
+									if (prop.name == "Speed") {
+										curAnim->speed = prop.value;
+									} else if (curAnim->type == Animator::FLY_CIRCLE && prop.name == "Radius") {
+										curAnim->circleRadius = prop.value;
+									} else if (curAnim->type == Animator::FOLLOW_SPLINE && prop.name == "Tightness") {
+										curAnim->tightness = prop.value;
+									}
+								} else {
+									if (prop.name == "FramesPerSecond" && Node::ANIMMESH == curNode->type) {
+										curNode->framesPerSecond = prop.value;
+									} else if (Node::CAMERA == curNode->type) {
+										/*  This is the vertical, not the horizontal FOV.
                                     *  We need to compute the right FOV from the
                                     *  We need to compute the right FOV from the
                                     *  screen aspect which we don't know yet.
                                     *  screen aspect which we don't know yet.
                                     */
                                     */
-                                    if (prop.name == "Fovy") {
-                                        cameras.back()->mHorizontalFOV = prop.value;
-                                    } else if (prop.name == "Aspect") {
-                                        cameras.back()->mAspect = prop.value;
-                                    } else if (prop.name == "ZNear") {
-                                        cameras.back()->mClipPlaneNear = prop.value;
-                                    } else if (prop.name == "ZFar") {
-                                        cameras.back()->mClipPlaneFar = prop.value;
-                                    }
-                                } else if (Node::LIGHT == curNode->type) {
-                                    /*  Additional light information
+										if (prop.name == "Fovy") {
+											cameras.back()->mHorizontalFOV = prop.value;
+										} else if (prop.name == "Aspect") {
+											cameras.back()->mAspect = prop.value;
+										} else if (prop.name == "ZNear") {
+											cameras.back()->mClipPlaneNear = prop.value;
+										} else if (prop.name == "ZFar") {
+											cameras.back()->mClipPlaneFar = prop.value;
+										}
+									} else if (Node::LIGHT == curNode->type) {
+										/*  Additional light information
                                      */
                                      */
-                                    if (prop.name == "Attenuation") {
-                                        lights.back()->mAttenuationLinear = prop.value;
-                                    } else if (prop.name == "OuterCone") {
-                                        lights.back()->mAngleOuterCone = AI_DEG_TO_RAD(prop.value);
-                                    } else if (prop.name == "InnerCone") {
-                                        lights.back()->mAngleInnerCone = AI_DEG_TO_RAD(prop.value);
-                                    }
-                                }
-                                // radius of the sphere to be generated -
-                                // or alternatively, size of the cube
-                                else if ((Node::SPHERE == curNode->type && prop.name == "Radius") || (Node::CUBE == curNode->type && prop.name == "Size")) {
-
-                                    curNode->sphereRadius = prop.value;
-                                }
-                            }
-                        } else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) {
-                            IntProperty prop;
-                            ReadIntProperty(prop);
-
-                            if (inAnimator) {
-                                if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") {
-                                    curAnim->timeForWay = prop.value;
-                                }
-                            } else {
-                                // sphere polgon numbers in each direction
-                                if (Node::SPHERE == curNode->type) {
-
-                                    if (prop.name == "PolyCountX") {
-                                        curNode->spherePolyCountX = prop.value;
-                                    } else if (prop.name == "PolyCountY") {
-                                        curNode->spherePolyCountY = prop.value;
-                                    }
-                                }
-                            }
-                        } else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) {
-                            StringProperty prop;
-                            ReadStringProperty(prop);
-                            if (prop.value.length()) {
-                                if (prop.name == "Name") {
-                                    curNode->name = prop.value;
-
-                                    /*  If we're either a camera or a light source
+										if (prop.name == "Attenuation") {
+											lights.back()->mAttenuationLinear = prop.value;
+										} else if (prop.name == "OuterCone") {
+											lights.back()->mAngleOuterCone = AI_DEG_TO_RAD(prop.value);
+										} else if (prop.name == "InnerCone") {
+											lights.back()->mAngleInnerCone = AI_DEG_TO_RAD(prop.value);
+										}
+									}
+									// radius of the sphere to be generated -
+									// or alternatively, size of the cube
+									else if ((Node::SPHERE == curNode->type && prop.name == "Radius") || (Node::CUBE == curNode->type && prop.name == "Size")) {
+
+										curNode->sphereRadius = prop.value;
+									}
+								}
+								//} else if (!ASSIMP_stricmp(reader->getNodeName(), "int")) {
+							} else if (!ASSIMP_stricmp(attrib.name(), "int")) {
+								IntProperty prop;
+								ReadIntProperty(prop);
+
+								if (inAnimator) {
+									if (curAnim->type == Animator::FLY_STRAIGHT && prop.name == "TimeForWay") {
+										curAnim->timeForWay = prop.value;
+									}
+								} else {
+									// sphere polygon numbers in each direction
+									if (Node::SPHERE == curNode->type) {
+
+										if (prop.name == "PolyCountX") {
+											curNode->spherePolyCountX = prop.value;
+										} else if (prop.name == "PolyCountY") {
+											curNode->spherePolyCountY = prop.value;
+										}
+									}
+								}
+								//} else if (!ASSIMP_stricmp(reader->getNodeName(), "string") || !ASSIMP_stricmp(reader->getNodeName(), "enum")) {
+							} else if (!ASSIMP_stricmp(attrib.name(), "string") || !ASSIMP_stricmp(attrib.name(), "enum")) {
+								StringProperty prop;
+								ReadStringProperty(prop);
+								if (prop.value.length()) {
+									if (prop.name == "Name") {
+										curNode->name = prop.value;
+
+										/*  If we're either a camera or a light source
                                      *  we need to update the name in the aiLight/
                                      *  we need to update the name in the aiLight/
                                      *  aiCamera structure, too.
                                      *  aiCamera structure, too.
                                      */
                                      */
-                                    if (Node::CAMERA == curNode->type) {
-                                        cameras.back()->mName.Set(prop.value);
-                                    } else if (Node::LIGHT == curNode->type) {
-                                        lights.back()->mName.Set(prop.value);
-                                    }
-                                } else if (Node::LIGHT == curNode->type && "LightType" == prop.name) {
-                                    if (prop.value == "Spot")
-                                        lights.back()->mType = aiLightSource_SPOT;
-                                    else if (prop.value == "Point")
-                                        lights.back()->mType = aiLightSource_POINT;
-                                    else if (prop.value == "Directional")
-                                        lights.back()->mType = aiLightSource_DIRECTIONAL;
-                                    else {
-                                        // We won't pass the validation with aiLightSourceType_UNDEFINED,
-                                        // so we remove the light and replace it with a silly dummy node
-                                        delete lights.back();
-                                        lights.pop_back();
-                                        curNode->type = Node::DUMMY;
-
-                                        ASSIMP_LOG_ERROR("Ignoring light of unknown type: " + prop.value);
-                                    }
-                                } else if ((prop.name == "Mesh" && Node::MESH == curNode->type) ||
-                                           Node::ANIMMESH == curNode->type) {
-                                    /*  This is the file name of the mesh - either
+										if (Node::CAMERA == curNode->type) {
+											cameras.back()->mName.Set(prop.value);
+										} else if (Node::LIGHT == curNode->type) {
+											lights.back()->mName.Set(prop.value);
+										}
+									} else if (Node::LIGHT == curNode->type && "LightType" == prop.name) {
+										if (prop.value == "Spot")
+											lights.back()->mType = aiLightSource_SPOT;
+										else if (prop.value == "Point")
+											lights.back()->mType = aiLightSource_POINT;
+										else if (prop.value == "Directional")
+											lights.back()->mType = aiLightSource_DIRECTIONAL;
+										else {
+											// We won't pass the validation with aiLightSourceType_UNDEFINED,
+											// so we remove the light and replace it with a silly dummy node
+											delete lights.back();
+											lights.pop_back();
+											curNode->type = Node::DUMMY;
+
+											ASSIMP_LOG_ERROR("Ignoring light of unknown type: " + prop.value);
+										}
+									} else if ((prop.name == "Mesh" && Node::MESH == curNode->type) ||
+											   Node::ANIMMESH == curNode->type) {
+    								/*  This is the file name of the mesh - either
                                      *  animated or not. We need to make sure we setup
                                      *  animated or not. We need to make sure we setup
                                      *  the correct post-processing settings here.
                                      *  the correct post-processing settings here.
                                      */
                                      */
-                                    unsigned int pp = 0;
-                                    BatchLoader::PropertyMap map;
+										unsigned int pp = 0;
+										BatchLoader::PropertyMap map;
 
 
-                                    /* If the mesh is a static one remove all animations from the impor data
+										/* If the mesh is a static one remove all animations from the impor data
                                      */
                                      */
-                                    if (Node::ANIMMESH != curNode->type) {
-                                        pp |= aiProcess_RemoveComponent;
-                                        SetGenericProperty<int>(map.ints, AI_CONFIG_PP_RVC_FLAGS,
-                                                aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
-                                    }
-
-                                    /*  TODO: maybe implement the protection against recursive
-                                    *  loading calls directly in BatchLoader? The current
-                                    *  implementation is not absolutely safe. A LWS and an IRR
-                                    *  file referencing each other *could* cause the system to
-                                    *  recurse forever.
-                                    */
-
-                                    const std::string extension = GetExtension(prop.value);
-                                    if ("irr" == extension) {
-                                        ASSIMP_LOG_ERROR("IRR: Can't load another IRR file recursively");
-                                    } else {
-                                        curNode->id = batch.AddLoadRequest(prop.value, pp, &map);
-                                        curNode->meshPath = prop.value;
-                                    }
-                                } else if (inAnimator && prop.name == "Type") {
-                                    // type of the animator
-                                    if (prop.value == "rotation") {
-                                        curAnim->type = Animator::ROTATION;
-                                    } else if (prop.value == "flyCircle") {
-                                        curAnim->type = Animator::FLY_CIRCLE;
-                                    } else if (prop.value == "flyStraight") {
-                                        curAnim->type = Animator::FLY_CIRCLE;
-                                    } else if (prop.value == "followSpline") {
-                                        curAnim->type = Animator::FOLLOW_SPLINE;
-                                    } else {
-                                        ASSIMP_LOG_WARN("IRR: Ignoring unknown animator: " + prop.value);
-
-                                        curAnim->type = Animator::UNKNOWN;
-                                    }
-                                }
-                            }
-                        }
-                    } else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(), "attributes")) {
-                        break;
-                    }
-                }
-            }
-            break;
-
-        case EXN_ELEMENT_END:
-
-            // If we reached the end of a node, we need to continue processing its parent
-            if (!ASSIMP_stricmp(reader->getNodeName(), "node")) {
-                if (!curNode) {
-                    // currently is no node set. We need to go
-                    // back in the node hierarchy
-                    if (!curParent) {
-                        curParent = root;
-                        ASSIMP_LOG_ERROR("IRR: Too many closing <node> elements");
-                    } else
-                        curParent = curParent->parent;
-                } else
-                    curNode = nullptr;
-            }
-            // clear all flags
-            else if (!ASSIMP_stricmp(reader->getNodeName(), "materials")) {
-                inMaterials = false;
-            } else if (!ASSIMP_stricmp(reader->getNodeName(), "animators")) {
-                inAnimator = false;
-            }
-            break;
-
-        default:
-            // GCC complains that not all enumeration values are handled
-            break;
-        }
-    }
-
-    //  Now iterate through all cameras and compute their final (horizontal) FOV
-    for (aiCamera *cam : cameras) {
-        // screen aspect could be missing
-        if (cam->mAspect) {
-            cam->mHorizontalFOV *= cam->mAspect;
-        } else {
-            ASSIMP_LOG_WARN("IRR: Camera aspect is not given, can't compute horizontal FOV");
-        }
-    }
-
-    batch.LoadAll();
-
-    /* Allocate a tempoary scene data structure
-     */
-    aiScene *tempScene = new aiScene();
-    tempScene->mRootNode = new aiNode();
-    tempScene->mRootNode->mName.Set("<IRRRoot>");
-
-    /* Copy the cameras to the output array
-     */
-    if (!cameras.empty()) {
-        tempScene->mNumCameras = (unsigned int)cameras.size();
-        tempScene->mCameras = new aiCamera *[tempScene->mNumCameras];
-        ::memcpy(tempScene->mCameras, &cameras[0], sizeof(void *) * tempScene->mNumCameras);
-    }
-
-    /* Copy the light sources to the output array
-     */
-    if (!lights.empty()) {
-        tempScene->mNumLights = (unsigned int)lights.size();
-        tempScene->mLights = new aiLight *[tempScene->mNumLights];
-        ::memcpy(tempScene->mLights, &lights[0], sizeof(void *) * tempScene->mNumLights);
-    }
-
-    // temporary data
-    std::vector<aiNodeAnim *> anims;
-    std::vector<aiMaterial *> materials;
-    std::vector<AttachmentInfo> attach;
-    std::vector<aiMesh *> meshes;
-
-    // try to guess how much storage we'll need
-    anims.reserve(guessedAnimCnt + (guessedAnimCnt >> 2));
-    meshes.reserve(guessedMeshCnt + (guessedMeshCnt >> 2));
-    materials.reserve(guessedMatCnt + (guessedMatCnt >> 2));
-
-    /* Now process our scenegraph recursively: generate final
-     * meshes and generate animation channels for all nodes.
-     */
-    unsigned int defMatIdx = UINT_MAX;
-    GenerateGraph(root, tempScene->mRootNode, tempScene,
-            batch, meshes, anims, attach, materials, defMatIdx);
-
-    if (!anims.empty()) {
-        tempScene->mNumAnimations = 1;
-        tempScene->mAnimations = new aiAnimation *[tempScene->mNumAnimations];
-        aiAnimation *an = tempScene->mAnimations[0] = new aiAnimation();
-
-        // ***********************************************************
-        // This is only the global animation channel of the scene.
-        // If there are animated models, they will have separate
-        // animation channels in the scene. To display IRR scenes
-        // correctly, users will need to combine the global anim
-        // channel with all the local animations they want to play
-        // ***********************************************************
-        an->mName.Set("Irr_GlobalAnimChannel");
-
-        // copy all node animation channels to the global channel
-        an->mNumChannels = (unsigned int)anims.size();
-        an->mChannels = new aiNodeAnim *[an->mNumChannels];
-        ::memcpy(an->mChannels, &anims[0], sizeof(void *) * an->mNumChannels);
-    }
-    if (!meshes.empty()) {
-        // copy all meshes to the temporary scene
-        tempScene->mNumMeshes = (unsigned int)meshes.size();
-        tempScene->mMeshes = new aiMesh *[tempScene->mNumMeshes];
-        ::memcpy(tempScene->mMeshes, &meshes[0], tempScene->mNumMeshes * sizeof(void *));
-    }
-
-    /* Copy all materials to the output array
-     */
-    if (!materials.empty()) {
-        tempScene->mNumMaterials = (unsigned int)materials.size();
-        tempScene->mMaterials = new aiMaterial *[tempScene->mNumMaterials];
-        ::memcpy(tempScene->mMaterials, &materials[0], sizeof(void *) * tempScene->mNumMaterials);
-    }
-
-    /*  Now merge all sub scenes and attach them to the correct
-     *  attachment points in the scenegraph.
-     */
-    SceneCombiner::MergeScenes(&pScene, tempScene, attach,
-            AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
-                                                                              AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
-                                                                      0));
-
-    /*  If we have no meshes | no materials now set the INCOMPLETE
-     *  scene flag. This is necessary if we failed to load all
-     *  models from external files
-     */
-    if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
-        ASSIMP_LOG_WARN("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE");
-        pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
-    }
-
-    /* Finished ... everything destructs automatically and all
-     * temporary scenes have already been deleted by MergeScenes()
-     */
-
-    delete root;
-    delete reader;
+										if (Node::ANIMMESH != curNode->type) {
+											pp |= aiProcess_RemoveComponent;
+											SetGenericProperty<int>(map.ints, AI_CONFIG_PP_RVC_FLAGS,
+													aiComponent_ANIMATIONS | aiComponent_BONEWEIGHTS);
+										}
+
+										/*  TODO: maybe implement the protection against recursive
+                                        *  loading calls directly in BatchLoader? The current
+                                        *  implementation is not absolutely safe. A LWS and an IRR
+                                        *  file referencing each other *could* cause the system to
+                                        *  recurse forever.
+                                        */
+
+										const std::string extension = GetExtension(prop.value);
+										if ("irr" == extension) {
+											ASSIMP_LOG_ERROR("IRR: Can't load another IRR file recursively");
+										} else {
+											curNode->id = batch.AddLoadRequest(prop.value, pp, &map);
+											curNode->meshPath = prop.value;
+										}
+									} else if (inAnimator && prop.name == "Type") {
+										// type of the animator
+										if (prop.value == "rotation") {
+											curAnim->type = Animator::ROTATION;
+										} else if (prop.value == "flyCircle") {
+											curAnim->type = Animator::FLY_CIRCLE;
+										} else if (prop.value == "flyStraight") {
+											curAnim->type = Animator::FLY_CIRCLE;
+										} else if (prop.value == "followSpline") {
+											curAnim->type = Animator::FOLLOW_SPLINE;
+										} else {
+											ASSIMP_LOG_WARN("IRR: Ignoring unknown animator: " + prop.value);
+
+											curAnim->type = Animator::UNKNOWN;
+										}
+									}
+								}
+							}
+							//} else if (reader->getNodeType() == EXN_ELEMENT_END && !ASSIMP_stricmp(reader->getNodeName(), "attributes")) {
+						} else if (attrib.type() == pugi::node_null && !ASSIMP_stricmp(attrib.name(), "attributes")) {
+							break;
+						}
+					}
+				}
+				break;
+
+				/*case EXN_ELEMENT_END:
+
+				// If we reached the end of a node, we need to continue processing its parent
+				if (!ASSIMP_stricmp(reader->getNodeName(), "node")) {
+					if (!curNode) {
+						// currently is no node set. We need to go
+						// back in the node hierarchy
+						if (!curParent) {
+							curParent = root;
+							ASSIMP_LOG_ERROR("IRR: Too many closing <node> elements");
+						} else
+							curParent = curParent->parent;
+					} else
+						curNode = nullptr;
+				}
+				// clear all flags
+				else if (!ASSIMP_stricmp(reader->getNodeName(), "materials")) {
+					inMaterials = false;
+				} else if (!ASSIMP_stricmp(reader->getNodeName(), "animators")) {
+					inAnimator = false;
+				}
+				break;*/
+
+			default:
+				// GCC complains that not all enumeration values are handled
+				break;
+		}
+	//}
+
+	//  Now iterate through all cameras and compute their final (horizontal) FOV
+	for (aiCamera *cam : cameras) {
+		// screen aspect could be missing
+		if (cam->mAspect) {
+			cam->mHorizontalFOV *= cam->mAspect;
+		} else {
+			ASSIMP_LOG_WARN("IRR: Camera aspect is not given, can't compute horizontal FOV");
+		}
+	}
+
+	batch.LoadAll();
+
+	// Allocate a temporary scene data structure
+	aiScene *tempScene = new aiScene();
+	tempScene->mRootNode = new aiNode();
+	tempScene->mRootNode->mName.Set("<IRRRoot>");
+
+	// Copy the cameras to the output array
+	if (!cameras.empty()) {
+		tempScene->mNumCameras = (unsigned int)cameras.size();
+		tempScene->mCameras = new aiCamera *[tempScene->mNumCameras];
+		::memcpy(tempScene->mCameras, &cameras[0], sizeof(void *) * tempScene->mNumCameras);
+	}
+
+	// Copy the light sources to the output array
+	if (!lights.empty()) {
+		tempScene->mNumLights = (unsigned int)lights.size();
+		tempScene->mLights = new aiLight *[tempScene->mNumLights];
+		::memcpy(tempScene->mLights, &lights[0], sizeof(void *) * tempScene->mNumLights);
+	}
+
+	// temporary data
+	std::vector<aiNodeAnim *> anims;
+	std::vector<aiMaterial *> materials;
+	std::vector<AttachmentInfo> attach;
+	std::vector<aiMesh *> meshes;
+
+	// try to guess how much storage we'll need
+	anims.reserve(guessedAnimCnt + (guessedAnimCnt >> 2));
+	meshes.reserve(guessedMeshCnt + (guessedMeshCnt >> 2));
+	materials.reserve(guessedMatCnt + (guessedMatCnt >> 2));
+
+	// Now process our scene-graph recursively: generate final
+	// meshes and generate animation channels for all nodes.
+	unsigned int defMatIdx = UINT_MAX;
+	GenerateGraph(root, tempScene->mRootNode, tempScene,
+			batch, meshes, anims, attach, materials, defMatIdx);
+
+	if (!anims.empty()) {
+		tempScene->mNumAnimations = 1;
+		tempScene->mAnimations = new aiAnimation *[tempScene->mNumAnimations];
+		aiAnimation *an = tempScene->mAnimations[0] = new aiAnimation();
+
+		// ***********************************************************
+		// This is only the global animation channel of the scene.
+		// If there are animated models, they will have separate
+		// animation channels in the scene. To display IRR scenes
+		// correctly, users will need to combine the global anim
+		// channel with all the local animations they want to play
+		// ***********************************************************
+		an->mName.Set("Irr_GlobalAnimChannel");
+
+		// copy all node animation channels to the global channel
+		an->mNumChannels = (unsigned int)anims.size();
+		an->mChannels = new aiNodeAnim *[an->mNumChannels];
+		::memcpy(an->mChannels, &anims[0], sizeof(void *) * an->mNumChannels);
+	}
+	if (!meshes.empty()) {
+		// copy all meshes to the temporary scene
+		tempScene->mNumMeshes = (unsigned int)meshes.size();
+		tempScene->mMeshes = new aiMesh *[tempScene->mNumMeshes];
+		::memcpy(tempScene->mMeshes, &meshes[0], tempScene->mNumMeshes * sizeof(void *));
+	}
+
+	// Copy all materials to the output array
+	if (!materials.empty()) {
+		tempScene->mNumMaterials = (unsigned int)materials.size();
+		tempScene->mMaterials = new aiMaterial *[tempScene->mNumMaterials];
+		::memcpy(tempScene->mMaterials, &materials[0], sizeof(void *) * tempScene->mNumMaterials);
+	}
+
+	//  Now merge all sub scenes and attach them to the correct
+	//  attachment points in the scenegraph.
+	SceneCombiner::MergeScenes(&pScene, tempScene, attach,
+			AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
+																			  AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) :
+																	  0));
+
+	// If we have no meshes | no materials now set the INCOMPLETE
+	// scene flag. This is necessary if we failed to load all
+	// models from external files
+	if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
+		ASSIMP_LOG_WARN("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE");
+		pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
+	}
+
+	// Finished ... everything destructs automatically and all
+	// temporary scenes have already been deleted by MergeScenes()
+	delete root;
 }
 }
 
 
 #endif // !! ASSIMP_BUILD_NO_IRR_IMPORTER
 #endif // !! ASSIMP_BUILD_NO_IRR_IMPORTER

+ 11 - 22
code/AssetLib/Irr/IRRLoader.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -40,7 +39,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
-
 /** @file IRRLoader.h
 /** @file IRRLoader.h
  *  @brief Declaration of the .irrMesh (Irrlight Engine Mesh Format)
  *  @brief Declaration of the .irrMesh (Irrlight Engine Mesh Format)
  *  importer class.
  *  importer class.
@@ -83,7 +81,7 @@ protected:
 
 
 private:
 private:
 
 
-    /** Data structure for a scenegraph node animator
+    /** Data structure for a scene-graph node animator
      */
      */
     struct Animator {
     struct Animator {
         // Type of the animator
         // Type of the animator
@@ -129,7 +127,7 @@ private:
         int timeForWay;
         int timeForWay;
     };
     };
 
 
-    /** Data structure for a scenegraph node in an IRR file
+    /** Data structure for a scene-graph node in an IRR file
      */
      */
     struct Node
     struct Node
     {
     {
@@ -227,8 +225,7 @@ private:
 
 
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
-    /** Fill the scenegraph recursively
-     */
+    /// Fill the scene-graph recursively
     void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
     void GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
         BatchLoader& batch,
         BatchLoader& batch,
         std::vector<aiMesh*>& meshes,
         std::vector<aiMesh*>& meshes,
@@ -237,27 +234,22 @@ private:
         std::vector<aiMaterial*>& materials,
         std::vector<aiMaterial*>& materials,
         unsigned int& defaultMatIdx);
         unsigned int& defaultMatIdx);
 
 
-
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
-    /** Generate a mesh that consists of just a single quad
-     */
+    /// Generate a mesh that consists of just a single quad
     aiMesh* BuildSingleQuadMesh(const SkyboxVertex& v1,
     aiMesh* BuildSingleQuadMesh(const SkyboxVertex& v1,
         const SkyboxVertex& v2,
         const SkyboxVertex& v2,
         const SkyboxVertex& v3,
         const SkyboxVertex& v3,
         const SkyboxVertex& v4);
         const SkyboxVertex& v4);
 
 
-
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
-    /** Build a skybox
-     *
-     *  @param meshes Receives 6 output meshes
-     *  @param materials The last 6 materials are assigned to the newly
-     *    created meshes. The names of the materials are adjusted.
-     */
+    /// Build a sky-box
+    ///
+    /// @param meshes Receives 6 output meshes
+    /// @param materials The last 6 materials are assigned to the newly
+    ///                  created meshes. The names of the materials are adjusted.
     void BuildSkybox(std::vector<aiMesh*>& meshes,
     void BuildSkybox(std::vector<aiMesh*>& meshes,
         std::vector<aiMaterial*> materials);
         std::vector<aiMaterial*> materials);
 
 
-
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Copy a material for a mesh to the output material list
     /** Copy a material for a mesh to the output material list
      *
      *
@@ -271,7 +263,6 @@ private:
         unsigned int& defMatIdx,
         unsigned int& defMatIdx,
         aiMesh* mesh);
         aiMesh* mesh);
 
 
-
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Compute animations for a specific node
     /** Compute animations for a specific node
      *
      *
@@ -281,13 +272,11 @@ private:
     void ComputeAnimations(Node* root, aiNode* real,
     void ComputeAnimations(Node* root, aiNode* real,
         std::vector<aiNodeAnim*>& anims);
         std::vector<aiNodeAnim*>& anims);
 
 
-
 private:
 private:
-
-    /** Configuration option: desired output FPS */
+    /// Configuration option: desired output FPS 
     double fps;
     double fps;
 
 
-    /** Configuration option: speed flag was set? */
+    /// Configuration option: speed flag was set?
     bool configSpeedFlag;
     bool configSpeedFlag;
 };
 };
 
 

+ 426 - 446
code/AssetLib/Irr/IRRMeshLoader.cpp

@@ -43,494 +43,474 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 /** @file Implementation of the IrrMesh importer class */
 /** @file Implementation of the IrrMesh importer class */
 
 
-
-
 #ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER
 #ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER
 
 
 #include "IRRMeshLoader.h"
 #include "IRRMeshLoader.h"
 #include <assimp/ParsingUtils.h>
 #include <assimp/ParsingUtils.h>
 #include <assimp/fast_atof.h>
 #include <assimp/fast_atof.h>
-#include <memory>
-#include <assimp/IOSystem.hpp>
-#include <assimp/mesh.h>
-#include <assimp/DefaultLogger.hpp>
+#include <assimp/importerdesc.h>
 #include <assimp/material.h>
 #include <assimp/material.h>
+#include <assimp/mesh.h>
 #include <assimp/scene.h>
 #include <assimp/scene.h>
-#include <assimp/importerdesc.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/IOSystem.hpp>
+#include <memory>
 
 
 using namespace Assimp;
 using namespace Assimp;
-using namespace irr;
-using namespace irr::io;
 
 
 static const aiImporterDesc desc = {
 static const aiImporterDesc desc = {
-    "Irrlicht Mesh Reader",
-    "",
-    "",
-    "http://irrlicht.sourceforge.net/",
-    aiImporterFlags_SupportTextFlavour,
-    0,
-    0,
-    0,
-    0,
-    "xml irrmesh"
+	"Irrlicht Mesh Reader",
+	"",
+	"",
+	"http://irrlicht.sourceforge.net/",
+	aiImporterFlags_SupportTextFlavour,
+	0,
+	0,
+	0,
+	0,
+	"xml irrmesh"
 };
 };
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
-IRRMeshImporter::IRRMeshImporter()
-{}
+IRRMeshImporter::IRRMeshImporter() :
+        BaseImporter(),
+        IrrlichtBase() {
+    // empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 // Destructor, private as well
-IRRMeshImporter::~IRRMeshImporter()
-{}
+IRRMeshImporter::~IRRMeshImporter() {}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
 // Returns whether the class can handle the format of the given file.
-bool IRRMeshImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
-{
-    /* NOTE: A simple check for the file extension is not enough
+bool IRRMeshImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
+	/* NOTE: A simple check for the file extension is not enough
      * here. Irrmesh and irr are easy, but xml is too generic
      * here. Irrmesh and irr are easy, but xml is too generic
      * and could be collada, too. So we need to open the file and
      * and could be collada, too. So we need to open the file and
      * search for typical tokens.
      * search for typical tokens.
      */
      */
-    const std::string extension = GetExtension(pFile);
+	const std::string extension = GetExtension(pFile);
 
 
-    if (extension == "irrmesh")return true;
-    else if (extension == "xml" || checkSig)
-    {
-        /*  If CanRead() is called to check whether the loader
+	if (extension == "irrmesh")
+		return true;
+	else if (extension == "xml" || checkSig) {
+		/*  If CanRead() is called to check whether the loader
          *  supports a specific file extension in general we
          *  supports a specific file extension in general we
          *  must return true here.
          *  must return true here.
          */
          */
-        if (!pIOHandler)return true;
-        const char* tokens[] = {"irrmesh"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
-    }
-    return false;
+		if (!pIOHandler) return true;
+		const char *tokens[] = { "irrmesh" };
+		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+	}
+	return false;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get a list of all file extensions which are handled by this class
 // Get a list of all file extensions which are handled by this class
-const aiImporterDesc* IRRMeshImporter::GetInfo () const
-{
-    return &desc;
+const aiImporterDesc *IRRMeshImporter::GetInfo() const {
+	return &desc;
 }
 }
 
 
-static void releaseMaterial( aiMaterial **mat ) {
-    if(*mat!= nullptr) {
-        delete *mat;
-        *mat = nullptr;
-    }
+static void releaseMaterial(aiMaterial **mat) {
+	if (*mat != nullptr) {
+		delete *mat;
+		*mat = nullptr;
+	}
 }
 }
 
 
-static void releaseMesh( aiMesh **mesh ) {
-    if (*mesh != nullptr){
-        delete *mesh;
-        *mesh = nullptr;
-    }
+static void releaseMesh(aiMesh **mesh) {
+	if (*mesh != nullptr) {
+		delete *mesh;
+		*mesh = nullptr;
+	}
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 // Imports the given file into the given scene structure.
-void IRRMeshImporter::InternReadFile( const std::string& pFile,
-    aiScene* pScene, IOSystem* pIOHandler)
-{
-    std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
-
-    // Check whether we can read from the file
-    if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open IRRMESH file " + pFile + ".");
-    }
-
-    // Construct the irrXML parser
-    CIrrXML_IOStreamReader st(file.get());
-    reader = createIrrXMLReader((IFileReadCallBack*) &st);
-
-    // final data
-    std::vector<aiMaterial*> materials;
-    std::vector<aiMesh*>     meshes;
-    materials.reserve (5);
-    meshes.reserve(5);
-
-    // temporary data - current mesh buffer
-    aiMaterial* curMat  = nullptr;
-    aiMesh* curMesh     = nullptr;
-    unsigned int curMatFlags = 0;
-
-    std::vector<aiVector3D> curVertices,curNormals,curTangents,curBitangents;
-    std::vector<aiColor4D>  curColors;
-    std::vector<aiVector3D> curUVs,curUV2s;
-
-    // some temporary variables
-    int textMeaning = 0;
-    int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
-    bool useColors = false;
-
-    // Parse the XML file
-    while (reader->read())  {
-        switch (reader->getNodeType())  {
-        case EXN_ELEMENT:
-
-            if (!ASSIMP_stricmp(reader->getNodeName(),"buffer") && (curMat || curMesh)) {
-                // end of previous buffer. A material and a mesh should be there
-                if ( !curMat || !curMesh)   {
-                    ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
-                    releaseMaterial( &curMat );
-                    releaseMesh( &curMesh );
-                } else {
-                    materials.push_back(curMat);
-                    meshes.push_back(curMesh);
-                }
-                curMat  = nullptr;
-                curMesh = nullptr;
-
-                curVertices.clear();
-                curColors.clear();
-                curNormals.clear();
-                curUV2s.clear();
-                curUVs.clear();
-                curTangents.clear();
-                curBitangents.clear();
-            }
-
-
-            if (!ASSIMP_stricmp(reader->getNodeName(),"material"))  {
-                if (curMat) {
-                    ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
-                    releaseMaterial( &curMat );
-                }
-                curMat = ParseMaterial(curMatFlags);
-            }
-            /* no else here! */ if (!ASSIMP_stricmp(reader->getNodeName(),"vertices"))
-            {
-                int num = reader->getAttributeValueAsInt("vertexCount");
-
-                if (!num)   {
-                    // This is possible ... remove the mesh from the list and skip further reading
-                    ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
-
-                    releaseMaterial( &curMat );
-                    releaseMesh( &curMesh );
-                    textMeaning = 0;
-                    continue;
-                }
-
-                curVertices.reserve(num);
-                curNormals.reserve(num);
-                curColors.reserve(num);
-                curUVs.reserve(num);
-
-                // Determine the file format
-                const char* t = reader->getAttributeValueSafe("type");
-                if (!ASSIMP_stricmp("2tcoords", t)) {
-                    curUV2s.reserve (num);
-                    vertexFormat = 1;
-
-                    if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
-                        // *********************************************************
-                        // We have a second texture! So use this UV channel
-                        // for it. The 2nd texture can be either a normal
-                        // texture (solid_2layer or lightmap_xxx) or a normal
-                        // map (normal_..., parallax_...)
-                        // *********************************************************
-                        int idx = 1;
-                        aiMaterial* mat = ( aiMaterial* ) curMat;
-
-                        if (curMatFlags & AI_IRRMESH_MAT_lightmap){
-                            mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_LIGHTMAP(0));
-                        }
-                        else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid){
-                            mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_NORMALS(0));
-                        }
-                        else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
-                            mat->AddProperty(&idx,1,AI_MATKEY_UVWSRC_DIFFUSE(1));
-                        }
-                    }
-                }
-                else if (!ASSIMP_stricmp("tangents", t))    {
-                    curTangents.reserve (num);
-                    curBitangents.reserve (num);
-                    vertexFormat = 2;
-                }
-                else if (ASSIMP_stricmp("standard", t)) {
-                    releaseMaterial( &curMat );
-                    ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format");
-                }
-                else vertexFormat = 0;
-                textMeaning = 1;
-            }
-            else if (!ASSIMP_stricmp(reader->getNodeName(),"indices"))  {
-                if (curVertices.empty() && curMat)  {
-                    releaseMaterial( &curMat );
-                    throw DeadlyImportError("IRRMESH: indices must come after vertices");
-                }
-
-                textMeaning = 2;
-
-                // start a new mesh
-                curMesh = new aiMesh();
-
-                // allocate storage for all faces
-                curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount");
-                if (!curMesh->mNumVertices) {
-                    // This is possible ... remove the mesh from the list and skip further reading
-                    ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
-
-                    // mesh - away
-                    releaseMesh( &curMesh );
-
-                    // material - away
-                    releaseMaterial( &curMat );
-
-                    textMeaning = 0;
-                    continue;
-                }
-
-                if (curMesh->mNumVertices % 3)  {
-                    ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
-                }
-
-                curMesh->mNumFaces = curMesh->mNumVertices / 3;
-                curMesh->mFaces = new aiFace[curMesh->mNumFaces];
-
-                // setup some members
-                curMesh->mMaterialIndex = (unsigned int)materials.size();
-                curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
-
-                // allocate storage for all vertices
-                curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
-
-                if (curNormals.size() == curVertices.size())    {
-                    curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
-                }
-                if (curTangents.size() == curVertices.size())   {
-                    curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
-                }
-                if (curBitangents.size() == curVertices.size()) {
-                    curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
-                }
-                if (curColors.size() == curVertices.size() && useColors)    {
-                    curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
-                }
-                if (curUVs.size() == curVertices.size())    {
-                    curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
-                }
-                if (curUV2s.size() == curVertices.size())   {
-                    curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
-                }
-            }
-            break;
-
-        case EXN_TEXT:
-            {
-            const char* sz = reader->getNodeData();
-            if (textMeaning == 1)   {
-                textMeaning = 0;
-
-                // read vertices
-                do  {
-                    SkipSpacesAndLineEnd(&sz);
-                    aiVector3D temp;aiColor4D c;
-
-                    // Read the vertex position
-                    sz = fast_atoreal_move<float>(sz,(float&)temp.x);
-                    SkipSpaces(&sz);
-
-                    sz = fast_atoreal_move<float>(sz,(float&)temp.y);
-                    SkipSpaces(&sz);
-
-                    sz = fast_atoreal_move<float>(sz,(float&)temp.z);
-                    SkipSpaces(&sz);
-                    curVertices.push_back(temp);
-
-                    // Read the vertex normals
-                    sz = fast_atoreal_move<float>(sz,(float&)temp.x);
-                    SkipSpaces(&sz);
-
-                    sz = fast_atoreal_move<float>(sz,(float&)temp.y);
-                    SkipSpaces(&sz);
-
-                    sz = fast_atoreal_move<float>(sz,(float&)temp.z);
-                    SkipSpaces(&sz);
-                    curNormals.push_back(temp);
-
-                    // read the vertex colors
-                    uint32_t clr = strtoul16(sz,&sz);
-                    ColorFromARGBPacked(clr,c);
-
-                    if (!curColors.empty() && c != *(curColors.end()-1))
-                        useColors = true;
-
-                    curColors.push_back(c);
-                    SkipSpaces(&sz);
-
-
-                    // read the first UV coordinate set
-                    sz = fast_atoreal_move<float>(sz,(float&)temp.x);
-                    SkipSpaces(&sz);
-
-                    sz = fast_atoreal_move<float>(sz,(float&)temp.y);
-                    SkipSpaces(&sz);
-                    temp.z = 0.f;
-                    temp.y = 1.f - temp.y;  // DX to OGL
-                    curUVs.push_back(temp);
-
-                    // read the (optional) second UV coordinate set
-                    if (vertexFormat == 1)  {
-                        sz = fast_atoreal_move<float>(sz,(float&)temp.x);
-                        SkipSpaces(&sz);
-
-                        sz = fast_atoreal_move<float>(sz,(float&)temp.y);
-                        temp.y = 1.f - temp.y; // DX to OGL
-                        curUV2s.push_back(temp);
-                    }
-                    // read optional tangent and bitangent vectors
-                    else if (vertexFormat == 2) {
-                        // tangents
-                        sz = fast_atoreal_move<float>(sz,(float&)temp.x);
-                        SkipSpaces(&sz);
-
-                        sz = fast_atoreal_move<float>(sz,(float&)temp.z);
-                        SkipSpaces(&sz);
-
-                        sz = fast_atoreal_move<float>(sz,(float&)temp.y);
-                        SkipSpaces(&sz);
-                        temp.y *= -1.0f;
-                        curTangents.push_back(temp);
-
-                        // bitangents
-                        sz = fast_atoreal_move<float>(sz,(float&)temp.x);
-                        SkipSpaces(&sz);
-
-                        sz = fast_atoreal_move<float>(sz,(float&)temp.z);
-                        SkipSpaces(&sz);
-
-                        sz = fast_atoreal_move<float>(sz,(float&)temp.y);
-                        SkipSpaces(&sz);
-                        temp.y *= -1.0f;
-                        curBitangents.push_back(temp);
-                    }
-                }
-
-                /* IMPORTANT: We assume that each vertex is specified in one
-                   line. So we can skip the rest of the line - unknown vertex
-                   elements are ignored.
-                 */
-
-                while (SkipLine(&sz));
-            }
-            else if (textMeaning == 2)  {
-                textMeaning = 0;
-
-                // read indices
-                aiFace* curFace = curMesh->mFaces;
-                aiFace* const faceEnd = curMesh->mFaces  + curMesh->mNumFaces;
-
-                aiVector3D* pcV  = curMesh->mVertices;
-                aiVector3D* pcN  = curMesh->mNormals;
-                aiVector3D* pcT  = curMesh->mTangents;
-                aiVector3D* pcB  = curMesh->mBitangents;
-                aiColor4D* pcC0  = curMesh->mColors[0];
-                aiVector3D* pcT0 = curMesh->mTextureCoords[0];
-                aiVector3D* pcT1 = curMesh->mTextureCoords[1];
-
-                unsigned int curIdx = 0;
-                unsigned int total = 0;
-                while(SkipSpacesAndLineEnd(&sz))    {
-                    if (curFace >= faceEnd) {
-                        ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
-                        break;
-                    }
-                    if (!curIdx)    {
-                        curFace->mNumIndices = 3;
-                        curFace->mIndices = new unsigned int[3];
-                    }
-
-                    unsigned int idx = strtoul10(sz,&sz);
-                    if (idx >= curVertices.size())  {
-                        ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
-                        idx = 0;
-                    }
-
-                    curFace->mIndices[curIdx] = total++;
-
-                    *pcV++ = curVertices[idx];
-                    if (pcN)*pcN++ = curNormals[idx];
-                    if (pcT)*pcT++ = curTangents[idx];
-                    if (pcB)*pcB++ = curBitangents[idx];
-                    if (pcC0)*pcC0++ = curColors[idx];
-                    if (pcT0)*pcT0++ = curUVs[idx];
-                    if (pcT1)*pcT1++ = curUV2s[idx];
-
-                    if (++curIdx == 3)  {
-                        ++curFace;
-                        curIdx = 0;
-                    }
-                }
-
-                if (curFace != faceEnd)
-                    ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
-
-                // Finish processing the mesh - do some small material workarounds
-                if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors)  {
-                    // Take the opacity value of the current material
-                    // from the common vertex color alpha
-                    aiMaterial* mat = (aiMaterial*)curMat;
-                    mat->AddProperty(&curColors[0].a,1,AI_MATKEY_OPACITY);
-                }
-            }}
-            break;
-
-            default:
-                // GCC complains here ...
-                break;
-
-        };
-    }
-
-    // End of the last buffer. A material and a mesh should be there
-    if (curMat || curMesh)  {
-        if ( !curMat || !curMesh)   {
-            ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
-            releaseMaterial( &curMat );
-            releaseMesh( &curMesh );
-        }
-        else    {
-            materials.push_back(curMat);
-            meshes.push_back(curMesh);
-        }
-    }
-
-    if (materials.empty())
-        throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
-
-
-    // now generate the output scene
-    pScene->mNumMeshes = (unsigned int)meshes.size();
-    pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
-    for (unsigned int i = 0; i < pScene->mNumMeshes;++i)    {
-        pScene->mMeshes[i] = meshes[i];
-
-        // clean this value ...
-        pScene->mMeshes[i]->mNumUVComponents[3] = 0;
+void IRRMeshImporter::InternReadFile(const std::string &pFile,
+		aiScene *pScene, IOSystem *pIOHandler) {
+	std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
+
+	// Check whether we can read from the file
+	if (file.get() == NULL)
+		throw DeadlyImportError("Failed to open IRRMESH file " + pFile + "");
+
+	// Construct the irrXML parser
+	XmlParser parser;
+    if (!parser.parse( file.get() )) {
+        return;
     }
     }
-
-    pScene->mNumMaterials = (unsigned int)materials.size();
-    pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
-    ::memcpy(pScene->mMaterials,&materials[0],sizeof(void*)*pScene->mNumMaterials);
-
-    pScene->mRootNode = new aiNode();
-    pScene->mRootNode->mName.Set("<IRRMesh>");
-    pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
-    pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
-
-    for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
-        pScene->mRootNode->mMeshes[i] = i;
-
-    // clean up and return
-    delete reader;
-    AI_DEBUG_INVALIDATE_PTR(reader);
+    XmlNode root = parser.getRootNode();
+
+	// final data
+	std::vector<aiMaterial *> materials;
+	std::vector<aiMesh *> meshes;
+	materials.reserve(5);
+	meshes.reserve(5);
+
+	// temporary data - current mesh buffer
+	aiMaterial *curMat = nullptr;
+	aiMesh *curMesh = nullptr;
+	unsigned int curMatFlags = 0;
+
+	std::vector<aiVector3D> curVertices, curNormals, curTangents, curBitangents;
+	std::vector<aiColor4D> curColors;
+	std::vector<aiVector3D> curUVs, curUV2s;
+
+	// some temporary variables
+	int textMeaning = 0;
+	int vertexFormat = 0; // 0 = normal; 1 = 2 tcoords, 2 = tangents
+	bool useColors = false;
+
+	// Parse the XML file
+	for (pugi::xml_node child : root.children()) {
+		if (child.type() == pugi::node_element) {
+			if (!ASSIMP_stricmp(child.name(), "buffer") && (curMat || curMesh)) {
+				// end of previous buffer. A material and a mesh should be there
+				if (!curMat || !curMesh) {
+					ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
+					releaseMaterial(&curMat);
+					releaseMesh(&curMesh);
+				} else {
+					materials.push_back(curMat);
+					meshes.push_back(curMesh);
+				}
+				curMat = nullptr;
+				curMesh = nullptr;
+
+				curVertices.clear();
+				curColors.clear();
+				curNormals.clear();
+				curUV2s.clear();
+				curUVs.clear();
+				curTangents.clear();
+				curBitangents.clear();
+			}
+
+			if (!ASSIMP_stricmp(child.name(), "material")) {
+				if (curMat) {
+					ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
+					releaseMaterial(&curMat);
+				}
+				curMat = ParseMaterial(curMatFlags);
+			}
+			/* no else here! */ if (!ASSIMP_stricmp(child.name(), "vertices")) {
+				pugi::xml_attribute attr = child.attribute("vertexCount");
+				int num = attr.as_int();
+                //int num = reader->getAttributeValueAsInt("vertexCount");
+
+				if (!num) {
+					// This is possible ... remove the mesh from the list and skip further reading
+					ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
+
+					releaseMaterial(&curMat);
+					releaseMesh(&curMesh);
+					textMeaning = 0;
+					continue;
+				}
+
+				curVertices.reserve(num);
+				curNormals.reserve(num);
+				curColors.reserve(num);
+				curUVs.reserve(num);
+
+				// Determine the file format
+				//const char *t = reader->getAttributeValueSafe("type");
+                pugi::xml_attribute t = child.attribute("type");
+				if (!ASSIMP_stricmp("2tcoords", t.name())) {
+					curUV2s.reserve(num);
+					vertexFormat = 1;
+
+					if (curMatFlags & AI_IRRMESH_EXTRA_2ND_TEXTURE) {
+						// *********************************************************
+						// We have a second texture! So use this UV channel
+						// for it. The 2nd texture can be either a normal
+						// texture (solid_2layer or lightmap_xxx) or a normal
+						// map (normal_..., parallax_...)
+						// *********************************************************
+						int idx = 1;
+						aiMaterial *mat = (aiMaterial *)curMat;
+
+						if (curMatFlags & AI_IRRMESH_MAT_lightmap) {
+							mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_LIGHTMAP(0));
+						} else if (curMatFlags & AI_IRRMESH_MAT_normalmap_solid) {
+							mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_NORMALS(0));
+						} else if (curMatFlags & AI_IRRMESH_MAT_solid_2layer) {
+							mat->AddProperty(&idx, 1, AI_MATKEY_UVWSRC_DIFFUSE(1));
+						}
+					}
+				} else if (!ASSIMP_stricmp("tangents", t.name())) {
+					curTangents.reserve(num);
+					curBitangents.reserve(num);
+					vertexFormat = 2;
+				} else if (ASSIMP_stricmp("standard", t.name())) {
+					releaseMaterial(&curMat);
+					ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format");
+				} else
+					vertexFormat = 0;
+				textMeaning = 1;
+			} else if (!ASSIMP_stricmp(child.name(), "indices")) {
+				if (curVertices.empty() && curMat) {
+					releaseMaterial(&curMat);
+					throw DeadlyImportError("IRRMESH: indices must come after vertices");
+				}
+
+				textMeaning = 2;
+
+				// start a new mesh
+				curMesh = new aiMesh();
+
+				// allocate storage for all faces
+				pugi::xml_attribute attr = child.attribute("indexCount");
+				curMesh->mNumVertices = attr.as_int();
+				if (!curMesh->mNumVertices) {
+					// This is possible ... remove the mesh from the list and skip further reading
+					ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
+
+					// mesh - away
+					releaseMesh(&curMesh);
+
+					// material - away
+					releaseMaterial(&curMat);
+
+					textMeaning = 0;
+					continue;
+				}
+
+				if (curMesh->mNumVertices % 3) {
+					ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
+				}
+
+				curMesh->mNumFaces = curMesh->mNumVertices / 3;
+				curMesh->mFaces = new aiFace[curMesh->mNumFaces];
+
+				// setup some members
+				curMesh->mMaterialIndex = (unsigned int)materials.size();
+				curMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+
+				// allocate storage for all vertices
+				curMesh->mVertices = new aiVector3D[curMesh->mNumVertices];
+
+				if (curNormals.size() == curVertices.size()) {
+					curMesh->mNormals = new aiVector3D[curMesh->mNumVertices];
+				}
+				if (curTangents.size() == curVertices.size()) {
+					curMesh->mTangents = new aiVector3D[curMesh->mNumVertices];
+				}
+				if (curBitangents.size() == curVertices.size()) {
+					curMesh->mBitangents = new aiVector3D[curMesh->mNumVertices];
+				}
+				if (curColors.size() == curVertices.size() && useColors) {
+					curMesh->mColors[0] = new aiColor4D[curMesh->mNumVertices];
+				}
+				if (curUVs.size() == curVertices.size()) {
+					curMesh->mTextureCoords[0] = new aiVector3D[curMesh->mNumVertices];
+				}
+				if (curUV2s.size() == curVertices.size()) {
+					curMesh->mTextureCoords[1] = new aiVector3D[curMesh->mNumVertices];
+				}
+			}
+			//break;
+
+			//case EXN_TEXT: {
+			const char *sz = child.child_value();
+			if (textMeaning == 1) {
+				textMeaning = 0;
+
+				// read vertices
+				do {
+					SkipSpacesAndLineEnd(&sz);
+					aiVector3D temp;
+					aiColor4D c;
+
+					// Read the vertex position
+					sz = fast_atoreal_move<float>(sz, (float &)temp.x);
+					SkipSpaces(&sz);
+
+					sz = fast_atoreal_move<float>(sz, (float &)temp.y);
+					SkipSpaces(&sz);
+
+					sz = fast_atoreal_move<float>(sz, (float &)temp.z);
+					SkipSpaces(&sz);
+					curVertices.push_back(temp);
+
+					// Read the vertex normals
+					sz = fast_atoreal_move<float>(sz, (float &)temp.x);
+					SkipSpaces(&sz);
+
+					sz = fast_atoreal_move<float>(sz, (float &)temp.y);
+					SkipSpaces(&sz);
+
+					sz = fast_atoreal_move<float>(sz, (float &)temp.z);
+					SkipSpaces(&sz);
+					curNormals.push_back(temp);
+
+					// read the vertex colors
+					uint32_t clr = strtoul16(sz, &sz);
+					ColorFromARGBPacked(clr, c);
+
+					if (!curColors.empty() && c != *(curColors.end() - 1))
+						useColors = true;
+
+					curColors.push_back(c);
+					SkipSpaces(&sz);
+
+					// read the first UV coordinate set
+					sz = fast_atoreal_move<float>(sz, (float &)temp.x);
+					SkipSpaces(&sz);
+
+					sz = fast_atoreal_move<float>(sz, (float &)temp.y);
+					SkipSpaces(&sz);
+					temp.z = 0.f;
+					temp.y = 1.f - temp.y; // DX to OGL
+					curUVs.push_back(temp);
+
+					// read the (optional) second UV coordinate set
+					if (vertexFormat == 1) {
+						sz = fast_atoreal_move<float>(sz, (float &)temp.x);
+						SkipSpaces(&sz);
+
+						sz = fast_atoreal_move<float>(sz, (float &)temp.y);
+						temp.y = 1.f - temp.y; // DX to OGL
+						curUV2s.push_back(temp);
+					}
+					// read optional tangent and bitangent vectors
+					else if (vertexFormat == 2) {
+						// tangents
+						sz = fast_atoreal_move<float>(sz, (float &)temp.x);
+						SkipSpaces(&sz);
+
+						sz = fast_atoreal_move<float>(sz, (float &)temp.z);
+						SkipSpaces(&sz);
+
+						sz = fast_atoreal_move<float>(sz, (float &)temp.y);
+						SkipSpaces(&sz);
+						temp.y *= -1.0f;
+						curTangents.push_back(temp);
+
+						// bitangents
+						sz = fast_atoreal_move<float>(sz, (float &)temp.x);
+						SkipSpaces(&sz);
+
+						sz = fast_atoreal_move<float>(sz, (float &)temp.z);
+						SkipSpaces(&sz);
+
+						sz = fast_atoreal_move<float>(sz, (float &)temp.y);
+						SkipSpaces(&sz);
+						temp.y *= -1.0f;
+						curBitangents.push_back(temp);
+					}
+				}
+
+				/* IMPORTANT: We assume that each vertex is specified in one
+                line. So we can skip the rest of the line - unknown vertex
+                elements are ignored.
+                */
+
+				while (SkipLine(&sz));
+			} else if (textMeaning == 2) {
+				textMeaning = 0;
+
+				// read indices
+				aiFace *curFace = curMesh->mFaces;
+				aiFace *const faceEnd = curMesh->mFaces + curMesh->mNumFaces;
+
+				aiVector3D *pcV = curMesh->mVertices;
+				aiVector3D *pcN = curMesh->mNormals;
+				aiVector3D *pcT = curMesh->mTangents;
+				aiVector3D *pcB = curMesh->mBitangents;
+				aiColor4D *pcC0 = curMesh->mColors[0];
+				aiVector3D *pcT0 = curMesh->mTextureCoords[0];
+				aiVector3D *pcT1 = curMesh->mTextureCoords[1];
+
+				unsigned int curIdx = 0;
+				unsigned int total = 0;
+				while (SkipSpacesAndLineEnd(&sz)) {
+					if (curFace >= faceEnd) {
+						ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
+						break;
+					}
+					if (!curIdx) {
+						curFace->mNumIndices = 3;
+						curFace->mIndices = new unsigned int[3];
+					}
+
+					unsigned int idx = strtoul10(sz, &sz);
+					if (idx >= curVertices.size()) {
+						ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
+						idx = 0;
+					}
+
+					curFace->mIndices[curIdx] = total++;
+
+					*pcV++ = curVertices[idx];
+					if (pcN) *pcN++ = curNormals[idx];
+					if (pcT) *pcT++ = curTangents[idx];
+					if (pcB) *pcB++ = curBitangents[idx];
+					if (pcC0) *pcC0++ = curColors[idx];
+					if (pcT0) *pcT0++ = curUVs[idx];
+					if (pcT1) *pcT1++ = curUV2s[idx];
+
+					if (++curIdx == 3) {
+						++curFace;
+						curIdx = 0;
+					}
+				}
+
+				if (curFace != faceEnd)
+					ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
+
+				// Finish processing the mesh - do some small material workarounds
+				if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
+					// Take the opacity value of the current material
+					// from the common vertex color alpha
+					aiMaterial *mat = (aiMaterial *)curMat;
+					mat->AddProperty(&curColors[0].a, 1, AI_MATKEY_OPACITY);
+				}
+			}
+		}
+	}
+
+	// End of the last buffer. A material and a mesh should be there
+	if (curMat || curMesh) {
+		if (!curMat || !curMesh) {
+			ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
+			releaseMaterial(&curMat);
+			releaseMesh(&curMesh);
+		} else {
+			materials.push_back(curMat);
+			meshes.push_back(curMesh);
+		}
+	}
+
+	if (materials.empty()) {
+		throw DeadlyImportError("IRRMESH: Unable to read a mesh from this file");
+	}
+
+	// now generate the output scene
+	pScene->mNumMeshes = (unsigned int)meshes.size();
+	pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
+	for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
+		pScene->mMeshes[i] = meshes[i];
+
+		// clean this value ...
+		pScene->mMeshes[i]->mNumUVComponents[3] = 0;
+	}
+
+	pScene->mNumMaterials = (unsigned int)materials.size();
+	pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
+	::memcpy(pScene->mMaterials, &materials[0], sizeof(void *) * pScene->mNumMaterials);
+
+	pScene->mRootNode = new aiNode();
+	pScene->mRootNode->mName.Set("<IRRMesh>");
+	pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
+	pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
+
+	for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
+		pScene->mRootNode->mMeshes[i] = i;
+	}
 }
 }
 
 
 #endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER
 #endif // !! ASSIMP_BUILD_NO_IRRMESH_IMPORTER

+ 8 - 15
code/AssetLib/Irr/IRRMeshLoader.h

@@ -4,7 +4,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,
@@ -47,12 +46,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_IRRMESHLOADER_H_INCLUDED
 #ifndef AI_IRRMESHLOADER_H_INCLUDED
 #define AI_IRRMESHLOADER_H_INCLUDED
 #define AI_IRRMESHLOADER_H_INCLUDED
 
 
-#include <assimp/BaseImporter.h>
 #include "IRRShared.h"
 #include "IRRShared.h"
+#include <assimp/BaseImporter.h>
 
 
 #ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER
 #ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER
 
 
-namespace Assimp    {
+namespace Assimp {
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** IrrMesh importer class.
 /** IrrMesh importer class.
@@ -61,37 +60,31 @@ namespace Assimp    {
  * irrEdit. As IrrEdit itself is capable of importing quite many file formats,
  * irrEdit. As IrrEdit itself is capable of importing quite many file formats,
  * it might be a good file format for data exchange.
  * it might be a good file format for data exchange.
  */
  */
-class IRRMeshImporter : public BaseImporter, public IrrlichtBase
-{
+class IRRMeshImporter : public BaseImporter, public IrrlichtBase {
 public:
 public:
     IRRMeshImporter();
     IRRMeshImporter();
     ~IRRMeshImporter();
     ~IRRMeshImporter();
 
 
-
-public:
-
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.
     /** Returns whether the class can handle the format of the given file.
      *  See BaseImporter::CanRead() for details.
      *  See BaseImporter::CanRead() for details.
      */
      */
-    bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
-        bool checkSig) const;
+    bool CanRead(const std::string &pFile, IOSystem *pIOHandler,
+            bool checkSig) const;
 
 
 protected:
 protected:
-
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Return importer meta information.
     /** Return importer meta information.
      * See #BaseImporter::GetInfo for the details
      * See #BaseImporter::GetInfo for the details
      */
      */
-    const aiImporterDesc* GetInfo () const;
+    const aiImporterDesc *GetInfo() const;
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Imports the given file into the given scene structure.
     /** Imports the given file into the given scene structure.
      * See BaseImporter::InternReadFile() for details
      * See BaseImporter::InternReadFile() for details
      */
      */
-    void InternReadFile( const std::string& pFile, aiScene* pScene,
-        IOSystem* pIOHandler);
-
+    void InternReadFile(const std::string &pFile, aiScene *pScene,
+            IOSystem *pIOHandler);
 };
 };
 
 
 } // end of namespace Assimp
 } // end of namespace Assimp

+ 215 - 329
code/AssetLib/Irr/IRRShared.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, 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,8 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Shared utilities for the IRR and IRRMESH loaders
  *  @brief Shared utilities for the IRR and IRRMESH loaders
  */
  */
 
 
-
-
 //This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
 //This section should be excluded only if both the Irrlicht AND the Irrlicht Mesh importers were omitted.
 #if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
 #if !(defined(ASSIMP_BUILD_NO_IRR_IMPORTER) && defined(ASSIMP_BUILD_NO_IRRMESH_IMPORTER))
 
 
@@ -56,10 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/material.h>
 #include <assimp/material.h>
 
 
-
 using namespace Assimp;
 using namespace Assimp;
-using namespace irr;
-using namespace irr::io;
 
 
 // Transformation matrix to convert from Assimp to IRR space
 // Transformation matrix to convert from Assimp to IRR space
 const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 (
 const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 (
@@ -70,125 +63,94 @@ const aiMatrix4x4 Assimp::AI_TO_IRR_MATRIX = aiMatrix4x4 (
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // read a property in hexadecimal format (i.e. ffffffff)
 // read a property in hexadecimal format (i.e. ffffffff)
-void IrrlichtBase::ReadHexProperty    (HexProperty&    out)
-{
-    for (int i = 0; i < reader->getAttributeCount();++i)
-    {
-        if (!ASSIMP_stricmp(reader->getAttributeName(i),"name"))
-        {
-            out.name = std::string( reader->getAttributeValue(i) );
-        }
-        else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
-        {
+void IrrlichtBase::ReadHexProperty(HexProperty &out ) {
+	for (pugi::xml_attribute attrib : mNode->attributes()) {
+        if (!ASSIMP_stricmp(attrib.name(), "name")) {
+            out.name = std::string( attrib.value() );
+        } else if (!ASSIMP_stricmp(attrib.name(),"value")) {
             // parse the hexadecimal value
             // parse the hexadecimal value
-            out.value = strtoul16(reader->getAttributeValue(i));
+			out.value = strtoul16(attrib.name());
         }
         }
     }
     }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // read a decimal property
 // read a decimal property
-void IrrlichtBase::ReadIntProperty    (IntProperty&    out)
-{
-    for (int i = 0; i < reader->getAttributeCount();++i)
-    {
-        if (!ASSIMP_stricmp(reader->getAttributeName(i),"name"))
-        {
-            out.name = std::string( reader->getAttributeValue(i) );
-        }
-        else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
-        {
-            // parse the ecimal value
-            out.value = strtol10(reader->getAttributeValue(i));
+void IrrlichtBase::ReadIntProperty(IntProperty & out) {
+	for (pugi::xml_attribute attrib : mNode->attributes()) {
+		if (!ASSIMP_stricmp(attrib.name(), "name")) {
+			out.name = std::string(attrib.value());
+        } else if (!ASSIMP_stricmp(attrib.value(),"value")) {
+            // parse the int value
+			out.value = strtol10(attrib.name());
         }
         }
     }
     }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // read a string property
 // read a string property
-void IrrlichtBase::ReadStringProperty (StringProperty& out)
-{
-    for (int i = 0; i < reader->getAttributeCount();++i)
-    {
-        if (!ASSIMP_stricmp(reader->getAttributeName(i),"name"))
-        {
-            out.name = std::string( reader->getAttributeValue(i) );
-        }
-        else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
-        {
+void IrrlichtBase::ReadStringProperty( StringProperty& out) {
+	for (pugi::xml_attribute attrib : mNode->attributes()) {
+		if (!ASSIMP_stricmp(attrib.name(), "name")) {
+			out.name = std::string(attrib.value());
+		} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
             // simple copy the string
             // simple copy the string
-            out.value = std::string (reader->getAttributeValue(i));
+			out.value = std::string(attrib.value());
         }
         }
     }
     }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // read a boolean property
 // read a boolean property
-void IrrlichtBase::ReadBoolProperty   (BoolProperty&   out)
-{
-    for (int i = 0; i < reader->getAttributeCount();++i)
-    {
-        if (!ASSIMP_stricmp(reader->getAttributeName(i),"name"))
-        {
-            out.name = std::string( reader->getAttributeValue(i) );
-        }
-        else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
-        {
+void IrrlichtBase::ReadBoolProperty(BoolProperty &out) {
+	for (pugi::xml_attribute attrib : mNode->attributes()) {
+		if (!ASSIMP_stricmp(attrib.name(), "name")){
+			out.name = std::string(attrib.value());
+		} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
             // true or false, case insensitive
             // true or false, case insensitive
-            out.value = (ASSIMP_stricmp( reader->getAttributeValue(i),
-                "true") ? false : true);
+			out.value = (ASSIMP_stricmp(attrib.value(), "true") ? false : true);
         }
         }
     }
     }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // read a float property
 // read a float property
-void IrrlichtBase::ReadFloatProperty  (FloatProperty&  out)
-{
-    for (int i = 0; i < reader->getAttributeCount();++i)
-    {
-        if (!ASSIMP_stricmp(reader->getAttributeName(i),"name"))
-        {
-            out.name = std::string( reader->getAttributeValue(i) );
-        }
-        else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
-        {
+void IrrlichtBase::ReadFloatProperty(FloatProperty &out) {
+	for (pugi::xml_attribute attrib : mNode->attributes()) {
+		if (!ASSIMP_stricmp(attrib.name(), "name")) {
+			out.name = std::string(attrib.value());
+		} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
             // just parse the float
             // just parse the float
-            out.value = fast_atof( reader->getAttributeValue(i) );
+			out.value = fast_atof(attrib.value());
         }
         }
     }
     }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // read a vector property
 // read a vector property
-void IrrlichtBase::ReadVectorProperty  (VectorProperty&  out)
-{
-    for (int i = 0; i < reader->getAttributeCount();++i)
-    {
-        if (!ASSIMP_stricmp(reader->getAttributeName(i),"name"))
-        {
-            out.name = std::string( reader->getAttributeValue(i) );
-        }
-        else if (!ASSIMP_stricmp(reader->getAttributeName(i),"value"))
-        {
+void IrrlichtBase::ReadVectorProperty( VectorProperty &out ) {
+	for (pugi::xml_attribute attrib : mNode->attributes()) {
+		if (!ASSIMP_stricmp(attrib.name(), "name")) {
+			out.name = std::string(attrib.value());
+		} else if (!ASSIMP_stricmp(attrib.name(), "value")) {
             // three floats, separated with commas
             // three floats, separated with commas
-            const char* ptr = reader->getAttributeValue(i);
+            const char *ptr = attrib.value();
 
 
             SkipSpaces(&ptr);
             SkipSpaces(&ptr);
             ptr = fast_atoreal_move<float>( ptr,(float&)out.value.x );
             ptr = fast_atoreal_move<float>( ptr,(float&)out.value.x );
             SkipSpaces(&ptr);
             SkipSpaces(&ptr);
-            if (',' != *ptr)
-            {
+            if (',' != *ptr) {
                 ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
                 ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
-            }
-            else SkipSpaces(ptr+1,&ptr);
+			} else {
+				SkipSpaces(ptr + 1, &ptr);
+			}
             ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y );
             ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y );
             SkipSpaces(&ptr);
             SkipSpaces(&ptr);
-            if (',' != *ptr)
-            {
+            if (',' != *ptr) {
                 ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
                 ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
-            }
-            else SkipSpaces(ptr+1,&ptr);
+			} else {
+				SkipSpaces(ptr + 1, &ptr);
+			}
             ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z );
             ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z );
         }
         }
     }
     }
@@ -196,22 +158,19 @@ void IrrlichtBase::ReadVectorProperty  (VectorProperty&  out)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Convert a string to a proper aiMappingMode
 // Convert a string to a proper aiMappingMode
-int ConvertMappingMode(const std::string& mode)
-{
-    if (mode == "texture_clamp_repeat")
-    {
+int ConvertMappingMode(const std::string& mode) {
+    if (mode == "texture_clamp_repeat") {
         return aiTextureMapMode_Wrap;
         return aiTextureMapMode_Wrap;
-    }
-    else if (mode == "texture_clamp_mirror")
-        return aiTextureMapMode_Mirror;
+	} else if (mode == "texture_clamp_mirror") {
+		return aiTextureMapMode_Mirror;
+	}
 
 
     return aiTextureMapMode_Clamp;
     return aiTextureMapMode_Clamp;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Parse a material from the XML file
 // Parse a material from the XML file
-aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
-{
+aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags) {
     aiMaterial* mat = new aiMaterial();
     aiMaterial* mat = new aiMaterial();
     aiColor4D clr;
     aiColor4D clr;
     aiString s;
     aiString s;
@@ -220,244 +179,170 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
     int cnt  = 0; // number of used texture channels
     int cnt  = 0; // number of used texture channels
     unsigned int nd = 0;
     unsigned int nd = 0;
 
 
-    // Continue reading from the file
-    while (reader->read())
-    {
-        switch (reader->getNodeType())
-        {
-        case EXN_ELEMENT:
-
-            // Hex properties
-            if (!ASSIMP_stricmp(reader->getNodeName(),"color"))
-            {
-                HexProperty prop;
-                ReadHexProperty(prop);
-                if (prop.name == "Diffuse")
-                {
-                    ColorFromARGBPacked(prop.value,clr);
-                    mat->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
-                }
-                else if (prop.name == "Ambient")
-                {
-                    ColorFromARGBPacked(prop.value,clr);
-                    mat->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT);
-                }
-                else if (prop.name == "Specular")
-                {
-                    ColorFromARGBPacked(prop.value,clr);
-                    mat->AddProperty(&clr,1,AI_MATKEY_COLOR_SPECULAR);
-                }
-
-                // NOTE: The 'emissive' property causes problems. It is
-                // often != 0, even if there is obviously no light
-                // emitted by the described surface. In fact I think
-                // IRRLICHT ignores this property, too.
+    for (pugi::xml_node child : mNode->children()) {
+		if (!ASSIMP_stricmp(child.name(), "color")) { // Hex properties
+			HexProperty prop;
+			ReadHexProperty(prop);
+			if (prop.name == "Diffuse") {
+				ColorFromARGBPacked(prop.value, clr);
+				mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
+			} else if (prop.name == "Ambient") {
+				ColorFromARGBPacked(prop.value, clr);
+				mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
+			} else if (prop.name == "Specular") {
+				ColorFromARGBPacked(prop.value, clr);
+				mat->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR);
+			}
+
+			// NOTE: The 'emissive' property causes problems. It is
+			// often != 0, even if there is obviously no light
+			// emitted by the described surface. In fact I think
+			// IRRLICHT ignores this property, too.
 #if 0
 #if 0
-                else if (prop.name == "Emissive")
-                {
-                    ColorFromARGBPacked(prop.value,clr);
-                    mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
-                }
-#endif
-            }
-            // Float properties
-            else if (!ASSIMP_stricmp(reader->getNodeName(),"float"))
-            {
-                FloatProperty prop;
-                ReadFloatProperty(prop);
-                if (prop.name == "Shininess")
-                {
-                    mat->AddProperty(&prop.value,1,AI_MATKEY_SHININESS);
-                }
-            }
-            // Bool properties
-            else if (!ASSIMP_stricmp(reader->getNodeName(),"bool"))
-            {
-                BoolProperty prop;
-                ReadBoolProperty(prop);
-                if (prop.name == "Wireframe")
-                {
-                    int val = (prop.value ? true : false);
-                    mat->AddProperty(&val,1,AI_MATKEY_ENABLE_WIREFRAME);
-                }
-                else if (prop.name == "GouraudShading")
-                {
-                    int val = (prop.value ? aiShadingMode_Gouraud
-                        : aiShadingMode_NoShading);
-                    mat->AddProperty(&val,1,AI_MATKEY_SHADING_MODEL);
-                }
-                else if (prop.name == "BackfaceCulling")
-                {
-                    int val = (!prop.value);
-                    mat->AddProperty(&val,1,AI_MATKEY_TWOSIDED);
-                }
-            }
-            // String properties - textures and texture related properties
-            else if (!ASSIMP_stricmp(reader->getNodeName(),"texture") ||
-                     !ASSIMP_stricmp(reader->getNodeName(),"enum"))
-            {
-                StringProperty prop;
-                ReadStringProperty(prop);
-                if (prop.value.length())
-                {
-                    // material type (shader)
-                    if (prop.name == "Type")
-                    {
-                        if (prop.value == "solid")
-                        {
-                            // default material ...
-                        }
-                        else if (prop.value == "trans_vertex_alpha")
-                        {
-                            matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
-                        }
-                        else if (prop.value == "lightmap")
-                        {
-                            matFlags = AI_IRRMESH_MAT_lightmap;
-                        }
-                        else if (prop.value == "solid_2layer")
-                        {
-                            matFlags = AI_IRRMESH_MAT_solid_2layer;
-                        }
-                        else if (prop.value == "lightmap_m2")
-                        {
-                            matFlags = AI_IRRMESH_MAT_lightmap_m2;
-                        }
-                        else if (prop.value == "lightmap_m4")
-                        {
-                            matFlags = AI_IRRMESH_MAT_lightmap_m4;
-                        }
-                        else if (prop.value == "lightmap_light")
-                        {
-                            matFlags = AI_IRRMESH_MAT_lightmap_light;
-                        }
-                        else if (prop.value == "lightmap_light_m2")
-                        {
-                            matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
-                        }
-                        else if (prop.value == "lightmap_light_m4")
-                        {
-                            matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
-                        }
-                        else if (prop.value == "lightmap_add")
-                        {
-                            matFlags = AI_IRRMESH_MAT_lightmap_add;
-                        }
-                        // Normal and parallax maps are treated equally
-                        else if (prop.value == "normalmap_solid" ||
-                            prop.value == "parallaxmap_solid")
-                        {
-                            matFlags = AI_IRRMESH_MAT_normalmap_solid;
-                        }
-                        else if (prop.value == "normalmap_trans_vertex_alpha" ||
-                            prop.value == "parallaxmap_trans_vertex_alpha")
-                        {
-                            matFlags = AI_IRRMESH_MAT_normalmap_tva;
-                        }
-                        else if (prop.value == "normalmap_trans_add" ||
-                            prop.value == "parallaxmap_trans_add")
-                        {
-                            matFlags = AI_IRRMESH_MAT_normalmap_ta;
-                        }
-                        else {
-                            ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: " + prop.value);
-                        }
-                    }
-
-                    // Up to 4 texture channels are supported
-                    if (prop.name == "Texture1")
-                    {
-                        // Always accept the primary texture channel
-                        ++cnt;
-                        s.Set(prop.value);
-                        mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0));
-                    }
-                    else if (prop.name == "Texture2" && cnt == 1)
-                    {
-                        // 2-layer material lightmapped?
-                        if (matFlags & AI_IRRMESH_MAT_lightmap) {
-                            ++cnt;
-                            s.Set(prop.value);
-                            mat->AddProperty(&s,AI_MATKEY_TEXTURE_LIGHTMAP(0));
-
-                            // set the corresponding material flag
-                            matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
-                        }
-                        // alternatively: normal or parallax mapping
-                        else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) {
-                            ++cnt;
-                            s.Set(prop.value);
-                            mat->AddProperty(&s,AI_MATKEY_TEXTURE_NORMALS(0));
-
-                            // set the corresponding material flag
-                            matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
-                        } else if (matFlags & AI_IRRMESH_MAT_solid_2layer)    {// or just as second diffuse texture
-                            ++cnt;
-                            s.Set(prop.value);
-                            mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(1));
-                            ++nd;
-
-                            // set the corresponding material flag
-                            matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
-                        } else {
-                            ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
-                        }
-                    } else if (prop.name == "Texture3" && cnt == 2) {
-                        // Irrlicht does not seem to use these channels.
-                        ++cnt;
-                        s.Set(prop.value);
-                        mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(nd+1));
-                    } else if (prop.name == "Texture4" && cnt == 3) {
-                        // Irrlicht does not seem to use these channels.
-                        ++cnt;
-                        s.Set(prop.value);
-                        mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(nd+2));
-                    }
-
-                    // Texture mapping options
-                    if (prop.name == "TextureWrap1" && cnt >= 1)
-                    {
-                        int map = ConvertMappingMode(prop.value);
-                        mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
-                        mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
-                    }
-                    else if (prop.name == "TextureWrap2" && cnt >= 2)
-                    {
-                        int map = ConvertMappingMode(prop.value);
-                        if (matFlags & AI_IRRMESH_MAT_lightmap) {
-                            mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
-                            mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
-                        }
-                        else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
-                            mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
-                            mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
-                        }
-                        else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
-                            mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
-                            mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
-                        }
-                    }
-                    else if (prop.name == "TextureWrap3" && cnt >= 3)
-                    {
-                        int map = ConvertMappingMode(prop.value);
-                        mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd+1));
-                        mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd+1));
-                    }
-                    else if (prop.name == "TextureWrap4" && cnt >= 4)
-                    {
-                        int map = ConvertMappingMode(prop.value);
-                        mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd+2));
-                        mat->AddProperty(&map,1,AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd+2));
-                    }
-                }
+            else if (prop.name == "Emissive") {
+                ColorFromARGBPacked(prop.value,clr);
+                mat->AddProperty(&clr,1,AI_MATKEY_COLOR_EMISSIVE);
             }
             }
-            break;
-            case EXN_ELEMENT_END:
-
-                /* Assume there are no further nested nodes in <material> elements
-                 */
-                if (/* IRRMESH */ !ASSIMP_stricmp(reader->getNodeName(),"material") ||
-                    /* IRR     */ !ASSIMP_stricmp(reader->getNodeName(),"attributes"))
+#endif
+		} else if (!ASSIMP_stricmp(child.name(), "float")) { // Float properties
+			FloatProperty prop;
+			ReadFloatProperty(prop);
+			if (prop.name == "Shininess") {
+				mat->AddProperty(&prop.value, 1, AI_MATKEY_SHININESS);
+			}
+		} else if (!ASSIMP_stricmp(child.name(), "bool")) { // Bool properties
+			BoolProperty prop;
+			ReadBoolProperty(prop);
+			if (prop.name == "Wireframe") {
+				int val = (prop.value ? true : false);
+				mat->AddProperty(&val, 1, AI_MATKEY_ENABLE_WIREFRAME);
+			} else if (prop.name == "GouraudShading") {
+				int val = (prop.value ? aiShadingMode_Gouraud : aiShadingMode_NoShading);
+				mat->AddProperty(&val, 1, AI_MATKEY_SHADING_MODEL);
+			} else if (prop.name == "BackfaceCulling") {
+				int val = (!prop.value);
+				mat->AddProperty(&val, 1, AI_MATKEY_TWOSIDED);
+			}
+		} else if (!ASSIMP_stricmp(child.name(), "texture") ||
+				   !ASSIMP_stricmp(child.name(), "enum")) { // String properties - textures and texture related properties
+			StringProperty prop;
+			ReadStringProperty(prop);
+			if (prop.value.length()) {
+				// material type (shader)
+				if (prop.name == "Type") {
+					if (prop.value == "solid") {
+						// default material ...
+					} else if (prop.value == "trans_vertex_alpha") {
+						matFlags = AI_IRRMESH_MAT_trans_vertex_alpha;
+					} else if (prop.value == "lightmap") {
+						matFlags = AI_IRRMESH_MAT_lightmap;
+					} else if (prop.value == "solid_2layer") {
+						matFlags = AI_IRRMESH_MAT_solid_2layer;
+					} else if (prop.value == "lightmap_m2") {
+						matFlags = AI_IRRMESH_MAT_lightmap_m2;
+					} else if (prop.value == "lightmap_m4") {
+						matFlags = AI_IRRMESH_MAT_lightmap_m4;
+					} else if (prop.value == "lightmap_light") {
+						matFlags = AI_IRRMESH_MAT_lightmap_light;
+					} else if (prop.value == "lightmap_light_m2") {
+						matFlags = AI_IRRMESH_MAT_lightmap_light_m2;
+					} else if (prop.value == "lightmap_light_m4") {
+						matFlags = AI_IRRMESH_MAT_lightmap_light_m4;
+					} else if (prop.value == "lightmap_add") {
+						matFlags = AI_IRRMESH_MAT_lightmap_add;
+					} else if (prop.value == "normalmap_solid" ||
+							   prop.value == "parallaxmap_solid") { // Normal and parallax maps are treated equally
+						matFlags = AI_IRRMESH_MAT_normalmap_solid;
+					} else if (prop.value == "normalmap_trans_vertex_alpha" ||
+							   prop.value == "parallaxmap_trans_vertex_alpha") {
+						matFlags = AI_IRRMESH_MAT_normalmap_tva;
+					} else if (prop.value == "normalmap_trans_add" ||
+							   prop.value == "parallaxmap_trans_add") {
+						matFlags = AI_IRRMESH_MAT_normalmap_ta;
+					} else {
+						ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: " + prop.value);
+					}
+				}
+
+				// Up to 4 texture channels are supported
+				if (prop.name == "Texture1") {
+					// Always accept the primary texture channel
+					++cnt;
+					s.Set(prop.value);
+					mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(0));
+				} else if (prop.name == "Texture2" && cnt == 1) {
+					// 2-layer material lightmapped?
+					if (matFlags & AI_IRRMESH_MAT_lightmap) {
+						++cnt;
+						s.Set(prop.value);
+						mat->AddProperty(&s, AI_MATKEY_TEXTURE_LIGHTMAP(0));
+
+						// set the corresponding material flag
+						matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
+					} else if (matFlags & AI_IRRMESH_MAT_normalmap_solid) { // alternatively: normal or parallax mapping
+						++cnt;
+						s.Set(prop.value);
+						mat->AddProperty(&s, AI_MATKEY_TEXTURE_NORMALS(0));
+
+						// set the corresponding material flag
+						matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
+					} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) { // or just as second diffuse texture
+						++cnt;
+						s.Set(prop.value);
+						mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(1));
+						++nd;
+
+						// set the corresponding material flag
+						matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
+					} else {
+						ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
+					}
+				} else if (prop.name == "Texture3" && cnt == 2) {
+					// Irrlicht does not seem to use these channels.
+					++cnt;
+					s.Set(prop.value);
+					mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 1));
+				} else if (prop.name == "Texture4" && cnt == 3) {
+					// Irrlicht does not seem to use these channels.
+					++cnt;
+					s.Set(prop.value);
+					mat->AddProperty(&s, AI_MATKEY_TEXTURE_DIFFUSE(nd + 2));
+				}
+
+				// Texture mapping options
+				if (prop.name == "TextureWrap1" && cnt >= 1) {
+					int map = ConvertMappingMode(prop.value);
+					mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
+					mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
+				} else if (prop.name == "TextureWrap2" && cnt >= 2) {
+					int map = ConvertMappingMode(prop.value);
+					if (matFlags & AI_IRRMESH_MAT_lightmap) {
+						mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_LIGHTMAP(0));
+						mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_LIGHTMAP(0));
+					} else if (matFlags & (AI_IRRMESH_MAT_normalmap_solid)) {
+						mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_NORMALS(0));
+						mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_NORMALS(0));
+					} else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
+						mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(1));
+						mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(1));
+					}
+				} else if (prop.name == "TextureWrap3" && cnt >= 3) {
+					int map = ConvertMappingMode(prop.value);
+					mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 1));
+					mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 1));
+				} else if (prop.name == "TextureWrap4" && cnt >= 4) {
+					int map = ConvertMappingMode(prop.value);
+					mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(nd + 2));
+					mat->AddProperty(&map, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(nd + 2));
+				}
+			}
+		}
+		//break;
+		/*case EXN_ELEMENT_END:
+
+                // Assume there are no further nested nodes in <material> elements
+                if ( !ASSIMP_stricmp(reader->getNodeName(),"material") ||
+                     !ASSIMP_stricmp(reader->getNodeName(),"attributes"))
                 {
                 {
                     // Now process lightmapping flags
                     // Now process lightmapping flags
                     // We should have at least one textur to do that ..
                     // We should have at least one textur to do that ..
@@ -492,7 +377,8 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
                 // GCC complains here ...
                 // GCC complains here ...
                 break;
                 break;
         }
         }
-    }
+    }*/
+	}
     ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
     ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
 
 
     return mat;
     return mat;

+ 45 - 44
code/AssetLib/Irr/IRRShared.h

@@ -7,50 +7,48 @@
 #ifndef INCLUDED_AI_IRRSHARED_H
 #ifndef INCLUDED_AI_IRRSHARED_H
 #define INCLUDED_AI_IRRSHARED_H
 #define INCLUDED_AI_IRRSHARED_H
 
 
-#include <assimp/irrXMLWrapper.h>
 #include <assimp/BaseImporter.h>
 #include <assimp/BaseImporter.h>
+#include <assimp/XmlParser.h>
 #include <stdint.h>
 #include <stdint.h>
 
 
 struct aiMaterial;
 struct aiMaterial;
 
 
-namespace Assimp    {
-
+namespace Assimp {
 
 
 /** @brief Matrix to convert from Assimp to IRR and backwards
 /** @brief Matrix to convert from Assimp to IRR and backwards
  */
  */
 extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
 extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
 
 
-
 // Default: 0 = solid, one texture
 // Default: 0 = solid, one texture
-#define AI_IRRMESH_MAT_solid_2layer         0x10000
+#define AI_IRRMESH_MAT_solid_2layer 0x10000
 
 
 // Transparency flags
 // Transparency flags
-#define AI_IRRMESH_MAT_trans_vertex_alpha   0x1
-#define AI_IRRMESH_MAT_trans_add            0x2
+#define AI_IRRMESH_MAT_trans_vertex_alpha 0x1
+#define AI_IRRMESH_MAT_trans_add 0x2
 
 
 // Lightmapping flags
 // Lightmapping flags
-#define AI_IRRMESH_MAT_lightmap             0x2
-#define AI_IRRMESH_MAT_lightmap_m2          (AI_IRRMESH_MAT_lightmap|0x4)
-#define AI_IRRMESH_MAT_lightmap_m4          (AI_IRRMESH_MAT_lightmap|0x8)
-#define AI_IRRMESH_MAT_lightmap_light       (AI_IRRMESH_MAT_lightmap|0x10)
-#define AI_IRRMESH_MAT_lightmap_light_m2    (AI_IRRMESH_MAT_lightmap|0x20)
-#define AI_IRRMESH_MAT_lightmap_light_m4    (AI_IRRMESH_MAT_lightmap|0x40)
-#define AI_IRRMESH_MAT_lightmap_add         (AI_IRRMESH_MAT_lightmap|0x80)
+#define AI_IRRMESH_MAT_lightmap 0x2
+#define AI_IRRMESH_MAT_lightmap_m2 (AI_IRRMESH_MAT_lightmap | 0x4)
+#define AI_IRRMESH_MAT_lightmap_m4 (AI_IRRMESH_MAT_lightmap | 0x8)
+#define AI_IRRMESH_MAT_lightmap_light (AI_IRRMESH_MAT_lightmap | 0x10)
+#define AI_IRRMESH_MAT_lightmap_light_m2 (AI_IRRMESH_MAT_lightmap | 0x20)
+#define AI_IRRMESH_MAT_lightmap_light_m4 (AI_IRRMESH_MAT_lightmap | 0x40)
+#define AI_IRRMESH_MAT_lightmap_add (AI_IRRMESH_MAT_lightmap | 0x80)
 
 
 // Standard NormalMap (or Parallax map, they're treated equally)
 // Standard NormalMap (or Parallax map, they're treated equally)
-#define AI_IRRMESH_MAT_normalmap_solid      (0x100)
+#define AI_IRRMESH_MAT_normalmap_solid (0x100)
 
 
 // Normal map combined with vertex alpha
 // Normal map combined with vertex alpha
-#define AI_IRRMESH_MAT_normalmap_tva    \
+#define AI_IRRMESH_MAT_normalmap_tva \
     (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_vertex_alpha)
     (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_vertex_alpha)
 
 
 // Normal map combined with additive transparency
 // Normal map combined with additive transparency
-#define AI_IRRMESH_MAT_normalmap_ta     \
+#define AI_IRRMESH_MAT_normalmap_ta \
     (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_add)
     (AI_IRRMESH_MAT_normalmap_solid | AI_IRRMESH_MAT_trans_add)
 
 
 // Special flag. It indicates a second texture has been found
 // Special flag. It indicates a second texture has been found
 // Its type depends ... either a normal textue or a normal map
 // Its type depends ... either a normal textue or a normal map
-#define AI_IRRMESH_EXTRA_2ND_TEXTURE        0x100000
+#define AI_IRRMESH_EXTRA_2ND_TEXTURE 0x100000
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** Base class for the Irr and IrrMesh importers.
 /** Base class for the Irr and IrrMesh importers.
@@ -58,61 +56,64 @@ extern const aiMatrix4x4 AI_TO_IRR_MATRIX;
  *  Declares some irrlight-related xml parsing utilities and provides tools
  *  Declares some irrlight-related xml parsing utilities and provides tools
  *  to load materials from IRR and IRRMESH files.
  *  to load materials from IRR and IRRMESH files.
  */
  */
-class IrrlichtBase
-{
+class IrrlichtBase {
 protected:
 protected:
+    IrrlichtBase() :
+            mNode(nullptr) {
+        // empty
+    }
+
+    ~IrrlichtBase() {
+        // empty
+    }
 
 
     /** @brief Data structure for a simple name-value property
     /** @brief Data structure for a simple name-value property
      */
      */
     template <class T>
     template <class T>
-    struct Property
-    {
+    struct Property {
         std::string name;
         std::string name;
         T value;
         T value;
     };
     };
 
 
-    typedef Property<uint32_t>      HexProperty;
-    typedef Property<std::string>   StringProperty;
-    typedef Property<bool>          BoolProperty;
-    typedef Property<float>         FloatProperty;
-    typedef Property<aiVector3D>    VectorProperty;
-    typedef Property<int>           IntProperty;
+    typedef Property<uint32_t> HexProperty;
+    typedef Property<std::string> StringProperty;
+    typedef Property<bool> BoolProperty;
+    typedef Property<float> FloatProperty;
+    typedef Property<aiVector3D> VectorProperty;
+    typedef Property<int> IntProperty;
 
 
-    /** XML reader instance
-     */
-  irr::io::IrrXMLReader* reader;
+    /// XML reader instance
+    XmlParser mParser;
+    pugi::xml_node *mNode;
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Parse a material description from the XML
     /** Parse a material description from the XML
      *  @return The created material
      *  @return The created material
      *  @param matFlags Receives AI_IRRMESH_MAT_XX flags
      *  @param matFlags Receives AI_IRRMESH_MAT_XX flags
      */
      */
-    aiMaterial* ParseMaterial(unsigned int& matFlags);
+    aiMaterial *ParseMaterial(unsigned int &matFlags);
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Read a property of the specified type from the current XML element.
     /** Read a property of the specified type from the current XML element.
      *  @param out Receives output data
      *  @param out Receives output data
      */
      */
-    void ReadHexProperty    (HexProperty&    out);
-    void ReadStringProperty (StringProperty& out);
-    void ReadBoolProperty   (BoolProperty&   out);
-    void ReadFloatProperty  (FloatProperty&  out);
-    void ReadVectorProperty (VectorProperty&  out);
-    void ReadIntProperty    (IntProperty&    out);
+    void ReadHexProperty(HexProperty &out);
+    void ReadStringProperty(StringProperty &out);
+    void ReadBoolProperty(BoolProperty &out);
+    void ReadFloatProperty(FloatProperty &out);
+    void ReadVectorProperty(VectorProperty &out);
+    void ReadIntProperty(IntProperty &out);
 };
 };
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Unpack a hex color, e.g. 0xdcdedfff
 // Unpack a hex color, e.g. 0xdcdedfff
-inline void ColorFromARGBPacked(uint32_t in, aiColor4D& clr)
-{
+inline void ColorFromARGBPacked(uint32_t in, aiColor4D &clr) {
     clr.a = ((in >> 24) & 0xff) / 255.f;
     clr.a = ((in >> 24) & 0xff) / 255.f;
     clr.r = ((in >> 16) & 0xff) / 255.f;
     clr.r = ((in >> 16) & 0xff) / 255.f;
-    clr.g = ((in >>  8) & 0xff) / 255.f;
-    clr.b = ((in      ) & 0xff) / 255.f;
+    clr.g = ((in >> 8) & 0xff) / 255.f;
+    clr.b = ((in)&0xff) / 255.f;
 }
 }
 
 
-
 } // end namespace Assimp
 } // end namespace Assimp
 
 
 #endif // !! INCLUDED_AI_IRRSHARED_H
 #endif // !! INCLUDED_AI_IRRSHARED_H

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

@@ -145,7 +145,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open LWO file " + pFile + ".");
+        throw DeadlyImportError("Failed to open LWO file ", pFile, ".");
     }
     }
 
 
     if ((this->fileSize = (unsigned int)file->FileSize()) < 12) {
     if ((this->fileSize = (unsigned int)file->FileSize()) < 12) {
@@ -212,7 +212,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
         szBuff[2] = (char)(fileType >> 8u);
         szBuff[2] = (char)(fileType >> 8u);
         szBuff[3] = (char)(fileType);
         szBuff[3] = (char)(fileType);
         szBuff[4] = '\0';
         szBuff[4] = '\0';
-        throw DeadlyImportError(std::string("Unknown LWO sub format: ") + szBuff);
+        throw DeadlyImportError("Unknown LWO sub format: ", szBuff);
     }
     }
 
 
     if (AI_LWO_FOURCC_LWOB != fileType) {
     if (AI_LWO_FOURCC_LWOB != fileType) {
@@ -232,7 +232,7 @@ void LWOImporter::InternReadFile(const std::string &pFile,
         }
         }
 
 
         if (configLayerName.length() && !hasNamedLayer) {
         if (configLayerName.length() && !hasNamedLayer) {
-            throw DeadlyImportError("LWO2: Unable to find the requested layer: " + configLayerName);
+            throw DeadlyImportError("LWO2: Unable to find the requested layer: ", configLayerName);
         }
         }
     }
     }
 
 

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

@@ -502,7 +502,7 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open LWS file " + pFile + ".");
+        throw DeadlyImportError("Failed to open LWS file ", pFile, ".");
     }
     }
 
 
     // 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
@@ -750,12 +750,17 @@ void LWSImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
         }
         }
         // 'LightIntensity': set intensity of currently active light
         // 'LightIntensity': set intensity of currently active light
         else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity") {
         else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity") {
-            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
+            if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT) {
                 ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightIntensity\'");
                 ASSIMP_LOG_ERROR("LWS: Unexpected keyword: \'LightIntensity\'");
-
-            else
-                fast_atoreal_move<float>(c, nodes.back().lightIntensity);
-
+            } else {
+                const std::string env = "(envelope)";
+                if (0 == strncmp(c, env.c_str(), env.size())) {
+                    ASSIMP_LOG_ERROR("LWS: envelopes for  LightIntensity not supported, set to 1.0");
+                    nodes.back().lightIntensity = (ai_real)1.0;
+                } else {
+                    fast_atoreal_move<float>(c, nodes.back().lightIntensity);
+                }
+            }
         }
         }
         // 'LightType': set type of currently active light
         // 'LightType': set type of currently active light
         else if ((*it).tokens[0] == "LightType") {
         else if ((*it).tokens[0] == "LightType") {

+ 5 - 2
code/AssetLib/M3D/M3DExporter.cpp

@@ -197,12 +197,15 @@ M3D_INDEX addMaterial(const Assimp::M3DWrapper &m3d, const aiMaterial *mat) {
                         break;
                         break;
                     case m3dpf_float:
                     case m3dpf_float:
                         if (mat->Get(aiProps[k].pKey, aiProps[k].type,
                         if (mat->Get(aiProps[k].pKey, aiProps[k].type,
-                                    aiProps[k].index, f) == AI_SUCCESS)
+                                    aiProps[k].index, f) == AI_SUCCESS) {
+                            uint32_t f_uint32;
+                            memcpy(&f_uint32, &f, sizeof(uint32_t));
                             addProp(&m3d->material[mi],
                             addProp(&m3d->material[mi],
                                     m3d_propertytypes[k].id,
                                     m3d_propertytypes[k].id,
                                     /* not (uint32_t)f, because we don't want to convert
                                     /* not (uint32_t)f, because we don't want to convert
                                          * it, we want to see it as 32 bits of memory */
                                          * it, we want to see it as 32 bits of memory */
-                                    *((uint32_t *)&f));
+                                    f_uint32);
+                        }
                         break;
                         break;
                     case m3dpf_uint8:
                     case m3dpf_uint8:
                         if (mat->Get(aiProps[k].pKey, aiProps[k].type,
                         if (mat->Get(aiProps[k].pKey, aiProps[k].type,

+ 5 - 5
code/AssetLib/M3D/M3DImporter.cpp

@@ -160,21 +160,21 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys
     // Read file into memory
     // Read file into memory
     std::unique_ptr<IOStream> pStream(pIOHandler->Open(file, "rb"));
     std::unique_ptr<IOStream> pStream(pIOHandler->Open(file, "rb"));
     if (!pStream.get()) {
     if (!pStream.get()) {
-        throw DeadlyImportError("Failed to open file " + file + ".");
+        throw DeadlyImportError("Failed to open file ", file, ".");
     }
     }
 
 
     // Get the file-size and validate it, throwing an exception when fails
     // Get the file-size and validate it, throwing an exception when fails
     size_t fileSize = pStream->FileSize();
     size_t fileSize = pStream->FileSize();
     if (fileSize < 8) {
     if (fileSize < 8) {
-        throw DeadlyImportError("M3D-file " + file + " is too small.");
+        throw DeadlyImportError("M3D-file ", file, " is too small.");
     }
     }
     std::vector<unsigned char> buffer(fileSize);
     std::vector<unsigned char> buffer(fileSize);
     if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) {
     if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) {
-        throw DeadlyImportError("Failed to read the file " + file + ".");
+        throw DeadlyImportError("Failed to read the file ", file, ".");
     }
     }
     // extra check for binary format's first 8 bytes. Not done for the ASCII variant
     // extra check for binary format's first 8 bytes. Not done for the ASCII variant
     if (!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) {
     if (!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) {
-        throw DeadlyImportError("Bad binary header in file " + file + ".");
+        throw DeadlyImportError("Bad binary header in file ", file, ".");
     }
     }
 #ifdef M3D_ASCII
 #ifdef M3D_ASCII
     // make sure there's a terminator zero character, as input must be ASCIIZ
     // make sure there's a terminator zero character, as input must be ASCIIZ
@@ -200,7 +200,7 @@ void M3DImporter::InternReadFile(const std::string &file, aiScene *pScene, IOSys
     M3DWrapper m3d(pIOHandler, buffer);
     M3DWrapper m3d(pIOHandler, buffer);
 
 
     if (!m3d) {
     if (!m3d) {
-        throw DeadlyImportError("Unable to parse " + file + " as M3D.");
+        throw DeadlyImportError("Unable to parse ", file, " as M3D.");
     }
     }
 
 
     // create the root node
     // create the root node

+ 3 - 0
code/AssetLib/M3D/M3DWrapper.cpp

@@ -133,6 +133,9 @@ unsigned char *M3DWrapper::Save(int quality, int flags, unsigned int &size) {
     saved_output_ = m3d_save(m3d_, quality, flags, &size);
     saved_output_ = m3d_save(m3d_, quality, flags, &size);
     return saved_output_;
     return saved_output_;
 #else
 #else
+    (void)quality;
+    (void)flags;
+    (void)size;
     return nullptr;
     return nullptr;
 #endif
 #endif
 }
 }

Dosya farkı çok büyük olduğundan ihmal edildi
+ 423 - 421
code/AssetLib/M3D/m3d.h


+ 1 - 1
code/AssetLib/MD2/MD2Loader.cpp

@@ -222,7 +222,7 @@ void MD2Importer::InternReadFile( const std::string& pFile,
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open MD2 file " + pFile + "");
+        throw DeadlyImportError("Failed to open MD2 file ", pFile, "");
     }
     }
 
 
     // check whether the md3 file is large enough to contain
     // check whether the md3 file is large enough to contain

+ 1 - 1
code/AssetLib/MD3/MD3Loader.cpp

@@ -715,7 +715,7 @@ void MD3Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSy
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open MD3 file " + pFile + ".");
+        throw DeadlyImportError("Failed to open MD3 file ", pFile, ".");
     }
     }
 
 
     // Check whether the md3 file is large enough to contain the header
     // Check whether the md3 file is large enough to contain the header

+ 1 - 1
code/AssetLib/MD5/MD5Loader.cpp

@@ -675,7 +675,7 @@ void MD5Importer::LoadMD5CameraFile() {
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (!file.get() || !file->FileSize()) {
     if (!file.get() || !file->FileSize()) {
-        throw DeadlyImportError("Failed to read MD5CAMERA file: " + pFile);
+        throw DeadlyImportError("Failed to read MD5CAMERA file: ", pFile);
     }
     }
     mHadMD5Camera = true;
     mHadMD5Camera = true;
     LoadFileIntoMemory(file.get());
     LoadFileIntoMemory(file.get());

+ 1 - 1
code/AssetLib/MDC/MDCLoader.cpp

@@ -219,7 +219,7 @@ void MDCImporter::InternReadFile(
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open MDC file " + pFile + ".");
+        throw DeadlyImportError("Failed to open MDC file ", pFile, ".");
     }
     }
 
 
     // check whether the mdc file is large enough to contain the file header
     // check whether the mdc file is large enough to contain the file header

+ 4 - 4
code/AssetLib/MDL/HalfLife/HL1MDLLoader.cpp

@@ -68,9 +68,9 @@ namespace Assimp {
 namespace MDL {
 namespace MDL {
 namespace HalfLife {
 namespace HalfLife {
 
 
-#ifdef _WIN32
-#    pragma warning(disable : 4706) 
-#endif // _WIN32
+#ifdef _MSC_VER
+#    pragma warning(disable : 4706)
+#endif // _MSC_VER
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 HL1MDLLoader::HL1MDLLoader(
 HL1MDLLoader::HL1MDLLoader(
@@ -829,7 +829,7 @@ void HL1MDLLoader::read_meshes() {
                         }
                         }
                     } else {
                     } else {
                         for (int faceIdx = 0; faceIdx < num_faces; ++faceIdx) {
                         for (int faceIdx = 0; faceIdx < num_faces; ++faceIdx) {
-                            if (i & 1) {
+                            if (faceIdx & 1) {
                                 // Preserve winding order.
                                 // Preserve winding order.
                                 mesh_faces.push_back(HL1MeshFace{
                                 mesh_faces.push_back(HL1MeshFace{
                                         tricmds[faceIdx + 1],
                                         tricmds[faceIdx + 1],

+ 2 - 2
code/AssetLib/MDL/HalfLife/HL1MDLLoader.h

@@ -218,12 +218,12 @@ private:
 template <typename MDLFileHeader>
 template <typename MDLFileHeader>
 void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) {
 void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) {
     if (!io_->Exists(file_path))
     if (!io_->Exists(file_path))
-        throw DeadlyImportError("Missing file " + DefaultIOSystem::fileName(file_path) + ".");
+        throw DeadlyImportError("Missing file ", DefaultIOSystem::fileName(file_path), ".");
 
 
     std::unique_ptr<IOStream> file(io_->Open(file_path));
     std::unique_ptr<IOStream> file(io_->Open(file_path));
 
 
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open MDL file " + DefaultIOSystem::fileName(file_path) + ".");
+        throw DeadlyImportError("Failed to open MDL file ", DefaultIOSystem::fileName(file_path), ".");
     }
     }
 
 
     const size_t file_size = file->FileSize();
     const size_t file_size = file->FileSize();

+ 3 - 3
code/AssetLib/MDL/MDLLoader.cpp

@@ -167,7 +167,7 @@ void MDLImporter::InternReadFile(const std::string &pFile,
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (file.get() == nullptr) {
     if (file.get() == nullptr) {
-        throw DeadlyImportError("Failed to open MDL file " + pFile + ".");
+        throw DeadlyImportError("Failed to open MDL file ", pFile, ".");
     }
     }
 
 
     // This should work for all other types of MDL files, too ...
     // This should work for all other types of MDL files, too ...
@@ -251,8 +251,8 @@ void MDLImporter::InternReadFile(const std::string &pFile,
             }
             }
         } else {
         } else {
             // print the magic word to the log file
             // print the magic word to the log file
-            throw DeadlyImportError("Unknown MDL subformat " + pFile +
-                                    ". Magic word (" + std::string((char *)&iMagicWord, 4) + ") is not known");
+            throw DeadlyImportError("Unknown MDL subformat ", pFile,
+                                    ". Magic word (", std::string((char *)&iMagicWord, 4), ") is not known");
         }
         }
 
 
         // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system
         // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system

+ 2 - 2
code/AssetLib/MMD/MMDImporter.cpp

@@ -111,7 +111,7 @@ void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene,
     // Read file by istream
     // Read file by istream
     std::filebuf fb;
     std::filebuf fb;
     if (!fb.open(file, std::ios::in | std::ios::binary)) {
     if (!fb.open(file, std::ios::in | std::ios::binary)) {
-        throw DeadlyImportError("Failed to open file " + file + ".");
+        throw DeadlyImportError("Failed to open file ", file, ".");
     }
     }
 
 
     std::istream fileStream(&fb);
     std::istream fileStream(&fb);
@@ -122,7 +122,7 @@ void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene,
     fileStream.seekg(0, fileStream.beg);
     fileStream.seekg(0, fileStream.beg);
 
 
     if (fileSize < sizeof(pmx::PmxModel)) {
     if (fileSize < sizeof(pmx::PmxModel)) {
-        throw DeadlyImportError(file + " is too small.");
+        throw DeadlyImportError(file, " is too small.");
     }
     }
 
 
     pmx::PmxModel model;
     pmx::PmxModel model;

+ 2 - 2
code/AssetLib/MMD/MMDPmxParser.cpp

@@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "MMDPmxParser.h"
 #include "MMDPmxParser.h"
 #include <assimp/StringUtils.h>
 #include <assimp/StringUtils.h>
 #ifdef ASSIMP_USE_HUNTER
 #ifdef ASSIMP_USE_HUNTER
-#  include <utf8/utf8.h>
+#  include <utf8.h>
 #else
 #else
 #  include "../contrib/utf8cpp/source/utf8.h"
 #  include "../contrib/utf8cpp/source/utf8.h"
 #endif
 #endif
@@ -524,7 +524,7 @@ namespace pmx
 		if (version != 2.0f && version != 2.1f)
 		if (version != 2.0f && version != 2.1f)
 		{
 		{
 			std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl;
 			std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl;
-            throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but " + to_string(version));
+            throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but ", to_string(version));
     }
     }
 		this->setting.Read(stream);
 		this->setting.Read(stream);
 
 

+ 1 - 1
code/AssetLib/MS3D/MS3DLoader.cpp

@@ -229,7 +229,7 @@ void MS3DImporter::InternReadFile( const std::string& pFile,
     stream.CopyAndAdvance(head,10);
     stream.CopyAndAdvance(head,10);
     stream >> version;
     stream >> version;
     if (strncmp(head,"MS3D000000",10)) {
     if (strncmp(head,"MS3D000000",10)) {
-        throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: "+pFile);
+        throw DeadlyImportError("Not a MS3D file, magic string MS3D000000 not found: ", pFile);
     }
     }
 
 
     if (version != 4) {
     if (version != 4) {

+ 7 - 7
code/AssetLib/NFF/NFFLoader.cpp

@@ -96,7 +96,7 @@ const aiImporterDesc *NFFImporter::GetInfo() const {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 #define AI_NFF_PARSE_FLOAT(f) \
 #define AI_NFF_PARSE_FLOAT(f) \
     SkipSpaces(&sz);          \
     SkipSpaces(&sz);          \
-    if (!::IsLineEnd(*sz)) sz = fast_atoreal_move<float>(sz, (float &)f);
+    if (!::IsLineEnd(*sz)) sz = fast_atoreal_move<ai_real>(sz, (ai_real &)f);
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 #define AI_NFF_PARSE_TRIPLE(v) \
 #define AI_NFF_PARSE_TRIPLE(v) \
@@ -214,7 +214,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
     if (!file.get())
     if (!file.get())
-        throw DeadlyImportError("Failed to open NFF file " + pFile + ".");
+        throw DeadlyImportError("Failed to open NFF file ", pFile, ".");
 
 
     // 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 NFFImporter::InternReadFile(const std::string &pFile,
 
 
     // camera parameters
     // camera parameters
     aiVector3D camPos, camUp(0.f, 1.f, 0.f), camLookAt(0.f, 0.f, 1.f);
     aiVector3D camPos, camUp(0.f, 1.f, 0.f), camLookAt(0.f, 0.f, 1.f);
-    float angle = 45.f;
+    ai_real angle = 45.f;
     aiVector2D resolution;
     aiVector2D resolution;
 
 
     bool hasCam = false;
     bool hasCam = false;
@@ -262,7 +262,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
 
 
     // check whether this is the NFF2 file format
     // check whether this is the NFF2 file format
     if (TokenMatch(buffer, "nff", 3)) {
     if (TokenMatch(buffer, "nff", 3)) {
-        const float qnan = get_qnan();
+        const ai_real qnan = get_qnan();
         const aiColor4D cQNAN = aiColor4D(qnan, 0.f, 0.f, 1.f);
         const aiColor4D cQNAN = aiColor4D(qnan, 0.f, 0.f, 1.f);
         const aiVector3D vQNAN = aiVector3D(qnan, 0.f, 0.f);
         const aiVector3D vQNAN = aiVector3D(qnan, 0.f, 0.f);
 
 
@@ -706,7 +706,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
             }
             }
             // 'f' - shading information block
             // 'f' - shading information block
             else if (TokenMatch(sz, "f", 1)) {
             else if (TokenMatch(sz, "f", 1)) {
-                float d;
+                ai_real d;
 
 
                 // read the RGB colors
                 // read the RGB colors
                 AI_NFF_PARSE_TRIPLE(s.color);
                 AI_NFF_PARSE_TRIPLE(s.color);
@@ -856,7 +856,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
 
 
                 // read the two center points and the respective radii
                 // read the two center points and the respective radii
                 aiVector3D center1, center2;
                 aiVector3D center1, center2;
-                float radius1 = 0.f, radius2 = 0.f;
+                ai_real radius1 = 0.f, radius2 = 0.f;
                 AI_NFF_PARSE_TRIPLE(center1);
                 AI_NFF_PARSE_TRIPLE(center1);
                 AI_NFF_PARSE_FLOAT(radius1);
                 AI_NFF_PARSE_FLOAT(radius1);
 
 
@@ -874,7 +874,7 @@ void NFFImporter::InternReadFile(const std::string &pFile,
                 curMesh.dir = center2 - center1;
                 curMesh.dir = center2 - center1;
                 curMesh.center = center1 + curMesh.dir / (ai_real)2.0;
                 curMesh.center = center1 + curMesh.dir / (ai_real)2.0;
 
 
-                float f;
+                ai_real f;
                 if ((f = curMesh.dir.Length()) < 10e-3f) {
                 if ((f = curMesh.dir.Length()) < 10e-3f) {
                     ASSIMP_LOG_ERROR("NFF: Cone height is close to zero");
                     ASSIMP_LOG_ERROR("NFF: Cone height is close to zero");
                     continue;
                     continue;

+ 3 - 3
code/AssetLib/NFF/NFFLoader.h

@@ -113,14 +113,14 @@ private:
         {}
         {}
 
 
         aiColor3D color,diffuse,specular,ambient,emissive;
         aiColor3D color,diffuse,specular,ambient,emissive;
-        float refracti;
+        ai_real refracti;
 
 
         std::string texFile;
         std::string texFile;
 
 
         // For NFF2
         // For NFF2
         bool twoSided;
         bool twoSided;
         bool shaded;
         bool shaded;
-        float opacity, shininess;
+        ai_real opacity, shininess;
 
 
         std::string name;
         std::string name;
 
 
@@ -155,7 +155,7 @@ private:
         {}
         {}
 
 
         aiVector3D position;
         aiVector3D position;
-        float intensity;
+        ai_real intensity;
         aiColor3D color;
         aiColor3D color;
     };
     };
 
 

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor