Forráskód Böngészése

replace NULL and avoid ai_assert with more than 2 tests.

Kim Kulling 5 éve
szülő
commit
6205af4efb
100 módosított fájl, 10456 hozzáadás és 5691 törlés
  1. 1 0
      .github/FUNDING.yml
  2. 38 0
      .github/ISSUE_TEMPLATE/bug_report.md
  3. 20 0
      .github/ISSUE_TEMPLATE/feature_request.md
  4. 46 33
      .github/workflows/ccpp.yml
  5. 56 0
      .github/workflows/sanitizer.yml
  6. 6 0
      .gitignore
  7. 24 27
      CMakeLists.txt
  8. 50 50
      INSTALL
  9. 23 0
      Readme.md
  10. 8 5
      assimpTargets-debug.cmake.in
  11. 9 3
      assimpTargets-release.cmake.in
  12. 0 978
      code/AMF/AMFImporter_Postprocess.cpp
  13. 249 308
      code/AssetLib/3DS/3DSConverter.cpp
  14. 108 123
      code/AssetLib/3DS/3DSExporter.cpp
  15. 0 0
      code/AssetLib/3DS/3DSExporter.h
  16. 49 24
      code/AssetLib/3DS/3DSHelper.h
  17. 247 310
      code/AssetLib/3DS/3DSLoader.cpp
  18. 1 5
      code/AssetLib/3DS/3DSLoader.h
  19. 0 0
      code/AssetLib/3MF/3MFXmlTags.h
  20. 124 122
      code/AssetLib/3MF/D3MFExporter.cpp
  21. 0 0
      code/AssetLib/3MF/D3MFExporter.h
  22. 138 140
      code/AssetLib/3MF/D3MFImporter.cpp
  23. 0 0
      code/AssetLib/3MF/D3MFImporter.h
  24. 53 56
      code/AssetLib/3MF/D3MFOpcPackage.cpp
  25. 0 0
      code/AssetLib/3MF/D3MFOpcPackage.h
  26. 40 40
      code/AssetLib/AC/ACLoader.cpp
  27. 33 62
      code/AssetLib/AC/ACLoader.h
  28. 674 0
      code/AssetLib/AMF/AMFImporter.cpp
  29. 0 0
      code/AssetLib/AMF/AMFImporter.hpp
  30. 1 1
      code/AssetLib/AMF/AMFImporter_Geometry.cpp
  31. 1 1
      code/AssetLib/AMF/AMFImporter_Macro.hpp
  32. 1 1
      code/AssetLib/AMF/AMFImporter_Material.cpp
  33. 1 1
      code/AssetLib/AMF/AMFImporter_Node.hpp
  34. 872 0
      code/AssetLib/AMF/AMFImporter_Postprocess.cpp
  35. 271 285
      code/AssetLib/ASE/ASELoader.cpp
  36. 0 0
      code/AssetLib/ASE/ASELoader.h
  37. 242 371
      code/AssetLib/ASE/ASEParser.cpp
  38. 95 123
      code/AssetLib/ASE/ASEParser.h
  39. 0 1
      code/AssetLib/Assbin/AssbinExporter.cpp
  40. 0 0
      code/AssetLib/Assbin/AssbinExporter.h
  41. 32 33
      code/AssetLib/Assbin/AssbinFileWriter.cpp
  42. 6 7
      code/AssetLib/Assbin/AssbinFileWriter.h
  43. 26 26
      code/AssetLib/Assbin/AssbinLoader.cpp
  44. 0 0
      code/AssetLib/Assbin/AssbinLoader.h
  45. 4 0
      code/AssetLib/Assjson/cencode.c
  46. 0 0
      code/AssetLib/Assjson/cencode.h
  47. 83 94
      code/AssetLib/Assjson/json_exporter.cpp
  48. 0 0
      code/AssetLib/Assjson/mesh_splitter.cpp
  49. 0 0
      code/AssetLib/Assjson/mesh_splitter.h
  50. 1 1
      code/AssetLib/Assxml/AssxmlExporter.cpp
  51. 0 0
      code/AssetLib/Assxml/AssxmlExporter.h
  52. 659 0
      code/AssetLib/Assxml/AssxmlFileWriter.cpp
  53. 0 0
      code/AssetLib/Assxml/AssxmlFileWriter.h
  54. 744 0
      code/AssetLib/B3D/B3DImporter.cpp
  55. 0 0
      code/AssetLib/B3D/B3DImporter.h
  56. 201 245
      code/AssetLib/BVH/BVHLoader.cpp
  57. 22 29
      code/AssetLib/BVH/BVHLoader.h
  58. 62 84
      code/AssetLib/Blender/BlenderBMesh.cpp
  59. 0 0
      code/AssetLib/Blender/BlenderBMesh.h
  60. 181 0
      code/AssetLib/Blender/BlenderCustomData.cpp
  61. 0 0
      code/AssetLib/Blender/BlenderCustomData.h
  62. 75 90
      code/AssetLib/Blender/BlenderDNA.cpp
  63. 165 208
      code/AssetLib/Blender/BlenderDNA.h
  64. 4 3
      code/AssetLib/Blender/BlenderDNA.inl
  65. 0 0
      code/AssetLib/Blender/BlenderIntermediate.h
  66. 240 281
      code/AssetLib/Blender/BlenderLoader.cpp
  67. 0 0
      code/AssetLib/Blender/BlenderLoader.h
  68. 15 15
      code/AssetLib/Blender/BlenderModifier.cpp
  69. 0 0
      code/AssetLib/Blender/BlenderModifier.h
  70. 838 0
      code/AssetLib/Blender/BlenderScene.cpp
  71. 252 277
      code/AssetLib/Blender/BlenderScene.h
  72. 0 0
      code/AssetLib/Blender/BlenderSceneGen.h
  73. 0 0
      code/AssetLib/Blender/BlenderTessellator.cpp
  74. 0 0
      code/AssetLib/Blender/BlenderTessellator.h
  75. 0 0
      code/AssetLib/C4D/C4DImporter.cpp
  76. 0 0
      code/AssetLib/C4D/C4DImporter.h
  77. 250 287
      code/AssetLib/COB/COBLoader.cpp
  78. 0 0
      code/AssetLib/COB/COBLoader.h
  79. 0 0
      code/AssetLib/COB/COBScene.h
  80. 1 1
      code/AssetLib/CSM/CSMLoader.cpp
  81. 0 0
      code/AssetLib/CSM/CSMLoader.h
  82. 1748 0
      code/AssetLib/Collada/ColladaExporter.cpp
  83. 257 0
      code/AssetLib/Collada/ColladaExporter.h
  84. 8 15
      code/AssetLib/Collada/ColladaHelper.cpp
  85. 185 224
      code/AssetLib/Collada/ColladaHelper.h
  86. 234 253
      code/AssetLib/Collada/ColladaLoader.cpp
  87. 0 0
      code/AssetLib/Collada/ColladaLoader.h
  88. 179 330
      code/AssetLib/Collada/ColladaParser.cpp
  89. 392 0
      code/AssetLib/Collada/ColladaParser.h
  90. 1 1
      code/AssetLib/DXF/DXFHelper.h
  91. 5 5
      code/AssetLib/DXF/DXFLoader.cpp
  92. 0 0
      code/AssetLib/DXF/DXFLoader.h
  93. 77 92
      code/AssetLib/FBX/FBXAnimation.cpp
  94. 4 1
      code/AssetLib/FBX/FBXBinaryTokenizer.cpp
  95. 0 0
      code/AssetLib/FBX/FBXCommon.h
  96. 0 0
      code/AssetLib/FBX/FBXCompileConfig.h
  97. 14 14
      code/AssetLib/FBX/FBXConverter.cpp
  98. 3 3
      code/AssetLib/FBX/FBXConverter.h
  99. 0 0
      code/AssetLib/FBX/FBXDeformer.cpp
  100. 7 2
      code/AssetLib/FBX/FBXDocument.cpp

+ 1 - 0
.github/FUNDING.yml

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

+ 38 - 0
.github/ISSUE_TEMPLATE/bug_report.md

@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.

+ 20 - 0
.github/ISSUE_TEMPLATE/feature_request.md

@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.

+ 46 - 33
.github/workflows/ccpp.yml

@@ -7,40 +7,53 @@ on:
     branches: [ master ]
 
 jobs:
-  linux:
-    runs-on: ubuntu-latest
-    
+  job:
+    name: ${{ matrix.os }}-${{ matrix.cxx }}-build-and-test
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        name: [ubuntu-gcc, macos-clang, windows-msvc, ubuntu-clang]
+        # For Windows msvc, for Linux and macOS let's use the clang compiler, use gcc for Linux.
+        include:
+          - name: windows-msvc
+            os: windows-latest
+            cxx: cl.exe
+            cc: cl.exe
+          - name: ubuntu-clang
+            os: ubuntu-latest
+            cxx: clang++
+            cc: clang
+          - name: macos-clang
+            os: macos-latest
+            cxx: clang++
+            cc: clang
+          - name: ubuntu-gcc
+            os: ubuntu-latest
+            cxx: g++
+            cc: gcc
+
     steps:
-    - uses: actions/checkout@v1
-    - name: configure
-      run: cmake CMakeLists.txt
-    - name: build
-      run: cmake --build .
-    - name: test
-      run: cd bin && ./unit
-  
-  mac:
-    runs-on: macos-latest
+    - uses: actions/checkout@v2
     
-    steps:
-    - uses: actions/checkout@v1
-    - name: configure
-      run: cmake CMakeLists.txt
-    - name: build
-      run: cmake --build .
-    - name: test
-      run: cd bin && ./unit
-
-  windows:
-    runs-on: windows-latest
+    - uses: lukka/get-cmake@latest
     
-    steps:
-    - uses: actions/checkout@v1
-    - name: configure
-      run: cmake CMakeLists.txt
-    - name: build
-      run: cmake --build . --config Release
+    - uses: ilammy/msvc-dev-cmd@v1
+    
+    - uses: lukka/set-shell-env@v1
+      with:
+        CXX: ${{ matrix.cxx }}
+        CC: ${{ matrix.cc }}
+    
+    - name: configure and build
+      uses: lukka/run-cmake@v2
+      with:
+        cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
+        cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
+        cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Release'
+        buildWithCMakeArgs: '-- -v'
+        buildDirectory: '${{ github.workspace }}/build/'
+        
     - name: test
-      run: | 
-        cd bin\Release
-        .\unit
+      run: cd build/bin && ./unit
+      shell: bash

+ 56 - 0
.github/workflows/sanitizer.yml

@@ -0,0 +1,56 @@
+name: C/C++ Sanitizer
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  job1:
+    name: adress-sanitizer
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+    - uses: lukka/get-cmake@latest    
+    - uses: lukka/set-shell-env@v1
+      with:
+        CXX: clang++
+        CC: clang
+    
+    - name: configure and build
+      uses: lukka/run-cmake@v2
+      with:
+        cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
+        cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
+        cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_ASAN=ON'
+        buildWithCMakeArgs: '-- -v'
+        buildDirectory: '${{ github.workspace }}/build/'
+    
+    - name: test
+      run: cd build/bin && ./unit
+      shell: bash
+
+  job2:
+    name: undefined-behavior-sanitizer
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+    - uses: lukka/get-cmake@latest    
+    - uses: lukka/set-shell-env@v1
+      with:
+        CXX: clang++
+        CC: clang
+    
+    - name: configure and build
+      uses: lukka/run-cmake@v2
+      with:
+        cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
+        cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
+        cmakeAppendedArgs: '-GNinja -DCMAKE_BUILD_TYPE=Debug -DASSIMP_UBSAN=ON'
+        buildWithCMakeArgs: '-- -v'
+        buildDirectory: '${{ github.workspace }}/build/'
+    
+    - name: test
+      run: cd build/bin && ./unit
+      shell: bash

+ 6 - 0
.gitignore

@@ -79,6 +79,12 @@ test/gtest/src/gtest-stamp/Debug/
 tools/assimp_view/assimp_viewer.vcxproj.user
 *.pyc
 
+### Rust ###
+# Generated by Cargo; will have compiled files and executables
+port/assimp_rs/target/
+# Backup files generated by rustfmt
+port/assimp_rs/**/*.rs.bk
+
 # Unix editor backups
 *~
 test/gtest/src/gtest-stamp/gtest-gitinfo.txt

+ 24 - 27
CMakeLists.txt

@@ -108,10 +108,6 @@ OPTION ( ASSIMP_ERROR_MAX
   "Enable all warnings."
   OFF
 )
-OPTION ( ASSIMP_WERROR
-  "Treat warnings as errors."
-  OFF
-)
 OPTION ( ASSIMP_ASAN
   "Enable AddressSanitizer."
   OFF
@@ -138,6 +134,12 @@ OPTION ( ASSIMP_IGNORE_GIT_HASH
    OFF
 )
 
+IF ( WIN32 )
+    OPTION ( ASSIMP_BUILD_ASSIMP_VIEW 
+      "If the Assimp view tool is built. (requires DirectX)" 
+      OFF )
+ENDIF()
+
 IF (IOS AND NOT ASSIMP_HUNTER_ENABLED)
   IF (NOT CMAKE_BUILD_TYPE)
     SET(CMAKE_BUILD_TYPE "Release")
@@ -238,14 +240,19 @@ SET(LIBASSIMP-DEV_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_M
 SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-dev)
 SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
 
-# Grouped compiler settings
+IF( UNIX )
+  # Use GNUInstallDirs for Unix predefined directories
+  INCLUDE(GNUInstallDirs)
+ENDIF()
+
+# Grouped compiler settings ########################################
 IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
   IF(NOT ASSIMP_HUNTER_ENABLED)
-    SET(CMAKE_CXX_FLAGS "-fPIC -std=c++0x ${CMAKE_CXX_FLAGS}")
-    SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
+    SET(CMAKE_CXX_STANDARD 11)
+    SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
   ENDIF()
   # hide all not-exported symbols
-  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
+  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++)
 ELSEIF(MSVC)
@@ -258,10 +265,10 @@ ELSEIF(MSVC)
   SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
 ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
   IF(NOT ASSIMP_HUNTER_ENABLED)
-    SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
-    SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
+    SET(CMAKE_CXX_STANDARD 11)
+    SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
   ENDIF()
-  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
+  SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" )
   SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
 ELSEIF( CMAKE_COMPILER_IS_MINGW )
   IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
@@ -306,16 +313,6 @@ IF (ASSIMP_ERROR_MAX)
   ENDIF()
 ENDIF()
 
-IF (ASSIMP_WERROR)
-  MESSAGE(STATUS "Treating warnings as errors")
-  IF (MSVC)
-    ADD_COMPILE_OPTIONS(/WX)
-  ELSE()
-    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
-    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
-  ENDIF()
-ENDIF()
-
 IF (ASSIMP_ASAN)
   MESSAGE(STATUS "AddressSanitizer enabled")
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
@@ -521,19 +518,19 @@ ENDIF()
 SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING
   "describe the current architecture."
 )
-IF    ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
-ELSE  ()
+IF( ASSIMP_BUILD_ARCHITECTURE STREQUAL "")
+ELSE()
   ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' )
-ENDIF ()
+ENDIF()
 
 # ${CMAKE_GENERATOR}
 SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING
   "describe the current compiler."
 )
-IF    ( ASSIMP_BUILD_COMPILER STREQUAL "")
-ELSE  ()
+IF( ASSIMP_BUILD_COMPILER STREQUAL "")
+ELSE()
   ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' )
-ENDIF ()
+ENDIF()
 
 MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER )
 

+ 50 - 50
INSTALL

@@ -1,50 +1,50 @@
-	
-========================================================================
-Open Asset Import Library (assimp) INSTALL 
-========================================================================
-
-------------------------------
-Getting the documentation
-------------------------------
-
-A regularly-updated copy is available at 
-http://assimp.sourceforge.net/lib_html/index.html
-
-A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm.
-To build the doxygen documentation on your own, follow these steps:
-
-a) download & install latest doxygen 
-b) make sure doxygen is in the executable search path
-c) navigate to ./doc
-d) and run 'doxygen'
-
-Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice.
-Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop'
-and configure the path to it in the DOXYFILE first. 
-
-------------------------------
-Building Assimp 
-------------------------------
-
-More detailed build instructions can be found in the documentation,
-this section is just for the inpatient among you.
-
-CMake is the preferred build system for Assimp. The minimum required version 
-is 2.6. If you don't have it yet, downloads for CMake can be found on
-http://www.cmake.org/. 
-
-For Unix:
-
-1. mkdir build && cd build
-2. cmake .. -G 'Unix Makefiles'
-3. make -j4
-
-For Windows:
-1. Open a command prompt
-2. mkdir build
-3. cd build
-4. cmake ..
-5. cmake --build .
-
-For iOS:
-Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS
+	
+========================================================================
+Open Asset Import Library (assimp) INSTALL 
+========================================================================
+
+------------------------------
+Getting the documentation
+------------------------------
+
+A regularly-updated copy is available at 
+http://assimp.sourceforge.net/lib_html/index.html
+
+A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm.
+To build the doxygen documentation on your own, follow these steps:
+
+a) download & install latest doxygen 
+b) make sure doxygen is in the executable search path
+c) navigate to ./doc
+d) and run 'doxygen'
+
+Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice.
+Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop'
+and configure the path to it in the DOXYFILE first. 
+
+------------------------------
+Building Assimp 
+------------------------------
+
+More detailed build instructions can be found in the documentation,
+this section is just for the inpatient among you.
+
+CMake is the preferred build system for Assimp. The minimum required version 
+is 2.6. If you don't have it yet, downloads for CMake can be found on
+http://www.cmake.org/. 
+
+For Unix:
+
+1. mkdir build && cd build
+2. cmake .. -G 'Unix Makefiles'
+3. make -j4
+
+For Windows:
+1. Open a command prompt
+2. mkdir build
+3. cd build
+4. cmake ..
+5. cmake --build .
+
+For iOS:
+Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS

+ 23 - 0
Readme.md

@@ -2,6 +2,7 @@ Open Asset Import Library (assimp)
 ==================================
 A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
 ### Current project status ###
+[![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)
 [![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)
@@ -179,6 +180,28 @@ And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/a
 Contributions to assimp are highly appreciated. The easiest way to get involved is to submit
 a pull request with your changes against the main repository's `master` branch.
 
+## Contributors
+
+### Code Contributors
+
+This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
+
+<a href="https://github.com/assimp/assimp/graphs/contributors"><img src="https://opencollective.com/assimp/contributors.svg?width=890&button=false" /></a>
+
+### Financial Contributors
+
+Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/assimp/contribute)]
+
+#### Individuals
+
+<a href="https://opencollective.com/assimp"><img src="https://opencollective.com/assimp/individuals.svg?width=890"></a>
+
+#### Organizations
+
+Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/assimp/contribute)]
+
+<a href="https://opencollective.com/assimp/organization/0/website"><img src="https://opencollective.com/assimp/organization/0/avatar.svg"></a>
+
 ### License ###
 Our license is based on the modified, __3-clause BSD__-License.
 

+ 8 - 5
assimpTargets-debug.cmake.in

@@ -7,6 +7,8 @@ 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}")
@@ -35,8 +37,6 @@ if(MSVC)
   endif()
   set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
 
-  file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX)
-
   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@")
@@ -73,6 +73,9 @@ else()
     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}"
@@ -81,6 +84,9 @@ else()
     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}"
     )
@@ -89,9 +95,6 @@ else()
   endif()
 endif()
 
-
-
-
 # Commands beyond this point should not need to know the version.
 set(CMAKE_IMPORT_FILE_VERSION)
 

+ 9 - 3
assimpTargets-release.cmake.in

@@ -7,6 +7,8 @@ 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}")
@@ -34,8 +36,6 @@ if(MSVC)
     endif()
   endif()
   set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
-  	
-  file(TO_NATIVE_PATH "${_IMPORT_PREFIX}" _IMPORT_PREFIX)
 
   if(ASSIMP_BUILD_SHARED_LIBS)
     set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
@@ -56,7 +56,7 @@ if(MSVC)
     # 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 "${_IMPORT_PREFIX}/lib/${staticLibraryName}"
+      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}")
@@ -73,6 +73,9 @@ else()
     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}"
@@ -81,6 +84,9 @@ else()
     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}"
     )

+ 0 - 978
code/AMF/AMFImporter_Postprocess.cpp

@@ -1,978 +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_Postprocess.cpp
-/// \brief Convert built scenegraph and objects to Assimp scenegraph.
-/// \date 2016
-/// \author [email protected]
-
-#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
-
-#include "AMFImporter.hpp"
-
-// Header files, Assimp.
-#include <assimp/SceneCombiner.h>
-#include <assimp/StandardShapes.h>
-#include <assimp/StringUtils.h>
-
-// Header files, stdlib.
-#include <iterator>
-
-namespace Assimp
-{
-
-aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*pY*/, const float /*pZ*/) const
-{
-    aiColor4D tcol;
-
-	// Check if stored data are supported.
-	if(!Composition.empty())
-	{
-		throw DeadlyImportError("IME. GetColor for composition");
-	}
-	else if(Color->Composed)
-	{
-		throw DeadlyImportError("IME. GetColor, composed color");
-	}
-	else
-	{
-		tcol = Color->Color;
-	}
-
-	// Check if default color must be used
-	if((tcol.r == 0) && (tcol.g == 0) && (tcol.b == 0) && (tcol.a == 0))
-	{
-		tcol.r = 0.5f;
-		tcol.g = 0.5f;
-		tcol.b = 0.5f;
-		tcol.a = 1;
-	}
-
-	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;
-    size_t col_idx;
-
-	// 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;
-	}
-
-	// If "vertices" not found then no work for us.
-	if(vn == nullptr) return;
-
-	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.
-	col_idx = 0;
-	// Inside vertices collect all data and place to arrays
-	for(CAMFImporter_NodeElement* vn_child: vn->Child)
-	{
-		// vertices, colors
-		if(vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex)
-		{
-			// by default clear color for current vertex
-			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);
-
-					continue;
-				}
-
-				if(vtx->Type == CAMFImporter_NodeElement::ENET_Color)
-				{
-					pVertexColorArray[col_idx] = (CAMFImporter_NodeElement_Color*)vtx;
-
-					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)
-}
-
-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())
-		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;
-	for(const SPP_Texture& tex_convd: mTexture_Converted)
-	{
-        if ( tex_convd.ID == TextureConverted_ID ) {
-            return TextureConverted_Index;
-        } else {
-            ++TextureConverted_Index;
-        }
-	}
-
-	//
-	// Converted texture not found, create it.
-	//
-	CAMFImporter_NodeElement_Texture* src_texture[4]{nullptr};
-	std::vector<CAMFImporter_NodeElement_Texture*> src_texture_4check;
-	SPP_Texture converted_texture;
-
-	{// find all specified source textures
-		CAMFImporter_NodeElement* t_tex;
-
-		// R
-		if(!pID_R.empty())
-		{
-			if(!Find_NodeElement(pID_R, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
-
-			src_texture[0] = (CAMFImporter_NodeElement_Texture*)t_tex;
-			src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
-		}
-		else
-		{
-			src_texture[0] = nullptr;
-		}
-
-		// G
-		if(!pID_G.empty())
-		{
-			if(!Find_NodeElement(pID_G, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
-
-			src_texture[1] = (CAMFImporter_NodeElement_Texture*)t_tex;
-			src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
-		}
-		else
-		{
-			src_texture[1] = nullptr;
-		}
-
-		// B
-		if(!pID_B.empty())
-		{
-			if(!Find_NodeElement(pID_B, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
-
-			src_texture[2] = (CAMFImporter_NodeElement_Texture*)t_tex;
-			src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
-		}
-		else
-		{
-			src_texture[2] = nullptr;
-		}
-
-		// A
-		if(!pID_A.empty())
-		{
-			if(!Find_NodeElement(pID_A, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
-
-			src_texture[3] = (CAMFImporter_NodeElement_Texture*)t_tex;
-			src_texture_4check.push_back((CAMFImporter_NodeElement_Texture*)t_tex);
-		}
-		else
-		{
-			src_texture[3] = nullptr;
-		}
-	}// END: find all specified source textures
-
-	// check that all textures has same size
-	if(src_texture_4check.size() > 1)
-	{
-		for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++)
-		{
-			if((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) ||
-				(src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth))
-			{
-				throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size.");
-			}
-		}
-	}// if(src_texture_4check.size() > 1)
-
-	// set texture attributes
-	converted_texture.Width = src_texture_4check[0]->Width;
-	converted_texture.Height = src_texture_4check[0]->Height;
-	converted_texture.Depth = src_texture_4check[0]->Depth;
-	// if one of source texture is tiled then converted texture is tiled too.
-	converted_texture.Tiled = false;
-	for(uint8_t i = 0; i < src_texture_4check.size(); i++) converted_texture.Tiled |= src_texture_4check[i]->Tiled;
-
-	// Create format hint.
-	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';
-
-	//
-	// Сopy data of textures.
-	//
-	size_t tex_size = 0;
-	size_t step = 0;
-	size_t off_g = 0;
-	size_t off_b = 0;
-
-	// Calculate size of the target array and rule how data will be copied.
-    if(!pID_R.empty() && nullptr != src_texture[ 0 ] ) {
-        tex_size += src_texture[0]->Data.size(); step++, off_g++, off_b++;
-    }
-    if(!pID_G.empty() && nullptr != src_texture[ 1 ] ) {
-        tex_size += src_texture[1]->Data.size(); step++, off_b++;
-    }
-    if(!pID_B.empty() && nullptr != src_texture[ 2 ] ) {
-        tex_size += src_texture[2]->Data.size(); step++;
-    }
-    if(!pID_A.empty() && nullptr != src_texture[ 3 ] ) {
-        tex_size += src_texture[3]->Data.size(); step++;
-    }
-
-    // Create target array.
-	converted_texture.Data = new uint8_t[tex_size];
-	// And copy data
-	auto CopyTextureData = [&](const std::string& pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
-	{
-		if(!pID.empty())
-		{
-			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];
-				ai_assert(tex);
-				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
-
-	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);
-
-	// Store new converted texture ID
-	converted_texture.ID = TextureConverted_ID;
-	// Store new converted texture
-	mTexture_Converted.push_back(converted_texture);
-
-	return TextureConverted_Index;
-}
-
-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
-    {
-	    if((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true;
-	    if(pTexMap1 == nullptr) return false;
-	    if(pTexMap2 == nullptr) return false;
-
-	    if(pTexMap1->TextureID_R != pTexMap2->TextureID_R) return false;
-	    if(pTexMap1->TextureID_G != pTexMap2->TextureID_G) return false;
-	    if(pTexMap1->TextureID_B != pTexMap2->TextureID_B) return false;
-	    if(pTexMap1->TextureID_A != pTexMap2->TextureID_A) return false;
-
-	    return true;
-    };
-
-	pOutputList_Separated.clear();
-	if(pInputList.empty()) return;
-
-	do
-	{
-		SComplexFace face_start = pInputList.front();
-		std::list<SComplexFace> face_list_cur;
-
-		for(std::list<SComplexFace>::iterator it = pInputList.begin(), it_end = pInputList.end(); it != it_end;)
-		{
-			if(texmap_is_equal(face_start.TexMap, it->TexMap))
-			{
-				auto it_old = it;
-
-				++it;
-				face_list_cur.push_back(*it_old);
-				pInputList.erase(it_old);
-			}
-			else
-			{
-				++it;
-			}
-		}
-
-		if(!face_list_cur.empty()) pOutputList_Separated.push_back(face_list_cur);
-
-	} 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.");
-
-		// 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())
-}
-
-void AMFImporter::Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list<aiMesh*>& pMeshList, aiNode** pSceneNode)
-{
-CAMFImporter_NodeElement_Color* object_color = nullptr;
-
-	// create new aiNode and set name as <object> has.
-	*pSceneNode = new aiNode;
-	(*pSceneNode)->mName = pNodeElement.ID;
-	// read mesh and color
-	for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
-	{
-		std::vector<aiVector3D> vertex_arr;
-		std::vector<CAMFImporter_NodeElement_Color*> color_arr;
-
-		// color for object
-		if(ne_child->Type == CAMFImporter_NodeElement::ENET_Color) object_color = (CAMFImporter_NodeElement_Color*)ne_child;
-
-		if(ne_child->Type == CAMFImporter_NodeElement::ENET_Mesh)
-		{
-			// Create arrays from children of mesh: vertices.
-			PostprocessHelper_CreateMeshDataArray(*((CAMFImporter_NodeElement_Mesh*)ne_child), vertex_arr, color_arr);
-			// 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);
-		}
-	}// 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)
-{
-std::list<unsigned int> mesh_idx;
-
-	// all data stored in "volume", search for it.
-	for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
-	{
-		const CAMFImporter_NodeElement_Color* ne_volume_color = nullptr;
-		const SPP_Material* cur_mat = nullptr;
-
-		if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume)
-		{
-			/******************* Get faces *******************/
-			const CAMFImporter_NodeElement_Volume* ne_volume = reinterpret_cast<const CAMFImporter_NodeElement_Volume*>(ne_child);
-
-			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.
-
-			// check if volume use material
-			if(!ne_volume->MaterialID.empty())
-			{
-				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
-			for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child)
-			{
-				// 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
-				{
-					const CAMFImporter_NodeElement_Triangle& tri_al = *reinterpret_cast<const CAMFImporter_NodeElement_Triangle*>(ne_volume_child);
-
-					SComplexFace complex_face;
-
-					// initialize pointers
-					complex_face.Color = nullptr;
-					complex_face.TexMap = nullptr;
-					// get data from triangle children: color, texture coordinates.
-					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);
-						}
-					}// if(tri_al.Child.size())
-
-					// create new face and store it.
-					complex_face.Face.mNumIndices = 3;
-					complex_face.Face.mIndices = new unsigned int[3];
-					complex_face.Face.mIndices[0] = static_cast<unsigned int>(tri_al.V[0]);
-					complex_face.Face.mIndices[1] = static_cast<unsigned int>(tri_al.V[1]);
-					complex_face.Face.mIndices[2] = static_cast<unsigned int>(tri_al.V[2]);
-					complex_faces_list.push_back(complex_face);
-				}
-			}// for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child)
-
-			/**** Split faces list: one list per mesh ****/
-			PostprocessHelper_SplitFacesByTextureID(complex_faces_list, complex_faces_toplist);
-
-			/***** Create mesh for every faces list ******/
-			for(std::list<SComplexFace>& face_list_cur: complex_faces_toplist)
-			{
-				auto VertexIndex_GetMinimal = [](const std::list<SComplexFace>& pFaceList, const size_t* pBiggerThan) -> size_t
-				{
-					size_t rv=0;
-
-					if(pBiggerThan != nullptr)
-					{
-						bool found = false;
-
-						for(const SComplexFace& face: pFaceList)
-						{
-							for(size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++)
-							{
-								if(face.Face.mIndices[idx_vert] > *pBiggerThan)
-								{
-									rv = face.Face.mIndices[idx_vert];
-									found = true;
-
-									break;
-								}
-							}
-
-							if(found) break;
-						}
-
-						if(!found) return *pBiggerThan;
-					}
-					else
-					{
-						rv = pFaceList.front().Face.mIndices[0];
-					}// if(pBiggerThan != nullptr) else
-
-					for(const SComplexFace& face: pFaceList)
-					{
-						for(size_t vi = 0; vi < face.Face.mNumIndices; vi++)
-						{
-							if(face.Face.mIndices[vi] < rv)
-							{
-								if(pBiggerThan != nullptr)
-								{
-									if(face.Face.mIndices[vi] > *pBiggerThan) rv = face.Face.mIndices[vi];
-								}
-								else
-								{
-									rv = face.Face.mIndices[vi];
-								}
-							}
-						}
-					}// for(const SComplexFace& face: pFaceList)
-
-					return rv;
-				};// auto VertexIndex_GetMinimal = [](const std::list<SComplexFace>& pFaceList, const size_t* pBiggerThan) -> size_t
-
-				auto VertexIndex_Replace = [](std::list<SComplexFace>& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void
-				{
-					for(const SComplexFace& face: pFaceList)
-					{
-						for(size_t vi = 0; vi < face.Face.mNumIndices; vi++)
-						{
-							if(face.Face.mIndices[vi] == pIdx_From) face.Face.mIndices[vi] = static_cast<unsigned int>(pIdx_To);
-						}
-					}
-				};// auto VertexIndex_Replace = [](std::list<SComplexFace>& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void
-
-				auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D
-				{
-					// Color priorities(In descending order):
-					// 1. triangle color;
-					// 2. vertex color;
-					// 3. volume color;
-					// 4. object color;
-					// 5. material;
-					// 6. default - invisible coat.
-					//
-					// Fill vertices colors in color priority list above that's points from 1 to 6.
-					if((pIdx < pVertexColorArray.size()) && (pVertexColorArray[pIdx] != nullptr))// check for vertex color
-					{
-						if(pVertexColorArray[pIdx]->Composed)
-							throw DeadlyImportError("IME: vertex color composed");
-						else
-							return pVertexColorArray[pIdx]->Color;
-					}
-					else if(ne_volume_color != nullptr)// check for volume color
-					{
-						if(ne_volume_color->Composed)
-							throw DeadlyImportError("IME: volume color composed");
-						else
-							return ne_volume_color->Color;
-					}
-					else if(pObjectColor != nullptr)// check for object color
-					{
-						if(pObjectColor->Composed)
-							throw DeadlyImportError("IME: object color composed");
-						else
-							return pObjectColor->Color;
-					}
-					else if(cur_mat != nullptr)// check for material
-					{
-						return cur_mat->GetColor(pVertexCoordinateArray.at(pIdx).x, pVertexCoordinateArray.at(pIdx).y, pVertexCoordinateArray.at(pIdx).z);
-					}
-					else// set default color.
-					{
-						return {0, 0, 0, 0};
-					}// if((vi < pVertexColorArray.size()) && (pVertexColorArray[vi] != nullptr)) else
-
-				};// auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D
-
-				aiMesh* tmesh = new aiMesh;
-
-				tmesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;// Only triangles is supported by AMF.
-				//
-				// set geometry and colors (vertices)
-				//
-				// copy faces/triangles
-				tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size());
-				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
-				// 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.
-				size_t VertexCount_Max = tmesh->mNumFaces * 3;// 3 - triangles.
-				std::vector<aiVector3D> vert_arr, texcoord_arr;
-				std::vector<aiColor4D> col_arr;
-
-				vert_arr.reserve(VertexCount_Max * 2);// "* 2" - see below TODO.
-				col_arr.reserve(VertexCount_Max * 2);
-
-				{// fill arrays
-					size_t vert_idx_from, vert_idx_to;
-
-					// first iteration.
-					vert_idx_to = 0;
-					vert_idx_from = VertexIndex_GetMinimal(face_list_cur, nullptr);
-					vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from));
-					col_arr.push_back(Vertex_CalculateColor(vert_idx_from));
-					if(vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to);
-
-					// rest iterations
-					do
-					{
-						vert_idx_from = VertexIndex_GetMinimal(face_list_cur, &vert_idx_to);
-						if(vert_idx_from == vert_idx_to) break;// all indices are transferred,
-
-						vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from));
-						col_arr.push_back(Vertex_CalculateColor(vert_idx_from));
-						vert_idx_to++;
-						if(vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to);
-
-					} while(true);
-				}// fill arrays. END.
-
-				//
-				// check if triangle colors are used and create additional faces if needed.
-				//
-				for(const SComplexFace& face_cur: face_list_cur)
-				{
-					if(face_cur.Color != nullptr)
-					{
-						aiColor4D face_color;
-						size_t vert_idx_new = vert_arr.size();
-
-						if(face_cur.Color->Composed)
-							throw DeadlyImportError("IME: face color composed");
-						else
-							face_color = face_cur.Color->Color;
-
-						for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++)
-						{
-							vert_arr.push_back(vert_arr.at(face_cur.Face.mIndices[idx_ind]));
-							col_arr.push_back(face_color);
-							face_cur.Face.mIndices[idx_ind] = static_cast<unsigned int>(vert_idx_new++);
-						}
-					}// if(face_cur.Color != nullptr)
-				}// for(const SComplexFace& face_cur: face_list_cur)
-
-				//
-				// if texture is used then copy texture coordinates too.
-				//
-				if(face_list_cur.front().TexMap != nullptr)
-				{
-					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
-					/// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about
-					/// optimisation.
-					bool* idx_vert_used;
-
-					idx_vert_used = new bool[VertexCount_Max * 2];
-					for(size_t i = 0, i_e = VertexCount_Max * 2; i < i_e; i++) idx_vert_used[i] = false;
-
-					// This ID's will be used when set materials ID in scene.
-					tmesh->mMaterialIndex = static_cast<unsigned int>(PostprocessHelper_GetTextureID_Or_Create(face_list_cur.front().TexMap->TextureID_R,
-																						face_list_cur.front().TexMap->TextureID_G,
-																						face_list_cur.front().TexMap->TextureID_B,
-																						face_list_cur.front().TexMap->TextureID_A));
-					texcoord_arr.resize(VertexCount_Max * 2);
-					for(const SComplexFace& face_cur: face_list_cur)
-					{
-						for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++)
-						{
-							const size_t idx_vert = face_cur.Face.mIndices[idx_ind];
-
-							if(!idx_vert_used[idx_vert])
-							{
-								texcoord_arr.at(idx_vert) = face_cur.TexMap->TextureCoordinate[idx_ind];
-								idx_vert_used[idx_vert] = true;
-							}
-							else if(texcoord_arr.at(idx_vert) != face_cur.TexMap->TextureCoordinate[idx_ind])
-							{
-								// in that case one vertex is shared with many texture coordinates. We need to duplicate vertex with another texture
-								// coordinates.
-								vert_arr.push_back(vert_arr.at(idx_vert));
-								col_arr.push_back(col_arr.at(idx_vert));
-								texcoord_arr.at(idx_vert_new) = face_cur.TexMap->TextureCoordinate[idx_ind];
-								face_cur.Face.mIndices[idx_ind] = static_cast<unsigned int>(idx_vert_new++);
-							}
-						}// for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++)
-					}// for(const SComplexFace& face_cur: face_list_cur)
-
-					delete [] idx_vert_used;
-					// shrink array
-					texcoord_arr.resize(idx_vert_new);
-				}// if(face_list_cur.front().TexMap != nullptr)
-
-				//
-				// copy collected data to mesh
-				//
-				tmesh->mNumVertices = static_cast<unsigned int>(vert_arr.size());
-				tmesh->mVertices = new aiVector3D[tmesh->mNumVertices];
-				tmesh->mColors[0] = new aiColor4D[tmesh->mNumVertices];
-
-				memcpy(tmesh->mVertices, vert_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D));
-				memcpy(tmesh->mColors[0], col_arr.data(), tmesh->mNumVertices * sizeof(aiColor4D));
-				if(texcoord_arr.size() > 0)
-				{
-					tmesh->mTextureCoords[0] = new aiVector3D[tmesh->mNumVertices];
-					memcpy(tmesh->mTextureCoords[0], texcoord_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D));
-					tmesh->mNumUVComponents[0] = 2;// U and V stored in "x", "y" of aiVector3D.
-				}
-
-				size_t idx_face = 0;
-				for(const SComplexFace& face_cur: face_list_cur) tmesh->mFaces[idx_face++] = face_cur.Face;
-
-				// store new aiMesh
-				mesh_idx.push_back(static_cast<unsigned int>(pMeshList.size()));
-				pMeshList.push_back(tmesh);
-			}// for(const std::list<SComplexFace>& face_list_cur: complex_faces_toplist)
-		}// if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume)
-	}// for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
-
-	// if meshes was created then assign new indices with current aiNode
-	if(!mesh_idx.empty())
-	{
-		std::list<unsigned int>::const_iterator mit = mesh_idx.begin();
-
-		pSceneNode.mNumMeshes = static_cast<unsigned int>(mesh_idx.size());
-		pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes];
-		for(size_t i = 0; i < pSceneNode.mNumMeshes; i++) pSceneNode.mMeshes[i] = *mit++;
-	}// if(mesh_idx.size() > 0)
-}
-
-void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial)
-{
-SPP_Material new_mat;
-
-	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 CAMFImporter_NodeElement* mat_child; pMaterial.Child)
-
-	// place converted material to special list
-	mMaterial_Converted.push_back(new_mat);
-}
-
-void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list<aiNode*>& pNodeList) const
-{
-aiNode* con_node;
-std::list<aiNode*> ch_node;
-
-	// We will build next hierarchy:
-	// aiNode as parent (<constellation>) for set of nodes as a children
-	//  |- aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
-	//  ...
-	//  \_ aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
-	con_node = new aiNode;
-	con_node->mName = pConstellation.ID;
-	// Walk through children and search for instances of another objects, constellations.
-	for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
-	{
-		aiMatrix4x4 tmat;
-		aiNode* t_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>.");
-
-		// create alias for conveniance
-		CAMFImporter_NodeElement_Instance& als = *((CAMFImporter_NodeElement_Instance*)ne);
-		// find referenced object
-		if(!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID);
-
-		// create node for applying transformation
-		t_node = new aiNode;
-		t_node->mParent = con_node;
-		// apply transformation
-		aiMatrix4x4::Translation(als.Delta, tmat), t_node->mTransformation *= tmat;
-		aiMatrix4x4::RotationX(als.Rotation.x, tmat), t_node->mTransformation *= tmat;
-		aiMatrix4x4::RotationY(als.Rotation.y, tmat), t_node->mTransformation *= tmat;
-		aiMatrix4x4::RotationZ(als.Rotation.z, tmat), t_node->mTransformation *= tmat;
-		// create array for one child node
-		t_node->mNumChildren = 1;
-		t_node->mChildren = new aiNode*[t_node->mNumChildren];
-		SceneCombiner::Copy(&t_node->mChildren[0], found_node);
-		t_node->mChildren[0]->mParent = t_node;
-		ch_node.push_back(t_node);
-	}// for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
-
-	// copy found aiNode's as children
-	if(ch_node.empty()) throw DeadlyImportError("<constellation> must have at least one <instance>.");
-
-	size_t ch_idx = 0;
-
-	con_node->mNumChildren = static_cast<unsigned int>(ch_node.size());
-	con_node->mChildren = new aiNode*[con_node->mNumChildren];
-	for(aiNode* node: ch_node) con_node->mChildren[ch_idx++] = node;
-
-	// and place "root" of <constellation> node to node list
-	pNodeList.push_back(con_node);
-}
-
-void AMFImporter::Postprocess_BuildScene(aiScene* pScene)
-{
-std::list<aiNode*> node_list;
-std::list<aiMesh*> mesh_list;
-std::list<CAMFImporter_NodeElement_Metadata*> meta_list;
-
-	//
-	// Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
-	// For building aiScene we are must to do few steps:
-	// at first creating root node for aiScene.
-	pScene->mRootNode = new aiNode;
-	pScene->mRootNode->mParent = nullptr;
-	pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
-	// search for root(<amf>) element
-	CAMFImporter_NodeElement* root_el = nullptr;
-
-	for(CAMFImporter_NodeElement* ne: mNodeElement_List)
-	{
-		if(ne->Type != CAMFImporter_NodeElement::ENET_Root) continue;
-
-		root_el = ne;
-
-		break;
-	}// for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
-
-	// Check if root element are 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>,
-	// <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
-	// at any moment.
-	//
-	// 1. <material>
-	// 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));
-	}
-
-	// After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
-	//
-	// 3. <object>
-	for(const CAMFImporter_NodeElement* root_child: root_el->Child)
-	{
-		if(root_child->Type == CAMFImporter_NodeElement::ENET_Object)
-		{
-			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>
-			Postprocess_BuildNodeAndObject(*((CAMFImporter_NodeElement_Object*)root_child), mesh_list, &tnode);
-			if(tnode != nullptr) node_list.push_back(tnode);
-
-		}
-	}// for(const CAMFImporter_NodeElement* root_child: root_el->Child)
-
-	// And finally read rest of nodes.
-	//
-	for(const CAMFImporter_NodeElement* root_child: root_el->Child)
-	{
-		// 4. <constellation>
-		if(root_child->Type == CAMFImporter_NodeElement::ENET_Constellation)
-		{
-			// <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);
-		}
-
-		// 5, <metadata>
-		if(root_child->Type == CAMFImporter_NodeElement::ENET_Metadata) meta_list.push_back((CAMFImporter_NodeElement_Metadata*)root_child);
-	}// for(const CAMFImporter_NodeElement* root_child: root_el->Child)
-
-	// at now we can add collected metadata to root node
-	Postprocess_AddMetadata(meta_list, *pScene->mRootNode);
-	//
-	// Check constellation children
-	//
-	// As said in specification:
-	// "When multiple objects and constellations are defined in a single file, only the top level objects and constellations are available for printing."
-	// What that means? For example: if some object is used in constellation then you must show only constellation but not original object.
-	// And at this step we are checking that relations.
-nl_clean_loop:
-
-	if(node_list.size() > 1)
-	{
-		// walk through all nodes
-		for(std::list<aiNode*>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it)
-		{
-			// and try to find them in another top nodes.
-			std::list<aiNode*>::const_iterator next_it = nl_it;
-
-			++next_it;
-			for(; next_it != node_list.end(); ++next_it)
-			{
-				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.
-					node_list.erase(nl_it);
-
-					goto nl_clean_loop;
-				}
-			}// for(; next_it != node_list.end(); next_it++)
-		}// for(std::list<aiNode*>::const_iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++)
-	}
-
-	//
-	// move created objects to aiScene
-	//
-	//
-	// Nodes
-	if(!node_list.empty())
-	{
-		std::list<aiNode*>::const_iterator nl_it = node_list.begin();
-
-		pScene->mRootNode->mNumChildren = static_cast<unsigned int>(node_list.size());
-		pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren];
-		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
-			// mRootNode only as parent.
-			(*nl_it)->mParent = pScene->mRootNode;
-			pScene->mRootNode->mChildren[i] = *nl_it++;
-		}
-	}// if(node_list.size() > 0)
-
-	//
-	// Meshes
-	if(!mesh_list.empty())
-	{
-		std::list<aiMesh*>::const_iterator ml_it = mesh_list.begin();
-
-		pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
-		pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
-		for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *ml_it++;
-	}// if(mesh_list.size() > 0)
-
-	//
-	// Textures
-	pScene->mNumTextures = static_cast<unsigned int>(mTexture_Converted.size());
-	if(pScene->mNumTextures > 0)
-	{
-		size_t idx;
-
-		idx = 0;
-		pScene->mTextures = new aiTexture*[pScene->mNumTextures];
-		for(const SPP_Texture& tex_convd: mTexture_Converted)
-		{
-			pScene->mTextures[idx] = new aiTexture;
-			pScene->mTextures[idx]->mWidth = static_cast<unsigned int>(tex_convd.Width);
-			pScene->mTextures[idx]->mHeight = static_cast<unsigned int>(tex_convd.Height);
-			pScene->mTextures[idx]->pcData = (aiTexel*)tex_convd.Data;
-			// texture format description.
-			strcpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint);
-			idx++;
-		}// for(const SPP_Texture& tex_convd: mTexture_Converted)
-
-		// Create materials for embedded textures.
-		idx = 0;
-		pScene->mNumMaterials = static_cast<unsigned int>(mTexture_Converted.size());
-		pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
-		for(const SPP_Texture& tex_convd: mTexture_Converted)
-		{
-			const aiString texture_id(AI_EMBEDDED_TEXNAME_PREFIX + to_string(idx));
-			const int mode = aiTextureOp_Multiply;
-			const int repeat = tex_convd.Tiled ? 1 : 0;
-
-			pScene->mMaterials[idx] = new aiMaterial;
-			pScene->mMaterials[idx]->AddProperty(&texture_id, AI_MATKEY_TEXTURE_DIFFUSE(0));
-			pScene->mMaterials[idx]->AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0));
-			pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
-			pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
-			idx++;
-		}
-	}// if(pScene->mNumTextures > 0)
-}// END: after that walk through children of root and collect data
-
-}// namespace Assimp
-
-#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 249 - 308
code/AssetLib/3DS/3DSConverter.cpp


+ 108 - 123
code/3DS/3DSExporter.cpp → code/AssetLib/3DS/3DSExporter.cpp

@@ -43,120 +43,117 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
 
-#include "3DS/3DSExporter.h"
-#include "3DS/3DSLoader.h"
-#include "3DS/3DSHelper.h"
+#include "AssetLib/3DS/3DSExporter.h"
+#include "AssetLib/3DS/3DSHelper.h"
+#include "AssetLib/3DS/3DSLoader.h"
 #include "PostProcessing/SplitLargeMeshes.h"
 
 #include <assimp/SceneCombiner.h>
 #include <assimp/StringComparison.h>
-#include <assimp/IOSystem.hpp>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Exporter.hpp>
+#include <assimp/IOSystem.hpp>
 
 #include <memory>
 
 using namespace Assimp;
-namespace Assimp    {
+namespace Assimp {
 using namespace D3DS;
 
 namespace {
 
-    //////////////////////////////////////////////////////////////////////////////////////
-    // Scope utility to write a 3DS file chunk.
-    //
-    // Upon construction, the chunk header is written with the chunk type (flags)
-    // filled out, but the chunk size left empty. Upon destruction, the correct chunk
-    // size based on the then-position of the output stream cursor is filled in.
-    class ChunkWriter {
-        enum {
-              CHUNK_SIZE_NOT_SET = 0xdeadbeef
-            , SIZE_OFFSET        = 2
-        };
-    public:
-
-        ChunkWriter(StreamWriterLE& writer, uint16_t chunk_type)
-            : writer(writer)
-        {
-            chunk_start_pos = writer.GetCurrentPos();
-            writer.PutU2(chunk_type);
-            writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET);
-        }
-
-        ~ChunkWriter() {
-            std::size_t head_pos = writer.GetCurrentPos();
+//////////////////////////////////////////////////////////////////////////////////////
+// Scope utility to write a 3DS file chunk.
+//
+// Upon construction, the chunk header is written with the chunk type (flags)
+// filled out, but the chunk size left empty. Upon destruction, the correct chunk
+// size based on the then-position of the output stream cursor is filled in.
+class ChunkWriter {
+    enum {
+        CHUNK_SIZE_NOT_SET = 0xdeadbeef,
+        SIZE_OFFSET = 2
+    };
 
-            ai_assert(head_pos > chunk_start_pos);
-            const std::size_t chunk_size = head_pos - chunk_start_pos;
+public:
+    ChunkWriter(StreamWriterLE &writer, uint16_t chunk_type) :
+            writer(writer) {
+        chunk_start_pos = writer.GetCurrentPos();
+        writer.PutU2(chunk_type);
+        writer.PutU4((uint32_t)CHUNK_SIZE_NOT_SET);
+    }
 
-            writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
-            writer.PutU4(static_cast<uint32_t>(chunk_size));
-            writer.SetCurrentPos(head_pos);
-        }
+    ~ChunkWriter() {
+        std::size_t head_pos = writer.GetCurrentPos();
 
-    private:
-        StreamWriterLE& writer;
-        std::size_t chunk_start_pos;
-    };
+        ai_assert(head_pos > chunk_start_pos);
+        const std::size_t chunk_size = head_pos - chunk_start_pos;
 
+        writer.SetCurrentPos(chunk_start_pos + SIZE_OFFSET);
+        writer.PutU4(static_cast<uint32_t>(chunk_size));
+        writer.SetCurrentPos(head_pos);
+    }
 
-    // Return an unique name for a given |mesh| attached to |node| that
-    // preserves the mesh's given name if it has one. |index| is the index
-    // of the mesh in |aiScene::mMeshes|.
-    std::string GetMeshName(const aiMesh& mesh, unsigned int index, const aiNode& node) {
-        static const std::string underscore = "_";
-        char postfix[10] = {0};
-        ASSIMP_itoa10(postfix, index);
+private:
+    StreamWriterLE &writer;
+    std::size_t chunk_start_pos;
+};
+
+// Return an unique name for a given |mesh| attached to |node| that
+// preserves the mesh's given name if it has one. |index| is the index
+// of the mesh in |aiScene::mMeshes|.
+std::string GetMeshName(const aiMesh &mesh, unsigned int index, const aiNode &node) {
+    static const std::string underscore = "_";
+    char postfix[10] = { 0 };
+    ASSIMP_itoa10(postfix, index);
+
+    std::string result = node.mName.C_Str();
+    if (mesh.mName.length > 0) {
+        result += underscore + mesh.mName.C_Str();
+    }
+    return result + underscore + postfix;
+}
 
-        std::string result = node.mName.C_Str();
-        if (mesh.mName.length > 0) {
-            result += underscore + mesh.mName.C_Str();
-        }
-        return result + underscore + postfix;
+// Return an unique name for a given |mat| with original position |index|
+// in |aiScene::mMaterials|. The name preserves the original material
+// name if possible.
+std::string GetMaterialName(const aiMaterial &mat, unsigned int index) {
+    static const std::string underscore = "_";
+    char postfix[10] = { 0 };
+    ASSIMP_itoa10(postfix, index);
+
+    aiString mat_name;
+    if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
+        return mat_name.C_Str() + underscore + postfix;
     }
 
-    // Return an unique name for a given |mat| with original position |index|
-    // in |aiScene::mMaterials|. The name preserves the original material
-    // name if possible.
-    std::string GetMaterialName(const aiMaterial& mat, unsigned int index) {
-        static const std::string underscore = "_";
-        char postfix[10] = {0};
-        ASSIMP_itoa10(postfix, index);
-
-        aiString mat_name;
-        if (AI_SUCCESS == mat.Get(AI_MATKEY_NAME, mat_name)) {
-            return mat_name.C_Str() + underscore + postfix;
-        }
+    return "Material" + underscore + postfix;
+}
 
-        return "Material" + underscore + postfix;
+// Collect world transformations for each node
+void CollectTrafos(const aiNode *node, std::map<const aiNode *, aiMatrix4x4> &trafos) {
+    const aiMatrix4x4 &parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
+    trafos[node] = parent * node->mTransformation;
+    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
+        CollectTrafos(node->mChildren[i], trafos);
     }
+}
 
-    // Collect world transformations for each node
-    void CollectTrafos(const aiNode* node, std::map<const aiNode*, aiMatrix4x4>& trafos) {
-        const aiMatrix4x4& parent = node->mParent ? trafos[node->mParent] : aiMatrix4x4();
-        trafos[node] = parent * node->mTransformation;
-        for (unsigned int i = 0; i < node->mNumChildren; ++i) {
-            CollectTrafos(node->mChildren[i], trafos);
-        }
+// Generate a flat list of the meshes (by index) assigned to each node
+void CollectMeshes(const aiNode *node, std::multimap<const aiNode *, unsigned int> &meshes) {
+    for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
+        meshes.insert(std::make_pair(node, node->mMeshes[i]));
     }
-
-    // Generate a flat list of the meshes (by index) assigned to each node
-    void CollectMeshes(const aiNode* node, std::multimap<const aiNode*, unsigned int>& meshes) {
-        for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
-            meshes.insert(std::make_pair(node, node->mMeshes[i]));
-        }
-        for (unsigned int i = 0; i < node->mNumChildren; ++i) {
-            CollectMeshes(node->mChildren[i], meshes);
-        }
+    for (unsigned int i = 0; i < node->mNumChildren; ++i) {
+        CollectMeshes(node->mChildren[i], meshes);
     }
 }
+} // namespace
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
-void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
-{
-    std::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
-    if(!outfile) {
+void ExportScene3DS(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
+    std::shared_ptr<IOStream> outfile(pIOSystem->Open(pFile, "wb"));
+    if (!outfile) {
         throw DeadlyExportError("Could not open output .3ds file: " + std::string(pFile));
     }
 
@@ -167,8 +164,8 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
     // SplitLargeMeshes can do this, but it requires the correct limit to be set
     // which is not possible with the current way of specifying preprocess steps
     // in |Exporter::ExportFormatEntry|.
-    aiScene* scenecopy_tmp;
-    SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
+    aiScene *scenecopy_tmp;
+    SceneCombiner::CopyScene(&scenecopy_tmp, pScene);
     std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
 
     SplitLargeMeshesProcess_Triangle tri_splitter;
@@ -186,10 +183,8 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
 } // end of namespace Assimp
 
 // ------------------------------------------------------------------------------------------------
-Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* scene)
-: scene(scene)
-, writer(outfile)
-{
+Discreet3DSExporter::Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene *scene) :
+        scene(scene), writer(outfile) {
     CollectTrafos(scene->mRootNode, trafos);
     CollectMeshes(scene->mRootNode, meshes);
 
@@ -217,10 +212,8 @@ Discreet3DSExporter::~Discreet3DSExporter() {
     // empty
 }
 
-
 // ------------------------------------------------------------------------------------------------
-int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
-{
+int Discreet3DSExporter::WriteHierarchy(const aiNode &node, int seq, int sibling_level) {
     // 3DS scene hierarchy is serialized as in http://www.martinreddy.net/gfx/3d/3DS.spec
     {
         ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_TRACKINFO);
@@ -237,7 +230,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
 
             int16_t hierarchy_pos = static_cast<int16_t>(seq);
             if (sibling_level != -1) {
-                hierarchy_pos =(uint16_t) sibling_level;
+                hierarchy_pos = (uint16_t)sibling_level;
             }
 
             // Write the hierarchy position
@@ -260,7 +253,7 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
         const bool first_child = node.mNumChildren == 0 && i == 0;
 
         const unsigned int mesh_idx = node.mMeshes[i];
-        const aiMesh& mesh = *scene->mMeshes[mesh_idx];
+        const aiMesh &mesh = *scene->mMeshes[mesh_idx];
 
         ChunkWriter curChunk(writer, Discreet3DS::CHUNK_TRACKINFO);
         {
@@ -276,15 +269,14 @@ int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling
 }
 
 // ------------------------------------------------------------------------------------------------
-void Discreet3DSExporter::WriteMaterials()
-{
+void Discreet3DSExporter::WriteMaterials() {
     for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
         ChunkWriter curRootChunk(writer, Discreet3DS::CHUNK_MAT_MATERIAL);
-        const aiMaterial& mat = *scene->mMaterials[i];
+        const aiMaterial &mat = *scene->mMaterials[i];
 
         {
             ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_MATNAME);
-            const std::string& name = GetMaterialName(mat, i);
+            const std::string &name = GetMaterialName(mat, i);
             WriteString(name);
         }
 
@@ -314,7 +306,7 @@ void Discreet3DSExporter::WriteMaterials()
             ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHADING);
 
             Discreet3DS::shadetype3ds shading_mode_out;
-            switch(shading_mode) {
+            switch (shading_mode) {
             case aiShadingMode_Flat:
             case aiShadingMode_NoShading:
                 shading_mode_out = Discreet3DS::Flat;
@@ -341,7 +333,6 @@ void Discreet3DSExporter::WriteMaterials()
             writer.PutU2(static_cast<uint16_t>(shading_mode_out));
         }
 
-
         float f;
         if (mat.Get(AI_MATKEY_SHININESS, f) == AI_SUCCESS) {
             ChunkWriter chunk(writer, Discreet3DS::CHUNK_MAT_SHININESS);
@@ -370,14 +361,13 @@ void Discreet3DSExporter::WriteMaterials()
 }
 
 // ------------------------------------------------------------------------------------------------
-void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags)
-{
+void Discreet3DSExporter::WriteTexture(const aiMaterial &mat, aiTextureType type, uint16_t chunk_flags) {
     aiString path;
     aiTextureMapMode map_mode[2] = {
         aiTextureMapMode_Wrap, aiTextureMapMode_Wrap
     };
     ai_real blend = 1.0;
-    if (mat.GetTexture(type, 0, &path, NULL, NULL, &blend, NULL, map_mode) != AI_SUCCESS || !path.length) {
+    if (mat.GetTexture(type, 0, &path, nullptr, nullptr, &blend, nullptr, map_mode) != AI_SUCCESS || !path.length) {
         return;
     }
 
@@ -400,8 +390,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
         uint16_t val = 0; // WRAP
         if (map_mode[0] == aiTextureMapMode_Mirror) {
             val = 0x2;
-        }
-        else if (map_mode[0] == aiTextureMapMode_Decal) {
+        } else if (map_mode[0] == aiTextureMapMode_Decal) {
             val = 0x10;
         }
         writer.PutU2(val);
@@ -410,8 +399,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
 }
 
 // ------------------------------------------------------------------------------------------------
-void Discreet3DSExporter::WriteMeshes()
-{
+void Discreet3DSExporter::WriteMeshes() {
     // NOTE: 3DS allows for instances. However:
     //   i)  not all importers support reading them
     //   ii) instances are not as flexible as they are in assimp, in particular,
@@ -423,25 +411,24 @@ void Discreet3DSExporter::WriteMeshes()
     // Furthermore, the TRIMESH is transformed into world space so that it will
     // appear correctly if importers don't read the scene hierarchy at all.
     for (MeshesByNodeMap::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
-        const aiNode& node = *(*it).first;
+        const aiNode &node = *(*it).first;
         const unsigned int mesh_idx = (*it).second;
 
-        const aiMesh& mesh = *scene->mMeshes[mesh_idx];
+        const aiMesh &mesh = *scene->mMeshes[mesh_idx];
 
         // This should not happen if the SLM step is correctly executed
         // before the scene is handed to the exporter
         ai_assert(mesh.mNumVertices <= 0xffff);
         ai_assert(mesh.mNumFaces <= 0xffff);
 
-        const aiMatrix4x4& trafo = trafos[&node];
+        const aiMatrix4x4 &trafo = trafos[&node];
 
         ChunkWriter chunk(writer, Discreet3DS::CHUNK_OBJBLOCK);
 
         // Mesh name is tied to the node it is attached to so it can later be referenced
-        const std::string& name = GetMeshName(mesh, mesh_idx, node);
+        const std::string &name = GetMeshName(mesh, mesh_idx, node);
         WriteString(name);
 
-
         // TRIMESH chunk
         ChunkWriter chunk2(writer, Discreet3DS::CHUNK_TRIMESH);
 
@@ -452,7 +439,7 @@ void Discreet3DSExporter::WriteMeshes()
             const uint16_t count = static_cast<uint16_t>(mesh.mNumVertices);
             writer.PutU2(count);
             for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
-                const aiVector3D& v = trafo * mesh.mVertices[i];
+                const aiVector3D &v = trafo * mesh.mVertices[i];
                 writer.PutF4(v.x);
                 writer.PutF4(v.y);
                 writer.PutF4(v.z);
@@ -466,7 +453,7 @@ void Discreet3DSExporter::WriteMeshes()
             writer.PutU2(count);
 
             for (unsigned int i = 0; i < mesh.mNumVertices; ++i) {
-                const aiVector3D& v = mesh.mTextureCoords[0][i];
+                const aiVector3D &v = mesh.mTextureCoords[0][i];
                 writer.PutF4(v.x);
                 writer.PutF4(v.y);
             }
@@ -481,7 +468,7 @@ void Discreet3DSExporter::WriteMeshes()
             // Count triangles, discard lines and points
             uint16_t count = 0;
             for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
-                const aiFace& f = mesh.mFaces[i];
+                const aiFace &f = mesh.mFaces[i];
                 if (f.mNumIndices < 3) {
                     continue;
                 }
@@ -492,7 +479,7 @@ void Discreet3DSExporter::WriteMeshes()
 
             writer.PutU2(count);
             for (unsigned int i = 0; i < mesh.mNumFaces; ++i) {
-                const aiFace& f = mesh.mFaces[i];
+                const aiFace &f = mesh.mFaces[i];
                 if (f.mNumIndices < 3) {
                     continue;
                 }
@@ -524,10 +511,9 @@ void Discreet3DSExporter::WriteMeshes()
 }
 
 // ------------------------------------------------------------------------------------------------
-void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
-{
+void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh &mesh) {
     ChunkWriter curChunk(writer, Discreet3DS::CHUNK_FACEMAT);
-    const std::string& name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
+    const std::string &name = GetMaterialName(*scene->mMaterials[mesh.mMaterialIndex], mesh.mMaterialIndex);
     WriteString(name);
 
     // Because assimp splits meshes by material, only a single
@@ -542,7 +528,7 @@ void Discreet3DSExporter::WriteFaceMaterialChunk(const aiMesh& mesh)
 }
 
 // ------------------------------------------------------------------------------------------------
-void Discreet3DSExporter::WriteString(const std::string& s) {
+void Discreet3DSExporter::WriteString(const std::string &s) {
     for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
         writer.PutI1(*it);
     }
@@ -550,7 +536,7 @@ void Discreet3DSExporter::WriteString(const std::string& s) {
 }
 
 // ------------------------------------------------------------------------------------------------
-void Discreet3DSExporter::WriteString(const aiString& s) {
+void Discreet3DSExporter::WriteString(const aiString &s) {
     for (std::size_t i = 0; i < s.length; ++i) {
         writer.PutI1(s.data[i]);
     }
@@ -558,7 +544,7 @@ void Discreet3DSExporter::WriteString(const aiString& s) {
 }
 
 // ------------------------------------------------------------------------------------------------
-void Discreet3DSExporter::WriteColor(const aiColor3D& color) {
+void Discreet3DSExporter::WriteColor(const aiColor3D &color) {
     ChunkWriter curChunk(writer, Discreet3DS::CHUNK_RGBF);
     writer.PutF4(color.r);
     writer.PutF4(color.g);
@@ -577,6 +563,5 @@ void Discreet3DSExporter::WritePercentChunk(double f) {
     writer.PutF8(f);
 }
 
-
 #endif // ASSIMP_BUILD_NO_3DS_EXPORTER
 #endif // ASSIMP_BUILD_NO_EXPORT

+ 0 - 0
code/3DS/3DSExporter.h → code/AssetLib/3DS/3DSExporter.h


+ 49 - 24
code/3DS/3DSHelper.h → code/AssetLib/3DS/3DSHelper.h

@@ -322,7 +322,7 @@ struct Face : public FaceWithSmoothingGroup {
 };
 
 #ifdef _WIN32
-#    pragma warning(disable : 4315)
+#pragma warning(disable : 4315)
 #endif
 
 // ---------------------------------------------------------------------------
@@ -441,30 +441,50 @@ struct Material {
         // empty
     }
 
-    Material(const Material &other) = default;
-    Material &operator=(const Material &other) = default;
+    Material(const Material &other) :
+            mName(other.mName),
+            mDiffuse(other.mDiffuse),
+            mSpecularExponent(other.mSpecularExponent),
+            mShininessStrength(other.mShininessStrength),
+            mSpecular(other.mSpecular),
+            mAmbient(other.mAmbient),
+            mShading(other.mShading),
+            mTransparency(other.mTransparency),
+            sTexDiffuse(other.sTexDiffuse),
+            sTexOpacity(other.sTexOpacity),
+            sTexSpecular(other.sTexSpecular),
+            sTexReflective(other.sTexReflective),
+            sTexBump(other.sTexBump),
+            sTexEmissive(other.sTexEmissive),
+            sTexShininess(other.sTexShininess),
+            mBumpHeight(other.mBumpHeight),
+            mEmissive(other.mEmissive),
+            sTexAmbient(other.sTexAmbient),
+            mTwoSided(other.mTwoSided) {
+        // empty
+    }
 
     //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
-    Material(Material &&other) AI_NO_EXCEPT
-            : mName(std::move(other.mName)),
-              mDiffuse(std::move(other.mDiffuse)),
-              mSpecularExponent(std::move(other.mSpecularExponent)),
-              mShininessStrength(std::move(other.mShininessStrength)),
-              mSpecular(std::move(other.mSpecular)),
-              mAmbient(std::move(other.mAmbient)),
-              mShading(std::move(other.mShading)),
-              mTransparency(std::move(other.mTransparency)),
-              sTexDiffuse(std::move(other.sTexDiffuse)),
-              sTexOpacity(std::move(other.sTexOpacity)),
-              sTexSpecular(std::move(other.sTexSpecular)),
-              sTexReflective(std::move(other.sTexReflective)),
-              sTexBump(std::move(other.sTexBump)),
-              sTexEmissive(std::move(other.sTexEmissive)),
-              sTexShininess(std::move(other.sTexShininess)),
-              mBumpHeight(std::move(other.mBumpHeight)),
-              mEmissive(std::move(other.mEmissive)),
-              sTexAmbient(std::move(other.sTexAmbient)),
-              mTwoSided(std::move(other.mTwoSided)) {
+    Material(Material &&other) AI_NO_EXCEPT : mName(std::move(other.mName)),
+                                              mDiffuse(std::move(other.mDiffuse)),
+                                              mSpecularExponent(std::move(other.mSpecularExponent)),
+                                              mShininessStrength(std::move(other.mShininessStrength)),
+                                              mSpecular(std::move(other.mSpecular)),
+                                              mAmbient(std::move(other.mAmbient)),
+                                              mShading(std::move(other.mShading)),
+                                              mTransparency(std::move(other.mTransparency)),
+                                              sTexDiffuse(std::move(other.sTexDiffuse)),
+                                              sTexOpacity(std::move(other.sTexOpacity)),
+                                              sTexSpecular(std::move(other.sTexSpecular)),
+                                              sTexReflective(std::move(other.sTexReflective)),
+                                              sTexBump(std::move(other.sTexBump)),
+                                              sTexEmissive(std::move(other.sTexEmissive)),
+                                              sTexShininess(std::move(other.sTexShininess)),
+                                              mBumpHeight(std::move(other.mBumpHeight)),
+                                              mEmissive(std::move(other.mEmissive)),
+                                              sTexAmbient(std::move(other.sTexAmbient)),
+                                              mTwoSided(std::move(other.mTwoSided)) {
+        // empty
     }
 
     Material &operator=(Material &&other) AI_NO_EXCEPT {
@@ -593,7 +613,12 @@ struct Node {
     Node() = delete;
 
     explicit Node(const std::string &name) :
-            mParent(NULL), mName(name), mInstanceNumber(0), mHierarchyPos(0), mHierarchyIndex(0), mInstanceCount(1) {
+            mParent(nullptr),
+            mName(name),
+            mInstanceNumber(0),
+            mHierarchyPos(0),
+            mHierarchyIndex(0),
+            mInstanceCount(1) {
         aRotationKeys.reserve(20);
         aPositionKeys.reserve(20);
         aScalingKeys.reserve(20);

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 247 - 310
code/AssetLib/3DS/3DSLoader.cpp


+ 1 - 5
code/3DS/3DSLoader.h → code/AssetLib/3DS/3DSLoader.h

@@ -65,15 +65,11 @@ using namespace D3DS;
 // ---------------------------------------------------------------------------------
 /** Importer class for 3D Studio r3 and r4 3DS files
  */
-class Discreet3DSImporter : public BaseImporter
-{
+class Discreet3DSImporter : public BaseImporter {
 public:
-
     Discreet3DSImporter();
     ~Discreet3DSImporter();
 
-public:
-
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.
      * See BaseImporter::CanRead() for details.

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


+ 124 - 122
code/3MF/D3MFExporter.cpp → code/AssetLib/3MF/D3MFExporter.cpp

@@ -44,81 +44,74 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "D3MFExporter.h"
 
+#include <assimp/Exceptional.h>
+#include <assimp/StringUtils.h>
 #include <assimp/scene.h>
-#include <assimp/IOSystem.hpp>
-#include <assimp/IOStream.hpp>
-#include <assimp/Exporter.hpp>
 #include <assimp/DefaultLogger.hpp>
-#include <assimp/StringUtils.h>
-#include <assimp/Exceptional.h>
+#include <assimp/Exporter.hpp>
+#include <assimp/IOStream.hpp>
+#include <assimp/IOSystem.hpp>
 
 #include "3MFXmlTags.h"
 #include "D3MFOpcPackage.h"
 
 #ifdef ASSIMP_USE_HUNTER
-#  include <zip/zip.h>
+#include <zip/zip.h>
 #else
-#  include <contrib/zip/src/zip.h>
+#include <contrib/zip/src/zip.h>
 #endif
 
 namespace Assimp {
 
-void ExportScene3MF( const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/ ) {
-    if ( nullptr == pIOSystem ) {
-        throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
+void ExportScene3MF(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
+    if (nullptr == pIOSystem) {
+        throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile));
     }
-    D3MF::D3MFExporter myExporter( pFile, pScene );
-    if ( myExporter.validate() ) {
-        if ( pIOSystem->Exists( pFile ) ) {
-            if ( !pIOSystem->DeleteFile( pFile ) ) {
-                throw DeadlyExportError( "File exists, cannot override : " + std::string( pFile ) );
+    D3MF::D3MFExporter myExporter(pFile, pScene);
+    if (myExporter.validate()) {
+        if (pIOSystem->Exists(pFile)) {
+            if (!pIOSystem->DeleteFile(pFile)) {
+                throw DeadlyExportError("File exists, cannot override : " + std::string(pFile));
             }
         }
         bool ok = myExporter.exportArchive(pFile);
-        if ( !ok ) {
-            throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
+        if (!ok) {
+            throw DeadlyExportError("Could not export 3MP archive: " + std::string(pFile));
         }
     }
 }
 
 namespace D3MF {
 
-D3MFExporter::D3MFExporter( const char* pFile, const aiScene* pScene )
-: mArchiveName( pFile )
-, m_zipArchive( nullptr )
-, mScene( pScene )
-, mModelOutput()
-, mRelOutput()
-, mContentOutput()
-, mBuildItems()
-, mRelations() {
+D3MFExporter::D3MFExporter(const char *pFile, const aiScene *pScene) :
+        mArchiveName(pFile), m_zipArchive(nullptr), mScene(pScene), mModelOutput(), mRelOutput(), mContentOutput(), mBuildItems(), mRelations() {
     // empty
 }
 
 D3MFExporter::~D3MFExporter() {
-    for ( size_t i = 0; i < mRelations.size(); ++i ) {
-        delete mRelations[ i ];
+    for (size_t i = 0; i < mRelations.size(); ++i) {
+        delete mRelations[i];
     }
     mRelations.clear();
 }
 
 bool D3MFExporter::validate() {
-    if ( mArchiveName.empty() ) {
+    if (mArchiveName.empty()) {
         return false;
     }
 
-    if ( nullptr == mScene ) {
+    if (nullptr == mScene) {
         return false;
     }
 
     return true;
 }
 
-bool D3MFExporter::exportArchive( const char *file ) {
-    bool ok( true );
+bool D3MFExporter::exportArchive(const char *file) {
+    bool ok(true);
 
-    m_zipArchive = zip_open( file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w' );
-    if ( nullptr == m_zipArchive ) {
+    m_zipArchive = zip_open(file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
+    if (nullptr == m_zipArchive) {
         return false;
     }
 
@@ -126,7 +119,7 @@ bool D3MFExporter::exportArchive( const char *file ) {
     ok |= export3DModel();
     ok |= exportRelations();
 
-    zip_close( m_zipArchive );
+    zip_close(m_zipArchive);
     m_zipArchive = nullptr;
 
     return ok;
@@ -145,7 +138,7 @@ bool D3MFExporter::exportContentTypes() {
     mContentOutput << std::endl;
     mContentOutput << "</Types>";
     mContentOutput << std::endl;
-    exportContentTyp( XmlTag::CONTENT_TYPES_ARCHIVE );
+    exportContentTyp(XmlTag::CONTENT_TYPES_ARCHIVE);
 
     return true;
 }
@@ -157,20 +150,20 @@ bool D3MFExporter::exportRelations() {
     mRelOutput << std::endl;
     mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
 
-    for ( size_t i = 0; i < mRelations.size(); ++i ) {
-        if ( mRelations[ i ]->target[ 0 ] == '/' ) {
-            mRelOutput << "<Relationship Target=\"" << mRelations[ i ]->target << "\" ";
+    for (size_t i = 0; i < mRelations.size(); ++i) {
+        if (mRelations[i]->target[0] == '/') {
+            mRelOutput << "<Relationship Target=\"" << mRelations[i]->target << "\" ";
         } else {
-            mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
+            mRelOutput << "<Relationship Target=\"/" << mRelations[i]->target << "\" ";
         }
         mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
-        mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
+        mRelOutput << "Type=\"" << mRelations[i]->type << "\" />";
         mRelOutput << std::endl;
     }
     mRelOutput << "</Relationships>";
     mRelOutput << std::endl;
 
-    writeRelInfoToFile( "_rels", ".rels" );
+    writeRelInfoToFile("_rels", ".rels");
     mRelOutput.flush();
 
     return true;
@@ -181,8 +174,8 @@ bool D3MFExporter::export3DModel() {
 
     writeHeader();
     mModelOutput << "<" << XmlTag::model << " " << XmlTag::model_unit << "=\"millimeter\""
-            << "xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">"
-            << std::endl;
+                 << " xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">"
+                 << std::endl;
     mModelOutput << "<" << XmlTag::resources << ">";
     mModelOutput << std::endl;
 
@@ -192,7 +185,6 @@ bool D3MFExporter::export3DModel() {
 
     writeObjects();
 
-
     mModelOutput << "</" << XmlTag::resources << ">";
     mModelOutput << std::endl;
     writeBuild();
@@ -203,36 +195,36 @@ bool D3MFExporter::export3DModel() {
     info->id = "rel0";
     info->target = "/3D/3DModel.model";
     info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
-    mRelations.push_back( info );
+    mRelations.push_back(info);
 
-    writeModelToArchive( "3D", "3DModel.model" );
+    writeModelToArchive("3D", "3DModel.model");
     mModelOutput.flush();
 
     return true;
 }
 
 void D3MFExporter::writeHeader() {
-    mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF - 8\"?>";
+    mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
     mModelOutput << std::endl;
 }
 
 void D3MFExporter::writeMetaData() {
-    if ( nullptr == mScene->mMetaData ) {
+    if (nullptr == mScene->mMetaData) {
         return;
     }
 
-    const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
-    if ( 0 == numMetaEntries ) {
+    const unsigned int numMetaEntries(mScene->mMetaData->mNumProperties);
+    if (0 == numMetaEntries) {
         return;
     }
 
-	const aiString *key = nullptr;
+    const aiString *key = nullptr;
     const aiMetadataEntry *entry(nullptr);
-    for ( size_t i = 0; i < numMetaEntries; ++i ) {
-        mScene->mMetaData->Get( i, key, entry );
-        std::string k( key->C_Str() );
+    for (size_t i = 0; i < numMetaEntries; ++i) {
+        mScene->mMetaData->Get(i, key, entry);
+        std::string k(key->C_Str());
         aiString value;
-        mScene->mMetaData->Get(  k, value );
+        mScene->mMetaData->Get(k, value);
         mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
         mModelOutput << value.C_Str();
         mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
@@ -241,103 +233,114 @@ void D3MFExporter::writeMetaData() {
 
 void D3MFExporter::writeBaseMaterials() {
     mModelOutput << "<basematerials id=\"1\">\n";
-    std::string strName, hexDiffuseColor , tmp;
-    for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
-        aiMaterial *mat = mScene->mMaterials[ i ];
+    std::string strName, hexDiffuseColor, tmp;
+    for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
+        aiMaterial *mat = mScene->mMaterials[i];
         aiString name;
-        if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
-            strName = "basemat_" + to_string( i );
+        if (mat->Get(AI_MATKEY_NAME, name) != aiReturn_SUCCESS) {
+            strName = "basemat_" + to_string(i);
         } else {
             strName = name.C_Str();
         }
         aiColor4D color;
-        if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
+        if (mat->Get(AI_MATKEY_COLOR_DIFFUSE, color) == aiReturn_SUCCESS) {
             hexDiffuseColor.clear();
             tmp.clear();
-            hexDiffuseColor = "#";
-            
-            tmp = DecimalToHexa( (ai_real) color.r );
-            hexDiffuseColor += tmp;
-            tmp = DecimalToHexa((ai_real)color.g);
-            hexDiffuseColor += tmp;
-            tmp = DecimalToHexa((ai_real)color.b);
-            hexDiffuseColor += tmp;
-            tmp = DecimalToHexa((ai_real)color.a);
-            hexDiffuseColor += tmp;
+            // rgbs %
+            if (color.r <= 1 && color.g <= 1 && color.b <= 1 && color.a <= 1) {
+
+                hexDiffuseColor = Rgba2Hex(
+                        (int)((ai_real)color.r) * 255,
+                        (int)((ai_real)color.g) * 255,
+                        (int)((ai_real)color.b) * 255,
+                        (int)((ai_real)color.a) * 255,
+                        true);
+
+            } else {
+                hexDiffuseColor = "#";
+                tmp = DecimalToHexa((ai_real)color.r);
+                hexDiffuseColor += tmp;
+                tmp = DecimalToHexa((ai_real)color.g);
+                hexDiffuseColor += tmp;
+                tmp = DecimalToHexa((ai_real)color.b);
+                hexDiffuseColor += tmp;
+                tmp = DecimalToHexa((ai_real)color.a);
+                hexDiffuseColor += tmp;
+            }
         } else {
             hexDiffuseColor = "#FFFFFFFF";
         }
 
-        mModelOutput << "<base name=\""+strName+"\" "+" displaycolor=\""+hexDiffuseColor+"\" />\n";
+        mModelOutput << "<base name=\"" + strName + "\" " + " displaycolor=\"" + hexDiffuseColor + "\" />\n";
     }
     mModelOutput << "</basematerials>\n";
 }
 
 void D3MFExporter::writeObjects() {
-    if ( nullptr == mScene->mRootNode ) {
+    if (nullptr == mScene->mRootNode) {
         return;
     }
 
     aiNode *root = mScene->mRootNode;
-    for ( unsigned int i = 0; i < root->mNumChildren; ++i ) {
-        aiNode *currentNode( root->mChildren[ i ] );
-        if ( nullptr == currentNode ) {
+    for (unsigned int i = 0; i < root->mNumChildren; ++i) {
+        aiNode *currentNode(root->mChildren[i]);
+        if (nullptr == currentNode) {
             continue;
         }
-        mModelOutput << "<" << XmlTag::object << " id=\"" << currentNode->mName.C_Str() << "\" type=\"model\">";
+        mModelOutput << "<" << XmlTag::object << " id=\"" << i + 2 << "\" type=\"model\">";
         mModelOutput << std::endl;
-        for ( unsigned int j = 0; j < currentNode->mNumMeshes; ++j ) {
-            aiMesh *currentMesh = mScene->mMeshes[ currentNode->mMeshes[ j ] ];
-            if ( nullptr == currentMesh ) {
+        for (unsigned int j = 0; j < currentNode->mNumMeshes; ++j) {
+            aiMesh *currentMesh = mScene->mMeshes[currentNode->mMeshes[j]];
+            if (nullptr == currentMesh) {
                 continue;
             }
-            writeMesh( currentMesh );
+            writeMesh(currentMesh);
         }
-        mBuildItems.push_back( i );
+        mBuildItems.push_back(i);
 
         mModelOutput << "</" << XmlTag::object << ">";
         mModelOutput << std::endl;
     }
 }
 
-void D3MFExporter::writeMesh( aiMesh *mesh ) {
-    if ( nullptr == mesh ) {
+void D3MFExporter::writeMesh(aiMesh *mesh) {
+    if (nullptr == mesh) {
         return;
     }
 
     mModelOutput << "<" << XmlTag::mesh << ">" << std::endl;
     mModelOutput << "<" << XmlTag::vertices << ">" << std::endl;
-    for ( unsigned int i = 0; i < mesh->mNumVertices; ++i ) {
-        writeVertex( mesh->mVertices[ i ] );
+    for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+        writeVertex(mesh->mVertices[i]);
     }
     mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
 
-    const unsigned int matIdx( mesh->mMaterialIndex );
+    const unsigned int matIdx(mesh->mMaterialIndex);
 
-    writeFaces( mesh, matIdx );
+    writeFaces(mesh, matIdx);
 
     mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
 }
 
-void D3MFExporter::writeVertex( const aiVector3D &pos ) {
+void D3MFExporter::writeVertex(const aiVector3D &pos) {
     mModelOutput << "<" << XmlTag::vertex << " x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\" />";
     mModelOutput << std::endl;
 }
 
-void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
-    if ( nullptr == mesh ) {
+void D3MFExporter::writeFaces(aiMesh *mesh, unsigned int matIdx) {
+    if (nullptr == mesh) {
         return;
     }
 
-    if ( !mesh->HasFaces() ) {
+    if (!mesh->HasFaces()) {
         return;
     }
     mModelOutput << "<" << XmlTag::triangles << ">" << std::endl;
-    for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) {
-        aiFace &currentFace = mesh->mFaces[ i ];
-        mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\""
-                << currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ]
-                << "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />";
+    for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
+        aiFace &currentFace = mesh->mFaces[i];
+        mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[0] << "\" v2=\""
+                     << currentFace.mIndices[1] << "\" v3=\"" << currentFace.mIndices[2]
+                     << "\" pid=\"1\" p1=\"" + to_string(matIdx) + "\" />";
         mModelOutput << std::endl;
     }
     mModelOutput << "</" << XmlTag::triangles << ">";
@@ -347,54 +350,53 @@ void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
 void D3MFExporter::writeBuild() {
     mModelOutput << "<" << XmlTag::build << ">" << std::endl;
 
-    for ( size_t i = 0; i < mBuildItems.size(); ++i ) {
-        mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 1 << "\"/>";
+    for (size_t i = 0; i < mBuildItems.size(); ++i) {
+        mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 2 << "\"/>";
         mModelOutput << std::endl;
     }
     mModelOutput << "</" << XmlTag::build << ">";
     mModelOutput << std::endl;
 }
 
-void D3MFExporter::exportContentTyp( const std::string &filename ) {
-    if ( nullptr == m_zipArchive ) {
-        throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
+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() );
+    zip_entry_open(m_zipArchive, entry.c_str());
 
-    const std::string &exportTxt( mContentOutput.str() );
-    zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
+    const std::string &exportTxt(mContentOutput.str());
+    zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
 
-    zip_entry_close( m_zipArchive );
+    zip_entry_close(m_zipArchive);
 }
 
-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::writeModelToArchive(const std::string &folder, const std::string &modelName) {
+    if (nullptr == m_zipArchive) {
+        throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
     }
     const std::string entry = folder + "/" + modelName;
-    zip_entry_open( m_zipArchive, entry.c_str() );
+    zip_entry_open(m_zipArchive, entry.c_str());
 
-    const std::string &exportTxt( mModelOutput.str() );
-    zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
+    const std::string &exportTxt(mModelOutput.str());
+    zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
 
-    zip_entry_close( m_zipArchive );
+    zip_entry_close(m_zipArchive);
 }
 
-void D3MFExporter::writeRelInfoToFile( const std::string &folder, const std::string &relName ) {
-    if ( nullptr == m_zipArchive ) {
-        throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
+void D3MFExporter::writeRelInfoToFile(const std::string &folder, const std::string &relName) {
+    if (nullptr == m_zipArchive) {
+        throw DeadlyExportError("3MF-Export: Zip archive not valid, nullptr.");
     }
     const std::string entry = folder + "/" + relName;
-    zip_entry_open( m_zipArchive, entry.c_str() );
+    zip_entry_open(m_zipArchive, entry.c_str());
 
-    const std::string &exportTxt( mRelOutput.str() );
-    zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
+    const std::string &exportTxt(mRelOutput.str());
+    zip_entry_write(m_zipArchive, exportTxt.c_str(), exportTxt.size());
 
-    zip_entry_close( m_zipArchive );
+    zip_entry_close(m_zipArchive);
 }
 
-
 } // Namespace D3MF
 } // Namespace Assimp
 

+ 0 - 0
code/3MF/D3MFExporter.h → code/AssetLib/3MF/D3MFExporter.h


+ 138 - 140
code/3MF/D3MFImporter.cpp → code/AssetLib/3MF/D3MFImporter.cpp

@@ -44,24 +44,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "D3MFImporter.h"
 
-#include <assimp/scene.h>
-#include <assimp/IOSystem.hpp>
-#include <assimp/DefaultLogger.hpp>
-#include <assimp/importerdesc.h>
 #include <assimp/StringComparison.h>
 #include <assimp/StringUtils.h>
 #include <assimp/ZipArchiveIOSystem.h>
+#include <assimp/importerdesc.h>
+#include <assimp/scene.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/IOSystem.hpp>
 
-#include <string>
-#include <vector>
-#include <map>
 #include <cassert>
+#include <map>
 #include <memory>
+#include <string>
+#include <vector>
 
-#include "D3MFOpcPackage.h"
-#include <assimp/irrXMLWrapper.h>
 #include "3MFXmlTags.h"
+#include "D3MFOpcPackage.h"
 #include <assimp/fast_atof.h>
+#include <assimp/irrXMLWrapper.h>
 
 #include <iomanip>
 
@@ -70,90 +70,90 @@ namespace D3MF {
 
 class XmlSerializer {
 public:
-    using MatArray = std::vector<aiMaterial*>;
+    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){
-		// empty
+    XmlSerializer(XmlReader *xmlReader) :
+            mMeshes(),
+            mMatArray(),
+            mActiveMatGroup(99999999),
+            mMatId2MatArray(),
+            xmlReader(xmlReader) {
+        // empty
     }
 
     ~XmlSerializer() {
         // empty
     }
 
-    void ImportXml(aiScene* scene) {
-        if ( nullptr == scene ) {
+    void ImportXml(aiScene *scene) {
+        if (nullptr == scene) {
             return;
         }
 
         scene->mRootNode = new aiNode();
-        std::vector<aiNode*> children;
+        std::vector<aiNode *> children;
 
         std::string nodeName;
-        while(ReadToEndElement(D3MF::XmlTag::model)) {
+        while (ReadToEndElement(D3MF::XmlTag::model)) {
             nodeName = xmlReader->getNodeName();
-            if( nodeName == D3MF::XmlTag::object) {
+            if (nodeName == D3MF::XmlTag::object) {
                 children.push_back(ReadObject(scene));
-            } else if( nodeName == D3MF::XmlTag::build) {
-                // 
-            } else if ( nodeName == D3MF::XmlTag::basematerials ) {
+            } else if (nodeName == D3MF::XmlTag::build) {
+                //
+            } else if (nodeName == D3MF::XmlTag::basematerials) {
                 ReadBaseMaterials();
-            } else if ( nodeName == D3MF::XmlTag::meta ) {
+            } else if (nodeName == D3MF::XmlTag::meta) {
                 ReadMetadata();
             }
         }
 
-        if ( scene->mRootNode->mName.length == 0 ) {
-            scene->mRootNode->mName.Set( "3MF" );
+        if (scene->mRootNode->mName.length == 0) {
+            scene->mRootNode->mName.Set("3MF");
         }
 
         // import the metadata
-        if ( !mMetaData.empty() ) {
-            const size_t numMeta( mMetaData.size() );
-            scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>( numMeta ) );
-            for ( size_t i = 0; i < numMeta; ++i ) {
-                aiString val( mMetaData[ i ].value );
-                scene->mMetaData->Set(static_cast<unsigned int>( i ), mMetaData[ i ].name, val );
+        if (!mMetaData.empty()) {
+            const size_t numMeta(mMetaData.size());
+            scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
+            for (size_t i = 0; i < numMeta; ++i) {
+                aiString val(mMetaData[i].value);
+                scene->mMetaData->Set(static_cast<unsigned int>(i), mMetaData[i].name, val);
             }
         }
 
         // 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>(mMeshes.size());
+        scene->mMeshes = new aiMesh *[scene->mNumMeshes]();
+        std::copy(mMeshes.begin(), mMeshes.end(), scene->mMeshes);
 
         // import the materials
-        scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
-        if ( 0 != scene->mNumMaterials ) {
-            scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
-            std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
+        scene->mNumMaterials = static_cast<unsigned int>(mMatArray.size());
+        if (0 != scene->mNumMaterials) {
+            scene->mMaterials = new aiMaterial *[scene->mNumMaterials];
+            std::copy(mMatArray.begin(), mMatArray.end(), scene->mMaterials);
         }
 
         // create the scenegraph
         scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
-        scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
+        scene->mRootNode->mChildren = new aiNode *[scene->mRootNode->mNumChildren]();
         std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
     }
 
 private:
-    aiNode* ReadObject(aiScene* scene) {
+    aiNode *ReadObject(aiScene *scene) {
         std::unique_ptr<aiNode> node(new aiNode());
 
         std::vector<unsigned long> meshIds;
 
-        const char *attrib( nullptr );
+        const char *attrib(nullptr);
         std::string name, type;
-        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
-        if ( nullptr != attrib ) {
+        attrib = xmlReader->getAttributeValue(D3MF::XmlTag::id.c_str());
+        if (nullptr != attrib) {
             name = attrib;
         }
-        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
-        if ( nullptr != attrib ) {
+        attrib = xmlReader->getAttributeValue(D3MF::XmlTag::type.c_str());
+        if (nullptr != attrib) {
             type = attrib;
         }
 
@@ -162,8 +162,8 @@ private:
 
         size_t meshIdx = mMeshes.size();
 
-        while(ReadToEndElement(D3MF::XmlTag::object)) {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
+        while (ReadToEndElement(D3MF::XmlTag::object)) {
+            if (xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
                 auto mesh = ReadMesh();
 
                 mesh->mName.Set(name);
@@ -183,11 +183,11 @@ private:
     }
 
     aiMesh *ReadMesh() {
-        aiMesh* mesh = new aiMesh();
-        while(ReadToEndElement(D3MF::XmlTag::mesh)) {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
+        aiMesh *mesh = new aiMesh();
+        while (ReadToEndElement(D3MF::XmlTag::mesh)) {
+            if (xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
                 ImportVertices(mesh);
-            } else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
+            } else if (xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
                 ImportTriangles(mesh);
             }
         }
@@ -196,24 +196,24 @@ private:
     }
 
     void ReadMetadata() {
-        const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
+        const std::string name = xmlReader->getAttributeValue(D3MF::XmlTag::meta_name.c_str());
         xmlReader->read();
         const std::string value = xmlReader->getNodeData();
 
-        if ( name.empty() ) {
+        if (name.empty()) {
             return;
         }
 
         MetaEntry entry;
         entry.name = name;
         entry.value = value;
-        mMetaData.push_back( entry );
+        mMetaData.push_back(entry);
     }
 
-    void ImportVertices(aiMesh* mesh) {
+    void ImportVertices(aiMesh *mesh) {
         std::vector<aiVector3D> vertices;
-        while(ReadToEndElement(D3MF::XmlTag::vertices)) {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
+        while (ReadToEndElement(D3MF::XmlTag::vertices)) {
+            if (xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
                 vertices.push_back(ReadVertex());
             }
         }
@@ -233,20 +233,20 @@ private:
         return vertex;
     }
 
-    void ImportTriangles(aiMesh* mesh) {
-         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;
-                 }
-             }
-         }
+    void ImportTriangles(aiMesh *mesh) {
+        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;
+                }
+            }
+        }
 
         mesh->mNumFaces = static_cast<unsigned int>(faces.size());
         mesh->mFaces = new aiFace[mesh->mNumFaces];
@@ -269,117 +269,115 @@ private:
 
     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 ) {
+        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 ) {
+                MatId2MatArray::const_iterator it(mMatId2MatArray.find(id));
+                if (mMatId2MatArray.end() == it) {
                     MatIdArray.clear();
-                    mMatId2MatArray[ id ] = MatIdArray;
+                    mMatId2MatArray[id] = MatIdArray;
                 } else {
                     MatIdArray = it->second;
                 }
             }
-            MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
-            mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
+            MatIdArray.push_back(static_cast<unsigned int>(newMatIdx));
+            mMatId2MatArray[mActiveMatGroup] = MatIdArray;
         }
 
-        while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
-            mMatArray.push_back( readMaterialDef() );
+        while (ReadToEndElement(D3MF::XmlTag::basematerials)) {
+            mMatArray.push_back(readMaterialDef());
         }
     }
 
-    bool parseColor( const char *color, aiColor4D &diffuse ) {
-        if ( nullptr == color ) {
+    bool parseColor(const char *color, aiColor4D &diffuse) {
+        if (nullptr == color) {
             return false;
         }
 
         //format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
-        const size_t len( strlen( color ) );
-        if ( 9 != len && 7 != len) {
+        const size_t len(strlen(color));
+        if (9 != len && 7 != len) {
             return false;
         }
 
-        const char *buf( color );
-        if ( '#' != *buf ) {
+        const char *buf(color);
+        if ('#' != *buf) {
             return false;
         }
         ++buf;
-        char comp[ 3 ] = { 0,0,'\0' };
+        char comp[3] = { 0, 0, '\0' };
 
-        comp[ 0 ] = *buf;
+        comp[0] = *buf;
         ++buf;
-        comp[ 1 ] = *buf;
+        comp[1] = *buf;
         ++buf;
-        diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
-
+        diffuse.r = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
 
-        comp[ 0 ] = *buf;
+        comp[0] = *buf;
         ++buf;
-        comp[ 1 ] = *buf;
+        comp[1] = *buf;
         ++buf;
-        diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
+        diffuse.g = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
 
-        comp[ 0 ] = *buf;
+        comp[0] = *buf;
         ++buf;
-        comp[ 1 ] = *buf;
+        comp[1] = *buf;
         ++buf;
-        diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
+        diffuse.b = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
 
-        if(7 == len)
+        if (7 == len)
             return true;
-        comp[ 0 ] = *buf;
+        comp[0] = *buf;
         ++buf;
-        comp[ 1 ] = *buf;
+        comp[1] = *buf;
         ++buf;
-        diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
+        diffuse.a = static_cast<ai_real>(strtol(comp, nullptr, 16)) / ai_real(255.0);
 
         return true;
     }
 
-    void assignDiffuseColor( aiMaterial *mat ) {
-        const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
+    void assignDiffuseColor(aiMaterial *mat) {
+        const char *color = xmlReader->getAttributeValue(D3MF::XmlTag::basematerials_displaycolor.c_str());
         aiColor4D diffuse;
-        if ( parseColor( color, diffuse ) ) {
-            mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
+        if (parseColor(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() );
+        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 ) );
+            std::string strId(to_string(mActiveMatGroup));
             stdMatName += "id";
             stdMatName += strId;
             stdMatName += "_";
-            if ( nullptr != name ) {
-                stdMatName += std::string( name );
+            if (nullptr != name) {
+                stdMatName += std::string(name);
             } else {
                 stdMatName += "basemat";
             }
-            matName.Set( stdMatName );
+            matName.Set(stdMatName);
 
             mat = new aiMaterial;
-            mat->AddProperty( &matName, AI_MATKEY_NAME );
+            mat->AddProperty(&matName, AI_MATKEY_NAME);
 
-            assignDiffuseColor( mat );
+            assignDiffuseColor(mat);
         }
 
         return mat;
     }
 
 private:
-    bool ReadToStartElement(const std::string& startTag) {
-        while(xmlReader->read()) {
-            const std::string &nodeName( xmlReader->getNodeName() );
+    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) {
@@ -390,9 +388,9 @@ private:
         return false;
     }
 
-    bool ReadToEndElement(const std::string& closeTag) {
-        while(xmlReader->read()) {
-            const std::string &nodeName( xmlReader->getNodeName() );
+    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) {
@@ -410,11 +408,11 @@ private:
         std::string value;
     };
     std::vector<MetaEntry> mMetaData;
-    std::vector<aiMesh*> mMeshes;
+    std::vector<aiMesh *> mMeshes;
     MatArray mMatArray;
     unsigned int mActiveMatGroup;
     MatId2MatArray mMatId2MatArray;
-    XmlReader* xmlReader;
+    XmlReader *xmlReader;
 };
 
 } //namespace D3MF
@@ -432,8 +430,8 @@ static const aiImporterDesc desc = {
     "3mf"
 };
 
-D3MFImporter::D3MFImporter()
-: BaseImporter() {
+D3MFImporter::D3MFImporter() :
+        BaseImporter() {
     // empty
 }
 
@@ -442,17 +440,17 @@ D3MFImporter::~D3MFImporter() {
 }
 
 bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
-    const std::string extension( GetExtension( filename ) );
-    if(extension == desc.mFileExtensions ) {
+    const std::string extension(GetExtension(filename));
+    if (extension == desc.mFileExtensions) {
         return true;
-    } else if ( !extension.length() || checkSig ) {
-        if ( nullptr == pIOHandler ) {
+    } else if (!extension.length() || checkSig) {
+        if (nullptr == pIOHandler) {
             return false;
         }
-        if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) {
+        if (!ZipArchiveIOSystem::isZipArchive(pIOHandler, filename)) {
             return false;
         }
-        D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
+        D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
         return opcPackage.validate();
     }
 
@@ -467,7 +465,7 @@ const aiImporterDesc *D3MFImporter::GetInfo() const {
     return &desc;
 }
 
-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);
 
     std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));

+ 0 - 0
code/3MF/D3MFImporter.h → code/AssetLib/3MF/D3MFImporter.h


+ 53 - 56
code/3MF/D3MFOpcPackage.cpp → code/AssetLib/3MF/D3MFOpcPackage.cpp

@@ -45,19 +45,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "D3MFOpcPackage.h"
 #include <assimp/Exceptional.h>
 
+#include <assimp/ZipArchiveIOSystem.h>
+#include <assimp/ai_assert.h>
+#include <assimp/DefaultLogger.hpp>
 #include <assimp/IOStream.hpp>
 #include <assimp/IOSystem.hpp>
-#include <assimp/DefaultLogger.hpp>
-#include <assimp/ai_assert.h>
-#include <assimp/ZipArchiveIOSystem.h>
 
+#include "3MFXmlTags.h"
+#include <algorithm>
+#include <cassert>
 #include <cstdlib>
+#include <map>
 #include <memory>
 #include <vector>
-#include <map>
-#include <algorithm>
-#include <cassert>
-#include "3MFXmlTags.h"
 
 namespace Assimp {
 
@@ -68,49 +68,45 @@ typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
 
 class OpcPackageRelationshipReader {
 public:
-    OpcPackageRelationshipReader(XmlReader* xmlReader) {        
-        while(xmlReader->read()) {
-            if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
-               xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER)
-            {
+    OpcPackageRelationshipReader(XmlReader *xmlReader) {
+        while (xmlReader->read()) {
+            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
+                    xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) {
                 ParseRootNode(xmlReader);
             }
         }
     }
 
-    void ParseRootNode(XmlReader* xmlReader)
-    {       
+    void ParseRootNode(XmlReader *xmlReader) {
         ParseAttributes(xmlReader);
 
-        while(xmlReader->read())
-        {
-            if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
-               xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE)
-            {
+        while (xmlReader->read()) {
+            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
+                    xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) {
                 ParseChildNode(xmlReader);
             }
         }
     }
 
-    void ParseAttributes(XmlReader*) {
+    void ParseAttributes(XmlReader *) {
         // empty
     }
 
-    bool validateRels( OpcPackageRelationshipPtr &relPtr ) {
-        if ( relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty() ) {
+    bool validateRels(OpcPackageRelationshipPtr &relPtr) {
+        if (relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty()) {
             return false;
         }
         return true;
     }
 
-    void ParseChildNode(XmlReader* xmlReader) {        
+    void ParseChildNode(XmlReader *xmlReader) {
         OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
 
         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 );
+        if (validateRels(relPtr)) {
+            m_relationShips.push_back(relPtr);
         }
     }
 
@@ -118,51 +114,52 @@ public:
 };
 
 // ------------------------------------------------------------------------------------------------
-D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
-: mRootStream(nullptr)
-, mZipArchive() {    
-    mZipArchive.reset( new ZipArchiveIOSystem( pIOHandler, rFile ) );
-    if(!mZipArchive->isOpen()) {
-        throw DeadlyImportError("Failed to open file " + rFile+ ".");
+D3MFOpcPackage::D3MFOpcPackage(IOSystem *pIOHandler, const std::string &rFile) :
+        mRootStream(nullptr), mZipArchive() {
+    mZipArchive.reset(new ZipArchiveIOSystem(pIOHandler, rFile));
+    if (!mZipArchive->isOpen()) {
+        throw DeadlyImportError("Failed to open file " + rFile + ".");
     }
 
     std::vector<std::string> fileList;
     mZipArchive->getFileList(fileList);
 
-    for (auto& file: fileList) {
-        if(file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) {
-            //PkgRelationshipReader pkgRelReader(file, archive);
-            ai_assert(mZipArchive->Exists(file.c_str()));
+    for (auto &file : fileList) {
+        if (file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) {
+            if (!mZipArchive->Exists(file.c_str())) {
+                continue;
+            }
 
             IOStream *fileStream = mZipArchive->Open(file.c_str());
-
-            ai_assert(fileStream != nullptr);
+            if (nullptr == fileStream) {
+                ai_assert(fileStream != nullptr);
+                continue;
+            }
 
             std::string rootFile = ReadPackageRootRelationship(fileStream);
-            if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) {
-                rootFile = rootFile.substr( 1 );
-                if ( rootFile[ 0 ] == '/' ) {
+            if (rootFile.size() > 0 && rootFile[0] == '/') {
+                rootFile = rootFile.substr(1);
+                if (rootFile[0] == '/') {
                     // deal with zip-bug
-                    rootFile = rootFile.substr( 1 );
+                    rootFile = rootFile.substr(1);
                 }
             }
 
-            ASSIMP_LOG_DEBUG(rootFile);
+            ASSIMP_LOG_VERBOSE_DEBUG(rootFile);
 
             mZipArchive->Close(fileStream);
 
             mRootStream = mZipArchive->Open(rootFile.c_str());
-            ai_assert( mRootStream != nullptr );
-            if ( nullptr == mRootStream ) {
-                throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile );
+            ai_assert(mRootStream != nullptr);
+            if (nullptr == mRootStream) {
+                throw DeadlyExportError("Cannot open root-file in archive : " + rootFile);
             }
 
-        } else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
-            ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file);
+        } else if (file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
+            ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES", file);
         } else {
-            ASSIMP_LOG_WARN_F("Ignored file of unknown type: ",file);
+            ASSIMP_LOG_WARN_F("Ignored file of unknown type: ", file);
         }
-
     }
 }
 
@@ -170,32 +167,32 @@ D3MFOpcPackage::~D3MFOpcPackage() {
     mZipArchive->Close(mRootStream);
 }
 
-IOStream* D3MFOpcPackage::RootStream() const {
+IOStream *D3MFOpcPackage::RootStream() const {
     return mRootStream;
 }
 
 static const std::string ModelRef = "3D/3dmodel.model";
 
 bool D3MFOpcPackage::validate() {
-    if ( nullptr == mRootStream || nullptr == mZipArchive ) {
+    if (nullptr == mRootStream || nullptr == mZipArchive) {
         return false;
     }
 
-    return mZipArchive->Exists( ModelRef.c_str() );
+    return mZipArchive->Exists(ModelRef.c_str());
 }
 
-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()));
 
     OpcPackageRelationshipReader reader(xml.get());
 
-    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;
     });
 
-    if ( itr == reader.m_relationShips.end() ) {
-        throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE );
+    if (itr == reader.m_relationShips.end()) {
+        throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
     }
 
     return (*itr)->target;

+ 0 - 0
code/3MF/D3MFOpcPackage.h → code/AssetLib/3MF/D3MFOpcPackage.h


+ 40 - 40
code/AC/ACLoader.cpp → code/AssetLib/AC/ACLoader.cpp

@@ -192,7 +192,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
     objects.push_back(Object());
     Object &obj = objects.back();
 
-    aiLight *light = NULL;
+    aiLight *light = nullptr;
     if (!ASSIMP_strincmp(buffer, "light", 5)) {
         // This is a light source. Add it to the list
         mLights->push_back(light = new aiLight());
@@ -207,7 +207,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
         light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i", static_cast<unsigned int>(mLights->size()) - 1);
         obj.name = std::string(light->mName.data);
 
-        ASSIMP_LOG_DEBUG("AC3D: Light source encountered");
+        ASSIMP_LOG_VERBOSE_DEBUG("AC3D: Light source encountered");
         obj.type = Object::Light;
     } else if (!ASSIMP_strincmp(buffer, "group", 5)) {
         obj.type = Object::Group;
@@ -294,7 +294,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object> &objects) {
                     // example writes no surf chunks
                     if (!Q3DWorkAround) {
                         ASSIMP_LOG_WARN("AC3D: SURF token was expected");
-                        ASSIMP_LOG_DEBUG("Continuing with Quick3D Workaround enabled");
+                        ASSIMP_LOG_VERBOSE_DEBUG("Continuing with Quick3D Workaround enabled");
                     }
                     --buffer; // make sure the line is processed a second time
                     // break; --- see fix notes above
@@ -472,29 +472,29 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
                 }
 
                 switch ((*it).flags & 0xf) {
-                        // closed line
-                    case 0x1:
-                        needMat[idx].first += (unsigned int)(*it).entries.size();
-                        needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
-                        break;
+                    // closed line
+                case 0x1:
+                    needMat[idx].first += (unsigned int)(*it).entries.size();
+                    needMat[idx].second += (unsigned int)(*it).entries.size() << 1u;
+                    break;
 
-                        // unclosed line
-                    case 0x2:
-                        needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
-                        needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
-                        break;
+                    // unclosed line
+                case 0x2:
+                    needMat[idx].first += (unsigned int)(*it).entries.size() - 1;
+                    needMat[idx].second += ((unsigned int)(*it).entries.size() - 1) << 1u;
+                    break;
 
-                        // 0 == polygon, else unknown
-                    default:
-                        if ((*it).flags & 0xf) {
-                            ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
-                            (*it).flags &= ~(0xf);
-                        }
+                    // 0 == polygon, else unknown
+                default:
+                    if ((*it).flags & 0xf) {
+                        ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
+                        (*it).flags &= ~(0xf);
+                    }
 
-                        // the number of faces increments by one, the number
-                        // of vertices by surface.numref.
-                        needMat[idx].first++;
-                        needMat[idx].second += (unsigned int)(*it).entries.size();
+                    // the number of faces increments by one, the number
+                    // of vertices by surface.numref.
+                    needMat[idx].first++;
+                    needMat[idx].second += (unsigned int)(*it).entries.size();
                 };
             }
             unsigned int *pip = node->mMeshes = new unsigned int[node->mNumMeshes];
@@ -535,7 +535,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
 
                 // allocate UV coordinates, but only if the texture name for the
                 // surface is not empty
-                aiVector3D *uv = NULL;
+                aiVector3D *uv = nullptr;
                 if (object.texture.length()) {
                     uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices];
                     mesh->mNumUVComponents[0] = 2;
@@ -627,7 +627,7 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
                     std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
                     ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: " + object.name);
 
-                    std::vector<aiMesh *> cpy(meshes.size() - oldm, NULL);
+                    std::vector<aiMesh *> cpy(meshes.size() - oldm, nullptr);
                     div->Subdivide(&meshes[oldm], cpy.size(), &cpy.front(), object.subDiv, true);
                     std::copy(cpy.begin(), cpy.end(), meshes.begin() + oldm);
 
@@ -644,20 +644,20 @@ aiNode *AC3DImporter::ConvertObjectSection(Object &object,
     else {
         // generate a name depending on the type of the node
         switch (object.type) {
-            case Object::Group:
-                node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++);
-                break;
-            case Object::Poly:
-                node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++);
-                break;
-            case Object::Light:
-                node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++);
-                break;
-
-                // there shouldn't be more than one world, but we don't care
-            case Object::World:
-                node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++);
-                break;
+        case Object::Group:
+            node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACGroup_%i", mGroupsCounter++);
+            break;
+        case Object::Poly:
+            node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACPoly_%i", mPolysCounter++);
+            break;
+        case Object::Light:
+            node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACLight_%i", mLightsCounter++);
+            break;
+
+            // there shouldn't be more than one world, but we don't care
+        case Object::World:
+            node->mName.length = ::ai_snprintf(node->mName.data, MAXLEN, "ACWorld_%i", mWorldsCounter++);
+            break;
         }
     }
 
@@ -696,7 +696,7 @@ void AC3DImporter::InternReadFile(const std::string &pFile,
     std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
 
     // Check whether we can read from the file
-    if ( file.get() == nullptr ) {
+    if (file.get() == nullptr) {
         throw DeadlyImportError("Failed to open AC3D file " + pFile + ".");
     }
 

+ 33 - 62
code/AC/ACLoader.h → code/AssetLib/AC/ACLoader.h

@@ -56,27 +56,20 @@ struct aiMesh;
 struct aiMaterial;
 struct aiLight;
 
-
-namespace Assimp    {
+namespace Assimp {
 
 // ---------------------------------------------------------------------------
 /** AC3D (*.ac) importer class
 */
-class AC3DImporter : public BaseImporter
-{
+class AC3DImporter : public BaseImporter {
 public:
     AC3DImporter();
     ~AC3DImporter();
 
     // Represents an AC3D material
-    struct Material
-    {
-        Material()
-            :   rgb     (0.6f,0.6f,0.6f)
-            ,   spec    (1.f,1.f,1.f)
-            ,   shin    (0.f)
-            ,   trans   (0.f)
-        {}
+    struct Material {
+        Material() :
+                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
         aiColor3D rgb;
@@ -101,43 +94,25 @@ public:
     };
 
     // Represents an AC3D surface
-    struct Surface
-    {
-        Surface()
-            :   mat     (0)
-            ,   flags   (0)
-        {}
+    struct Surface {
+        Surface() :
+                mat(0), flags(0) {}
 
-        unsigned int mat,flags;
+        unsigned int mat, flags;
 
-        typedef std::pair<unsigned int, aiVector2D > SurfaceEntry;
-        std::vector< SurfaceEntry > entries;
+        typedef std::pair<unsigned int, aiVector2D> SurfaceEntry;
+        std::vector<SurfaceEntry> entries;
     };
 
     // Represents an AC3D object
-    struct 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()
-        {}
+    struct 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 description
-        enum Type
-        {
+        enum Type {
             World = 0x0,
-            Poly  = 0x1,
+            Poly = 0x1,
             Group = 0x2,
             Light = 0x4
         } type;
@@ -177,37 +152,33 @@ public:
         float crease;
     };
 
-
 public:
-
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.
      * 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:
-
     // -------------------------------------------------------------------
     /** Return importer meta information.
      * See #BaseImporter::GetInfo for the details */
-    const aiImporterDesc* GetInfo () const;
+    const aiImporterDesc *GetInfo() const;
 
     // -------------------------------------------------------------------
     /** Imports the given file into the given scene structure.
      * 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);
 
     // -------------------------------------------------------------------
     /** Called prior to ReadFile().
     * The function is a request to the importer to update its configuration
     * basing on the Importer's configuration property list.*/
-    void SetupProperties(const Importer* pImp);
+    void SetupProperties(const Importer *pImp);
 
 private:
-
     // -------------------------------------------------------------------
     /** Get the next line from the file.
      *  @return false if the end of the file was reached*/
@@ -218,7 +189,7 @@ private:
      *  load subobjects, the method returns after a 'kids 0' was
      *  encountered.
      *  @objects List of output objects*/
-    void LoadObjectSection(std::vector<Object>& objects);
+    void LoadObjectSection(std::vector<Object> &objects);
 
     // -------------------------------------------------------------------
     /** Convert all objects into meshes and nodes.
@@ -227,24 +198,24 @@ private:
      *  @param outMaterials List of output materials
      *  @param materials Material list
      *  @param Scenegraph node for the object */
-    aiNode* ConvertObjectSection(Object& object,
-        std::vector<aiMesh*>& meshes,
-        std::vector<aiMaterial*>& outMaterials,
-        const std::vector<Material>& materials,
-        aiNode* parent = NULL);
+    aiNode *ConvertObjectSection(Object &object,
+            std::vector<aiMesh *> &meshes,
+            std::vector<aiMaterial *> &outMaterials,
+            const std::vector<Material> &materials,
+            aiNode *parent = nullptr);
 
     // -------------------------------------------------------------------
     /** Convert a material
      *  @param object Current object
      *  @param matSrc Source material description
      *  @param matDest Destination material to be filled */
-    void ConvertMaterial(const Object& object,
-        const Material& matSrc,
-        aiMaterial& matDest);
+    void ConvertMaterial(const Object &object,
+            const Material &matSrc,
+            aiMaterial &matDest);
 
 private:
     // points to the next data line
-    const char* buffer;
+    const char *buffer;
 
     // Configuration option: if enabled, up to two meshes
     // are generated per material: those faces who have
@@ -261,7 +232,7 @@ private:
     unsigned int mNumMeshes;
 
     // current list of light sources
-    std::vector<aiLight*>* mLights;
+    std::vector<aiLight *> *mLights;
 
     // name counters
     unsigned int mLightsCounter, mGroupsCounter, mPolysCounter, mWorldsCounter;

+ 674 - 0
code/AssetLib/AMF/AMFImporter.cpp

@@ -0,0 +1,674 @@
+/*
+---------------------------------------------------------------------------
+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/DefaultIOSystem.h>
+#include <assimp/fast_atof.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

+ 0 - 0
code/AMF/AMFImporter.hpp → code/AssetLib/AMF/AMFImporter.hpp


+ 1 - 1
code/AMF/AMFImporter_Geometry.cpp → code/AssetLib/AMF/AMFImporter_Geometry.cpp

@@ -1,4 +1,4 @@
-/*
+/*
 ---------------------------------------------------------------------------
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------

+ 1 - 1
code/AMF/AMFImporter_Macro.hpp → code/AssetLib/AMF/AMFImporter_Macro.hpp

@@ -1,4 +1,4 @@
-/*
+/*
 ---------------------------------------------------------------------------
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------

+ 1 - 1
code/AMF/AMFImporter_Material.cpp → code/AssetLib/AMF/AMFImporter_Material.cpp

@@ -1,4 +1,4 @@
-/*
+/*
 ---------------------------------------------------------------------------
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------

+ 1 - 1
code/AMF/AMFImporter_Node.hpp → code/AssetLib/AMF/AMFImporter_Node.hpp

@@ -1,4 +1,4 @@
-/*
+/*
 ---------------------------------------------------------------------------
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------

+ 872 - 0
code/AssetLib/AMF/AMFImporter_Postprocess.cpp

@@ -0,0 +1,872 @@
+/*
+---------------------------------------------------------------------------
+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_Postprocess.cpp
+/// \brief Convert built scenegraph and objects to Assimp scenegraph.
+/// \date 2016
+/// \author [email protected]
+
+#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
+
+#include "AMFImporter.hpp"
+
+// Header files, Assimp.
+#include <assimp/SceneCombiner.h>
+#include <assimp/StandardShapes.h>
+#include <assimp/StringUtils.h>
+
+// Header files, stdlib.
+#include <iterator>
+
+namespace Assimp {
+
+aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*pY*/, const float /*pZ*/) const {
+    aiColor4D tcol;
+
+    // Check if stored data are supported.
+    if (!Composition.empty()) {
+        throw DeadlyImportError("IME. GetColor for composition");
+    } else if (Color->Composed) {
+        throw DeadlyImportError("IME. GetColor, composed color");
+    } else {
+        tcol = Color->Color;
+    }
+
+    // Check if default color must be used
+    if ((tcol.r == 0) && (tcol.g == 0) && (tcol.b == 0) && (tcol.a == 0)) {
+        tcol.r = 0.5f;
+        tcol.g = 0.5f;
+        tcol.b = 0.5f;
+        tcol.a = 1;
+    }
+
+    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;
+    size_t col_idx;
+
+    // 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;
+    }
+
+    // If "vertices" not found then no work for us.
+    if (vn == nullptr) return;
+
+    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.
+    col_idx = 0;
+    // Inside vertices collect all data and place to arrays
+    for (CAMFImporter_NodeElement *vn_child : vn->Child) {
+        // vertices, colors
+        if (vn_child->Type == CAMFImporter_NodeElement::ENET_Vertex) {
+            // by default clear color for current vertex
+            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);
+
+                    continue;
+                }
+
+                if (vtx->Type == CAMFImporter_NodeElement::ENET_Color) {
+                    pVertexColorArray[col_idx] = (CAMFImporter_NodeElement_Color *)vtx;
+
+                    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)
+}
+
+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())
+        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;
+    for (const SPP_Texture &tex_convd : mTexture_Converted) {
+        if (tex_convd.ID == TextureConverted_ID) {
+            return TextureConverted_Index;
+        } else {
+            ++TextureConverted_Index;
+        }
+    }
+
+    //
+    // Converted texture not found, create it.
+    //
+    CAMFImporter_NodeElement_Texture *src_texture[4]{ nullptr };
+    std::vector<CAMFImporter_NodeElement_Texture *> src_texture_4check;
+    SPP_Texture converted_texture;
+
+    { // find all specified source textures
+        CAMFImporter_NodeElement *t_tex;
+
+        // R
+        if (!pID_R.empty()) {
+            if (!Find_NodeElement(pID_R, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_R);
+
+            src_texture[0] = (CAMFImporter_NodeElement_Texture *)t_tex;
+            src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
+        } else {
+            src_texture[0] = nullptr;
+        }
+
+        // G
+        if (!pID_G.empty()) {
+            if (!Find_NodeElement(pID_G, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_G);
+
+            src_texture[1] = (CAMFImporter_NodeElement_Texture *)t_tex;
+            src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
+        } else {
+            src_texture[1] = nullptr;
+        }
+
+        // B
+        if (!pID_B.empty()) {
+            if (!Find_NodeElement(pID_B, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_B);
+
+            src_texture[2] = (CAMFImporter_NodeElement_Texture *)t_tex;
+            src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
+        } else {
+            src_texture[2] = nullptr;
+        }
+
+        // A
+        if (!pID_A.empty()) {
+            if (!Find_NodeElement(pID_A, CAMFImporter_NodeElement::ENET_Texture, &t_tex)) Throw_ID_NotFound(pID_A);
+
+            src_texture[3] = (CAMFImporter_NodeElement_Texture *)t_tex;
+            src_texture_4check.push_back((CAMFImporter_NodeElement_Texture *)t_tex);
+        } else {
+            src_texture[3] = nullptr;
+        }
+    } // END: find all specified source textures
+
+    // check that all textures has same size
+    if (src_texture_4check.size() > 1) {
+        for (size_t i = 0, i_e = (src_texture_4check.size() - 1); i < i_e; i++) {
+            if ((src_texture_4check[i]->Width != src_texture_4check[i + 1]->Width) || (src_texture_4check[i]->Height != src_texture_4check[i + 1]->Height) ||
+                    (src_texture_4check[i]->Depth != src_texture_4check[i + 1]->Depth)) {
+                throw DeadlyImportError("PostprocessHelper_GetTextureID_Or_Create. Source texture must has the same size.");
+            }
+        }
+    } // if(src_texture_4check.size() > 1)
+
+    // set texture attributes
+    converted_texture.Width = src_texture_4check[0]->Width;
+    converted_texture.Height = src_texture_4check[0]->Height;
+    converted_texture.Depth = src_texture_4check[0]->Depth;
+    // if one of source texture is tiled then converted texture is tiled too.
+    converted_texture.Tiled = false;
+    for (uint8_t i = 0; i < src_texture_4check.size(); i++)
+        converted_texture.Tiled |= src_texture_4check[i]->Tiled;
+
+    // Create format hint.
+    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';
+
+    //
+    // Сopy data of textures.
+    //
+    size_t tex_size = 0;
+    size_t step = 0;
+    size_t off_g = 0;
+    size_t off_b = 0;
+
+    // Calculate size of the target array and rule how data will be copied.
+    if (!pID_R.empty() && nullptr != src_texture[0]) {
+        tex_size += src_texture[0]->Data.size();
+        step++, off_g++, off_b++;
+    }
+    if (!pID_G.empty() && nullptr != src_texture[1]) {
+        tex_size += src_texture[1]->Data.size();
+        step++, off_b++;
+    }
+    if (!pID_B.empty() && nullptr != src_texture[2]) {
+        tex_size += src_texture[2]->Data.size();
+        step++;
+    }
+    if (!pID_A.empty() && nullptr != src_texture[3]) {
+        tex_size += src_texture[3]->Data.size();
+        step++;
+    }
+
+    // Create target array.
+    converted_texture.Data = new uint8_t[tex_size];
+    // And copy data
+    auto CopyTextureData = [&](const std::string &pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void {
+        if (!pID.empty()) {
+            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];
+                ai_assert(tex);
+                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
+
+    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);
+
+    // Store new converted texture ID
+    converted_texture.ID = TextureConverted_ID;
+    // Store new converted texture
+    mTexture_Converted.push_back(converted_texture);
+
+    return TextureConverted_Index;
+}
+
+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 {
+        if ((pTexMap1 == nullptr) && (pTexMap2 == nullptr)) return true;
+        if (pTexMap1 == nullptr) return false;
+        if (pTexMap2 == nullptr) return false;
+
+        if (pTexMap1->TextureID_R != pTexMap2->TextureID_R) return false;
+        if (pTexMap1->TextureID_G != pTexMap2->TextureID_G) return false;
+        if (pTexMap1->TextureID_B != pTexMap2->TextureID_B) return false;
+        if (pTexMap1->TextureID_A != pTexMap2->TextureID_A) return false;
+
+        return true;
+    };
+
+    pOutputList_Separated.clear();
+    if (pInputList.empty()) return;
+
+    do {
+        SComplexFace face_start = pInputList.front();
+        std::list<SComplexFace> face_list_cur;
+
+        for (std::list<SComplexFace>::iterator it = pInputList.begin(), it_end = pInputList.end(); it != it_end;) {
+            if (texmap_is_equal(face_start.TexMap, it->TexMap)) {
+                auto it_old = it;
+
+                ++it;
+                face_list_cur.push_back(*it_old);
+                pInputList.erase(it_old);
+            } else {
+                ++it;
+            }
+        }
+
+        if (!face_list_cur.empty()) pOutputList_Separated.push_back(face_list_cur);
+
+    } 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.");
+
+        // 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())
+}
+
+void AMFImporter::Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object &pNodeElement, std::list<aiMesh *> &pMeshList, aiNode **pSceneNode) {
+    CAMFImporter_NodeElement_Color *object_color = nullptr;
+
+    // create new aiNode and set name as <object> has.
+    *pSceneNode = new aiNode;
+    (*pSceneNode)->mName = pNodeElement.ID;
+    // read mesh and color
+    for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
+        std::vector<aiVector3D> vertex_arr;
+        std::vector<CAMFImporter_NodeElement_Color *> color_arr;
+
+        // color for object
+        if (ne_child->Type == CAMFImporter_NodeElement::ENET_Color) object_color = (CAMFImporter_NodeElement_Color *)ne_child;
+
+        if (ne_child->Type == CAMFImporter_NodeElement::ENET_Mesh) {
+            // Create arrays from children of mesh: vertices.
+            PostprocessHelper_CreateMeshDataArray(*((CAMFImporter_NodeElement_Mesh *)ne_child), vertex_arr, color_arr);
+            // 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);
+        }
+    } // 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) {
+    std::list<unsigned int> mesh_idx;
+
+    // all data stored in "volume", search for it.
+    for (const CAMFImporter_NodeElement *ne_child : pNodeElement.Child) {
+        const CAMFImporter_NodeElement_Color *ne_volume_color = nullptr;
+        const SPP_Material *cur_mat = nullptr;
+
+        if (ne_child->Type == CAMFImporter_NodeElement::ENET_Volume) {
+            /******************* Get faces *******************/
+            const CAMFImporter_NodeElement_Volume *ne_volume = reinterpret_cast<const CAMFImporter_NodeElement_Volume *>(ne_child);
+
+            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.
+
+            // check if volume use material
+            if (!ne_volume->MaterialID.empty()) {
+                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
+            for (const CAMFImporter_NodeElement *ne_volume_child : ne_volume->Child) {
+                // 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
+                {
+                    const CAMFImporter_NodeElement_Triangle &tri_al = *reinterpret_cast<const CAMFImporter_NodeElement_Triangle *>(ne_volume_child);
+
+                    SComplexFace complex_face;
+
+                    // initialize pointers
+                    complex_face.Color = nullptr;
+                    complex_face.TexMap = nullptr;
+                    // get data from triangle children: color, texture coordinates.
+                    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);
+                        }
+                    } // if(tri_al.Child.size())
+
+                    // create new face and store it.
+                    complex_face.Face.mNumIndices = 3;
+                    complex_face.Face.mIndices = new unsigned int[3];
+                    complex_face.Face.mIndices[0] = static_cast<unsigned int>(tri_al.V[0]);
+                    complex_face.Face.mIndices[1] = static_cast<unsigned int>(tri_al.V[1]);
+                    complex_face.Face.mIndices[2] = static_cast<unsigned int>(tri_al.V[2]);
+                    complex_faces_list.push_back(complex_face);
+                }
+            } // for(const CAMFImporter_NodeElement* ne_volume_child: ne_volume->Child)
+
+            /**** Split faces list: one list per mesh ****/
+            PostprocessHelper_SplitFacesByTextureID(complex_faces_list, complex_faces_toplist);
+
+            /***** Create mesh for every faces list ******/
+            for (std::list<SComplexFace> &face_list_cur : complex_faces_toplist) {
+                auto VertexIndex_GetMinimal = [](const std::list<SComplexFace> &pFaceList, const size_t *pBiggerThan) -> size_t {
+                    size_t rv = 0;
+
+                    if (pBiggerThan != nullptr) {
+                        bool found = false;
+
+                        for (const SComplexFace &face : pFaceList) {
+                            for (size_t idx_vert = 0; idx_vert < face.Face.mNumIndices; idx_vert++) {
+                                if (face.Face.mIndices[idx_vert] > *pBiggerThan) {
+                                    rv = face.Face.mIndices[idx_vert];
+                                    found = true;
+
+                                    break;
+                                }
+                            }
+
+                            if (found) break;
+                        }
+
+                        if (!found) return *pBiggerThan;
+                    } else {
+                        rv = pFaceList.front().Face.mIndices[0];
+                    } // if(pBiggerThan != nullptr) else
+
+                    for (const SComplexFace &face : pFaceList) {
+                        for (size_t vi = 0; vi < face.Face.mNumIndices; vi++) {
+                            if (face.Face.mIndices[vi] < rv) {
+                                if (pBiggerThan != nullptr) {
+                                    if (face.Face.mIndices[vi] > *pBiggerThan) rv = face.Face.mIndices[vi];
+                                } else {
+                                    rv = face.Face.mIndices[vi];
+                                }
+                            }
+                        }
+                    } // for(const SComplexFace& face: pFaceList)
+
+                    return rv;
+                }; // auto VertexIndex_GetMinimal = [](const std::list<SComplexFace>& pFaceList, const size_t* pBiggerThan) -> size_t
+
+                auto VertexIndex_Replace = [](std::list<SComplexFace> &pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void {
+                    for (const SComplexFace &face : pFaceList) {
+                        for (size_t vi = 0; vi < face.Face.mNumIndices; vi++) {
+                            if (face.Face.mIndices[vi] == pIdx_From) face.Face.mIndices[vi] = static_cast<unsigned int>(pIdx_To);
+                        }
+                    }
+                }; // auto VertexIndex_Replace = [](std::list<SComplexFace>& pFaceList, const size_t pIdx_From, const size_t pIdx_To) -> void
+
+                auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D {
+                    // Color priorities(In descending order):
+                    // 1. triangle color;
+                    // 2. vertex color;
+                    // 3. volume color;
+                    // 4. object color;
+                    // 5. material;
+                    // 6. default - invisible coat.
+                    //
+                    // Fill vertices colors in color priority list above that's points from 1 to 6.
+                    if ((pIdx < pVertexColorArray.size()) && (pVertexColorArray[pIdx] != nullptr)) // check for vertex color
+                    {
+                        if (pVertexColorArray[pIdx]->Composed)
+                            throw DeadlyImportError("IME: vertex color composed");
+                        else
+                            return pVertexColorArray[pIdx]->Color;
+                    } else if (ne_volume_color != nullptr) // check for volume color
+                    {
+                        if (ne_volume_color->Composed)
+                            throw DeadlyImportError("IME: volume color composed");
+                        else
+                            return ne_volume_color->Color;
+                    } else if (pObjectColor != nullptr) // check for object color
+                    {
+                        if (pObjectColor->Composed)
+                            throw DeadlyImportError("IME: object color composed");
+                        else
+                            return pObjectColor->Color;
+                    } else if (cur_mat != nullptr) // check for material
+                    {
+                        return cur_mat->GetColor(pVertexCoordinateArray.at(pIdx).x, pVertexCoordinateArray.at(pIdx).y, pVertexCoordinateArray.at(pIdx).z);
+                    } else // set default color.
+                    {
+                        return { 0, 0, 0, 0 };
+                    } // if((vi < pVertexColorArray.size()) && (pVertexColorArray[vi] != nullptr)) else
+                }; // auto Vertex_CalculateColor = [&](const size_t pIdx) -> aiColor4D
+
+                aiMesh *tmesh = new aiMesh;
+
+                tmesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; // Only triangles is supported by AMF.
+                //
+                // set geometry and colors (vertices)
+                //
+                // copy faces/triangles
+                tmesh->mNumFaces = static_cast<unsigned int>(face_list_cur.size());
+                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
+                // 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.
+                size_t VertexCount_Max = tmesh->mNumFaces * 3; // 3 - triangles.
+                std::vector<aiVector3D> vert_arr, texcoord_arr;
+                std::vector<aiColor4D> col_arr;
+
+                vert_arr.reserve(VertexCount_Max * 2); // "* 2" - see below TODO.
+                col_arr.reserve(VertexCount_Max * 2);
+
+                { // fill arrays
+                    size_t vert_idx_from, vert_idx_to;
+
+                    // first iteration.
+                    vert_idx_to = 0;
+                    vert_idx_from = VertexIndex_GetMinimal(face_list_cur, nullptr);
+                    vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from));
+                    col_arr.push_back(Vertex_CalculateColor(vert_idx_from));
+                    if (vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to);
+
+                    // rest iterations
+                    do {
+                        vert_idx_from = VertexIndex_GetMinimal(face_list_cur, &vert_idx_to);
+                        if (vert_idx_from == vert_idx_to) break; // all indices are transferred,
+
+                        vert_arr.push_back(pVertexCoordinateArray.at(vert_idx_from));
+                        col_arr.push_back(Vertex_CalculateColor(vert_idx_from));
+                        vert_idx_to++;
+                        if (vert_idx_from != vert_idx_to) VertexIndex_Replace(face_list_cur, vert_idx_from, vert_idx_to);
+
+                    } while (true);
+                } // fill arrays. END.
+
+                //
+                // check if triangle colors are used and create additional faces if needed.
+                //
+                for (const SComplexFace &face_cur : face_list_cur) {
+                    if (face_cur.Color != nullptr) {
+                        aiColor4D face_color;
+                        size_t vert_idx_new = vert_arr.size();
+
+                        if (face_cur.Color->Composed)
+                            throw DeadlyImportError("IME: face color composed");
+                        else
+                            face_color = face_cur.Color->Color;
+
+                        for (size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) {
+                            vert_arr.push_back(vert_arr.at(face_cur.Face.mIndices[idx_ind]));
+                            col_arr.push_back(face_color);
+                            face_cur.Face.mIndices[idx_ind] = static_cast<unsigned int>(vert_idx_new++);
+                        }
+                    } // if(face_cur.Color != nullptr)
+                } // for(const SComplexFace& face_cur: face_list_cur)
+
+                //
+                // if texture is used then copy texture coordinates too.
+                //
+                if (face_list_cur.front().TexMap != nullptr) {
+                    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
+                    /// colored triangles and initial vertices (for colored vertices) which in real became unused. This part need more thinking about
+                    /// optimisation.
+                    bool *idx_vert_used;
+
+                    idx_vert_used = new bool[VertexCount_Max * 2];
+                    for (size_t i = 0, i_e = VertexCount_Max * 2; i < i_e; i++)
+                        idx_vert_used[i] = false;
+
+                    // This ID's will be used when set materials ID in scene.
+                    tmesh->mMaterialIndex = static_cast<unsigned int>(PostprocessHelper_GetTextureID_Or_Create(face_list_cur.front().TexMap->TextureID_R,
+                            face_list_cur.front().TexMap->TextureID_G,
+                            face_list_cur.front().TexMap->TextureID_B,
+                            face_list_cur.front().TexMap->TextureID_A));
+                    texcoord_arr.resize(VertexCount_Max * 2);
+                    for (const SComplexFace &face_cur : face_list_cur) {
+                        for (size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++) {
+                            const size_t idx_vert = face_cur.Face.mIndices[idx_ind];
+
+                            if (!idx_vert_used[idx_vert]) {
+                                texcoord_arr.at(idx_vert) = face_cur.TexMap->TextureCoordinate[idx_ind];
+                                idx_vert_used[idx_vert] = true;
+                            } else if (texcoord_arr.at(idx_vert) != face_cur.TexMap->TextureCoordinate[idx_ind]) {
+                                // in that case one vertex is shared with many texture coordinates. We need to duplicate vertex with another texture
+                                // coordinates.
+                                vert_arr.push_back(vert_arr.at(idx_vert));
+                                col_arr.push_back(col_arr.at(idx_vert));
+                                texcoord_arr.at(idx_vert_new) = face_cur.TexMap->TextureCoordinate[idx_ind];
+                                face_cur.Face.mIndices[idx_ind] = static_cast<unsigned int>(idx_vert_new++);
+                            }
+                        } // for(size_t idx_ind = 0; idx_ind < face_cur.Face.mNumIndices; idx_ind++)
+                    } // for(const SComplexFace& face_cur: face_list_cur)
+
+                    delete[] idx_vert_used;
+                    // shrink array
+                    texcoord_arr.resize(idx_vert_new);
+                } // if(face_list_cur.front().TexMap != nullptr)
+
+                //
+                // copy collected data to mesh
+                //
+                tmesh->mNumVertices = static_cast<unsigned int>(vert_arr.size());
+                tmesh->mVertices = new aiVector3D[tmesh->mNumVertices];
+                tmesh->mColors[0] = new aiColor4D[tmesh->mNumVertices];
+
+                memcpy(tmesh->mVertices, vert_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D));
+                memcpy(tmesh->mColors[0], col_arr.data(), tmesh->mNumVertices * sizeof(aiColor4D));
+                if (texcoord_arr.size() > 0) {
+                    tmesh->mTextureCoords[0] = new aiVector3D[tmesh->mNumVertices];
+                    memcpy(tmesh->mTextureCoords[0], texcoord_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D));
+                    tmesh->mNumUVComponents[0] = 2; // U and V stored in "x", "y" of aiVector3D.
+                }
+
+                size_t idx_face = 0;
+                for (const SComplexFace &face_cur : face_list_cur)
+                    tmesh->mFaces[idx_face++] = face_cur.Face;
+
+                // store new aiMesh
+                mesh_idx.push_back(static_cast<unsigned int>(pMeshList.size()));
+                pMeshList.push_back(tmesh);
+            } // for(const std::list<SComplexFace>& face_list_cur: complex_faces_toplist)
+        } // if(ne_child->Type == CAMFImporter_NodeElement::ENET_Volume)
+    } // for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
+
+    // if meshes was created then assign new indices with current aiNode
+    if (!mesh_idx.empty()) {
+        std::list<unsigned int>::const_iterator mit = mesh_idx.begin();
+
+        pSceneNode.mNumMeshes = static_cast<unsigned int>(mesh_idx.size());
+        pSceneNode.mMeshes = new unsigned int[pSceneNode.mNumMeshes];
+        for (size_t i = 0; i < pSceneNode.mNumMeshes; i++)
+            pSceneNode.mMeshes[i] = *mit++;
+    } // if(mesh_idx.size() > 0)
+}
+
+void AMFImporter::Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material &pMaterial) {
+    SPP_Material new_mat;
+
+    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 CAMFImporter_NodeElement* mat_child; pMaterial.Child)
+
+    // place converted material to special list
+    mMaterial_Converted.push_back(new_mat);
+}
+
+void AMFImporter::Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation &pConstellation, std::list<aiNode *> &pNodeList) const {
+    aiNode *con_node;
+    std::list<aiNode *> ch_node;
+
+    // We will build next hierarchy:
+    // aiNode as parent (<constellation>) for set of nodes as a children
+    //  |- aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
+    //  ...
+    //  \_ aiNode for transformation (<instance> -> <delta...>, <r...>) - aiNode for pointing to object ("objectid")
+    con_node = new aiNode;
+    con_node->mName = pConstellation.ID;
+    // Walk through children and search for instances of another objects, constellations.
+    for (const CAMFImporter_NodeElement *ne : pConstellation.Child) {
+        aiMatrix4x4 tmat;
+        aiNode *t_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>.");
+
+        // create alias for conveniance
+        CAMFImporter_NodeElement_Instance &als = *((CAMFImporter_NodeElement_Instance *)ne);
+        // find referenced object
+        if (!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID);
+
+        // create node for applying transformation
+        t_node = new aiNode;
+        t_node->mParent = con_node;
+        // apply transformation
+        aiMatrix4x4::Translation(als.Delta, tmat), t_node->mTransformation *= tmat;
+        aiMatrix4x4::RotationX(als.Rotation.x, tmat), t_node->mTransformation *= tmat;
+        aiMatrix4x4::RotationY(als.Rotation.y, tmat), t_node->mTransformation *= tmat;
+        aiMatrix4x4::RotationZ(als.Rotation.z, tmat), t_node->mTransformation *= tmat;
+        // create array for one child node
+        t_node->mNumChildren = 1;
+        t_node->mChildren = new aiNode *[t_node->mNumChildren];
+        SceneCombiner::Copy(&t_node->mChildren[0], found_node);
+        t_node->mChildren[0]->mParent = t_node;
+        ch_node.push_back(t_node);
+    } // for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
+
+    // copy found aiNode's as children
+    if (ch_node.empty()) throw DeadlyImportError("<constellation> must have at least one <instance>.");
+
+    size_t ch_idx = 0;
+
+    con_node->mNumChildren = static_cast<unsigned int>(ch_node.size());
+    con_node->mChildren = new aiNode *[con_node->mNumChildren];
+    for (aiNode *node : ch_node)
+        con_node->mChildren[ch_idx++] = node;
+
+    // and place "root" of <constellation> node to node list
+    pNodeList.push_back(con_node);
+}
+
+void AMFImporter::Postprocess_BuildScene(aiScene *pScene) {
+    std::list<aiNode *> node_list;
+    std::list<aiMesh *> mesh_list;
+    std::list<CAMFImporter_NodeElement_Metadata *> meta_list;
+
+    //
+    // Because for AMF "material" is just complex colors mixing so aiMaterial will not be used.
+    // For building aiScene we are must to do few steps:
+    // at first creating root node for aiScene.
+    pScene->mRootNode = new aiNode;
+    pScene->mRootNode->mParent = nullptr;
+    pScene->mFlags |= AI_SCENE_FLAGS_ALLOW_SHARED;
+    // search for root(<amf>) element
+    CAMFImporter_NodeElement *root_el = nullptr;
+
+    for (CAMFImporter_NodeElement *ne : mNodeElement_List) {
+        if (ne->Type != CAMFImporter_NodeElement::ENET_Root) continue;
+
+        root_el = ne;
+
+        break;
+    } // for(const CAMFImporter_NodeElement* ne: mNodeElement_List)
+
+    // Check if root element are 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>,
+    // <constellation> and <metadata>. But at first we must read <material> and <texture> because they will be used in <object>. <metadata> can be read
+    // at any moment.
+    //
+    // 1. <material>
+    // 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));
+    }
+
+    // After "appearance" nodes we must read <object> because it will be used in <constellation> -> <instance>.
+    //
+    // 3. <object>
+    for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
+        if (root_child->Type == CAMFImporter_NodeElement::ENET_Object) {
+            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>
+            Postprocess_BuildNodeAndObject(*((CAMFImporter_NodeElement_Object *)root_child), mesh_list, &tnode);
+            if (tnode != nullptr) node_list.push_back(tnode);
+        }
+    } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
+
+    // And finally read rest of nodes.
+    //
+    for (const CAMFImporter_NodeElement *root_child : root_el->Child) {
+        // 4. <constellation>
+        if (root_child->Type == CAMFImporter_NodeElement::ENET_Constellation) {
+            // <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);
+        }
+
+        // 5, <metadata>
+        if (root_child->Type == CAMFImporter_NodeElement::ENET_Metadata) meta_list.push_back((CAMFImporter_NodeElement_Metadata *)root_child);
+    } // for(const CAMFImporter_NodeElement* root_child: root_el->Child)
+
+    // at now we can add collected metadata to root node
+    Postprocess_AddMetadata(meta_list, *pScene->mRootNode);
+    //
+    // Check constellation children
+    //
+    // As said in specification:
+    // "When multiple objects and constellations are defined in a single file, only the top level objects and constellations are available for printing."
+    // What that means? For example: if some object is used in constellation then you must show only constellation but not original object.
+    // And at this step we are checking that relations.
+nl_clean_loop:
+
+    if (node_list.size() > 1) {
+        // walk through all nodes
+        for (std::list<aiNode *>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it) {
+            // and try to find them in another top nodes.
+            std::list<aiNode *>::const_iterator next_it = nl_it;
+
+            ++next_it;
+            for (; next_it != node_list.end(); ++next_it) {
+                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.
+                    node_list.erase(nl_it);
+
+                    goto nl_clean_loop;
+                }
+            } // for(; next_it != node_list.end(); next_it++)
+        } // for(std::list<aiNode*>::const_iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++)
+    }
+
+    //
+    // move created objects to aiScene
+    //
+    //
+    // Nodes
+    if (!node_list.empty()) {
+        std::list<aiNode *>::const_iterator nl_it = node_list.begin();
+
+        pScene->mRootNode->mNumChildren = static_cast<unsigned int>(node_list.size());
+        pScene->mRootNode->mChildren = new aiNode *[pScene->mRootNode->mNumChildren];
+        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
+            // mRootNode only as parent.
+            (*nl_it)->mParent = pScene->mRootNode;
+            pScene->mRootNode->mChildren[i] = *nl_it++;
+        }
+    } // if(node_list.size() > 0)
+
+    //
+    // Meshes
+    if (!mesh_list.empty()) {
+        std::list<aiMesh *>::const_iterator ml_it = mesh_list.begin();
+
+        pScene->mNumMeshes = static_cast<unsigned int>(mesh_list.size());
+        pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
+        for (size_t i = 0; i < pScene->mNumMeshes; i++)
+            pScene->mMeshes[i] = *ml_it++;
+    } // if(mesh_list.size() > 0)
+
+    //
+    // Textures
+    pScene->mNumTextures = static_cast<unsigned int>(mTexture_Converted.size());
+    if (pScene->mNumTextures > 0) {
+        size_t idx;
+
+        idx = 0;
+        pScene->mTextures = new aiTexture *[pScene->mNumTextures];
+        for (const SPP_Texture &tex_convd : mTexture_Converted) {
+            pScene->mTextures[idx] = new aiTexture;
+            pScene->mTextures[idx]->mWidth = static_cast<unsigned int>(tex_convd.Width);
+            pScene->mTextures[idx]->mHeight = static_cast<unsigned int>(tex_convd.Height);
+            pScene->mTextures[idx]->pcData = (aiTexel *)tex_convd.Data;
+            // texture format description.
+            strcpy(pScene->mTextures[idx]->achFormatHint, tex_convd.FormatHint);
+            idx++;
+        } // for(const SPP_Texture& tex_convd: mTexture_Converted)
+
+        // Create materials for embedded textures.
+        idx = 0;
+        pScene->mNumMaterials = static_cast<unsigned int>(mTexture_Converted.size());
+        pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials];
+        for (const SPP_Texture &tex_convd : mTexture_Converted) {
+            const aiString texture_id(AI_EMBEDDED_TEXNAME_PREFIX + to_string(idx));
+            const int mode = aiTextureOp_Multiply;
+            const int repeat = tex_convd.Tiled ? 1 : 0;
+
+            pScene->mMaterials[idx] = new aiMaterial;
+            pScene->mMaterials[idx]->AddProperty(&texture_id, AI_MATKEY_TEXTURE_DIFFUSE(0));
+            pScene->mMaterials[idx]->AddProperty(&mode, 1, AI_MATKEY_TEXOP_DIFFUSE(0));
+            pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_U_DIFFUSE(0));
+            pScene->mMaterials[idx]->AddProperty(&repeat, 1, AI_MATKEY_MAPPINGMODE_V_DIFFUSE(0));
+            idx++;
+        }
+    } // if(pScene->mNumTextures > 0)
+} // END: after that walk through children of root and collect data
+
+} // namespace Assimp
+
+#endif // !ASSIMP_BUILD_NO_AMF_IMPORTER

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 271 - 285
code/AssetLib/ASE/ASELoader.cpp


+ 0 - 0
code/ASE/ASELoader.h → code/AssetLib/ASE/ASELoader.h


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 242 - 371
code/AssetLib/ASE/ASEParser.cpp


+ 95 - 123
code/ASE/ASEParser.h → code/AssetLib/ASE/ASEParser.h

@@ -40,15 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
-
 /** @file Defines the helper data structures for importing ASE files  */
 #ifndef AI_ASEFILEHELPER_H_INC
 #define AI_ASEFILEHELPER_H_INC
 
 // public ASSIMP headers
-#include <assimp/types.h>
-#include <assimp/mesh.h>
 #include <assimp/anim.h>
+#include <assimp/mesh.h>
+#include <assimp/types.h>
 
 #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
 
@@ -57,29 +56,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/qnan.h>
 
 // ASE is quite similar to 3ds. We can reuse some structures
-#include "3DS/3DSLoader.h"
+#include "AssetLib/3DS/3DSLoader.h"
 
-namespace Assimp    {
-namespace ASE   {
+namespace Assimp {
+namespace ASE {
 
 using namespace D3DS;
 
 // ---------------------------------------------------------------------------
 /** Helper structure representing an ASE material */
-struct Material : public D3DS::Material
-{
+struct Material : public D3DS::Material {
     //! Default constructor has been deleted
     Material() = delete;
 
     //! Constructor with explicit name
-    explicit Material(const std::string &name)
-    : D3DS::Material(name)
-    , pcInstance(NULL)
-    , bNeed (false) {
+    explicit Material(const std::string &name) :
+            D3DS::Material(name),
+            pcInstance(nullptr),
+            bNeed(false) {
         // empty
     }
 
-    Material(const Material &other)            = default;
+    Material(const Material &other) = default;
 
     Material &operator=(const Material &other) {
         if (this == &other) {
@@ -93,19 +91,16 @@ struct Material : public D3DS::Material
         return *this;
     }
 
-
     //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
     Material(Material &&other) AI_NO_EXCEPT
-    : D3DS::Material(std::move(other))
-    , avSubMaterials(std::move(other.avSubMaterials))
-    , pcInstance(std::move(other.pcInstance))
-    , bNeed(std::move(other.bNeed))
-    {
+            : D3DS::Material(std::move(other)),
+              avSubMaterials(std::move(other.avSubMaterials)),
+              pcInstance(std::move(other.pcInstance)),
+              bNeed(std::move(other.bNeed)) {
         other.pcInstance = nullptr;
     }
 
-
-    Material &operator=( Material &&other) AI_NO_EXCEPT {
+    Material &operator=(Material &&other) AI_NO_EXCEPT {
         if (this == &other) {
             return *this;
         }
@@ -121,15 +116,13 @@ struct Material : public D3DS::Material
         return *this;
     }
 
-
     ~Material() {}
 
-
     //! Contains all sub materials of this material
     std::vector<Material> avSubMaterials;
 
     //! aiMaterial object
-    aiMaterial* pcInstance;
+    aiMaterial *pcInstance;
 
     //! Can we remove this material?
     bool bNeed;
@@ -140,8 +133,8 @@ struct Material : public D3DS::Material
 struct Face : public FaceWithSmoothingGroup {
     //! Default constructor. Initializes everything with 0
     Face() AI_NO_EXCEPT
-    : iMaterial(DEFAULT_MATINDEX)
-    , iFace(0) {
+            : iMaterial(DEFAULT_MATINDEX),
+              iFace(0) {
         // empty
     }
 
@@ -172,8 +165,8 @@ struct Bone {
     Bone() = delete;
 
     //! Construction from an existing name
-    explicit Bone( const std::string& name)
-    : mName(name) {
+    explicit Bone(const std::string &name) :
+            mName(name) {
         // empty
     }
 
@@ -186,33 +179,34 @@ struct Bone {
 struct BoneVertex {
     //! Bone and corresponding vertex weight.
     //! -1 for unrequired bones ....
-    std::vector<std::pair<int,float> > mBoneWeights;
+    std::vector<std::pair<int, float>> mBoneWeights;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file animation */
 struct Animation {
     enum Type {
-        TRACK   = 0x0,
-        BEZIER  = 0x1,
-        TCB     = 0x2
-    } mRotationType, mScalingType, mPositionType;
+        TRACK = 0x0,
+        BEZIER = 0x1,
+        TCB = 0x2
+    } mRotationType,
+            mScalingType, mPositionType;
 
     Animation() AI_NO_EXCEPT
-    :   mRotationType   (TRACK)
-    ,   mScalingType    (TRACK)
-    ,   mPositionType   (TRACK) {
+            : mRotationType(TRACK),
+              mScalingType(TRACK),
+              mPositionType(TRACK) {
         // empty
     }
 
     //! List of track rotation keyframes
-    std::vector< aiQuatKey > akeyRotations;
+    std::vector<aiQuatKey> akeyRotations;
 
     //! List of track position keyframes
-    std::vector< aiVectorKey > akeyPositions;
+    std::vector<aiVectorKey> akeyPositions;
 
     //! List of track scaling keyframes
-    std::vector< aiVectorKey > akeyScaling;
+    std::vector<aiVectorKey> akeyScaling;
 };
 
 // ---------------------------------------------------------------------------
@@ -220,7 +214,7 @@ struct Animation {
 struct InheritanceInfo {
     //! Default constructor
     InheritanceInfo() AI_NO_EXCEPT {
-        for ( size_t i=0; i<3; ++i ) {
+        for (size_t i = 0; i < 3; ++i) {
             abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true;
         }
     }
@@ -239,17 +233,15 @@ struct InheritanceInfo {
 /** Represents an ASE file node. Base class for mesh, light and cameras */
 struct BaseNode {
     enum Type {
-        Light, 
-        Camera, 
-        Mesh, 
+        Light,
+        Camera,
+        Mesh,
         Dummy
     } mType;
 
     //! Construction from an existing name
-    BaseNode(Type _mType, const std::string &name)
-    : mType         (_mType)
-    , mName         (name)
-    , mProcessed    (false) {
+    BaseNode(Type _mType, const std::string &name) :
+            mType(_mType), mName(name), mProcessed(false) {
         // Set mTargetPosition to qnan
         const ai_real qnan = get_qnan();
         mTargetPosition.x = qnan;
@@ -289,14 +281,9 @@ struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode {
     Mesh() = delete;
 
     //! Construction from an existing name
-    explicit Mesh(const std::string &name)
-    : BaseNode( BaseNode::Mesh, name )
-    , mVertexColors()
-    , mBoneVertices()
-    , mBones()
-    , iMaterialIndex(Face::DEFAULT_MATINDEX)
-    , bSkip     (false) {
-        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
+    explicit Mesh(const std::string &name) :
+            BaseNode(BaseNode::Mesh, name), mVertexColors(), mBoneVertices(), mBones(), iMaterialIndex(Face::DEFAULT_MATINDEX), bSkip(false) {
+        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c) {
             this->mNumUVComponents[c] = 2;
         }
     }
@@ -325,10 +312,8 @@ struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode {
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE light source */
-struct Light : public BaseNode
-{
-    enum LightType
-    {
+struct Light : public BaseNode {
+    enum LightType {
         OMNI,
         TARGET,
         FREE,
@@ -339,17 +324,13 @@ struct Light : public BaseNode
     Light() = delete;
 
     //! Construction from an existing name
-    explicit Light(const std::string &name)
-    : BaseNode   (BaseNode::Light, name)
-    , mLightType (OMNI)
-    , mColor     (1.f,1.f,1.f)
-    , mIntensity (1.f) // light is white by default
-    , mAngle     (45.f)
-    , mFalloff   (0.f)
-    {
+    explicit Light(const std::string &name) :
+            BaseNode(BaseNode::Light, name), mLightType(OMNI), mColor(1.f, 1.f, 1.f), mIntensity(1.f) // light is white by default
+            ,
+            mAngle(45.f),
+            mFalloff(0.f) {
     }
 
-
     LightType mLightType;
     aiColor3D mColor;
     ai_real mIntensity;
@@ -359,10 +340,8 @@ struct Light : public BaseNode
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE camera */
-struct Camera : public BaseNode
-{
-    enum CameraType
-    {
+struct Camera : public BaseNode {
+    enum CameraType {
         FREE,
         TARGET
     };
@@ -370,18 +349,16 @@ struct Camera : public BaseNode
     //! Default constructor has been deleted
     Camera() = delete;
 
-
     //! Construction from an existing name
-    explicit Camera(const std::string &name)
-    : BaseNode    (BaseNode::Camera, name)
-    , mFOV        (0.75f)   // in radians
-    , mNear       (0.1f)
-    , mFar        (1000.f)  // could be zero
-    , mCameraType (FREE)
-    {
+    explicit Camera(const std::string &name) :
+            BaseNode(BaseNode::Camera, name), mFOV(0.75f) // in radians
+            ,
+            mNear(0.1f),
+            mFar(1000.f) // could be zero
+            ,
+            mCameraType(FREE) {
     }
 
-
     ai_real mFOV, mNear, mFar;
     CameraType mCameraType;
 };
@@ -391,7 +368,7 @@ struct Camera : public BaseNode
 struct Dummy : public BaseNode {
     //! Constructor
     Dummy() AI_NO_EXCEPT
-    : BaseNode  (BaseNode::Dummy, "DUMMY") {
+            : BaseNode(BaseNode::Dummy, "DUMMY") {
         // empty
     }
 };
@@ -414,7 +391,6 @@ private:
     }
 
 public:
-
     // -------------------------------------------------------------------
     //! Construct a parser from a given input file which is
     //! guaranteed to be terminated with zero.
@@ -422,15 +398,13 @@ public:
     //! @param fileFormatDefault Assumed file format version. If the
     //!   file format is specified in the file the new value replaces
     //!   the default value.
-    Parser (const char* szFile, unsigned int fileFormatDefault);
+    Parser(const char *szFile, unsigned int fileFormatDefault);
 
     // -------------------------------------------------------------------
     //! Parses the file into the parsers internal representation
     void Parse();
 
-
 private:
-
     // -------------------------------------------------------------------
     //! Parse the *SCENE block in a file
     void ParseLV1SceneBlock();
@@ -446,45 +420,45 @@ private:
     // -------------------------------------------------------------------
     //! Parse a *<xxx>OBJECT block in a file
     //! \param mesh Node to be filled
-    void ParseLV1ObjectBlock(BaseNode& mesh);
+    void ParseLV1ObjectBlock(BaseNode &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *MATERIAL blocks in a material list
     //! \param mat Material structure to be filled
-    void ParseLV2MaterialBlock(Material& mat);
+    void ParseLV2MaterialBlock(Material &mat);
 
     // -------------------------------------------------------------------
     //! Parse a *NODE_TM block in a file
     //! \param mesh Node (!) object to be filled
-    void ParseLV2NodeTransformBlock(BaseNode& mesh);
+    void ParseLV2NodeTransformBlock(BaseNode &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *TM_ANIMATION block in a file
     //! \param mesh Mesh object to be filled
-    void ParseLV2AnimationBlock(BaseNode& mesh);
-    void ParseLV3PosAnimationBlock(ASE::Animation& anim);
-    void ParseLV3ScaleAnimationBlock(ASE::Animation& anim);
-    void ParseLV3RotAnimationBlock(ASE::Animation& anim);
+    void ParseLV2AnimationBlock(BaseNode &mesh);
+    void ParseLV3PosAnimationBlock(ASE::Animation &anim);
+    void ParseLV3ScaleAnimationBlock(ASE::Animation &anim);
+    void ParseLV3RotAnimationBlock(ASE::Animation &anim);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH block in a file
     //! \param mesh Mesh object to be filled
-    void ParseLV2MeshBlock(Mesh& mesh);
+    void ParseLV2MeshBlock(Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *LIGHT_SETTINGS block in a file
     //! \param light Light object to be filled
-    void ParseLV2LightSettingsBlock(Light& light);
+    void ParseLV2LightSettingsBlock(Light &light);
 
     // -------------------------------------------------------------------
     //! Parse a *CAMERA_SETTINGS block in a file
     //! \param cam Camera object to be filled
-    void ParseLV2CameraSettingsBlock(Camera& cam);
+    void ParseLV2CameraSettingsBlock(Camera &cam);
 
     // -------------------------------------------------------------------
     //! Parse the *MAP_XXXXXX blocks in a material
     //! \param map Texture structure to be filled
-    void ParseLV3MapBlock(Texture& map);
+    void ParseLV3MapBlock(Texture &map);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_VERTEX_LIST block in a file
@@ -493,7 +467,7 @@ private:
     //! A warning is sent to the logger if the validations fails.
     //! \param mesh Mesh object to be filled
     void ParseLV3MeshVertexListBlock(
-        unsigned int iNumVertices,Mesh& mesh);
+            unsigned int iNumVertices, Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_FACE_LIST block in a file
@@ -502,7 +476,7 @@ private:
     //! A warning is sent to the logger if the validations fails.
     //! \param mesh Mesh object to be filled
     void ParseLV3MeshFaceListBlock(
-        unsigned int iNumFaces,Mesh& mesh);
+            unsigned int iNumFaces, Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_TVERT_LIST block in a file
@@ -512,7 +486,7 @@ private:
     //! \param mesh Mesh object to be filled
     //! \param iChannel Output UVW channel
     void ParseLV3MeshTListBlock(
-        unsigned int iNumVertices,Mesh& mesh, unsigned int iChannel = 0);
+            unsigned int iNumVertices, Mesh &mesh, unsigned int iChannel = 0);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_TFACELIST block in a file
@@ -522,7 +496,7 @@ private:
     //! \param mesh Mesh object to be filled
     //! \param iChannel Output UVW channel
     void ParseLV3MeshTFaceListBlock(
-        unsigned int iNumFaces,Mesh& mesh, unsigned int iChannel = 0);
+            unsigned int iNumFaces, Mesh &mesh, unsigned int iChannel = 0);
 
     // -------------------------------------------------------------------
     //! Parse an additional mapping channel
@@ -530,7 +504,7 @@ private:
     //! \param iChannel Channel index to be filled
     //! \param mesh Mesh object to be filled
     void ParseLV3MappingChannel(
-        unsigned int iChannel, Mesh& mesh);
+            unsigned int iChannel, Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_CVERTLIST block in a file
@@ -539,7 +513,7 @@ private:
     //! A warning is sent to the logger if the validations fails.
     //! \param mesh Mesh object to be filled
     void ParseLV3MeshCListBlock(
-        unsigned int iNumVertices, Mesh& mesh);
+            unsigned int iNumVertices, Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_CFACELIST block in a file
@@ -548,70 +522,70 @@ private:
     //! A warning is sent to the logger if the validations fails.
     //! \param mesh Mesh object to be filled
     void ParseLV3MeshCFaceListBlock(
-        unsigned int iNumFaces, Mesh& mesh);
+            unsigned int iNumFaces, Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_NORMALS block in a file
     //! \param mesh Mesh object to be filled
-    void ParseLV3MeshNormalListBlock(Mesh& mesh);
+    void ParseLV3MeshNormalListBlock(Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_WEIGHTSblock in a file
     //! \param mesh Mesh object to be filled
-    void ParseLV3MeshWeightsBlock(Mesh& mesh);
+    void ParseLV3MeshWeightsBlock(Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse the bone list of a file
     //! \param mesh Mesh object to be filled
     //! \param iNumBones Number of bones in the mesh
-    void ParseLV4MeshBones(unsigned int iNumBones,Mesh& mesh);
+    void ParseLV4MeshBones(unsigned int iNumBones, Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse the bone vertices list of a file
     //! \param mesh Mesh object to be filled
     //! \param iNumVertices Number of vertices to be parsed
-    void ParseLV4MeshBonesVertices(unsigned int iNumVertices,Mesh& mesh);
+    void ParseLV4MeshBonesVertices(unsigned int iNumVertices, Mesh &mesh);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_FACE block in a file
     //! \param out receive the face data
-    void ParseLV4MeshFace(ASE::Face& out);
+    void ParseLV4MeshFace(ASE::Face &out);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_VERT block in a file
     //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL  ...)
     //! \param apOut Output buffer (3 floats)
     //! \param rIndexOut Output index
-    void ParseLV4MeshFloatTriple(ai_real* apOut, unsigned int& rIndexOut);
+    void ParseLV4MeshFloatTriple(ai_real *apOut, unsigned int &rIndexOut);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_VERT block in a file
     //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL  ...)
     //! \param apOut Output buffer (3 floats)
-    void ParseLV4MeshFloatTriple(ai_real* apOut);
+    void ParseLV4MeshFloatTriple(ai_real *apOut);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_TFACE block in a file
     //! (also works for MESH_CFACE)
     //! \param apOut Output buffer (3 ints)
     //! \param rIndexOut Output index
-    void ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut);
+    void ParseLV4MeshLongTriple(unsigned int *apOut, unsigned int &rIndexOut);
 
     // -------------------------------------------------------------------
     //! Parse a *MESH_TFACE block in a file
     //! (also works for MESH_CFACE)
     //! \param apOut Output buffer (3 ints)
-    void ParseLV4MeshLongTriple(unsigned int* apOut);
+    void ParseLV4MeshLongTriple(unsigned int *apOut);
 
     // -------------------------------------------------------------------
     //! Parse a single float element
     //! \param fOut Output float
-    void ParseLV4MeshFloat(ai_real& fOut);
+    void ParseLV4MeshFloat(ai_real &fOut);
 
     // -------------------------------------------------------------------
     //! Parse a single int element
     //! \param iOut Output integer
-    void ParseLV4MeshLong(unsigned int& iOut);
+    void ParseLV4MeshLong(unsigned int &iOut);
 
     // -------------------------------------------------------------------
     //! Skip everything to the next: '*' or '\0'
@@ -625,17 +599,17 @@ private:
     // -------------------------------------------------------------------
     //! Output a warning to the logger
     //! \param szWarn Warn message
-    void LogWarning(const char* szWarn);
+    void LogWarning(const char *szWarn);
 
     // -------------------------------------------------------------------
     //! Output a message to the logger
     //! \param szWarn Message
-    void LogInfo(const char* szWarn);
+    void LogInfo(const char *szWarn);
 
     // -------------------------------------------------------------------
     //! Output an error to the logger
     //! \param szWarn Error message
-    AI_WONT_RETURN void LogError(const char* szWarn) AI_WONT_RETURN_SUFFIX;
+    AI_WONT_RETURN void LogError(const char *szWarn) AI_WONT_RETURN_SUFFIX;
 
     // -------------------------------------------------------------------
     //! Parse a string, enclosed in double quotation marks
@@ -643,12 +617,11 @@ private:
     //! \param szName Name of the enclosing element -> used in error
     //! messages.
     //! \return false if an error occurred
-    bool ParseString(std::string& out,const char* szName);
+    bool ParseString(std::string &out, const char *szName);
 
 public:
-
     //! Pointer to current data
-    const char* filePtr;
+    const char *filePtr;
 
     //! background color to be passed to the viewer
     //! QNAN if none was found
@@ -695,9 +668,8 @@ public:
     unsigned int iFileFormat;
 };
 
-
 } // Namespace ASE
-} // Namespace ASSIMP
+} // namespace Assimp
 
 #endif // ASSIMP_BUILD_NO_3DS_IMPORTER
 

+ 0 - 1
code/Assbin/AssbinExporter.cpp → code/AssetLib/Assbin/AssbinExporter.cpp

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

+ 0 - 0
code/Assbin/AssbinExporter.h → code/AssetLib/Assbin/AssbinExporter.h


+ 32 - 33
code/Assbin/AssbinFileWriter.cpp → code/AssetLib/Assbin/AssbinFileWriter.cpp

@@ -4,7 +4,6 @@ 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,
@@ -54,16 +53,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/IOStream.hpp>
 
 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#    include <zlib.h>
+#include <zlib.h>
 #else
-#    include "../contrib/zlib/zlib.h"
+#include "../contrib/zlib/zlib.h"
 #endif
 
 #include <time.h>
 
 #ifdef _WIN32
-#    pragma warning(push)
-#    pragma warning(disable : 4706)
+#pragma warning(push)
+#pragma warning(disable : 4706)
 #endif // _WIN32
 
 namespace Assimp {
@@ -269,7 +268,7 @@ private:
 
 public:
     AssbinChunkWriter(IOStream *container, uint32_t magic, size_t initial = 4096) :
-            buffer(NULL),
+            buffer(nullptr),
             magic(magic),
             container(container),
             cur_size(0),
@@ -337,7 +336,7 @@ protected:
     void WriteBinaryNode(IOStream *container, const aiNode *node) {
         AssbinChunkWriter chunk(container, ASSBIN_CHUNK_AINODE);
 
-        unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
+        unsigned int nb_metadata = (node->mMetaData != nullptr ? node->mMetaData->mNumProperties : 0);
 
         Write<aiString>(&chunk, node->mName);
         Write<aiMatrix4x4>(&chunk, node->mTransformation);
@@ -362,32 +361,32 @@ protected:
             Write<uint16_t>(&chunk, (uint16_t)type);
 
             switch (type) {
-                case AI_BOOL:
-                    Write<bool>(&chunk, *((bool *)value));
-                    break;
-                case AI_INT32:
-                    Write<int32_t>(&chunk, *((int32_t *)value));
-                    break;
-                case AI_UINT64:
-                    Write<uint64_t>(&chunk, *((uint64_t *)value));
-                    break;
-                case AI_FLOAT:
-                    Write<float>(&chunk, *((float *)value));
-                    break;
-                case AI_DOUBLE:
-                    Write<double>(&chunk, *((double *)value));
-                    break;
-                case AI_AISTRING:
-                    Write<aiString>(&chunk, *((aiString *)value));
-                    break;
-                case AI_AIVECTOR3D:
-                    Write<aiVector3D>(&chunk, *((aiVector3D *)value));
-                    break;
+            case AI_BOOL:
+                Write<bool>(&chunk, *((bool *)value));
+                break;
+            case AI_INT32:
+                Write<int32_t>(&chunk, *((int32_t *)value));
+                break;
+            case AI_UINT64:
+                Write<uint64_t>(&chunk, *((uint64_t *)value));
+                break;
+            case AI_FLOAT:
+                Write<float>(&chunk, *((float *)value));
+                break;
+            case AI_DOUBLE:
+                Write<double>(&chunk, *((double *)value));
+                break;
+            case AI_AISTRING:
+                Write<aiString>(&chunk, *((aiString *)value));
+                break;
+            case AI_AIVECTOR3D:
+                Write<aiVector3D>(&chunk, *((aiVector3D *)value));
+                break;
 #ifdef SWIG
                 case FORCE_32BIT:
 #endif // SWIG
-                default:
-                    break;
+            default:
+                break;
             }
         }
     }
@@ -745,7 +744,7 @@ public:
         };
 
         try {
-            time_t tt = time(NULL);
+            time_t tt = time(nullptr);
 #if _WIN32
             tm *p = gmtime(&tt);
 #else
@@ -791,7 +790,7 @@ public:
             // Up to here the data is uncompressed. For compressed files, the rest
             // is compressed using standard DEFLATE from zlib.
             if (compressed) {
-                AssbinChunkWriter uncompressedStream(NULL, 0);
+                AssbinChunkWriter uncompressedStream(nullptr, 0);
                 WriteBinaryScene(&uncompressedStream, pScene);
 
                 uLongf uncompressedSize = static_cast<uLongf>(uncompressedStream.Tell());
@@ -827,7 +826,7 @@ void DumpSceneToAssbin(
     fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene);
 }
 #ifdef _WIN32
-#    pragma warning(pop)
+#pragma warning(pop)
 #endif // _WIN32
 
 } // end of namespace Assimp

+ 6 - 7
code/Assbin/AssbinFileWriter.h → code/AssetLib/Assbin/AssbinFileWriter.h

@@ -4,7 +4,6 @@ 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,
@@ -54,12 +53,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 
 void ASSIMP_API DumpSceneToAssbin(
-    const char* pFile,
-    const char* cmd,
-    IOSystem* pIOSystem,
-    const aiScene* pScene,
-    bool shortened,
-    bool compressed);
+        const char *pFile,
+        const char *cmd,
+        IOSystem *pIOSystem,
+        const aiScene *pScene,
+        bool shortened,
+        bool compressed);
 
 }
 

+ 26 - 26
code/Assbin/AssbinLoader.cpp → code/AssetLib/Assbin/AssbinLoader.cpp

@@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
 
 // internal headers
-#include "Assbin/AssbinLoader.h"
+#include "AssetLib/Assbin/AssbinLoader.h"
 #include "Common/assbin_chunks.h"
 #include <assimp/MemoryIOWrapper.h>
 #include <assimp/anim.h>
@@ -253,32 +253,32 @@ void AssbinImporter::ReadBinaryNode(IOStream *stream, aiNode **onode, aiNode *pa
             void *data = nullptr;
 
             switch (node->mMetaData->mValues[i].mType) {
-                case AI_BOOL:
-                    data = new bool(Read<bool>(stream));
-                    break;
-                case AI_INT32:
-                    data = new int32_t(Read<int32_t>(stream));
-                    break;
-                case AI_UINT64:
-                    data = new uint64_t(Read<uint64_t>(stream));
-                    break;
-                case AI_FLOAT:
-                    data = new ai_real(Read<ai_real>(stream));
-                    break;
-                case AI_DOUBLE:
-                    data = new double(Read<double>(stream));
-                    break;
-                case AI_AISTRING:
-                    data = new aiString(Read<aiString>(stream));
-                    break;
-                case AI_AIVECTOR3D:
-                    data = new aiVector3D(Read<aiVector3D>(stream));
-                    break;
+            case AI_BOOL:
+                data = new bool(Read<bool>(stream));
+                break;
+            case AI_INT32:
+                data = new int32_t(Read<int32_t>(stream));
+                break;
+            case AI_UINT64:
+                data = new uint64_t(Read<uint64_t>(stream));
+                break;
+            case AI_FLOAT:
+                data = new ai_real(Read<ai_real>(stream));
+                break;
+            case AI_DOUBLE:
+                data = new double(Read<double>(stream));
+                break;
+            case AI_AISTRING:
+                data = new aiString(Read<aiString>(stream));
+                break;
+            case AI_AIVECTOR3D:
+                data = new aiVector3D(Read<aiVector3D>(stream));
+                break;
 #ifndef SWIG
-                case FORCE_32BIT:
+            case FORCE_32BIT:
 #endif // SWIG
-                default:
-                    break;
+            default:
+                break;
             }
 
             node->mMetaData->mValues[i].mData = data;
@@ -604,7 +604,7 @@ void AssbinImporter::ReadBinaryScene(IOStream *stream, aiScene *scene) {
 
     // Read node graph
     //scene->mRootNode = new aiNode[1];
-    ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)NULL);
+    ReadBinaryNode(stream, &scene->mRootNode, (aiNode *)nullptr);
 
     // Read all meshes
     if (scene->mNumMeshes) {

+ 0 - 0
code/Assbin/AssbinLoader.h → code/AssetLib/Assbin/AssbinLoader.h


+ 4 - 0
code/Assjson/cencode.c → code/AssetLib/Assjson/cencode.c

@@ -9,6 +9,9 @@ For details, see http://sourceforge.net/projects/libb64
 
 const int CHARS_PER_LINE = 72;
 
+#pragma warning(push)
+#pragma warning(disable : 4244)
+
 void base64_init_encodestate(base64_encodestate* state_in)
 {
 	state_in->step = step_A;
@@ -107,3 +110,4 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 	return (int)(codechar - code_out);
 }
 
+#pragma warning(pop)

+ 0 - 0
code/Assjson/cencode.h → code/AssetLib/Assjson/cencode.h


+ 83 - 94
code/Assjson/json_exporter.cpp → code/AssetLib/Assjson/json_exporter.cpp

@@ -9,30 +9,31 @@ Licensed under a 3-clause BSD license. See the LICENSE file for more information
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
 
-#include <assimp/Importer.hpp>
+#include <assimp/scene.h>
 #include <assimp/Exporter.hpp>
 #include <assimp/IOStream.hpp>
 #include <assimp/IOSystem.hpp>
-#include <assimp/scene.h>
+#include <assimp/Importer.hpp>
+#include <assimp/Exceptional.h>
 
-#include <sstream>
-#include <limits>
 #include <cassert>
+#include <limits>
 #include <memory>
+#include <sstream>
 
 #define CURRENT_FORMAT_VERSION 100
 
-// grab scoped_ptr from assimp to avoid a dependency on boost. 
+// grab scoped_ptr from assimp to avoid a dependency on boost.
 //#include <assimp/../../code/BoostWorkaround/boost/scoped_ptr.hpp>
 
 #include "mesh_splitter.h"
 
 extern "C" {
-    #include "cencode.h"
+#include "cencode.h"
 }
 namespace Assimp {
 
-void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
+void ExportAssimp2Json(const char *, Assimp::IOSystem *, const aiScene *, const Assimp::ExportProperties *);
 
 // small utility class to simplify serializing the aiScene to Json
 class JSONWriter {
@@ -42,10 +43,8 @@ public:
         Flag_WriteSpecialFloats = 0x2,
     };
 
-    JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u)
-    : out(out)
-    , first()
-    , flags(flags) {
+    JSONWriter(Assimp::IOStream &out, unsigned int flags = 0u) :
+            out(out), first(), flags(flags) {
         // make sure that all formatting happens using the standard, C locale and not the user's current locale
         buff.imbue(std::locale("C"));
     }
@@ -68,30 +67,30 @@ public:
         indent.erase(indent.end() - 1);
     }
 
-    void Key(const std::string& name) {
+    void Key(const std::string &name) {
         AddIndentation();
         Delimit();
         buff << '\"' + name + "\": ";
     }
 
-    template<typename Literal>
-    void Element(const Literal& name) {
+    template <typename Literal>
+    void Element(const Literal &name) {
         AddIndentation();
         Delimit();
 
         LiteralToString(buff, name) << '\n';
     }
 
-    template<typename Literal>
-    void SimpleValue(const Literal& s) {
+    template <typename Literal>
+    void SimpleValue(const Literal &s) {
         LiteralToString(buff, s) << '\n';
     }
 
-    void SimpleValue(const void* buffer, size_t len) {
+    void SimpleValue(const void *buffer, size_t len) {
         base64_encodestate s;
         base64_init_encodestate(&s);
 
-        char* const cur_out = new char[std::max(len * 2, static_cast<size_t>(16u))];
+        char *const cur_out = new char[std::max(len * 2, static_cast<size_t>(16u))];
         const int n = base64_encode_block(reinterpret_cast<const char *>(buffer), static_cast<int>(len), cur_out, &s);
         cur_out[n + base64_encode_blockend(cur_out + n, &s)] = '\0';
 
@@ -156,21 +155,20 @@ public:
     void Delimit() {
         if (!first) {
             buff << ',';
-        }
-        else {
+        } else {
             buff << ' ';
             first = false;
         }
     }
 
 private:
-    template<typename Literal>
-    std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) {
+    template <typename Literal>
+    std::stringstream &LiteralToString(std::stringstream &stream, const Literal &s) {
         stream << s;
         return stream;
     }
 
-    std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) {
+    std::stringstream &LiteralToString(std::stringstream &stream, const aiString &s) {
         std::string t;
 
         // escape backslashes and single quotes, both would render the JSON invalid if left as is
@@ -189,10 +187,10 @@ private:
         return stream;
     }
 
-    std::stringstream& LiteralToString(std::stringstream& stream, float f) {
+    std::stringstream &LiteralToString(std::stringstream &stream, float f) {
         if (!std::numeric_limits<float>::is_iec559) {
             // on a non IEEE-754 platform, we make no assumptions about the representation or existence
-            // of special floating-point numbers. 
+            // of special floating-point numbers.
             stream << f;
             return stream;
         }
@@ -228,7 +226,7 @@ private:
     }
 
 private:
-    Assimp::IOStream& out;
+    Assimp::IOStream &out;
     std::string indent, newline;
     std::stringstream buff;
     bool first;
@@ -236,7 +234,7 @@ private:
     unsigned int flags;
 };
 
-void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiVector3D &ai, bool is_elem = true) {
     out.StartArray(is_elem);
     out.Element(ai.x);
     out.Element(ai.y);
@@ -244,7 +242,7 @@ void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) {
     out.EndArray();
 }
 
-void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiQuaternion &ai, bool is_elem = true) {
     out.StartArray(is_elem);
     out.Element(ai.w);
     out.Element(ai.x);
@@ -253,7 +251,7 @@ void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) {
     out.EndArray();
 }
 
-void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiColor3D &ai, bool is_elem = true) {
     out.StartArray(is_elem);
     out.Element(ai.r);
     out.Element(ai.g);
@@ -261,7 +259,7 @@ void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) {
     out.EndArray();
 }
 
-void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiMatrix4x4 &ai, bool is_elem = true) {
     out.StartArray(is_elem);
     for (unsigned int x = 0; x < 4; ++x) {
         for (unsigned int y = 0; y < 4; ++y) {
@@ -271,7 +269,7 @@ void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) {
     out.EndArray();
 }
 
-void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiBone &ai, bool is_elem = true) {
     out.StartObj(is_elem);
 
     out.Key("name");
@@ -292,7 +290,7 @@ void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) {
     out.EndObj();
 }
 
-void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiFace &ai, bool is_elem = true) {
     out.StartArray(is_elem);
     for (unsigned int i = 0; i < ai.mNumIndices; ++i) {
         out.Element(ai.mIndices[i]);
@@ -300,7 +298,7 @@ void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) {
     out.EndArray();
 }
 
-void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiMesh &ai, bool is_elem = true) {
     out.StartObj(is_elem);
 
     out.Key("name");
@@ -411,7 +409,7 @@ void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) {
     out.EndObj();
 }
 
-void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiNode &ai, bool is_elem = true) {
     out.StartObj(is_elem);
 
     out.Key("name");
@@ -441,13 +439,13 @@ void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) {
     out.EndObj();
 }
 
-void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiMaterial &ai, bool is_elem = true) {
     out.StartObj(is_elem);
 
     out.Key("properties");
     out.StartArray();
     for (unsigned int i = 0; i < ai.mNumProperties; ++i) {
-        const aiMaterialProperty* const prop = ai.mProperties[i];
+        const aiMaterialProperty *const prop = ai.mProperties[i];
         out.StartObj(true);
         out.Key("key");
         out.SimpleValue(prop->mKey);
@@ -461,46 +459,41 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
 
         out.Key("value");
         switch (prop->mType) {
-            case aiPTI_Float:
-                if (prop->mDataLength / sizeof(float) > 1) {
-                    out.StartArray();
-                    for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) {
-                        out.Element(reinterpret_cast<float*>(prop->mData)[ii]);
-                    }
-                    out.EndArray();
-                }
-                else {
-                    out.SimpleValue(*reinterpret_cast<float*>(prop->mData));
-                }
-                break;
-
-            case aiPTI_Integer:
-                if (prop->mDataLength / sizeof(int) > 1) {
-                    out.StartArray();
-                    for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) {
-                        out.Element(reinterpret_cast<int*>(prop->mData)[ii]);
-                    }
-                    out.EndArray();
-                } else {
-                    out.SimpleValue(*reinterpret_cast<int*>(prop->mData));
+        case aiPTI_Float:
+            if (prop->mDataLength / sizeof(float) > 1) {
+                out.StartArray();
+                for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(float); ++ii) {
+                    out.Element(reinterpret_cast<float *>(prop->mData)[ii]);
                 }
-                break;
+                out.EndArray();
+            } else {
+                out.SimpleValue(*reinterpret_cast<float *>(prop->mData));
+            }
+            break;
 
-            case aiPTI_String:
-                {
-                    aiString s;
-                    aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
-                    out.SimpleValue(s);
-                }
-                break;
-            case aiPTI_Buffer:
-                {
-                    // binary data is written as series of hex-encoded octets
-                    out.SimpleValue(prop->mData, prop->mDataLength);
+        case aiPTI_Integer:
+            if (prop->mDataLength / sizeof(int) > 1) {
+                out.StartArray();
+                for (unsigned int ii = 0; ii < prop->mDataLength / sizeof(int); ++ii) {
+                    out.Element(reinterpret_cast<int *>(prop->mData)[ii]);
                 }
-                break;
-            default:
-                assert(false);
+                out.EndArray();
+            } else {
+                out.SimpleValue(*reinterpret_cast<int *>(prop->mData));
+            }
+            break;
+
+        case aiPTI_String: {
+            aiString s;
+            aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s);
+            out.SimpleValue(s);
+        } break;
+        case aiPTI_Buffer: {
+            // binary data is written as series of hex-encoded octets
+            out.SimpleValue(prop->mData, prop->mDataLength);
+        } break;
+        default:
+            assert(false);
         }
 
         out.EndObj();
@@ -510,7 +503,7 @@ void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) {
     out.EndObj();
 }
 
-void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiTexture &ai, bool is_elem = true) {
     out.StartObj(is_elem);
 
     out.Key("width");
@@ -525,13 +518,12 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
     out.Key("data");
     if (!ai.mHeight) {
         out.SimpleValue(ai.pcData, ai.mWidth);
-    }
-    else {
+    } else {
         out.StartArray();
         for (unsigned int y = 0; y < ai.mHeight; ++y) {
             out.StartArray(true);
             for (unsigned int x = 0; x < ai.mWidth; ++x) {
-                const aiTexel& tx = ai.pcData[y*ai.mWidth + x];
+                const aiTexel &tx = ai.pcData[y * ai.mWidth + x];
                 out.StartArray(true);
                 out.Element(static_cast<unsigned int>(tx.r));
                 out.Element(static_cast<unsigned int>(tx.g));
@@ -547,7 +539,7 @@ void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) {
     out.EndObj();
 }
 
-void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiLight &ai, bool is_elem = true) {
     out.StartObj(is_elem);
 
     out.Key("name");
@@ -585,7 +577,6 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
     if (ai.mType != aiLightSource_POINT) {
         out.Key("direction");
         Write(out, ai.mDirection, false);
-
     }
 
     if (ai.mType != aiLightSource_DIRECTIONAL) {
@@ -596,7 +587,7 @@ void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) {
     out.EndObj();
 }
 
-void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiNodeAnim &ai, bool is_elem = true) {
     out.StartObj(is_elem);
 
     out.Key("name");
@@ -612,7 +603,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
         out.Key("positionkeys");
         out.StartArray();
         for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) {
-            const aiVectorKey& pos = ai.mPositionKeys[n];
+            const aiVectorKey &pos = ai.mPositionKeys[n];
             out.StartArray(true);
             out.Element(pos.mTime);
             Write(out, pos.mValue);
@@ -625,7 +616,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
         out.Key("rotationkeys");
         out.StartArray();
         for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) {
-            const aiQuatKey& rot = ai.mRotationKeys[n];
+            const aiQuatKey &rot = ai.mRotationKeys[n];
             out.StartArray(true);
             out.Element(rot.mTime);
             Write(out, rot.mValue);
@@ -638,7 +629,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
         out.Key("scalingkeys");
         out.StartArray();
         for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) {
-            const aiVectorKey& scl = ai.mScalingKeys[n];
+            const aiVectorKey &scl = ai.mScalingKeys[n];
             out.StartArray(true);
             out.Element(scl.mTime);
             Write(out, scl.mValue);
@@ -649,7 +640,7 @@ void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) {
     out.EndObj();
 }
 
-void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiAnimation &ai, bool is_elem = true) {
     out.StartObj(is_elem);
 
     out.Key("name");
@@ -670,7 +661,7 @@ void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) {
     out.EndObj();
 }
 
-void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
+void Write(JSONWriter &out, const aiCamera &ai, bool is_elem = true) {
     out.StartObj(is_elem);
 
     out.Key("name");
@@ -697,7 +688,7 @@ void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) {
     out.EndObj();
 }
 
-void WriteFormatInfo(JSONWriter& out) {
+void WriteFormatInfo(JSONWriter &out) {
     out.StartObj();
     out.Key("format");
     out.SimpleValue("\"assimp2json\"");
@@ -706,7 +697,7 @@ void WriteFormatInfo(JSONWriter& out) {
     out.EndObj();
 }
 
-void Write(JSONWriter& out, const aiScene& ai) {
+void Write(JSONWriter &out, const aiScene &ai) {
     out.StartObj();
 
     out.Key("__metadata__");
@@ -774,15 +765,14 @@ void Write(JSONWriter& out, const aiScene& ai) {
     out.EndObj();
 }
 
-
-void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) {
+void ExportAssimp2Json(const char *file, Assimp::IOSystem *io, const aiScene *scene, const Assimp::ExportProperties *) {
     std::unique_ptr<Assimp::IOStream> str(io->Open(file, "wt"));
     if (!str) {
-        //throw Assimp::DeadlyExportError("could not open output file");
+        throw DeadlyExportError("could not open output file");
     }
 
     // get a copy of the scene so we can modify it
-    aiScene* scenecopy_tmp;
+    aiScene *scenecopy_tmp;
     aiCopyScene(scene, &scenecopy_tmp);
 
     try {
@@ -795,15 +785,14 @@ void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* sc
         JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats);
         Write(s, *scenecopy_tmp);
 
-    }
-    catch (...) {
+    } catch (...) {
         aiFreeScene(scenecopy_tmp);
         throw;
     }
     aiFreeScene(scenecopy_tmp);
 }
 
-}
+} // namespace Assimp
 
 #endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER
 #endif // ASSIMP_BUILD_NO_EXPORT

+ 0 - 0
code/Assjson/mesh_splitter.cpp → code/AssetLib/Assjson/mesh_splitter.cpp


+ 0 - 0
code/Assjson/mesh_splitter.h → code/AssetLib/Assjson/mesh_splitter.h


+ 1 - 1
code/Assxml/AssxmlExporter.cpp → code/AssetLib/Assxml/AssxmlExporter.cpp

@@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/IOSystem.hpp>
 #include <assimp/Exporter.hpp>
 
-namespace Assimp    {
+namespace Assimp   { 
 
 void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
 {

+ 0 - 0
code/Assxml/AssxmlExporter.h → code/AssetLib/Assxml/AssxmlExporter.h


+ 659 - 0
code/AssetLib/Assxml/AssxmlFileWriter.cpp

@@ -0,0 +1,659 @@
+/*
+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 AssxmlFileWriter.cpp
+ *  @brief Implementation of Assxml file writer.
+ */
+
+#include "AssxmlFileWriter.h"
+
+#include "PostProcessing/ProcessHelper.h"
+
+#include <assimp/version.h>
+#include <assimp/Exporter.hpp>
+#include <assimp/IOStream.hpp>
+#include <assimp/IOSystem.hpp>
+
+#include <stdarg.h>
+
+#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#include <zlib.h>
+#else
+#include <contrib/zlib/zlib.h>
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <memory>
+
+using namespace Assimp;
+
+namespace Assimp {
+
+namespace AssxmlFileWriter {
+
+// -----------------------------------------------------------------------------------
+static int ioprintf(IOStream *io, const char *format, ...) {
+    using namespace std;
+    if (nullptr == io) {
+        return -1;
+    }
+
+    static const int Size = 4096;
+    char sz[Size];
+    ::memset(sz, '\0', Size);
+    va_list va;
+    va_start(va, format);
+    const unsigned int nSize = vsnprintf(sz, Size - 1, format, va);
+    ai_assert(nSize < Size);
+    va_end(va);
+
+    io->Write(sz, sizeof(char), nSize);
+
+    return nSize;
+}
+
+// -----------------------------------------------------------------------------------
+// Convert a name to standard XML format
+static void ConvertName(aiString &out, const aiString &in) {
+    out.length = 0;
+    for (unsigned int i = 0; i < in.length; ++i) {
+        switch (in.data[i]) {
+        case '<':
+            out.Append("&lt;");
+            break;
+        case '>':
+            out.Append("&gt;");
+            break;
+        case '&':
+            out.Append("&amp;");
+            break;
+        case '\"':
+            out.Append("&quot;");
+            break;
+        case '\'':
+            out.Append("&apos;");
+            break;
+        default:
+            out.data[out.length++] = in.data[i];
+        }
+    }
+    out.data[out.length] = 0;
+}
+
+// -----------------------------------------------------------------------------------
+// Write a single node as text dump
+static void WriteNode(const aiNode *node, IOStream *io, unsigned int depth) {
+    char prefix[512];
+    for (unsigned int i = 0; i < depth; ++i)
+        prefix[i] = '\t';
+    prefix[depth] = '\0';
+
+    const aiMatrix4x4 &m = node->mTransformation;
+
+    aiString name;
+    ConvertName(name, node->mName);
+    ioprintf(io, "%s<Node name=\"%s\"> \n"
+                 "%s\t<Matrix4> \n"
+                 "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                 "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                 "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                 "%s\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                 "%s\t</Matrix4> \n",
+            prefix, name.data, prefix,
+            prefix, m.a1, m.a2, m.a3, m.a4,
+            prefix, m.b1, m.b2, m.b3, m.b4,
+            prefix, m.c1, m.c2, m.c3, m.c4,
+            prefix, m.d1, m.d2, m.d3, m.d4, prefix);
+
+    if (node->mNumMeshes) {
+        ioprintf(io, "%s\t<MeshRefs num=\"%u\">\n%s\t",
+                prefix, node->mNumMeshes, prefix);
+
+        for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
+            ioprintf(io, "%u ", node->mMeshes[i]);
+        }
+        ioprintf(io, "\n%s\t</MeshRefs>\n", prefix);
+    }
+
+    if (node->mNumChildren) {
+        ioprintf(io, "%s\t<NodeList num=\"%u\">\n",
+                prefix, node->mNumChildren);
+
+        for (unsigned int i = 0; i < node->mNumChildren; ++i) {
+            WriteNode(node->mChildren[i], io, depth + 2);
+        }
+        ioprintf(io, "%s\t</NodeList>\n", prefix);
+    }
+    ioprintf(io, "%s</Node>\n", prefix);
+}
+
+// -----------------------------------------------------------------------------------
+// Some chuncks of text will need to be encoded for XML
+// http://stackoverflow.com/questions/5665231/most-efficient-way-to-escape-xml-html-in-c-string#5665377
+static std::string encodeXML(const std::string &data) {
+    std::string buffer;
+    buffer.reserve(data.size());
+    for (size_t pos = 0; pos != data.size(); ++pos) {
+        switch (data[pos]) {
+        case '&': buffer.append("&amp;"); break;
+        case '\"': buffer.append("&quot;"); break;
+        case '\'': buffer.append("&apos;"); break;
+        case '<': buffer.append("&lt;"); break;
+        case '>': buffer.append("&gt;"); break;
+        default: buffer.append(&data[pos], 1); break;
+        }
+    }
+    return buffer;
+}
+
+// -----------------------------------------------------------------------------------
+// Write a text model dump
+static void WriteDump(const char *pFile, const char *cmd, const aiScene *scene, IOStream *io, bool shortened) {
+    time_t tt = ::time(nullptr);
+#if _WIN32
+    tm *p = gmtime(&tt);
+#else
+    struct tm now;
+    tm *p = gmtime_r(&tt, &now);
+#endif
+    ai_assert(nullptr != p);
+
+    std::string c = cmd;
+    std::string::size_type s;
+
+    // https://sourceforge.net/tracker/?func=detail&aid=3167364&group_id=226462&atid=1067632
+    // -- not allowed in XML comments
+    while ((s = c.find("--")) != std::string::npos) {
+        c[s] = '?';
+    }
+
+    // write header
+    std::string header(
+            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+            "<ASSIMP format_id=\"1\">\n\n"
+            "<!-- XML Model dump produced by assimp dump\n"
+            "  Library version: %u.%u.%u\n"
+            "  Source: %s\n"
+            "  Command line: %s\n"
+            "  %s\n"
+            "-->"
+            " \n\n"
+            "<Scene flags=\"%u\" postprocessing=\"%u\">\n");
+
+    const unsigned int majorVersion(aiGetVersionMajor());
+    const unsigned int minorVersion(aiGetVersionMinor());
+    const unsigned int rev(aiGetVersionRevision());
+    const char *curtime(asctime(p));
+    ioprintf(io, header.c_str(), majorVersion, minorVersion, rev, pFile, c.c_str(), curtime, scene->mFlags, 0u);
+
+    // write the node graph
+    WriteNode(scene->mRootNode, io, 0);
+
+#if 0
+    // write cameras
+    for (unsigned int i = 0; i < scene->mNumCameras;++i) {
+        aiCamera* cam  = scene->mCameras[i];
+        ConvertName(name,cam->mName);
+
+        // camera header
+        ioprintf(io,"\t<Camera parent=\"%s\">\n"
+            "\t\t<Vector3 name=\"up\"        > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Float   name=\"fov\"       > %f </Float>\n"
+            "\t\t<Float   name=\"aspect\"    > %f </Float>\n"
+            "\t\t<Float   name=\"near_clip\" > %f </Float>\n"
+            "\t\t<Float   name=\"far_clip\"  > %f </Float>\n"
+            "\t</Camera>\n",
+            name.data,
+            cam->mUp.x,cam->mUp.y,cam->mUp.z,
+            cam->mLookAt.x,cam->mLookAt.y,cam->mLookAt.z,
+            cam->mPosition.x,cam->mPosition.y,cam->mPosition.z,
+            cam->mHorizontalFOV,cam->mAspect,cam->mClipPlaneNear,cam->mClipPlaneFar,i);
+    }
+
+    // write lights
+    for (unsigned int i = 0; i < scene->mNumLights;++i) {
+        aiLight* l  = scene->mLights[i];
+        ConvertName(name,l->mName);
+
+        // light header
+        ioprintf(io,"\t<Light parent=\"%s\"> type=\"%s\"\n"
+            "\t\t<Vector3 name=\"diffuse\"   > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Vector3 name=\"specular\"  > %0 8f %0 8f %0 8f </Vector3>\n"
+            "\t\t<Vector3 name=\"ambient\"   > %0 8f %0 8f %0 8f </Vector3>\n",
+            name.data,
+            (l->mType == aiLightSource_DIRECTIONAL ? "directional" :
+            (l->mType == aiLightSource_POINT ? "point" : "spot" )),
+            l->mColorDiffuse.r, l->mColorDiffuse.g, l->mColorDiffuse.b,
+            l->mColorSpecular.r,l->mColorSpecular.g,l->mColorSpecular.b,
+            l->mColorAmbient.r, l->mColorAmbient.g, l->mColorAmbient.b);
+
+        if (l->mType != aiLightSource_DIRECTIONAL) {
+            ioprintf(io,
+                "\t\t<Vector3 name=\"pos\"       > %0 8f %0 8f %0 8f </Vector3>\n"
+                "\t\t<Float   name=\"atten_cst\" > %f </Float>\n"
+                "\t\t<Float   name=\"atten_lin\" > %f </Float>\n"
+                "\t\t<Float   name=\"atten_sqr\" > %f </Float>\n",
+                l->mPosition.x,l->mPosition.y,l->mPosition.z,
+                l->mAttenuationConstant,l->mAttenuationLinear,l->mAttenuationQuadratic);
+        }
+
+        if (l->mType != aiLightSource_POINT) {
+            ioprintf(io,
+                "\t\t<Vector3 name=\"lookat\"    > %0 8f %0 8f %0 8f </Vector3>\n",
+                l->mDirection.x,l->mDirection.y,l->mDirection.z);
+        }
+
+        if (l->mType == aiLightSource_SPOT) {
+            ioprintf(io,
+                "\t\t<Float   name=\"cone_out\" > %f </Float>\n"
+                "\t\t<Float   name=\"cone_inn\" > %f </Float>\n",
+                l->mAngleOuterCone,l->mAngleInnerCone);
+        }
+        ioprintf(io,"\t</Light>\n");
+    }
+#endif
+    aiString name;
+
+    // write textures
+    if (scene->mNumTextures) {
+        ioprintf(io, "<TextureList num=\"%u\">\n", scene->mNumTextures);
+        for (unsigned int i = 0; i < scene->mNumTextures; ++i) {
+            aiTexture *tex = scene->mTextures[i];
+            bool compressed = (tex->mHeight == 0);
+
+            // mesh header
+            ioprintf(io, "\t<Texture width=\"%u\" height=\"%u\" compressed=\"%s\"> \n",
+                    (compressed ? -1 : tex->mWidth), (compressed ? -1 : tex->mHeight),
+                    (compressed ? "true" : "false"));
+
+            if (compressed) {
+                ioprintf(io, "\t\t<Data length=\"%u\"> \n", tex->mWidth);
+
+                if (!shortened) {
+                    for (unsigned int n = 0; n < tex->mWidth; ++n) {
+                        ioprintf(io, "\t\t\t%2x", reinterpret_cast<uint8_t *>(tex->pcData)[n]);
+                        if (n && !(n % 50)) {
+                            ioprintf(io, "\n");
+                        }
+                    }
+                }
+            } else if (!shortened) {
+                ioprintf(io, "\t\t<Data length=\"%u\"> \n", tex->mWidth * tex->mHeight * 4);
+
+                // const unsigned int width = (unsigned int)std::log10((double)std::max(tex->mHeight,tex->mWidth))+1;
+                for (unsigned int y = 0; y < tex->mHeight; ++y) {
+                    for (unsigned int x = 0; x < tex->mWidth; ++x) {
+                        aiTexel *tx = tex->pcData + y * tex->mWidth + x;
+                        unsigned int r = tx->r, g = tx->g, b = tx->b, a = tx->a;
+                        ioprintf(io, "\t\t\t%2x %2x %2x %2x", r, g, b, a);
+
+                        // group by four for readability
+                        if (0 == (x + y * tex->mWidth) % 4) {
+                            ioprintf(io, "\n");
+                        }
+                    }
+                }
+            }
+            ioprintf(io, "\t\t</Data>\n\t</Texture>\n");
+        }
+        ioprintf(io, "</TextureList>\n");
+    }
+
+    // write materials
+    if (scene->mNumMaterials) {
+        ioprintf(io, "<MaterialList num=\"%u\">\n", scene->mNumMaterials);
+        for (unsigned int i = 0; i < scene->mNumMaterials; ++i) {
+            const aiMaterial *mat = scene->mMaterials[i];
+
+            ioprintf(io, "\t<Material>\n");
+            ioprintf(io, "\t\t<MatPropertyList  num=\"%u\">\n", mat->mNumProperties);
+            for (unsigned int n = 0; n < mat->mNumProperties; ++n) {
+
+                const aiMaterialProperty *prop = mat->mProperties[n];
+                const char *sz = "";
+                if (prop->mType == aiPTI_Float) {
+                    sz = "float";
+                } else if (prop->mType == aiPTI_Integer) {
+                    sz = "integer";
+                } else if (prop->mType == aiPTI_String) {
+                    sz = "string";
+                } else if (prop->mType == aiPTI_Buffer) {
+                    sz = "binary_buffer";
+                }
+
+                ioprintf(io, "\t\t\t<MatProperty key=\"%s\" \n\t\t\ttype=\"%s\" tex_usage=\"%s\" tex_index=\"%u\"",
+                        prop->mKey.data, sz,
+                        ::TextureTypeToString((aiTextureType)prop->mSemantic), prop->mIndex);
+
+                if (prop->mType == aiPTI_Float) {
+                    ioprintf(io, " size=\"%i\">\n\t\t\t\t",
+                            static_cast<int>(prop->mDataLength / sizeof(float)));
+
+                    for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(float); ++pp) {
+                        ioprintf(io, "%f ", *((float *)(prop->mData + pp * sizeof(float))));
+                    }
+                } else if (prop->mType == aiPTI_Integer) {
+                    ioprintf(io, " size=\"%i\">\n\t\t\t\t",
+                            static_cast<int>(prop->mDataLength / sizeof(int)));
+
+                    for (unsigned int pp = 0; pp < prop->mDataLength / sizeof(int); ++pp) {
+                        ioprintf(io, "%i ", *((int *)(prop->mData + pp * sizeof(int))));
+                    }
+                } else if (prop->mType == aiPTI_Buffer) {
+                    ioprintf(io, " size=\"%i\">\n\t\t\t\t",
+                            static_cast<int>(prop->mDataLength));
+
+                    for (unsigned int pp = 0; pp < prop->mDataLength; ++pp) {
+                        ioprintf(io, "%2x ", prop->mData[pp]);
+                        if (pp && 0 == pp % 30) {
+                            ioprintf(io, "\n\t\t\t\t");
+                        }
+                    }
+                } else if (prop->mType == aiPTI_String) {
+                    ioprintf(io, ">\n\t\t\t\t\"%s\"", encodeXML(prop->mData + 4).c_str() /* skip length */);
+                }
+                ioprintf(io, "\n\t\t\t</MatProperty>\n");
+            }
+            ioprintf(io, "\t\t</MatPropertyList>\n");
+            ioprintf(io, "\t</Material>\n");
+        }
+        ioprintf(io, "</MaterialList>\n");
+    }
+
+    // write animations
+    if (scene->mNumAnimations) {
+        ioprintf(io, "<AnimationList num=\"%u\">\n", scene->mNumAnimations);
+        for (unsigned int i = 0; i < scene->mNumAnimations; ++i) {
+            aiAnimation *anim = scene->mAnimations[i];
+
+            // anim header
+            ConvertName(name, anim->mName);
+            ioprintf(io, "\t<Animation name=\"%s\" duration=\"%e\" tick_cnt=\"%e\">\n",
+                    name.data, anim->mDuration, anim->mTicksPerSecond);
+
+            // write bone animation channels
+            if (anim->mNumChannels) {
+                ioprintf(io, "\t\t<NodeAnimList num=\"%u\">\n", anim->mNumChannels);
+                for (unsigned int n = 0; n < anim->mNumChannels; ++n) {
+                    aiNodeAnim *nd = anim->mChannels[n];
+
+                    // node anim header
+                    ConvertName(name, nd->mNodeName);
+                    ioprintf(io, "\t\t\t<NodeAnim node=\"%s\">\n", name.data);
+
+                    if (!shortened) {
+                        // write position keys
+                        if (nd->mNumPositionKeys) {
+                            ioprintf(io, "\t\t\t\t<PositionKeyList num=\"%u\">\n", nd->mNumPositionKeys);
+                            for (unsigned int a = 0; a < nd->mNumPositionKeys; ++a) {
+                                aiVectorKey *vc = nd->mPositionKeys + a;
+                                ioprintf(io, "\t\t\t\t\t<PositionKey time=\"%e\">\n"
+                                             "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</PositionKey>\n",
+                                        vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z);
+                            }
+                            ioprintf(io, "\t\t\t\t</PositionKeyList>\n");
+                        }
+
+                        // write scaling keys
+                        if (nd->mNumScalingKeys) {
+                            ioprintf(io, "\t\t\t\t<ScalingKeyList num=\"%u\">\n", nd->mNumScalingKeys);
+                            for (unsigned int a = 0; a < nd->mNumScalingKeys; ++a) {
+                                aiVectorKey *vc = nd->mScalingKeys + a;
+                                ioprintf(io, "\t\t\t\t\t<ScalingKey time=\"%e\">\n"
+                                             "\t\t\t\t\t\t%0 8f %0 8f %0 8f\n\t\t\t\t\t</ScalingKey>\n",
+                                        vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z);
+                            }
+                            ioprintf(io, "\t\t\t\t</ScalingKeyList>\n");
+                        }
+
+                        // write rotation keys
+                        if (nd->mNumRotationKeys) {
+                            ioprintf(io, "\t\t\t\t<RotationKeyList num=\"%u\">\n", nd->mNumRotationKeys);
+                            for (unsigned int a = 0; a < nd->mNumRotationKeys; ++a) {
+                                aiQuatKey *vc = nd->mRotationKeys + a;
+                                ioprintf(io, "\t\t\t\t\t<RotationKey time=\"%e\">\n"
+                                             "\t\t\t\t\t\t%0 8f %0 8f %0 8f %0 8f\n\t\t\t\t\t</RotationKey>\n",
+                                        vc->mTime, vc->mValue.x, vc->mValue.y, vc->mValue.z, vc->mValue.w);
+                            }
+                            ioprintf(io, "\t\t\t\t</RotationKeyList>\n");
+                        }
+                    }
+                    ioprintf(io, "\t\t\t</NodeAnim>\n");
+                }
+                ioprintf(io, "\t\t</NodeAnimList>\n");
+            }
+            ioprintf(io, "\t</Animation>\n");
+        }
+        ioprintf(io, "</AnimationList>\n");
+    }
+
+    // write meshes
+    if (scene->mNumMeshes) {
+        ioprintf(io, "<MeshList num=\"%u\">\n", scene->mNumMeshes);
+        for (unsigned int i = 0; i < scene->mNumMeshes; ++i) {
+            aiMesh *mesh = scene->mMeshes[i];
+            // const unsigned int width = (unsigned int)std::log10((double)mesh->mNumVertices)+1;
+
+            // mesh header
+            ioprintf(io, "\t<Mesh types=\"%s %s %s %s\" material_index=\"%u\">\n",
+                    (mesh->mPrimitiveTypes & aiPrimitiveType_POINT ? "points" : ""),
+                    (mesh->mPrimitiveTypes & aiPrimitiveType_LINE ? "lines" : ""),
+                    (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE ? "triangles" : ""),
+                    (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON ? "polygons" : ""),
+                    mesh->mMaterialIndex);
+
+            // bones
+            if (mesh->mNumBones) {
+                ioprintf(io, "\t\t<BoneList num=\"%u\">\n", mesh->mNumBones);
+
+                for (unsigned int n = 0; n < mesh->mNumBones; ++n) {
+                    aiBone *bone = mesh->mBones[n];
+
+                    ConvertName(name, bone->mName);
+                    // bone header
+                    ioprintf(io, "\t\t\t<Bone name=\"%s\">\n"
+                                 "\t\t\t\t<Matrix4> \n"
+                                 "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                                 "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                                 "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                                 "\t\t\t\t\t%0 6f %0 6f %0 6f %0 6f\n"
+                                 "\t\t\t\t</Matrix4> \n",
+                            name.data,
+                            bone->mOffsetMatrix.a1, bone->mOffsetMatrix.a2, bone->mOffsetMatrix.a3, bone->mOffsetMatrix.a4,
+                            bone->mOffsetMatrix.b1, bone->mOffsetMatrix.b2, bone->mOffsetMatrix.b3, bone->mOffsetMatrix.b4,
+                            bone->mOffsetMatrix.c1, bone->mOffsetMatrix.c2, bone->mOffsetMatrix.c3, bone->mOffsetMatrix.c4,
+                            bone->mOffsetMatrix.d1, bone->mOffsetMatrix.d2, bone->mOffsetMatrix.d3, bone->mOffsetMatrix.d4);
+
+                    if (!shortened && bone->mNumWeights) {
+                        ioprintf(io, "\t\t\t\t<WeightList num=\"%u\">\n", bone->mNumWeights);
+
+                        // bone weights
+                        for (unsigned int a = 0; a < bone->mNumWeights; ++a) {
+                            aiVertexWeight *wght = bone->mWeights + a;
+
+                            ioprintf(io, "\t\t\t\t\t<Weight index=\"%u\">\n\t\t\t\t\t\t%f\n\t\t\t\t\t</Weight>\n",
+                                    wght->mVertexId, wght->mWeight);
+                        }
+                        ioprintf(io, "\t\t\t\t</WeightList>\n");
+                    }
+                    ioprintf(io, "\t\t\t</Bone>\n");
+                }
+                ioprintf(io, "\t\t</BoneList>\n");
+            }
+
+            // faces
+            if (!shortened && mesh->mNumFaces) {
+                ioprintf(io, "\t\t<FaceList num=\"%u\">\n", mesh->mNumFaces);
+                for (unsigned int n = 0; n < mesh->mNumFaces; ++n) {
+                    aiFace &f = mesh->mFaces[n];
+                    ioprintf(io, "\t\t\t<Face num=\"%u\">\n"
+                                 "\t\t\t\t",
+                            f.mNumIndices);
+
+                    for (unsigned int j = 0; j < f.mNumIndices; ++j)
+                        ioprintf(io, "%u ", f.mIndices[j]);
+
+                    ioprintf(io, "\n\t\t\t</Face>\n");
+                }
+                ioprintf(io, "\t\t</FaceList>\n");
+            }
+
+            // vertex positions
+            if (mesh->HasPositions()) {
+                ioprintf(io, "\t\t<Positions num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
+                                mesh->mVertices[n].x,
+                                mesh->mVertices[n].y,
+                                mesh->mVertices[n].z);
+                    }
+                }
+                ioprintf(io, "\t\t</Positions>\n");
+            }
+
+            // vertex normals
+            if (mesh->HasNormals()) {
+                ioprintf(io, "\t\t<Normals num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
+                                mesh->mNormals[n].x,
+                                mesh->mNormals[n].y,
+                                mesh->mNormals[n].z);
+                    }
+                }
+                ioprintf(io, "\t\t</Normals>\n");
+            }
+
+            // vertex tangents and bitangents
+            if (mesh->HasTangentsAndBitangents()) {
+                ioprintf(io, "\t\t<Tangents num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
+                                mesh->mTangents[n].x,
+                                mesh->mTangents[n].y,
+                                mesh->mTangents[n].z);
+                    }
+                }
+                ioprintf(io, "\t\t</Tangents>\n");
+
+                ioprintf(io, "\t\t<Bitangents num=\"%u\" set=\"0\" num_components=\"3\"> \n", mesh->mNumVertices);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
+                                mesh->mBitangents[n].x,
+                                mesh->mBitangents[n].y,
+                                mesh->mBitangents[n].z);
+                    }
+                }
+                ioprintf(io, "\t\t</Bitangents>\n");
+            }
+
+            // texture coordinates
+            for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
+                if (!mesh->mTextureCoords[a])
+                    break;
+
+                ioprintf(io, "\t\t<TextureCoords num=\"%u\" set=\"%u\" num_components=\"%u\"> \n", mesh->mNumVertices,
+                        a, mesh->mNumUVComponents[a]);
+
+                if (!shortened) {
+                    if (mesh->mNumUVComponents[a] == 3) {
+                        for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                            ioprintf(io, "\t\t%0 8f %0 8f %0 8f\n",
+                                    mesh->mTextureCoords[a][n].x,
+                                    mesh->mTextureCoords[a][n].y,
+                                    mesh->mTextureCoords[a][n].z);
+                        }
+                    } else {
+                        for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                            ioprintf(io, "\t\t%0 8f %0 8f\n",
+                                    mesh->mTextureCoords[a][n].x,
+                                    mesh->mTextureCoords[a][n].y);
+                        }
+                    }
+                }
+                ioprintf(io, "\t\t</TextureCoords>\n");
+            }
+
+            // vertex colors
+            for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
+                if (!mesh->mColors[a])
+                    break;
+                ioprintf(io, "\t\t<Colors num=\"%u\" set=\"%u\" num_components=\"4\"> \n", mesh->mNumVertices, a);
+                if (!shortened) {
+                    for (unsigned int n = 0; n < mesh->mNumVertices; ++n) {
+                        ioprintf(io, "\t\t%0 8f %0 8f %0 8f %0 8f\n",
+                                mesh->mColors[a][n].r,
+                                mesh->mColors[a][n].g,
+                                mesh->mColors[a][n].b,
+                                mesh->mColors[a][n].a);
+                    }
+                }
+                ioprintf(io, "\t\t</Colors>\n");
+            }
+            ioprintf(io, "\t</Mesh>\n");
+        }
+        ioprintf(io, "</MeshList>\n");
+    }
+    ioprintf(io, "</Scene>\n</ASSIMP>");
+}
+
+} // end of namespace AssxmlFileWriter
+
+void DumpSceneToAssxml(
+        const char *pFile, const char *cmd, IOSystem *pIOSystem,
+        const aiScene *pScene, bool shortened) {
+    std::unique_ptr<IOStream> file(pIOSystem->Open(pFile, "wt"));
+    if (!file.get()) {
+        throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n');
+    }
+
+    AssxmlFileWriter::WriteDump(pFile, cmd, pScene, file.get(), shortened);
+}
+
+} // end of namespace Assimp

+ 0 - 0
code/Assxml/AssxmlFileWriter.h → code/AssetLib/Assxml/AssxmlFileWriter.h


+ 744 - 0
code/AssetLib/B3D/B3DImporter.cpp

@@ -0,0 +1,744 @@
+/*
+---------------------------------------------------------------------------
+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  B3DImporter.cpp
+ *  @brief Implementation of the b3d importer class
+ */
+
+#ifndef ASSIMP_BUILD_NO_B3D_IMPORTER
+
+// internal headers
+#include "AssetLib/B3D/B3DImporter.h"
+#include "PostProcessing/ConvertToLHProcess.h"
+#include "PostProcessing/TextureTransform.h"
+
+#include <assimp/StringUtils.h>
+#include <assimp/anim.h>
+#include <assimp/importerdesc.h>
+#include <assimp/scene.h>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/IOSystem.hpp>
+
+#include <memory>
+
+using namespace Assimp;
+using namespace std;
+
+static const aiImporterDesc desc = {
+    "BlitzBasic 3D Importer",
+    "",
+    "",
+    "http://www.blitzbasic.com/",
+    aiImporterFlags_SupportBinaryFlavour,
+    0,
+    0,
+    0,
+    0,
+    "b3d"
+};
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4018)
+#endif
+
+//#define DEBUG_B3D
+
+template <typename T>
+void DeleteAllBarePointers(std::vector<T> &x) {
+    for (auto p : x) {
+        delete p;
+    }
+}
+
+B3DImporter::~B3DImporter() {
+}
+
+// ------------------------------------------------------------------------------------------------
+bool B3DImporter::CanRead(const std::string &pFile, IOSystem * /*pIOHandler*/, bool /*checkSig*/) const {
+
+    size_t pos = pFile.find_last_of('.');
+    if (pos == string::npos) {
+        return false;
+    }
+
+    string ext = pFile.substr(pos + 1);
+    if (ext.size() != 3) {
+        return false;
+    }
+
+    return (ext[0] == 'b' || ext[0] == 'B') && (ext[1] == '3') && (ext[2] == 'd' || ext[2] == 'D');
+}
+
+// ------------------------------------------------------------------------------------------------
+// Loader meta information
+const aiImporterDesc *B3DImporter::GetInfo() const {
+    return &desc;
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::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 B3D file " + pFile + ".");
+    }
+
+    // check whether the .b3d file is large enough to contain
+    // at least one chunk.
+    size_t fileSize = file->FileSize();
+    if (fileSize < 8) {
+        throw DeadlyImportError("B3D File is too small.");
+    }
+
+    _pos = 0;
+    _buf.resize(fileSize);
+    file->Read(&_buf[0], 1, fileSize);
+    _stack.clear();
+
+    ReadBB3D(pScene);
+}
+
+// ------------------------------------------------------------------------------------------------
+AI_WONT_RETURN void B3DImporter::Oops() {
+    throw DeadlyImportError("B3D Importer - INTERNAL ERROR");
+}
+
+// ------------------------------------------------------------------------------------------------
+AI_WONT_RETURN void B3DImporter::Fail(string str) {
+#ifdef DEBUG_B3D
+    ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
+#endif
+    throw DeadlyImportError("B3D Importer - error in B3D file data: " + str);
+}
+
+// ------------------------------------------------------------------------------------------------
+int B3DImporter::ReadByte() {
+    if (_pos > _buf.size()) {
+        Fail("EOF");
+    }
+
+    return _buf[_pos++];
+}
+
+// ------------------------------------------------------------------------------------------------
+int B3DImporter::ReadInt() {
+    if (_pos + 4 > _buf.size()) {
+        Fail("EOF");
+    }
+
+    int n;
+    memcpy(&n, &_buf[_pos], 4);
+    _pos += 4;
+
+    return n;
+}
+
+// ------------------------------------------------------------------------------------------------
+float B3DImporter::ReadFloat() {
+    if (_pos + 4 > _buf.size()) {
+        Fail("EOF");
+    }
+
+    float n;
+    memcpy(&n, &_buf[_pos], 4);
+    _pos += 4;
+
+    return n;
+}
+
+// ------------------------------------------------------------------------------------------------
+aiVector2D B3DImporter::ReadVec2() {
+    float x = ReadFloat();
+    float y = ReadFloat();
+    return aiVector2D(x, y);
+}
+
+// ------------------------------------------------------------------------------------------------
+aiVector3D B3DImporter::ReadVec3() {
+    float x = ReadFloat();
+    float y = ReadFloat();
+    float z = ReadFloat();
+    return aiVector3D(x, y, z);
+}
+
+// ------------------------------------------------------------------------------------------------
+aiQuaternion B3DImporter::ReadQuat() {
+    // (aramis_acg) Fix to adapt the loader to changed quat orientation
+    float w = -ReadFloat();
+    float x = ReadFloat();
+    float y = ReadFloat();
+    float z = ReadFloat();
+    return aiQuaternion(w, x, y, z);
+}
+
+// ------------------------------------------------------------------------------------------------
+string B3DImporter::ReadString() {
+    if (_pos > _buf.size()) {
+        Fail("EOF");
+    }
+    string str;
+    while (_pos < _buf.size()) {
+        char c = (char)ReadByte();
+        if (!c) {
+            return str;
+        }
+        str += c;
+    }
+    return string();
+}
+
+// ------------------------------------------------------------------------------------------------
+string B3DImporter::ReadChunk() {
+    string tag;
+    for (int i = 0; i < 4; ++i) {
+        tag += char(ReadByte());
+    }
+#ifdef DEBUG_B3D
+    ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag);
+#endif
+    unsigned sz = (unsigned)ReadInt();
+    _stack.push_back(_pos + sz);
+    return tag;
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ExitChunk() {
+    _pos = _stack.back();
+    _stack.pop_back();
+}
+
+// ------------------------------------------------------------------------------------------------
+size_t B3DImporter::ChunkSize() {
+    return _stack.back() - _pos;
+}
+// ------------------------------------------------------------------------------------------------
+
+template <class T>
+T *B3DImporter::to_array(const vector<T> &v) {
+    if (v.empty()) {
+        return 0;
+    }
+    T *p = new T[v.size()];
+    for (size_t i = 0; i < v.size(); ++i) {
+        p[i] = v[i];
+    }
+    return p;
+}
+
+// ------------------------------------------------------------------------------------------------
+template <class T>
+T **unique_to_array(vector<std::unique_ptr<T>> &v) {
+    if (v.empty()) {
+        return 0;
+    }
+    T **p = new T *[v.size()];
+    for (size_t i = 0; i < v.size(); ++i) {
+        p[i] = v[i].release();
+    }
+    return p;
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ReadTEXS() {
+    while (ChunkSize()) {
+        string name = ReadString();
+        /*int flags=*/ReadInt();
+        /*int blend=*/ReadInt();
+        /*aiVector2D pos=*/ReadVec2();
+        /*aiVector2D scale=*/ReadVec2();
+        /*float rot=*/ReadFloat();
+
+        _textures.push_back(name);
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ReadBRUS() {
+    int n_texs = ReadInt();
+    if (n_texs < 0 || n_texs > 8) {
+        Fail("Bad texture count");
+    }
+    while (ChunkSize()) {
+        string name = ReadString();
+        aiVector3D color = ReadVec3();
+        float alpha = ReadFloat();
+        float shiny = ReadFloat();
+        /*int blend=**/ ReadInt();
+        int fx = ReadInt();
+
+        std::unique_ptr<aiMaterial> mat(new aiMaterial);
+
+        // Name
+        aiString ainame(name);
+        mat->AddProperty(&ainame, AI_MATKEY_NAME);
+
+        // Diffuse color
+        mat->AddProperty(&color, 1, AI_MATKEY_COLOR_DIFFUSE);
+
+        // Opacity
+        mat->AddProperty(&alpha, 1, AI_MATKEY_OPACITY);
+
+        // Specular color
+        aiColor3D speccolor(shiny, shiny, shiny);
+        mat->AddProperty(&speccolor, 1, AI_MATKEY_COLOR_SPECULAR);
+
+        // Specular power
+        float specpow = shiny * 128;
+        mat->AddProperty(&specpow, 1, AI_MATKEY_SHININESS);
+
+        // Double sided
+        if (fx & 0x10) {
+            int i = 1;
+            mat->AddProperty(&i, 1, AI_MATKEY_TWOSIDED);
+        }
+
+        //Textures
+        for (int i = 0; i < n_texs; ++i) {
+            int texid = ReadInt();
+            if (texid < -1 || (texid >= 0 && texid >= static_cast<int>(_textures.size()))) {
+                Fail("Bad texture id");
+            }
+            if (i == 0 && texid >= 0) {
+                aiString texname(_textures[texid]);
+                mat->AddProperty(&texname, AI_MATKEY_TEXTURE_DIFFUSE(0));
+            }
+        }
+        _materials.emplace_back(std::move(mat));
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ReadVRTS() {
+    _vflags = ReadInt();
+    _tcsets = ReadInt();
+    _tcsize = ReadInt();
+    if (_tcsets < 0 || _tcsets > 4 || _tcsize < 0 || _tcsize > 4) {
+        Fail("Bad texcoord data");
+    }
+
+    int sz = 12 + (_vflags & 1 ? 12 : 0) + (_vflags & 2 ? 16 : 0) + (_tcsets * _tcsize * 4);
+    size_t n_verts = ChunkSize() / sz;
+
+    int v0 = static_cast<int>(_vertices.size());
+    _vertices.resize(v0 + n_verts);
+
+    for (unsigned int i = 0; i < n_verts; ++i) {
+        Vertex &v = _vertices[v0 + i];
+
+        memset(v.bones, 0, sizeof(v.bones));
+        memset(v.weights, 0, sizeof(v.weights));
+
+        v.vertex = ReadVec3();
+
+        if (_vflags & 1) {
+            v.normal = ReadVec3();
+        }
+
+        if (_vflags & 2) {
+            ReadQuat(); //skip v 4bytes...
+        }
+
+        for (int j = 0; j < _tcsets; ++j) {
+            float t[4] = { 0, 0, 0, 0 };
+            for (int k = 0; k < _tcsize; ++k) {
+                t[k] = ReadFloat();
+            }
+            t[1] = 1 - t[1];
+            if (!j) {
+                v.texcoords = aiVector3D(t[0], t[1], t[2]);
+            }
+        }
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ReadTRIS(int v0) {
+    int matid = ReadInt();
+    if (matid == -1) {
+        matid = 0;
+    } else if (matid < 0 || matid >= (int)_materials.size()) {
+#ifdef DEBUG_B3D
+        ASSIMP_LOG_ERROR_F("material id=", matid);
+#endif
+        Fail("Bad material id");
+    }
+
+    std::unique_ptr<aiMesh> mesh(new aiMesh);
+
+    mesh->mMaterialIndex = matid;
+    mesh->mNumFaces = 0;
+    mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+
+    size_t n_tris = ChunkSize() / 12;
+    aiFace *face = mesh->mFaces = new aiFace[n_tris];
+
+    for (unsigned int i = 0; i < n_tris; ++i) {
+        int i0 = ReadInt() + v0;
+        int i1 = ReadInt() + v0;
+        int i2 = ReadInt() + v0;
+        if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) {
+#ifdef DEBUG_B3D
+            ASSIMP_LOG_ERROR_F("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
+#endif
+            Fail("Bad triangle index");
+            continue;
+        }
+        face->mNumIndices = 3;
+        face->mIndices = new unsigned[3];
+        face->mIndices[0] = i0;
+        face->mIndices[1] = i1;
+        face->mIndices[2] = i2;
+        ++mesh->mNumFaces;
+        ++face;
+    }
+
+    _meshes.emplace_back(std::move(mesh));
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ReadMESH() {
+    /*int matid=*/ReadInt();
+
+    int v0 = static_cast<int>(_vertices.size());
+
+    while (ChunkSize()) {
+        string t = ReadChunk();
+        if (t == "VRTS") {
+            ReadVRTS();
+        } else if (t == "TRIS") {
+            ReadTRIS(v0);
+        }
+        ExitChunk();
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ReadBONE(int id) {
+    while (ChunkSize()) {
+        int vertex = ReadInt();
+        float weight = ReadFloat();
+        if (vertex < 0 || vertex >= (int)_vertices.size()) {
+            Fail("Bad vertex index");
+        }
+
+        Vertex &v = _vertices[vertex];
+        for (int i = 0; i < 4; ++i) {
+            if (!v.weights[i]) {
+                v.bones[i] = static_cast<unsigned char>(id);
+                v.weights[i] = weight;
+                break;
+            }
+        }
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ReadKEYS(aiNodeAnim *nodeAnim) {
+    vector<aiVectorKey> trans, scale;
+    vector<aiQuatKey> rot;
+    int flags = ReadInt();
+    while (ChunkSize()) {
+        int frame = ReadInt();
+        if (flags & 1) {
+            trans.push_back(aiVectorKey(frame, ReadVec3()));
+        }
+        if (flags & 2) {
+            scale.push_back(aiVectorKey(frame, ReadVec3()));
+        }
+        if (flags & 4) {
+            rot.push_back(aiQuatKey(frame, ReadQuat()));
+        }
+    }
+
+    if (flags & 1) {
+        nodeAnim->mNumPositionKeys = static_cast<unsigned int>(trans.size());
+        nodeAnim->mPositionKeys = to_array(trans);
+    }
+
+    if (flags & 2) {
+        nodeAnim->mNumScalingKeys = static_cast<unsigned int>(scale.size());
+        nodeAnim->mScalingKeys = to_array(scale);
+    }
+
+    if (flags & 4) {
+        nodeAnim->mNumRotationKeys = static_cast<unsigned int>(rot.size());
+        nodeAnim->mRotationKeys = to_array(rot);
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ReadANIM() {
+    /*int flags=*/ReadInt();
+    int frames = ReadInt();
+    float fps = ReadFloat();
+
+    std::unique_ptr<aiAnimation> anim(new aiAnimation);
+
+    anim->mDuration = frames;
+    anim->mTicksPerSecond = fps;
+    _animations.emplace_back(std::move(anim));
+}
+
+// ------------------------------------------------------------------------------------------------
+aiNode *B3DImporter::ReadNODE(aiNode *parent) {
+
+    string name = ReadString();
+    aiVector3D t = ReadVec3();
+    aiVector3D s = ReadVec3();
+    aiQuaternion r = ReadQuat();
+
+    aiMatrix4x4 trans, scale, rot;
+
+    aiMatrix4x4::Translation(t, trans);
+    aiMatrix4x4::Scaling(s, scale);
+    rot = aiMatrix4x4(r.GetMatrix());
+
+    aiMatrix4x4 tform = trans * rot * scale;
+
+    int nodeid = static_cast<int>(_nodes.size());
+
+    aiNode *node = new aiNode(name);
+    _nodes.push_back(node);
+
+    node->mParent = parent;
+    node->mTransformation = tform;
+
+    std::unique_ptr<aiNodeAnim> nodeAnim;
+    vector<unsigned> meshes;
+    vector<aiNode *> children;
+
+    while (ChunkSize()) {
+        const string chunk = ReadChunk();
+        if (chunk == "MESH") {
+            unsigned int n = static_cast<unsigned int>(_meshes.size());
+            ReadMESH();
+            for (unsigned int i = n; i < static_cast<unsigned int>(_meshes.size()); ++i) {
+                meshes.push_back(i);
+            }
+        } else if (chunk == "BONE") {
+            ReadBONE(nodeid);
+        } else if (chunk == "ANIM") {
+            ReadANIM();
+        } else if (chunk == "KEYS") {
+            if (!nodeAnim) {
+                nodeAnim.reset(new aiNodeAnim);
+                nodeAnim->mNodeName = node->mName;
+            }
+            ReadKEYS(nodeAnim.get());
+        } else if (chunk == "NODE") {
+            aiNode *child = ReadNODE(node);
+            children.push_back(child);
+        }
+        ExitChunk();
+    }
+
+    if (nodeAnim) {
+        _nodeAnims.emplace_back(std::move(nodeAnim));
+    }
+
+    node->mNumMeshes = static_cast<unsigned int>(meshes.size());
+    node->mMeshes = to_array(meshes);
+
+    node->mNumChildren = static_cast<unsigned int>(children.size());
+    node->mChildren = to_array(children);
+
+    return node;
+}
+
+// ------------------------------------------------------------------------------------------------
+void B3DImporter::ReadBB3D(aiScene *scene) {
+
+    _textures.clear();
+
+    _materials.clear();
+
+    _vertices.clear();
+
+    _meshes.clear();
+
+    DeleteAllBarePointers(_nodes);
+    _nodes.clear();
+
+    _nodeAnims.clear();
+
+    _animations.clear();
+
+    string t = ReadChunk();
+    if (t == "BB3D") {
+        int version = ReadInt();
+
+        if (!DefaultLogger::isNullLogger()) {
+            char dmp[128];
+            ai_snprintf(dmp, 128, "B3D file format version: %i", version);
+            ASSIMP_LOG_INFO(dmp);
+        }
+
+        while (ChunkSize()) {
+            const string chunk = ReadChunk();
+            if (chunk == "TEXS") {
+                ReadTEXS();
+            } else if (chunk == "BRUS") {
+                ReadBRUS();
+            } else if (chunk == "NODE") {
+                ReadNODE(0);
+            }
+            ExitChunk();
+        }
+    }
+    ExitChunk();
+
+    if (!_nodes.size()) {
+        Fail("No nodes");
+    }
+
+    if (!_meshes.size()) {
+        Fail("No meshes");
+    }
+
+    // Fix nodes/meshes/bones
+    for (size_t i = 0; i < _nodes.size(); ++i) {
+        aiNode *node = _nodes[i];
+
+        for (size_t j = 0; j < node->mNumMeshes; ++j) {
+            aiMesh *mesh = _meshes[node->mMeshes[j]].get();
+
+            int n_tris = mesh->mNumFaces;
+            int n_verts = mesh->mNumVertices = n_tris * 3;
+
+            aiVector3D *mv = mesh->mVertices = new aiVector3D[n_verts], *mn = 0, *mc = 0;
+            if (_vflags & 1) {
+                mn = mesh->mNormals = new aiVector3D[n_verts];
+            }
+            if (_tcsets) {
+                mc = mesh->mTextureCoords[0] = new aiVector3D[n_verts];
+            }
+
+            aiFace *face = mesh->mFaces;
+
+            vector<vector<aiVertexWeight>> vweights(_nodes.size());
+
+            for (int vertIdx = 0; vertIdx < n_verts; vertIdx += 3) {
+                for (int faceIndex = 0; faceIndex < 3; ++faceIndex) {
+                    Vertex &v = _vertices[face->mIndices[faceIndex]];
+
+                    *mv++ = v.vertex;
+                    if (mn) *mn++ = v.normal;
+                    if (mc) *mc++ = v.texcoords;
+
+                    face->mIndices[faceIndex] = vertIdx + faceIndex;
+
+                    for (int k = 0; k < 4; ++k) {
+                        if (!v.weights[k])
+                            break;
+
+                        int bone = v.bones[k];
+                        float weight = v.weights[k];
+
+                        vweights[bone].push_back(aiVertexWeight(vertIdx + faceIndex, weight));
+                    }
+                }
+                ++face;
+            }
+
+            vector<aiBone *> bones;
+            for (size_t weightIndx = 0; weightIndx < vweights.size(); ++weightIndx) {
+                vector<aiVertexWeight> &weights = vweights[weightIndx];
+                if (!weights.size()) {
+                    continue;
+                }
+
+                aiBone *bone = new aiBone;
+                bones.push_back(bone);
+
+                aiNode *bnode = _nodes[weightIndx];
+
+                bone->mName = bnode->mName;
+                bone->mNumWeights = static_cast<unsigned int>(weights.size());
+                bone->mWeights = to_array(weights);
+
+                aiMatrix4x4 mat = bnode->mTransformation;
+                while (bnode->mParent) {
+                    bnode = bnode->mParent;
+                    mat = bnode->mTransformation * mat;
+                }
+                bone->mOffsetMatrix = mat.Inverse();
+            }
+            mesh->mNumBones = static_cast<unsigned int>(bones.size());
+            mesh->mBones = to_array(bones);
+        }
+    }
+
+    //nodes
+    scene->mRootNode = _nodes[0];
+    _nodes.clear(); // node ownership now belongs to scene
+
+    //material
+    if (!_materials.size()) {
+        _materials.emplace_back(std::unique_ptr<aiMaterial>(new aiMaterial));
+    }
+    scene->mNumMaterials = static_cast<unsigned int>(_materials.size());
+    scene->mMaterials = unique_to_array(_materials);
+
+    //meshes
+    scene->mNumMeshes = static_cast<unsigned int>(_meshes.size());
+    scene->mMeshes = unique_to_array(_meshes);
+
+    //animations
+    if (_animations.size() == 1 && _nodeAnims.size()) {
+
+        aiAnimation *anim = _animations.back().get();
+        anim->mNumChannels = static_cast<unsigned int>(_nodeAnims.size());
+        anim->mChannels = unique_to_array(_nodeAnims);
+
+        scene->mNumAnimations = static_cast<unsigned int>(_animations.size());
+        scene->mAnimations = unique_to_array(_animations);
+    }
+
+    // convert to RH
+    MakeLeftHandedProcess makeleft;
+    makeleft.Execute(scene);
+
+    FlipWindingOrderProcess flip;
+    flip.Execute(scene);
+}
+
+#endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER

+ 0 - 0
code/B3D/B3DImporter.h → code/AssetLib/B3D/B3DImporter.h


+ 201 - 245
code/BVH/BVHLoader.cpp → code/AssetLib/BVH/BVHLoader.cpp

@@ -42,19 +42,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
 
-
 #ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
 
 #include "BVHLoader.h"
-#include <assimp/fast_atof.h>
 #include <assimp/SkeletonMeshBuilder.h>
-#include <assimp/Importer.hpp>
-#include <memory>
 #include <assimp/TinyFormatter.h>
-#include <assimp/IOSystem.hpp>
-#include <assimp/scene.h>
+#include <assimp/fast_atof.h>
 #include <assimp/importerdesc.h>
+#include <assimp/scene.h>
+#include <assimp/IOSystem.hpp>
+#include <assimp/Importer.hpp>
 #include <map>
+#include <memory>
 
 using namespace Assimp;
 using namespace Assimp::Formatter;
@@ -74,56 +73,50 @@ static const aiImporterDesc desc = {
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-BVHLoader::BVHLoader()
-    : mLine(),
-    mAnimTickDuration(),
-    mAnimNumFrames(),
-    noSkeletonMesh()
-{}
+BVHLoader::BVHLoader() :
+        mLine(),
+        mAnimTickDuration(),
+        mAnimNumFrames(),
+        noSkeletonMesh() {}
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
-BVHLoader::~BVHLoader()
-{}
+BVHLoader::~BVHLoader() {}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const
-{
+bool BVHLoader::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const {
     // check file extension
     const std::string extension = GetExtension(pFile);
 
-    if( extension == "bvh")
+    if (extension == "bvh")
         return true;
 
     if ((!extension.length() || cs) && pIOHandler) {
-        const char* tokens[] = {"HIERARCHY"};
-        return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
+        const char *tokens[] = { "HIERARCHY" };
+        return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
     }
     return false;
 }
 
 // ------------------------------------------------------------------------------------------------
-void BVHLoader::SetupProperties(const Importer* pImp)
-{
-    noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
+void BVHLoader::SetupProperties(const Importer *pImp) {
+    noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Loader meta information
-const aiImporterDesc* BVHLoader::GetInfo () const
-{
+const aiImporterDesc *BVHLoader::GetInfo() const {
     return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
-void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
-{
+void BVHLoader::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
     mFileName = pFile;
 
     // read file into memory
-    std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
+    std::unique_ptr<IOStream> file(pIOHandler->Open(pFile));
     if (file.get() == nullptr) {
         throw DeadlyImportError("Failed to open file " + pFile + ".");
     }
@@ -133,47 +126,45 @@ void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSys
         throw DeadlyImportError("File is too small.");
     }
 
-    mBuffer.resize( fileSize);
-    file->Read( &mBuffer.front(), 1, fileSize);
+    mBuffer.resize(fileSize);
+    file->Read(&mBuffer.front(), 1, fileSize);
 
     // start reading
     mReader = mBuffer.begin();
     mLine = 1;
-    ReadStructure( pScene);
+    ReadStructure(pScene);
 
     if (!noSkeletonMesh) {
         // build a dummy mesh for the skeleton so that we see something at least
-        SkeletonMeshBuilder meshBuilder( pScene);
+        SkeletonMeshBuilder meshBuilder(pScene);
     }
 
     // construct an animation from all the motion data we read
-    CreateAnimation( pScene);
+    CreateAnimation(pScene);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the file
-void BVHLoader::ReadStructure( aiScene* pScene)
-{
+void BVHLoader::ReadStructure(aiScene *pScene) {
     // first comes hierarchy
     std::string header = GetNextToken();
-    if( header != "HIERARCHY")
-        ThrowException( "Expected header string \"HIERARCHY\".");
-    ReadHierarchy( pScene);
+    if (header != "HIERARCHY")
+        ThrowException("Expected header string \"HIERARCHY\".");
+    ReadHierarchy(pScene);
 
     // then comes the motion data
     std::string motion = GetNextToken();
-    if( motion != "MOTION")
-        ThrowException( "Expected beginning of motion data \"MOTION\".");
-    ReadMotion( pScene);
+    if (motion != "MOTION")
+        ThrowException("Expected beginning of motion data \"MOTION\".");
+    ReadMotion(pScene);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the hierarchy
-void BVHLoader::ReadHierarchy( aiScene* pScene)
-{
+void BVHLoader::ReadHierarchy(aiScene *pScene) {
     std::string root = GetNextToken();
-    if( root != "ROOT")
-        ThrowException( "Expected root node \"ROOT\".");
+    if (root != "ROOT")
+        ThrowException("Expected root node \"ROOT\".");
 
     // Go read the hierarchy from here
     pScene->mRootNode = ReadNode();
@@ -181,73 +172,64 @@ void BVHLoader::ReadHierarchy( aiScene* pScene)
 
 // ------------------------------------------------------------------------------------------------
 // Reads a node and recursively its childs and returns the created node;
-aiNode* BVHLoader::ReadNode()
-{
+aiNode *BVHLoader::ReadNode() {
     // first token is name
     std::string nodeName = GetNextToken();
-    if( nodeName.empty() || nodeName == "{")
-        ThrowException( format() << "Expected node name, but found \"" << nodeName << "\"." );
+    if (nodeName.empty() || nodeName == "{")
+        ThrowException(format() << "Expected node name, but found \"" << nodeName << "\".");
 
     // then an opening brace should follow
     std::string openBrace = GetNextToken();
-    if( openBrace != "{")
-        ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\"." );
+    if (openBrace != "{")
+        ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
 
     // Create a node
-    aiNode* node = new aiNode( nodeName);
-    std::vector<aiNode*> childNodes;
+    aiNode *node = new aiNode(nodeName);
+    std::vector<aiNode *> childNodes;
 
     // and create an bone entry for it
-    mNodes.push_back( Node( node));
-    Node& internNode = mNodes.back();
+    mNodes.push_back(Node(node));
+    Node &internNode = mNodes.back();
 
     // now read the node's contents
     std::string siteToken;
-    while( 1)
-    {
+    while (1) {
         std::string token = GetNextToken();
 
         // node offset to parent node
-        if( token == "OFFSET")
-            ReadNodeOffset( node);
-        else if( token == "CHANNELS")
-            ReadNodeChannels( internNode);
-        else if( token == "JOINT")
-        {
+        if (token == "OFFSET")
+            ReadNodeOffset(node);
+        else if (token == "CHANNELS")
+            ReadNodeChannels(internNode);
+        else if (token == "JOINT") {
             // child node follows
-            aiNode* child = ReadNode();
+            aiNode *child = ReadNode();
             child->mParent = node;
-            childNodes.push_back( child);
-        }
-        else if( token == "End")
-        {
+            childNodes.push_back(child);
+        } else if (token == "End") {
             // The real symbol is "End Site". Second part comes in a separate token
             siteToken.clear();
             siteToken = GetNextToken();
-            if( siteToken != "Site")
-                ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
+            if (siteToken != "Site")
+                ThrowException(format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\".");
 
-            aiNode* child = ReadEndSite( nodeName);
+            aiNode *child = ReadEndSite(nodeName);
             child->mParent = node;
-            childNodes.push_back( child);
-        }
-        else if( token == "}")
-        {
+            childNodes.push_back(child);
+        } else if (token == "}") {
             // we're done with that part of the hierarchy
             break;
-        } else
-        {
+        } else {
             // everything else is a parse error
-            ThrowException( format() << "Unknown keyword \"" << token << "\"." );
+            ThrowException(format() << "Unknown keyword \"" << token << "\".");
         }
     }
 
     // add the child nodes if there are any
-    if( childNodes.size() > 0)
-    {
+    if (childNodes.size() > 0) {
         node->mNumChildren = static_cast<unsigned int>(childNodes.size());
-        node->mChildren = new aiNode*[node->mNumChildren];
-        std::copy( childNodes.begin(), childNodes.end(), node->mChildren);
+        node->mChildren = new aiNode *[node->mNumChildren];
+        std::copy(childNodes.begin(), childNodes.end(), node->mChildren);
     }
 
     // and return the sub-hierarchy we built here
@@ -256,31 +238,30 @@ aiNode* BVHLoader::ReadNode()
 
 // ------------------------------------------------------------------------------------------------
 // Reads an end node and returns the created node.
-aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
-{
+aiNode *BVHLoader::ReadEndSite(const std::string &pParentName) {
     // check opening brace
     std::string openBrace = GetNextToken();
-    if( openBrace != "{")
-        ThrowException( format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
+    if (openBrace != "{")
+        ThrowException(format() << "Expected opening brace \"{\", but found \"" << openBrace << "\".");
 
     // Create a node
-    aiNode* node = new aiNode( "EndSite_" + pParentName);
+    aiNode *node = new aiNode("EndSite_" + pParentName);
 
     // now read the node's contents. Only possible entry is "OFFSET"
     std::string token;
-    while( 1) {
+    while (1) {
         token.clear();
         token = GetNextToken();
 
         // end node's offset
-        if( token == "OFFSET") {
-            ReadNodeOffset( node);
-        } else if( token == "}") {
+        if (token == "OFFSET") {
+            ReadNodeOffset(node);
+        } else if (token == "}") {
             // we're done with the end node
             break;
         } else {
             // everything else is a parse error
-            ThrowException( format() << "Unknown keyword \"" << token << "\"." );
+            ThrowException(format() << "Unknown keyword \"" << token << "\".");
         }
     }
 
@@ -289,8 +270,7 @@ aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
 }
 // ------------------------------------------------------------------------------------------------
 // Reads a node offset for the given node
-void BVHLoader::ReadNodeOffset( aiNode* pNode)
-{
+void BVHLoader::ReadNodeOffset(aiNode *pNode) {
     // Offset consists of three floats to read
     aiVector3D offset;
     offset.x = GetNextTokenAsFloat();
@@ -298,74 +278,69 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
     offset.z = GetNextTokenAsFloat();
 
     // build a transformation matrix from it
-    pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x,
-                                          0.0f, 1.0f, 0.0f, offset.y,
-                                          0.0f, 0.0f, 1.0f, offset.z,
-                                          0.0f, 0.0f, 0.0f, 1.0f);
+    pNode->mTransformation = aiMatrix4x4(1.0f, 0.0f, 0.0f, offset.x,
+            0.0f, 1.0f, 0.0f, offset.y,
+            0.0f, 0.0f, 1.0f, offset.z,
+            0.0f, 0.0f, 0.0f, 1.0f);
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the animation channels for the given node
-void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode)
-{
+void BVHLoader::ReadNodeChannels(BVHLoader::Node &pNode) {
     // number of channels. Use the float reader because we're lazy
     float numChannelsFloat = GetNextTokenAsFloat();
-    unsigned int numChannels = (unsigned int) numChannelsFloat;
+    unsigned int numChannels = (unsigned int)numChannelsFloat;
 
-    for( unsigned int a = 0; a < numChannels; a++)
-    {
+    for (unsigned int a = 0; a < numChannels; a++) {
         std::string channelToken = GetNextToken();
 
-        if( channelToken == "Xposition")
-            pNode.mChannels.push_back( Channel_PositionX);
-        else if( channelToken == "Yposition")
-            pNode.mChannels.push_back( Channel_PositionY);
-        else if( channelToken == "Zposition")
-            pNode.mChannels.push_back( Channel_PositionZ);
-        else if( channelToken == "Xrotation")
-            pNode.mChannels.push_back( Channel_RotationX);
-        else if( channelToken == "Yrotation")
-            pNode.mChannels.push_back( Channel_RotationY);
-        else if( channelToken == "Zrotation")
-            pNode.mChannels.push_back( Channel_RotationZ);
+        if (channelToken == "Xposition")
+            pNode.mChannels.push_back(Channel_PositionX);
+        else if (channelToken == "Yposition")
+            pNode.mChannels.push_back(Channel_PositionY);
+        else if (channelToken == "Zposition")
+            pNode.mChannels.push_back(Channel_PositionZ);
+        else if (channelToken == "Xrotation")
+            pNode.mChannels.push_back(Channel_RotationX);
+        else if (channelToken == "Yrotation")
+            pNode.mChannels.push_back(Channel_RotationY);
+        else if (channelToken == "Zrotation")
+            pNode.mChannels.push_back(Channel_RotationZ);
         else
-            ThrowException( format() << "Invalid channel specifier \"" << channelToken << "\"." );
+            ThrowException(format() << "Invalid channel specifier \"" << channelToken << "\".");
     }
 }
 
 // ------------------------------------------------------------------------------------------------
 // Reads the motion data
-void BVHLoader::ReadMotion( aiScene* /*pScene*/)
-{
+void BVHLoader::ReadMotion(aiScene * /*pScene*/) {
     // Read number of frames
     std::string tokenFrames = GetNextToken();
-    if( tokenFrames != "Frames:")
-        ThrowException( format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
+    if (tokenFrames != "Frames:")
+        ThrowException(format() << "Expected frame count \"Frames:\", but found \"" << tokenFrames << "\".");
 
     float numFramesFloat = GetNextTokenAsFloat();
-    mAnimNumFrames = (unsigned int) numFramesFloat;
+    mAnimNumFrames = (unsigned int)numFramesFloat;
 
     // Read frame duration
     std::string tokenDuration1 = GetNextToken();
     std::string tokenDuration2 = GetNextToken();
-    if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
-        ThrowException( format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\"." );
+    if (tokenDuration1 != "Frame" || tokenDuration2 != "Time:")
+        ThrowException(format() << "Expected frame duration \"Frame Time:\", but found \"" << tokenDuration1 << " " << tokenDuration2 << "\".");
 
     mAnimTickDuration = GetNextTokenAsFloat();
 
     // resize value vectors for each node
-    for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
-        it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames);
+    for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
+        it->mChannelValues.reserve(it->mChannels.size() * mAnimNumFrames);
 
     // now read all the data and store it in the corresponding node's value vector
-    for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame)
-    {
+    for (unsigned int frame = 0; frame < mAnimNumFrames; ++frame) {
         // on each line read the values for all nodes
-        for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
-        {
+        for (std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) {
             // get as many values as the node has channels
-            for( unsigned int c = 0; c < it->mChannels.size(); ++c)
-                it->mChannelValues.push_back( GetNextTokenAsFloat());
+            for (unsigned int c = 0; c < it->mChannels.size(); ++c)
+                it->mChannelValues.push_back(GetNextTokenAsFloat());
         }
 
         // after one frame worth of values for all nodes there should be a newline, but we better don't rely on it
@@ -374,16 +349,14 @@ void BVHLoader::ReadMotion( aiScene* /*pScene*/)
 
 // ------------------------------------------------------------------------------------------------
 // Retrieves the next token
-std::string BVHLoader::GetNextToken()
-{
+std::string BVHLoader::GetNextToken() {
     // skip any preceding whitespace
-    while( mReader != mBuffer.end())
-    {
-        if( !isspace( *mReader))
+    while (mReader != mBuffer.end()) {
+        if (!isspace(*mReader))
             break;
 
         // count lines
-        if( *mReader == '\n')
+        if (*mReader == '\n')
             mLine++;
 
         ++mReader;
@@ -391,16 +364,15 @@ std::string BVHLoader::GetNextToken()
 
     // collect all chars till the next whitespace. BVH is easy in respect to that.
     std::string token;
-    while( mReader != mBuffer.end())
-    {
-        if( isspace( *mReader))
+    while (mReader != mBuffer.end()) {
+        if (isspace(*mReader))
             break;
 
-        token.push_back( *mReader);
+        token.push_back(*mReader);
         ++mReader;
 
         // little extra logic to make sure braces are counted correctly
-        if( token == "{" || token == "}")
+        if (token == "{" || token == "}")
             break;
     }
 
@@ -410,111 +382,101 @@ std::string BVHLoader::GetNextToken()
 
 // ------------------------------------------------------------------------------------------------
 // Reads the next token as a float
-float BVHLoader::GetNextTokenAsFloat()
-{
+float BVHLoader::GetNextTokenAsFloat() {
     std::string token = GetNextToken();
-    if( token.empty())
-        ThrowException( "Unexpected end of file while trying to read a float");
+    if (token.empty())
+        ThrowException("Unexpected end of file while trying to read a float");
 
     // check if the float is valid by testing if the atof() function consumed every char of the token
-    const char* ctoken = token.c_str();
+    const char *ctoken = token.c_str();
     float result = 0.0f;
-    ctoken = fast_atoreal_move<float>( ctoken, result);
+    ctoken = fast_atoreal_move<float>(ctoken, result);
 
-    if( ctoken != token.c_str() + token.length())
-        ThrowException( format() << "Expected a floating point number, but found \"" << token << "\"." );
+    if (ctoken != token.c_str() + token.length())
+        ThrowException(format() << "Expected a floating point number, but found \"" << token << "\".");
 
     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);
+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
-void BVHLoader::CreateAnimation( aiScene* pScene)
-{
+void BVHLoader::CreateAnimation(aiScene *pScene) {
     // create the animation
     pScene->mNumAnimations = 1;
-    pScene->mAnimations = new aiAnimation*[1];
-    aiAnimation* anim = new aiAnimation;
+    pScene->mAnimations = new aiAnimation *[1];
+    aiAnimation *anim = new aiAnimation;
     pScene->mAnimations[0] = anim;
 
     // put down the basic parameters
-    anim->mName.Set( "Motion");
-    anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration);
-    anim->mDuration = double( mAnimNumFrames - 1);
+    anim->mName.Set("Motion");
+    anim->mTicksPerSecond = 1.0 / double(mAnimTickDuration);
+    anim->mDuration = double(mAnimNumFrames - 1);
 
     // now generate the tracks for all nodes
     anim->mNumChannels = static_cast<unsigned int>(mNodes.size());
-    anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
+    anim->mChannels = new aiNodeAnim *[anim->mNumChannels];
 
-    // FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown
-    for (unsigned int i = 0; i < anim->mNumChannels;++i)
-        anim->mChannels[i] = NULL;
+    // FIX: set the array elements to nullptr to ensure proper deletion if an exception is thrown
+    for (unsigned int i = 0; i < anim->mNumChannels; ++i)
+        anim->mChannels[i] = nullptr;
 
-    for( unsigned int a = 0; a < anim->mNumChannels; a++)
-    {
-        const Node& node = mNodes[a];
-        const std::string nodeName = std::string( node.mNode->mName.data );
-        aiNodeAnim* nodeAnim = new aiNodeAnim;
+    for (unsigned int a = 0; a < anim->mNumChannels; a++) {
+        const Node &node = mNodes[a];
+        const std::string nodeName = std::string(node.mNode->mName.data);
+        aiNodeAnim *nodeAnim = new aiNodeAnim;
         anim->mChannels[a] = nodeAnim;
-        nodeAnim->mNodeName.Set( nodeName);
-		std::map<BVHLoader::ChannelType, int> channelMap;
+        nodeAnim->mNodeName.Set(nodeName);
+        std::map<BVHLoader::ChannelType, int> channelMap;
 
-		//Build map of channels 
-		for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel)
-		{
-			channelMap[node.mChannels[channel]] = channel;
-		}
+        //Build map of channels
+        for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel) {
+            channelMap[node.mChannels[channel]] = channel;
+        }
 
         // translational part, if given
-        if( node.mChannels.size() == 6)
-        {
+        if (node.mChannels.size() == 6) {
             nodeAnim->mNumPositionKeys = mAnimNumFrames;
             nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames];
-            aiVectorKey* poskey = nodeAnim->mPositionKeys;
-            for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
-            {
-                poskey->mTime = double( fr);
-
-                // Now compute all translations 
-                for(BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel +1))
-                {
-					//Find channel in node
-					std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
-
-					if (mapIter == channelMap.end())
-						throw DeadlyImportError("Missing position channel in node " + nodeName);
-					else {
-						int channelIdx = mapIter->second;
-						switch (channel) {
-						    case Channel_PositionX: 
-                                poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; 
-                                break;
-						    case Channel_PositionY: 
-                                poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; 
-                                break;
-						    case Channel_PositionZ: 
-                                poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; 
-                                break;
-                                
-                            default:
-                                break;
-						}
-
-					}
+            aiVectorKey *poskey = nodeAnim->mPositionKeys;
+            for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
+                poskey->mTime = double(fr);
+
+                // Now compute all translations
+                for (BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel + 1)) {
+                    //Find channel in node
+                    std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
+
+                    if (mapIter == channelMap.end())
+                        throw DeadlyImportError("Missing position channel in node " + nodeName);
+                    else {
+                        int channelIdx = mapIter->second;
+                        switch (channel) {
+                        case Channel_PositionX:
+                            poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
+                            break;
+                        case Channel_PositionY:
+                            poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
+                            break;
+                        case Channel_PositionZ:
+                            poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx];
+                            break;
+
+                        default:
+                            break;
+                        }
+                    }
                 }
                 ++poskey;
             }
-        } else
-        {
+        } else {
             // if no translation part is given, put a default sequence
-            aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
+            aiVector3D nodePos(node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4);
             nodeAnim->mNumPositionKeys = 1;
             nodeAnim->mPositionKeys = new aiVectorKey[1];
             nodeAnim->mPositionKeys[0].mTime = 0.0;
@@ -527,42 +489,36 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
             // Then create the number of rotation keys
             nodeAnim->mNumRotationKeys = mAnimNumFrames;
             nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames];
-            aiQuatKey* rotkey = nodeAnim->mRotationKeys;
-            for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr)
-            {
+            aiQuatKey *rotkey = nodeAnim->mRotationKeys;
+            for (unsigned int fr = 0; fr < mAnimNumFrames; ++fr) {
                 aiMatrix4x4 temp;
                 aiMatrix3x3 rotMatrix;
-				for (BVHLoader::ChannelType channel = Channel_RotationX; channel <= Channel_RotationZ; channel = (BVHLoader::ChannelType)(channel + 1))
-				{
-					//Find channel in node
-					std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
-
-					if (mapIter == channelMap.end())
-						throw DeadlyImportError("Missing rotation channel in node " + nodeName);
-					else {
-						int channelIdx = mapIter->second;
-						// translate ZXY euler angels into a quaternion
-						const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
-
-						// Compute rotation transformations in the right order
-						switch (channel)
-						{
-							case Channel_RotationX: 
-                                aiMatrix4x4::RotationX(angle, temp); rotMatrix *= aiMatrix3x3(temp); 
-                                break;
-							case Channel_RotationY: 
-                                aiMatrix4x4::RotationY(angle, temp); rotMatrix *= aiMatrix3x3(temp);  
-                                break;
-							case Channel_RotationZ: aiMatrix4x4::RotationZ(angle, temp); rotMatrix *= aiMatrix3x3(temp); 
-                                break;
-                            default:
-                                break;
-						}
+				for (unsigned int channelIdx = 0; channelIdx < node.mChannels.size(); ++ channelIdx) {
+					switch (node.mChannels[channelIdx]) {
+                    case Channel_RotationX:
+                        {
+                        const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
+                        aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp);
+                        }
+                        break;
+                    case Channel_RotationY:
+                        {
+                        const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
+                        aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);
+                        }
+                        break;
+                    case Channel_RotationZ:
+                        {
+                        const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
+                        aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp);
+                        }
+                        break;
+                    default:
+                        break;
 					}
-                }
-
-                rotkey->mTime = double( fr);
-                rotkey->mValue = aiQuaternion( rotMatrix);
+				}
+                rotkey->mTime = double(fr);
+                rotkey->mValue = aiQuaternion(rotMatrix);
                 ++rotkey;
             }
         }
@@ -572,7 +528,7 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
             nodeAnim->mNumScalingKeys = 1;
             nodeAnim->mScalingKeys = new aiVectorKey[1];
             nodeAnim->mScalingKeys[0].mTime = 0.0;
-            nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f);
+            nodeAnim->mScalingKeys[0].mValue.Set(1.0f, 1.0f, 1.0f);
         }
     }
 }

+ 22 - 29
code/BVH/BVHLoader.h → code/AssetLib/BVH/BVHLoader.h

@@ -53,8 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 struct aiNode;
 
-namespace Assimp
-{
+namespace Assimp {
 
 // --------------------------------------------------------------------------------
 /** Loader class to read Motion Capturing data from a .bvh file.
@@ -63,12 +62,10 @@ namespace Assimp
  * the hierarchy. It contains no actual mesh data, but we generate a dummy mesh
  * inside the loader just to be able to see something.
 */
-class BVHLoader : public BaseImporter
-{
+class BVHLoader : public BaseImporter {
 
     /** Possible animation channels for which the motion data holds the values */
-    enum ChannelType
-    {
+    enum ChannelType {
         Channel_PositionX,
         Channel_PositionY,
         Channel_PositionZ,
@@ -78,61 +75,57 @@ class BVHLoader : public BaseImporter
     };
 
     /** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */
-    struct Node
-    {
-        const aiNode* mNode;
+    struct Node {
+        const aiNode *mNode;
         std::vector<ChannelType> mChannels;
         std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
 
-        Node()
-        : mNode(nullptr)
-        { }
+        Node() :
+                mNode(nullptr) {}
 
-        explicit Node( const aiNode* pNode) : mNode( pNode) { }
+        explicit Node(const aiNode *pNode) :
+                mNode(pNode) {}
     };
 
 public:
-
     BVHLoader();
     ~BVHLoader();
 
 public:
     /** Returns whether the class can handle the format of the given file.
      * See BaseImporter::CanRead() for details. */
-    bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const;
+    bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool cs) const;
 
-    void SetupProperties(const Importer* pImp);
-    const aiImporterDesc* GetInfo () const;
+    void SetupProperties(const Importer *pImp);
+    const aiImporterDesc *GetInfo() const;
 
 protected:
-
-
     /** Imports the given file into the given scene structure.
      * 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);
 
 protected:
     /** Reads the file */
-    void ReadStructure( aiScene* pScene);
+    void ReadStructure(aiScene *pScene);
 
     /** Reads the hierarchy */
-    void ReadHierarchy( aiScene* pScene);
+    void ReadHierarchy(aiScene *pScene);
 
     /** Reads a node and recursively its childs and returns the created node. */
-    aiNode* ReadNode();
+    aiNode *ReadNode();
 
     /** Reads an end node and returns the created node. */
-    aiNode* ReadEndSite( const std::string& pParentName);
+    aiNode *ReadEndSite(const std::string &pParentName);
 
     /** Reads a node offset for the given node */
-    void ReadNodeOffset( aiNode* pNode);
+    void ReadNodeOffset(aiNode *pNode);
 
     /** Reads the animation channels into the given node */
-    void ReadNodeChannels( BVHLoader::Node& pNode);
+    void ReadNodeChannels(BVHLoader::Node &pNode);
 
     /** Reads the motion data */
-    void ReadMotion( aiScene* pScene);
+    void ReadMotion(aiScene *pScene);
 
     /** Retrieves the next token */
     std::string GetNextToken();
@@ -141,10 +134,10 @@ protected:
     float GetNextTokenAsFloat();
 
     /** Aborts the file reading with an exception */
-    AI_WONT_RETURN void ThrowException( const std::string& pError) AI_WONT_RETURN_SUFFIX;
+    AI_WONT_RETURN void ThrowException(const std::string &pError) AI_WONT_RETURN_SUFFIX;
 
     /** Constructs an animation for the motion data and stores it in the given scene */
-    void CreateAnimation( aiScene* pScene);
+    void CreateAnimation(aiScene *pScene);
 
 protected:
     /** Filename, for a verbose error message */

+ 62 - 84
code/Blender/BlenderBMesh.cpp → code/AssetLib/Blender/BlenderBMesh.cpp

@@ -42,165 +42,143 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Conversion of Blender's new BMesh stuff
  */
 
-
 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
 
+#include "BlenderBMesh.h"
 #include "BlenderDNA.h"
 #include "BlenderScene.h"
-#include "BlenderBMesh.h"
 #include "BlenderTessellator.h"
 
-namespace Assimp
-{
-    template< > const char* LogFunctions< BlenderBMeshConverter >::Prefix()
-    {
-        static auto prefix = "BLEND_BMESH: ";
-        return prefix;
-    }
+namespace Assimp {
+template <>
+const char *LogFunctions<BlenderBMeshConverter>::Prefix() {
+    static auto prefix = "BLEND_BMESH: ";
+    return prefix;
 }
+} // namespace Assimp
 
 using namespace Assimp;
 using namespace Assimp::Blender;
 using namespace Assimp::Formatter;
 
 // ------------------------------------------------------------------------------------------------
-BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ):
-    BMesh( mesh ),
-    triMesh( NULL )
-{
+BlenderBMeshConverter::BlenderBMeshConverter(const Mesh *mesh) :
+        BMesh(mesh),
+        triMesh(nullptr) {
+    ai_assert(nullptr != mesh);
 }
 
 // ------------------------------------------------------------------------------------------------
-BlenderBMeshConverter::~BlenderBMeshConverter( )
-{
-    DestroyTriMesh( );
+BlenderBMeshConverter::~BlenderBMeshConverter() {
+    DestroyTriMesh();
 }
 
 // ------------------------------------------------------------------------------------------------
-bool BlenderBMeshConverter::ContainsBMesh( ) const
-{
+bool BlenderBMeshConverter::ContainsBMesh() const {
     // TODO - Should probably do some additional verification here
     return BMesh->totpoly && BMesh->totloop && BMesh->totvert;
 }
 
 // ------------------------------------------------------------------------------------------------
-const Mesh* BlenderBMeshConverter::TriangulateBMesh( )
-{
-    AssertValidMesh( );
-    AssertValidSizes( );
-    PrepareTriMesh( );
-
-    for ( int i = 0; i < BMesh->totpoly; ++i )
-    {
-        const MPoly& poly = BMesh->mpoly[ i ];
-        ConvertPolyToFaces( poly );
+const Mesh *BlenderBMeshConverter::TriangulateBMesh() {
+    AssertValidMesh();
+    AssertValidSizes();
+    PrepareTriMesh();
+
+    for (int i = 0; i < BMesh->totpoly; ++i) {
+        const MPoly &poly = BMesh->mpoly[i];
+        ConvertPolyToFaces(poly);
     }
 
     return triMesh;
 }
 
 // ------------------------------------------------------------------------------------------------
-void BlenderBMeshConverter::AssertValidMesh( )
-{
-    if ( !ContainsBMesh( ) )
-    {
-        ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" );
+void BlenderBMeshConverter::AssertValidMesh() {
+    if (!ContainsBMesh()) {
+        ThrowException("BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first");
     }
 }
 
 // ------------------------------------------------------------------------------------------------
-void BlenderBMeshConverter::AssertValidSizes( )
-{
-    if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
-    {
-        ThrowException( "BMesh poly array has incorrect size" );
+void BlenderBMeshConverter::AssertValidSizes() {
+    if (BMesh->totpoly != static_cast<int>(BMesh->mpoly.size())) {
+        ThrowException("BMesh poly array has incorrect size");
     }
-    if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
-    {
-        ThrowException( "BMesh loop array has incorrect size" );
+    if (BMesh->totloop != static_cast<int>(BMesh->mloop.size())) {
+        ThrowException("BMesh loop array has incorrect size");
     }
 }
 
 // ------------------------------------------------------------------------------------------------
-void BlenderBMeshConverter::PrepareTriMesh( )
-{
-    if ( triMesh )
-    {
-        DestroyTriMesh( );
+void BlenderBMeshConverter::PrepareTriMesh() {
+    if (triMesh) {
+        DestroyTriMesh();
     }
 
-    triMesh = new Mesh( *BMesh );
+    triMesh = new Mesh(*BMesh);
     triMesh->totface = 0;
-    triMesh->mface.clear( );
+    triMesh->mface.clear();
 }
 
 // ------------------------------------------------------------------------------------------------
-void BlenderBMeshConverter::DestroyTriMesh( )
-{
+void BlenderBMeshConverter::DestroyTriMesh() {
     delete triMesh;
-    triMesh = NULL;
+    triMesh = nullptr;
 }
 
 // ------------------------------------------------------------------------------------------------
-void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly )
-{
-    const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ];
+void BlenderBMeshConverter::ConvertPolyToFaces(const MPoly &poly) {
+    const MLoop *polyLoop = &BMesh->mloop[poly.loopstart];
 
-    if ( poly.totloop == 3 || poly.totloop == 4 )
-    {
-        AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 );
+    if (poly.totloop == 3 || poly.totloop == 4) {
+        AddFace(polyLoop[0].v, polyLoop[1].v, polyLoop[2].v, poly.totloop == 4 ? polyLoop[3].v : 0);
 
         // UVs are optional, so only convert when present.
-        if ( BMesh->mloopuv.size() )
-        {
-            if ( (poly.loopstart + poly.totloop ) > static_cast<int>( BMesh->mloopuv.size() ) )
-            {
-                ThrowException( "BMesh uv loop array has incorrect size" );
+        if (BMesh->mloopuv.size()) {
+            if ((poly.loopstart + poly.totloop) > static_cast<int>(BMesh->mloopuv.size())) {
+                ThrowException("BMesh uv loop array has incorrect size");
             }
-            const MLoopUV* loopUV = &BMesh->mloopuv[ poly.loopstart ];
-            AddTFace( loopUV[ 0 ].uv, loopUV[ 1 ].uv, loopUV[ 2 ].uv, poly.totloop == 4 ? loopUV[ 3 ].uv : 0 );
+            const MLoopUV *loopUV = &BMesh->mloopuv[poly.loopstart];
+            AddTFace(loopUV[0].uv, loopUV[1].uv, loopUV[2].uv, poly.totloop == 4 ? loopUV[3].uv : 0);
         }
-    }
-    else if ( poly.totloop > 4 )
-    {
+    } else if (poly.totloop > 4) {
 #if ASSIMP_BLEND_WITH_GLU_TESSELLATE
-        BlenderTessellatorGL tessGL( *this );
-        tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
+        BlenderTessellatorGL tessGL(*this);
+        tessGL.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
 #elif ASSIMP_BLEND_WITH_POLY_2_TRI
-        BlenderTessellatorP2T tessP2T( *this );
-        tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert );
+        BlenderTessellatorP2T tessP2T(*this);
+        tessP2T.Tessellate(polyLoop, poly.totloop, triMesh->mvert);
 #endif
     }
 }
 
 // ------------------------------------------------------------------------------------------------
-void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 )
-{
+void BlenderBMeshConverter::AddFace(int v1, int v2, int v3, int v4) {
     MFace face;
     face.v1 = v1;
     face.v2 = v2;
     face.v3 = v3;
     face.v4 = v4;
+    face.flag = 0;
     // TODO - Work out how materials work
     face.mat_nr = 0;
-    triMesh->mface.push_back( face );
-    triMesh->totface = static_cast<int>(triMesh->mface.size( ));
+    triMesh->mface.push_back(face);
+    triMesh->totface = static_cast<int>(triMesh->mface.size());
 }
 
 // ------------------------------------------------------------------------------------------------
-void BlenderBMeshConverter::AddTFace( const float* uv1, const float *uv2, const float *uv3, const float* uv4 )
-{
+void BlenderBMeshConverter::AddTFace(const float *uv1, const float *uv2, const float *uv3, const float *uv4) {
     MTFace mtface;
-    memcpy( &mtface.uv[ 0 ], uv1, sizeof(float) * 2 );
-    memcpy( &mtface.uv[ 1 ], uv2, sizeof(float) * 2 );
-    memcpy( &mtface.uv[ 2 ], uv3, sizeof(float) * 2 );
+    memcpy(&mtface.uv[0], uv1, sizeof(float) * 2);
+    memcpy(&mtface.uv[1], uv2, sizeof(float) * 2);
+    memcpy(&mtface.uv[2], uv3, sizeof(float) * 2);
 
-    if ( uv4 )
-    {
-        memcpy( &mtface.uv[ 3 ], uv4, sizeof(float) * 2 );
+    if (uv4) {
+        memcpy(&mtface.uv[3], uv4, sizeof(float) * 2);
     }
 
-    triMesh->mtface.push_back( mtface );
+    triMesh->mtface.push_back(mtface);
 }
 
 #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 0 - 0
code/Blender/BlenderBMesh.h → code/AssetLib/Blender/BlenderBMesh.h


+ 181 - 0
code/AssetLib/Blender/BlenderCustomData.cpp

@@ -0,0 +1,181 @@
+#include "BlenderCustomData.h"
+#include "BlenderDNA.h"
+#include <array>
+#include <functional>
+
+namespace Assimp {
+namespace Blender {
+/**
+        *   @brief  read/convert of Structure array to memory
+        */
+template <typename T>
+bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
+    for (size_t i = 0; i < cnt; ++i) {
+        T read;
+        s.Convert(read, db);
+        *p = read;
+        p++;
+    }
+    return true;
+}
+
+/**
+        *   @brief  pointer to function read memory for n CustomData types
+        */
+typedef bool (*PRead)(ElemBase *pOut, const size_t cnt, const FileDatabase &db);
+typedef ElemBase *(*PCreate)(const size_t cnt);
+typedef void (*PDestroy)(ElemBase *);
+
+#define IMPL_STRUCT_READ(ty)                                               \
+    bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
+        ty *ptr = dynamic_cast<ty *>(v);                                   \
+        if (nullptr == ptr) {                                              \
+            return false;                                                  \
+        }                                                                  \
+        return read<ty>(db.dna[#ty], ptr, cnt, db);                        \
+    }
+
+#define IMPL_STRUCT_CREATE(ty)               \
+    ElemBase *create##ty(const size_t cnt) { \
+        return new ty[cnt];                  \
+    }
+
+#define IMPL_STRUCT_DESTROY(ty)         \
+    void destroy##ty(ElemBase *pE) {    \
+        ty *p = dynamic_cast<ty *>(pE); \
+        delete[] p;                     \
+    }
+
+/**
+        *   @brief  helper macro to define Structure functions
+        */
+#define IMPL_STRUCT(ty)    \
+    IMPL_STRUCT_READ(ty)   \
+    IMPL_STRUCT_CREATE(ty) \
+    IMPL_STRUCT_DESTROY(ty)
+
+// supported structures for CustomData
+IMPL_STRUCT(MVert)
+IMPL_STRUCT(MEdge)
+IMPL_STRUCT(MFace)
+IMPL_STRUCT(MTFace)
+IMPL_STRUCT(MTexPoly)
+IMPL_STRUCT(MLoopUV)
+IMPL_STRUCT(MLoopCol)
+IMPL_STRUCT(MPoly)
+IMPL_STRUCT(MLoop)
+
+/**
+        *   @brief  describes the size of data and the read function to be used for single CustomerData.type
+        */
+struct CustomDataTypeDescription {
+    PRead Read; ///< function to read one CustomData type element
+    PCreate Create; ///< function to allocate n type elements
+    PDestroy Destroy;
+
+    CustomDataTypeDescription(PRead read, PCreate create, PDestroy destroy) :
+            Read(read), Create(create), Destroy(destroy) {}
+};
+
+/**
+        *   @brief  helper macro to define Structure type specific CustomDataTypeDescription
+        *   @note   IMPL_STRUCT_READ for same ty must be used earlier to implement the typespecific read function
+        */
+#define DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(ty) \
+    CustomDataTypeDescription { &read##ty, &create##ty, &destroy##ty }
+
+/**
+        *   @brief  helper macro to define CustomDataTypeDescription for UNSUPPORTED type
+        */
+#define DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION \
+    CustomDataTypeDescription { nullptr, nullptr, nullptr }
+
+/**
+        *   @brief  descriptors for data pointed to from CustomDataLayer.data
+        *   @note   some of the CustomData uses already well defined Structures
+        *           other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures
+        *           use a special readfunction for that cases
+        */
+std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { { DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge),
+        DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MFace),
+        DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTFace),
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTexPoly),
+        DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopUV),
+        DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopCol),
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MPoly),
+        DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoop),
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
+        DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION } };
+
+bool isValidCustomDataType(const int cdtype) {
+    return cdtype >= 0 && cdtype < CD_NUMTYPES;
+}
+
+bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
+    if (!isValidCustomDataType(cdtype)) {
+        throw Error((Formatter::format(), "CustomData.type ", cdtype, " out of index"));
+    }
+
+    const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];
+    if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) {
+        // allocate cnt elements and parse them from file
+        out.reset(cdtd.Create(cnt), cdtd.Destroy);
+        return cdtd.Read(out.get(), cnt, db);
+    }
+    return false;
+}
+
+std::shared_ptr<CustomDataLayer> getCustomDataLayer(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
+    for (auto it = customdata.layers.begin(); it != customdata.layers.end(); ++it) {
+        if (it->get()->type == cdtype && name == it->get()->name) {
+            return *it;
+        }
+    }
+    return nullptr;
+}
+
+const ElemBase *getCustomDataLayerData(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
+    const std::shared_ptr<CustomDataLayer> pLayer = getCustomDataLayer(customdata, cdtype, name);
+    if (pLayer && pLayer->data) {
+        return pLayer->data.get();
+    }
+    return nullptr;
+}
+} // namespace Blender
+} // namespace Assimp

+ 0 - 0
code/Blender/BlenderCustomData.h → code/AssetLib/Blender/BlenderCustomData.h


+ 75 - 90
code/Blender/BlenderDNA.cpp → code/AssetLib/Blender/BlenderDNA.cpp

@@ -45,25 +45,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *    serialized set of data structures.
  */
 
-
 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
 #include "BlenderDNA.h"
 #include <assimp/StreamReader.h>
-#include <assimp/fast_atof.h>
 #include <assimp/TinyFormatter.h>
+#include <assimp/fast_atof.h>
 
 using namespace Assimp;
 using namespace Assimp::Blender;
 using namespace Assimp::Formatter;
 
-static bool match4(StreamReaderAny& stream, const char* string) {
-    ai_assert( nullptr != string );
+static bool match4(StreamReaderAny &stream, const char *string) {
+    ai_assert(nullptr != string);
     char tmp[4];
-    tmp[ 0 ] = ( stream ).GetI1();
-    tmp[ 1 ] = ( stream ).GetI1();
-    tmp[ 2 ] = ( stream ).GetI1();
-    tmp[ 3 ] = ( stream ).GetI1();
-    return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
+    tmp[0] = (stream).GetI1();
+    tmp[1] = (stream).GetI1();
+    tmp[2] = (stream).GetI1();
+    tmp[3] = (stream).GetI1();
+    return (tmp[0] == string[0] && tmp[1] == string[1] && tmp[2] == string[2] && tmp[3] == string[3]);
 }
 
 struct Type {
@@ -72,75 +71,76 @@ struct Type {
 };
 
 // ------------------------------------------------------------------------------------------------
-void DNAParser::Parse ()
-{
-    StreamReaderAny& stream = *db.reader.get();
-    DNA& dna = db.dna;
+void DNAParser::Parse() {
+    StreamReaderAny &stream = *db.reader.get();
+    DNA &dna = db.dna;
 
-    if(!match4(stream,"SDNA")) {
+    if (!match4(stream, "SDNA")) {
         throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
     }
 
     // name dictionary
-    if(!match4(stream,"NAME")) {
+    if (!match4(stream, "NAME")) {
         throw DeadlyImportError("BlenderDNA: Expected NAME field");
     }
 
-    std::vector<std::string> names (stream.GetI4());
-    for(std::string& s : names) {
+    std::vector<std::string> names(stream.GetI4());
+    for (std::string &s : names) {
         while (char c = stream.GetI1()) {
             s += c;
         }
     }
 
     // type dictionary
-    for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
-    if(!match4(stream,"TYPE")) {
+    for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
+        ;
+    if (!match4(stream, "TYPE")) {
         throw DeadlyImportError("BlenderDNA: Expected TYPE field");
     }
 
-    std::vector<Type> types (stream.GetI4());
-    for(Type& s : types) {
+    std::vector<Type> types(stream.GetI4());
+    for (Type &s : types) {
         while (char c = stream.GetI1()) {
             s.name += c;
         }
     }
 
     // type length dictionary
-    for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
-    if(!match4(stream,"TLEN")) {
+    for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
+        ;
+    if (!match4(stream, "TLEN")) {
         throw DeadlyImportError("BlenderDNA: Expected TLEN field");
     }
 
-    for(Type& s : types) {
+    for (Type &s : types) {
         s.size = stream.GetI2();
     }
 
     // structures dictionary
-    for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
-    if(!match4(stream,"STRC")) {
+    for (; stream.GetCurrentPos() & 0x3; stream.GetI1())
+        ;
+    if (!match4(stream, "STRC")) {
         throw DeadlyImportError("BlenderDNA: Expected STRC field");
     }
 
     size_t end = stream.GetI4(), fields = 0;
 
     dna.structures.reserve(end);
-    for(size_t i = 0; i != end; ++i) {
+    for (size_t i = 0; i != end; ++i) {
 
         uint16_t n = stream.GetI2();
         if (n >= types.size()) {
             throw DeadlyImportError((format(),
-                "BlenderDNA: Invalid type index in structure name" ,n,
-                " (there are only ", types.size(), " entries)"
-            ));
+                    "BlenderDNA: Invalid type index in structure name", n,
+                    " (there are only ", types.size(), " entries)"));
         }
 
         // maintain separate indexes
         dna.indices[types[n].name] = dna.structures.size();
 
         dna.structures.push_back(Structure());
-        Structure& s = dna.structures.back();
-        s.name  = types[n].name;
+        Structure &s = dna.structures.back();
+        s.name = types[n].name;
         //s.index = dna.structures.size()-1;
 
         n = stream.GetI2();
@@ -152,12 +152,11 @@ void DNAParser::Parse ()
             uint16_t j = stream.GetI2();
             if (j >= types.size()) {
                 throw DeadlyImportError((format(),
-                    "BlenderDNA: Invalid type index in structure field ", j,
-                    " (there are only ", types.size(), " entries)"
-                ));
+                        "BlenderDNA: Invalid type index in structure field ", j,
+                        " (there are only ", types.size(), " entries)"));
             }
             s.fields.push_back(Field());
-            Field& f = s.fields.back();
+            Field &f = s.fields.back();
             f.offset = offset;
 
             f.type = types[j].name;
@@ -166,9 +165,8 @@ void DNAParser::Parse ()
             j = stream.GetI2();
             if (j >= names.size()) {
                 throw DeadlyImportError((format(),
-                    "BlenderDNA: Invalid name index in structure field ", j,
-                    " (there are only ", names.size(), " entries)"
-                ));
+                        "BlenderDNA: Invalid name index in structure field ", j,
+                        " (there are only ", names.size(), " entries)"));
             }
 
             f.name = names[j];
@@ -191,26 +189,25 @@ void DNAParser::Parse ()
                 const std::string::size_type rb = f.name.find('[');
                 if (rb == std::string::npos) {
                     throw DeadlyImportError((format(),
-                        "BlenderDNA: Encountered invalid array declaration ",
-                        f.name
-                    ));
+                            "BlenderDNA: Encountered invalid array declaration ",
+                            f.name));
                 }
 
                 f.flags |= FieldFlag_Array;
-                DNA::ExtractArraySize(f.name,f.array_sizes);
-                f.name = f.name.substr(0,rb);
+                DNA::ExtractArraySize(f.name, f.array_sizes);
+                f.name = f.name.substr(0, rb);
 
                 f.size *= f.array_sizes[0] * f.array_sizes[1];
             }
 
             // maintain separate indexes
-            s.indices[f.name] = s.fields.size()-1;
+            s.indices[f.name] = s.fields.size() - 1;
             offset += f.size;
         }
         s.size = offset;
     }
 
-    ASSIMP_LOG_DEBUG_F( "BlenderDNA: Got ", dna.structures.size()," structures with totally ",fields," fields");
+    ASSIMP_LOG_DEBUG_F("BlenderDNA: Got ", dna.structures.size(), " structures with totally ", fields, " fields");
 
 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
     dna.DumpToFile();
@@ -220,13 +217,11 @@ void DNAParser::Parse ()
     dna.RegisterConverters();
 }
 
-
 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
 
 #include <fstream>
 // ------------------------------------------------------------------------------------------------
-void DNA :: DumpToFile()
-{
+void DNA ::DumpToFile() {
     // we don't bother using the VFS here for this is only for debugging.
     // (and all your bases are belong to us).
 
@@ -235,12 +230,14 @@ void DNA :: DumpToFile()
         ASSIMP_LOG_ERROR("Could not dump dna to dna.txt");
         return;
     }
-    f << "Field format: type name offset size" << "\n";
-    f << "Structure format: name size" << "\n";
+    f << "Field format: type name offset size"
+      << "\n";
+    f << "Structure format: name size"
+      << "\n";
 
-    for(const Structure& s : structures) {
+    for (const Structure &s : structures) {
         f << s.name << " " << s.size << "\n\n";
-        for(const Field& ff : s.fields) {
+        for (const Field &ff : s.fields) {
             f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << "\n";
         }
         f << "\n";
@@ -252,11 +249,9 @@ void DNA :: DumpToFile()
 #endif
 
 // ------------------------------------------------------------------------------------------------
-/*static*/ void  DNA :: ExtractArraySize(
-    const std::string& out,
-    size_t array_sizes[2]
-)
-{
+/*static*/ void DNA ::ExtractArraySize(
+        const std::string &out,
+        size_t array_sizes[2]) {
     array_sizes[0] = array_sizes[1] = 1;
     std::string::size_type pos = out.find('[');
     if (pos++ == std::string::npos) {
@@ -264,7 +259,7 @@ void DNA :: DumpToFile()
     }
     array_sizes[0] = strtoul10(&out[pos]);
 
-    pos = out.find('[',pos);
+    pos = out.find('[', pos);
     if (pos++ == std::string::npos) {
         return;
     }
@@ -272,36 +267,32 @@ void DNA :: DumpToFile()
 }
 
 // ------------------------------------------------------------------------------------------------
-std::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
-    const Structure& structure,
-    const FileDatabase& db
-) const
-{
-    std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
+std::shared_ptr<ElemBase> DNA ::ConvertBlobToStructure(
+        const Structure &structure,
+        const FileDatabase &db) const {
+    std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
     if (it == converters.end()) {
-        return std::shared_ptr< ElemBase >();
+        return std::shared_ptr<ElemBase>();
     }
 
-    std::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
-    (structure.*((*it).second.second))(ret,db);
+    std::shared_ptr<ElemBase> ret = (structure.*((*it).second.first))();
+    (structure.*((*it).second.second))(ret, db);
 
     return ret;
 }
 
 // ------------------------------------------------------------------------------------------------
-DNA::FactoryPair DNA :: GetBlobToStructureConverter(
-    const Structure& structure,
-    const FileDatabase& /*db*/
-) const
-{
-    std::map<std::string,  FactoryPair>::const_iterator it = converters.find(structure.name);
+DNA::FactoryPair DNA ::GetBlobToStructureConverter(
+        const Structure &structure,
+        const FileDatabase & /*db*/
+) const {
+    std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
     return it == converters.end() ? FactoryPair() : (*it).second;
 }
 
 // basing on http://www.blender.org/development/architecture/notes-on-sdna/
 // ------------------------------------------------------------------------------------------------
-void DNA :: AddPrimitiveStructures()
-{
+void DNA ::AddPrimitiveStructures() {
     // NOTE: these are just dummies. Their presence enforces
     // Structure::Convert<target_type> to be called on these
     // empty structures. These converters are special
@@ -311,30 +302,27 @@ void DNA :: AddPrimitiveStructures()
     // in question.
 
     indices["int"] = structures.size();
-    structures.push_back( Structure() );
+    structures.push_back(Structure());
     structures.back().name = "int";
     structures.back().size = 4;
 
     indices["short"] = structures.size();
-    structures.push_back( Structure() );
+    structures.push_back(Structure());
     structures.back().name = "short";
     structures.back().size = 2;
 
-
     indices["char"] = structures.size();
-    structures.push_back( Structure() );
+    structures.push_back(Structure());
     structures.back().name = "char";
     structures.back().size = 1;
 
-
     indices["float"] = structures.size();
-    structures.push_back( Structure() );
+    structures.push_back(Structure());
     structures.back().name = "float";
     structures.back().size = 4;
 
-
     indices["double"] = structures.size();
-    structures.push_back( Structure() );
+    structures.push_back(Structure());
     structures.back().name = "double";
     structures.back().size = 8;
 
@@ -342,8 +330,7 @@ void DNA :: AddPrimitiveStructures()
 }
 
 // ------------------------------------------------------------------------------------------------
-void SectionParser :: Next()
-{
+void SectionParser ::Next() {
     stream.SetCurrentPos(current.start + current.size);
 
     const char tmp[] = {
@@ -352,7 +339,7 @@ void SectionParser :: Next()
         (const char)stream.GetI1(),
         (const char)stream.GetI1()
     };
-    current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
+    current.id = std::string(tmp, tmp[3] ? 4 : tmp[2] ? 3 : tmp[1] ? 2 : 1);
 
     current.size = stream.GetI4();
     current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
@@ -366,10 +353,8 @@ void SectionParser :: Next()
     }
 
 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
-    ASSIMP_LOG_DEBUG(current.id);
+    ASSIMP_LOG_VERBOSE_DEBUG(current.id);
 #endif
 }
 
-
-
 #endif

+ 165 - 208
code/Blender/BlenderDNA.h → code/AssetLib/Blender/BlenderDNA.h

@@ -49,26 +49,27 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <assimp/BaseImporter.h>
 #include <assimp/StreamReader.h>
-#include <assimp/DefaultLogger.hpp>
 #include <stdint.h>
-#include <memory>
+#include <assimp/DefaultLogger.hpp>
 #include <map>
+#include <memory>
 
 // enable verbose log output. really verbose, so be careful.
 #ifdef ASSIMP_BUILD_DEBUG
-#   define ASSIMP_BUILD_BLENDER_DEBUG
+#define ASSIMP_BUILD_BLENDER_DEBUG
 #endif
 
 // #define ASSIMP_BUILD_BLENDER_NO_STATS
 
-namespace Assimp    {
+namespace Assimp {
 
-template <bool,bool> class StreamReader;
-typedef StreamReader<true,true> StreamReaderAny;
+template <bool, bool>
+class StreamReader;
+typedef StreamReader<true, true> StreamReaderAny;
 
 namespace Blender {
 
-class  FileDatabase;
+class FileDatabase;
 struct FileBlockHead;
 
 template <template <typename> class TOUT>
@@ -82,8 +83,8 @@ class ObjectCache;
  *  ancestry. */
 // -------------------------------------------------------------------------------
 struct Error : DeadlyImportError {
-    Error (const std::string& s)
-    : DeadlyImportError(s) {
+    Error(const std::string &s) :
+            DeadlyImportError(s) {
         // empty
     }
 };
@@ -93,9 +94,8 @@ struct Error : DeadlyImportError {
  *  descendents. It serves as base class for all data structure fields. */
 // -------------------------------------------------------------------------------
 struct ElemBase {
-    ElemBase()
-    : dna_type(nullptr)
-    {
+    ElemBase() :
+            dna_type(nullptr) {
         // empty
     }
 
@@ -110,7 +110,7 @@ struct ElemBase {
      * data type is not static, i.e. a std::shared_ptr<ElemBase>
      * in the scene description would have its type resolved
      * at runtime, so this member is always set. */
-    const char* dna_type;
+    const char *dna_type;
 };
 
 // -------------------------------------------------------------------------------
@@ -120,8 +120,8 @@ struct ElemBase {
  *  they used to point to.*/
 // -------------------------------------------------------------------------------
 struct Pointer {
-    Pointer()
-    : val() {
+    Pointer() :
+            val() {
         // empty
     }
     uint64_t val;
@@ -131,8 +131,8 @@ struct Pointer {
 /** Represents a generic offset within a BLEND file */
 // -------------------------------------------------------------------------------
 struct FileOffset {
-    FileOffset()
-    : val() {
+    FileOffset() :
+            val() {
         // empty
     }
     uint64_t val;
@@ -154,7 +154,7 @@ public:
         resize(0);
     }
 
-    operator bool () const {
+    operator bool() const {
         return !empty();
     }
 };
@@ -164,7 +164,7 @@ public:
 // -------------------------------------------------------------------------------
 enum FieldFlags {
     FieldFlag_Pointer = 0x1,
-    FieldFlag_Array   = 0x2
+    FieldFlag_Array = 0x2
 };
 
 // -------------------------------------------------------------------------------
@@ -200,7 +200,7 @@ enum ErrorPolicy {
 };
 
 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
-#   define ErrorPolicy_Igno ErrorPolicy_Warn
+#define ErrorPolicy_Igno ErrorPolicy_Warn
 #endif
 
 // -------------------------------------------------------------------------------
@@ -212,47 +212,42 @@ enum ErrorPolicy {
  *  meaningful contents. */
 // -------------------------------------------------------------------------------
 class Structure {
-    template <template <typename> class> friend class ObjectCache;
+    template <template <typename> class>
+    friend class ObjectCache;
 
 public:
-    Structure()
-    : cache_idx(static_cast<size_t>(-1) ){
+    Structure() :
+            cache_idx(static_cast<size_t>(-1)) {
         // empty
     }
 
-public:
-
     // publicly accessible members
     std::string name;
-    vector< Field > fields;
+    vector<Field> fields;
     std::map<std::string, size_t> indices;
 
     size_t size;
 
-public:
-
     // --------------------------------------------------------
     /** Access a field of the structure by its canonical name. The pointer version
-     *  returns NULL on failure while the reference version raises an import error. */
-    inline const Field& operator [] (const std::string& ss) const;
-    inline const Field* Get (const std::string& ss) const;
+     *  returns nullptr on failure while the reference version raises an import error. */
+    inline const Field &operator[](const std::string &ss) const;
+    inline const Field *Get(const std::string &ss) const;
 
     // --------------------------------------------------------
     /** Access a field of the structure by its index */
-    inline const Field& operator [] (const size_t i) const;
+    inline const Field &operator[](const size_t i) const;
 
     // --------------------------------------------------------
-    inline bool operator== (const Structure& other) const {
+    inline bool operator==(const Structure &other) const {
         return name == other.name; // name is meant to be an unique identifier
     }
 
     // --------------------------------------------------------
-    inline bool operator!= (const Structure& other) const {
+    inline bool operator!=(const Structure &other) const {
         return name != other.name;
     }
 
-public:
-
     // --------------------------------------------------------
     /** Try to read an instance of the structure from the stream
      *  and attempt to convert to `T`. This is done by
@@ -260,54 +255,54 @@ public:
      *  a compiler complain is the result.
      *  @param dest Destination value to be written
      *  @param db File database, including input stream. */
-    template <typename T> void Convert (T& dest, const FileDatabase& db) const;
+    template <typename T>
+    void Convert(T &dest, const FileDatabase &db) const;
 
     // --------------------------------------------------------
     // generic converter
     template <typename T>
-    void Convert(std::shared_ptr<ElemBase> in,const FileDatabase& db) const;
+    void Convert(std::shared_ptr<ElemBase> in, const FileDatabase &db) const;
 
     // --------------------------------------------------------
     // generic allocator
-    template <typename T> std::shared_ptr<ElemBase> Allocate() const;
-
-
+    template <typename T>
+    std::shared_ptr<ElemBase> Allocate() const;
 
     // --------------------------------------------------------
     // field parsing for 1d arrays
     template <int error_policy, typename T, size_t M>
-    void ReadFieldArray(T (& out)[M], const char* name,
-        const FileDatabase& db) const;
+    void ReadFieldArray(T (&out)[M], const char *name,
+            const FileDatabase &db) const;
 
     // --------------------------------------------------------
     // field parsing for 2d arrays
     template <int error_policy, typename T, size_t M, size_t N>
-    void ReadFieldArray2(T (& out)[M][N], const char* name,
-        const FileDatabase& db) const;
+    void ReadFieldArray2(T (&out)[M][N], const char *name,
+            const FileDatabase &db) const;
 
     // --------------------------------------------------------
     // field parsing for pointer or dynamic array types
     // (std::shared_ptr)
     // The return value indicates whether the data was already cached.
     template <int error_policy, template <typename> class TOUT, typename T>
-    bool ReadFieldPtr(TOUT<T>& out, const char* name,
-        const FileDatabase& db,
-        bool non_recursive = false) const;
+    bool ReadFieldPtr(TOUT<T> &out, const char *name,
+            const FileDatabase &db,
+            bool non_recursive = false) const;
 
     // --------------------------------------------------------
     // field parsing for static arrays of pointer or dynamic
     // array types (std::shared_ptr[])
     // The return value indicates whether the data was already cached.
     template <int error_policy, template <typename> class TOUT, typename T, size_t N>
-    bool ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
-        const FileDatabase& db) const;
+    bool ReadFieldPtr(TOUT<T> (&out)[N], const char *name,
+            const FileDatabase &db) const;
 
     // --------------------------------------------------------
     // field parsing for `normal` values
     // The return value indicates whether the data was already cached.
     template <int error_policy, typename T>
-    void ReadField(T& out, const char* name,
-        const FileDatabase& db) const;
+    void ReadField(T &out, const char *name,
+            const FileDatabase &db) const;
 
     // --------------------------------------------------------
     /**
@@ -318,7 +313,7 @@ public:
     *   @return true when read was successful
     */
     template <int error_policy, template <typename> class TOUT, typename T>
-    bool ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const;
+    bool ReadFieldPtrVector(vector<TOUT<T>> &out, const char *name, const FileDatabase &db) const;
 
     /**
     *   @brief  parses raw customdata
@@ -329,42 +324,42 @@ public:
     *   @return true when read was successful
     */
     template <int error_policy>
-    bool ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const;
+    bool ReadCustomDataPtr(std::shared_ptr<ElemBase> &out, int cdtype, const char *name, const FileDatabase &db) const;
 
 private:
-
     // --------------------------------------------------------
     template <template <typename> class TOUT, typename T>
-    bool ResolvePointer(TOUT<T>& out, const Pointer & ptrval,
-        const FileDatabase& db, const Field& f,
-        bool non_recursive = false) const;
+    bool ResolvePointer(TOUT<T> &out, const Pointer &ptrval,
+            const FileDatabase &db, const Field &f,
+            bool non_recursive = false) const;
 
     // --------------------------------------------------------
     template <template <typename> class TOUT, typename T>
-    bool ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval,
-        const FileDatabase& db, const Field& f, bool) const;
+    bool ResolvePointer(vector<TOUT<T>> &out, const Pointer &ptrval,
+            const FileDatabase &db, const Field &f, bool) const;
 
     // --------------------------------------------------------
-    bool ResolvePointer( std::shared_ptr< FileOffset >& out, const Pointer & ptrval,
-        const FileDatabase& db, const Field& f, bool) const;
+    bool ResolvePointer(std::shared_ptr<FileOffset> &out, const Pointer &ptrval,
+            const FileDatabase &db, const Field &f, bool) const;
 
     // --------------------------------------------------------
-    inline const FileBlockHead* LocateFileBlockForAddress(
-        const Pointer & ptrval,
-        const FileDatabase& db) const;
+    inline const FileBlockHead *LocateFileBlockForAddress(
+            const Pointer &ptrval,
+            const FileDatabase &db) const;
 
 private:
-
     // ------------------------------------------------------------------------------
-    template <typename T> T* _allocate(std::shared_ptr<T>& out, size_t& s) const {
+    template <typename T>
+    T *_allocate(std::shared_ptr<T> &out, size_t &s) const {
         out = std::shared_ptr<T>(new T());
         s = 1;
         return out.get();
     }
 
-    template <typename T> T* _allocate(vector<T>& out, size_t& s) const {
+    template <typename T>
+    T *_allocate(vector<T> &out, size_t &s) const {
         out.resize(s);
-        return s ? &out.front() : NULL;
+        return s ? &out.front() : nullptr;
     }
 
     // --------------------------------------------------------
@@ -372,14 +367,14 @@ private:
     struct _defaultInitializer {
 
         template <typename T, unsigned int N>
-        void operator ()(T (& out)[N], const char* = NULL) {
+        void operator()(T (&out)[N], const char * = nullptr) {
             for (unsigned int i = 0; i < N; ++i) {
                 out[i] = T();
             }
         }
 
         template <typename T, unsigned int N, unsigned int M>
-        void operator ()(T (& out)[N][M], const char* = NULL) {
+        void operator()(T (&out)[N][M], const char * = nullptr) {
             for (unsigned int i = 0; i < N; ++i) {
                 for (unsigned int j = 0; j < M; ++j) {
                     out[i][j] = T();
@@ -388,21 +383,21 @@ private:
         }
 
         template <typename T>
-        void operator ()(T& out, const char* = NULL) {
+        void operator()(T &out, const char * = nullptr) {
             out = T();
         }
     };
 
 private:
-
     mutable size_t cache_idx;
 };
 
 // --------------------------------------------------------
-template <>  struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
+template <>
+struct Structure ::_defaultInitializer<ErrorPolicy_Warn> {
 
     template <typename T>
-    void operator ()(T& out, const char* reason = "<add reason>") {
+    void operator()(T &out, const char *reason = "<add reason>") {
         ASSIMP_LOG_WARN(reason);
 
         // ... and let the show go on
@@ -410,10 +405,11 @@ template <>  struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
     }
 };
 
-template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
+template <>
+struct Structure ::_defaultInitializer<ErrorPolicy_Fail> {
 
     template <typename T>
-    void operator ()(T& /*out*/,const char* = "") {
+    void operator()(T & /*out*/, const char * = "") {
         // obviously, it is crucial that _DefaultInitializer is used
         // only from within a catch clause.
         throw DeadlyImportError("Constructing BlenderDNA Structure encountered an error");
@@ -421,13 +417,12 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
 };
 
 // -------------------------------------------------------------------------------------------------------
-template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shared_ptr<ElemBase>& out,
-    const Pointer & ptrval,
-    const FileDatabase& db,
-    const Field& f,
-    bool
-    ) const;
-
+template <>
+inline bool Structure ::ResolvePointer<std::shared_ptr, ElemBase>(std::shared_ptr<ElemBase> &out,
+        const Pointer &ptrval,
+        const FileDatabase &db,
+        const Field &f,
+        bool) const;
 
 // -------------------------------------------------------------------------------
 /** Represents the full data structure information for a single BLEND file.
@@ -435,40 +430,34 @@ template <> inline bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(st
  *  #DNAParser does the reading and represents currently the only place where
  *  DNA is altered.*/
 // -------------------------------------------------------------------------------
-class DNA
-{
+class DNA {
 public:
-
-    typedef void (Structure::*ConvertProcPtr) (
-        std::shared_ptr<ElemBase> in,
-        const FileDatabase&
-    ) const;
+    typedef void (Structure::*ConvertProcPtr)(
+            std::shared_ptr<ElemBase> in,
+            const FileDatabase &) const;
 
     typedef std::shared_ptr<ElemBase> (
-        Structure::*AllocProcPtr) () const;
+            Structure::*AllocProcPtr)() const;
 
-    typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair;
+    typedef std::pair<AllocProcPtr, ConvertProcPtr> FactoryPair;
 
 public:
-
-    std::map<std::string, FactoryPair > converters;
-    vector<Structure > structures;
+    std::map<std::string, FactoryPair> converters;
+    vector<Structure> structures;
     std::map<std::string, size_t> indices;
 
 public:
-
     // --------------------------------------------------------
-    /** Access a structure by its canonical name, the pointer version returns NULL on failure
+    /** Access a structure by its canonical name, the pointer version returns nullptr on failure
       * while the reference version raises an error. */
-    inline const Structure& operator [] (const std::string& ss) const;
-    inline const Structure* Get (const std::string& ss) const;
+    inline const Structure &operator[](const std::string &ss) const;
+    inline const Structure *Get(const std::string &ss) const;
 
     // --------------------------------------------------------
     /** Access a structure by its index */
-    inline const Structure& operator [] (const size_t i) const;
+    inline const Structure &operator[](const size_t i) const;
 
 public:
-
     // --------------------------------------------------------
     /** Add structure definitions for all the primitive types,
      *  i.e. integer, short, char, float */
@@ -483,7 +472,6 @@ public:
      *  known at compile time (consier Object::data).*/
     void RegisterConverters();
 
-
     // --------------------------------------------------------
     /** Take an input blob from the stream, interpret it according to
      *  a its structure name and convert it to the intermediate
@@ -491,10 +479,9 @@ public:
      *  @param structure Destination structure definition
      *  @param db File database.
      *  @return A null pointer if no appropriate converter is available.*/
-    std::shared_ptr< ElemBase > ConvertBlobToStructure(
-        const Structure& structure,
-        const FileDatabase& db
-        ) const;
+    std::shared_ptr<ElemBase> ConvertBlobToStructure(
+            const Structure &structure,
+            const FileDatabase &db) const;
 
     // --------------------------------------------------------
     /** Find a suitable conversion function for a given Structure.
@@ -505,10 +492,8 @@ public:
      *  @param db File database.
      *  @return A null pointer in .first if no appropriate converter is available.*/
     FactoryPair GetBlobToStructureConverter(
-        const Structure& structure,
-        const FileDatabase& db
-        ) const;
-
+            const Structure &structure,
+            const FileDatabase &db) const;
 
 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
     // --------------------------------------------------------
@@ -527,25 +512,29 @@ public:
      *  @throw DeadlyImportError if more than 2 dimensions are
      *    encountered. */
     static void ExtractArraySize(
-        const std::string& out,
-        size_t array_sizes[2]
-    );
+            const std::string &out,
+            size_t array_sizes[2]);
 };
 
 // special converters for primitive types
-template <> inline void Structure :: Convert<int>       (int& dest,const FileDatabase& db) const;
-template <> inline void Structure :: Convert<short>     (short& dest,const FileDatabase& db) const;
-template <> inline void Structure :: Convert<char>      (char& dest,const FileDatabase& db) const;
-template <> inline void Structure :: Convert<float>     (float& dest,const FileDatabase& db) const;
-template <> inline void Structure :: Convert<double>    (double& dest,const FileDatabase& db) const;
-template <> inline void Structure :: Convert<Pointer>   (Pointer& dest,const FileDatabase& db) const;
+template <>
+inline void Structure ::Convert<int>(int &dest, const FileDatabase &db) const;
+template <>
+inline void Structure ::Convert<short>(short &dest, const FileDatabase &db) const;
+template <>
+inline void Structure ::Convert<char>(char &dest, const FileDatabase &db) const;
+template <>
+inline void Structure ::Convert<float>(float &dest, const FileDatabase &db) const;
+template <>
+inline void Structure ::Convert<double>(double &dest, const FileDatabase &db) const;
+template <>
+inline void Structure ::Convert<Pointer>(Pointer &dest, const FileDatabase &db) const;
 
 // -------------------------------------------------------------------------------
 /** Describes a master file block header. Each master file sections holds n
  *  elements of a certain SDNA structure (or otherwise unspecified data). */
 // -------------------------------------------------------------------------------
-struct FileBlockHead
-{
+struct FileBlockHead {
     // points right after the header of the file block
     StreamReaderAny::pos start;
 
@@ -561,66 +550,55 @@ struct FileBlockHead
     // number of structure instances to follow
     size_t num;
 
-
-
     // file blocks are sorted by address to quickly locate specific memory addresses
-    bool operator < (const FileBlockHead& o) const {
+    bool operator<(const FileBlockHead &o) const {
         return address.val < o.address.val;
     }
 
     // for std::upper_bound
-    operator const Pointer& () const {
+    operator const Pointer &() const {
         return address;
     }
 };
 
 // for std::upper_bound
-inline bool operator< (const Pointer& a, const Pointer& b) {
+inline bool operator<(const Pointer &a, const Pointer &b) {
     return a.val < b.val;
 }
 
 // -------------------------------------------------------------------------------
 /** Utility to read all master file blocks in turn. */
 // -------------------------------------------------------------------------------
-class SectionParser
-{
+class SectionParser {
 public:
-
     // --------------------------------------------------------
     /** @param stream Inout stream, must point to the
      *  first section in the file. Call Next() once
      *  to have it read.
      *  @param ptr64 Pointer size in file is 64 bits? */
-    SectionParser(StreamReaderAny& stream,bool ptr64)
-        : stream(stream)
-        , ptr64(ptr64)
-    {
+    SectionParser(StreamReaderAny &stream, bool ptr64) :
+            stream(stream), ptr64(ptr64) {
         current.size = current.start = 0;
     }
 
 public:
-
     // --------------------------------------------------------
-    const FileBlockHead& GetCurrent() const {
+    const FileBlockHead &GetCurrent() const {
         return current;
     }
 
-
 public:
-
     // --------------------------------------------------------
     /** Advance to the next section.
      *  @throw DeadlyImportError if the last chunk was passed. */
     void Next();
 
 public:
-
     FileBlockHead current;
-    StreamReaderAny& stream;
+    StreamReaderAny &stream;
     bool ptr64;
 };
 
-
 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
 // -------------------------------------------------------------------------------
 /** Import statistics, i.e. number of file blocks read*/
@@ -628,17 +606,13 @@ public:
 class Statistics {
 
 public:
-
-    Statistics ()
-        : fields_read       ()
-        , pointers_resolved ()
-        , cache_hits        ()
-//      , blocks_read       ()
-        , cached_objects    ()
-    {}
+    Statistics() :
+            fields_read(), pointers_resolved(), cache_hits()
+            //      , blocks_read       ()
+            ,
+            cached_objects() {}
 
 public:
-
     /** total number of fields we read */
     unsigned int fields_read;
 
@@ -662,17 +636,13 @@ public:
  *  avoids circular references and avoids object duplication. */
 // -------------------------------------------------------------------------------
 template <template <typename> class TOUT>
-class ObjectCache
-{
+class ObjectCache {
 public:
-
-    typedef std::map< Pointer, TOUT<ElemBase> > StructureCache;
+    typedef std::map<Pointer, TOUT<ElemBase>> StructureCache;
 
 public:
-
-    ObjectCache(const FileDatabase& db)
-        : db(db)
-    {
+    ObjectCache(const FileDatabase &db) :
+            db(db) {
         // currently there are only ~400 structure records per blend file.
         // we read only a small part of them and don't cache objects
         // which we don't need, so this should suffice.
@@ -680,17 +650,17 @@ public:
     }
 
 public:
-
     // --------------------------------------------------------
     /** Check whether a specific item is in the cache.
      *  @param s Data type of the item
      *  @param out Output pointer. Unchanged if the
      *   cache doesn't know the item yet.
      *  @param ptr Item address to look for. */
-    template <typename T> void get (
-        const Structure& s,
-        TOUT<T>& out,
-        const Pointer& ptr) const;
+    template <typename T>
+    void get(
+            const Structure &s,
+            TOUT<T> &out,
+            const Pointer &ptr) const;
 
     // --------------------------------------------------------
     /** Add an item to the cache after the item has
@@ -700,47 +670,44 @@ public:
      *  @param s Data type of the item
      *  @param out Item to insert into the cache
      *  @param ptr address (cache key) of the item. */
-    template <typename T> void set
-        (const Structure& s,
-        const TOUT<T>& out,
-        const Pointer& ptr);
+    template <typename T>
+    void set(const Structure &s,
+            const TOUT<T> &out,
+            const Pointer &ptr);
 
 private:
-
     mutable vector<StructureCache> caches;
-    const FileDatabase& db;
+    const FileDatabase &db;
 };
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
-template <> class ObjectCache<Blender::vector>
-{
+template <>
+class ObjectCache<Blender::vector> {
 public:
+    ObjectCache(const FileDatabase &) {}
 
-    ObjectCache(const FileDatabase&) {}
-
-    template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {}
-    template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {}
+    template <typename T>
+    void get(const Structure &, vector<T> &, const Pointer &) {}
+    template <typename T>
+    void set(const Structure &, const vector<T> &, const Pointer &) {}
 };
 
 #ifdef _MSC_VER
-#   pragma warning(disable:4355)
+#pragma warning(disable : 4355)
 #endif
 
 // -------------------------------------------------------------------------------
 /** Memory representation of a full BLEND file and all its dependencies. The
  *  output aiScene is constructed from an instance of this data structure. */
 // -------------------------------------------------------------------------------
-class FileDatabase
-{
-    template <template <typename> class TOUT> friend class ObjectCache;
+class FileDatabase {
+    template <template <typename> class TOUT>
+    friend class ObjectCache;
 
 public:
-    FileDatabase()
-        : _cacheArrays(*this)
-        , _cache(*this)
-        , next_cache_idx()
-    {}
+    FileDatabase() :
+            _cacheArrays(*this), _cache(*this), next_cache_idx() {}
 
 public:
     // publicly accessible fields
@@ -748,12 +715,11 @@ public:
     bool little;
 
     DNA dna;
-    std::shared_ptr< StreamReaderAny > reader;
-    vector< FileBlockHead > entries;
+    std::shared_ptr<StreamReaderAny> reader;
+    vector<FileBlockHead> entries;
 
 public:
-
-    Statistics& stats() const {
+    Statistics &stats() const {
         return _stats;
     }
 
@@ -762,18 +728,16 @@ public:
     // arrays of objects are never cached because we can't easily
     // ensure their proper destruction.
     template <typename T>
-    ObjectCache<std::shared_ptr>& cache(std::shared_ptr<T>& /*in*/) const {
+    ObjectCache<std::shared_ptr> &cache(std::shared_ptr<T> & /*in*/) const {
         return _cache;
     }
 
     template <typename T>
-    ObjectCache<vector>& cache(vector<T>& /*in*/) const {
+    ObjectCache<vector> &cache(vector<T> & /*in*/) const {
         return _cacheArrays;
     }
 
 private:
-
-
 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
     mutable Statistics _stats;
 #endif
@@ -785,24 +749,20 @@ private:
 };
 
 #ifdef _MSC_VER
-#   pragma warning(default:4355)
+#pragma warning(default : 4355)
 #endif
 
 // -------------------------------------------------------------------------------
 /** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */
 // -------------------------------------------------------------------------------
-class DNAParser
-{
+class DNAParser {
 
 public:
-
     /** Bind the parser to a empty DNA and an input stream */
-    DNAParser(FileDatabase& db)
-        : db(db)
-    {}
+    DNAParser(FileDatabase &db) :
+            db(db) {}
 
 public:
-
     // --------------------------------------------------------
     /** Locate the DNA in the file and parse it. The input
      *  stream is expected to point to the beginning of the DN1
@@ -811,18 +771,16 @@ public:
      *  @throw DeadlyImportError if the DNA cannot be read.
      *  @note The position of the stream pointer is undefined
      *    afterwards.*/
-    void Parse ();
+    void Parse();
 
 public:
-
     /** Obtain a reference to the extracted DNA information */
-    const Blender::DNA& GetDNA() const {
+    const Blender::DNA &GetDNA() const {
         return db.dna;
     }
 
 private:
-
-    FileDatabase& db;
+    FileDatabase &db;
 };
 
 /**
@@ -835,9 +793,8 @@ private:
 */
 bool readCustomData(std::shared_ptr<ElemBase> &out, int cdtype, size_t cnt, const FileDatabase &db);
 
-
-    } // end Blend
-} // end Assimp
+} // namespace Blender
+} // namespace Assimp
 
 #include "BlenderDNA.inl"
 

+ 4 - 3
code/Blender/BlenderDNA.inl → code/AssetLib/Blender/BlenderDNA.inl

@@ -4,7 +4,6 @@ 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,
@@ -70,7 +69,7 @@ const Field& Structure :: operator [] (const std::string& ss) const
 const Field* Structure :: Get (const std::string& ss) const
 {
     std::map<std::string, size_t>::const_iterator it = indices.find(ss);
-    return it == indices.end() ? NULL : &fields[(*it).second];
+    return it == indices.end() ? nullptr : &fields[(*it).second];
 }
 
 //--------------------------------------------------------------------------------
@@ -239,11 +238,13 @@ bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name,
     try {
         f = &(*this)[name];
 
+#ifdef _DEBUG
         // sanity check, should never happen if the genblenddna script is right
         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"));
         }
+#endif // _DEBUG
 
         db.reader->IncPtr(f->offset);
 
@@ -795,7 +796,7 @@ const Structure& DNA :: operator [] (const std::string& ss) const
 const Structure* DNA :: Get (const std::string& ss) const
 {
     std::map<std::string, size_t>::const_iterator it = indices.find(ss);
-    return it == indices.end() ? NULL : &structures[(*it).second];
+    return it == indices.end() ? nullptr : &structures[(*it).second];
 }
 
 //--------------------------------------------------------------------------------

+ 0 - 0
code/Blender/BlenderIntermediate.h → code/AssetLib/Blender/BlenderIntermediate.h


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 240 - 281
code/AssetLib/Blender/BlenderLoader.cpp


+ 0 - 0
code/Blender/BlenderLoader.h → code/AssetLib/Blender/BlenderLoader.h


+ 15 - 15
code/Blender/BlenderModifier.cpp → code/AssetLib/Blender/BlenderModifier.cpp

@@ -68,7 +68,7 @@ static const fpCreateModifier creators[] = {
     &god<BlenderModifier_Mirror>,
     &god<BlenderModifier_Subdivision>,
 
-    NULL // sentinel
+    nullptr // sentinel
 };
 
 // ------------------------------------------------------------------------------------------------
@@ -127,7 +127,7 @@ void BlenderModifierShowcase::ApplyModifiers(aiNode &out, ConversionData &conv_d
                 modifier->DoIt(out, conv_data, *static_cast<const ElemBase *>(cur), in, orig_object);
                 cnt++;
 
-                curgod = NULL;
+                curgod = nullptr;
                 break;
             }
         }
@@ -229,7 +229,7 @@ void BlenderModifier_Mirror ::DoIt(aiNode &out, ConversionData &conv_data, const
 
         // Only reverse the winding order if an odd number of axes were mirrored.
         if (xs * ys * zs < 0) {
-            for (unsigned int j = 0; j < mesh->mNumFaces; ++j ) {
+            for (unsigned int j = 0; j < mesh->mNumFaces; ++j) {
                 aiFace &face = mesh->mFaces[j];
                 for (unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
                     std::swap(face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
@@ -267,18 +267,18 @@ void BlenderModifier_Subdivision ::DoIt(aiNode &out, ConversionData &conv_data,
 
     Subdivider::Algorithm algo;
     switch (mir.subdivType) {
-        case SubsurfModifierData::TYPE_CatmullClarke:
-            algo = Subdivider::CATMULL_CLARKE;
-            break;
-
-        case SubsurfModifierData::TYPE_Simple:
-            ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
-            algo = Subdivider::CATMULL_CLARKE;
-            break;
-
-        default:
-            ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
-            return;
+    case SubsurfModifierData::TYPE_CatmullClarke:
+        algo = Subdivider::CATMULL_CLARKE;
+        break;
+
+    case SubsurfModifierData::TYPE_Simple:
+        ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke");
+        algo = Subdivider::CATMULL_CLARKE;
+        break;
+
+    default:
+        ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ", mir.subdivType);
+        return;
     };
 
     std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));

+ 0 - 0
code/Blender/BlenderModifier.h → code/AssetLib/Blender/BlenderModifier.h


+ 838 - 0
code/AssetLib/Blender/BlenderScene.cpp

@@ -0,0 +1,838 @@
+/*
+Open Asset Import Library (ASSIMP)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2020, ASSIMP Development 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 Development 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  BlenderScene.cpp
+ *  @brief MACHINE GENERATED BY ./scripts/BlenderImporter/genblenddna.py
+ */
+
+#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
+
+#include "BlenderScene.h"
+#include "BlenderCustomData.h"
+#include "BlenderDNA.h"
+#include "BlenderSceneGen.h"
+
+using namespace Assimp;
+using namespace Assimp::Blender;
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Object>(
+        Object &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+    int temp = 0;
+    ReadField<ErrorPolicy_Fail>(temp, "type", db);
+    dest.type = static_cast<Assimp::Blender::Object::Type>(temp);
+    ReadFieldArray2<ErrorPolicy_Warn>(dest.obmat, "obmat", db);
+    ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv, "parentinv", db);
+    ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr, "parsubstr", db);
+    {
+        std::shared_ptr<Object> parent;
+        ReadFieldPtr<ErrorPolicy_Warn>(parent, "*parent", db);
+        dest.parent = parent.get();
+    }
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.track, "*track", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy, "*proxy", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_from, "*proxy_from", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_group, "*proxy_group", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.dup_group, "*dup_group", db);
+    ReadFieldPtr<ErrorPolicy_Fail>(dest.data, "*data", db);
+    ReadField<ErrorPolicy_Igno>(dest.modifiers, "modifiers", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Group>(
+        Group &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+    ReadField<ErrorPolicy_Igno>(dest.layer, "layer", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.gobject, "*gobject", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MTex>(
+        MTex &dest,
+        const FileDatabase &db) const {
+
+    int temp_short = 0;
+    ReadField<ErrorPolicy_Igno>(temp_short, "mapto", db);
+    dest.mapto = static_cast<Assimp::Blender::MTex::MapType>(temp_short);
+    int temp = 0;
+    ReadField<ErrorPolicy_Igno>(temp, "blendtype", db);
+    dest.blendtype = static_cast<Assimp::Blender::MTex::BlendType>(temp);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.object, "*object", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.tex, "*tex", db);
+    ReadFieldArray<ErrorPolicy_Igno>(dest.uvname, "uvname", db);
+    ReadField<ErrorPolicy_Igno>(temp, "projx", db);
+    dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
+    ReadField<ErrorPolicy_Igno>(temp, "projy", db);
+    dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
+    ReadField<ErrorPolicy_Igno>(temp, "projz", db);
+    dest.projz = static_cast<Assimp::Blender::MTex::Projection>(temp);
+    ReadField<ErrorPolicy_Igno>(dest.mapping, "mapping", db);
+    ReadFieldArray<ErrorPolicy_Igno>(dest.ofs, "ofs", db);
+    ReadFieldArray<ErrorPolicy_Igno>(dest.size, "size", db);
+    ReadField<ErrorPolicy_Igno>(dest.rot, "rot", db);
+    ReadField<ErrorPolicy_Igno>(dest.texflag, "texflag", db);
+    ReadField<ErrorPolicy_Igno>(dest.colormodel, "colormodel", db);
+    ReadField<ErrorPolicy_Igno>(dest.pmapto, "pmapto", db);
+    ReadField<ErrorPolicy_Igno>(dest.pmaptoneg, "pmaptoneg", db);
+    ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
+    ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
+    ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
+    ReadField<ErrorPolicy_Warn>(dest.k, "k", db);
+    ReadField<ErrorPolicy_Igno>(dest.colspecfac, "colspecfac", db);
+    ReadField<ErrorPolicy_Igno>(dest.mirrfac, "mirrfac", db);
+    ReadField<ErrorPolicy_Igno>(dest.alphafac, "alphafac", db);
+    ReadField<ErrorPolicy_Igno>(dest.difffac, "difffac", db);
+    ReadField<ErrorPolicy_Igno>(dest.specfac, "specfac", db);
+    ReadField<ErrorPolicy_Igno>(dest.emitfac, "emitfac", db);
+    ReadField<ErrorPolicy_Igno>(dest.hardfac, "hardfac", db);
+    ReadField<ErrorPolicy_Igno>(dest.norfac, "norfac", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<TFace>(
+        TFace &dest,
+        const FileDatabase &db) const {
+
+    ReadFieldArray2<ErrorPolicy_Fail>(dest.uv, "uv", db);
+    ReadFieldArray<ErrorPolicy_Fail>(dest.col, "col", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
+    ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
+    ReadField<ErrorPolicy_Igno>(dest.unwrap, "unwrap", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<SubsurfModifierData>(
+        SubsurfModifierData &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.modifier, "modifier", db);
+    ReadField<ErrorPolicy_Warn>(dest.subdivType, "subdivType", db);
+    ReadField<ErrorPolicy_Fail>(dest.levels, "levels", db);
+    ReadField<ErrorPolicy_Igno>(dest.renderLevels, "renderLevels", db);
+    ReadField<ErrorPolicy_Igno>(dest.flags, "flags", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MFace>(
+        MFace &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.v1, "v1", db);
+    ReadField<ErrorPolicy_Fail>(dest.v2, "v2", db);
+    ReadField<ErrorPolicy_Fail>(dest.v3, "v3", db);
+    ReadField<ErrorPolicy_Fail>(dest.v4, "v4", db);
+    ReadField<ErrorPolicy_Fail>(dest.mat_nr, "mat_nr", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Lamp>(
+        Lamp &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+    int temp = 0;
+    ReadField<ErrorPolicy_Fail>(temp, "type", db);
+    dest.type = static_cast<Assimp::Blender::Lamp::Type>(temp);
+    ReadField<ErrorPolicy_Igno>(dest.flags, "flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.colormodel, "colormodel", db);
+    ReadField<ErrorPolicy_Igno>(dest.totex, "totex", db);
+    ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
+    ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
+    ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
+    ReadField<ErrorPolicy_Warn>(dest.k, "k", db);
+    ReadField<ErrorPolicy_Igno>(dest.energy, "energy", db);
+    ReadField<ErrorPolicy_Warn>(dest.dist, "dist", db);
+    ReadField<ErrorPolicy_Igno>(dest.spotsize, "spotsize", db);
+    ReadField<ErrorPolicy_Igno>(dest.spotblend, "spotblend", db);
+    ReadField<ErrorPolicy_Warn>(dest.constant_coefficient, "coeff_const", db);
+    ReadField<ErrorPolicy_Warn>(dest.linear_coefficient, "coeff_lin", db);
+    ReadField<ErrorPolicy_Warn>(dest.quadratic_coefficient, "coeff_quad", db);
+    ReadField<ErrorPolicy_Igno>(dest.att1, "att1", db);
+    ReadField<ErrorPolicy_Igno>(dest.att2, "att2", db);
+    ReadField<ErrorPolicy_Igno>(temp, "falloff_type", db);
+    dest.falloff_type = static_cast<Assimp::Blender::Lamp::FalloffType>(temp);
+    ReadField<ErrorPolicy_Igno>(dest.sun_brightness, "sun_brightness", db);
+    ReadField<ErrorPolicy_Igno>(dest.area_size, "area_size", db);
+    ReadField<ErrorPolicy_Igno>(dest.area_sizey, "area_sizey", db);
+    ReadField<ErrorPolicy_Igno>(dest.area_sizez, "area_sizez", db);
+    ReadField<ErrorPolicy_Igno>(dest.area_shape, "area_shape", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MDeformWeight>(
+        MDeformWeight &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.def_nr, "def_nr", db);
+    ReadField<ErrorPolicy_Fail>(dest.weight, "weight", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<PackedFile>(
+        PackedFile &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Warn>(dest.size, "size", db);
+    ReadField<ErrorPolicy_Warn>(dest.seek, "seek", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.data, "*data", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Base>(
+        Base &dest,
+        const FileDatabase &db) const {
+    // note: as per https://github.com/assimp/assimp/issues/128,
+    // reading the Object linked list recursively is prone to stack overflow.
+    // This structure converter is therefore an hand-written exception that
+    // does it iteratively.
+
+    const int initial_pos = db.reader->GetCurrentPos();
+
+    std::pair<Base *, int> todo = std::make_pair(&dest, initial_pos);
+    for (;;) {
+
+        Base &cur_dest = *todo.first;
+        db.reader->SetCurrentPos(todo.second);
+
+        // we know that this is a double-linked, circular list which we never
+        // traverse backwards, so don't bother resolving the back links.
+        cur_dest.prev = nullptr;
+
+        ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object, "*object", db);
+
+        // the return value of ReadFieldPtr indicates whether the object
+        // was already cached. In this case, we don't need to resolve
+        // it again.
+        if (!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next, "*next", db, true) && cur_dest.next) {
+            todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos());
+            continue;
+        }
+        break;
+    }
+
+    db.reader->SetCurrentPos(initial_pos + size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MTFace>(
+        MTFace &dest,
+        const FileDatabase &db) const {
+
+    ReadFieldArray2<ErrorPolicy_Fail>(dest.uv, "uv", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
+    ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
+    ReadField<ErrorPolicy_Igno>(dest.unwrap, "unwrap", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Material>(
+        Material &dest,
+        const FileDatabase &db) const {
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+    ReadField<ErrorPolicy_Warn>(dest.r, "r", db);
+    ReadField<ErrorPolicy_Warn>(dest.g, "g", db);
+    ReadField<ErrorPolicy_Warn>(dest.b, "b", db);
+    ReadField<ErrorPolicy_Warn>(dest.specr, "specr", db);
+    ReadField<ErrorPolicy_Warn>(dest.specg, "specg", db);
+    ReadField<ErrorPolicy_Warn>(dest.specb, "specb", db);
+    ReadField<ErrorPolicy_Igno>(dest.har, "har", db);
+    ReadField<ErrorPolicy_Warn>(dest.ambr, "ambr", db);
+    ReadField<ErrorPolicy_Warn>(dest.ambg, "ambg", db);
+    ReadField<ErrorPolicy_Warn>(dest.ambb, "ambb", db);
+    ReadField<ErrorPolicy_Igno>(dest.mirr, "mirr", db);
+    ReadField<ErrorPolicy_Igno>(dest.mirg, "mirg", db);
+    ReadField<ErrorPolicy_Igno>(dest.mirb, "mirb", db);
+    ReadField<ErrorPolicy_Warn>(dest.emit, "emit", db);
+    ReadField<ErrorPolicy_Igno>(dest.ray_mirror, "ray_mirror", db);
+    ReadField<ErrorPolicy_Warn>(dest.alpha, "alpha", db);
+    ReadField<ErrorPolicy_Igno>(dest.ref, "ref", db);
+    ReadField<ErrorPolicy_Igno>(dest.translucency, "translucency", db);
+    ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
+    ReadField<ErrorPolicy_Igno>(dest.roughness, "roughness", db);
+    ReadField<ErrorPolicy_Igno>(dest.darkness, "darkness", db);
+    ReadField<ErrorPolicy_Igno>(dest.refrac, "refrac", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.group, "*group", db);
+    ReadField<ErrorPolicy_Warn>(dest.diff_shader, "diff_shader", db);
+    ReadField<ErrorPolicy_Warn>(dest.spec_shader, "spec_shader", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.mtex, "*mtex", db);
+
+    ReadField<ErrorPolicy_Igno>(dest.amb, "amb", db);
+    ReadField<ErrorPolicy_Igno>(dest.ang, "ang", db);
+    ReadField<ErrorPolicy_Igno>(dest.spectra, "spectra", db);
+    ReadField<ErrorPolicy_Igno>(dest.spec, "spec", db);
+    ReadField<ErrorPolicy_Igno>(dest.zoffs, "zoffs", db);
+    ReadField<ErrorPolicy_Igno>(dest.add, "add", db);
+    ReadField<ErrorPolicy_Igno>(dest.fresnel_mir, "fresnel_mir", db);
+    ReadField<ErrorPolicy_Igno>(dest.fresnel_mir_i, "fresnel_mir_i", db);
+    ReadField<ErrorPolicy_Igno>(dest.fresnel_tra, "fresnel_tra", db);
+    ReadField<ErrorPolicy_Igno>(dest.fresnel_tra_i, "fresnel_tra_i", db);
+    ReadField<ErrorPolicy_Igno>(dest.filter, "filter", db);
+    ReadField<ErrorPolicy_Igno>(dest.tx_limit, "tx_limit", db);
+    ReadField<ErrorPolicy_Igno>(dest.tx_falloff, "tx_falloff", db);
+    ReadField<ErrorPolicy_Igno>(dest.gloss_mir, "gloss_mir", db);
+    ReadField<ErrorPolicy_Igno>(dest.gloss_tra, "gloss_tra", db);
+    ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_mir, "adapt_thresh_mir", db);
+    ReadField<ErrorPolicy_Igno>(dest.adapt_thresh_tra, "adapt_thresh_tra", db);
+    ReadField<ErrorPolicy_Igno>(dest.aniso_gloss_mir, "aniso_gloss_mir", db);
+    ReadField<ErrorPolicy_Igno>(dest.dist_mir, "dist_mir", db);
+    ReadField<ErrorPolicy_Igno>(dest.hasize, "hasize", db);
+    ReadField<ErrorPolicy_Igno>(dest.flaresize, "flaresize", db);
+    ReadField<ErrorPolicy_Igno>(dest.subsize, "subsize", db);
+    ReadField<ErrorPolicy_Igno>(dest.flareboost, "flareboost", db);
+    ReadField<ErrorPolicy_Igno>(dest.strand_sta, "strand_sta", db);
+    ReadField<ErrorPolicy_Igno>(dest.strand_end, "strand_end", db);
+    ReadField<ErrorPolicy_Igno>(dest.strand_ease, "strand_ease", db);
+    ReadField<ErrorPolicy_Igno>(dest.strand_surfnor, "strand_surfnor", db);
+    ReadField<ErrorPolicy_Igno>(dest.strand_min, "strand_min", db);
+    ReadField<ErrorPolicy_Igno>(dest.strand_widthfade, "strand_widthfade", db);
+    ReadField<ErrorPolicy_Igno>(dest.sbias, "sbias", db);
+    ReadField<ErrorPolicy_Igno>(dest.lbias, "lbias", db);
+    ReadField<ErrorPolicy_Igno>(dest.shad_alpha, "shad_alpha", db);
+    ReadField<ErrorPolicy_Igno>(dest.param, "param", db);
+    ReadField<ErrorPolicy_Igno>(dest.rms, "rms", db);
+    ReadField<ErrorPolicy_Igno>(dest.rampfac_col, "rampfac_col", db);
+    ReadField<ErrorPolicy_Igno>(dest.rampfac_spec, "rampfac_spec", db);
+    ReadField<ErrorPolicy_Igno>(dest.friction, "friction", db);
+    ReadField<ErrorPolicy_Igno>(dest.fh, "fh", db);
+    ReadField<ErrorPolicy_Igno>(dest.reflect, "reflect", db);
+    ReadField<ErrorPolicy_Igno>(dest.fhdist, "fhdist", db);
+    ReadField<ErrorPolicy_Igno>(dest.xyfrict, "xyfrict", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_radius, "sss_radius", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_col, "sss_col", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_error, "sss_error", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_scale, "sss_scale", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_ior, "sss_ior", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_colfac, "sss_colfac", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_texfac, "sss_texfac", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_front, "sss_front", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_back, "sss_back", db);
+
+    ReadField<ErrorPolicy_Igno>(dest.material_type, "material_type", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.ray_depth, "ray_depth", db);
+    ReadField<ErrorPolicy_Igno>(dest.ray_depth_tra, "ray_depth_tra", db);
+    ReadField<ErrorPolicy_Igno>(dest.samp_gloss_mir, "samp_gloss_mir", db);
+    ReadField<ErrorPolicy_Igno>(dest.samp_gloss_tra, "samp_gloss_tra", db);
+    ReadField<ErrorPolicy_Igno>(dest.fadeto_mir, "fadeto_mir", db);
+    ReadField<ErrorPolicy_Igno>(dest.shade_flag, "shade_flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.flarec, "flarec", db);
+    ReadField<ErrorPolicy_Igno>(dest.starc, "starc", db);
+    ReadField<ErrorPolicy_Igno>(dest.linec, "linec", db);
+    ReadField<ErrorPolicy_Igno>(dest.ringc, "ringc", db);
+    ReadField<ErrorPolicy_Igno>(dest.pr_lamp, "pr_lamp", db);
+    ReadField<ErrorPolicy_Igno>(dest.pr_texture, "pr_texture", db);
+    ReadField<ErrorPolicy_Igno>(dest.ml_flag, "ml_flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.diff_shader, "diff_shader", db);
+    ReadField<ErrorPolicy_Igno>(dest.spec_shader, "spec_shader", db);
+    ReadField<ErrorPolicy_Igno>(dest.texco, "texco", db);
+    ReadField<ErrorPolicy_Igno>(dest.mapto, "mapto", db);
+    ReadField<ErrorPolicy_Igno>(dest.ramp_show, "ramp_show", db);
+    ReadField<ErrorPolicy_Igno>(dest.pad3, "pad3", db);
+    ReadField<ErrorPolicy_Igno>(dest.dynamode, "dynamode", db);
+    ReadField<ErrorPolicy_Igno>(dest.pad2, "pad2", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_flag, "sss_flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.sss_preset, "sss_preset", db);
+    ReadField<ErrorPolicy_Igno>(dest.shadowonly_flag, "shadowonly_flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.index, "index", db);
+    ReadField<ErrorPolicy_Igno>(dest.vcol_alpha, "vcol_alpha", db);
+    ReadField<ErrorPolicy_Igno>(dest.pad4, "pad4", db);
+
+    ReadField<ErrorPolicy_Igno>(dest.seed1, "seed1", db);
+    ReadField<ErrorPolicy_Igno>(dest.seed2, "seed2", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MTexPoly>(
+        MTexPoly &dest,
+        const FileDatabase &db) const {
+
+    {
+        std::shared_ptr<Image> tpage;
+        ReadFieldPtr<ErrorPolicy_Igno>(tpage, "*tpage", db);
+        dest.tpage = tpage.get();
+    }
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.transp, "transp", db);
+    ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
+    ReadField<ErrorPolicy_Igno>(dest.tile, "tile", db);
+    ReadField<ErrorPolicy_Igno>(dest.pad, "pad", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Mesh>(
+        Mesh &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+    ReadField<ErrorPolicy_Fail>(dest.totface, "totface", db);
+    ReadField<ErrorPolicy_Fail>(dest.totedge, "totedge", db);
+    ReadField<ErrorPolicy_Fail>(dest.totvert, "totvert", db);
+    ReadField<ErrorPolicy_Igno>(dest.totloop, "totloop", db);
+    ReadField<ErrorPolicy_Igno>(dest.totpoly, "totpoly", db);
+    ReadField<ErrorPolicy_Igno>(dest.subdiv, "subdiv", db);
+    ReadField<ErrorPolicy_Igno>(dest.subdivr, "subdivr", db);
+    ReadField<ErrorPolicy_Igno>(dest.subsurftype, "subsurftype", db);
+    ReadField<ErrorPolicy_Igno>(dest.smoothresh, "smoothresh", db);
+    ReadFieldPtr<ErrorPolicy_Fail>(dest.mface, "*mface", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.mtface, "*mtface", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.tface, "*tface", db);
+    ReadFieldPtr<ErrorPolicy_Fail>(dest.mvert, "*mvert", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.medge, "*medge", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.mloop, "*mloop", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopuv, "*mloopuv", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopcol, "*mloopcol", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.mpoly, "*mpoly", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.mtpoly, "*mtpoly", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.dvert, "*dvert", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol, "*mcol", db);
+    ReadFieldPtr<ErrorPolicy_Fail>(dest.mat, "**mat", db);
+
+    ReadField<ErrorPolicy_Igno>(dest.vdata, "vdata", db);
+    ReadField<ErrorPolicy_Igno>(dest.edata, "edata", db);
+    ReadField<ErrorPolicy_Igno>(dest.fdata, "fdata", db);
+    ReadField<ErrorPolicy_Igno>(dest.pdata, "pdata", db);
+    ReadField<ErrorPolicy_Warn>(dest.ldata, "ldata", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MDeformVert>(
+        MDeformVert &dest,
+        const FileDatabase &db) const {
+
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.dw, "*dw", db);
+    ReadField<ErrorPolicy_Igno>(dest.totweight, "totweight", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<World>(
+        World &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MLoopCol>(
+        MLoopCol &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Igno>(dest.r, "r", db);
+    ReadField<ErrorPolicy_Igno>(dest.g, "g", db);
+    ReadField<ErrorPolicy_Igno>(dest.b, "b", db);
+    ReadField<ErrorPolicy_Igno>(dest.a, "a", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MVert>(
+        MVert &dest,
+        const FileDatabase &db) const {
+
+    ReadFieldArray<ErrorPolicy_Fail>(dest.co, "co", db);
+    ReadFieldArray<ErrorPolicy_Fail>(dest.no, "no", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+    //ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db);
+    ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MEdge>(
+        MEdge &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.v1, "v1", db);
+    ReadField<ErrorPolicy_Fail>(dest.v2, "v2", db);
+    ReadField<ErrorPolicy_Igno>(dest.crease, "crease", db);
+    ReadField<ErrorPolicy_Igno>(dest.bweight, "bweight", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MLoopUV>(
+        MLoopUV &dest,
+        const FileDatabase &db) const {
+
+    ReadFieldArray<ErrorPolicy_Igno>(dest.uv, "uv", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<GroupObject>(
+        GroupObject &dest,
+        const FileDatabase &db) const {
+
+    ReadFieldPtr<ErrorPolicy_Fail>(dest.prev, "*prev", db);
+    ReadFieldPtr<ErrorPolicy_Fail>(dest.next, "*next", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.ob, "*ob", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<ListBase>(
+        ListBase &dest,
+        const FileDatabase &db) const {
+
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.first, "*first", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.last, "*last", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MLoop>(
+        MLoop &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Igno>(dest.v, "v", db);
+    ReadField<ErrorPolicy_Igno>(dest.e, "e", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<ModifierData>(
+        ModifierData &dest,
+        const FileDatabase &db) const {
+
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.next, "*next", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.prev, "*prev", db);
+    ReadField<ErrorPolicy_Igno>(dest.type, "type", db);
+    ReadField<ErrorPolicy_Igno>(dest.mode, "mode", db);
+    ReadFieldArray<ErrorPolicy_Igno>(dest.name, "name", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<ID>(
+        ID &dest,
+        const FileDatabase &db) const {
+
+    ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MCol>(
+        MCol &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.r, "r", db);
+    ReadField<ErrorPolicy_Fail>(dest.g, "g", db);
+    ReadField<ErrorPolicy_Fail>(dest.b, "b", db);
+    ReadField<ErrorPolicy_Fail>(dest.a, "a", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MPoly>(
+        MPoly &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Igno>(dest.loopstart, "loopstart", db);
+    ReadField<ErrorPolicy_Igno>(dest.totloop, "totloop", db);
+    ReadField<ErrorPolicy_Igno>(dest.mat_nr, "mat_nr", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Scene>(
+        Scene &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.camera, "*camera", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.world, "*world", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.basact, "*basact", db);
+    ReadField<ErrorPolicy_Igno>(dest.base, "base", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Library>(
+        Library &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+    ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
+    ReadFieldArray<ErrorPolicy_Fail>(dest.filename, "filename", db);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.parent, "*parent", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Tex>(
+        Tex &dest,
+        const FileDatabase &db) const {
+    short temp_short = 0;
+    ReadField<ErrorPolicy_Igno>(temp_short, "imaflag", db);
+    dest.imaflag = static_cast<Assimp::Blender::Tex::ImageFlags>(temp_short);
+    int temp = 0;
+    ReadField<ErrorPolicy_Fail>(temp, "type", db);
+    dest.type = static_cast<Assimp::Blender::Tex::Type>(temp);
+    ReadFieldPtr<ErrorPolicy_Warn>(dest.ima, "*ima", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Camera>(
+        Camera &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+    int temp = 0;
+    ReadField<ErrorPolicy_Warn>(temp, "type", db);
+    dest.type = static_cast<Assimp::Blender::Camera::Type>(temp);
+    ReadField<ErrorPolicy_Warn>(temp, "flag", db);
+    dest.flag = static_cast<Assimp::Blender::Camera::Type>(temp);
+    ReadField<ErrorPolicy_Warn>(dest.lens, "lens", db);
+    ReadField<ErrorPolicy_Warn>(dest.sensor_x, "sensor_x", db);
+    ReadField<ErrorPolicy_Igno>(dest.clipsta, "clipsta", db);
+    ReadField<ErrorPolicy_Igno>(dest.clipend, "clipend", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<MirrorModifierData>(
+        MirrorModifierData &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.modifier, "modifier", db);
+    ReadField<ErrorPolicy_Igno>(dest.axis, "axis", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.tolerance, "tolerance", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.mirror_ob, "*mirror_ob", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure ::Convert<Image>(
+        Image &dest,
+        const FileDatabase &db) const {
+
+    ReadField<ErrorPolicy_Fail>(dest.id, "id", db);
+    ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
+    ReadField<ErrorPolicy_Igno>(dest.ok, "ok", db);
+    ReadField<ErrorPolicy_Igno>(dest.flag, "flag", db);
+    ReadField<ErrorPolicy_Igno>(dest.source, "source", db);
+    ReadField<ErrorPolicy_Igno>(dest.type, "type", db);
+    ReadField<ErrorPolicy_Igno>(dest.pad, "pad", db);
+    ReadField<ErrorPolicy_Igno>(dest.pad1, "pad1", db);
+    ReadField<ErrorPolicy_Igno>(dest.lastframe, "lastframe", db);
+    ReadField<ErrorPolicy_Igno>(dest.tpageflag, "tpageflag", db);
+    ReadField<ErrorPolicy_Igno>(dest.totbind, "totbind", db);
+    ReadField<ErrorPolicy_Igno>(dest.xrep, "xrep", db);
+    ReadField<ErrorPolicy_Igno>(dest.yrep, "yrep", db);
+    ReadField<ErrorPolicy_Igno>(dest.twsta, "twsta", db);
+    ReadField<ErrorPolicy_Igno>(dest.twend, "twend", db);
+    ReadFieldPtr<ErrorPolicy_Igno>(dest.packedfile, "*packedfile", db);
+    ReadField<ErrorPolicy_Igno>(dest.lastupdate, "lastupdate", db);
+    ReadField<ErrorPolicy_Igno>(dest.lastused, "lastused", db);
+    ReadField<ErrorPolicy_Igno>(dest.animspeed, "animspeed", db);
+    ReadField<ErrorPolicy_Igno>(dest.gen_x, "gen_x", db);
+    ReadField<ErrorPolicy_Igno>(dest.gen_y, "gen_y", db);
+    ReadField<ErrorPolicy_Igno>(dest.gen_type, "gen_type", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure::Convert<CustomData>(
+        CustomData &dest,
+        const FileDatabase &db) const {
+    ReadFieldArray<ErrorPolicy_Warn>(dest.typemap, "typemap", db);
+    ReadField<ErrorPolicy_Warn>(dest.totlayer, "totlayer", db);
+    ReadField<ErrorPolicy_Warn>(dest.maxlayer, "maxlayer", db);
+    ReadField<ErrorPolicy_Warn>(dest.totsize, "totsize", db);
+    ReadFieldPtrVector<ErrorPolicy_Warn>(dest.layers, "*layers", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <>
+void Structure::Convert<CustomDataLayer>(
+        CustomDataLayer &dest,
+        const FileDatabase &db) const {
+    ReadField<ErrorPolicy_Fail>(dest.type, "type", db);
+    ReadField<ErrorPolicy_Fail>(dest.offset, "offset", db);
+    ReadField<ErrorPolicy_Fail>(dest.flag, "flag", db);
+    ReadField<ErrorPolicy_Fail>(dest.active, "active", db);
+    ReadField<ErrorPolicy_Fail>(dest.active_rnd, "active_rnd", db);
+    ReadField<ErrorPolicy_Fail>(dest.active_clone, "active_clone", db);
+    ReadField<ErrorPolicy_Fail>(dest.active_mask, "active_mask", db);
+    ReadField<ErrorPolicy_Fail>(dest.uid, "uid", db);
+    ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
+    ReadCustomDataPtr<ErrorPolicy_Fail>(dest.data, dest.type, "*data", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+void DNA::RegisterConverters() {
+
+    converters["Object"] = DNA::FactoryPair(&Structure::Allocate<Object>, &Structure::Convert<Object>);
+    converters["Group"] = DNA::FactoryPair(&Structure::Allocate<Group>, &Structure::Convert<Group>);
+    converters["MTex"] = DNA::FactoryPair(&Structure::Allocate<MTex>, &Structure::Convert<MTex>);
+    converters["TFace"] = DNA::FactoryPair(&Structure::Allocate<TFace>, &Structure::Convert<TFace>);
+    converters["SubsurfModifierData"] = DNA::FactoryPair(&Structure::Allocate<SubsurfModifierData>, &Structure::Convert<SubsurfModifierData>);
+    converters["MFace"] = DNA::FactoryPair(&Structure::Allocate<MFace>, &Structure::Convert<MFace>);
+    converters["Lamp"] = DNA::FactoryPair(&Structure::Allocate<Lamp>, &Structure::Convert<Lamp>);
+    converters["MDeformWeight"] = DNA::FactoryPair(&Structure::Allocate<MDeformWeight>, &Structure::Convert<MDeformWeight>);
+    converters["PackedFile"] = DNA::FactoryPair(&Structure::Allocate<PackedFile>, &Structure::Convert<PackedFile>);
+    converters["Base"] = DNA::FactoryPair(&Structure::Allocate<Base>, &Structure::Convert<Base>);
+    converters["MTFace"] = DNA::FactoryPair(&Structure::Allocate<MTFace>, &Structure::Convert<MTFace>);
+    converters["Material"] = DNA::FactoryPair(&Structure::Allocate<Material>, &Structure::Convert<Material>);
+    converters["MTexPoly"] = DNA::FactoryPair(&Structure::Allocate<MTexPoly>, &Structure::Convert<MTexPoly>);
+    converters["Mesh"] = DNA::FactoryPair(&Structure::Allocate<Mesh>, &Structure::Convert<Mesh>);
+    converters["MDeformVert"] = DNA::FactoryPair(&Structure::Allocate<MDeformVert>, &Structure::Convert<MDeformVert>);
+    converters["World"] = DNA::FactoryPair(&Structure::Allocate<World>, &Structure::Convert<World>);
+    converters["MLoopCol"] = DNA::FactoryPair(&Structure::Allocate<MLoopCol>, &Structure::Convert<MLoopCol>);
+    converters["MVert"] = DNA::FactoryPair(&Structure::Allocate<MVert>, &Structure::Convert<MVert>);
+    converters["MEdge"] = DNA::FactoryPair(&Structure::Allocate<MEdge>, &Structure::Convert<MEdge>);
+    converters["MLoopUV"] = DNA::FactoryPair(&Structure::Allocate<MLoopUV>, &Structure::Convert<MLoopUV>);
+    converters["GroupObject"] = DNA::FactoryPair(&Structure::Allocate<GroupObject>, &Structure::Convert<GroupObject>);
+    converters["ListBase"] = DNA::FactoryPair(&Structure::Allocate<ListBase>, &Structure::Convert<ListBase>);
+    converters["MLoop"] = DNA::FactoryPair(&Structure::Allocate<MLoop>, &Structure::Convert<MLoop>);
+    converters["ModifierData"] = DNA::FactoryPair(&Structure::Allocate<ModifierData>, &Structure::Convert<ModifierData>);
+    converters["ID"] = DNA::FactoryPair(&Structure::Allocate<ID>, &Structure::Convert<ID>);
+    converters["MCol"] = DNA::FactoryPair(&Structure::Allocate<MCol>, &Structure::Convert<MCol>);
+    converters["MPoly"] = DNA::FactoryPair(&Structure::Allocate<MPoly>, &Structure::Convert<MPoly>);
+    converters["Scene"] = DNA::FactoryPair(&Structure::Allocate<Scene>, &Structure::Convert<Scene>);
+    converters["Library"] = DNA::FactoryPair(&Structure::Allocate<Library>, &Structure::Convert<Library>);
+    converters["Tex"] = DNA::FactoryPair(&Structure::Allocate<Tex>, &Structure::Convert<Tex>);
+    converters["Camera"] = DNA::FactoryPair(&Structure::Allocate<Camera>, &Structure::Convert<Camera>);
+    converters["MirrorModifierData"] = DNA::FactoryPair(&Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData>);
+    converters["Image"] = DNA::FactoryPair(&Structure::Allocate<Image>, &Structure::Convert<Image>);
+    converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
+    converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
+}
+
+#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 252 - 277
code/Blender/BlenderScene.h → code/AssetLib/Blender/BlenderScene.h

@@ -48,14 +48,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "BlenderDNA.h"
 
-namespace Assimp    {
+namespace Assimp {
 namespace Blender {
 
 // Minor parts of this file are extracts from blender data structures,
 // declared in the ./source/blender/makesdna directory.
 // Stuff that is not used by Assimp is commented.
 
-
 // NOTE
 // this file serves as input data to the `./scripts/genblenddna.py`
 // script. This script generates the actual binding code to read a
@@ -95,15 +94,15 @@ namespace Blender {
 
 // warn if field is missing, substitute default value
 #ifdef WARN
-#  undef WARN
+#undef WARN
 #endif
-#define WARN 
+#define WARN
 
 // fail the import if the field does not exist
 #ifdef FAIL
-#  undef FAIL
+#undef FAIL
 #endif
-#define FAIL 
+#define FAIL
 
 struct Object;
 struct MTex;
@@ -117,7 +116,7 @@ static const size_t MaxNameLen = 1024;
 
 // -------------------------------------------------------------------------------
 struct ID : ElemBase {
-    char name[ MaxNameLen ] WARN;
+    char name[MaxNameLen] WARN;
     short flag;
 };
 
@@ -127,17 +126,16 @@ struct ListBase : ElemBase {
     std::shared_ptr<ElemBase> last;
 };
 
-
 // -------------------------------------------------------------------------------
 struct PackedFile : ElemBase {
-     int size WARN;
-     int seek WARN;
-     std::shared_ptr< FileOffset > data WARN;
+    int size WARN;
+    int seek WARN;
+    std::shared_ptr<FileOffset> data WARN;
 };
 
 // -------------------------------------------------------------------------------
 struct GroupObject : ElemBase {
-    std::shared_ptr<GroupObject> prev,next FAIL;
+    std::shared_ptr<GroupObject> prev, next FAIL;
     std::shared_ptr<Object> ob;
 };
 
@@ -157,23 +155,20 @@ struct World : ElemBase {
 // -------------------------------------------------------------------------------
 struct MVert : ElemBase {
     float co[3] FAIL;
-    float no[3] FAIL;       // readed as short and divided through / 32767.f
+    float no[3] FAIL; // readed as short and divided through / 32767.f
     char flag;
     int mat_nr WARN;
     int bweight;
 
-    MVert() : ElemBase()
-        , flag(0)
-        , mat_nr(0)
-        , bweight(0)
-    {}
+    MVert() :
+            ElemBase(), flag(0), mat_nr(0), bweight(0) {}
 };
 
 // -------------------------------------------------------------------------------
 struct MEdge : ElemBase {
-      int v1, v2 FAIL;
-      char crease, bweight;
-      short flag;
+    int v1, v2 FAIL;
+    char crease, bweight;
+    short flag;
 };
 
 // -------------------------------------------------------------------------------
@@ -190,7 +185,7 @@ struct MLoopUV : ElemBase {
 // -------------------------------------------------------------------------------
 // Note that red and blue are not swapped, as with MCol
 struct MLoopCol : ElemBase {
-	unsigned char r, g, b, a;
+    unsigned char r, g, b, a;
 };
 
 // -------------------------------------------------------------------------------
@@ -203,19 +198,19 @@ struct MPoly : ElemBase {
 
 // -------------------------------------------------------------------------------
 struct MTexPoly : ElemBase {
-    Image* tpage;
+    Image *tpage;
     char flag, transp;
     short mode, tile, pad;
 };
 
 // -------------------------------------------------------------------------------
 struct MCol : ElemBase {
-    char r,g,b,a FAIL;
+    char r, g, b, a FAIL;
 };
 
 // -------------------------------------------------------------------------------
 struct MFace : ElemBase {
-    int v1,v2,v3,v4 FAIL;
+    int v1, v2, v3, v4 FAIL;
     int mat_nr FAIL;
     char flag;
 };
@@ -232,13 +227,9 @@ struct TFace : ElemBase {
 
 // -------------------------------------------------------------------------------
 struct MTFace : ElemBase {
-	MTFace()
-	: flag(0)
-	, mode(0)
-	, tile(0)
-	, unwrap(0)
-	{
-	}
+    MTFace() :
+            flag(0), mode(0), tile(0), unwrap(0) {
+    }
 
     float uv[4][2] FAIL;
     char flag;
@@ -250,31 +241,31 @@ struct MTFace : ElemBase {
 };
 
 // -------------------------------------------------------------------------------
-struct MDeformWeight : ElemBase  {
-      int    def_nr FAIL;
-      float  weight FAIL;
+struct MDeformWeight : ElemBase {
+    int def_nr FAIL;
+    float weight FAIL;
 };
 
 // -------------------------------------------------------------------------------
-struct MDeformVert : ElemBase  {
+struct MDeformVert : ElemBase {
     vector<MDeformWeight> dw WARN;
     int totweight;
 };
 
 // -------------------------------------------------------------------------------
-#define MA_RAYMIRROR    0x40000
+#define MA_RAYMIRROR 0x40000
 #define MA_TRANSPARENCY 0x10000
-#define MA_RAYTRANSP    0x20000
-#define MA_ZTRANSP      0x00040
+#define MA_RAYTRANSP 0x20000
+#define MA_ZTRANSP 0x00040
 
 struct Material : ElemBase {
     ID id FAIL;
 
-    float r,g,b WARN;
-    float specr,specg,specb WARN;
+    float r, g, b WARN;
+    float specr, specg, specb WARN;
     short har;
-    float ambr,ambg,ambb WARN;
-    float mirr,mirg,mirb;
+    float ambr, ambg, ambb WARN;
+    float mirr, mirg, mirb;
     float emit WARN;
     float ray_mirror;
     float alpha WARN;
@@ -399,20 +390,19 @@ struct CustomDataLayer : ElemBase {
     int active_mask;
     int uid;
     char name[64];
-    std::shared_ptr<ElemBase> data;     // must be converted to real type according type member
-
-    CustomDataLayer()
-        : ElemBase()
-        , type(0)
-        , offset(0)
-        , flag(0)
-        , active(0)
-        , active_rnd(0)
-        , active_clone(0)
-        , active_mask(0)
-        , uid(0)
-        , data(nullptr)
-    {
+    std::shared_ptr<ElemBase> data; // must be converted to real type according type member
+
+    CustomDataLayer() :
+            ElemBase(),
+            type(0),
+            offset(0),
+            flag(0),
+            active(0),
+            active_rnd(0),
+            active_clone(0),
+            active_mask(0),
+            uid(0),
+            data(nullptr) {
         memset(name, 0, sizeof name);
     }
 };
@@ -430,8 +420,8 @@ CustomData 208
     CustomDataExternal *external 200 8
 */
 struct CustomData : ElemBase {
-    vector<std::shared_ptr<struct CustomDataLayer> > layers;
-    int typemap[42];    // CD_NUMTYPES
+    vector<std::shared_ptr<struct CustomDataLayer>> layers;
+    int typemap[42]; // CD_NUMTYPES
     int totlayer;
     int maxlayer;
     int totsize;
@@ -469,7 +459,7 @@ struct Mesh : ElemBase {
     vector<MDeformVert> dvert;
     vector<MCol> mcol;
 
-    vector< std::shared_ptr<Material> > mat FAIL;
+    vector<std::shared_ptr<Material>> mat FAIL;
 
     struct CustomData vdata;
     struct CustomData edata;
@@ -490,142 +480,141 @@ struct Library : ElemBase {
 // -------------------------------------------------------------------------------
 struct Camera : ElemBase {
     enum Type {
-          Type_PERSP    =   0
-         ,Type_ORTHO    =   1
+        Type_PERSP = 0,
+        Type_ORTHO = 1
     };
 
     ID id FAIL;
 
-    Type type,flag WARN;
+    Type type, flag WARN;
     float lens WARN;
     float sensor_x WARN;
     float clipsta, clipend;
 };
 
-
 // -------------------------------------------------------------------------------
 struct Lamp : ElemBase {
 
     enum FalloffType {
-         FalloffType_Constant   = 0x0
-        ,FalloffType_InvLinear  = 0x1
-        ,FalloffType_InvSquare  = 0x2
+        FalloffType_Constant = 0x0,
+        FalloffType_InvLinear = 0x1,
+        FalloffType_InvSquare = 0x2
         //,FalloffType_Curve    = 0x3
         //,FalloffType_Sliders  = 0x4
     };
 
     enum Type {
-         Type_Local         = 0x0
-        ,Type_Sun           = 0x1
-        ,Type_Spot          = 0x2
-        ,Type_Hemi          = 0x3
-        ,Type_Area          = 0x4
+        Type_Local = 0x0,
+        Type_Sun = 0x1,
+        Type_Spot = 0x2,
+        Type_Hemi = 0x3,
+        Type_Area = 0x4
         //,Type_YFPhoton    = 0x5
     };
 
-      ID id FAIL;
-      //AnimData *adt;
+    ID id FAIL;
+    //AnimData *adt;
 
-      Type type FAIL;
-      short flags;
+    Type type FAIL;
+    short flags;
 
-      //int mode;
+    //int mode;
 
-      short colormodel, totex;
-      float r,g,b,k WARN;
-      //float shdwr, shdwg, shdwb;
+    short colormodel, totex;
+    float r, g, b, k WARN;
+    //float shdwr, shdwg, shdwb;
 
-      float energy, dist, spotsize, spotblend;
-      //float haint;
+    float energy, dist, spotsize, spotblend;
+    //float haint;
 
-      float constant_coefficient;
-      float linear_coefficient;
-      float quadratic_coefficient;
+    float constant_coefficient;
+    float linear_coefficient;
+    float quadratic_coefficient;
 
-      float att1, att2;
-      //struct CurveMapping *curfalloff;
-      FalloffType falloff_type;
+    float att1, att2;
+    //struct CurveMapping *curfalloff;
+    FalloffType falloff_type;
 
-      //float clipsta, clipend, shadspotsize;
-      //float bias, soft, compressthresh;
-      //short bufsize, samp, buffers, filtertype;
-      //char bufflag, buftype;
+    //float clipsta, clipend, shadspotsize;
+    //float bias, soft, compressthresh;
+    //short bufsize, samp, buffers, filtertype;
+    //char bufflag, buftype;
 
-      //short ray_samp, ray_sampy, ray_sampz;
-      //short ray_samp_type;
-      short area_shape;
-      float area_size, area_sizey, area_sizez;
-      //float adapt_thresh;
-      //short ray_samp_method;
+    //short ray_samp, ray_sampy, ray_sampz;
+    //short ray_samp_type;
+    short area_shape;
+    float area_size, area_sizey, area_sizez;
+    //float adapt_thresh;
+    //short ray_samp_method;
 
-      //short texact, shadhalostep;
+    //short texact, shadhalostep;
 
-      //short sun_effect_type;
-      //short skyblendtype;
-      //float horizon_brightness;
-      //float spread;
-      float sun_brightness;
-      //float sun_size;
-      //float backscattered_light;
-      //float sun_intensity;
-      //float atm_turbidity;
-      //float atm_inscattering_factor;
-      //float atm_extinction_factor;
-      //float atm_distance_factor;
-      //float skyblendfac;
-      //float sky_exposure;
-      //short sky_colorspace;
+    //short sun_effect_type;
+    //short skyblendtype;
+    //float horizon_brightness;
+    //float spread;
+    float sun_brightness;
+    //float sun_size;
+    //float backscattered_light;
+    //float sun_intensity;
+    //float atm_turbidity;
+    //float atm_inscattering_factor;
+    //float atm_extinction_factor;
+    //float atm_distance_factor;
+    //float skyblendfac;
+    //float sky_exposure;
+    //short sky_colorspace;
 
-      // int YF_numphotons, YF_numsearch;
-      // short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
-      // float YF_causticblur, YF_ltradius;
+    // int YF_numphotons, YF_numsearch;
+    // short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad;
+    // float YF_causticblur, YF_ltradius;
 
-      // float YF_glowint, YF_glowofs;
-      // short YF_glowtype, YF_pad2;
+    // float YF_glowint, YF_glowofs;
+    // short YF_glowtype, YF_pad2;
 
-      //struct Ipo *ipo;
-      //struct MTex *mtex[18];
-      // short pr_texture;
+    //struct Ipo *ipo;
+    //struct MTex *mtex[18];
+    // short pr_texture;
 
-      //struct PreviewImage *preview;
+    //struct PreviewImage *preview;
 };
 
 // -------------------------------------------------------------------------------
-struct ModifierData : ElemBase  {
+struct ModifierData : ElemBase {
     enum ModifierType {
-      eModifierType_None = 0,
-      eModifierType_Subsurf,
-      eModifierType_Lattice,
-      eModifierType_Curve,
-      eModifierType_Build,
-      eModifierType_Mirror,
-      eModifierType_Decimate,
-      eModifierType_Wave,
-      eModifierType_Armature,
-      eModifierType_Hook,
-      eModifierType_Softbody,
-      eModifierType_Boolean,
-      eModifierType_Array,
-      eModifierType_EdgeSplit,
-      eModifierType_Displace,
-      eModifierType_UVProject,
-      eModifierType_Smooth,
-      eModifierType_Cast,
-      eModifierType_MeshDeform,
-      eModifierType_ParticleSystem,
-      eModifierType_ParticleInstance,
-      eModifierType_Explode,
-      eModifierType_Cloth,
-      eModifierType_Collision,
-      eModifierType_Bevel,
-      eModifierType_Shrinkwrap,
-      eModifierType_Fluidsim,
-      eModifierType_Mask,
-      eModifierType_SimpleDeform,
-      eModifierType_Multires,
-      eModifierType_Surface,
-      eModifierType_Smoke,
-      eModifierType_ShapeKey
+        eModifierType_None = 0,
+        eModifierType_Subsurf,
+        eModifierType_Lattice,
+        eModifierType_Curve,
+        eModifierType_Build,
+        eModifierType_Mirror,
+        eModifierType_Decimate,
+        eModifierType_Wave,
+        eModifierType_Armature,
+        eModifierType_Hook,
+        eModifierType_Softbody,
+        eModifierType_Boolean,
+        eModifierType_Array,
+        eModifierType_EdgeSplit,
+        eModifierType_Displace,
+        eModifierType_UVProject,
+        eModifierType_Smooth,
+        eModifierType_Cast,
+        eModifierType_MeshDeform,
+        eModifierType_ParticleSystem,
+        eModifierType_ParticleInstance,
+        eModifierType_Explode,
+        eModifierType_Cloth,
+        eModifierType_Collision,
+        eModifierType_Bevel,
+        eModifierType_Shrinkwrap,
+        eModifierType_Fluidsim,
+        eModifierType_Mask,
+        eModifierType_SimpleDeform,
+        eModifierType_Multires,
+        eModifierType_Surface,
+        eModifierType_Smoke,
+        eModifierType_ShapeKey
     };
 
     std::shared_ptr<ElemBase> next WARN;
@@ -636,7 +625,7 @@ struct ModifierData : ElemBase  {
 };
 
 // -------------------------------------------------------------------------------
-struct SubsurfModifierData : ElemBase  {
+struct SubsurfModifierData : ElemBase {
 
     enum Type {
 
@@ -646,13 +635,13 @@ struct SubsurfModifierData : ElemBase  {
 
     enum Flags {
         // some omitted
-        FLAGS_SubsurfUV     =1<<3
+        FLAGS_SubsurfUV = 1 << 3
     };
 
     ModifierData modifier FAIL;
     short subdivType WARN;
     short levels FAIL;
-    short renderLevels ;
+    short renderLevels;
     short flags;
 };
 
@@ -660,13 +649,13 @@ struct SubsurfModifierData : ElemBase  {
 struct MirrorModifierData : ElemBase {
 
     enum Flags {
-        Flags_CLIPPING      =1<<0,
-        Flags_MIRROR_U      =1<<1,
-        Flags_MIRROR_V      =1<<2,
-        Flags_AXIS_X        =1<<3,
-        Flags_AXIS_Y        =1<<4,
-        Flags_AXIS_Z        =1<<5,
-        Flags_VGROUP        =1<<6
+        Flags_CLIPPING = 1 << 0,
+        Flags_MIRROR_U = 1 << 1,
+        Flags_MIRROR_V = 1 << 2,
+        Flags_AXIS_X = 1 << 3,
+        Flags_AXIS_Y = 1 << 4,
+        Flags_AXIS_Z = 1 << 5,
+        Flags_VGROUP = 1 << 6
     };
 
     ModifierData modifier FAIL;
@@ -677,22 +666,24 @@ struct MirrorModifierData : ElemBase {
 };
 
 // -------------------------------------------------------------------------------
-struct Object : ElemBase  {
+struct Object : ElemBase {
     ID id FAIL;
 
     enum Type {
-         Type_EMPTY     =   0
-        ,Type_MESH      =   1
-        ,Type_CURVE     =   2
-        ,Type_SURF      =   3
-        ,Type_FONT      =   4
-        ,Type_MBALL     =   5
-
-        ,Type_LAMP      =   10
-        ,Type_CAMERA    =   11
-
-        ,Type_WAVE      =   21
-        ,Type_LATTICE   =   22
+        Type_EMPTY = 0,
+        Type_MESH = 1,
+        Type_CURVE = 2,
+        Type_SURF = 3,
+        Type_FONT = 4,
+        Type_MBALL = 5
+
+        ,
+        Type_LAMP = 10,
+        Type_CAMERA = 11
+
+        ,
+        Type_WAVE = 21,
+        Type_LATTICE = 22
     };
 
     Type type FAIL;
@@ -700,39 +691,29 @@ struct Object : ElemBase  {
     float parentinv[4][4] WARN;
     char parsubstr[32] WARN;
 
-    Object* parent WARN;
+    Object *parent WARN;
     std::shared_ptr<Object> track WARN;
 
-    std::shared_ptr<Object> proxy,proxy_from,proxy_group WARN;
+    std::shared_ptr<Object> proxy, proxy_from, proxy_group WARN;
     std::shared_ptr<Group> dup_group WARN;
     std::shared_ptr<ElemBase> data FAIL;
 
     ListBase modifiers;
 
-    Object()
-    : ElemBase()
-    , type( Type_EMPTY )
-    , parent( nullptr )
-    , track()
-    , proxy()
-    , proxy_from()
-    , data() {
+    Object() :
+            ElemBase(), type(Type_EMPTY), parent(nullptr), track(), proxy(), proxy_from(), data() {
         // empty
     }
 };
 
-
 // -------------------------------------------------------------------------------
 struct Base : ElemBase {
-    Base* prev WARN;
+    Base *prev WARN;
     std::shared_ptr<Base> next WARN;
     std::shared_ptr<Object> object WARN;
 
-    Base() 
-    : ElemBase()
-    , prev( nullptr )
-    , next()
-    , object() {
+    Base() :
+            ElemBase(), prev(nullptr), next(), object() {
         // empty
         // empty
     }
@@ -748,11 +729,8 @@ struct Scene : ElemBase {
 
     ListBase base;
 
-    Scene()
-    : ElemBase()
-    , camera()
-    , world()
-    , basact() {
+    Scene() :
+            ElemBase(), camera(), world(), basact() {
         // empty
     }
 };
@@ -783,9 +761,9 @@ struct Image : ElemBase {
     short animspeed;
 
     short gen_x, gen_y, gen_type;
-    
-    Image()
-    : ElemBase() {
+
+    Image() :
+            ElemBase() {
         // empty
     }
 };
@@ -795,33 +773,33 @@ struct Tex : ElemBase {
 
     // actually, the only texture type we support is Type_IMAGE
     enum Type {
-         Type_CLOUDS        = 1
-        ,Type_WOOD          = 2
-        ,Type_MARBLE        = 3
-        ,Type_MAGIC         = 4
-        ,Type_BLEND         = 5
-        ,Type_STUCCI        = 6
-        ,Type_NOISE         = 7
-        ,Type_IMAGE         = 8
-        ,Type_PLUGIN        = 9
-        ,Type_ENVMAP        = 10
-        ,Type_MUSGRAVE      = 11
-        ,Type_VORONOI       = 12
-        ,Type_DISTNOISE     = 13
-        ,Type_POINTDENSITY  = 14
-        ,Type_VOXELDATA     = 15
+        Type_CLOUDS = 1,
+        Type_WOOD = 2,
+        Type_MARBLE = 3,
+        Type_MAGIC = 4,
+        Type_BLEND = 5,
+        Type_STUCCI = 6,
+        Type_NOISE = 7,
+        Type_IMAGE = 8,
+        Type_PLUGIN = 9,
+        Type_ENVMAP = 10,
+        Type_MUSGRAVE = 11,
+        Type_VORONOI = 12,
+        Type_DISTNOISE = 13,
+        Type_POINTDENSITY = 14,
+        Type_VOXELDATA = 15
     };
 
     enum ImageFlags {
-         ImageFlags_INTERPOL         = 1
-        ,ImageFlags_USEALPHA         = 2
-        ,ImageFlags_MIPMAP           = 4
-        ,ImageFlags_IMAROT           = 16
-        ,ImageFlags_CALCALPHA        = 32
-        ,ImageFlags_NORMALMAP        = 2048
-        ,ImageFlags_GAUSS_MIP        = 4096
-        ,ImageFlags_FILTER_MIN       = 8192
-        ,ImageFlags_DERIVATIVEMAP   = 16384
+        ImageFlags_INTERPOL = 1,
+        ImageFlags_USEALPHA = 2,
+        ImageFlags_MIPMAP = 4,
+        ImageFlags_IMAROT = 16,
+        ImageFlags_CALCALPHA = 32,
+        ImageFlags_NORMALMAP = 2048,
+        ImageFlags_GAUSS_MIP = 4096,
+        ImageFlags_FILTER_MIN = 8192,
+        ImageFlags_DERIVATIVEMAP = 16384
     };
 
     ID id FAIL;
@@ -876,11 +854,8 @@ struct Tex : ElemBase {
 
     //char use_nodes;
 
-    Tex()
-    : ElemBase()
-    , imaflag( ImageFlags_INTERPOL )
-    , type( Type_CLOUDS )
-    , ima() {
+    Tex() :
+            ElemBase(), imaflag(ImageFlags_INTERPOL), type(Type_CLOUDS), ima() {
         // empty
     }
 };
@@ -889,52 +864,52 @@ struct Tex : ElemBase {
 struct MTex : ElemBase {
 
     enum Projection {
-         Proj_N = 0
-        ,Proj_X = 1
-        ,Proj_Y = 2
-        ,Proj_Z = 3
+        Proj_N = 0,
+        Proj_X = 1,
+        Proj_Y = 2,
+        Proj_Z = 3
     };
 
     enum Flag {
-         Flag_RGBTOINT      = 0x1
-        ,Flag_STENCIL       = 0x2
-        ,Flag_NEGATIVE      = 0x4
-        ,Flag_ALPHAMIX      = 0x8
-        ,Flag_VIEWSPACE     = 0x10
+        Flag_RGBTOINT = 0x1,
+        Flag_STENCIL = 0x2,
+        Flag_NEGATIVE = 0x4,
+        Flag_ALPHAMIX = 0x8,
+        Flag_VIEWSPACE = 0x10
     };
 
     enum BlendType {
-         BlendType_BLEND            = 0
-        ,BlendType_MUL              = 1
-        ,BlendType_ADD              = 2
-        ,BlendType_SUB              = 3
-        ,BlendType_DIV              = 4
-        ,BlendType_DARK             = 5
-        ,BlendType_DIFF             = 6
-        ,BlendType_LIGHT            = 7
-        ,BlendType_SCREEN           = 8
-        ,BlendType_OVERLAY          = 9
-        ,BlendType_BLEND_HUE        = 10
-        ,BlendType_BLEND_SAT        = 11
-        ,BlendType_BLEND_VAL        = 12
-        ,BlendType_BLEND_COLOR      = 13
+        BlendType_BLEND = 0,
+        BlendType_MUL = 1,
+        BlendType_ADD = 2,
+        BlendType_SUB = 3,
+        BlendType_DIV = 4,
+        BlendType_DARK = 5,
+        BlendType_DIFF = 6,
+        BlendType_LIGHT = 7,
+        BlendType_SCREEN = 8,
+        BlendType_OVERLAY = 9,
+        BlendType_BLEND_HUE = 10,
+        BlendType_BLEND_SAT = 11,
+        BlendType_BLEND_VAL = 12,
+        BlendType_BLEND_COLOR = 13
     };
 
     enum MapType {
-         MapType_COL         = 1
-        ,MapType_NORM        = 2
-        ,MapType_COLSPEC     = 4
-        ,MapType_COLMIR      = 8
-        ,MapType_REF         = 16
-        ,MapType_SPEC        = 32
-        ,MapType_EMIT        = 64
-        ,MapType_ALPHA       = 128
-        ,MapType_HAR         = 256
-        ,MapType_RAYMIRR     = 512
-        ,MapType_TRANSLU     = 1024
-        ,MapType_AMB         = 2048
-        ,MapType_DISPLACE    = 4096
-        ,MapType_WARP        = 8192
+        MapType_COL = 1,
+        MapType_NORM = 2,
+        MapType_COLSPEC = 4,
+        MapType_COLMIR = 8,
+        MapType_REF = 16,
+        MapType_SPEC = 32,
+        MapType_EMIT = 64,
+        MapType_ALPHA = 128,
+        MapType_HAR = 256,
+        MapType_RAYMIRR = 512,
+        MapType_TRANSLU = 1024,
+        MapType_AMB = 2048,
+        MapType_DISPLACE = 4096,
+        MapType_WARP = 8192
     };
 
     // short texco, maptoneg;
@@ -945,7 +920,7 @@ struct MTex : ElemBase {
     std::shared_ptr<Tex> tex;
     char uvname[32];
 
-    Projection projx,projy,projz;
+    Projection projx, projy, projz;
     char mapping;
     float ofs[3], size[3], rot;
 
@@ -953,7 +928,7 @@ struct MTex : ElemBase {
     short colormodel, pmapto, pmaptoneg;
     //short normapspace, which_output;
     //char brush_map_mode;
-    float r,g,b,k WARN;
+    float r, g, b, k WARN;
     //float def_var, rt;
 
     //float colfac, varfac;
@@ -972,12 +947,12 @@ struct MTex : ElemBase {
     //float shadowfac;
     //float zenupfac, zendownfac, blendfac;
 
-    MTex()
-    : ElemBase() {
+    MTex() :
+            ElemBase() {
         // empty
     }
 };
 
-}
-}
+} // namespace Blender
+} // namespace Assimp
 #endif

+ 0 - 0
code/Blender/BlenderSceneGen.h → code/AssetLib/Blender/BlenderSceneGen.h


+ 0 - 0
code/Blender/BlenderTessellator.cpp → code/AssetLib/Blender/BlenderTessellator.cpp


+ 0 - 0
code/Blender/BlenderTessellator.h → code/AssetLib/Blender/BlenderTessellator.h


+ 0 - 0
code/C4D/C4DImporter.cpp → code/AssetLib/C4D/C4DImporter.cpp


+ 0 - 0
code/C4D/C4DImporter.h → code/AssetLib/C4D/C4DImporter.h


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 250 - 287
code/AssetLib/COB/COBLoader.cpp


+ 0 - 0
code/COB/COBLoader.h → code/AssetLib/COB/COBLoader.h


+ 0 - 0
code/COB/COBScene.h → code/AssetLib/COB/COBScene.h


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

@@ -178,7 +178,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
                         *ot++ = *buffer++;
 
                     *ot = '\0';
-                    nda->mNodeName.length = (ai_uint32)(ot-nda->mNodeName.data);
+                    nda->mNodeName.length = static_cast<ai_uint32>(ot-nda->mNodeName.data);
                 }
 
                 anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());

+ 0 - 0
code/CSM/CSMLoader.h → code/AssetLib/CSM/CSMLoader.h


+ 1748 - 0
code/AssetLib/Collada/ColladaExporter.cpp

@@ -0,0 +1,1748 @@
+/*
+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.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
+
+#include "ColladaExporter.h"
+
+#include <assimp/Bitmap.h>
+#include <assimp/ColladaMetaData.h>
+#include <assimp/DefaultIOSystem.h>
+#include <assimp/Exceptional.h>
+#include <assimp/MathFunctions.h>
+#include <assimp/SceneCombiner.h>
+#include <assimp/StringUtils.h>
+#include <assimp/XMLTools.h>
+#include <assimp/commonMetaData.h>
+#include <assimp/fast_atof.h>
+#include <assimp/scene.h>
+#include <assimp/Exporter.hpp>
+#include <assimp/IOSystem.hpp>
+
+#include <ctime>
+#include <memory>
+
+namespace Assimp {
+
+// ------------------------------------------------------------------------------------------------
+// Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
+void ExportSceneCollada(const char *pFile, IOSystem *pIOSystem, const aiScene *pScene, const ExportProperties * /*pProperties*/) {
+    std::string path = DefaultIOSystem::absolutePath(std::string(pFile));
+    std::string file = DefaultIOSystem::completeBaseName(std::string(pFile));
+
+    // invoke the exporter
+    ColladaExporter iDoTheExportThing(pScene, pIOSystem, path, file);
+
+    if (iDoTheExportThing.mOutput.fail()) {
+        throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile));
+    }
+
+    // we're still here - export successfully completed. Write result to the given IOSYstem
+    std::unique_ptr<IOStream> outfile(pIOSystem->Open(pFile, "wt"));
+    if (outfile == nullptr) {
+        throw DeadlyExportError("could not open output .dae file: " + std::string(pFile));
+    }
+
+    // XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy.
+    outfile->Write(iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()), 1);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Encodes a string into a valid XML ID using the xsd:ID schema qualifications.
+static const std::string XMLIDEncode(const std::string &name) {
+    const char XML_ID_CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.";
+    const unsigned int XML_ID_CHARS_COUNT = sizeof(XML_ID_CHARS) / sizeof(char);
+
+    if (name.length() == 0) {
+        return name;
+    }
+
+    std::stringstream idEncoded;
+
+    // xsd:ID must start with letter or underscore
+    if (!((name[0] >= 'A' && name[0] <= 'z') || name[0] == '_')) {
+        idEncoded << '_';
+    }
+
+    for (std::string::const_iterator it = name.begin(); it != name.end(); ++it) {
+        // xsd:ID can only contain letters, digits, underscores, hyphens and periods
+        if (strchr(XML_ID_CHARS, *it) != nullptr) {
+            idEncoded << *it;
+        } else {
+            // Select placeholder character based on invalid character to reduce ID collisions
+            idEncoded << XML_ID_CHARS[(*it) % XML_ID_CHARS_COUNT];
+        }
+    }
+
+    return idEncoded.str();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Helper functions to create unique ids
+inline bool IsUniqueId(const std::unordered_set<std::string> &idSet, const std::string &idStr) {
+    return (idSet.find(idStr) == idSet.end());
+}
+
+inline std::string MakeUniqueId(const std::unordered_set<std::string> &idSet, const std::string &idPrefix, const std::string &postfix) {
+    std::string result(idPrefix + postfix);
+    if (!IsUniqueId(idSet, result)) {
+        // Select a number to append
+        size_t idnum = 1;
+        do {
+            result = idPrefix + '_' + to_string(idnum) + postfix;
+            ++idnum;
+        } while (!IsUniqueId(idSet, result));
+    }
+    return result;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Constructor for a specific scene to export
+ColladaExporter::ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file) :
+        mIOSystem(pIOSystem),
+        mPath(path),
+        mFile(file),
+        mScene(pScene),
+        endstr("\n") {
+    // make sure that all formatting happens using the standard, C locale and not the user's current locale
+    mOutput.imbue(std::locale("C"));
+    mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION);
+
+    // start writing the file
+    WriteFile();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Destructor
+ColladaExporter::~ColladaExporter() {
+}
+
+// ------------------------------------------------------------------------------------------------
+// Starts writing the contents
+void ColladaExporter::WriteFile() {
+    // write the DTD
+    mOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>" << endstr;
+    // COLLADA element start
+    mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
+    PushTag();
+
+    WriteTextures();
+    WriteHeader();
+
+    // Add node names to the unique id database first so they are most likely to use their names as unique ids
+    CreateNodeIds(mScene->mRootNode);
+
+    WriteCamerasLibrary();
+    WriteLightsLibrary();
+    WriteMaterials();
+    WriteGeometryLibrary();
+    WriteControllerLibrary();
+
+    WriteSceneLibrary();
+
+    // customized, Writes the animation library
+    WriteAnimationsLibrary();
+
+    // instantiate the scene(s)
+    // For Assimp there will only ever be one
+    mOutput << startstr << "<scene>" << endstr;
+    PushTag();
+    mOutput << startstr << "<instance_visual_scene url=\"#" + mSceneId + "\" />" << endstr;
+    PopTag();
+    mOutput << startstr << "</scene>" << endstr;
+    PopTag();
+    mOutput << "</COLLADA>" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes the asset header
+void ColladaExporter::WriteHeader() {
+    static const ai_real epsilon = Math::getEpsilon<ai_real>();
+    static const aiQuaternion x_rot(aiMatrix3x3(
+            0, -1, 0,
+            1, 0, 0,
+            0, 0, 1));
+    static const aiQuaternion y_rot(aiMatrix3x3(
+            1, 0, 0,
+            0, 1, 0,
+            0, 0, 1));
+    static const aiQuaternion z_rot(aiMatrix3x3(
+            1, 0, 0,
+            0, 0, 1,
+            0, -1, 0));
+
+    static const unsigned int date_nb_chars = 20;
+    char date_str[date_nb_chars];
+    std::time_t date = std::time(nullptr);
+    std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date));
+
+    aiVector3D scaling;
+    aiQuaternion rotation;
+    aiVector3D position;
+    mScene->mRootNode->mTransformation.Decompose(scaling, rotation, position);
+    rotation.Normalize();
+
+    mAdd_root_node = false;
+
+    ai_real scale = 1.0;
+    if (std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) {
+        scale = (ai_real)((((double)scaling.x) + ((double)scaling.y) + ((double)scaling.z)) / 3.0);
+    } else {
+        mAdd_root_node = true;
+    }
+
+    std::string up_axis = "Y_UP";
+    if (rotation.Equal(x_rot, epsilon)) {
+        up_axis = "X_UP";
+    } else if (rotation.Equal(y_rot, epsilon)) {
+        up_axis = "Y_UP";
+    } else if (rotation.Equal(z_rot, epsilon)) {
+        up_axis = "Z_UP";
+    } else {
+        mAdd_root_node = true;
+    }
+
+    if (!position.Equal(aiVector3D(0, 0, 0))) {
+        mAdd_root_node = true;
+    }
+
+    // Assimp root nodes can have meshes, Collada Scenes cannot
+    if (mScene->mRootNode->mNumChildren == 0 || mScene->mRootNode->mMeshes != 0) {
+        mAdd_root_node = true;
+    }
+
+    if (mAdd_root_node) {
+        up_axis = "Y_UP";
+        scale = 1.0;
+    }
+
+    mOutput << startstr << "<asset>" << endstr;
+    PushTag();
+    mOutput << startstr << "<contributor>" << endstr;
+    PushTag();
+
+    // If no Scene metadata, use root node metadata
+    aiMetadata *meta = mScene->mMetaData;
+    if (nullptr == meta) {
+        meta = mScene->mRootNode->mMetaData;
+    }
+
+    aiString value;
+    if (!meta || !meta->Get("Author", value)) {
+        mOutput << startstr << "<author>"
+                << "Assimp"
+                << "</author>" << endstr;
+    } else {
+        mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
+    }
+
+    if (nullptr == meta || !meta->Get(AI_METADATA_SOURCE_GENERATOR, value)) {
+        mOutput << startstr << "<authoring_tool>"
+                << "Assimp Exporter"
+                << "</authoring_tool>" << endstr;
+    } else {
+        mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
+    }
+
+    if (meta) {
+        if (meta->Get("Comments", value)) {
+            mOutput << startstr << "<comments>" << XMLEscape(value.C_Str()) << "</comments>" << endstr;
+        }
+        if (meta->Get(AI_METADATA_SOURCE_COPYRIGHT, value)) {
+            mOutput << startstr << "<copyright>" << XMLEscape(value.C_Str()) << "</copyright>" << endstr;
+        }
+        if (meta->Get("SourceData", value)) {
+            mOutput << startstr << "<source_data>" << XMLEscape(value.C_Str()) << "</source_data>" << endstr;
+        }
+    }
+
+    PopTag();
+    mOutput << startstr << "</contributor>" << endstr;
+
+    if (nullptr == meta || !meta->Get("Created", value)) {
+        mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
+    } else {
+        mOutput << startstr << "<created>" << XMLEscape(value.C_Str()) << "</created>" << endstr;
+    }
+
+    // Modified date is always the date saved
+    mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr;
+
+    if (meta) {
+        if (meta->Get("Keywords", value)) {
+            mOutput << startstr << "<keywords>" << XMLEscape(value.C_Str()) << "</keywords>" << endstr;
+        }
+        if (meta->Get("Revision", value)) {
+            mOutput << startstr << "<revision>" << XMLEscape(value.C_Str()) << "</revision>" << endstr;
+        }
+        if (meta->Get("Subject", value)) {
+            mOutput << startstr << "<subject>" << XMLEscape(value.C_Str()) << "</subject>" << endstr;
+        }
+        if (meta->Get("Title", value)) {
+            mOutput << startstr << "<title>" << XMLEscape(value.C_Str()) << "</title>" << endstr;
+        }
+    }
+
+    mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr;
+    mOutput << startstr << "<up_axis>" << up_axis << "</up_axis>" << endstr;
+    PopTag();
+    mOutput << startstr << "</asset>" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Write the embedded textures
+void ColladaExporter::WriteTextures() {
+    static const unsigned int buffer_size = 1024;
+    char str[buffer_size];
+
+    if (mScene->HasTextures()) {
+        for (unsigned int i = 0; i < mScene->mNumTextures; i++) {
+            // It would be great to be able to create a directory in portable standard C++, but it's not the case,
+            // so we just write the textures in the current directory.
+
+            aiTexture *texture = mScene->mTextures[i];
+            if (nullptr == texture) {
+                continue;
+            }
+
+            ASSIMP_itoa10(str, buffer_size, i + 1);
+
+            std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char *)texture->achFormatHint);
+
+            std::unique_ptr<IOStream> outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb"));
+            if (outfile == nullptr) {
+                throw DeadlyExportError("could not open output texture file: " + mPath + name);
+            }
+
+            if (texture->mHeight == 0) {
+                outfile->Write((void *)texture->pcData, texture->mWidth, 1);
+            } else {
+                Bitmap::Save(texture, outfile.get());
+            }
+
+            outfile->Flush();
+
+            textures.insert(std::make_pair(i, name));
+        }
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Write the embedded textures
+void ColladaExporter::WriteCamerasLibrary() {
+    if (mScene->HasCameras()) {
+
+        mOutput << startstr << "<library_cameras>" << endstr;
+        PushTag();
+
+        for (size_t a = 0; a < mScene->mNumCameras; ++a)
+            WriteCamera(a);
+
+        PopTag();
+        mOutput << startstr << "</library_cameras>" << endstr;
+    }
+}
+
+void ColladaExporter::WriteCamera(size_t pIndex) {
+
+    const aiCamera *cam = mScene->mCameras[pIndex];
+    const std::string cameraId = GetObjectUniqueId(AiObjectType::Camera, pIndex);
+    const std::string cameraName = GetObjectName(AiObjectType::Camera, pIndex);
+
+    mOutput << startstr << "<camera id=\"" << cameraId << "\" name=\"" << cameraName << "\" >" << endstr;
+    PushTag();
+    mOutput << startstr << "<optics>" << endstr;
+    PushTag();
+    mOutput << startstr << "<technique_common>" << endstr;
+    PushTag();
+    //assimp doesn't support the import of orthographic cameras! se we write
+    //always perspective
+    mOutput << startstr << "<perspective>" << endstr;
+    PushTag();
+    mOutput << startstr << "<xfov sid=\"xfov\">" << AI_RAD_TO_DEG(cam->mHorizontalFOV)
+            << "</xfov>" << endstr;
+    mOutput << startstr << "<aspect_ratio>"
+            << cam->mAspect
+            << "</aspect_ratio>" << endstr;
+    mOutput << startstr << "<znear sid=\"znear\">"
+            << cam->mClipPlaneNear
+            << "</znear>" << endstr;
+    mOutput << startstr << "<zfar sid=\"zfar\">"
+            << cam->mClipPlaneFar
+            << "</zfar>" << endstr;
+    PopTag();
+    mOutput << startstr << "</perspective>" << endstr;
+    PopTag();
+    mOutput << startstr << "</technique_common>" << endstr;
+    PopTag();
+    mOutput << startstr << "</optics>" << endstr;
+    PopTag();
+    mOutput << startstr << "</camera>" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Write the embedded textures
+void ColladaExporter::WriteLightsLibrary() {
+    if (mScene->HasLights()) {
+
+        mOutput << startstr << "<library_lights>" << endstr;
+        PushTag();
+
+        for (size_t a = 0; a < mScene->mNumLights; ++a)
+            WriteLight(a);
+
+        PopTag();
+        mOutput << startstr << "</library_lights>" << endstr;
+    }
+}
+
+void ColladaExporter::WriteLight(size_t pIndex) {
+
+    const aiLight *light = mScene->mLights[pIndex];
+    const std::string lightId = GetObjectUniqueId(AiObjectType::Light, pIndex);
+    const std::string lightName = GetObjectName(AiObjectType::Light, pIndex);
+
+    mOutput << startstr << "<light id=\"" << lightId << "\" name=\""
+            << lightName << "\" >" << endstr;
+    PushTag();
+    mOutput << startstr << "<technique_common>" << endstr;
+    PushTag();
+    switch (light->mType) {
+    case aiLightSource_AMBIENT:
+        WriteAmbienttLight(light);
+        break;
+    case aiLightSource_DIRECTIONAL:
+        WriteDirectionalLight(light);
+        break;
+    case aiLightSource_POINT:
+        WritePointLight(light);
+        break;
+    case aiLightSource_SPOT:
+        WriteSpotLight(light);
+        break;
+    case aiLightSource_AREA:
+    case aiLightSource_UNDEFINED:
+    case _aiLightSource_Force32Bit:
+        break;
+    }
+    PopTag();
+    mOutput << startstr << "</technique_common>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</light>" << endstr;
+}
+
+void ColladaExporter::WritePointLight(const aiLight *const light) {
+    const aiColor3D &color = light->mColorDiffuse;
+    mOutput << startstr << "<point>" << endstr;
+    PushTag();
+    mOutput << startstr << "<color sid=\"color\">"
+            << color.r << " " << color.g << " " << color.b
+            << "</color>" << endstr;
+    mOutput << startstr << "<constant_attenuation>"
+            << light->mAttenuationConstant
+            << "</constant_attenuation>" << endstr;
+    mOutput << startstr << "<linear_attenuation>"
+            << light->mAttenuationLinear
+            << "</linear_attenuation>" << endstr;
+    mOutput << startstr << "<quadratic_attenuation>"
+            << light->mAttenuationQuadratic
+            << "</quadratic_attenuation>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</point>" << endstr;
+}
+
+void ColladaExporter::WriteDirectionalLight(const aiLight *const light) {
+    const aiColor3D &color = light->mColorDiffuse;
+    mOutput << startstr << "<directional>" << endstr;
+    PushTag();
+    mOutput << startstr << "<color sid=\"color\">"
+            << color.r << " " << color.g << " " << color.b
+            << "</color>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</directional>" << endstr;
+}
+
+void ColladaExporter::WriteSpotLight(const aiLight *const light) {
+
+    const aiColor3D &color = light->mColorDiffuse;
+    mOutput << startstr << "<spot>" << endstr;
+    PushTag();
+    mOutput << startstr << "<color sid=\"color\">"
+            << color.r << " " << color.g << " " << color.b
+            << "</color>" << endstr;
+    mOutput << startstr << "<constant_attenuation>"
+            << light->mAttenuationConstant
+            << "</constant_attenuation>" << endstr;
+    mOutput << startstr << "<linear_attenuation>"
+            << light->mAttenuationLinear
+            << "</linear_attenuation>" << endstr;
+    mOutput << startstr << "<quadratic_attenuation>"
+            << light->mAttenuationQuadratic
+            << "</quadratic_attenuation>" << endstr;
+    /*
+    out->mAngleOuterCone = AI_DEG_TO_RAD (std::acos(std::pow(0.1f,1.f/srcLight->mFalloffExponent))+
+                            srcLight->mFalloffAngle);
+    */
+
+    const ai_real fallOffAngle = AI_RAD_TO_DEG(light->mAngleInnerCone);
+    mOutput << startstr << "<falloff_angle sid=\"fall_off_angle\">"
+            << fallOffAngle
+            << "</falloff_angle>" << endstr;
+    double temp = light->mAngleOuterCone - light->mAngleInnerCone;
+
+    temp = std::cos(temp);
+    temp = std::log(temp) / std::log(0.1);
+    temp = 1 / temp;
+    mOutput << startstr << "<falloff_exponent sid=\"fall_off_exponent\">"
+            << temp
+            << "</falloff_exponent>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</spot>" << endstr;
+}
+
+void ColladaExporter::WriteAmbienttLight(const aiLight *const light) {
+
+    const aiColor3D &color = light->mColorAmbient;
+    mOutput << startstr << "<ambient>" << endstr;
+    PushTag();
+    mOutput << startstr << "<color sid=\"color\">"
+            << color.r << " " << color.g << " " << color.b
+            << "</color>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</ambient>" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads a single surface entry from the given material keys
+bool ColladaExporter::ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex) {
+    if (pSrcMat.GetTextureCount(pTexture) > 0) {
+        aiString texfile;
+        unsigned int uvChannel = 0;
+        pSrcMat.GetTexture(pTexture, 0, &texfile, nullptr, &uvChannel);
+
+        std::string index_str(texfile.C_Str());
+
+        if (index_str.size() != 0 && index_str[0] == '*') {
+            unsigned int index;
+
+            index_str = index_str.substr(1, std::string::npos);
+
+            try {
+                index = (unsigned int)strtoul10_64(index_str.c_str());
+            } catch (std::exception &error) {
+                throw DeadlyExportError(error.what());
+            }
+
+            std::map<unsigned int, std::string>::const_iterator name = textures.find(index);
+
+            if (name != textures.end()) {
+                poSurface.texture = name->second;
+            } else {
+                throw DeadlyExportError("could not find embedded texture at index " + index_str);
+            }
+        } else {
+            poSurface.texture = texfile.C_Str();
+        }
+
+        poSurface.channel = uvChannel;
+        poSurface.exist = true;
+    } else {
+        if (pKey)
+            poSurface.exist = pSrcMat.Get(pKey, static_cast<unsigned int>(pType), static_cast<unsigned int>(pIndex), poSurface.color) == aiReturn_SUCCESS;
+    }
+    return poSurface.exist;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reimplementation of isalnum(,C locale), because AppVeyor does not see standard version.
+static bool isalnum_C(char c) {
+    return (nullptr != strchr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", c));
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes an image entry for the given surface
+void ColladaExporter::WriteImageEntry(const Surface &pSurface, const std::string &imageId) {
+    if (!pSurface.texture.empty()) {
+        mOutput << startstr << "<image id=\"" << imageId << "\">" << endstr;
+        PushTag();
+        mOutput << startstr << "<init_from>";
+
+        // URL encode image file name first, then XML encode on top
+        std::stringstream imageUrlEncoded;
+        for (std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it) {
+            if (isalnum_C((unsigned char)*it) || *it == ':' || *it == '_' || *it == '-' || *it == '.' || *it == '/' || *it == '\\')
+                imageUrlEncoded << *it;
+            else
+                imageUrlEncoded << '%' << std::hex << size_t((unsigned char)*it) << std::dec;
+        }
+        mOutput << XMLEscape(imageUrlEncoded.str());
+        mOutput << "</init_from>" << endstr;
+        PopTag();
+        mOutput << startstr << "</image>" << endstr;
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes a color-or-texture entry into an effect definition
+void ColladaExporter::WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId) {
+    if (pSurface.exist) {
+        mOutput << startstr << "<" << pTypeName << ">" << endstr;
+        PushTag();
+        if (pSurface.texture.empty()) {
+            mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
+        } else {
+            mOutput << startstr << "<texture texture=\"" << imageId << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
+        }
+        PopTag();
+        mOutput << startstr << "</" << pTypeName << ">" << endstr;
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes the two parameters necessary for referencing a texture in an effect entry
+void ColladaExporter::WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId) {
+    // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture
+    if (!pSurface.texture.empty()) {
+        mOutput << startstr << "<newparam sid=\"" << materialId << "-" << pTypeName << "-surface\">" << endstr;
+        PushTag();
+        mOutput << startstr << "<surface type=\"2D\">" << endstr;
+        PushTag();
+        mOutput << startstr << "<init_from>" << materialId << "-" << pTypeName << "-image</init_from>" << endstr;
+        PopTag();
+        mOutput << startstr << "</surface>" << endstr;
+        PopTag();
+        mOutput << startstr << "</newparam>" << endstr;
+
+        mOutput << startstr << "<newparam sid=\"" << materialId << "-" << pTypeName << "-sampler\">" << endstr;
+        PushTag();
+        mOutput << startstr << "<sampler2D>" << endstr;
+        PushTag();
+        mOutput << startstr << "<source>" << materialId << "-" << pTypeName << "-surface</source>" << endstr;
+        PopTag();
+        mOutput << startstr << "</sampler2D>" << endstr;
+        PopTag();
+        mOutput << startstr << "</newparam>" << endstr;
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes a scalar property
+void ColladaExporter::WriteFloatEntry(const Property &pProperty, const std::string &pTypeName) {
+    if (pProperty.exist) {
+        mOutput << startstr << "<" << pTypeName << ">" << endstr;
+        PushTag();
+        mOutput << startstr << "<float sid=\"" << pTypeName << "\">" << pProperty.value << "</float>" << endstr;
+        PopTag();
+        mOutput << startstr << "</" << pTypeName << ">" << endstr;
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes the material setup
+void ColladaExporter::WriteMaterials() {
+    std::vector<Material> materials;
+    materials.resize(mScene->mNumMaterials);
+
+    /// collect all materials from the scene
+    size_t numTextures = 0;
+    for (size_t a = 0; a < mScene->mNumMaterials; ++a) {
+        Material &material = materials[a];
+        material.id = GetObjectUniqueId(AiObjectType::Material, a);
+        material.name = GetObjectName(AiObjectType::Material, a);
+
+        const aiMaterial &mat = *(mScene->mMaterials[a]);
+        aiShadingMode shading = aiShadingMode_Flat;
+        material.shading_model = "phong";
+        if (mat.Get(AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) {
+            if (shading == aiShadingMode_Phong) {
+                material.shading_model = "phong";
+            } else if (shading == aiShadingMode_Blinn) {
+                material.shading_model = "blinn";
+            } else if (shading == aiShadingMode_NoShading) {
+                material.shading_model = "constant";
+            } else if (shading == aiShadingMode_Gouraud) {
+                material.shading_model = "lambert";
+            }
+        }
+
+        if (ReadMaterialSurface(material.ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT))
+            ++numTextures;
+        if (ReadMaterialSurface(material.diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE))
+            ++numTextures;
+        if (ReadMaterialSurface(material.specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR))
+            ++numTextures;
+        if (ReadMaterialSurface(material.emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE))
+            ++numTextures;
+        if (ReadMaterialSurface(material.reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE))
+            ++numTextures;
+        if (ReadMaterialSurface(material.transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT))
+            ++numTextures;
+        if (ReadMaterialSurface(material.normal, mat, aiTextureType_NORMALS, nullptr, 0, 0))
+            ++numTextures;
+
+        material.shininess.exist = mat.Get(AI_MATKEY_SHININESS, material.shininess.value) == aiReturn_SUCCESS;
+        material.transparency.exist = mat.Get(AI_MATKEY_OPACITY, material.transparency.value) == aiReturn_SUCCESS;
+        material.index_refraction.exist = mat.Get(AI_MATKEY_REFRACTI, material.index_refraction.value) == aiReturn_SUCCESS;
+    }
+
+    // output textures if present
+    if (numTextures > 0) {
+        mOutput << startstr << "<library_images>" << endstr;
+        PushTag();
+        for (const Material &mat : materials) {
+            WriteImageEntry(mat.ambient, mat.id + "-ambient-image");
+            WriteImageEntry(mat.diffuse, mat.id + "-diffuse-image");
+            WriteImageEntry(mat.specular, mat.id + "-specular-image");
+            WriteImageEntry(mat.emissive, mat.id + "-emission-image");
+            WriteImageEntry(mat.reflective, mat.id + "-reflective-image");
+            WriteImageEntry(mat.transparent, mat.id + "-transparent-image");
+            WriteImageEntry(mat.normal, mat.id + "-normal-image");
+        }
+        PopTag();
+        mOutput << startstr << "</library_images>" << endstr;
+    }
+
+    // output effects - those are the actual carriers of information
+    if (!materials.empty()) {
+        mOutput << startstr << "<library_effects>" << endstr;
+        PushTag();
+        for (const Material &mat : materials) {
+            // this is so ridiculous it must be right
+            mOutput << startstr << "<effect id=\"" << mat.id << "-fx\" name=\"" << mat.name << "\">" << endstr;
+            PushTag();
+            mOutput << startstr << "<profile_COMMON>" << endstr;
+            PushTag();
+
+            // write sampler- and surface params for the texture entries
+            WriteTextureParamEntry(mat.emissive, "emission", mat.id);
+            WriteTextureParamEntry(mat.ambient, "ambient", mat.id);
+            WriteTextureParamEntry(mat.diffuse, "diffuse", mat.id);
+            WriteTextureParamEntry(mat.specular, "specular", mat.id);
+            WriteTextureParamEntry(mat.reflective, "reflective", mat.id);
+            WriteTextureParamEntry(mat.transparent, "transparent", mat.id);
+            WriteTextureParamEntry(mat.normal, "normal", mat.id);
+
+            mOutput << startstr << "<technique sid=\"standard\">" << endstr;
+            PushTag();
+            mOutput << startstr << "<" << mat.shading_model << ">" << endstr;
+            PushTag();
+
+            WriteTextureColorEntry(mat.emissive, "emission", mat.id + "-emission-sampler");
+            WriteTextureColorEntry(mat.ambient, "ambient", mat.id + "-ambient-sampler");
+            WriteTextureColorEntry(mat.diffuse, "diffuse", mat.id + "-diffuse-sampler");
+            WriteTextureColorEntry(mat.specular, "specular", mat.id + "-specular-sampler");
+            WriteFloatEntry(mat.shininess, "shininess");
+            WriteTextureColorEntry(mat.reflective, "reflective", mat.id + "-reflective-sampler");
+            WriteTextureColorEntry(mat.transparent, "transparent", mat.id + "-transparent-sampler");
+            WriteFloatEntry(mat.transparency, "transparency");
+            WriteFloatEntry(mat.index_refraction, "index_of_refraction");
+
+            if (!mat.normal.texture.empty()) {
+                WriteTextureColorEntry(mat.normal, "bump", mat.id + "-normal-sampler");
+            }
+
+            PopTag();
+            mOutput << startstr << "</" << mat.shading_model << ">" << endstr;
+            PopTag();
+            mOutput << startstr << "</technique>" << endstr;
+            PopTag();
+            mOutput << startstr << "</profile_COMMON>" << endstr;
+            PopTag();
+            mOutput << startstr << "</effect>" << endstr;
+        }
+        PopTag();
+        mOutput << startstr << "</library_effects>" << endstr;
+
+        // write materials - they're just effect references
+        mOutput << startstr << "<library_materials>" << endstr;
+        PushTag();
+        for (std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it) {
+            const Material &mat = *it;
+            mOutput << startstr << "<material id=\"" << mat.id << "\" name=\"" << mat.name << "\">" << endstr;
+            PushTag();
+            mOutput << startstr << "<instance_effect url=\"#" << mat.id << "-fx\"/>" << endstr;
+            PopTag();
+            mOutput << startstr << "</material>" << endstr;
+        }
+        PopTag();
+        mOutput << startstr << "</library_materials>" << endstr;
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes the controller library
+void ColladaExporter::WriteControllerLibrary() {
+    mOutput << startstr << "<library_controllers>" << endstr;
+    PushTag();
+
+    for (size_t a = 0; a < mScene->mNumMeshes; ++a) {
+        WriteController(a);
+    }
+
+    PopTag();
+    mOutput << startstr << "</library_controllers>" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes a skin controller of the given mesh
+void ColladaExporter::WriteController(size_t pIndex) {
+    const aiMesh *mesh = mScene->mMeshes[pIndex];
+    // Is there a skin controller?
+    if (mesh->mNumBones == 0 || mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
+        return;
+
+    const std::string idstr = GetObjectUniqueId(AiObjectType::Mesh, pIndex);
+    const std::string namestr = GetObjectName(AiObjectType::Mesh, pIndex);
+
+    mOutput << startstr << "<controller id=\"" << idstr << "-skin\" ";
+    mOutput << "name=\"skinCluster" << pIndex << "\">" << endstr;
+    PushTag();
+
+    mOutput << startstr << "<skin source=\"#" << idstr << "\">" << endstr;
+    PushTag();
+
+    // bind pose matrix
+    mOutput << startstr << "<bind_shape_matrix>" << endstr;
+    PushTag();
+
+    // I think it is identity in general cases.
+    aiMatrix4x4 mat;
+    mOutput << startstr << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << endstr;
+    mOutput << startstr << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << endstr;
+    mOutput << startstr << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << endstr;
+    mOutput << startstr << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4 << endstr;
+
+    PopTag();
+    mOutput << startstr << "</bind_shape_matrix>" << endstr;
+
+    mOutput << startstr << "<source id=\"" << idstr << "-skin-joints\" name=\"" << namestr << "-skin-joints\">" << endstr;
+    PushTag();
+
+    mOutput << startstr << "<Name_array id=\"" << idstr << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\">";
+
+    for (size_t i = 0; i < mesh->mNumBones; ++i)
+        mOutput << GetBoneUniqueId(mesh->mBones[i]) << ' ';
+
+    mOutput << "</Name_array>" << endstr;
+
+    mOutput << startstr << "<technique_common>" << endstr;
+    PushTag();
+
+    mOutput << startstr << "<accessor source=\"#" << idstr << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\" stride=\"" << 1 << "\">" << endstr;
+    PushTag();
+
+    mOutput << startstr << "<param name=\"JOINT\" type=\"Name\"></param>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</accessor>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</technique_common>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</source>" << endstr;
+
+    std::vector<ai_real> bind_poses;
+    bind_poses.reserve(mesh->mNumBones * 16);
+    for (unsigned int i = 0; i < mesh->mNumBones; ++i)
+        for (unsigned int j = 0; j < 4; ++j)
+            bind_poses.insert(bind_poses.end(), mesh->mBones[i]->mOffsetMatrix[j], mesh->mBones[i]->mOffsetMatrix[j] + 4);
+
+    WriteFloatArray(idstr + "-skin-bind_poses", FloatType_Mat4x4, (const ai_real *)bind_poses.data(), bind_poses.size() / 16);
+
+    bind_poses.clear();
+
+    std::vector<ai_real> skin_weights;
+    skin_weights.reserve(mesh->mNumVertices * mesh->mNumBones);
+    for (size_t i = 0; i < mesh->mNumBones; ++i)
+        for (size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j)
+            skin_weights.push_back(mesh->mBones[i]->mWeights[j].mWeight);
+
+    WriteFloatArray(idstr + "-skin-weights", FloatType_Weight, (const ai_real *)skin_weights.data(), skin_weights.size());
+
+    skin_weights.clear();
+
+    mOutput << startstr << "<joints>" << endstr;
+    PushTag();
+
+    mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstr << "-skin-joints\"></input>" << endstr;
+    mOutput << startstr << "<input semantic=\"INV_BIND_MATRIX\" source=\"#" << idstr << "-skin-bind_poses\"></input>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</joints>" << endstr;
+
+    mOutput << startstr << "<vertex_weights count=\"" << mesh->mNumVertices << "\">" << endstr;
+    PushTag();
+
+    mOutput << startstr << "<input semantic=\"JOINT\" source=\"#" << idstr << "-skin-joints\" offset=\"0\"></input>" << endstr;
+    mOutput << startstr << "<input semantic=\"WEIGHT\" source=\"#" << idstr << "-skin-weights\" offset=\"1\"></input>" << endstr;
+
+    mOutput << startstr << "<vcount>";
+
+    std::vector<ai_uint> num_influences(mesh->mNumVertices, (ai_uint)0);
+    for (size_t i = 0; i < mesh->mNumBones; ++i)
+        for (size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j)
+            ++num_influences[mesh->mBones[i]->mWeights[j].mVertexId];
+
+    for (size_t i = 0; i < mesh->mNumVertices; ++i)
+        mOutput << num_influences[i] << " ";
+
+    mOutput << "</vcount>" << endstr;
+
+    mOutput << startstr << "<v>";
+
+    ai_uint joint_weight_indices_length = 0;
+    std::vector<ai_uint> accum_influences;
+    accum_influences.reserve(num_influences.size());
+    for (size_t i = 0; i < num_influences.size(); ++i) {
+        accum_influences.push_back(joint_weight_indices_length);
+        joint_weight_indices_length += num_influences[i];
+    }
+
+    ai_uint weight_index = 0;
+    std::vector<ai_int> joint_weight_indices(2 * joint_weight_indices_length, (ai_int)-1);
+    for (unsigned int i = 0; i < mesh->mNumBones; ++i)
+        for (unsigned j = 0; j < mesh->mBones[i]->mNumWeights; ++j) {
+            unsigned int vId = mesh->mBones[i]->mWeights[j].mVertexId;
+            for (ai_uint k = 0; k < num_influences[vId]; ++k) {
+                if (joint_weight_indices[2 * (accum_influences[vId] + k)] == -1) {
+                    joint_weight_indices[2 * (accum_influences[vId] + k)] = i;
+                    joint_weight_indices[2 * (accum_influences[vId] + k) + 1] = weight_index;
+                    break;
+                }
+            }
+            ++weight_index;
+        }
+
+    for (size_t i = 0; i < joint_weight_indices.size(); ++i)
+        mOutput << joint_weight_indices[i] << " ";
+
+    num_influences.clear();
+    accum_influences.clear();
+    joint_weight_indices.clear();
+
+    mOutput << "</v>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</vertex_weights>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</skin>" << endstr;
+
+    PopTag();
+    mOutput << startstr << "</controller>" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes the geometry library
+void ColladaExporter::WriteGeometryLibrary() {
+    mOutput << startstr << "<library_geometries>" << endstr;
+    PushTag();
+
+    for (size_t a = 0; a < mScene->mNumMeshes; ++a)
+        WriteGeometry(a);
+
+    PopTag();
+    mOutput << startstr << "</library_geometries>" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes the given mesh
+void ColladaExporter::WriteGeometry(size_t pIndex) {
+    const aiMesh *mesh = mScene->mMeshes[pIndex];
+    const std::string geometryId = GetObjectUniqueId(AiObjectType::Mesh, pIndex);
+    const std::string geometryName = GetObjectName(AiObjectType::Mesh, pIndex);
+
+    if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
+        return;
+
+    // opening tag
+    mOutput << startstr << "<geometry id=\"" << geometryId << "\" name=\"" << geometryName << "\" >" << endstr;
+    PushTag();
+
+    mOutput << startstr << "<mesh>" << endstr;
+    PushTag();
+
+    // Positions
+    WriteFloatArray(geometryId + "-positions", FloatType_Vector, (ai_real *)mesh->mVertices, mesh->mNumVertices);
+    // Normals, if any
+    if (mesh->HasNormals())
+        WriteFloatArray(geometryId + "-normals", FloatType_Vector, (ai_real *)mesh->mNormals, mesh->mNumVertices);
+
+    // texture coords
+    for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
+        if (mesh->HasTextureCoords(static_cast<unsigned int>(a))) {
+            WriteFloatArray(geometryId + "-tex" + to_string(a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2,
+                    (ai_real *)mesh->mTextureCoords[a], mesh->mNumVertices);
+        }
+    }
+
+    // vertex colors
+    for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
+        if (mesh->HasVertexColors(static_cast<unsigned int>(a)))
+            WriteFloatArray(geometryId + "-color" + to_string(a), FloatType_Color, (ai_real *)mesh->mColors[a], mesh->mNumVertices);
+    }
+
+    // assemble vertex structure
+    // Only write input for POSITION since we will write other as shared inputs in polygon definition
+    mOutput << startstr << "<vertices id=\"" << geometryId << "-vertices"
+            << "\">" << endstr;
+    PushTag();
+    mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << geometryId << "-positions\" />" << endstr;
+    PopTag();
+    mOutput << startstr << "</vertices>" << endstr;
+
+    // count the number of lines, triangles and polygon meshes
+    int countLines = 0;
+    int countPoly = 0;
+    for (size_t a = 0; a < mesh->mNumFaces; ++a) {
+        if (mesh->mFaces[a].mNumIndices == 2)
+            countLines++;
+        else if (mesh->mFaces[a].mNumIndices >= 3)
+            countPoly++;
+    }
+
+    // lines
+    if (countLines) {
+        mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
+        PushTag();
+        mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << geometryId << "-vertices\" />" << endstr;
+        if (mesh->HasNormals())
+            mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << geometryId << "-normals\" />" << endstr;
+        for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
+            if (mesh->HasTextureCoords(static_cast<unsigned int>(a)))
+                mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << geometryId << "-tex" << a << "\" "
+                        << "set=\"" << a << "\""
+                        << " />" << endstr;
+        }
+        for (size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
+            if (mesh->HasVertexColors(static_cast<unsigned int>(a)))
+                mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << geometryId << "-color" << a << "\" "
+                        << "set=\"" << a << "\""
+                        << " />" << endstr;
+        }
+
+        mOutput << startstr << "<p>";
+        for (size_t a = 0; a < mesh->mNumFaces; ++a) {
+            const aiFace &face = mesh->mFaces[a];
+            if (face.mNumIndices != 2) continue;
+            for (size_t b = 0; b < face.mNumIndices; ++b)
+                mOutput << face.mIndices[b] << " ";
+        }
+        mOutput << "</p>" << endstr;
+        PopTag();
+        mOutput << startstr << "</lines>" << endstr;
+    }
+
+    // triangle - don't use it, because compatibility problems
+
+    // polygons
+    if (countPoly) {
+        mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
+        PushTag();
+        mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << geometryId << "-vertices\" />" << endstr;
+        if (mesh->HasNormals())
+            mOutput << startstr << "<input offset=\"0\" semantic=\"NORMAL\" source=\"#" << geometryId << "-normals\" />" << endstr;
+        for (size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
+            if (mesh->HasTextureCoords(static_cast<unsigned int>(a)))
+                mOutput << startstr << "<input offset=\"0\" semantic=\"TEXCOORD\" source=\"#" << geometryId << "-tex" << a << "\" "
+                        << "set=\"" << a << "\""
+                        << " />" << endstr;
+        }
+        for (size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) {
+            if (mesh->HasVertexColors(static_cast<unsigned int>(a)))
+                mOutput << startstr << "<input offset=\"0\" semantic=\"COLOR\" source=\"#" << geometryId << "-color" << a << "\" "
+                        << "set=\"" << a << "\""
+                        << " />" << endstr;
+        }
+
+        mOutput << startstr << "<vcount>";
+        for (size_t a = 0; a < mesh->mNumFaces; ++a) {
+            if (mesh->mFaces[a].mNumIndices < 3) continue;
+            mOutput << mesh->mFaces[a].mNumIndices << " ";
+        }
+        mOutput << "</vcount>" << endstr;
+
+        mOutput << startstr << "<p>";
+        for (size_t a = 0; a < mesh->mNumFaces; ++a) {
+            const aiFace &face = mesh->mFaces[a];
+            if (face.mNumIndices < 3) continue;
+            for (size_t b = 0; b < face.mNumIndices; ++b)
+                mOutput << face.mIndices[b] << " ";
+        }
+        mOutput << "</p>" << endstr;
+        PopTag();
+        mOutput << startstr << "</polylist>" << endstr;
+    }
+
+    // closing tags
+    PopTag();
+    mOutput << startstr << "</mesh>" << endstr;
+    PopTag();
+    mOutput << startstr << "</geometry>" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes a float array of the given type
+void ColladaExporter::WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount) {
+    size_t floatsPerElement = 0;
+    switch (pType) {
+    case FloatType_Vector: floatsPerElement = 3; break;
+    case FloatType_TexCoord2: floatsPerElement = 2; break;
+    case FloatType_TexCoord3: floatsPerElement = 3; break;
+    case FloatType_Color: floatsPerElement = 3; break;
+    case FloatType_Mat4x4: floatsPerElement = 16; break;
+    case FloatType_Weight: floatsPerElement = 1; break;
+    case FloatType_Time: floatsPerElement = 1; break;
+    default:
+        return;
+    }
+
+    std::string arrayId = XMLIDEncode(pIdString) + "-array";
+
+    mOutput << startstr << "<source id=\"" << XMLIDEncode(pIdString) << "\" name=\"" << XMLEscape(pIdString) << "\">" << endstr;
+    PushTag();
+
+    // source array
+    mOutput << startstr << "<float_array id=\"" << arrayId << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
+    PushTag();
+
+    if (pType == FloatType_TexCoord2) {
+        for (size_t a = 0; a < pElementCount; ++a) {
+            mOutput << pData[a * 3 + 0] << " ";
+            mOutput << pData[a * 3 + 1] << " ";
+        }
+    } else if (pType == FloatType_Color) {
+        for (size_t a = 0; a < pElementCount; ++a) {
+            mOutput << pData[a * 4 + 0] << " ";
+            mOutput << pData[a * 4 + 1] << " ";
+            mOutput << pData[a * 4 + 2] << " ";
+        }
+    } else {
+        for (size_t a = 0; a < pElementCount * floatsPerElement; ++a)
+            mOutput << pData[a] << " ";
+    }
+    mOutput << "</float_array>" << endstr;
+    PopTag();
+
+    // the usual Collada fun. Let's bloat it even more!
+    mOutput << startstr << "<technique_common>" << endstr;
+    PushTag();
+    mOutput << startstr << "<accessor count=\"" << pElementCount << "\" offset=\"0\" source=\"#" << arrayId << "\" stride=\"" << floatsPerElement << "\">" << endstr;
+    PushTag();
+
+    switch (pType) {
+    case FloatType_Vector:
+        mOutput << startstr << "<param name=\"X\" type=\"float\" />" << endstr;
+        mOutput << startstr << "<param name=\"Y\" type=\"float\" />" << endstr;
+        mOutput << startstr << "<param name=\"Z\" type=\"float\" />" << endstr;
+        break;
+
+    case FloatType_TexCoord2:
+        mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
+        mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
+        break;
+
+    case FloatType_TexCoord3:
+        mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr;
+        mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr;
+        mOutput << startstr << "<param name=\"P\" type=\"float\" />" << endstr;
+        break;
+
+    case FloatType_Color:
+        mOutput << startstr << "<param name=\"R\" type=\"float\" />" << endstr;
+        mOutput << startstr << "<param name=\"G\" type=\"float\" />" << endstr;
+        mOutput << startstr << "<param name=\"B\" type=\"float\" />" << endstr;
+        break;
+
+    case FloatType_Mat4x4:
+        mOutput << startstr << "<param name=\"TRANSFORM\" type=\"float4x4\" />" << endstr;
+        break;
+
+    case FloatType_Weight:
+        mOutput << startstr << "<param name=\"WEIGHT\" type=\"float\" />" << endstr;
+        break;
+
+    // customized, add animation related
+    case FloatType_Time:
+        mOutput << startstr << "<param name=\"TIME\" type=\"float\" />" << endstr;
+        break;
+    }
+
+    PopTag();
+    mOutput << startstr << "</accessor>" << endstr;
+    PopTag();
+    mOutput << startstr << "</technique_common>" << endstr;
+    PopTag();
+    mOutput << startstr << "</source>" << endstr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Writes the scene library
+void ColladaExporter::WriteSceneLibrary() {
+    // Determine if we are using the aiScene root or our own
+    std::string sceneName("Scene");
+    if (mAdd_root_node) {
+        mSceneId = MakeUniqueId(mUniqueIds, sceneName, std::string());
+        mUniqueIds.insert(mSceneId);
+    } else {
+        mSceneId = GetNodeUniqueId(mScene->mRootNode);
+        sceneName = GetNodeName(mScene->mRootNode);
+    }
+
+    mOutput << startstr << "<library_visual_scenes>" << endstr;
+    PushTag();
+    mOutput << startstr << "<visual_scene id=\"" + mSceneId + "\" name=\"" + sceneName + "\">" << endstr;
+    PushTag();
+
+    if (mAdd_root_node) {
+        // Export the root node
+        WriteNode(mScene->mRootNode);
+    } else {
+        // Have already exported the root node
+        for (size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a)
+            WriteNode(mScene->mRootNode->mChildren[a]);
+    }
+
+    PopTag();
+    mOutput << startstr << "</visual_scene>" << endstr;
+    PopTag();
+    mOutput << startstr << "</library_visual_scenes>" << endstr;
+}
+// ------------------------------------------------------------------------------------------------
+void ColladaExporter::WriteAnimationLibrary(size_t pIndex) {
+    const aiAnimation *anim = mScene->mAnimations[pIndex];
+
+    if (anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels == 0)
+        return;
+
+    const std::string animationNameEscaped = GetObjectName(AiObjectType::Animation, pIndex);
+    const std::string idstrEscaped = GetObjectUniqueId(AiObjectType::Animation, pIndex);
+
+    mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animationNameEscaped + "\">" << endstr;
+    PushTag();
+
+    std::string cur_node_idstr;
+    for (size_t a = 0; a < anim->mNumChannels; ++a) {
+        const aiNodeAnim *nodeAnim = anim->mChannels[a];
+
+        // sanity check
+        if (nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys || nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys) {
+            continue;
+        }
+
+        {
+            cur_node_idstr.clear();
+            cur_node_idstr += nodeAnim->mNodeName.data;
+            cur_node_idstr += std::string("_matrix-input");
+
+            std::vector<ai_real> frames;
+            for (size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
+                frames.push_back(static_cast<ai_real>(nodeAnim->mPositionKeys[i].mTime));
+            }
+
+            WriteFloatArray(cur_node_idstr, FloatType_Time, (const ai_real *)frames.data(), frames.size());
+            frames.clear();
+        }
+
+        {
+            cur_node_idstr.clear();
+
+            cur_node_idstr += nodeAnim->mNodeName.data;
+            cur_node_idstr += std::string("_matrix-output");
+
+            std::vector<ai_real> keyframes;
+            keyframes.reserve(nodeAnim->mNumPositionKeys * 16);
+            for (size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
+                aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue;
+                aiMatrix4x4 ScalingM; // identity
+                ScalingM[0][0] = Scaling.x;
+                ScalingM[1][1] = Scaling.y;
+                ScalingM[2][2] = Scaling.z;
+
+                aiQuaternion RotationQ = nodeAnim->mRotationKeys[i].mValue;
+                aiMatrix4x4 s = aiMatrix4x4(RotationQ.GetMatrix());
+                aiMatrix4x4 RotationM(s.a1, s.a2, s.a3, 0, s.b1, s.b2, s.b3, 0, s.c1, s.c2, s.c3, 0, 0, 0, 0, 1);
+
+                aiVector3D Translation = nodeAnim->mPositionKeys[i].mValue;
+                aiMatrix4x4 TranslationM; // identity
+                TranslationM[0][3] = Translation.x;
+                TranslationM[1][3] = Translation.y;
+                TranslationM[2][3] = Translation.z;
+
+                // Combine the above transformations
+                aiMatrix4x4 mat = TranslationM * RotationM * ScalingM;
+
+                for (unsigned int j = 0; j < 4; ++j) {
+                    keyframes.insert(keyframes.end(), mat[j], mat[j] + 4);
+                }
+            }
+
+            WriteFloatArray(cur_node_idstr, FloatType_Mat4x4, (const ai_real *)keyframes.data(), keyframes.size() / 16);
+        }
+
+        {
+            std::vector<std::string> names;
+            for (size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
+                if (nodeAnim->mPreState == aiAnimBehaviour_DEFAULT || nodeAnim->mPreState == aiAnimBehaviour_LINEAR || nodeAnim->mPreState == aiAnimBehaviour_REPEAT) {
+                    names.push_back("LINEAR");
+                } else if (nodeAnim->mPostState == aiAnimBehaviour_CONSTANT) {
+                    names.push_back("STEP");
+                }
+            }
+
+            const std::string cur_node_idstr2 = nodeAnim->mNodeName.data + std::string("_matrix-interpolation");
+            std::string arrayId = XMLIDEncode(cur_node_idstr2) + "-array";
+
+            mOutput << startstr << "<source id=\"" << XMLIDEncode(cur_node_idstr2) << "\">" << endstr;
+            PushTag();
+
+            // source array
+            mOutput << startstr << "<Name_array id=\"" << arrayId << "\" count=\"" << names.size() << "\"> ";
+            for (size_t aa = 0; aa < names.size(); ++aa) {
+                mOutput << names[aa] << " ";
+            }
+            mOutput << "</Name_array>" << endstr;
+
+            mOutput << startstr << "<technique_common>" << endstr;
+            PushTag();
+
+            mOutput << startstr << "<accessor source=\"#" << arrayId << "\" count=\"" << names.size() << "\" stride=\"" << 1 << "\">" << endstr;
+            PushTag();
+
+            mOutput << startstr << "<param name=\"INTERPOLATION\" type=\"name\"></param>" << endstr;
+
+            PopTag();
+            mOutput << startstr << "</accessor>" << endstr;
+
+            PopTag();
+            mOutput << startstr << "</technique_common>" << endstr;
+
+            PopTag();
+            mOutput << startstr << "</source>" << endstr;
+        }
+    }
+
+    for (size_t a = 0; a < anim->mNumChannels; ++a) {
+        const aiNodeAnim *nodeAnim = anim->mChannels[a];
+
+        {
+            // samplers
+            const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-sampler");
+            mOutput << startstr << "<sampler id=\"" << XMLIDEncode(node_idstr) << "\">" << endstr;
+            PushTag();
+
+            mOutput << startstr << "<input semantic=\"INPUT\" source=\"#" << XMLIDEncode(nodeAnim->mNodeName.data + std::string("_matrix-input")) << "\"/>" << endstr;
+            mOutput << startstr << "<input semantic=\"OUTPUT\" source=\"#" << XMLIDEncode(nodeAnim->mNodeName.data + std::string("_matrix-output")) << "\"/>" << endstr;
+            mOutput << startstr << "<input semantic=\"INTERPOLATION\" source=\"#" << XMLIDEncode(nodeAnim->mNodeName.data + std::string("_matrix-interpolation")) << "\"/>" << endstr;
+
+            PopTag();
+            mOutput << startstr << "</sampler>" << endstr;
+        }
+    }
+
+    for (size_t a = 0; a < anim->mNumChannels; ++a) {
+        const aiNodeAnim *nodeAnim = anim->mChannels[a];
+
+        {
+            // channels
+            mOutput << startstr << "<channel source=\"#" << XMLIDEncode(nodeAnim->mNodeName.data + std::string("_matrix-sampler")) << "\" target=\"" << XMLIDEncode(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr;
+        }
+    }
+
+    PopTag();
+    mOutput << startstr << "</animation>" << endstr;
+}
+// ------------------------------------------------------------------------------------------------
+void ColladaExporter::WriteAnimationsLibrary() {
+    if (mScene->mNumAnimations > 0) {
+        mOutput << startstr << "<library_animations>" << endstr;
+        PushTag();
+
+        // start recursive write at the root node
+        for (size_t a = 0; a < mScene->mNumAnimations; ++a)
+            WriteAnimationLibrary(a);
+
+        PopTag();
+        mOutput << startstr << "</library_animations>" << endstr;
+    }
+}
+// ------------------------------------------------------------------------------------------------
+// Helper to find a bone by name in the scene
+aiBone *findBone(const aiScene *scene, const aiString &name) {
+    for (size_t m = 0; m < scene->mNumMeshes; m++) {
+        aiMesh *mesh = scene->mMeshes[m];
+        for (size_t b = 0; b < mesh->mNumBones; b++) {
+            aiBone *bone = mesh->mBones[b];
+            if (name == bone->mName) {
+                return bone;
+            }
+        }
+    }
+    return nullptr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Helper to find the node associated with a bone in the scene
+const aiNode *findBoneNode(const aiNode *aNode, const aiBone *bone) {
+    if (aNode && bone && aNode->mName == bone->mName) {
+        return aNode;
+    }
+
+    if (aNode && bone) {
+        for (unsigned int i = 0; i < aNode->mNumChildren; ++i) {
+            aiNode *aChild = aNode->mChildren[i];
+            const aiNode *foundFromChild = nullptr;
+            if (aChild) {
+                foundFromChild = findBoneNode(aChild, bone);
+                if (foundFromChild) {
+                    return foundFromChild;
+                }
+            }
+        }
+    }
+
+    return nullptr;
+}
+
+const aiNode *findSkeletonRootNode(const aiScene *scene, const aiMesh *mesh) {
+    std::set<const aiNode *> topParentBoneNodes;
+    if (mesh && mesh->mNumBones > 0) {
+        for (unsigned int i = 0; i < mesh->mNumBones; ++i) {
+            aiBone *bone = mesh->mBones[i];
+
+            const aiNode *node = findBoneNode(scene->mRootNode, bone);
+            if (node) {
+                while (node->mParent && findBone(scene, node->mParent->mName) != nullptr) {
+                    node = node->mParent;
+                }
+                topParentBoneNodes.insert(node);
+            }
+        }
+    }
+
+    if (!topParentBoneNodes.empty()) {
+        const aiNode *parentBoneNode = *topParentBoneNodes.begin();
+        if (topParentBoneNodes.size() == 1) {
+            return parentBoneNode;
+        } else {
+            for (auto it : topParentBoneNodes) {
+                if (it->mParent) return it->mParent;
+            }
+            return parentBoneNode;
+        }
+    }
+
+    return nullptr;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Recursively writes the given node
+void ColladaExporter::WriteNode(const aiNode *pNode) {
+    // If the node is associated with a bone, it is a joint node (JOINT)
+    // otherwise it is a normal node (NODE)
+    // Assimp-specific: nodes with no name cannot be associated with bones
+    const char *node_type;
+    bool is_joint, is_skeleton_root = false;
+    if (pNode->mName.length == 0 || nullptr == findBone(mScene, pNode->mName)) {
+        node_type = "NODE";
+        is_joint = false;
+    } else {
+        node_type = "JOINT";
+        is_joint = true;
+        if (!pNode->mParent || nullptr == findBone(mScene, pNode->mParent->mName)) {
+            is_skeleton_root = true;
+        }
+    }
+
+    const std::string node_id = GetNodeUniqueId(pNode);
+    const std::string node_name = GetNodeName(pNode);
+    mOutput << startstr << "<node ";
+    if (is_skeleton_root) {
+        mFoundSkeletonRootNodeID = node_id; // For now, only support one skeleton in a scene.
+    }
+    mOutput << "id=\"" << node_id << "\" " << (is_joint ? "sid=\"" + node_id + "\" " : "");
+    mOutput << "name=\"" << node_name
+            << "\" type=\"" << node_type
+            << "\">" << endstr;
+    PushTag();
+
+    // write transformation - we can directly put the matrix there
+    // TODO: (thom) decompose into scale - rot - quad to allow addressing it by animations afterwards
+    aiMatrix4x4 mat = pNode->mTransformation;
+
+    // If this node is a Camera node, the camera coordinate system needs to be multiplied in.
+    // When importing from Collada, the mLookAt is set to 0, 0, -1, and the node transform is unchanged.
+    // When importing from a different format, mLookAt is set to 0, 0, 1. Therefore, the local camera
+    // coordinate system must be changed to matche the Collada specification.
+    for (size_t i = 0; i < mScene->mNumCameras; i++) {
+        if (mScene->mCameras[i]->mName == pNode->mName) {
+            aiMatrix4x4 sourceView;
+            mScene->mCameras[i]->GetCameraMatrix(sourceView);
+
+            aiMatrix4x4 colladaView;
+            colladaView.a1 = colladaView.c3 = -1; // move into -z space.
+            mat *= (sourceView * colladaView);
+            break;
+        }
+    }
+
+    // customized, sid should be 'matrix' to match with loader code.
+    //mOutput << startstr << "<matrix sid=\"transform\">";
+    mOutput << startstr << "<matrix sid=\"matrix\">";
+
+    mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
+    mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " ";
+    mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " ";
+    mOutput << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4;
+    mOutput << "</matrix>" << endstr;
+
+    if (pNode->mNumMeshes == 0) {
+        //check if it is a camera node
+        for (size_t i = 0; i < mScene->mNumCameras; i++) {
+            if (mScene->mCameras[i]->mName == pNode->mName) {
+                mOutput << startstr << "<instance_camera url=\"#" << GetObjectUniqueId(AiObjectType::Camera, i) << "\"/>" << endstr;
+                break;
+            }
+        }
+        //check if it is a light node
+        for (size_t i = 0; i < mScene->mNumLights; i++) {
+            if (mScene->mLights[i]->mName == pNode->mName) {
+                mOutput << startstr << "<instance_light url=\"#" << GetObjectUniqueId(AiObjectType::Light, i) << "\"/>" << endstr;
+                break;
+            }
+        }
+
+    } else
+        // instance every geometry
+        for (size_t a = 0; a < pNode->mNumMeshes; ++a) {
+            const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[a]];
+            // do not instantiate mesh if empty. I wonder how this could happen
+            if (mesh->mNumFaces == 0 || mesh->mNumVertices == 0)
+                continue;
+
+            const std::string meshId = GetObjectUniqueId(AiObjectType::Mesh, pNode->mMeshes[a]);
+
+            if (mesh->mNumBones == 0) {
+                mOutput << startstr << "<instance_geometry url=\"#" << meshId << "\">" << endstr;
+                PushTag();
+            } else {
+                mOutput << startstr
+                        << "<instance_controller url=\"#" << meshId << "-skin\">"
+                        << endstr;
+                PushTag();
+
+                // note! this mFoundSkeletonRootNodeID some how affects animation, it makes the mesh attaches to armature skeleton root node.
+                // use the first bone to find skeleton root
+                const aiNode *skeletonRootBoneNode = findSkeletonRootNode(mScene, mesh);
+                if (skeletonRootBoneNode) {
+                    mFoundSkeletonRootNodeID = GetNodeUniqueId(skeletonRootBoneNode);
+                }
+                mOutput << startstr << "<skeleton>#" << mFoundSkeletonRootNodeID << "</skeleton>" << endstr;
+            }
+            mOutput << startstr << "<bind_material>" << endstr;
+            PushTag();
+            mOutput << startstr << "<technique_common>" << endstr;
+            PushTag();
+            mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << GetObjectUniqueId(AiObjectType::Material, mesh->mMaterialIndex) << "\">" << endstr;
+            PushTag();
+            for (size_t aa = 0; aa < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++aa) {
+                if (mesh->HasTextureCoords(static_cast<unsigned int>(aa)))
+                    // semantic       as in <texture texcoord=...>
+                    // input_semantic as in <input semantic=...>
+                    // input_set      as in <input set=...>
+                    mOutput << startstr << "<bind_vertex_input semantic=\"CHANNEL" << aa << "\" input_semantic=\"TEXCOORD\" input_set=\"" << aa << "\"/>" << endstr;
+            }
+            PopTag();
+            mOutput << startstr << "</instance_material>" << endstr;
+            PopTag();
+            mOutput << startstr << "</technique_common>" << endstr;
+            PopTag();
+            mOutput << startstr << "</bind_material>" << endstr;
+
+            PopTag();
+            if (mesh->mNumBones == 0)
+                mOutput << startstr << "</instance_geometry>" << endstr;
+            else
+                mOutput << startstr << "</instance_controller>" << endstr;
+        }
+
+    // recurse into subnodes
+    for (size_t a = 0; a < pNode->mNumChildren; ++a)
+        WriteNode(pNode->mChildren[a]);
+
+    PopTag();
+    mOutput << startstr << "</node>" << endstr;
+}
+
+void ColladaExporter::CreateNodeIds(const aiNode *node) {
+    GetNodeUniqueId(node);
+    for (size_t a = 0; a < node->mNumChildren; ++a)
+        CreateNodeIds(node->mChildren[a]);
+}
+
+std::string ColladaExporter::GetNodeUniqueId(const aiNode *node) {
+    // Use the pointer as the key. This is safe because the scene is immutable.
+    auto idIt = mNodeIdMap.find(node);
+    if (idIt != mNodeIdMap.cend())
+        return idIt->second;
+
+    // Prefer the requested Collada Id if extant
+    std::string idStr;
+    aiString origId;
+    if (node->mMetaData && node->mMetaData->Get(AI_METADATA_COLLADA_ID, origId)) {
+        idStr = origId.C_Str();
+    } else {
+        idStr = node->mName.C_Str();
+    }
+    // Make sure the requested id is valid
+    if (idStr.empty())
+        idStr = "node";
+    else
+        idStr = XMLIDEncode(idStr);
+
+    // Ensure it's unique
+    idStr = MakeUniqueId(mUniqueIds, idStr, std::string());
+    mUniqueIds.insert(idStr);
+    mNodeIdMap.insert(std::make_pair(node, idStr));
+    return idStr;
+}
+
+std::string ColladaExporter::GetNodeName(const aiNode *node) {
+
+    return XMLEscape(node->mName.C_Str());
+}
+
+std::string ColladaExporter::GetBoneUniqueId(const aiBone *bone) {
+    // Find the Node that is this Bone
+    const aiNode *boneNode = findBoneNode(mScene->mRootNode, bone);
+    if (boneNode == nullptr)
+        return std::string();
+
+    return GetNodeUniqueId(boneNode);
+}
+
+std::string ColladaExporter::GetObjectUniqueId(AiObjectType type, size_t pIndex) {
+    auto idIt = GetObjectIdMap(type).find(pIndex);
+    if (idIt != GetObjectIdMap(type).cend())
+        return idIt->second;
+
+    // Not seen this object before, create and add
+    NameIdPair result = AddObjectIndexToMaps(type, pIndex);
+    return result.second;
+}
+
+std::string ColladaExporter::GetObjectName(AiObjectType type, size_t pIndex) {
+    auto objectName = GetObjectNameMap(type).find(pIndex);
+    if (objectName != GetObjectNameMap(type).cend())
+        return objectName->second;
+
+    // Not seen this object before, create and add
+    NameIdPair result = AddObjectIndexToMaps(type, pIndex);
+    return result.first;
+}
+
+// Determine unique id and add the name and id to the maps
+// @param type object type
+// @param index object index
+// @param name in/out. Caller to set the original name if known.
+// @param idStr in/out. Caller to set the preferred id if known.
+ColladaExporter::NameIdPair ColladaExporter::AddObjectIndexToMaps(AiObjectType type, size_t index) {
+
+    std::string name;
+    std::string idStr;
+    std::string idPostfix;
+
+    // Get the name and id postfix
+    switch (type) {
+    case AiObjectType::Mesh: name = mScene->mMeshes[index]->mName.C_Str(); break;
+    case AiObjectType::Material: name = mScene->mMaterials[index]->GetName().C_Str(); break;
+    case AiObjectType::Animation: name = mScene->mAnimations[index]->mName.C_Str(); break;
+    case AiObjectType::Light:
+        name = mScene->mLights[index]->mName.C_Str();
+        idPostfix = "-light";
+        break;
+    case AiObjectType::Camera:
+        name = mScene->mCameras[index]->mName.C_Str();
+        idPostfix = "-camera";
+        break;
+    case AiObjectType::Count: throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type");
+    }
+
+    if (name.empty()) {
+        // Default ids if empty name
+        switch (type) {
+        case AiObjectType::Mesh: idStr = std::string("mesh_"); break;
+        case AiObjectType::Material: idStr = std::string("material_"); break; // This one should never happen
+        case AiObjectType::Animation: idStr = std::string("animation_"); break;
+        case AiObjectType::Light: idStr = std::string("light_"); break;
+        case AiObjectType::Camera: idStr = std::string("camera_"); break;
+        case AiObjectType::Count: throw std::logic_error("ColladaExporter::AiObjectType::Count is not an object type");
+        }
+        idStr.append(to_string(index));
+    } else {
+        idStr = XMLIDEncode(name);
+    }
+
+    if (!name.empty())
+        name = XMLEscape(name);
+
+    idStr = MakeUniqueId(mUniqueIds, idStr, idPostfix);
+
+    // Add to maps
+    mUniqueIds.insert(idStr);
+    GetObjectIdMap(type).insert(std::make_pair(index, idStr));
+    GetObjectNameMap(type).insert(std::make_pair(index, name));
+
+    return std::make_pair(name, idStr);
+}
+
+} // end of namespace Assimp
+
+#endif
+#endif

+ 257 - 0
code/AssetLib/Collada/ColladaExporter.h

@@ -0,0 +1,257 @@
+/*
+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 ColladaExporter.h
+ * Declares the exporter class to write a scene to a Collada file
+ */
+#ifndef AI_COLLADAEXPORTER_H_INC
+#define AI_COLLADAEXPORTER_H_INC
+
+#include <assimp/ai_assert.h>
+#include <assimp/material.h>
+
+#include <array>
+#include <map>
+#include <sstream>
+#include <unordered_set>
+#include <vector>
+
+struct aiScene;
+struct aiNode;
+struct aiLight;
+struct aiBone;
+
+namespace Assimp {
+
+class IOSystem;
+
+/// Helper class to export a given scene to a Collada file. Just for my personal
+/// comfort when implementing it.
+class ColladaExporter {
+public:
+    /// Constructor for a specific scene to export
+    ColladaExporter(const aiScene *pScene, IOSystem *pIOSystem, const std::string &path, const std::string &file);
+
+    /// Destructor
+    virtual ~ColladaExporter();
+
+protected:
+    /// Starts writing the contents
+    void WriteFile();
+
+    /// Writes the asset header
+    void WriteHeader();
+
+    /// Writes the embedded textures
+    void WriteTextures();
+
+    /// Writes the material setup
+    void WriteMaterials();
+
+    /// Writes the cameras library
+    void WriteCamerasLibrary();
+
+    // Write a camera entry
+    void WriteCamera(size_t pIndex);
+
+    /// Writes the cameras library
+    void WriteLightsLibrary();
+
+    // Write a camera entry
+    void WriteLight(size_t pIndex);
+    void WritePointLight(const aiLight *const light);
+    void WriteDirectionalLight(const aiLight *const light);
+    void WriteSpotLight(const aiLight *const light);
+    void WriteAmbienttLight(const aiLight *const light);
+
+    /// Writes the controller library
+    void WriteControllerLibrary();
+
+    /// Writes a skin controller of the given mesh
+    void WriteController(size_t pIndex);
+
+    /// Writes the geometry library
+    void WriteGeometryLibrary();
+
+    /// Writes the given mesh
+    void WriteGeometry(size_t pIndex);
+
+    //enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight };
+    // customized to add animation related type
+    enum FloatDataType { FloatType_Vector,
+        FloatType_TexCoord2,
+        FloatType_TexCoord3,
+        FloatType_Color,
+        FloatType_Mat4x4,
+        FloatType_Weight,
+        FloatType_Time };
+
+    /// Writes a float array of the given type
+    void WriteFloatArray(const std::string &pIdString, FloatDataType pType, const ai_real *pData, size_t pElementCount);
+
+    /// Writes the scene library
+    void WriteSceneLibrary();
+
+    // customized, Writes the animation library
+    void WriteAnimationsLibrary();
+    void WriteAnimationLibrary(size_t pIndex);
+    std::string mFoundSkeletonRootNodeID = "skeleton_root"; // will be replaced by found node id in the WriteNode call.
+
+    /// Recursively writes the given node
+    void WriteNode(const aiNode *pNode);
+
+    /// Enters a new xml element, which increases the indentation
+    void PushTag() { startstr.append("  "); }
+    /// Leaves an element, decreasing the indentation
+    void PopTag() {
+        ai_assert(startstr.length() > 1);
+        startstr.erase(startstr.length() - 2);
+    }
+
+    void CreateNodeIds(const aiNode *node);
+
+    /// Get or Create a unique Node ID string for the given Node
+    std::string GetNodeUniqueId(const aiNode *node);
+    std::string GetNodeName(const aiNode *node);
+
+    std::string GetBoneUniqueId(const aiBone *bone);
+
+    enum class AiObjectType {
+        Mesh,
+        Material,
+        Animation,
+        Light,
+        Camera,
+        Count,
+    };
+    /// Get or Create a unique ID string for the given scene object index
+    std::string GetObjectUniqueId(AiObjectType type, size_t pIndex);
+    /// Get or Create a name string for the given scene object index
+    std::string GetObjectName(AiObjectType type, size_t pIndex);
+
+    typedef std::map<size_t, std::string> IndexIdMap;
+    typedef std::pair<std::string, std::string> NameIdPair;
+    NameIdPair AddObjectIndexToMaps(AiObjectType type, size_t pIndex);
+
+    // Helpers
+    inline IndexIdMap &GetObjectIdMap(AiObjectType type) { return mObjectIdMap[static_cast<size_t>(type)]; }
+    inline IndexIdMap &GetObjectNameMap(AiObjectType type) { return mObjectNameMap[static_cast<size_t>(type)]; }
+
+private:
+    std::unordered_set<std::string> mUniqueIds; // Cache of used unique ids
+    std::map<const void *, std::string> mNodeIdMap; // Cache of encoded node and bone ids
+    std::array<IndexIdMap, static_cast<size_t>(AiObjectType::Count)> mObjectIdMap; // Cache of encoded unique IDs
+    std::array<IndexIdMap, static_cast<size_t>(AiObjectType::Count)> mObjectNameMap; // Cache of encoded names
+
+public:
+    /// Stringstream to write all output into
+    std::stringstream mOutput;
+
+    /// The IOSystem for output
+    IOSystem *mIOSystem;
+
+    /// Path of the directory where the scene will be exported
+    const std::string mPath;
+
+    /// Name of the file (without extension) where the scene will be exported
+    const std::string mFile;
+
+    /// The scene to be written
+    const aiScene *const mScene;
+    std::string mSceneId;
+    bool mAdd_root_node = false;
+
+    /// current line start string, contains the current indentation for simple stream insertion
+    std::string startstr;
+    /// current line end string for simple stream insertion
+    const std::string endstr;
+
+    // pair of color and texture - texture precedences color
+    struct Surface {
+        bool exist;
+        aiColor4D color;
+        std::string texture;
+        size_t channel;
+        Surface() {
+            exist = false;
+            channel = 0;
+        }
+    };
+
+    struct Property {
+        bool exist;
+        ai_real value;
+        Property() :
+                exist(false),
+                value(0.0) {}
+    };
+
+    // summarize a material in an convenient way.
+    struct Material {
+        std::string id;
+        std::string name;
+        std::string shading_model;
+        Surface ambient, diffuse, specular, emissive, reflective, transparent, normal;
+        Property shininess, transparency, index_refraction;
+
+        Material() {}
+    };
+
+    std::map<unsigned int, std::string> textures;
+
+public:
+    /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
+    /// Reads a single surface entry from the given material keys
+    bool ReadMaterialSurface(Surface &poSurface, const aiMaterial &pSrcMat, aiTextureType pTexture, const char *pKey, size_t pType, size_t pIndex);
+    /// Writes an image entry for the given surface
+    void WriteImageEntry(const Surface &pSurface, const std::string &imageId);
+    /// Writes the two parameters necessary for referencing a texture in an effect entry
+    void WriteTextureParamEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &materialId);
+    /// Writes a color-or-texture entry into an effect definition
+    void WriteTextureColorEntry(const Surface &pSurface, const std::string &pTypeName, const std::string &imageId);
+    /// Writes a scalar property
+    void WriteFloatEntry(const Property &pProperty, const std::string &pTypeName);
+};
+
+} // namespace Assimp
+
+#endif // !! AI_COLLADAEXPORTER_H_INC

+ 8 - 15
code/Collada/ColladaHelper.cpp → code/AssetLib/Collada/ColladaHelper.cpp

@@ -43,8 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "ColladaHelper.h"
 
-#include <assimp/commonMetaData.h>
 #include <assimp/ParsingUtils.h>
+#include <assimp/commonMetaData.h>
 
 namespace Assimp {
 namespace Collada {
@@ -63,42 +63,35 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
 
 const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
     MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
-    for (auto &val : result)
-    {
+    for (auto &val : result) {
         ToCamelCase(val.first);
     }
     return result;
 };
 
-const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase()
-{
+const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase() {
     static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
     return result;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
-void ToCamelCase(std::string &text)
-{
+void ToCamelCase(std::string &text) {
     if (text.empty())
         return;
     // Capitalise first character
     auto it = text.begin();
     (*it) = ToUpper(*it);
     ++it;
-    for (/*started above*/ ; it != text.end(); /*iterated below*/)
-    {
-        if ((*it) == '_')
-        {
+    for (/*started above*/; it != text.end(); /*iterated below*/) {
+        if ((*it) == '_') {
             it = text.erase(it);
             if (it != text.end())
                 (*it) = ToUpper(*it);
-        }
-        else
-        {
+        } else {
             // Make lower case
             (*it) = ToLower(*it);
-            ++it;               
+            ++it;
         }
     }
 }

+ 185 - 224
code/Collada/ColladaHelper.h → code/AssetLib/Collada/ColladaHelper.h

@@ -45,31 +45,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_COLLADAHELPER_H_INC
 #define AI_COLLADAHELPER_H_INC
 
-#include <map>
-#include <vector>
-#include <set>
-#include <stdint.h>
 #include <assimp/light.h>
-#include <assimp/mesh.h>
 #include <assimp/material.h>
+#include <assimp/mesh.h>
+#include <stdint.h>
+#include <map>
+#include <set>
+#include <vector>
 
 struct aiMaterial;
 
-namespace Assimp    {
-namespace Collada       {
+namespace Assimp {
+namespace Collada {
 
 /** Collada file versions which evolved during the years ... */
-enum FormatVersion
-{
+enum FormatVersion {
     FV_1_5_n,
     FV_1_4_n,
     FV_1_3_n
 };
 
-
 /** Transformation types that can be applied to a node */
-enum TransformType
-{
+enum TransformType {
     TF_LOOKAT,
     TF_ROTATE,
     TF_TRANSLATE,
@@ -79,10 +76,9 @@ enum TransformType
 };
 
 /** Different types of input data to a vertex or face */
-enum InputType
-{
+enum InputType {
     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.
     IT_Position,
     IT_Normal,
     IT_Texcoord,
@@ -92,15 +88,13 @@ enum InputType
 };
 
 /** Supported controller types */
-enum ControllerType
-{
+enum ControllerType {
     Skin,
     Morph
 };
 
 /** Supported morph methods */
-enum MorphMethod
-{
+enum MorphMethod {
     Normalized,
     Relative
 };
@@ -118,24 +112,21 @@ const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
 void ToCamelCase(std::string &text);
 
 /** Contains all data for one of the different transformation types */
-struct Transform
-{
-    std::string mID;  ///< SID of the transform step, by which anim channels address their target node
+struct Transform {
+    std::string mID; ///< SID of the transform step, by which anim channels address their target node
     TransformType mType;
     ai_real f[16]; ///< Interpretation of data depends on the type of the transformation
 };
 
 /** A collada camera. */
-struct Camera
-{
-    Camera()
-        :   mOrtho  (false)
-        ,   mHorFov (10e10f)
-        ,   mVerFov (10e10f)
-        ,   mAspect (10e10f)
-        ,   mZNear  (0.1f)
-        ,   mZFar   (1000.f)
-    {}
+struct Camera {
+    Camera() :
+            mOrtho(false),
+            mHorFov(10e10f),
+            mVerFov(10e10f),
+            mAspect(10e10f),
+            mZNear(0.1f),
+            mZFar(1000.f) {}
 
     // Name of camera
     std::string mName;
@@ -159,19 +150,17 @@ struct Camera
 #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f
 
 /** A collada light source. */
-struct Light
-{
-    Light()
-        :   mType            (aiLightSource_UNDEFINED)
-        ,   mAttConstant     (1.f)
-        ,   mAttLinear       (0.f)
-        ,   mAttQuadratic    (0.f)
-        ,   mFalloffAngle    (180.f)
-        ,   mFalloffExponent (0.f)
-        ,   mPenumbraAngle   (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
-        ,   mOuterAngle      (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET)
-        ,   mIntensity       (1.f)
-    {}
+struct Light {
+    Light() :
+            mType(aiLightSource_UNDEFINED),
+            mAttConstant(1.f),
+            mAttLinear(0.f),
+            mAttQuadratic(0.f),
+            mFalloffAngle(180.f),
+            mFalloffExponent(0.f),
+            mPenumbraAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
+            mOuterAngle(ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET),
+            mIntensity(1.f) {}
 
     //! Type of the light source aiLightSourceType + ambient
     unsigned int mType;
@@ -180,7 +169,7 @@ struct Light
     aiColor3D mColor;
 
     //! Light attenuation
-    ai_real mAttConstant,mAttLinear,mAttQuadratic;
+    ai_real mAttConstant, mAttLinear, mAttQuadratic;
 
     //! Spot light falloff
     ai_real mFalloffAngle;
@@ -198,12 +187,10 @@ struct Light
 };
 
 /** Short vertex index description */
-struct InputSemanticMapEntry
-{
-    InputSemanticMapEntry()
-        :   mSet(0)
-        ,   mType(IT_Invalid)
-    {}
+struct InputSemanticMapEntry {
+    InputSemanticMapEntry() :
+            mSet(0),
+            mType(IT_Invalid) {}
 
     //! Index of set, optional
     unsigned int mSet;
@@ -213,8 +200,7 @@ struct InputSemanticMapEntry
 };
 
 /** Table to map from effect to vertex input semantics */
-struct SemanticMappingTable
-{
+struct SemanticMappingTable {
     //! Name of material
     std::string mMatName;
 
@@ -222,7 +208,7 @@ struct SemanticMappingTable
     std::map<std::string, InputSemanticMapEntry> mMap;
 
     //! For std::find
-    bool operator == (const std::string& s) const {
+    bool operator==(const std::string &s) const {
         return s == mMatName;
     }
 };
@@ -230,8 +216,7 @@ struct SemanticMappingTable
 /** 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
     std::string mMeshOrController;
 
@@ -240,34 +225,30 @@ struct MeshInstance
 };
 
 /** A reference to a camera inside a node*/
-struct CameraInstance
-{
-     ///< ID of the camera
+struct CameraInstance {
+    ///< ID of the camera
     std::string mCamera;
 };
 
 /** A reference to a light inside a node*/
-struct LightInstance
-{
-     ///< ID of the camera
+struct LightInstance {
+    ///< ID of the camera
     std::string mLight;
 };
 
 /** A reference to a node inside a node*/
-struct NodeInstance
-{
-     ///< ID of the node
+struct NodeInstance {
+    ///< ID of the node
     std::string mNode;
 };
 
 /** A node in a scene hierarchy */
-struct Node
-{
+struct Node {
     std::string mName;
     std::string mID;
     std::string mSID;
-    Node* mParent;
-    std::vector<Node*> mChildren;
+    Node *mParent;
+    std::vector<Node *> mChildren;
 
     /** Operations in order to calculate the resulting transformation to parent. */
     std::vector<Transform> mTransforms;
@@ -288,80 +269,83 @@ struct Node
     std::string mPrimaryCamera;
 
     //! Constructor. Begin with a zero parent
-    Node()
-    : mParent( nullptr ){
+    Node() :
+            mParent(nullptr) {
         // empty
     }
 
     //! Destructor: delete all children subsequently
     ~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;
     }
 };
 
 /** Data source array: either floats or strings */
-struct Data
-{
+struct Data {
     bool mIsStringArray;
     std::vector<ai_real> mValues;
     std::vector<std::string> mStrings;
 };
 
 /** Accessor to a data array */
-struct Accessor
-{
-    size_t mCount;   // in number of objects
-    size_t mSize;    // size of an object, in elements (floats or strings, mostly 1)
-    size_t mOffset;  // in number of values
-    size_t mStride;  // Stride in number of values
+struct Accessor {
+    size_t mCount; // in number of objects
+    size_t mSize; // size of an object, in elements (floats or strings, mostly 1)
+    size_t mOffset; // 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.
     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.
-                          // 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
-    mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
-
-    Accessor()
-    {
-        mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL;
+            // 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
+    mutable const Data *mData; // Pointer to the source array, if resolved. nullptr else
+
+    Accessor() {
+        mCount = 0;
+        mSize = 0;
+        mOffset = 0;
+        mStride = 0;
+        mData = nullptr;
         mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0;
     }
 };
 
 /** A single face in a mesh */
-struct Face
-{
+struct Face {
     std::vector<size_t> mIndices;
 };
 
 /** An input channel for mesh data, referring to a single accessor */
-struct InputChannel
-{
-    InputType mType;      // Type of the data
-    size_t mIndex;        // Optional index, if multiple sets of the same data type are given
-    size_t mOffset;       // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
+struct InputChannel {
+    InputType mType; // Type of the data
+    size_t mIndex; // Optional index, if multiple sets of the same data type are given
+    size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better.
     std::string mAccessor; // ID of the accessor where to read the actual values from.
-    mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else
+    mutable const Accessor *mResolved; // Pointer to the accessor, if resolved. nullptr else
 
-    InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; }
+    InputChannel() {
+        mType = IT_Invalid;
+        mIndex = 0;
+        mOffset = 0;
+        mResolved = nullptr;
+    }
 };
 
 /** Subset of a mesh with a certain material */
-struct SubMesh
-{
+struct SubMesh {
     std::string mMaterial; ///< subgroup identifier
     size_t mNumFaces; ///< number of faces in this submesh
 };
 
 /** Contains data for a single mesh */
-struct Mesh
-{
-    Mesh()
-    {
-        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
+struct Mesh {
+    Mesh(const std::string &id) :
+            mId(id) {
+        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i)
             mNumUVComponents[i] = 2;
     }
 
+    const std::string mId;
     std::string mName;
 
     // just to check if there's some sophisticated addressing involved...
@@ -377,7 +361,7 @@ struct Mesh
     std::vector<aiVector3D> mTangents;
     std::vector<aiVector3D> mBitangents;
     std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
-    std::vector<aiColor4D>  mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
+    std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS];
 
     unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 
@@ -394,8 +378,7 @@ struct Mesh
 };
 
 /** Which type of primitives the ReadPrimitives() function is going to read */
-enum PrimitiveType
-{
+enum PrimitiveType {
     Prim_Invalid,
     Prim_Lines,
     Prim_LineStrip,
@@ -407,8 +390,7 @@ enum PrimitiveType
 };
 
 /** A skeleton controller to deform a mesh with the use of joints */
-struct Controller
-{
+struct Controller {
     // controller type
     ControllerType mType;
 
@@ -436,36 +418,32 @@ struct Controller
     std::vector<size_t> mWeightCounts;
 
     // JointIndex-WeightIndex pairs for all vertices
-    std::vector< std::pair<size_t, size_t> > mWeights;
+    std::vector<std::pair<size_t, size_t>> mWeights;
 
     std::string mMorphTarget;
     std::string mMorphWeight;
 };
 
 /** A collada material. Pretty much the only member is a reference to an effect. */
-struct Material
-{
+struct Material {
     std::string mName;
     std::string mEffect;
 };
 
 /** Type of the effect param */
-enum ParamType
-{
+enum ParamType {
     Param_Sampler,
     Param_Surface
 };
 
 /** 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;
     std::string mReference; // to which other thing the param is referring to.
 };
 
 /** Shading type supported by the standard effect spec of Collada */
-enum ShadeType
-{
+enum ShadeType {
     Shade_Invalid,
     Shade_Constant,
     Shade_Lambert,
@@ -474,18 +452,16 @@ enum ShadeType
 };
 
 /** Represents a texture sampler in collada */
-struct Sampler
-{
-    Sampler()
-        :   mWrapU      (true)
-        ,   mWrapV      (true)
-        ,   mMirrorU    ()
-        ,   mMirrorV    ()
-        ,   mOp         (aiTextureOp_Multiply)
-        ,   mUVId       (UINT_MAX)
-        ,   mWeighting  (1.f)
-        ,   mMixWithPrevious (1.f)
-    {}
+struct Sampler {
+    Sampler() :
+            mWrapU(true),
+            mWrapV(true),
+            mMirrorU(),
+            mMirrorV(),
+            mOp(aiTextureOp_Multiply),
+            mUVId(UINT_MAX),
+            mWeighting(1.f),
+            mMixWithPrevious(1.f) {}
 
     /** Name of image reference
      */
@@ -537,18 +513,17 @@ struct Sampler
 
 /** 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
     ShadeType mShadeType;
 
     // Colors
     aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular,
-        mTransparent, mReflective;
+            mTransparent, mReflective;
 
     // Textures
     Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular,
-        mTexTransparent, mTexBump, mTexReflective;
+            mTexTransparent, mTexBump, mTexReflective;
 
     // Scalar factory
     ai_real mShininess, mRefractIndex, mReflectivity;
@@ -566,30 +541,28 @@ struct Effect
     // Double-sided?
     bool mDoubleSided, mWireframe, mFaceted;
 
-    Effect()
-        : mShadeType    (Shade_Phong)
-        , mEmissive     ( 0, 0, 0, 1)
-        , mAmbient      ( 0.1f, 0.1f, 0.1f, 1)
-        , mDiffuse      ( 0.6f, 0.6f, 0.6f, 1)
-        , mSpecular     ( 0.4f, 0.4f, 0.4f, 1)
-        , mTransparent  ( 0, 0, 0, 1)
-        , mShininess    (10.0f)
-        , mRefractIndex (1.f)
-        , mReflectivity (0.f)
-        , mTransparency (1.f)
-        , mHasTransparency (false)
-        , mRGBTransparency(false)
-        , mInvertTransparency(false)
-        , mDoubleSided  (false)
-        , mWireframe    (false)
-        , mFaceted      (false)
-    {
+    Effect() :
+            mShadeType(Shade_Phong),
+            mEmissive(0, 0, 0, 1),
+            mAmbient(0.1f, 0.1f, 0.1f, 1),
+            mDiffuse(0.6f, 0.6f, 0.6f, 1),
+            mSpecular(0.4f, 0.4f, 0.4f, 1),
+            mTransparent(0, 0, 0, 1),
+            mShininess(10.0f),
+            mRefractIndex(1.f),
+            mReflectivity(0.f),
+            mTransparency(1.f),
+            mHasTransparency(false),
+            mRGBTransparency(false),
+            mInvertTransparency(false),
+            mDoubleSided(false),
+            mWireframe(false),
+            mFaceted(false) {
     }
 };
 
 /** An image, meaning texture */
-struct Image
-{
+struct Image {
     std::string mFileName;
 
     /** Embedded image data */
@@ -600,8 +573,7 @@ struct Image
 };
 
 /** 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
      */
@@ -620,8 +592,7 @@ struct AnimationChannel
 };
 
 /** An animation. Container for 0-x animation channels or 0-x animations */
-struct Animation
-{
+struct Animation {
     /** Anim name */
     std::string mName;
 
@@ -629,96 +600,86 @@ struct Animation
     std::vector<AnimationChannel> mChannels;
 
     /** the sub-animations, if any */
-    std::vector<Animation*> mSubAnims;
+    std::vector<Animation *> mSubAnims;
 
     /** Destructor */
-    ~Animation()
-    {
-        for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
+    ~Animation() {
+        for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
             delete *it;
     }
 
-	/** Collect all channels in the animation hierarchy into a single channel list. */
-	void CollectChannelsRecursively(std::vector<AnimationChannel> &channels)
-	{
-		channels.insert(channels.end(), mChannels.begin(), mChannels.end());
+    /** Collect all channels in the animation hierarchy into a single channel list. */
+    void CollectChannelsRecursively(std::vector<AnimationChannel> &channels) {
+        channels.insert(channels.end(), mChannels.begin(), mChannels.end());
 
-		for (std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
-		{
-			Animation *pAnim = (*it);
+        for (std::vector<Animation *>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) {
+            Animation *pAnim = (*it);
 
-			pAnim->CollectChannelsRecursively(channels);
-		}
-	}
+            pAnim->CollectChannelsRecursively(channels);
+        }
+    }
 
-	/** Combine all single-channel animations' channel into the same (parent) animation channel list. */
-	void CombineSingleChannelAnimations()
-	{
-		CombineSingleChannelAnimationsRecursively(this);
-	}
+    /** Combine all single-channel animations' channel into the same (parent) animation channel list. */
+    void CombineSingleChannelAnimations() {
+        CombineSingleChannelAnimationsRecursively(this);
+    }
 
-	void CombineSingleChannelAnimationsRecursively(Animation *pParent)
-	{
-		std::set<std::string> childrenTargets;
-		bool childrenAnimationsHaveDifferentChannels = true;
+    void CombineSingleChannelAnimationsRecursively(Animation *pParent) {
+        std::set<std::string> childrenTargets;
+        bool childrenAnimationsHaveDifferentChannels = true;
 
-		for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
-		{
-			Animation *anim = *it;
-			CombineSingleChannelAnimationsRecursively(anim);
+        for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
+            Animation *anim = *it;
+            CombineSingleChannelAnimationsRecursively(anim);
 
-			if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
-				childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
-				childrenTargets.insert(anim->mChannels[0].mTarget);
-			} else {
-				childrenAnimationsHaveDifferentChannels = false;
-			}
+            if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
+                    childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
+                childrenTargets.insert(anim->mChannels[0].mTarget);
+            } else {
+                childrenAnimationsHaveDifferentChannels = false;
+            }
 
-			++it;
-		}
+            ++it;
+        }
 
-		// We only want to combine animations if they have different channels
-		if (childrenAnimationsHaveDifferentChannels)
-		{
-			for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
-			{
-				Animation *anim = *it;
+        // We only want to combine animations if they have different channels
+        if (childrenAnimationsHaveDifferentChannels) {
+            for (std::vector<Animation *>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();) {
+                Animation *anim = *it;
 
-				pParent->mChannels.push_back(anim->mChannels[0]);
+                pParent->mChannels.push_back(anim->mChannels[0]);
 
-				it = pParent->mSubAnims.erase(it);
+                it = pParent->mSubAnims.erase(it);
 
-				delete anim;
-				continue;
-			}
-		}
-	}
+                delete anim;
+                continue;
+            }
+        }
+    }
 };
 
 /** Description of a collada animation channel which has been determined to affect the current node */
-struct ChannelEntry
-{
-    const Collada::AnimationChannel* mChannel; ///> the source channel
+struct ChannelEntry {
+    const Collada::AnimationChannel *mChannel; ///> the source channel
     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 mSubElement; // starting index inside the transform data
 
     // resolved data references
-    const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values
-    const Collada::Data* mTimeData; ///> Source data array for the time values
-    const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values
-    const Collada::Data* mValueData; ///> Source datat array for the key value values
-
-    ChannelEntry()
-      : mChannel()
-      , mTransformIndex()
-      , mSubElement()
-      , mTimeAccessor()
-      , mTimeData()
-      , mValueAccessor()
-      , mValueData()
-   {}
+    const Collada::Accessor *mTimeAccessor; ///> Collada accessor to the time values
+    const Collada::Data *mTimeData; ///> Source data array for the time values
+    const Collada::Accessor *mValueAccessor; ///> Collada accessor to the key value values
+    const Collada::Data *mValueData; ///> Source datat array for the key value values
+
+    ChannelEntry() :
+            mChannel(),
+            mTransformIndex(),
+            mSubElement(),
+            mTimeAccessor(),
+            mTimeData(),
+            mValueAccessor(),
+            mValueData() {}
 };
 
 } // end of namespace Collada

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 234 - 253
code/AssetLib/Collada/ColladaLoader.cpp


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


A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 179 - 330
code/AssetLib/Collada/ColladaParser.cpp


+ 392 - 0
code/AssetLib/Collada/ColladaParser.h

@@ -0,0 +1,392 @@
+/*
+ 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 ColladaParser.h
+ *  @brief Defines the parser helper class for the collada loader
+ */
+
+#ifndef AI_COLLADAPARSER_H_INC
+#define AI_COLLADAPARSER_H_INC
+
+#include "ColladaHelper.h"
+#include <assimp/TinyFormatter.h>
+#include <assimp/ai_assert.h>
+#include <assimp/irrXMLWrapper.h>
+
+namespace Assimp {
+class ZipArchiveIOSystem;
+
+// ------------------------------------------------------------------------------------------
+/** Parser helper class for the Collada loader.
+     *
+     *  Does all the XML reading and builds internal data structures from it,
+     *  but leaves the resolving of all the references to the loader.
+     */
+class ColladaParser {
+    friend class ColladaLoader;
+
+    /** Converts a path read from a collada file to the usual representation */
+    static void UriDecodePath(aiString &ss);
+
+protected:
+    /** Map for generic metadata as aiString */
+    typedef std::map<std::string, aiString> StringMetaData;
+
+    /** Constructor from XML file */
+    ColladaParser(IOSystem *pIOHandler, const std::string &pFile);
+
+    /** Destructor */
+    ~ColladaParser();
+
+    /** Attempts to read the ZAE manifest and returns the DAE to open */
+    static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
+
+    /** Reads the contents of the file */
+    void ReadContents();
+
+    /** Reads the structure of the file */
+    void ReadStructure();
+
+    /** Reads asset information such as coordinate system information and legal blah */
+    void ReadAssetInfo();
+
+    /** Reads contributor information such as author and legal blah */
+    void ReadContributorInfo();
+
+    /** Reads generic metadata into provided map and renames keys for Assimp */
+    void ReadMetaDataItem(StringMetaData &metadata);
+
+    /** Reads the animation library */
+    void ReadAnimationLibrary();
+
+    /** Reads the animation clip library */
+    void ReadAnimationClipLibrary();
+
+    /** Unwrap controllers dependency hierarchy */
+    void PostProcessControllers();
+
+    /** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */
+    void PostProcessRootAnimations();
+
+    /** Reads an animation into the given parent structure */
+    void ReadAnimation(Collada::Animation *pParent);
+
+    /** Reads an animation sampler into the given anim channel */
+    void ReadAnimationSampler(Collada::AnimationChannel &pChannel);
+
+    /** Reads the skeleton controller library */
+    void ReadControllerLibrary();
+
+    /** Reads a controller into the given mesh structure */
+    void ReadController(Collada::Controller &pController);
+
+    /** Reads the joint definitions for the given controller */
+    void ReadControllerJoints(Collada::Controller &pController);
+
+    /** Reads the joint weights for the given controller */
+    void ReadControllerWeights(Collada::Controller &pController);
+
+    /** Reads the image library contents */
+    void ReadImageLibrary();
+
+    /** Reads an image entry into the given image */
+    void ReadImage(Collada::Image &pImage);
+
+    /** Reads the material library */
+    void ReadMaterialLibrary();
+
+    /** Reads a material entry into the given material */
+    void ReadMaterial(Collada::Material &pMaterial);
+
+    /** Reads the camera library */
+    void ReadCameraLibrary();
+
+    /** Reads a camera entry into the given camera */
+    void ReadCamera(Collada::Camera &pCamera);
+
+    /** Reads the light library */
+    void ReadLightLibrary();
+
+    /** Reads a light entry into the given light */
+    void ReadLight(Collada::Light &pLight);
+
+    /** Reads the effect library */
+    void ReadEffectLibrary();
+
+    /** Reads an effect entry into the given effect*/
+    void ReadEffect(Collada::Effect &pEffect);
+
+    /** Reads an COMMON effect profile */
+    void ReadEffectProfileCommon(Collada::Effect &pEffect);
+
+    /** Read sampler properties */
+    void ReadSamplerProperties(Collada::Sampler &pSampler);
+
+    /** Reads an effect entry containing a color or a texture defining that color */
+    void ReadEffectColor(aiColor4D &pColor, Collada::Sampler &pSampler);
+
+    /** Reads an effect entry containing a float */
+    void ReadEffectFloat(ai_real &pFloat);
+
+    /** Reads an effect parameter specification of any kind */
+    void ReadEffectParam(Collada::EffectParam &pParam);
+
+    /** Reads the geometry library contents */
+    void ReadGeometryLibrary();
+
+    /** Reads a geometry from the geometry library. */
+    void ReadGeometry(Collada::Mesh &pMesh);
+
+    /** Reads a mesh from the geometry library */
+    void ReadMesh(Collada::Mesh &pMesh);
+
+    /** Reads a source element - a combination of raw data and an accessor defining
+         * things that should not be redefinable. Yes, that's another rant.
+         */
+    void ReadSource();
+
+    /** 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.
+         */
+    void ReadDataArray();
+
+    /** Reads an accessor and stores it in the global library under the given ID -
+         * accessors use the ID of the parent <source> element
+         */
+    void ReadAccessor(const std::string &pID);
+
+    /** Reads input declarations of per-vertex mesh data into the given mesh */
+    void ReadVertexData(Collada::Mesh &pMesh);
+
+    /** Reads input declarations of per-index mesh data into the given mesh */
+    void ReadIndexData(Collada::Mesh &pMesh);
+
+    /** Reads a single input channel element and stores it in the given array, if valid */
+    void ReadInputChannel(std::vector<Collada::InputChannel> &poChannels);
+
+    /** 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 pNumPrimitives, const std::vector<size_t> &pVCount, Collada::PrimitiveType pPrimType);
+
+    /** Copies the data for a single primitive into the mesh, based on the InputChannels */
+    void CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset,
+            Collada::Mesh &pMesh, std::vector<Collada::InputChannel> &pPerIndexChannels,
+            size_t currentPrimitive, const std::vector<size_t> &indices);
+
+    /** Reads one triangle of a tristrip into the mesh */
+    void ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Collada::Mesh &pMesh,
+            std::vector<Collada::InputChannel> &pPerIndexChannels, size_t currentPrimitive, const std::vector<size_t> &indices);
+
+    /** Extracts a single object from an input channel and stores it in the appropriate mesh data array */
+    void ExtractDataObjectFromChannel(const Collada::InputChannel &pInput, size_t pLocalIndex, Collada::Mesh &pMesh);
+
+    /** Reads the library of node hierarchies and scene parts */
+    void ReadSceneLibrary();
+
+    /** Reads a scene node's contents including children and stores it in the given node */
+    void ReadSceneNode(Collada::Node *pNode);
+
+    /** 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);
+
+    /** Reads a mesh reference in a node and adds it to the node's mesh list */
+    void ReadNodeGeometry(Collada::Node *pNode);
+
+    /** Reads the collada scene */
+    void ReadScene();
+
+    // Processes bind_vertex_input and bind elements
+    void ReadMaterialVertexInputBinding(Collada::SemanticMappingTable &tbl);
+
+    /** Reads embedded textures from a ZAE archive*/
+    void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
+
+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 */
+    aiMatrix4x4 CalculateResultTransform(const std::vector<Collada::Transform> &pTransforms) const;
+
+    /** Determines the input data type for the given semantic string */
+    Collada::InputType GetTypeForSemantic(const std::string &pSemantic);
+
+    /** Finds the item in the given library by its reference, throws if not found */
+    template <typename Type>
+    const Type &ResolveLibraryReference(const std::map<std::string, Type> &pLibrary, const std::string &pURL) const;
+
+protected:
+    /** Filename, for a verbose error message */
+    std::string mFileName;
+
+    /** XML reader, member for everyday use */
+    irr::io::IrrXMLReader *mReader;
+
+    /** All data arrays found in the file by ID. Might be referred to by actually
+         everyone. Collada, you are a steaming pile of indirection. */
+    typedef std::map<std::string, Collada::Data> DataLibrary;
+    DataLibrary mDataLibrary;
+
+    /** Same for accessors which define how the data in a data array is accessed. */
+    typedef std::map<std::string, Collada::Accessor> AccessorLibrary;
+    AccessorLibrary mAccessorLibrary;
+
+    /** Mesh library: mesh by ID */
+    typedef std::map<std::string, Collada::Mesh *> MeshLibrary;
+    MeshLibrary mMeshLibrary;
+
+    /** node library: root node of the hierarchy part by ID */
+    typedef std::map<std::string, Collada::Node *> NodeLibrary;
+    NodeLibrary mNodeLibrary;
+
+    /** Image library: stores texture properties by ID */
+    typedef std::map<std::string, Collada::Image> ImageLibrary;
+    ImageLibrary mImageLibrary;
+
+    /** Effect library: surface attributes by ID */
+    typedef std::map<std::string, Collada::Effect> EffectLibrary;
+    EffectLibrary mEffectLibrary;
+
+    /** Material library: surface material by ID */
+    typedef std::map<std::string, Collada::Material> MaterialLibrary;
+    MaterialLibrary mMaterialLibrary;
+
+    /** Light library: surface light by ID */
+    typedef std::map<std::string, Collada::Light> LightLibrary;
+    LightLibrary mLightLibrary;
+
+    /** Camera library: surface material by ID */
+    typedef std::map<std::string, Collada::Camera> CameraLibrary;
+    CameraLibrary mCameraLibrary;
+
+    /** Controller library: joint controllers by ID */
+    typedef std::map<std::string, Collada::Controller> ControllerLibrary;
+    ControllerLibrary mControllerLibrary;
+
+    /** Animation library: animation references by ID */
+    typedef std::map<std::string, Collada::Animation *> AnimationLibrary;
+    AnimationLibrary mAnimationLibrary;
+
+    /** Animation clip library: clip animation references by ID */
+    typedef std::vector<std::pair<std::string, std::vector<std::string>>> AnimationClipLibrary;
+    AnimationClipLibrary mAnimationClipLibrary;
+
+    /** Pointer to the root node. Don't delete, it just points to one of
+         the nodes in the node library. */
+    Collada::Node *mRootNode;
+
+    /** Root animation container */
+    Collada::Animation mAnims;
+
+    /** Size unit: how large compared to a meter */
+    ai_real mUnitSize;
+
+    /** Which is the up vector */
+    enum { UP_X,
+        UP_Y,
+        UP_Z } mUpDirection;
+
+    /** Asset metadata (global for scene) */
+    StringMetaData mAssetMetaData;
+
+    /** Collada file format version */
+    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
+template <typename Type>
+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);
+    if (it == pLibrary.end())
+        ThrowException(Formatter::format() << "Unable to resolve library reference \"" << pURL << "\".");
+    return it->second;
+}
+
+} // end of namespace Assimp
+
+#endif // AI_COLLADAPARSER_H_INC

+ 1 - 1
code/DXF/DXFHelper.h → code/AssetLib/DXF/DXFHelper.h

@@ -135,7 +135,7 @@ public:
                 for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
 
                 splitter++;
-                ASSIMP_LOG_DEBUG((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
+                ASSIMP_LOG_VERBOSE_DEBUG((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
             }
         } catch(std::logic_error&) {
             ai_assert(!splitter);

+ 5 - 5
code/DXF/DXFLoader.cpp → code/AssetLib/DXF/DXFLoader.cpp

@@ -48,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_DXF_IMPORTER
 
-#include "DXF/DXFLoader.h"
-#include "DXF/DXFHelper.h"
+#include "AssetLib/DXF/DXFLoader.h"
+#include "AssetLib/DXF/DXFHelper.h"
 #include "PostProcessing/ConvertToLHProcess.h"
 
 #include <assimp/ParsingUtils.h>
@@ -241,7 +241,7 @@ void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output) {
             }
         }
 
-        ASSIMP_LOG_DEBUG_F("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
+        ASSIMP_LOG_VERBOSE_DEBUG_F("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
     }
 
     if (! output.blocks.size()  ) {
@@ -473,7 +473,7 @@ void DXFImporter::ParseBlocks(DXF::LineReader& reader, DXF::FileData& output) {
         ++reader;
     }
 
-    ASSIMP_LOG_DEBUG_F("DXF: got ", output.blocks.size()," entries in BLOCKS" );
+    ASSIMP_LOG_VERBOSE_DEBUG_F("DXF: got ", output.blocks.size()," entries in BLOCKS" );
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -549,7 +549,7 @@ void DXFImporter::ParseEntities(DXF::LineReader& reader, DXF::FileData& output)
         ++reader;
     }
 
-    ASSIMP_LOG_DEBUG_F( "DXF: got ", block.lines.size()," polylines and ", block.insertions.size(), 
+    ASSIMP_LOG_VERBOSE_DEBUG_F( "DXF: got ", block.lines.size()," polylines and ", block.insertions.size(), 
         " inserted blocks in ENTITIES" );
 }
 

+ 0 - 0
code/DXF/DXFLoader.h → code/AssetLib/DXF/DXFLoader.h


+ 77 - 92
code/FBX/FBXAnimation.cpp → code/AssetLib/FBX/FBXAnimation.cpp

@@ -47,10 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
 
-#include "FBXParser.h"
 #include "FBXDocument.h"
-#include "FBXImporter.h"
 #include "FBXDocumentUtil.h"
+#include "FBXImporter.h"
+#include "FBXParser.h"
 
 namespace Assimp {
 namespace FBX {
@@ -58,65 +58,60 @@ namespace FBX {
 using namespace Util;
 
 // ------------------------------------------------------------------------------------------------
-AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/)
-: Object(id, element, name)
-{
-    const Scope& sc = GetRequiredScope(element);
-    const Element& KeyTime = GetRequiredElement(sc,"KeyTime");
-    const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat");
+AnimationCurve::AnimationCurve(uint64_t id, const Element &element, const std::string &name, const Document & /*doc*/) :
+        Object(id, element, name) {
+    const Scope &sc = GetRequiredScope(element);
+    const Element &KeyTime = GetRequiredElement(sc, "KeyTime");
+    const Element &KeyValueFloat = GetRequiredElement(sc, "KeyValueFloat");
 
     ParseVectorDataArray(keys, KeyTime);
     ParseVectorDataArray(values, KeyValueFloat);
 
-    if(keys.size() != values.size()) {
-        DOMError("the number of key times does not match the number of keyframe values",&KeyTime);
+    if (keys.size() != values.size()) {
+        DOMError("the number of key times does not match the number of keyframe values", &KeyTime);
     }
 
     // check if the key times are well-ordered
-    if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
-        DOMError("the keyframes are not in ascending order",&KeyTime);
+    if (!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) {
+        DOMError("the keyframes are not in ascending order", &KeyTime);
     }
 
-    const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"];
-    if(KeyAttrDataFloat) {
+    const Element *KeyAttrDataFloat = sc["KeyAttrDataFloat"];
+    if (KeyAttrDataFloat) {
         ParseVectorDataArray(attributes, *KeyAttrDataFloat);
     }
 
-    const Element* KeyAttrFlags = sc["KeyAttrFlags"];
-    if(KeyAttrFlags) {
+    const Element *KeyAttrFlags = sc["KeyAttrFlags"];
+    if (KeyAttrFlags) {
         ParseVectorDataArray(flags, *KeyAttrFlags);
     }
 }
 
 // ------------------------------------------------------------------------------------------------
-AnimationCurve::~AnimationCurve()
-{
+AnimationCurve::~AnimationCurve() {
     // empty
 }
 
 // ------------------------------------------------------------------------------------------------
-AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, 
-        const Document& doc, const char* const * target_prop_whitelist /*= NULL*/, 
-        size_t whitelist_size /*= 0*/)
-: Object(id, element, name)
-, target()
-, doc(doc)
-{
-    const Scope& sc = GetRequiredScope(element);
+AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element &element, const std::string &name,
+        const Document &doc, const char *const *target_prop_whitelist /*= nullptr*/,
+        size_t whitelist_size /*= 0*/) :
+        Object(id, element, name), target(), doc(doc) {
+    const Scope &sc = GetRequiredScope(element);
 
     // find target node
-    const char* whitelist[] = {"Model","NodeAttribute","Deformer"};
-    const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,3);
+    const char *whitelist[] = { "Model", "NodeAttribute", "Deformer" };
+    const std::vector<const Connection *> &conns = doc.GetConnectionsBySourceSequenced(ID(), whitelist, 3);
 
-    for(const Connection* con : conns) {
+    for (const Connection *con : conns) {
 
         // link should go for a property
         if (!con->PropertyName().length()) {
             continue;
         }
 
-        if(target_prop_whitelist) {
-            const char* const s = con->PropertyName().c_str();
+        if (target_prop_whitelist) {
+            const char *const s = con->PropertyName().c_str();
             bool ok = false;
             for (size_t i = 0; i < whitelist_size; ++i) {
                 if (!strcmp(s, target_prop_whitelist[i])) {
@@ -130,16 +125,14 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, cons
             }
         }
 
-        const Object* const ob = con->DestinationObject();
-        if(!ob) {
-            DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element);
+        const Object *const ob = con->DestinationObject();
+        if (!ob) {
+            DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring", &element);
             continue;
         }
 
-        // XXX support constraints as DOM class
-        //ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob));
         target = ob;
-        if(!target) {
+        if (!target) {
             continue;
         }
 
@@ -147,42 +140,40 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, cons
         break;
     }
 
-    if(!target) {
-        DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element);
+    if (!target) {
+        DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode", &element);
     }
 
-    props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false);
+    props = GetPropertyTable(doc, "AnimationCurveNode.FbxAnimCurveNode", element, sc, false);
 }
 
 // ------------------------------------------------------------------------------------------------
-AnimationCurveNode::~AnimationCurveNode()
-{
+AnimationCurveNode::~AnimationCurveNode() {
     // empty
 }
 
 // ------------------------------------------------------------------------------------------------
-const AnimationCurveMap& AnimationCurveNode::Curves() const
-{
-    if ( curves.empty() ) {
+const AnimationCurveMap &AnimationCurveNode::Curves() const {
+    if (curves.empty()) {
         // resolve attached animation curves
-        const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve");
+        const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurve");
 
-        for(const Connection* con : conns) {
+        for (const Connection *con : conns) {
 
             // link should go for a property
             if (!con->PropertyName().length()) {
                 continue;
             }
 
-            const Object* const ob = con->SourceObject();
-            if(!ob) {
-                DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element);
+            const Object *const ob = con->SourceObject();
+            if (nullptr == ob) {
+                DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring", &element);
                 continue;
             }
 
-            const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob);
-            if(!anim) {
-                DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element);
+            const AnimationCurve *const anim = dynamic_cast<const AnimationCurve *>(ob);
+            if (nullptr == anim) {
+                DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve", &element);
                 continue;
             }
 
@@ -194,53 +185,49 @@ const AnimationCurveMap& AnimationCurveNode::Curves() const
 }
 
 // ------------------------------------------------------------------------------------------------
-AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc)
-: Object(id, element, name)
-, doc(doc)
-{
-    const Scope& sc = GetRequiredScope(element);
+AnimationLayer::AnimationLayer(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
+        Object(id, element, name), doc(doc) {
+    const Scope &sc = GetRequiredScope(element);
 
     // note: the props table here bears little importance and is usually absent
-    props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true);
+    props = GetPropertyTable(doc, "AnimationLayer.FbxAnimLayer", element, sc, true);
 }
 
 // ------------------------------------------------------------------------------------------------
-AnimationLayer::~AnimationLayer()
-{
+AnimationLayer::~AnimationLayer() {
     // empty
 }
 
 // ------------------------------------------------------------------------------------------------
-AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/,
-    size_t whitelist_size /*= 0*/) const
-{
+AnimationCurveNodeList AnimationLayer::Nodes(const char *const *target_prop_whitelist /*= nullptr*/,
+        size_t whitelist_size /*= 0*/) const {
     AnimationCurveNodeList nodes;
 
     // resolve attached animation nodes
-    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode");
+    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationCurveNode");
     nodes.reserve(conns.size());
 
-    for(const Connection* con : conns) {
+    for (const Connection *con : conns) {
 
         // link should not go to a property
         if (con->PropertyName().length()) {
             continue;
         }
 
-        const Object* const ob = con->SourceObject();
-        if(!ob) {
-            DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element);
+        const Object *const ob = con->SourceObject();
+        if (!ob) {
+            DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring", &element);
             continue;
         }
 
-        const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob);
-        if(!anim) {
-            DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element);
+        const AnimationCurveNode *const anim = dynamic_cast<const AnimationCurveNode *>(ob);
+        if (!anim) {
+            DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode", &element);
             continue;
         }
 
-        if(target_prop_whitelist) {
-            const char* s = anim->TargetProperty().c_str();
+        if (target_prop_whitelist) {
+            const char *s = anim->TargetProperty().c_str();
             bool ok = false;
             for (size_t i = 0; i < whitelist_size; ++i) {
                 if (!strcmp(s, target_prop_whitelist[i])) {
@@ -248,7 +235,7 @@ AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whi
                     break;
                 }
             }
-            if(!ok) {
+            if (!ok) {
                 continue;
             }
         }
@@ -259,34 +246,33 @@ AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whi
 }
 
 // ------------------------------------------------------------------------------------------------
-AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc)
-: Object(id, element, name)
-{
-    const Scope& sc = GetRequiredScope(element);
+AnimationStack::AnimationStack(uint64_t id, const Element &element, const std::string &name, const Document &doc) :
+        Object(id, element, name) {
+    const Scope &sc = GetRequiredScope(element);
 
     // note: we don't currently use any of these properties so we shouldn't bother if it is missing
-    props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true);
+    props = GetPropertyTable(doc, "AnimationStack.FbxAnimStack", element, sc, true);
 
     // resolve attached animation layers
-    const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer");
+    const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(ID(), "AnimationLayer");
     layers.reserve(conns.size());
 
-    for(const Connection* con : conns) {
+    for (const Connection *con : conns) {
 
         // link should not go to a property
         if (con->PropertyName().length()) {
             continue;
         }
 
-        const Object* const ob = con->SourceObject();
-        if(!ob) {
-            DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element);
+        const Object *const ob = con->SourceObject();
+        if (!ob) {
+            DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring", &element);
             continue;
         }
 
-        const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob);
-        if(!anim) {
-            DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element);
+        const AnimationLayer *const anim = dynamic_cast<const AnimationLayer *>(ob);
+        if (!anim) {
+            DOMWarning("source object for ->AnimationStack link is not an AnimationLayer", &element);
             continue;
         }
         layers.push_back(anim);
@@ -294,12 +280,11 @@ AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::s
 }
 
 // ------------------------------------------------------------------------------------------------
-AnimationStack::~AnimationStack()
-{
+AnimationStack::~AnimationStack() {
     // empty
 }
 
-} //!FBX
-} //!Assimp
+} // namespace FBX
+} // namespace Assimp
 
 #endif // ASSIMP_BUILD_NO_FBX_IMPORTER

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

@@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <stdint.h>
 #include <assimp/Exceptional.h>
 #include <assimp/ByteSwapper.h>
+#include <assimp/DefaultLogger.hpp>
 
 namespace Assimp {
 namespace FBX {
@@ -426,7 +427,8 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
 // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
 void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
 {
-    ai_assert(input);
+	ai_assert(input);
+	ASSIMP_LOG_DEBUG("Tokenizing binary FBX file");
 
     if(length < 0x1b) {
         TokenizeError("file is too short",0);
@@ -451,6 +453,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
 	/*Result ignored*/ ReadByte(input, cursor, input + length);
 	/*Result ignored*/ ReadByte(input, cursor, input + length);
 	const uint32_t version = ReadWord(input, cursor, input + length);
+	ASSIMP_LOG_DEBUG_F("FBX version: ", version);
 	const bool is64bits = version >= 7500;
     const char *end = input + length;
     while (cursor < end ) {

+ 0 - 0
code/FBX/FBXCommon.h → code/AssetLib/FBX/FBXCommon.h


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


+ 14 - 14
code/FBX/FBXConverter.cpp → code/AssetLib/FBX/FBXConverter.cpp

@@ -105,7 +105,7 @@ FBXConverter::FBXConverter(aiScene *out, const Document &doc, bool removeEmptyBo
     // The idea here is to traverse all objects to find these Textures and convert them,
     // so later during material conversion it will find converted texture in the textures_converted array.
     if (doc.Settings().readTextures) {
-        ConvertOrphantEmbeddedTextures();
+        ConvertOrphanedEmbeddedTextures();
     }
     ConvertRootNode();
 
@@ -804,11 +804,6 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
         aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]);
     }
 
-    // is_complex needs to be consistent with NeedsComplexTransformationChain()
-    // or the interplay between this code and the animation converter would
-    // not be guaranteed.
-    //ai_assert(NeedsComplexTransformationChain(model) == ((chainBits & chainMaskComplex) != 0));
-
     // now, if we have more than just Translation, Scaling and Rotation,
     // we need to generate a full node chain to accommodate for assimp's
     // lack to express pivots and offsets.
@@ -1163,7 +1158,8 @@ unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, c
                 const std::vector<aiVector3D> &curVertices = shapeGeometry->GetVertices();
                 const std::vector<aiVector3D> &curNormals = shapeGeometry->GetNormals();
                 const std::vector<unsigned int> &curIndices = shapeGeometry->GetIndices();
-                animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
+                //losing channel name if using shapeGeometry->Name()
+                animMesh->mName.Set(FixAnimMeshName(blendShapeChannel->Name()));
                 for (size_t j = 0; j < curIndices.size(); j++) {
                     const unsigned int curIndex = curIndices.at(j);
                     aiVector3D vertex = curVertices.at(j);
@@ -1289,7 +1285,8 @@ unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, co
         }
 
         if (binormals) {
-            ai_assert(tangents.size() == vertices.size() && binormals->size() == vertices.size());
+            ai_assert(tangents.size() == vertices.size());
+            ai_assert(binormals->size() == vertices.size());
 
             out_mesh->mTangents = new aiVector3D[vertices.size()];
             out_mesh->mBitangents = new aiVector3D[vertices.size()];
@@ -1542,10 +1539,10 @@ void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const
     aiBone *bone = nullptr;
 
     if (bone_map.count(deformer_name)) {
-        ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name);
+        ASSIMP_LOG_VERBOSE_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name);
         bone = bone_map[deformer_name];
     } else {
-        ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name);
+        ASSIMP_LOG_VERBOSE_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name);
         bone = new aiBone();
         bone->mName = bone_name;
 
@@ -2719,7 +2716,7 @@ void FBXConverter::GenerateNodeAnimations(std::vector<aiNodeAnim *> &node_anims,
             if (doc.Settings().optimizeEmptyAnimationCurves &&
                     IsRedundantAnimationData(target, comp, (chain[i]->second))) {
 
-                FBXImporter::LogDebug("dropping redundant animation channel for node " + target.Name());
+                FBXImporter::LogVerboseDebug("dropping redundant animation channel for node " + target.Name());
                 continue;
             }
 
@@ -3164,7 +3161,8 @@ FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector<c
             }
 
             const AnimationCurve *const curve = kv.second;
-            ai_assert(curve->GetKeys().size() == curve->GetValues().size() && curve->GetKeys().size());
+            ai_assert(curve->GetKeys().size() == curve->GetValues().size());
+            ai_assert(curve->GetKeys().size());
 
             //get values within the start/stop time window
             std::shared_ptr<KeyTimeList> Keys(new KeyTimeList());
@@ -3315,6 +3313,7 @@ void FBXConverter::InterpolateKeys(aiQuatKey *valOut, const KeyTimeList &keys, c
         // http://www.3dkingdoms.com/weekly/weekly.php?a=36
         if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0) {
             quat.Conjugate();
+            quat.w = -quat.w;
         }
         lastq = quat;
 
@@ -3401,7 +3400,8 @@ void FBXConverter::ConvertGlobalSettings() {
     mSceneOut->mMetaData->Set(5, "CoordAxisSign", doc.GlobalSettings().CoordAxisSign());
     mSceneOut->mMetaData->Set(6, "OriginalUpAxis", doc.GlobalSettings().OriginalUpAxis());
     mSceneOut->mMetaData->Set(7, "OriginalUpAxisSign", doc.GlobalSettings().OriginalUpAxisSign());
-    mSceneOut->mMetaData->Set(8, "UnitScaleFactor", (double)doc.GlobalSettings().UnitScaleFactor());
+    //const double unitScaleFactor = (double)doc.GlobalSettings().UnitScaleFactor();
+    mSceneOut->mMetaData->Set(8, "UnitScaleFactor", doc.GlobalSettings().UnitScaleFactor());
     mSceneOut->mMetaData->Set(9, "OriginalUnitScaleFactor", doc.GlobalSettings().OriginalUnitScaleFactor());
     mSceneOut->mMetaData->Set(10, "AmbientColor", doc.GlobalSettings().AmbientColor());
     mSceneOut->mMetaData->Set(11, "FrameRate", (int)doc.GlobalSettings().TimeMode());
@@ -3465,7 +3465,7 @@ void FBXConverter::TransferDataToScene() {
     }
 }
 
-void FBXConverter::ConvertOrphantEmbeddedTextures() {
+void FBXConverter::ConvertOrphanedEmbeddedTextures() {
     // in C++14 it could be:
     // for (auto&& [id, object] : objects)
     for (auto &&id_and_object : doc.Objects()) {

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

@@ -220,8 +220,8 @@ private:
     *    each output vertex the DOM index it maps to.
     */
     void ConvertWeights(aiMesh *out, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
-                        aiNode *parent = NULL, unsigned int materialIndex = NO_MATERIAL_SEPARATION,
-                        std::vector<unsigned int> *outputVertStartIndices = NULL);
+            aiNode *parent = nullptr, unsigned int materialIndex = NO_MATERIAL_SEPARATION,
+            std::vector<unsigned int> *outputVertStartIndices = nullptr);
 
     // ------------------------------------------------------------------------------------------------
     void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
@@ -412,7 +412,7 @@ private:
 
     // ------------------------------------------------------------------------------------------------
     // FBX file could have embedded textures not connected to anything
-    void ConvertOrphantEmbeddedTextures();
+    void ConvertOrphanedEmbeddedTextures();
 
 private:
     // 0: not assigned yet, others: index is value - 1

+ 0 - 0
code/FBX/FBXDeformer.cpp → code/AssetLib/FBX/FBXDeformer.cpp


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

@@ -55,6 +55,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "FBXDocumentUtil.h"
 #include "FBXProperties.h"
 
+#include <assimp/DefaultLogger.hpp>
+
 #include <memory>
 #include <functional>
 #include <map>
@@ -219,7 +221,7 @@ const Object* LazyObject::Get(bool dieOnError)
         if(!DefaultLogger::isNullLogger()) {
             ASSIMP_LOG_ERROR(ex.what());
         }
-        return NULL;
+        return nullptr;
     }
 
     if (!object.get()) {
@@ -264,6 +266,8 @@ Document::Document(const Parser& parser, const ImportSettings& settings)
 : settings(settings)
 , parser(parser)
 {
+	ASSIMP_LOG_DEBUG("Creating FBX Document");
+
     // Cannot use array default initialization syntax because vc8 fails on it
     for (auto &timeStamp : creationTimeStamp) {
         timeStamp = 0;
@@ -308,6 +312,7 @@ void Document::ReadHeader() {
 
     const Scope& shead = *ehead->Compound();
     fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0));
+	ASSIMP_LOG_DEBUG_F("FBX Version: ", fbxVersion);
 
     // While we may have some success with newer files, we don't support
     // the older 6.n fbx format
@@ -462,7 +467,7 @@ void Document::ReadPropertyTemplates()
             const Element *Properties70 = (*innerSc)["Properties70"];
             if(Properties70) {
                 std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>(
-                    *Properties70,std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL))
+                        *Properties70, std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable *>(nullptr))
                 );
 
                 templates[oname+"."+pname] = props;

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott