2
0
Эх сурвалжийг харах

Merge pull request #13 from assimp/master

Update to upstream master
ardenpm 5 жил өмнө
parent
commit
be391a3b66
100 өөрчлөгдсөн 2349 нэмэгдсэн , 1825 устгасан
  1. 2 2
      .clang-format
  2. 1 1
      .github/FUNDING.yml
  3. 1 1
      .travis.sh
  4. 3 0
      .travis.yml
  5. 1 0
      Build.md
  6. 82 58
      CMakeLists.txt
  7. 1 1
      LICENSE
  8. 1 1
      Readme.md
  9. 8 6
      appveyor.yml
  10. 1 1
      assimp-config-version.cmake.in
  11. 1 1
      code/3DS/3DSConverter.cpp
  12. 1 1
      code/3DS/3DSExporter.cpp
  13. 1 1
      code/3DS/3DSExporter.h
  14. 1 1
      code/3DS/3DSHelper.h
  15. 1 1
      code/3DS/3DSLoader.cpp
  16. 1 1
      code/3DS/3DSLoader.h
  17. 1 1
      code/3MF/3MFXmlTags.h
  18. 1 1
      code/3MF/D3MFExporter.cpp
  19. 1 1
      code/3MF/D3MFExporter.h
  20. 1 1
      code/3MF/D3MFImporter.cpp
  21. 1 1
      code/3MF/D3MFImporter.h
  22. 1 1
      code/3MF/D3MFOpcPackage.cpp
  23. 1 1
      code/3MF/D3MFOpcPackage.h
  24. 1 1
      code/AC/ACLoader.cpp
  25. 1 1
      code/AC/ACLoader.h
  26. 1 1
      code/AMF/AMFImporter.cpp
  27. 1 1
      code/AMF/AMFImporter.hpp
  28. 1 1
      code/AMF/AMFImporter_Geometry.cpp
  29. 1 1
      code/AMF/AMFImporter_Macro.hpp
  30. 1 1
      code/AMF/AMFImporter_Material.cpp
  31. 1 1
      code/AMF/AMFImporter_Node.hpp
  32. 1 1
      code/AMF/AMFImporter_Postprocess.cpp
  33. 1 1
      code/ASE/ASELoader.cpp
  34. 1 1
      code/ASE/ASELoader.h
  35. 1 1
      code/ASE/ASEParser.cpp
  36. 1 1
      code/ASE/ASEParser.h
  37. 10 787
      code/Assbin/AssbinExporter.cpp
  38. 1 1
      code/Assbin/AssbinExporter.h
  39. 858 0
      code/Assbin/AssbinFileWriter.cpp
  40. 66 0
      code/Assbin/AssbinFileWriter.h
  41. 2 2
      code/Assbin/AssbinLoader.cpp
  42. 1 1
      code/Assbin/AssbinLoader.h
  43. 5 5
      code/Assjson/cencode.c
  44. 8 595
      code/Assxml/AssxmlExporter.cpp
  45. 1 1
      code/Assxml/AssxmlExporter.h
  46. 664 0
      code/Assxml/AssxmlFileWriter.cpp
  47. 65 0
      code/Assxml/AssxmlFileWriter.h
  48. 95 94
      code/B3D/B3DImporter.cpp
  49. 1 1
      code/B3D/B3DImporter.h
  50. 1 1
      code/BVH/BVHLoader.cpp
  51. 1 1
      code/BVH/BVHLoader.h
  52. 1 1
      code/Blender/BlenderBMesh.cpp
  53. 1 1
      code/Blender/BlenderBMesh.h
  54. 1 1
      code/Blender/BlenderDNA.cpp
  55. 1 1
      code/Blender/BlenderDNA.h
  56. 1 1
      code/Blender/BlenderDNA.inl
  57. 1 1
      code/Blender/BlenderIntermediate.h
  58. 1 1
      code/Blender/BlenderLoader.cpp
  59. 1 1
      code/Blender/BlenderLoader.h
  60. 1 1
      code/Blender/BlenderModifier.cpp
  61. 1 1
      code/Blender/BlenderModifier.h
  62. 1 1
      code/Blender/BlenderScene.cpp
  63. 1 1
      code/Blender/BlenderScene.h
  64. 1 1
      code/Blender/BlenderSceneGen.h
  65. 1 1
      code/Blender/BlenderTessellator.cpp
  66. 1 1
      code/Blender/BlenderTessellator.h
  67. 1 1
      code/C4D/C4DImporter.cpp
  68. 1 1
      code/C4D/C4DImporter.h
  69. 1 1
      code/CApi/AssimpCExport.cpp
  70. 1 1
      code/CApi/CInterfaceIOWrapper.cpp
  71. 1 1
      code/CApi/CInterfaceIOWrapper.h
  72. 20 5
      code/CMakeLists.txt
  73. 2 2
      code/COB/COBLoader.cpp
  74. 1 1
      code/COB/COBLoader.h
  75. 1 1
      code/COB/COBScene.h
  76. 2 2
      code/CSM/CSMLoader.cpp
  77. 1 1
      code/CSM/CSMLoader.h
  78. 4 3
      code/Collada/ColladaExporter.cpp
  79. 1 1
      code/Collada/ColladaExporter.h
  80. 107 0
      code/Collada/ColladaHelper.cpp
  81. 33 7
      code/Collada/ColladaHelper.h
  82. 24 4
      code/Collada/ColladaLoader.cpp
  83. 1 1
      code/Collada/ColladaLoader.h
  84. 42 35
      code/Collada/ColladaParser.cpp
  85. 2 5
      code/Collada/ColladaParser.h
  86. 1 1
      code/Common/Assimp.cpp
  87. 4 5
      code/Common/BaseImporter.cpp
  88. 1 1
      code/Common/BaseProcess.cpp
  89. 1 1
      code/Common/BaseProcess.h
  90. 1 1
      code/Common/Bitmap.cpp
  91. 1 1
      code/Common/CreateAnimMesh.cpp
  92. 1 1
      code/Common/DefaultIOStream.cpp
  93. 1 1
      code/Common/DefaultIOSystem.cpp
  94. 1 1
      code/Common/DefaultLogger.cpp
  95. 1 1
      code/Common/DefaultProgressHandler.h
  96. 4 4
      code/Common/Exporter.cpp
  97. 1 1
      code/Common/FileLogStream.h
  98. 1 1
      code/Common/FileSystemFilter.h
  99. 162 130
      code/Common/Importer.cpp
  100. 1 1
      code/Common/Importer.h

+ 2 - 2
.clang-format

@@ -71,7 +71,7 @@ IncludeCategories:
     Priority:        3
     Priority:        3
 # IncludeIsMainRegex: '(Test)?$'
 # IncludeIsMainRegex: '(Test)?$'
 IndentCaseLabels: true
 IndentCaseLabels: true
-# IndentPPDirectives: None
+IndentPPDirectives: AfterHash
 IndentWidth:     4
 IndentWidth:     4
 # IndentWrappedFunctionNames: false
 # IndentWrappedFunctionNames: false
 # JavaScriptQuotes: Leave
 # JavaScriptQuotes: Leave
@@ -108,7 +108,7 @@ IndentWidth:     4
 # SpacesInParentheses: false
 # SpacesInParentheses: false
 # SpacesInSquareBrackets: false
 # SpacesInSquareBrackets: false
 TabWidth:        4
 TabWidth:        4
-UseTab:          Always
+UseTab:          Never
 ---
 ---
 ### C++ specific config ###
 ### C++ specific config ###
 Language:        Cpp
 Language:        Cpp

+ 1 - 1
.github/FUNDING.yml

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

+ 1 - 1
.travis.sh

@@ -1,7 +1,7 @@
 #---------------------------------------------------------------------------
 #---------------------------------------------------------------------------
 #Open Asset Import Library (assimp)
 #Open Asset Import Library (assimp)
 #---------------------------------------------------------------------------
 #---------------------------------------------------------------------------
-# Copyright (c) 2006-2017, assimp team
+# Copyright (c) 2006-2020, assimp team
 #
 #
 # License see LICENSE file
 # License see LICENSE file
 #
 #

+ 3 - 0
.travis.yml

@@ -30,6 +30,9 @@ env:
     - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
     - secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
     - PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
     - PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
 
 
+git:
+  depth: 1
+
 matrix:
 matrix:
   include:
   include:
     - os: linux
     - os: linux

+ 1 - 0
Build.md

@@ -77,6 +77,7 @@ The cmake-build-environment provides options to configure the build. The followi
 - **ASSIMP_BUILD_SAMPLES ( default OFF )**: If the official samples are built as well (needs Glut).
 - **ASSIMP_BUILD_SAMPLES ( default OFF )**: If the official samples are built as well (needs Glut).
 - **ASSIMP_BUILD_TESTS ( default ON )**: If the test suite for Assimp is built in addition to the library.
 - **ASSIMP_BUILD_TESTS ( default ON )**: If the test suite for Assimp is built in addition to the library.
 - **ASSIMP_COVERALLS ( default OFF )**: Enable this to measure test coverage.
 - **ASSIMP_COVERALLS ( default OFF )**: Enable this to measure test coverage.
+- **ASSIMP_ERROR_MAX( default OFF)**: Enable all warnings.
 - **ASSIMP_WERROR( default OFF )**: Treat warnings as errors.
 - **ASSIMP_WERROR( default OFF )**: Treat warnings as errors.
 - **ASSIMP_ASAN ( default OFF )**: Enable AddressSanitizer.
 - **ASSIMP_ASAN ( default OFF )**: Enable AddressSanitizer.
 - **ASSIMP_UBSAN ( default OFF )**: Enable Undefined Behavior sanitizer.
 - **ASSIMP_UBSAN ( default OFF )**: Enable Undefined Behavior sanitizer.

+ 82 - 58
CMakeLists.txt

@@ -1,6 +1,6 @@
 # Open Asset Import Library (assimp)
 # Open Asset Import Library (assimp)
 # ----------------------------------------------------------------------
 # ----------------------------------------------------------------------
-# Copyright (c) 2006-2019, assimp team
+# Copyright (c) 2006-2020, assimp team
 #
 #
 # All rights reserved.
 # All rights reserved.
 #
 #
@@ -41,17 +41,17 @@ CMAKE_MINIMUM_REQUIRED( VERSION 3.0 )
 # Toggles the use of the hunter package manager
 # Toggles the use of the hunter package manager
 option(HUNTER_ENABLED "Enable Hunter package manager support" OFF)
 option(HUNTER_ENABLED "Enable Hunter package manager support" OFF)
 
 
-include("cmake/HunterGate.cmake")
-HunterGate(
+IF(HUNTER_ENABLED)
+  include("cmake/HunterGate.cmake")
+  HunterGate(
     URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz"
     URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz"
     SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a"
     SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a"
-)
+  )
 
 
-IF(HUNTER_ENABLED)
   add_definitions(-DASSIMP_USE_HUNTER)
   add_definitions(-DASSIMP_USE_HUNTER)
 ENDIF(HUNTER_ENABLED)
 ENDIF(HUNTER_ENABLED)
 
 
-PROJECT( Assimp VERSION 5.0.0 )
+PROJECT( Assimp VERSION 5.0.1 )
 
 
 # All supported options ###############################################
 # All supported options ###############################################
 
 
@@ -100,6 +100,14 @@ OPTION ( ASSIMP_COVERALLS
   "Enable this to measure test coverage."
   "Enable this to measure test coverage."
   OFF
   OFF
 )
 )
+OPTION( ASSIMP_INSTALL
+  "DIsable this if you want to use assimp as a submodule."
+  ON
+)
+OPTION ( ASSIMP_ERROR_MAX
+  "Enable all warnings."
+  OFF
+)
 OPTION ( ASSIMP_WERROR
 OPTION ( ASSIMP_WERROR
   "Treat warnings as errors."
   "Treat warnings as errors."
   OFF
   OFF
@@ -253,7 +261,7 @@ ELSEIF(MSVC)
   IF(MSVC12)
   IF(MSVC12)
     ADD_COMPILE_OPTIONS(/wd4351)
     ADD_COMPILE_OPTIONS(/wd4351)
   ENDIF()
   ENDIF()
-  SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /Zi")
+  SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
 ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
 ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
   IF(NOT HUNTER_ENABLED)
   IF(NOT HUNTER_ENABLED)
     SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
     SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
@@ -294,6 +302,16 @@ IF (ASSIMP_COVERALLS)
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
 ENDIF()
 ENDIF()
 
 
+IF (ASSIMP_ERROR_MAX)
+  MESSAGE(STATUS "Turning on all warnings")
+  IF (MSVC)
+    ADD_COMPILE_OPTIONS(/W4) # NB: there is a /Wall option, pedantic mode
+  ELSE()
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
+  ENDIF()
+ENDIF()
+
 IF (ASSIMP_WERROR)
 IF (ASSIMP_WERROR)
   MESSAGE(STATUS "Treating warnings as errors")
   MESSAGE(STATUS "Treating warnings as errors")
   IF (MSVC)
   IF (MSVC)
@@ -324,9 +342,13 @@ INCLUDE (PrecompiledHeader)
 # source tree. During an out-of-source build, however, do not litter this
 # source tree. During an out-of-source build, however, do not litter this
 # directory, since that is probably what the user wanted to avoid.
 # directory, since that is probably what the user wanted to avoid.
 IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
 IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
-  SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
+  SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
   SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
   SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/lib" )
   SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
   SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" )
+ELSE()
+  SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
+  SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
+  SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
 ENDIF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
 ENDIF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR )
 
 
 # Cache these to allow the user to override them manually.
 # Cache these to allow the user to override them manually.
@@ -419,8 +441,6 @@ ELSE(HUNTER_ENABLED)
     DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
     DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
 ENDIF(HUNTER_ENABLED)
 ENDIF(HUNTER_ENABLED)
 
 
-FIND_PACKAGE( DirectX )
-
 IF( BUILD_DOCS )
 IF( BUILD_DOCS )
   ADD_SUBDIRECTORY(doc)
   ADD_SUBDIRECTORY(doc)
 ENDIF( BUILD_DOCS )
 ENDIF( BUILD_DOCS )
@@ -587,55 +607,59 @@ ENDIF ( ASSIMP_BUILD_TESTS )
 
 
 # Generate a pkg-config .pc for the Assimp library.
 # Generate a pkg-config .pc for the Assimp library.
 CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
 CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY )
-INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
-
-IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
-  # Packing information
-  SET(CPACK_PACKAGE_NAME                    "assimp{ASSIMP_VERSION_MAJOR}.{ASSIMP_VERSION_MINOR}")
-  SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.")
-  SET(CPACK_PACKAGE_VENDOR                  "https://github.com/assimp")
-  SET(CPACK_PACKAGE_DISPLAY_NAME            "Assimp ${ASSIMP_VERSION}")
-  SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY     " - Open Asset Import Library ${ASSIMP_VERSION}")
-  SET(CPACK_PACKAGE_VERSION                 "${ASSIMP_VERSION}.${ASSIMP_PACKAGE_VERSION}" )
-  SET(CPACK_PACKAGE_VERSION_MAJOR           "${ASSIMP_VERSION_MAJOR}")
-  SET(CPACK_PACKAGE_VERSION_MINOR           "${ASSIMP_VERSION_MINOR}")
-  SET(CPACK_PACKAGE_VERSION_PATCH           "${ASSIMP_VERSION_PATCH}")
-  SET(CPACK_PACKAGE_INSTALL_DIRECTORY       "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
-  SET(CPACK_RESOURCE_FILE_LICENSE           "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
-
-  STRING(TOUPPER ${LIBASSIMP_COMPONENT}     "LIBASSIMP_COMPONENT_UPPER")
-  STRING(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER")
-
-  SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME                       "tools")
-  SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS                            "${LIBASSIMP_COMPONENT}" )
-  SET(CPACK_COMPONENT_${LIBASSIMP_COMPONENT_UPPER}_DISPLAY_NAME     "libraries")
-  SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DISPLAY_NAME "common headers and installs")
-  SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DEPENDS $    "{LIBASSIMP_COMPONENT}" )
-  SET(CPACK_COMPONENT_ASSIMP-DEV_DISPLAY_NAME                       "${CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT}_DISPLAY_NAME}" )
-  SET(CPACK_COMPONENT_ASSIMP-DEV_DEPENDS                            "${LIBASSIMP-DEV_COMPONENT}" )
-  SET(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake zlib1g-dev pkg-config)
-
-  # debian
-  SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
-  SET(CPACK_DEBIAN_CMAKE_OPTIONS    "-DBUILD_ASSIMP_SAMPLES:BOOL=${ASSIMP_BUILD_SAMPLES}")
-  SET(CPACK_DEBIAN_PACKAGE_SECTION  "libs" )
-  SET(CPACK_DEBIAN_PACKAGE_DEPENDS  "${CPACK_COMPONENTS_ALL}")
-  SET(CPACK_DEBIAN_PACKAGE_SUGGESTS)
-  set(cPACK_DEBIAN_PACKAGE_NAME     "assimp")
-  SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging)
-  SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force)
-  SET(CPACK_DEBIAN_CHANGELOG)
-  execute_process(COMMAND lsb_release -is
-    OUTPUT_VARIABLE _lsb_distribution OUTPUT_STRIP_TRAILING_WHITESPACE
-    RESULT_VARIABLE _lsb_release_failed)
-  SET(CPACK_DEBIAN_DISTRIBUTION_NAME ${_lsb_distribution} CACHE STRING "Name of the distrubiton")
-  STRING(TOLOWER ${CPACK_DEBIAN_DISTRIBUTION_NAME} CPACK_DEBIAN_DISTRIBUTION_NAME)
-  IF( ${CPACK_DEBIAN_DISTRIBUTION_NAME} STREQUAL "ubuntu" )
-    SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release")
+IF ( ASSIMP_INSTALL )
+  INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT})
+ENDIF( ASSIMP_INSTALL )
+
+IF ( ASSIMP_INSTALL )
+  IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
+    # Packing information
+    SET(CPACK_PACKAGE_NAME                    "assimp{ASSIMP_VERSION_MAJOR}.{ASSIMP_VERSION_MINOR}")
+    SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.")
+    SET(CPACK_PACKAGE_VENDOR                  "https://github.com/assimp")
+    SET(CPACK_PACKAGE_DISPLAY_NAME            "Assimp ${ASSIMP_VERSION}")
+    SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY     " - Open Asset Import Library ${ASSIMP_VERSION}")
+    SET(CPACK_PACKAGE_VERSION                 "${ASSIMP_VERSION}.${ASSIMP_PACKAGE_VERSION}" )
+    SET(CPACK_PACKAGE_VERSION_MAJOR           "${ASSIMP_VERSION_MAJOR}")
+    SET(CPACK_PACKAGE_VERSION_MINOR           "${ASSIMP_VERSION_MINOR}")
+    SET(CPACK_PACKAGE_VERSION_PATCH           "${ASSIMP_VERSION_PATCH}")
+    SET(CPACK_PACKAGE_INSTALL_DIRECTORY       "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}")
+    SET(CPACK_RESOURCE_FILE_LICENSE           "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
+
+    STRING(TOUPPER ${LIBASSIMP_COMPONENT}     "LIBASSIMP_COMPONENT_UPPER")
+    STRING(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER")
+
+    SET(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME                       "tools")
+    SET(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS                            "${LIBASSIMP_COMPONENT}" )
+    SET(CPACK_COMPONENT_${LIBASSIMP_COMPONENT_UPPER}_DISPLAY_NAME     "libraries")
+    SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DISPLAY_NAME "common headers and installs")
+    SET(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DEPENDS $    "{LIBASSIMP_COMPONENT}" )
+    SET(CPACK_COMPONENT_ASSIMP-DEV_DISPLAY_NAME                       "${CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT}_DISPLAY_NAME}" )
+    SET(CPACK_COMPONENT_ASSIMP-DEV_DEPENDS                            "${LIBASSIMP-DEV_COMPONENT}" )
+    SET(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake zlib1g-dev pkg-config)
+
+    # debian
+    SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
+    SET(CPACK_DEBIAN_CMAKE_OPTIONS    "-DBUILD_ASSIMP_SAMPLES:BOOL=${ASSIMP_BUILD_SAMPLES}")
+    SET(CPACK_DEBIAN_PACKAGE_SECTION  "libs" )
+    SET(CPACK_DEBIAN_PACKAGE_DEPENDS  "${CPACK_COMPONENTS_ALL}")
+    SET(CPACK_DEBIAN_PACKAGE_SUGGESTS)
+    SET(cPACK_DEBIAN_PACKAGE_NAME     "assimp")
+    SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging)
+    SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force)
+    SET(CPACK_DEBIAN_CHANGELOG)
+    execute_process(COMMAND lsb_release -is
+      OUTPUT_VARIABLE _lsb_distribution OUTPUT_STRIP_TRAILING_WHITESPACE
+      RESULT_VARIABLE _lsb_release_failed)
+    SET(CPACK_DEBIAN_DISTRIBUTION_NAME ${_lsb_distribution} CACHE STRING "Name of the distrubiton")
+    STRING(TOLOWER ${CPACK_DEBIAN_DISTRIBUTION_NAME} CPACK_DEBIAN_DISTRIBUTION_NAME)
+    IF( ${CPACK_DEBIAN_DISTRIBUTION_NAME} STREQUAL "ubuntu" )
+      SET(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release")
+    ENDIF()
+    SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources")
+    INCLUDE(CPack)
+    INCLUDE(DebSourcePPA)
   ENDIF()
   ENDIF()
-  SET(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources")
-  INCLUDE(CPack)
-  INCLUDE(DebSourcePPA)
 ENDIF()
 ENDIF()
 
 
 if(WIN32)
 if(WIN32)

+ 1 - 1
LICENSE

@@ -1,6 +1,6 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 
 
-Copyright (c) 2006-2016, assimp team
+Copyright (c) 2006-2020, assimp team
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,

+ 1 - 1
Readme.md

@@ -131,7 +131,7 @@ Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file.
 ### Ports ###
 ### Ports ###
 * [Android](port/AndroidJNI/README.md)
 * [Android](port/AndroidJNI/README.md)
 * [Python](port/PyAssimp/README.md)
 * [Python](port/PyAssimp/README.md)
-* [.NET](https://github.com/kebby/assimp-net)
+* [.NET](https://github.com/assimp/assimp-net)
 * [Pascal](port/AssimpPascal/Readme.md)
 * [Pascal](port/AssimpPascal/Readme.md)
 * [Javascript (Alpha)](https://github.com/makc/assimp2json)
 * [Javascript (Alpha)](https://github.com/makc/assimp2json)
 * [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
 * [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)

+ 8 - 6
appveyor.yml

@@ -4,6 +4,8 @@
 # clone directory
 # clone directory
 clone_folder: c:\projects\assimp
 clone_folder: c:\projects\assimp
 
 
+clone_depth: 1
+
 # branches to build
 # branches to build
 branches:
 branches:
   # whitelist
   # whitelist
@@ -15,10 +17,10 @@ matrix:
     
     
 image:
 image:
   - Visual Studio 2013
   - Visual Studio 2013
-  - Visual Studio 2015
-  - Visual Studio 2017
+  #- Visual Studio 2015
+  #- Visual Studio 2017
   - Visual Studio 2019
   - Visual Studio 2019
-  - MinGW  
+  #- MinGW  
     
     
 platform:
 platform:
   - Win32
   - Win32
@@ -52,11 +54,11 @@ cache:
   - bin\.mtime_cache
   - bin\.mtime_cache
   
   
 before_build:
 before_build:
+  - echo NUMBER_OF_PROCESSORS=%NUMBER_OF_PROCESSORS%
   - ruby scripts\AppVeyor\mtime_cache -g scripts\AppVeyor\cacheglobs.txt -c bin\.mtime_cache\cache.json
   - ruby scripts\AppVeyor\mtime_cache -g scripts\AppVeyor\cacheglobs.txt -c bin\.mtime_cache\cache.json
   
   
-build:
-  parallel: true
-  project: Assimp.sln
+build_script:
+  cmake --build . --config Release -- /maxcpucount:2
   
   
 after_build:
 after_build:
   - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
   - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (

+ 1 - 1
assimp-config-version.cmake.in

@@ -1,6 +1,6 @@
 # Open Asset Import Library (assimp)
 # Open Asset Import Library (assimp)
 # ----------------------------------------------------------------------
 # ----------------------------------------------------------------------
-# Copyright (c) 2006-2017, assimp team
+# Copyright (c) 2006-2020, assimp team
 # All rights reserved.
 # All rights reserved.
 #
 #
 # Redistribution and use of this software in source and binary forms,
 # Redistribution and use of this software in source and binary forms,

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

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/3DS/3DSExporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/3DS/3DSExporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/3DS/3DSHelper.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

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

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/3DS/3DSLoader.h

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

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

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/3MF/D3MFExporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/3MF/D3MFExporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/3MF/D3MFImporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/3MF/D3MFImporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/3MF/D3MFOpcPackage.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/3MF/D3MFOpcPackage.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/AC/ACLoader.cpp

@@ -4,7 +4,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/AC/ACLoader.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/AMF/AMFImporter.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/AMF/AMFImporter.hpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/AMF/AMFImporter_Geometry.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/AMF/AMFImporter_Macro.hpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/AMF/AMFImporter_Material.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/AMF/AMFImporter_Node.hpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/AMF/AMFImporter_Postprocess.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/ASE/ASELoader.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/ASE/ASELoader.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 

+ 1 - 1
code/ASE/ASEParser.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/ASE/ASEParser.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 10 - 787
code/Assbin/AssbinExporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.
@@ -46,799 +46,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
 
 
-#include "Common/assbin_chunks.h"
-#include "PostProcessing/ProcessHelper.h"
+#include "AssbinFileWriter.h"
 
 
-#include <assimp/version.h>
-#include <assimp/IOStream.hpp>
+#include <assimp/scene.h>
 #include <assimp/IOSystem.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/Exporter.hpp>
 #include <assimp/Exporter.hpp>
-#include <assimp/Exceptional.h>
-
-#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#   include <zlib.h>
-#else
-#   include "../contrib/zlib/zlib.h"
-#endif
-
-#include <time.h>
 
 
 namespace Assimp {
 namespace Assimp {
 
 
-template <typename T>
-size_t Write(IOStream * stream, const T& v) {
-    return stream->Write( &v, sizeof(T), 1 );
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize an aiString
-template <>
-inline
-size_t Write<aiString>(IOStream * stream, const aiString& s) {
-    const size_t s2 = (uint32_t)s.length;
-    stream->Write(&s,4,1);
-    stream->Write(s.data,s2,1);
-
-    return s2+4;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize an unsigned int as uint32_t
-template <>
-inline
-size_t Write<unsigned int>(IOStream * stream, const unsigned int& w) {
-    const uint32_t t = (uint32_t)w;
-    if (w > t) {
-        // this shouldn't happen, integers in Assimp data structures never exceed 2^32
-        throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
-    }
-
-    stream->Write(&t,4,1);
-
-    return 4;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize an unsigned int as uint16_t
-template <>
-inline
-size_t Write<uint16_t>(IOStream * stream, const uint16_t& w) {
-    static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2");
-    stream->Write(&w,2,1);
-
-    return 2;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize a float
-template <>
-inline
-size_t Write<float>(IOStream * stream, const float& f) {
-    static_assert(sizeof(float)==4, "sizeof(float)==4");
-    stream->Write(&f,4,1);
-
-    return 4;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize a double
-template <>
-inline
-size_t Write<double>(IOStream * stream, const double& f) {
-    static_assert(sizeof(double)==8, "sizeof(double)==8");
-    stream->Write(&f,8,1);
-
-    return 8;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize a vec3
-template <>
-inline
-size_t Write<aiVector3D>(IOStream * stream, const aiVector3D& v) {
-    size_t t = Write<float>(stream,v.x);
-    t += Write<float>(stream,v.y);
-    t += Write<float>(stream,v.z);
-
-    return t;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize a color value
-template <>
-inline
-size_t Write<aiColor3D>(IOStream * stream, const aiColor3D& v) {
-    size_t t = Write<float>(stream,v.r);
-    t += Write<float>(stream,v.g);
-    t += Write<float>(stream,v.b);
-
-    return t;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize a color value
-template <>
-inline
-size_t Write<aiColor4D>(IOStream * stream, const aiColor4D& v) {
-    size_t t = Write<float>(stream,v.r);
-    t += Write<float>(stream,v.g);
-    t += Write<float>(stream,v.b);
-    t += Write<float>(stream,v.a);
-
-    return t;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize a quaternion
-template <>
-inline
-size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v) {
-    size_t t = Write<float>(stream,v.w);
-    t += Write<float>(stream,v.x);
-    t += Write<float>(stream,v.y);
-    t += Write<float>(stream,v.z);
-    ai_assert(t == 16);
-
-    return 16;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize a vertex weight
-template <>
-inline
-size_t Write<aiVertexWeight>(IOStream * stream, const aiVertexWeight& v) {
-    size_t t = Write<unsigned int>(stream,v.mVertexId);
-
-    return t+Write<float>(stream,v.mWeight);
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize a mat4x4
-template <>
-inline
-size_t Write<aiMatrix4x4>(IOStream * stream, const aiMatrix4x4& m) {
-    for (unsigned int i = 0; i < 4;++i) {
-        for (unsigned int i2 = 0; i2 < 4;++i2) {
-            Write<float>(stream,m[i][i2]);
-        }
-    }
-
-    return 64;
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize an aiVectorKey
-template <>
-inline
-size_t Write<aiVectorKey>(IOStream * stream, const aiVectorKey& v) {
-    const size_t t = Write<double>(stream,v.mTime);
-    return t + Write<aiVector3D>(stream,v.mValue);
-}
-
-// -----------------------------------------------------------------------------------
-// Serialize an aiQuatKey
-template <>
-inline
-size_t Write<aiQuatKey>(IOStream * stream, const aiQuatKey& v) {
-    const size_t t = Write<double>(stream,v.mTime);
-    return t + Write<aiQuaternion>(stream,v.mValue);
-}
-
-template <typename T>
-inline
-size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) {
-    T minc, maxc;
-    ArrayBounds(in,size,minc,maxc);
-
-    const size_t t = Write<T>(stream,minc);
-    return t + Write<T>(stream,maxc);
-}
-
-// We use this to write out non-byte arrays so that we write using the specializations.
-// This way we avoid writing out extra bytes that potentially come from struct alignment.
-template <typename T>
-inline
-size_t WriteArray(IOStream * stream, const T* in, unsigned int size) {
-    size_t n = 0;
-    for (unsigned int i=0; i<size; i++) n += Write<T>(stream,in[i]);
-
-    return n;
-}
-
-// ----------------------------------------------------------------------------------
-/** @class  AssbinChunkWriter
- *  @brief  Chunk writer mechanism for the .assbin file structure
- *
- *  This is a standard in-memory IOStream (most of the code is based on BlobIOStream),
- *  the difference being that this takes another IOStream as a "container" in the
- *  constructor, and when it is destroyed, it appends the magic number, the chunk size,
- *  and the chunk contents to the container stream. This allows relatively easy chunk
- *  chunk construction, even recursively.
- */
-class AssbinChunkWriter : public IOStream
-{
-private:
-
-    uint8_t* buffer;
-    uint32_t magic;
-    IOStream * container;
-    size_t cur_size, cursor, initial;
-
-private:
-    // -------------------------------------------------------------------
-    void Grow(size_t need = 0)
-    {
-        size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
-
-        const uint8_t* const old = buffer;
-        buffer = new uint8_t[new_size];
-
-        if (old) {
-            memcpy(buffer,old,cur_size);
-            delete[] old;
-        }
-
-        cur_size = new_size;
-    }
-
-public:
-
-    AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096)
-        : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial)
-    {
-    }
-
-    virtual ~AssbinChunkWriter()
-    {
-        if (container) {
-            container->Write( &magic, sizeof(uint32_t), 1 );
-            container->Write( &cursor, sizeof(uint32_t), 1 );
-            container->Write( buffer, 1, cursor );
-        }
-        if (buffer) delete[] buffer;
-    }
-
-    void * GetBufferPointer() { return buffer; }
-
-    // -------------------------------------------------------------------
-    virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
-        return 0;
-    }
-    virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
-        return aiReturn_FAILURE;
-    }
-    virtual size_t Tell() const {
-        return cursor;
-    }
-    virtual void Flush() {
-        // not implemented
-    }
-
-    virtual size_t FileSize() const {
-        return cursor;
-    }
-
-    // -------------------------------------------------------------------
-    virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) {
-        pSize *= pCount;
-        if (cursor + pSize > cur_size) {
-            Grow(cursor + pSize);
-        }
-
-        memcpy(buffer+cursor, pvBuffer, pSize);
-        cursor += pSize;
-
-        return pCount;
-    }
-
-};
-
-// ----------------------------------------------------------------------------------
-/** @class  AssbinExport
- *  @brief  Assbin exporter class
- *
- *  This class performs the .assbin exporting, and is responsible for the file layout.
- */
-class AssbinExport
-{
-private:
-    bool shortened;
-    bool compressed;
-
-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);
-
-        Write<aiString>(&chunk,node->mName);
-        Write<aiMatrix4x4>(&chunk,node->mTransformation);
-        Write<unsigned int>(&chunk,node->mNumChildren);
-        Write<unsigned int>(&chunk,node->mNumMeshes);
-        Write<unsigned int>(&chunk,nb_metadata);
-
-        for (unsigned int i = 0; i < node->mNumMeshes;++i) {
-            Write<unsigned int>(&chunk,node->mMeshes[i]);
-        }
-
-        for (unsigned int i = 0; i < node->mNumChildren;++i) {
-            WriteBinaryNode( &chunk, node->mChildren[i] );
-        }
-
-        for (unsigned int i = 0; i < nb_metadata; ++i) {
-            const aiString& key = node->mMetaData->mKeys[i];
-            aiMetadataType type = node->mMetaData->mValues[i].mType;
-            void* value = node->mMetaData->mValues[i].mData;
-
-            Write<aiString>(&chunk, key);
-            Write<uint16_t>(&chunk, 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;
-#ifdef SWIG
-                case FORCE_32BIT:
-#endif // SWIG
-                default:
-                    break;
-            }
-        }
-    }
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryTexture(IOStream * container, const aiTexture* tex)
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE );
-
-        Write<unsigned int>(&chunk,tex->mWidth);
-        Write<unsigned int>(&chunk,tex->mHeight);
-        chunk.Write( tex->achFormatHint, sizeof(char), 4 );
-
-        if(!shortened) {
-            if (!tex->mHeight) {
-                chunk.Write(tex->pcData,1,tex->mWidth);
-            }
-            else {
-                chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4);
-            }
-        }
-
-    }
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryBone(IOStream * container, const aiBone* b)
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE );
-
-        Write<aiString>(&chunk,b->mName);
-        Write<unsigned int>(&chunk,b->mNumWeights);
-        Write<aiMatrix4x4>(&chunk,b->mOffsetMatrix);
-
-        // for the moment we write dumb min/max values for the bones, too.
-        // maybe I'll add a better, hash-like solution later
-        if (shortened) {
-            WriteBounds(&chunk,b->mWeights,b->mNumWeights);
-        } // else write as usual
-        else WriteArray<aiVertexWeight>(&chunk,b->mWeights,b->mNumWeights);
-    }
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryMesh(IOStream * container, const aiMesh* mesh)
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH );
-
-        Write<unsigned int>(&chunk,mesh->mPrimitiveTypes);
-        Write<unsigned int>(&chunk,mesh->mNumVertices);
-        Write<unsigned int>(&chunk,mesh->mNumFaces);
-        Write<unsigned int>(&chunk,mesh->mNumBones);
-        Write<unsigned int>(&chunk,mesh->mMaterialIndex);
-
-        // first of all, write bits for all existent vertex components
-        unsigned int c = 0;
-        if (mesh->mVertices) {
-            c |= ASSBIN_MESH_HAS_POSITIONS;
-        }
-        if (mesh->mNormals) {
-            c |= ASSBIN_MESH_HAS_NORMALS;
-        }
-        if (mesh->mTangents && mesh->mBitangents) {
-            c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS;
-        }
-        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
-            if (!mesh->mTextureCoords[n]) {
-                break;
-            }
-            c |= ASSBIN_MESH_HAS_TEXCOORD(n);
-        }
-        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
-            if (!mesh->mColors[n]) {
-                break;
-            }
-            c |= ASSBIN_MESH_HAS_COLOR(n);
-        }
-        Write<unsigned int>(&chunk,c);
-
-        aiVector3D minVec, maxVec;
-        if (mesh->mVertices) {
-            if (shortened) {
-                WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices);
-            } // else write as usual
-            else WriteArray<aiVector3D>(&chunk,mesh->mVertices,mesh->mNumVertices);
-        }
-        if (mesh->mNormals) {
-            if (shortened) {
-                WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices);
-            } // else write as usual
-            else WriteArray<aiVector3D>(&chunk,mesh->mNormals,mesh->mNumVertices);
-        }
-        if (mesh->mTangents && mesh->mBitangents) {
-            if (shortened) {
-                WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices);
-                WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices);
-            } // else write as usual
-            else {
-                WriteArray<aiVector3D>(&chunk,mesh->mTangents,mesh->mNumVertices);
-                WriteArray<aiVector3D>(&chunk,mesh->mBitangents,mesh->mNumVertices);
-            }
-        }
-        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
-            if (!mesh->mColors[n])
-                break;
-
-            if (shortened) {
-                WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices);
-            } // else write as usual
-            else WriteArray<aiColor4D>(&chunk,mesh->mColors[n],mesh->mNumVertices);
-        }
-        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
-            if (!mesh->mTextureCoords[n])
-                break;
-
-            // write number of UV components
-            Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
-
-            if (shortened) {
-                WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
-            } // else write as usual
-            else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
-        }
-
-        // write faces. There are no floating-point calculations involved
-        // in these, so we can write a simple hash over the face data
-        // to the dump file. We generate a single 32 Bit hash for 512 faces
-        // using Assimp's standard hashing function.
-        if (shortened) {
-            unsigned int processed = 0;
-            for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) {
-
-                uint32_t hash = 0;
-                for (unsigned int a = 0; a < job;++a) {
-
-                    const aiFace& f = mesh->mFaces[processed+a];
-                    uint32_t tmp = f.mNumIndices;
-                    hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
-                    for (unsigned int i = 0; i < f.mNumIndices; ++i) {
-                        static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff");
-                        tmp = static_cast<uint32_t>( f.mIndices[i] );
-                        hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
-                    }
-                }
-                Write<unsigned int>(&chunk,hash);
-            }
-        }
-        else // else write as usual
-        {
-            // if there are less than 2^16 vertices, we can simply use 16 bit integers ...
-            for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
-                const aiFace& f = mesh->mFaces[i];
-
-                static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
-                Write<uint16_t>(&chunk,f.mNumIndices);
-
-                for (unsigned int a = 0; a < f.mNumIndices;++a) {
-                    if (mesh->mNumVertices < (1u<<16)) {
-                        Write<uint16_t>(&chunk,f.mIndices[a]);
-                    }
-                    else Write<unsigned int>(&chunk,f.mIndices[a]);
-                }
-            }
-        }
-
-        // write bones
-        if (mesh->mNumBones) {
-            for (unsigned int a = 0; a < mesh->mNumBones;++a) {
-                const aiBone* b = mesh->mBones[a];
-                WriteBinaryBone(&chunk,b);
-            }
-        }
-    }
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop)
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY );
-
-        Write<aiString>(&chunk,prop->mKey);
-        Write<unsigned int>(&chunk,prop->mSemantic);
-        Write<unsigned int>(&chunk,prop->mIndex);
-
-        Write<unsigned int>(&chunk,prop->mDataLength);
-        Write<unsigned int>(&chunk,(unsigned int)prop->mType);
-        chunk.Write(prop->mData,1,prop->mDataLength);
-    }
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat)
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL);
-
-        Write<unsigned int>(&chunk,mat->mNumProperties);
-        for (unsigned int i = 0; i < mat->mNumProperties;++i) {
-            WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]);
-        }
-    }
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd)
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM );
-
-        Write<aiString>(&chunk,nd->mNodeName);
-        Write<unsigned int>(&chunk,nd->mNumPositionKeys);
-        Write<unsigned int>(&chunk,nd->mNumRotationKeys);
-        Write<unsigned int>(&chunk,nd->mNumScalingKeys);
-        Write<unsigned int>(&chunk,nd->mPreState);
-        Write<unsigned int>(&chunk,nd->mPostState);
-
-        if (nd->mPositionKeys) {
-            if (shortened) {
-                WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
-
-            } // else write as usual
-            else WriteArray<aiVectorKey>(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
-        }
-        if (nd->mRotationKeys) {
-            if (shortened) {
-                WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
-
-            } // else write as usual
-            else WriteArray<aiQuatKey>(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
-        }
-        if (nd->mScalingKeys) {
-            if (shortened) {
-                WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
-
-            } // else write as usual
-            else WriteArray<aiVectorKey>(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
-        }
-    }
-
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryAnim( IOStream * container, const aiAnimation* anim )
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION );
-
-        Write<aiString>(&chunk,anim->mName);
-        Write<double>(&chunk,anim->mDuration);
-        Write<double>(&chunk,anim->mTicksPerSecond);
-        Write<unsigned int>(&chunk,anim->mNumChannels);
-
-        for (unsigned int a = 0; a < anim->mNumChannels;++a) {
-            const aiNodeAnim* nd = anim->mChannels[a];
-            WriteBinaryNodeAnim(&chunk,nd);
-        }
-    }
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryLight( IOStream * container, const aiLight* l )
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT );
-
-        Write<aiString>(&chunk,l->mName);
-        Write<unsigned int>(&chunk,l->mType);
-
-        if (l->mType != aiLightSource_DIRECTIONAL) {
-            Write<float>(&chunk,l->mAttenuationConstant);
-            Write<float>(&chunk,l->mAttenuationLinear);
-            Write<float>(&chunk,l->mAttenuationQuadratic);
-        }
-
-        Write<aiColor3D>(&chunk,l->mColorDiffuse);
-        Write<aiColor3D>(&chunk,l->mColorSpecular);
-        Write<aiColor3D>(&chunk,l->mColorAmbient);
-
-        if (l->mType == aiLightSource_SPOT) {
-            Write<float>(&chunk,l->mAngleInnerCone);
-            Write<float>(&chunk,l->mAngleOuterCone);
-        }
-
-    }
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
-
-        Write<aiString>(&chunk,cam->mName);
-        Write<aiVector3D>(&chunk,cam->mPosition);
-        Write<aiVector3D>(&chunk,cam->mLookAt);
-        Write<aiVector3D>(&chunk,cam->mUp);
-        Write<float>(&chunk,cam->mHorizontalFOV);
-        Write<float>(&chunk,cam->mClipPlaneNear);
-        Write<float>(&chunk,cam->mClipPlaneFar);
-        Write<float>(&chunk,cam->mAspect);
-    }
-
-    // -----------------------------------------------------------------------------------
-    void WriteBinaryScene( IOStream * container, const aiScene* scene)
-    {
-        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE );
-
-        // basic scene information
-        Write<unsigned int>(&chunk,scene->mFlags);
-        Write<unsigned int>(&chunk,scene->mNumMeshes);
-        Write<unsigned int>(&chunk,scene->mNumMaterials);
-        Write<unsigned int>(&chunk,scene->mNumAnimations);
-        Write<unsigned int>(&chunk,scene->mNumTextures);
-        Write<unsigned int>(&chunk,scene->mNumLights);
-        Write<unsigned int>(&chunk,scene->mNumCameras);
-
-        // write node graph
-        WriteBinaryNode( &chunk, scene->mRootNode );
-
-        // write all meshes
-        for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
-            const aiMesh* mesh = scene->mMeshes[i];
-            WriteBinaryMesh( &chunk,mesh);
-        }
-
-        // write materials
-        for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
-            const aiMaterial* mat = scene->mMaterials[i];
-            WriteBinaryMaterial(&chunk,mat);
-        }
-
-        // write all animations
-        for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
-            const aiAnimation* anim = scene->mAnimations[i];
-            WriteBinaryAnim(&chunk,anim);
-        }
-
-
-        // write all textures
-        for (unsigned int i = 0; i < scene->mNumTextures;++i) {
-            const aiTexture* mesh = scene->mTextures[i];
-            WriteBinaryTexture(&chunk,mesh);
-        }
-
-        // write lights
-        for (unsigned int i = 0; i < scene->mNumLights;++i) {
-            const aiLight* l = scene->mLights[i];
-            WriteBinaryLight(&chunk,l);
-        }
-
-        // write cameras
-        for (unsigned int i = 0; i < scene->mNumCameras;++i) {
-            const aiCamera* cam = scene->mCameras[i];
-            WriteBinaryCamera(&chunk,cam);
-        }
-
-    }
-
-public:
-    AssbinExport()
-        : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters
-    {
-    }
-
-    // -----------------------------------------------------------------------------------
-    // Write a binary model dump
-    void WriteBinaryDump(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene)
-    {
-        IOStream * out = pIOSystem->Open( pFile, "wb" );
-        if (!out) return;
-
-        time_t tt = time(NULL);
-#if _WIN32
-        tm* p     = gmtime(&tt);
-#else
-        struct tm now;
-        tm* p = gmtime_r(&tt, &now);
-#endif
-
-        // header
-        char s[64];
-        memset( s, 0, 64 );
-#if _MSC_VER >= 1400
-        sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p));
-#else
-        ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p));
-#endif
-        out->Write( s, 44, 1 );
-        // == 44 bytes
-
-        Write<unsigned int>( out, ASSBIN_VERSION_MAJOR );
-        Write<unsigned int>( out, ASSBIN_VERSION_MINOR );
-        Write<unsigned int>( out, aiGetVersionRevision() );
-        Write<unsigned int>( out, aiGetCompileFlags() );
-        Write<uint16_t>( out, shortened );
-        Write<uint16_t>( out, compressed );
-        // ==  20 bytes
-
-        char buff[256];
-        strncpy(buff,pFile,256);
-        out->Write(buff,sizeof(char),256);
-
-        char cmd[] = "\0";
-        strncpy(buff,cmd,128);
-        out->Write(buff,sizeof(char),128);
-
-        // leave 64 bytes free for future extensions
-        memset(buff,0xcd,64);
-        out->Write(buff,sizeof(char),64);
-        // == 435 bytes
-
-        // ==== total header size: 512 bytes
-        ai_assert( out->Tell() == ASSBIN_HEADER_LENGTH );
-
-        // 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 );
-            WriteBinaryScene( &uncompressedStream, pScene );
-
-            uLongf uncompressedSize = static_cast<uLongf>(uncompressedStream.Tell());
-            uLongf compressedSize = (uLongf)compressBound(uncompressedSize);
-            uint8_t* compressedBuffer = new uint8_t[ compressedSize ];
-
-            int res = compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 );
-            if(res != Z_OK)
-            {
-                delete [] compressedBuffer;
-                pIOSystem->Close(out);
-                throw DeadlyExportError("Compression failed.");
-            }
-
-            out->Write( &uncompressedSize, sizeof(uint32_t), 1 );
-            out->Write( compressedBuffer, sizeof(char), compressedSize );
-
-            delete[] compressedBuffer;
-        }
-        else
-        {
-            WriteBinaryScene( out, pScene );
-        }
-
-        pIOSystem->Close( out );
-    }
-};
-
 void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) {
 void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) {
-    AssbinExport exporter;
-    exporter.WriteBinaryDump( pFile, pIOSystem, pScene );
+    DumpSceneToAssbin(
+        pFile,
+        "\0", // no command(s).
+        pIOSystem,
+        pScene,
+        false, // shortened?
+        false); // compressed?
 }
 }
 } // end of namespace Assimp
 } // end of namespace Assimp
 
 

+ 1 - 1
code/Assbin/AssbinExporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 858 - 0
code/Assbin/AssbinFileWriter.cpp

@@ -0,0 +1,858 @@
+/*
+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  AssbinFileWriter.cpp
+ *  @brief Implementation of Assbin file writer.
+ */
+
+#include "AssbinFileWriter.h"
+
+#include "Common/assbin_chunks.h"
+#include "PostProcessing/ProcessHelper.h"
+
+#include <assimp/version.h>
+#include <assimp/IOStream.hpp>
+#include <assimp/Exporter.hpp>
+#include <assimp/Exceptional.h>
+
+#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#   include <zlib.h>
+#else
+#   include "../contrib/zlib/zlib.h"
+#endif
+
+#include <time.h>
+
+namespace Assimp {
+
+template <typename T>
+size_t Write(IOStream * stream, const T& v) {
+    return stream->Write( &v, sizeof(T), 1 );
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize an aiString
+template <>
+inline
+size_t Write<aiString>(IOStream * stream, const aiString& s) {
+    const size_t s2 = (uint32_t)s.length;
+    stream->Write(&s,4,1);
+    stream->Write(s.data,s2,1);
+
+    return s2+4;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize an unsigned int as uint32_t
+template <>
+inline
+size_t Write<unsigned int>(IOStream * stream, const unsigned int& w) {
+    const uint32_t t = (uint32_t)w;
+    if (w > t) {
+        // this shouldn't happen, integers in Assimp data structures never exceed 2^32
+        throw DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
+    }
+
+    stream->Write(&t,4,1);
+
+    return 4;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize an unsigned int as uint16_t
+template <>
+inline
+size_t Write<uint16_t>(IOStream * stream, const uint16_t& w) {
+    static_assert(sizeof(uint16_t)==2, "sizeof(uint16_t)==2");
+    stream->Write(&w,2,1);
+
+    return 2;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a float
+template <>
+inline
+size_t Write<float>(IOStream * stream, const float& f) {
+    static_assert(sizeof(float)==4, "sizeof(float)==4");
+    stream->Write(&f,4,1);
+
+    return 4;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a double
+template <>
+inline
+size_t Write<double>(IOStream * stream, const double& f) {
+    static_assert(sizeof(double)==8, "sizeof(double)==8");
+    stream->Write(&f,8,1);
+
+    return 8;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a vec3
+template <>
+inline
+size_t Write<aiVector3D>(IOStream * stream, const aiVector3D& v) {
+    size_t t = Write<float>(stream,v.x);
+    t += Write<float>(stream,v.y);
+    t += Write<float>(stream,v.z);
+
+    return t;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a color value
+template <>
+inline
+size_t Write<aiColor3D>(IOStream * stream, const aiColor3D& v) {
+    size_t t = Write<float>(stream,v.r);
+    t += Write<float>(stream,v.g);
+    t += Write<float>(stream,v.b);
+
+    return t;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a color value
+template <>
+inline
+size_t Write<aiColor4D>(IOStream * stream, const aiColor4D& v) {
+    size_t t = Write<float>(stream,v.r);
+    t += Write<float>(stream,v.g);
+    t += Write<float>(stream,v.b);
+    t += Write<float>(stream,v.a);
+
+    return t;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a quaternion
+template <>
+inline
+size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v) {
+    size_t t = Write<float>(stream,v.w);
+    t += Write<float>(stream,v.x);
+    t += Write<float>(stream,v.y);
+    t += Write<float>(stream,v.z);
+    ai_assert(t == 16);
+
+    return 16;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a vertex weight
+template <>
+inline
+size_t Write<aiVertexWeight>(IOStream * stream, const aiVertexWeight& v) {
+    size_t t = Write<unsigned int>(stream,v.mVertexId);
+
+    return t+Write<float>(stream,v.mWeight);
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize a mat4x4
+template <>
+inline
+size_t Write<aiMatrix4x4>(IOStream * stream, const aiMatrix4x4& m) {
+    for (unsigned int i = 0; i < 4;++i) {
+        for (unsigned int i2 = 0; i2 < 4;++i2) {
+            Write<float>(stream,m[i][i2]);
+        }
+    }
+
+    return 64;
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize an aiVectorKey
+template <>
+inline
+size_t Write<aiVectorKey>(IOStream * stream, const aiVectorKey& v) {
+    const size_t t = Write<double>(stream,v.mTime);
+    return t + Write<aiVector3D>(stream,v.mValue);
+}
+
+// -----------------------------------------------------------------------------------
+// Serialize an aiQuatKey
+template <>
+inline
+size_t Write<aiQuatKey>(IOStream * stream, const aiQuatKey& v) {
+    const size_t t = Write<double>(stream,v.mTime);
+    return t + Write<aiQuaternion>(stream,v.mValue);
+}
+
+template <typename T>
+inline
+size_t WriteBounds(IOStream * stream, const T* in, unsigned int size) {
+    T minc, maxc;
+    ArrayBounds(in,size,minc,maxc);
+
+    const size_t t = Write<T>(stream,minc);
+    return t + Write<T>(stream,maxc);
+}
+
+// We use this to write out non-byte arrays so that we write using the specializations.
+// This way we avoid writing out extra bytes that potentially come from struct alignment.
+template <typename T>
+inline
+size_t WriteArray(IOStream * stream, const T* in, unsigned int size) {
+    size_t n = 0;
+    for (unsigned int i=0; i<size; i++) n += Write<T>(stream,in[i]);
+
+    return n;
+}
+
+// ----------------------------------------------------------------------------------
+/** @class  AssbinChunkWriter
+ *  @brief  Chunk writer mechanism for the .assbin file structure
+ *
+ *  This is a standard in-memory IOStream (most of the code is based on BlobIOStream),
+ *  the difference being that this takes another IOStream as a "container" in the
+ *  constructor, and when it is destroyed, it appends the magic number, the chunk size,
+ *  and the chunk contents to the container stream. This allows relatively easy chunk
+ *  chunk construction, even recursively.
+ */
+class AssbinChunkWriter : public IOStream
+{
+private:
+
+    uint8_t* buffer;
+    uint32_t magic;
+    IOStream * container;
+    size_t cur_size, cursor, initial;
+
+private:
+    // -------------------------------------------------------------------
+    void Grow(size_t need = 0)
+    {
+        size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
+
+        const uint8_t* const old = buffer;
+        buffer = new uint8_t[new_size];
+
+        if (old) {
+            memcpy(buffer,old,cur_size);
+            delete[] old;
+        }
+
+        cur_size = new_size;
+    }
+
+public:
+
+    AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096)
+        : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial)
+    {
+    }
+
+    virtual ~AssbinChunkWriter()
+    {
+        if (container) {
+            container->Write( &magic, sizeof(uint32_t), 1 );
+            container->Write( &cursor, sizeof(uint32_t), 1 );
+            container->Write( buffer, 1, cursor );
+        }
+        if (buffer) delete[] buffer;
+    }
+
+    void * GetBufferPointer() { return buffer; }
+
+    // -------------------------------------------------------------------
+    virtual size_t Read(void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
+        return 0;
+    }
+    virtual aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
+        return aiReturn_FAILURE;
+    }
+    virtual size_t Tell() const {
+        return cursor;
+    }
+    virtual void Flush() {
+        // not implemented
+    }
+
+    virtual size_t FileSize() const {
+        return cursor;
+    }
+
+    // -------------------------------------------------------------------
+    virtual size_t Write(const void* pvBuffer, size_t pSize, size_t pCount) {
+        pSize *= pCount;
+        if (cursor + pSize > cur_size) {
+            Grow(cursor + pSize);
+        }
+
+        memcpy(buffer+cursor, pvBuffer, pSize);
+        cursor += pSize;
+
+        return pCount;
+    }
+
+};
+
+// ----------------------------------------------------------------------------------
+/** @class  AssbinFileWriter
+ *  @brief  Assbin file writer class
+ *
+ *  This class writes an .assbin file, and is responsible for the file layout.
+ */
+class AssbinFileWriter
+{
+private:
+    bool shortened;
+    bool compressed;
+
+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);
+
+        Write<aiString>(&chunk,node->mName);
+        Write<aiMatrix4x4>(&chunk,node->mTransformation);
+        Write<unsigned int>(&chunk,node->mNumChildren);
+        Write<unsigned int>(&chunk,node->mNumMeshes);
+        Write<unsigned int>(&chunk,nb_metadata);
+
+        for (unsigned int i = 0; i < node->mNumMeshes;++i) {
+            Write<unsigned int>(&chunk,node->mMeshes[i]);
+        }
+
+        for (unsigned int i = 0; i < node->mNumChildren;++i) {
+            WriteBinaryNode( &chunk, node->mChildren[i] );
+        }
+
+        for (unsigned int i = 0; i < nb_metadata; ++i) {
+            const aiString& key = node->mMetaData->mKeys[i];
+            aiMetadataType type = node->mMetaData->mValues[i].mType;
+            void* value = node->mMetaData->mValues[i].mData;
+
+            Write<aiString>(&chunk, key);
+            Write<uint16_t>(&chunk, 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;
+#ifdef SWIG
+                case FORCE_32BIT:
+#endif // SWIG
+                default:
+                    break;
+            }
+        }
+    }
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryTexture(IOStream * container, const aiTexture* tex)
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE );
+
+        Write<unsigned int>(&chunk,tex->mWidth);
+        Write<unsigned int>(&chunk,tex->mHeight);
+        // Write the texture format, but don't include the null terminator.
+        chunk.Write( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 );
+
+        if(!shortened) {
+            if (!tex->mHeight) {
+                chunk.Write(tex->pcData,1,tex->mWidth);
+            }
+            else {
+                chunk.Write(tex->pcData,1,tex->mWidth*tex->mHeight*4);
+            }
+        }
+
+    }
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryBone(IOStream * container, const aiBone* b)
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIBONE );
+
+        Write<aiString>(&chunk,b->mName);
+        Write<unsigned int>(&chunk,b->mNumWeights);
+        Write<aiMatrix4x4>(&chunk,b->mOffsetMatrix);
+
+        // for the moment we write dumb min/max values for the bones, too.
+        // maybe I'll add a better, hash-like solution later
+        if (shortened) {
+            WriteBounds(&chunk,b->mWeights,b->mNumWeights);
+        } // else write as usual
+        else WriteArray<aiVertexWeight>(&chunk,b->mWeights,b->mNumWeights);
+    }
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryMesh(IOStream * container, const aiMesh* mesh)
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMESH );
+
+        Write<unsigned int>(&chunk,mesh->mPrimitiveTypes);
+        Write<unsigned int>(&chunk,mesh->mNumVertices);
+        Write<unsigned int>(&chunk,mesh->mNumFaces);
+        Write<unsigned int>(&chunk,mesh->mNumBones);
+        Write<unsigned int>(&chunk,mesh->mMaterialIndex);
+
+        // first of all, write bits for all existent vertex components
+        unsigned int c = 0;
+        if (mesh->mVertices) {
+            c |= ASSBIN_MESH_HAS_POSITIONS;
+        }
+        if (mesh->mNormals) {
+            c |= ASSBIN_MESH_HAS_NORMALS;
+        }
+        if (mesh->mTangents && mesh->mBitangents) {
+            c |= ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS;
+        }
+        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
+            if (!mesh->mTextureCoords[n]) {
+                break;
+            }
+            c |= ASSBIN_MESH_HAS_TEXCOORD(n);
+        }
+        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+            if (!mesh->mColors[n]) {
+                break;
+            }
+            c |= ASSBIN_MESH_HAS_COLOR(n);
+        }
+        Write<unsigned int>(&chunk,c);
+
+        aiVector3D minVec, maxVec;
+        if (mesh->mVertices) {
+            if (shortened) {
+                WriteBounds(&chunk,mesh->mVertices,mesh->mNumVertices);
+            } // else write as usual
+            else WriteArray<aiVector3D>(&chunk,mesh->mVertices,mesh->mNumVertices);
+        }
+        if (mesh->mNormals) {
+            if (shortened) {
+                WriteBounds(&chunk,mesh->mNormals,mesh->mNumVertices);
+            } // else write as usual
+            else WriteArray<aiVector3D>(&chunk,mesh->mNormals,mesh->mNumVertices);
+        }
+        if (mesh->mTangents && mesh->mBitangents) {
+            if (shortened) {
+                WriteBounds(&chunk,mesh->mTangents,mesh->mNumVertices);
+                WriteBounds(&chunk,mesh->mBitangents,mesh->mNumVertices);
+            } // else write as usual
+            else {
+                WriteArray<aiVector3D>(&chunk,mesh->mTangents,mesh->mNumVertices);
+                WriteArray<aiVector3D>(&chunk,mesh->mBitangents,mesh->mNumVertices);
+            }
+        }
+        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+            if (!mesh->mColors[n])
+                break;
+
+            if (shortened) {
+                WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices);
+            } // else write as usual
+            else WriteArray<aiColor4D>(&chunk,mesh->mColors[n],mesh->mNumVertices);
+        }
+        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
+            if (!mesh->mTextureCoords[n])
+                break;
+
+            // write number of UV components
+            Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
+
+            if (shortened) {
+                WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
+            } // else write as usual
+            else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
+        }
+
+        // write faces. There are no floating-point calculations involved
+        // in these, so we can write a simple hash over the face data
+        // to the dump file. We generate a single 32 Bit hash for 512 faces
+        // using Assimp's standard hashing function.
+        if (shortened) {
+            unsigned int processed = 0;
+            for (unsigned int job;(job = std::min(mesh->mNumFaces-processed,512u));processed += job) {
+
+                uint32_t hash = 0;
+                for (unsigned int a = 0; a < job;++a) {
+
+                    const aiFace& f = mesh->mFaces[processed+a];
+                    uint32_t tmp = f.mNumIndices;
+                    hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
+                    for (unsigned int i = 0; i < f.mNumIndices; ++i) {
+                        static_assert(AI_MAX_VERTICES <= 0xffffffff, "AI_MAX_VERTICES <= 0xffffffff");
+                        tmp = static_cast<uint32_t>( f.mIndices[i] );
+                        hash = SuperFastHash(reinterpret_cast<const char*>(&tmp),sizeof tmp,hash);
+                    }
+                }
+                Write<unsigned int>(&chunk,hash);
+            }
+        }
+        else // else write as usual
+        {
+            // if there are less than 2^16 vertices, we can simply use 16 bit integers ...
+            for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
+                const aiFace& f = mesh->mFaces[i];
+
+                static_assert(AI_MAX_FACE_INDICES <= 0xffff, "AI_MAX_FACE_INDICES <= 0xffff");
+                Write<uint16_t>(&chunk,f.mNumIndices);
+
+                for (unsigned int a = 0; a < f.mNumIndices;++a) {
+                    if (mesh->mNumVertices < (1u<<16)) {
+                        Write<uint16_t>(&chunk,f.mIndices[a]);
+                    }
+                    else Write<unsigned int>(&chunk,f.mIndices[a]);
+                }
+            }
+        }
+
+        // write bones
+        if (mesh->mNumBones) {
+            for (unsigned int a = 0; a < mesh->mNumBones;++a) {
+                const aiBone* b = mesh->mBones[a];
+                WriteBinaryBone(&chunk,b);
+            }
+        }
+    }
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryMaterialProperty(IOStream * container, const aiMaterialProperty* prop)
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIALPROPERTY );
+
+        Write<aiString>(&chunk,prop->mKey);
+        Write<unsigned int>(&chunk,prop->mSemantic);
+        Write<unsigned int>(&chunk,prop->mIndex);
+
+        Write<unsigned int>(&chunk,prop->mDataLength);
+        Write<unsigned int>(&chunk,(unsigned int)prop->mType);
+        chunk.Write(prop->mData,1,prop->mDataLength);
+    }
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryMaterial(IOStream * container, const aiMaterial* mat)
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIMATERIAL);
+
+        Write<unsigned int>(&chunk,mat->mNumProperties);
+        for (unsigned int i = 0; i < mat->mNumProperties;++i) {
+            WriteBinaryMaterialProperty( &chunk, mat->mProperties[i]);
+        }
+    }
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryNodeAnim(IOStream * container, const aiNodeAnim* nd)
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODEANIM );
+
+        Write<aiString>(&chunk,nd->mNodeName);
+        Write<unsigned int>(&chunk,nd->mNumPositionKeys);
+        Write<unsigned int>(&chunk,nd->mNumRotationKeys);
+        Write<unsigned int>(&chunk,nd->mNumScalingKeys);
+        Write<unsigned int>(&chunk,nd->mPreState);
+        Write<unsigned int>(&chunk,nd->mPostState);
+
+        if (nd->mPositionKeys) {
+            if (shortened) {
+                WriteBounds(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
+
+            } // else write as usual
+            else WriteArray<aiVectorKey>(&chunk,nd->mPositionKeys,nd->mNumPositionKeys);
+        }
+        if (nd->mRotationKeys) {
+            if (shortened) {
+                WriteBounds(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
+
+            } // else write as usual
+            else WriteArray<aiQuatKey>(&chunk,nd->mRotationKeys,nd->mNumRotationKeys);
+        }
+        if (nd->mScalingKeys) {
+            if (shortened) {
+                WriteBounds(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
+
+            } // else write as usual
+            else WriteArray<aiVectorKey>(&chunk,nd->mScalingKeys,nd->mNumScalingKeys);
+        }
+    }
+
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryAnim( IOStream * container, const aiAnimation* anim )
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AIANIMATION );
+
+        Write<aiString>(&chunk,anim->mName);
+        Write<double>(&chunk,anim->mDuration);
+        Write<double>(&chunk,anim->mTicksPerSecond);
+        Write<unsigned int>(&chunk,anim->mNumChannels);
+
+        for (unsigned int a = 0; a < anim->mNumChannels;++a) {
+            const aiNodeAnim* nd = anim->mChannels[a];
+            WriteBinaryNodeAnim(&chunk,nd);
+        }
+    }
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryLight( IOStream * container, const aiLight* l )
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT );
+
+        Write<aiString>(&chunk,l->mName);
+        Write<unsigned int>(&chunk,l->mType);
+
+        if (l->mType != aiLightSource_DIRECTIONAL) {
+            Write<float>(&chunk,l->mAttenuationConstant);
+            Write<float>(&chunk,l->mAttenuationLinear);
+            Write<float>(&chunk,l->mAttenuationQuadratic);
+        }
+
+        Write<aiColor3D>(&chunk,l->mColorDiffuse);
+        Write<aiColor3D>(&chunk,l->mColorSpecular);
+        Write<aiColor3D>(&chunk,l->mColorAmbient);
+
+        if (l->mType == aiLightSource_SPOT) {
+            Write<float>(&chunk,l->mAngleInnerCone);
+            Write<float>(&chunk,l->mAngleOuterCone);
+        }
+
+    }
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
+
+        Write<aiString>(&chunk,cam->mName);
+        Write<aiVector3D>(&chunk,cam->mPosition);
+        Write<aiVector3D>(&chunk,cam->mLookAt);
+        Write<aiVector3D>(&chunk,cam->mUp);
+        Write<float>(&chunk,cam->mHorizontalFOV);
+        Write<float>(&chunk,cam->mClipPlaneNear);
+        Write<float>(&chunk,cam->mClipPlaneFar);
+        Write<float>(&chunk,cam->mAspect);
+    }
+
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryScene( IOStream * container, const aiScene* scene)
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AISCENE );
+
+        // basic scene information
+        Write<unsigned int>(&chunk,scene->mFlags);
+        Write<unsigned int>(&chunk,scene->mNumMeshes);
+        Write<unsigned int>(&chunk,scene->mNumMaterials);
+        Write<unsigned int>(&chunk,scene->mNumAnimations);
+        Write<unsigned int>(&chunk,scene->mNumTextures);
+        Write<unsigned int>(&chunk,scene->mNumLights);
+        Write<unsigned int>(&chunk,scene->mNumCameras);
+
+        // write node graph
+        WriteBinaryNode( &chunk, scene->mRootNode );
+
+        // write all meshes
+        for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
+            const aiMesh* mesh = scene->mMeshes[i];
+            WriteBinaryMesh( &chunk,mesh);
+        }
+
+        // write materials
+        for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
+            const aiMaterial* mat = scene->mMaterials[i];
+            WriteBinaryMaterial(&chunk,mat);
+        }
+
+        // write all animations
+        for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
+            const aiAnimation* anim = scene->mAnimations[i];
+            WriteBinaryAnim(&chunk,anim);
+        }
+
+
+        // write all textures
+        for (unsigned int i = 0; i < scene->mNumTextures;++i) {
+            const aiTexture* mesh = scene->mTextures[i];
+            WriteBinaryTexture(&chunk,mesh);
+        }
+
+        // write lights
+        for (unsigned int i = 0; i < scene->mNumLights;++i) {
+            const aiLight* l = scene->mLights[i];
+            WriteBinaryLight(&chunk,l);
+        }
+
+        // write cameras
+        for (unsigned int i = 0; i < scene->mNumCameras;++i) {
+            const aiCamera* cam = scene->mCameras[i];
+            WriteBinaryCamera(&chunk,cam);
+        }
+
+    }
+
+public:
+    AssbinFileWriter(bool shortened, bool compressed)
+        : shortened(shortened), compressed(compressed)
+    {
+    }
+
+    // -----------------------------------------------------------------------------------
+    // Write a binary model dump
+    void WriteBinaryDump(const char* pFile, const char* cmd, IOSystem* pIOSystem, const aiScene* pScene)
+    {
+        IOStream * out = pIOSystem->Open( pFile, "wb" );
+        if (!out)
+            throw std::runtime_error("Unable to open output file " + std::string(pFile) + '\n');
+
+        auto CloseIOStream = [&]() {
+            if (out) {
+                pIOSystem->Close(out);
+                out = nullptr; // Ensure this is only done once.
+            }
+        };
+
+        try {
+            time_t tt = time(NULL);
+#if _WIN32
+            tm* p = gmtime(&tt);
+#else
+            struct tm now;
+            tm* p = gmtime_r(&tt, &now);
+#endif
+
+            // header
+            char s[64];
+            memset(s, 0, 64);
+#if _MSC_VER >= 1400
+            sprintf_s(s, "ASSIMP.binary-dump.%s", asctime(p));
+#else
+            ai_snprintf(s, 64, "ASSIMP.binary-dump.%s", asctime(p));
+#endif
+            out->Write(s, 44, 1);
+            // == 44 bytes
+
+            Write<unsigned int>(out, ASSBIN_VERSION_MAJOR);
+            Write<unsigned int>(out, ASSBIN_VERSION_MINOR);
+            Write<unsigned int>(out, aiGetVersionRevision());
+            Write<unsigned int>(out, aiGetCompileFlags());
+            Write<uint16_t>(out, shortened);
+            Write<uint16_t>(out, compressed);
+            // ==  20 bytes
+
+            char buff[256] = {0};
+            ai_snprintf(buff, 256, "%s", pFile);
+            out->Write(buff, sizeof(char), 256);
+
+            memset(buff, 0, sizeof(buff));
+            ai_snprintf(buff, 128, "%s", cmd);
+            out->Write(buff, sizeof(char), 128);
+            
+            // leave 64 bytes free for future extensions
+            memset(buff, 0xcd, 64);
+            out->Write(buff, sizeof(char), 64);
+            // == 435 bytes
+
+            // ==== total header size: 512 bytes
+            ai_assert(out->Tell() == ASSBIN_HEADER_LENGTH);
+
+            // 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);
+                WriteBinaryScene(&uncompressedStream, pScene);
+
+                uLongf uncompressedSize = static_cast<uLongf>(uncompressedStream.Tell());
+                uLongf compressedSize = (uLongf)compressBound(uncompressedSize);
+                uint8_t* compressedBuffer = new uint8_t[compressedSize];
+
+                int res = compress2(compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9);
+                if (res != Z_OK)
+                {
+                    delete[] compressedBuffer;
+                    throw DeadlyExportError("Compression failed.");
+                }
+
+                out->Write(&uncompressedSize, sizeof(uint32_t), 1);
+                out->Write(compressedBuffer, sizeof(char), compressedSize);
+
+                delete[] compressedBuffer;
+            }
+            else
+            {
+                WriteBinaryScene(out, pScene);
+            }
+
+            CloseIOStream();
+        }
+        catch (...) {
+            CloseIOStream();
+            throw;
+        }
+    }
+};
+
+void DumpSceneToAssbin(
+    const char* pFile, const char* cmd, IOSystem* pIOSystem,
+    const aiScene* pScene, bool shortened, bool compressed) {
+    AssbinFileWriter fileWriter(shortened, compressed);
+    fileWriter.WriteBinaryDump(pFile, cmd, pIOSystem, pScene);
+}
+
+} // end of namespace Assimp

+ 66 - 0
code/Assbin/AssbinFileWriter.h

@@ -0,0 +1,66 @@
+/*
+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 AssbinFileWriter.h
+ *  @brief Declaration of Assbin file writer.
+ */
+
+#ifndef AI_ASSBINFILEWRITER_H_INC
+#define AI_ASSBINFILEWRITER_H_INC
+
+#include <assimp/defs.h>
+#include <assimp/scene.h>
+#include <assimp/IOSystem.hpp>
+
+namespace Assimp {
+
+void ASSIMP_API DumpSceneToAssbin(
+    const char* pFile,
+    const char* cmd,
+    IOSystem* pIOSystem,
+    const aiScene* pScene,
+    bool shortened,
+    bool compressed);
+
+}
+
+#endif // AI_ASSBINFILEWRITER_H_INC

+ 2 - 2
code/Assbin/AssbinLoader.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 
@@ -535,7 +535,7 @@ void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) {
 
 
     tex->mWidth = Read<unsigned int>(stream);
     tex->mWidth = Read<unsigned int>(stream);
     tex->mHeight = Read<unsigned int>(stream);
     tex->mHeight = Read<unsigned int>(stream);
-    stream->Read( tex->achFormatHint, sizeof(char), 4 );
+    stream->Read( tex->achFormatHint, sizeof(char), HINTMAXTEXTURELEN - 1 );
 
 
     if(!shortened) {
     if(!shortened) {
         if (!tex->mHeight) {
         if (!tex->mHeight) {

+ 1 - 1
code/Assbin/AssbinLoader.h

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 5 - 5
code/Assjson/cencode.c

@@ -42,7 +42,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 			{
 			{
 				state_in->result = result;
 				state_in->result = result;
 				state_in->step = step_A;
 				state_in->step = step_A;
-				return codechar - code_out;
+				return (int)(codechar - code_out);
 			}
 			}
 			fragment = *plainchar++;
 			fragment = *plainchar++;
 			result = (fragment & 0x0fc) >> 2;
 			result = (fragment & 0x0fc) >> 2;
@@ -53,7 +53,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 			{
 			{
 				state_in->result = result;
 				state_in->result = result;
 				state_in->step = step_B;
 				state_in->step = step_B;
-				return codechar - code_out;
+				return (int)(codechar - code_out);
 			}
 			}
 			fragment = *plainchar++;
 			fragment = *plainchar++;
 			result |= (fragment & 0x0f0) >> 4;
 			result |= (fragment & 0x0f0) >> 4;
@@ -64,7 +64,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 			{
 			{
 				state_in->result = result;
 				state_in->result = result;
 				state_in->step = step_C;
 				state_in->step = step_C;
-				return codechar - code_out;
+				return (int)(codechar - code_out);
 			}
 			}
 			fragment = *plainchar++;
 			fragment = *plainchar++;
 			result |= (fragment & 0x0c0) >> 6;
 			result |= (fragment & 0x0c0) >> 6;
@@ -81,7 +81,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 		}
 		}
 	}
 	}
 	/* control should not reach here */
 	/* control should not reach here */
-	return codechar - code_out;
+	return (int)(codechar - code_out);
 }
 }
 
 
 int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
@@ -104,6 +104,6 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 	}
 	}
 	*codechar++ = '\n';
 	*codechar++ = '\n';
 	
 	
-	return codechar - code_out;
+	return (int)(codechar - code_out);
 }
 }
 
 

+ 8 - 595
code/Assxml/AssxmlExporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.
@@ -46,607 +46,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
 #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
 
 
-#include "PostProcessing/ProcessHelper.h"
-
-#include <assimp/version.h>
-#include <assimp/IOStream.hpp>
+#include "AssxmlFileWriter.h"
 #include <assimp/IOSystem.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/Exporter.hpp>
 #include <assimp/Exporter.hpp>
 
 
-#include <stdarg.h>
-
-#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
-#   include <zlib.h>
-#else
-#   include <contrib/zlib/zlib.h>
-#endif
-
-#include <time.h>
-#include <stdio.h>
-
-using namespace Assimp;
-
 namespace Assimp    {
 namespace Assimp    {
 
 
-namespace AssxmlExport  {
-
-// -----------------------------------------------------------------------------------
-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=\"%i\">\n%s\t",
-            prefix,node->mNumMeshes,prefix);
-
-        for (unsigned int i = 0; i < node->mNumMeshes;++i) {
-            ioprintf(io,"%i ",node->mMeshes[i]);
-        }
-        ioprintf(io,"\n%s\t</MeshRefs>\n",prefix);
-    }
-
-    if (node->mNumChildren) {
-        ioprintf(io,"%s\t<NodeList num=\"%i\">\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 aiScene* scene, IOStream* io, bool shortened) {
-    time_t tt = ::time( NULL );
-#if _WIN32
-    tm* p = gmtime(&tt);
-#else
-    struct tm now;
-    tm* p = gmtime_r(&tt, &now);
-#endif
-    ai_assert(nullptr != p);
-
-    // 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: %i.%i.%i\n"
-        "  %s\n"
-        "-->"
-        " \n\n"
-        "<Scene flags=\"%d\" postprocessing=\"%i\">\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, curtime, scene->mFlags, 0 );
-
-    // 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=\"%i\">\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=\"%i\" height=\"%i\" compressed=\"%s\"> \n",
-                (compressed ? -1 : tex->mWidth),(compressed ? -1 : tex->mHeight),
-                (compressed ? "true" : "false"));
-
-            if (compressed) {
-                ioprintf(io,"\t\t<Data length=\"%i\"> \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=\"%i\"> \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=\"%i\">\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=\"%i\">\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=\"%i\"",
-                    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 p = 0; p < prop->mDataLength/sizeof(float);++p) {
-                        ioprintf(io,"%f ",*((float*)(prop->mData+p*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 p = 0; p < prop->mDataLength/sizeof(int);++p) {
-                        ioprintf(io,"%i ",*((int*)(prop->mData+p*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 p = 0; p < prop->mDataLength;++p) {
-                        ioprintf(io,"%2x ",prop->mData[p]);
-                        if (p && 0 == p%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=\"%i\">\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=\"%i\">\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=\"%i\">\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=\"%i\">\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=\"%i\">\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=\"%i\">\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=\"%i\">\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=\"%i\">\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=\"%i\">\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=\"%i\">\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=\"%i\">\n",mesh->mNumFaces);
-                for (unsigned int n = 0; n < mesh->mNumFaces; ++n) {
-                    aiFace& f = mesh->mFaces[n];
-                    ioprintf(io,"\t\t\t<Face num=\"%i\">\n"
-                        "\t\t\t\t",f.mNumIndices);
-
-                    for (unsigned int j = 0; j < f.mNumIndices;++j)
-                        ioprintf(io,"%i ",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=\"%i\" 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=\"%i\" 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=\"%i\" 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=\"%i\" 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=\"%i\" set=\"%i\" num_components=\"%i\"> \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=\"%i\" set=\"%i\" 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 AssxmlExport
-
 void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
 void ExportSceneAssxml(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
 {
 {
-    IOStream * out = pIOSystem->Open( pFile, "wt" );
-    if (!out) return;
-
-    bool shortened = false;
-    AssxmlExport::WriteDump( pScene, out, shortened );
-
-    pIOSystem->Close( out );
+    DumpSceneToAssxml(
+        pFile,
+        "\0", // command(s)
+        pIOSystem,
+        pScene,
+        false); // shortened?
 }
 }
 
 
 } // end of namespace Assimp
 } // end of namespace Assimp

+ 1 - 1
code/Assxml/AssxmlExporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 664 - 0
code/Assxml/AssxmlFileWriter.cpp

@@ -0,0 +1,664 @@
+/*
+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/IOStream.hpp>
+#include <assimp/IOSystem.hpp>
+#include <assimp/Exporter.hpp>
+
+#include <stdarg.h>
+
+#ifdef ASSIMP_BUILD_NO_OWN_ZLIB
+#   include <zlib.h>
+#else
+#   include <contrib/zlib/zlib.h>
+#endif
+
+#include <time.h>
+#include <stdio.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( NULL );
+#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 p = 0; p < prop->mDataLength/sizeof(float);++p) {
+                        ioprintf(io,"%f ",*((float*)(prop->mData+p*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 p = 0; p < prop->mDataLength/sizeof(int);++p) {
+                        ioprintf(io,"%i ",*((int*)(prop->mData+p*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 p = 0; p < prop->mDataLength;++p) {
+                        ioprintf(io,"%2x ",prop->mData[p]);
+                        if (p && 0 == p%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

+ 65 - 0
code/Assxml/AssxmlFileWriter.h

@@ -0,0 +1,65 @@
+/*
+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.h
+ *  @brief Declaration of Assxml file writer.
+ */
+
+#ifndef AI_ASSXMLFILEWRITER_H_INC
+#define AI_ASSXMLFILEWRITER_H_INC
+
+#include <assimp/defs.h>
+#include <assimp/scene.h>
+#include <assimp/IOSystem.hpp>
+
+namespace Assimp {
+
+void ASSIMP_API DumpSceneToAssxml(
+    const char* pFile,
+    const char* cmd,
+    IOSystem* pIOSystem,
+    const aiScene* pScene,
+    bool shortened);
+
+}
+
+#endif // AI_ASSXMLFILEWRITER_H_INC

+ 95 - 94
code/B3D/B3DImporter.cpp

@@ -3,9 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
-
-
+Copyright (c) 2006-2020, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 
@@ -78,7 +76,6 @@ static const aiImporterDesc desc = {
     "b3d"
     "b3d"
 };
 };
 
 
-// (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings
 #ifdef _MSC_VER
 #ifdef _MSC_VER
 #	pragma warning (disable: 4018)
 #	pragma warning (disable: 4018)
 #endif
 #endif
@@ -86,10 +83,8 @@ static const aiImporterDesc desc = {
 //#define DEBUG_B3D
 //#define DEBUG_B3D
 
 
 template<typename T>
 template<typename T>
-void DeleteAllBarePointers(std::vector<T>& x)
-{
-    for(auto p : x)
-    {
+void DeleteAllBarePointers(std::vector<T>& x) {
+    for(auto p : x) {
         delete p;
         delete p;
     }
     }
 }
 }
@@ -102,10 +97,14 @@ B3DImporter::~B3DImporter()
 bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{
 bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{
 
 
     size_t pos=pFile.find_last_of( '.' );
     size_t pos=pFile.find_last_of( '.' );
-    if( pos==string::npos ) return false;
+    if( pos==string::npos ) {
+        return false;
+    }
 
 
     string ext=pFile.substr( pos+1 );
     string ext=pFile.substr( pos+1 );
-    if( ext.size()!=3 ) return false;
+    if( ext.size()!=3 ) {
+        return false;
+    }
 
 
     return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D');
     return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D');
 }
 }
@@ -117,30 +116,21 @@ const aiImporterDesc* B3DImporter::GetInfo () const
     return &desc;
     return &desc;
 }
 }
 
 
-#ifdef DEBUG_B3D
-    extern "C"{ void _stdcall AllocConsole(); }
-#endif
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){
 void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){
-
-#ifdef DEBUG_B3D
-    AllocConsole();
-    freopen( "conin$","r",stdin );
-    freopen( "conout$","w",stdout );
-    freopen( "conout$","w",stderr );
-    cout<<"Hello world from the B3DImporter!"<<endl;
-#endif
-
     std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
     std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
 
 
     // Check whether we can read from the file
     // Check whether we can read from the file
-    if( file.get() == NULL)
+    if( file.get() == nullptr) {
         throw DeadlyImportError( "Failed to open B3D file " + pFile + ".");
         throw DeadlyImportError( "Failed to open B3D file " + pFile + ".");
+    }
 
 
     // check whether the .b3d file is large enough to contain
     // check whether the .b3d file is large enough to contain
     // at least one chunk.
     // at least one chunk.
     size_t fileSize = file->FileSize();
     size_t fileSize = file->FileSize();
-    if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small.");
+    if( fileSize<8 ) {
+        throw DeadlyImportError( "B3D File is too small.");
+    }
 
 
     _pos=0;
     _pos=0;
     _buf.resize( fileSize );
     _buf.resize( fileSize );
@@ -158,14 +148,17 @@ AI_WONT_RETURN void B3DImporter::Oops(){
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 AI_WONT_RETURN void B3DImporter::Fail( string str ){
 AI_WONT_RETURN void B3DImporter::Fail( string str ){
 #ifdef DEBUG_B3D
 #ifdef DEBUG_B3D
-    cout<<"Error in B3D file data: "<<str<<endl;
+    ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
 #endif
 #endif
     throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
     throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 int B3DImporter::ReadByte(){
 int B3DImporter::ReadByte(){
-    if( _pos<_buf.size() ) return _buf[_pos++];
+    if( _pos<_buf.size() ) {
+        return _buf[_pos++];
+    }
+    
     Fail( "EOF" );
     Fail( "EOF" );
     return 0;
     return 0;
 }
 }
@@ -224,7 +217,9 @@ string B3DImporter::ReadString(){
     string str;
     string str;
     while( _pos<_buf.size() ){
     while( _pos<_buf.size() ){
         char c=(char)ReadByte();
         char c=(char)ReadByte();
-        if( !c ) return str;
+        if( !c ) {
+            return str;
+        }
         str+=c;
         str+=c;
     }
     }
     Fail( "EOF" );
     Fail( "EOF" );
@@ -238,7 +233,7 @@ string B3DImporter::ReadChunk(){
         tag+=char( ReadByte() );
         tag+=char( ReadByte() );
     }
     }
 #ifdef DEBUG_B3D
 #ifdef DEBUG_B3D
-//	cout<<"ReadChunk:"<<tag<<endl;
+    ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag);
 #endif
 #endif
     unsigned sz=(unsigned)ReadInt();
     unsigned sz=(unsigned)ReadInt();
     _stack.push_back( _pos+sz );
     _stack.push_back( _pos+sz );
@@ -269,7 +264,6 @@ T *B3DImporter::to_array( const vector<T> &v ){
     return p;
     return p;
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template<class T>
 template<class T>
 T **unique_to_array( vector<std::unique_ptr<T> > &v ){
 T **unique_to_array( vector<std::unique_ptr<T> > &v ){
@@ -283,7 +277,6 @@ T **unique_to_array( vector<std::unique_ptr<T> > &v ){
     return p;
     return p;
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadTEXS(){
 void B3DImporter::ReadTEXS(){
     while( ChunkSize() ){
     while( ChunkSize() ){
@@ -376,9 +369,13 @@ void B3DImporter::ReadVRTS(){
 
 
         v.vertex=ReadVec3();
         v.vertex=ReadVec3();
 
 
-        if( _vflags & 1 ) v.normal=ReadVec3();
+        if( _vflags & 1 ) {
+            v.normal=ReadVec3();
+        }
 
 
-        if( _vflags & 2 ) ReadQuat();	//skip v 4bytes...
+        if( _vflags & 2 ) {
+            ReadQuat();	//skip v 4bytes...
+        }
 
 
         for( int i=0;i<_tcsets;++i ){
         for( int i=0;i<_tcsets;++i ){
             float t[4]={0,0,0,0};
             float t[4]={0,0,0,0};
@@ -386,53 +383,55 @@ void B3DImporter::ReadVRTS(){
                 t[j]=ReadFloat();
                 t[j]=ReadFloat();
             }
             }
             t[1]=1-t[1];
             t[1]=1-t[1];
-            if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] );
+            if( !i ) {
+                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() ){
+void B3DImporter::ReadTRIS(int v0) {
+	int matid = ReadInt();
+	if (matid == -1) {
+		matid = 0;
+	} else if (matid < 0 || matid >= (int)_materials.size()) {
 #ifdef DEBUG_B3D
 #ifdef DEBUG_B3D
-        cout<<"material id="<<matid<<endl;
+		ASSIMP_LOG_ERROR_F("material id=", matid);
 #endif
 #endif
-        Fail( "Bad material id" );
-    }
+		Fail("Bad material id");
+	}
 
 
-    std::unique_ptr<aiMesh> mesh(new aiMesh);
+	std::unique_ptr<aiMesh> mesh(new aiMesh);
 
 
-    mesh->mMaterialIndex=matid;
-    mesh->mNumFaces=0;
-    mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE;
+	mesh->mMaterialIndex = matid;
+	mesh->mNumFaces = 0;
+	mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
 
 
-    int n_tris=ChunkSize()/12;
-    aiFace *face=mesh->mFaces=new aiFace[n_tris];
+	int n_tris = ChunkSize() / 12;
+	aiFace *face = mesh->mFaces = new aiFace[n_tris];
 
 
-    for( 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() ){
+	for (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
 #ifdef DEBUG_B3D
-            cout<<"Bad triangle index: i0="<<i0<<", i1="<<i1<<", i2="<<i2<<endl;
+			ASSIMP_LOG_ERROR_F("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
 #endif
 #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) );
+			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));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -453,29 +452,23 @@ void B3DImporter::ReadMESH(){
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-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];
-        int i;
-        for( i=0;i<4;++i ){
-            if( !v.weights[i] ){
-                v.bones[i]=id;
-                v.weights[i]=weight;
-                break;
-            }
-        }
-#ifdef DEBUG_B3D
-        if( i==4 ){
-            cout<<"Too many bone weights"<<endl;
-        }
-#endif
-    }
+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] = id;
+				v.weights[i] = weight;
+				break;
+			}
+		}
+	}
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -633,11 +626,15 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
     }
     }
     ExitChunk();
     ExitChunk();
 
 
-    if( !_nodes.size() ) Fail( "No nodes" );
+    if( !_nodes.size() ) {
+        Fail( "No nodes" );
+    }
 
 
-    if( !_meshes.size() ) Fail( "No meshes" );
+    if( !_meshes.size() ) {
+        Fail( "No meshes" );
+    }
 
 
-    //Fix nodes/meshes/bones
+    // Fix nodes/meshes/bones
     for(size_t i=0;i<_nodes.size();++i ){
     for(size_t i=0;i<_nodes.size();++i ){
         aiNode *node=_nodes[i];
         aiNode *node=_nodes[i];
 
 
@@ -648,8 +645,12 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
             int n_verts=mesh->mNumVertices=n_tris * 3;
             int n_verts=mesh->mNumVertices=n_tris * 3;
 
 
             aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0;
             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 ];
+            if( _vflags & 1 ) {
+                mn=mesh->mNormals=new aiVector3D[ n_verts ];
+            }
+            if( _tcsets ) {
+                mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ];
+            }
 
 
             aiFace *face=mesh->mFaces;
             aiFace *face=mesh->mFaces;
 
 

+ 1 - 1
code/B3D/B3DImporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/BVH/BVHLoader.cpp

@@ -4,7 +4,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/BVH/BVHLoader.h

@@ -4,7 +4,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderBMesh.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2013, assimp team
+Copyright (c) 2006-2020, assimp team
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,

+ 1 - 1
code/Blender/BlenderBMesh.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2013, assimp team
+Copyright (c) 2006-2020, assimp team
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,

+ 1 - 1
code/Blender/BlenderDNA.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderDNA.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderDNA.inl

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderIntermediate.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderLoader.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderLoader.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderModifier.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderModifier.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderScene.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (ASSIMP)
 Open Asset Import Library (ASSIMP)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2016, ASSIMP Development Team
+Copyright (c) 2006-2020, ASSIMP Development Team
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,

+ 1 - 1
code/Blender/BlenderScene.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderSceneGen.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (ASSIMP)
 Open Asset Import Library (ASSIMP)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2016, ASSIMP Development Team
+Copyright (c) 2006-2020, ASSIMP Development Team
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,

+ 1 - 1
code/Blender/BlenderTessellator.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Blender/BlenderTessellator.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/C4D/C4DImporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,

+ 1 - 1
code/C4D/C4DImporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,

+ 1 - 1
code/CApi/AssimpCExport.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/CApi/CInterfaceIOWrapper.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/CApi/CInterfaceIOWrapper.h

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 20 - 5
code/CMakeLists.txt

@@ -1,7 +1,7 @@
 # Open Asset Import Library (assimp)
 # Open Asset Import Library (assimp)
 # ----------------------------------------------------------------------
 # ----------------------------------------------------------------------
 #
 #
-# Copyright (c) 2006-2019, assimp team
+# Copyright (c) 2006-2020, assimp team
 #
 #
 # All rights reserved.
 # All rights reserved.
 #
 #
@@ -66,6 +66,7 @@ SET( PUBLIC_HEADERS
   ${HEADER_PATH}/color4.h
   ${HEADER_PATH}/color4.h
   ${HEADER_PATH}/color4.inl
   ${HEADER_PATH}/color4.inl
   ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h
   ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h
+  ${HEADER_PATH}/commonMetaData.h
   ${HEADER_PATH}/defs.h
   ${HEADER_PATH}/defs.h
   ${HEADER_PATH}/Defines.h
   ${HEADER_PATH}/Defines.h
   ${HEADER_PATH}/cfileio.h
   ${HEADER_PATH}/cfileio.h
@@ -197,6 +198,7 @@ SET( Common_SRCS
   Common/CreateAnimMesh.cpp
   Common/CreateAnimMesh.cpp
   Common/simd.h
   Common/simd.h
   Common/simd.cpp
   Common/simd.cpp
+  Common/material.cpp
 )
 )
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 
 
@@ -330,11 +332,15 @@ ADD_ASSIMP_IMPORTER( ASSBIN
 ADD_ASSIMP_EXPORTER( ASSBIN
 ADD_ASSIMP_EXPORTER( ASSBIN
   Assbin/AssbinExporter.h
   Assbin/AssbinExporter.h
   Assbin/AssbinExporter.cpp
   Assbin/AssbinExporter.cpp
+  Assbin/AssbinFileWriter.h
+  Assbin/AssbinFileWriter.cpp
 )
 )
 
 
 ADD_ASSIMP_EXPORTER( ASSXML
 ADD_ASSIMP_EXPORTER( ASSXML
   Assxml/AssxmlExporter.h
   Assxml/AssxmlExporter.h
   Assxml/AssxmlExporter.cpp
   Assxml/AssxmlExporter.cpp
+  Assxml/AssxmlFileWriter.h
+  Assxml/AssxmlFileWriter.cpp
 )
 )
 
 
 ADD_ASSIMP_IMPORTER( B3D
 ADD_ASSIMP_IMPORTER( B3D
@@ -348,6 +354,7 @@ ADD_ASSIMP_IMPORTER( BVH
 )
 )
 
 
 ADD_ASSIMP_IMPORTER( COLLADA
 ADD_ASSIMP_IMPORTER( COLLADA
+  Collada/ColladaHelper.cpp
   Collada/ColladaHelper.h
   Collada/ColladaHelper.h
   Collada/ColladaLoader.cpp
   Collada/ColladaLoader.cpp
   Collada/ColladaLoader.h
   Collada/ColladaLoader.h
@@ -411,6 +418,8 @@ ADD_ASSIMP_IMPORTER( M3D
   M3D/M3DMaterials.h
   M3D/M3DMaterials.h
   M3D/M3DImporter.h
   M3D/M3DImporter.h
   M3D/M3DImporter.cpp
   M3D/M3DImporter.cpp
+  M3D/M3DWrapper.h
+  M3D/M3DWrapper.cpp
   M3D/m3d.h
   M3D/m3d.h
 )
 )
 
 
@@ -452,6 +461,16 @@ ADD_ASSIMP_IMPORTER( MDL
   MDL/MDLLoader.cpp
   MDL/MDLLoader.cpp
   MDL/MDLLoader.h
   MDL/MDLLoader.h
   MDL/MDLMaterialLoader.cpp
   MDL/MDLMaterialLoader.cpp
+  MDL/HalfLife/HalfLifeMDLBaseHeader.h
+  MDL/HalfLife/HL1FileData.h
+  MDL/HalfLife/HL1MDLLoader.cpp
+  MDL/HalfLife/HL1MDLLoader.h
+  MDL/HalfLife/HL1ImportDefinitions.h
+  MDL/HalfLife/HL1ImportSettings.h
+  MDL/HalfLife/HL1MeshTrivert.h
+  MDL/HalfLife/LogFunctions.h
+  MDL/HalfLife/UniqueNameGenerator.cpp
+  MDL/HalfLife/UniqueNameGenerator.h
 )
 )
 
 
 SET( MaterialSystem_SRCS
 SET( MaterialSystem_SRCS
@@ -1199,10 +1218,6 @@ SET_TARGET_PROPERTIES( assimp PROPERTIES
 )
 )
 
 
 if (APPLE)
 if (APPLE)
-  SET_TARGET_PROPERTIES( assimp PROPERTIES
-    INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR}"
-  )
-
   if (BUILD_FRAMEWORK)
   if (BUILD_FRAMEWORK)
     SET_TARGET_PROPERTIES( assimp PROPERTIES
     SET_TARGET_PROPERTIES( assimp PROPERTIES
       FRAMEWORK TRUE
       FRAMEWORK TRUE

+ 2 - 2
code/COB/COBLoader.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 
@@ -250,7 +250,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
         const Mesh& ndmesh = (const Mesh&)(root);
         const Mesh& ndmesh = (const Mesh&)(root);
         if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) {
         if (ndmesh.vertex_positions.size() && ndmesh.texture_coords.size()) {
 
 
-            typedef std::pair<unsigned int,Mesh::FaceRefList> Entry;
+            typedef std::pair<const unsigned int,Mesh::FaceRefList> Entry;
             for(const Entry& reflist : ndmesh.temp_map) {
             for(const Entry& reflist : ndmesh.temp_map) {
                 {   // create mesh
                 {   // create mesh
                     size_t n = 0;
                     size_t n = 0;

+ 1 - 1
code/COB/COBLoader.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/COB/COBScene.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 2 - 2
code/CSM/CSMLoader.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 
@@ -178,7 +178,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
                         *ot++ = *buffer++;
                         *ot++ = *buffer++;
 
 
                     *ot = '\0';
                     *ot = '\0';
-                    nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data);
+                    nda->mNodeName.length = (ai_uint32)(ot-nda->mNodeName.data);
                 }
                 }
 
 
                 anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());
                 anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());

+ 1 - 1
code/CSM/CSMLoader.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 4 - 3
code/Collada/ColladaExporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.
@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include "ColladaExporter.h"
 #include "ColladaExporter.h"
 #include <assimp/Bitmap.h>
 #include <assimp/Bitmap.h>
+#include <assimp/commonMetaData.h>
 #include <assimp/MathFunctions.h>
 #include <assimp/MathFunctions.h>
 #include <assimp/fast_atof.h>
 #include <assimp/fast_atof.h>
 #include <assimp/SceneCombiner.h>
 #include <assimp/SceneCombiner.h>
@@ -277,7 +278,7 @@ void ColladaExporter::WriteHeader() {
         mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
         mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
     }
     }
 
 
-    if (nullptr == meta || !meta->Get("AuthoringTool", value)) {
+    if (nullptr == meta || !meta->Get(AI_METADATA_SOURCE_GENERATOR, value)) {
         mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
         mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
     } else {
     } else {
         mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
         mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
@@ -287,7 +288,7 @@ void ColladaExporter::WriteHeader() {
         if (meta->Get("Comments", value)) {
         if (meta->Get("Comments", value)) {
             mOutput << startstr << "<comments>" << XMLEscape(value.C_Str()) << "</comments>" << endstr;
             mOutput << startstr << "<comments>" << XMLEscape(value.C_Str()) << "</comments>" << endstr;
         }
         }
-        if (meta->Get("Copyright", value)) {
+        if (meta->Get(AI_METADATA_SOURCE_COPYRIGHT, value)) {
             mOutput << startstr << "<copyright>" << XMLEscape(value.C_Str()) << "</copyright>" << endstr;
             mOutput << startstr << "<copyright>" << XMLEscape(value.C_Str()) << "</copyright>" << endstr;
         }
         }
         if (meta->Get("SourceData", value)) {
         if (meta->Get("SourceData", value)) {

+ 1 - 1
code/Collada/ColladaExporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 107 - 0
code/Collada/ColladaHelper.cpp

@@ -0,0 +1,107 @@
+/** Helper structures for the Collada loader */
+
+/*
+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.
+
+----------------------------------------------------------------------
+*/
+
+#include "ColladaHelper.h"
+
+#include <assimp/commonMetaData.h>
+#include <assimp/ParsingUtils.h>
+
+namespace Assimp {
+namespace Collada {
+
+const MetaKeyPairVector MakeColladaAssimpMetaKeys() {
+    MetaKeyPairVector result;
+    result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR);
+    result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT);
+    return result;
+};
+
+const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
+    static const MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
+    return result;
+}
+
+const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
+    MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
+    for (auto &val : result)
+    {
+        ToCamelCase(val.first);
+    }
+    return result;
+};
+
+const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase()
+{
+    static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
+    return result;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
+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) == '_')
+        {
+            it = text.erase(it);
+            if (it != text.end())
+                (*it) = ToUpper(*it);
+        }
+        else
+        {
+            // Make lower case
+            (*it) = ToLower(*it);
+            ++it;               
+        }
+    }
+}
+
+} // namespace Collada
+} // namespace Assimp

+ 33 - 7
code/Collada/ColladaHelper.h

@@ -4,7 +4,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.
@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include <map>
 #include <map>
 #include <vector>
 #include <vector>
+#include <set>
 #include <stdint.h>
 #include <stdint.h>
 #include <assimp/light.h>
 #include <assimp/light.h>
 #include <assimp/mesh.h>
 #include <assimp/mesh.h>
@@ -104,6 +105,17 @@ enum MorphMethod
     Relative
     Relative
 };
 };
 
 
+/** Common metadata keys as <Collada, Assimp> */
+typedef std::pair<std::string, std::string> MetaKeyPair;
+typedef std::vector<MetaKeyPair> MetaKeyPairVector;
+
+// Collada as lower_case (native)
+const MetaKeyPairVector &GetColladaAssimpMetaKeys();
+// Collada as CamelCase (used by Assimp for consistency)
+const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
+
+/** Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool" */
+void ToCamelCase(std::string &text);
 
 
 /** Contains all data for one of the different transformation types */
 /** Contains all data for one of the different transformation types */
 struct Transform
 struct Transform
@@ -647,23 +659,37 @@ struct Animation
 
 
 	void CombineSingleChannelAnimationsRecursively(Animation *pParent)
 	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();)
 		for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
 		{
 		{
 			Animation *anim = *it;
 			Animation *anim = *it;
-
 			CombineSingleChannelAnimationsRecursively(anim);
 			CombineSingleChannelAnimationsRecursively(anim);
 
 
-			if (anim->mChannels.size() == 1)
+			if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
+				childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
+				childrenTargets.insert(anim->mChannels[0].mTarget);
+			} else {
+				childrenAnimationsHaveDifferentChannels = false;
+			}
+
+			++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;
 				delete anim;
-			}
-			else
-			{
-				++it;
+				continue;
 			}
 			}
 		}
 		}
 	}
 	}

+ 24 - 4
code/Collada/ColladaLoader.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 
@@ -963,18 +963,38 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
 
 
     // catch special case: many animations with the same length, each affecting only a single node.
     // catch special case: many animations with the same length, each affecting only a single node.
     // we need to unite all those single-node-anims to a proper combined animation
     // we need to unite all those single-node-anims to a proper combined animation
-    for( size_t a = 0; a < mAnims.size(); ++a) {
+    for(size_t a = 0; a < mAnims.size(); ++a) {
         aiAnimation* templateAnim = mAnims[a];
         aiAnimation* templateAnim = mAnims[a];
-        if( templateAnim->mNumChannels == 1) {
+
+        if (templateAnim->mNumChannels == 1) {
             // search for other single-channel-anims with the same duration
             // search for other single-channel-anims with the same duration
             std::vector<size_t> collectedAnimIndices;
             std::vector<size_t> collectedAnimIndices;
             for( size_t b = a+1; b < mAnims.size(); ++b) {
             for( size_t b = a+1; b < mAnims.size(); ++b) {
                 aiAnimation* other = mAnims[b];
                 aiAnimation* other = mAnims[b];
                 if (other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration &&
                 if (other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration &&
                     other->mTicksPerSecond == templateAnim->mTicksPerSecond)
                     other->mTicksPerSecond == templateAnim->mTicksPerSecond)
-                    collectedAnimIndices.push_back(b);
+						collectedAnimIndices.push_back(b);
             }
             }
 
 
+			// We only want to combine the animations if they have different channels
+			std::set<std::string> animTargets;
+			animTargets.insert(templateAnim->mChannels[0]->mNodeName.C_Str());
+			bool collectedAnimationsHaveDifferentChannels = true;
+			for (size_t b = 0; b < collectedAnimIndices.size(); ++b)
+			{
+				aiAnimation* srcAnimation = mAnims[collectedAnimIndices[b]];
+				std::string channelName = std::string(srcAnimation->mChannels[0]->mNodeName.C_Str());
+				if (animTargets.find(channelName) == animTargets.end()) {
+					animTargets.insert(channelName);
+				} else {
+					collectedAnimationsHaveDifferentChannels = false;
+					break;
+				}
+			}
+
+			if (!collectedAnimationsHaveDifferentChannels)
+				continue;
+
             // if there are other animations which fit the template anim, combine all channels into a single anim
             // if there are other animations which fit the template anim, combine all channels into a single anim
             if (!collectedAnimIndices.empty())
             if (!collectedAnimIndices.empty())
             {
             {

+ 1 - 1
code/Collada/ColladaLoader.h

@@ -4,7 +4,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 42 - 35
code/Collada/ColladaParser.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 
@@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <sstream>
 #include <sstream>
 #include <stdarg.h>
 #include <stdarg.h>
 #include "ColladaParser.h"
 #include "ColladaParser.h"
+#include <assimp/commonMetaData.h>
 #include <assimp/fast_atof.h>
 #include <assimp/fast_atof.h>
 #include <assimp/ParsingUtils.h>
 #include <assimp/ParsingUtils.h>
 #include <assimp/StringUtils.h>
 #include <assimp/StringUtils.h>
@@ -249,6 +250,9 @@ void ColladaParser::UriDecodePath(aiString& ss)
 bool ColladaParser::ReadBoolFromTextContent()
 bool ColladaParser::ReadBoolFromTextContent()
 {
 {
     const char* cur = GetTextContent();
     const char* cur = GetTextContent();
+    if ( nullptr == cur) {
+        return false;
+    }
     return (!ASSIMP_strincmp(cur, "true", 4) || '0' != *cur);
     return (!ASSIMP_strincmp(cur, "true", 4) || '0' != *cur);
 }
 }
 
 
@@ -257,6 +261,9 @@ bool ColladaParser::ReadBoolFromTextContent()
 ai_real ColladaParser::ReadFloatFromTextContent()
 ai_real ColladaParser::ReadFloatFromTextContent()
 {
 {
     const char* cur = GetTextContent();
     const char* cur = GetTextContent();
+    if ( nullptr == cur ) {
+        return 0.0;
+    }
     return fast_atof(cur);
     return fast_atof(cur);
 }
 }
 
 
@@ -276,6 +283,11 @@ void ColladaParser::ReadContents()
                 if (attrib != -1) {
                 if (attrib != -1) {
                     const char* version = mReader->getAttributeValue(attrib);
                     const char* version = mReader->getAttributeValue(attrib);
 
 
+                    // Store declared format version string
+                    aiString v;
+                    v.Set(version);
+                    mAssetMetaData.emplace(AI_METADATA_SOURCE_FORMAT_VERSION, v );
+
                     if (!::strncmp(version, "1.5", 3)) {
                     if (!::strncmp(version, "1.5", 3)) {
                         mFormat = FV_1_5_n;
                         mFormat = FV_1_5_n;
                         ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n");
                         ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n");
@@ -434,23 +446,39 @@ void ColladaParser::ReadContributorInfo()
     }
     }
 }
 }
 
 
+static bool FindCommonKey(const std::string &collada_key, const MetaKeyPairVector &key_renaming, size_t &found_index) {
+    for (size_t i = 0; i < key_renaming.size(); ++i) {
+		if (key_renaming[i].first == collada_key) {
+            found_index = i;
+            return true;
+		}
+	}
+    found_index = std::numeric_limits<size_t>::max();
+    return false;
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads a single string metadata item
 // Reads a single string metadata item
-void ColladaParser::ReadMetaDataItem(StringMetaData &metadata)
-{
-    // Metadata such as created, keywords, subject etc
-    const char* key_char = mReader->getNodeName();
-    if (key_char != nullptr)
-    {
+void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) {
+    const Collada::MetaKeyPairVector &key_renaming = GetColladaAssimpMetaKeysCamelCase();
+	// Metadata such as created, keywords, subject etc
+	const char *key_char = mReader->getNodeName();
+	if (key_char != nullptr) {
         const std::string key_str(key_char);
         const std::string key_str(key_char);
-        const char* value_char = TestTextContent();
-        if (value_char != nullptr)
-        {
-            std::string camel_key_str = key_str;
-            ToCamelCase(camel_key_str);
+		const char *value_char = TestTextContent();
+		if (value_char != nullptr) {
             aiString aistr;
             aiString aistr;
-            aistr.Set(value_char);
-            metadata.emplace(camel_key_str, aistr);
+			aistr.Set(value_char);
+
+            std::string camel_key_str(key_str);
+			ToCamelCase(camel_key_str);
+
+			size_t found_index;
+			if (FindCommonKey(camel_key_str, key_renaming, found_index)) {
+                metadata.emplace(key_renaming[found_index].second, aistr);
+            } else {
+				metadata.emplace(camel_key_str, aistr);
+			}
         }
         }
         TestClosing(key_str.c_str());
         TestClosing(key_str.c_str());
     }
     }
@@ -458,27 +486,6 @@ void ColladaParser::ReadMetaDataItem(StringMetaData &metadata)
         SkipElement();
         SkipElement();
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-// Convert underscore_seperated to CamelCase: "authoring_tool" becomes "AuthoringTool"
-void ColladaParser::ToCamelCase(std::string &text)
-{
-    if (text.empty())
-        return;
-    // Capitalise first character
-    text[0] = ToUpper(text[0]);
-    for (auto it = text.begin(); it != text.end(); /*iterated below*/)
-    {
-        if ((*it) == '_')
-        {
-            it = text.erase(it);
-            if (it != text.end())
-                (*it) = ToUpper(*it);
-        }
-        else
-            ++it;
-    }
-}
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads the animation clips
 // Reads the animation clips
 void ColladaParser::ReadAnimationClipLibrary()
 void ColladaParser::ReadAnimationClipLibrary()

+ 2 - 5
code/Collada/ColladaParser.h

@@ -2,7 +2,7 @@
  Open Asset Import Library (assimp)
  Open Asset Import Library (assimp)
  ----------------------------------------------------------------------
  ----------------------------------------------------------------------
 
 
- Copyright (c) 2006-2019, assimp team
+ Copyright (c) 2006-2020, assimp team
 
 
 
 
  All rights reserved.
  All rights reserved.
@@ -94,12 +94,9 @@ namespace Assimp
         /** Reads contributor information such as author and legal blah */
         /** Reads contributor information such as author and legal blah */
         void ReadContributorInfo();
         void ReadContributorInfo();
 
 
-        /** Reads generic metadata into provided map */
+        /** Reads generic metadata into provided map and renames keys for Assimp */
         void ReadMetaDataItem(StringMetaData &metadata);
         void ReadMetaDataItem(StringMetaData &metadata);
 
 
-        /** Convert underscore_seperated to CamelCase "authoring_tool" becomes "AuthoringTool" */
-        static void ToCamelCase(std::string &text);
-
         /** Reads the animation library */
         /** Reads the animation library */
         void ReadAnimationLibrary();
         void ReadAnimationLibrary();
 
 

+ 1 - 1
code/Common/Assimp.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 4 - 5
code/Common/BaseImporter.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 
@@ -191,7 +191,7 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
     }
     }
 
 
     std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
     std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
-    if (pStream.get() ) {
+    if (pStream) {
         // read 200 characters from the file
         // read 200 characters from the file
         std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]);
         std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]);
         char *buffer( _buffer.get() );
         char *buffer( _buffer.get() );
@@ -283,7 +283,6 @@ std::string BaseImporter::GetExtension( const std::string& file ) {
         return "";
         return "";
     }
     }
 
 
-
     // thanks to Andy Maloney for the hint
     // thanks to Andy Maloney for the hint
     std::string ret = file.substr( pos + 1 );
     std::string ret = file.substr( pos + 1 );
     std::transform( ret.begin(), ret.end(), ret.begin(), ToLower<char>);
     std::transform( ret.begin(), ret.end(), ret.begin(), ToLower<char>);
@@ -309,7 +308,7 @@ std::string BaseImporter::GetExtension( const std::string& file ) {
     };
     };
     magic = reinterpret_cast<const char*>(_magic);
     magic = reinterpret_cast<const char*>(_magic);
     std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
     std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
-    if (pStream.get() ) {
+    if (pStream) {
 
 
         // skip to offset
         // skip to offset
         pStream->Seek(offset,aiOrigin_SET);
         pStream->Seek(offset,aiOrigin_SET);
@@ -603,7 +602,7 @@ unsigned int BatchLoader::AddLoadRequest(const std::string& file,
     }
     }
 
 
     // no, we don't have it. So add it to the queue ...
     // no, we don't have it. So add it to the queue ...
-    m_data->requests.push_back(LoadRequest(file,steps,map, m_data->next_id));
+    m_data->requests.emplace_back(file, steps, map, m_data->next_id);
     return m_data->next_id++;
     return m_data->next_id++;
 }
 }
 
 

+ 1 - 1
code/Common/BaseProcess.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/Common/BaseProcess.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 1 - 1
code/Common/Bitmap.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/Common/CreateAnimMesh.cpp

@@ -4,7 +4,7 @@ Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
 Copyright (C) 2016 The Qt Company Ltd.
 Copyright (C) 2016 The Qt Company Ltd.
-Copyright (c) 2006-2012, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 

+ 1 - 1
code/Common/DefaultIOStream.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/Common/DefaultIOSystem.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/Common/DefaultLogger.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 

+ 1 - 1
code/Common/DefaultProgressHandler.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

+ 4 - 4
code/Common/Exporter.cpp

@@ -3,7 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 
 
@@ -103,7 +103,7 @@ void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperti
 void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
 void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
 void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
-void ExportSceneA3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneM3DA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
 void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
 
 
 
 
@@ -177,7 +177,7 @@ static void setupExporterArray(std::vector<Exporter::ExportFormatEntry> &exporte
 
 
 #ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
 #ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
 	exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0));
 	exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0));
-	exporters.push_back(Exporter::ExportFormatEntry("a3d", "Model 3D (ascii)", "m3d", &ExportSceneA3D, 0));
+	exporters.push_back(Exporter::ExportFormatEntry("m3da", "Model 3D (ascii)", "a3d", &ExportSceneM3DA, 0));
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
 #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
@@ -445,7 +445,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
 
 
                 ExportProperties emptyProperties;  // Never pass NULL ExportProperties so Exporters don't have to worry.
                 ExportProperties emptyProperties;  // Never pass NULL ExportProperties so Exporters don't have to worry.
                 ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
                 ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
-                pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again);
+        		pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices);
                 exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
                 exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
 
 
                 pimpl->mProgressHandler->UpdateFileWrite(4, 4);
                 pimpl->mProgressHandler->UpdateFileWrite(4, 4);

+ 1 - 1
code/Common/FileLogStream.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 

+ 1 - 1
code/Common/FileSystemFilter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2008, assimp team
+Copyright (c) 2006-2020, assimp team
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 Redistribution and use of this software in source and binary forms,

+ 162 - 130
code/Common/Importer.cpp

@@ -3,9 +3,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 ---------------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
-
-
+Copyright (c) 2006-2020, assimp team
 
 
 All rights reserved.
 All rights reserved.
 
 
@@ -78,6 +76,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/TinyFormatter.h>
 #include <assimp/TinyFormatter.h>
 #include <assimp/Exceptional.h>
 #include <assimp/Exceptional.h>
 #include <assimp/Profiler.h>
 #include <assimp/Profiler.h>
+#include <assimp/commonMetaData.h>
+
 #include <set>
 #include <set>
 #include <memory>
 #include <memory>
 #include <cctype>
 #include <cctype>
@@ -119,7 +119,7 @@ void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothro
         return AllocateFromAssimpHeap::operator new( num_bytes );
         return AllocateFromAssimpHeap::operator new( num_bytes );
     }
     }
     catch( ... )    {
     catch( ... )    {
-        return NULL;
+        return nullptr;
     }
     }
 }
 }
 
 
@@ -134,9 +134,8 @@ void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes)    {
 void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() {
 void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() {
     try {
     try {
         return AllocateFromAssimpHeap::operator new[]( num_bytes );
         return AllocateFromAssimpHeap::operator new[]( num_bytes );
-    }
-    catch( ... )    {
-        return NULL;
+    } catch( ... )    {
+        return nullptr;
     }
     }
 }
 }
 
 
@@ -148,7 +147,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data)    {
 // Importer constructor.
 // Importer constructor.
 Importer::Importer()
 Importer::Importer()
  : pimpl( new ImporterPimpl ) {
  : pimpl( new ImporterPimpl ) {
-    pimpl->mScene = NULL;
+    pimpl->mScene = nullptr;
     pimpl->mErrorString = "";
     pimpl->mErrorString = "";
 
 
     // Allocate a default IO handler
     // Allocate a default IO handler
@@ -174,14 +173,14 @@ Importer::Importer()
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Destructor of Importer
 // Destructor of Importer
-Importer::~Importer()
-{
+Importer::~Importer() {
     // Delete all import plugins
     // Delete all import plugins
 	DeleteImporterInstanceList(pimpl->mImporter);
 	DeleteImporterInstanceList(pimpl->mImporter);
 
 
     // Delete all post-processing plug-ins
     // Delete all post-processing plug-ins
-    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)
+    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
         delete pimpl->mPostProcessingSteps[a];
         delete pimpl->mPostProcessingSteps[a];
+    }
 
 
     // Delete the assigned IO and progress handler
     // Delete the assigned IO and progress handler
     delete pimpl->mIOHandler;
     delete pimpl->mIOHandler;
@@ -199,9 +198,9 @@ Importer::~Importer()
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Register a custom post-processing step
 // Register a custom post-processing step
-aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
-{
-    ai_assert(NULL != pImp);
+aiReturn Importer::RegisterPPStep(BaseProcess* pImp) {
+    ai_assert( nullptr != pImp );
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
         pimpl->mPostProcessingSteps.push_back(pImp);
         pimpl->mPostProcessingSteps.push_back(pImp);
@@ -213,9 +212,9 @@ aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Register a custom loader plugin
 // Register a custom loader plugin
-aiReturn Importer::RegisterLoader(BaseImporter* pImp)
-{
-    ai_assert(NULL != pImp);
+aiReturn Importer::RegisterLoader(BaseImporter* pImp) {
+    ai_assert(nullptr != pImp);
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
     // --------------------------------------------------------------------
     // --------------------------------------------------------------------
@@ -242,13 +241,13 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
     pimpl->mImporter.push_back(pImp);
     pimpl->mImporter.push_back(pImp);
     ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked);
     ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked);
     ASSIMP_END_EXCEPTION_REGION(aiReturn);
     ASSIMP_END_EXCEPTION_REGION(aiReturn);
+    
     return AI_SUCCESS;
     return AI_SUCCESS;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Unregister a custom loader plugin
 // Unregister a custom loader plugin
-aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
-{
+aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
     if(!pImp) {
     if(!pImp) {
         // unregistering a NULL importer is no problem for us ... really!
         // unregistering a NULL importer is no problem for us ... really!
         return AI_SUCCESS;
         return AI_SUCCESS;
@@ -265,13 +264,13 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
     }
     }
     ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ...");
     ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ...");
     ASSIMP_END_EXCEPTION_REGION(aiReturn);
     ASSIMP_END_EXCEPTION_REGION(aiReturn);
+
     return AI_FAILURE;
     return AI_FAILURE;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Unregister a custom loader plugin
 // Unregister a custom loader plugin
-aiReturn Importer::UnregisterPPStep(BaseProcess* pImp)
-{
+aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) {
     if(!pImp) {
     if(!pImp) {
         // unregistering a NULL ppstep is no problem for us ... really!
         // unregistering a NULL ppstep is no problem for us ... really!
         return AI_SUCCESS;
         return AI_SUCCESS;
@@ -288,24 +287,22 @@ aiReturn Importer::UnregisterPPStep(BaseProcess* pImp)
     }
     }
     ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you ..");
     ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you ..");
     ASSIMP_END_EXCEPTION_REGION(aiReturn);
     ASSIMP_END_EXCEPTION_REGION(aiReturn);
+
     return AI_FAILURE;
     return AI_FAILURE;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Supplies a custom IO handler to the importer to open and access files.
 // Supplies a custom IO handler to the importer to open and access files.
-void Importer::SetIOHandler( IOSystem* pIOHandler)
-{
+void Importer::SetIOHandler( IOSystem* pIOHandler) {
+    ai_assert(nullptr != pimpl);
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
     // If the new handler is zero, allocate a default IO implementation.
     // If the new handler is zero, allocate a default IO implementation.
-    if (!pIOHandler)
-    {
+    if (!pIOHandler) {
         // Release pointer in the possession of the caller
         // Release pointer in the possession of the caller
         pimpl->mIOHandler = new DefaultIOSystem();
         pimpl->mIOHandler = new DefaultIOSystem();
         pimpl->mIsDefaultHandler = true;
         pimpl->mIsDefaultHandler = true;
-    }
-    // Otherwise register the custom handler
-    else if (pimpl->mIOHandler != pIOHandler)
-    {
+    } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
         delete pimpl->mIOHandler;
         delete pimpl->mIOHandler;
         pimpl->mIOHandler = pIOHandler;
         pimpl->mIOHandler = pIOHandler;
         pimpl->mIsDefaultHandler = false;
         pimpl->mIsDefaultHandler = false;
@@ -316,29 +313,32 @@ void Importer::SetIOHandler( IOSystem* pIOHandler)
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get the currently set IO handler
 // Get the currently set IO handler
 IOSystem* Importer::GetIOHandler() const {
 IOSystem* Importer::GetIOHandler() const {
+    ai_assert(nullptr != pimpl);
+    
     return pimpl->mIOHandler;
     return pimpl->mIOHandler;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Check whether a custom IO handler is currently set
 // Check whether a custom IO handler is currently set
 bool Importer::IsDefaultIOHandler() const {
 bool Importer::IsDefaultIOHandler() const {
+    ai_assert(nullptr != pimpl);
+    
     return pimpl->mIsDefaultHandler;
     return pimpl->mIsDefaultHandler;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Supplies a custom progress handler to get regular callbacks during importing
 // Supplies a custom progress handler to get regular callbacks during importing
 void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
 void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
+    ai_assert(nullptr != pimpl);
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
+    
     // If the new handler is zero, allocate a default implementation.
     // If the new handler is zero, allocate a default implementation.
-    if (!pHandler)
-    {
+    if (!pHandler) {
         // Release pointer in the possession of the caller
         // Release pointer in the possession of the caller
         pimpl->mProgressHandler = new DefaultProgressHandler();
         pimpl->mProgressHandler = new DefaultProgressHandler();
         pimpl->mIsDefaultProgressHandler = true;
         pimpl->mIsDefaultProgressHandler = true;
-    }
-    // Otherwise register the custom handler
-    else if (pimpl->mProgressHandler != pHandler)
-    {
+    } else if (pimpl->mProgressHandler != pHandler) { // Otherwise register the custom handler
         delete pimpl->mProgressHandler;
         delete pimpl->mProgressHandler;
         pimpl->mProgressHandler = pHandler;
         pimpl->mProgressHandler = pHandler;
         pimpl->mIsDefaultProgressHandler = false;
         pimpl->mIsDefaultProgressHandler = false;
@@ -349,19 +349,22 @@ void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get the currently set progress handler
 // Get the currently set progress handler
 ProgressHandler* Importer::GetProgressHandler() const {
 ProgressHandler* Importer::GetProgressHandler() const {
+    ai_assert(nullptr != pimpl);
+    
     return pimpl->mProgressHandler;
     return pimpl->mProgressHandler;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Check whether a custom progress handler is currently set
 // Check whether a custom progress handler is currently set
 bool Importer::IsDefaultProgressHandler() const {
 bool Importer::IsDefaultProgressHandler() const {
+    ai_assert(nullptr != pimpl);
+    
     return pimpl->mIsDefaultProgressHandler;
     return pimpl->mIsDefaultProgressHandler;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Validate post process step flags
 // Validate post process step flags
-bool _ValidateFlags(unsigned int pFlags)
-{
+bool _ValidateFlags(unsigned int pFlags) {
     if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals)   {
     if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals)   {
         ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
         ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
         return false;
         return false;
@@ -375,12 +378,13 @@ bool _ValidateFlags(unsigned int pFlags)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Free the current scene
 // Free the current scene
-void Importer::FreeScene( )
-{
+void Importer::FreeScene( ) {
+    ai_assert(nullptr != pimpl);
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
     delete pimpl->mScene;
     delete pimpl->mScene;
-    pimpl->mScene = NULL;
+    pimpl->mScene = nullptr;
 
 
     pimpl->mErrorString = "";
     pimpl->mErrorString = "";
     ASSIMP_END_EXCEPTION_REGION(void);
     ASSIMP_END_EXCEPTION_REGION(void);
@@ -388,44 +392,48 @@ void Importer::FreeScene( )
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get the current error string, if any
 // Get the current error string, if any
-const char* Importer::GetErrorString() const
-{
-     /* Must remain valid as long as ReadFile() or FreeFile() are not called */
+const char* Importer::GetErrorString() const {
+    ai_assert(nullptr != pimpl);
+    
+    // Must remain valid as long as ReadFile() or FreeFile() are not called
     return pimpl->mErrorString.c_str();
     return pimpl->mErrorString.c_str();
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Enable extra-verbose mode
 // Enable extra-verbose mode
-void Importer::SetExtraVerbose(bool bDo)
-{
+void Importer::SetExtraVerbose(bool bDo) {
+    ai_assert(nullptr != pimpl);
+    
     pimpl->bExtraVerbose = bDo;
     pimpl->bExtraVerbose = bDo;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get the current scene
 // Get the current scene
-const aiScene* Importer::GetScene() const
-{
+const aiScene* Importer::GetScene() const {
+    ai_assert(nullptr != pimpl);
+    
     return pimpl->mScene;
     return pimpl->mScene;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Orphan the current scene and return it.
 // Orphan the current scene and return it.
-aiScene* Importer::GetOrphanedScene()
-{
+aiScene* Importer::GetOrphanedScene() {
+    ai_assert(nullptr != pimpl);
+    
     aiScene* s = pimpl->mScene;
     aiScene* s = pimpl->mScene;
 
 
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
-    pimpl->mScene = NULL;
+    pimpl->mScene = nullptr;
 
 
-    pimpl->mErrorString = ""; /* reset error string */
+    pimpl->mErrorString = ""; // reset error string
     ASSIMP_END_EXCEPTION_REGION(aiScene*);
     ASSIMP_END_EXCEPTION_REGION(aiScene*);
+    
     return s;
     return s;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Validate post-processing flags
 // Validate post-processing flags
-bool Importer::ValidateFlags(unsigned int pFlags) const
-{
+bool Importer::ValidateFlags(unsigned int pFlags) const {
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
     // run basic checks for mutually exclusive flags
     // run basic checks for mutually exclusive flags
     if(!_ValidateFlags(pFlags)) {
     if(!_ValidateFlags(pFlags)) {
@@ -467,8 +475,9 @@ bool Importer::ValidateFlags(unsigned int pFlags) const
 const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
 const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
     size_t pLength,
     size_t pLength,
     unsigned int pFlags,
     unsigned int pFlags,
-    const char* pHint /*= ""*/)
-{
+    const char* pHint /*= ""*/) {
+    ai_assert(nullptr != pimpl);
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
     if (!pHint) {
     if (!pHint) {
         pHint = "";
         pHint = "";
@@ -476,12 +485,12 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
 
 
     if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
     if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
         pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
         pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
-        return NULL;
+        return nullptr;
     }
     }
 
 
     // prevent deletion of the previous IOHandler
     // prevent deletion of the previous IOHandler
     IOSystem* io = pimpl->mIOHandler;
     IOSystem* io = pimpl->mIOHandler;
-    pimpl->mIOHandler = NULL;
+    pimpl->mIOHandler = nullptr;
 
 
     SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
     SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
 
 
@@ -493,13 +502,13 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
     ReadFile(fbuff,pFlags);
     ReadFile(fbuff,pFlags);
     SetIOHandler(io);
     SetIOHandler(io);
 
 
-    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
     return pimpl->mScene;
     return pimpl->mScene;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void WriteLogOpening(const std::string& file)
-{
+void WriteLogOpening(const std::string& file) {
+    
     ASSIMP_LOG_INFO_F("Load ", file);
     ASSIMP_LOG_INFO_F("Load ", file);
 
 
     // print a full version dump. This is nice because we don't
     // print a full version dump. This is nice because we don't
@@ -550,8 +559,9 @@ void WriteLogOpening(const std::string& file)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads the given file and returns its contents if successful.
 // Reads the given file and returns its contents if successful.
-const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
-{
+const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
+    ai_assert(nullptr != pimpl);
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
     const std::string pFile(_pFile);
     const std::string pFile(_pFile);
 
 
@@ -580,7 +590,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 
 
             pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
             pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
             ASSIMP_LOG_ERROR(pimpl->mErrorString);
             ASSIMP_LOG_ERROR(pimpl->mErrorString);
-            return NULL;
+            return nullptr;
         }
         }
 
 
         std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
         std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
@@ -589,7 +599,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
         }
         }
 
 
         // Find an worker class which can handle the file
         // Find an worker class which can handle the file
-        BaseImporter* imp = NULL;
+        BaseImporter* imp = nullptr;
         SetPropertyInteger("importerIndex", -1);
         SetPropertyInteger("importerIndex", -1);
         for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
         for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
 
 
@@ -617,7 +627,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
             if( !imp)   {
             if( !imp)   {
                 pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
                 pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
                 ASSIMP_LOG_ERROR(pimpl->mErrorString);
                 ASSIMP_LOG_ERROR(pimpl->mErrorString);
-                return NULL;
+                return nullptr;
             }
             }
         }
         }
 
 
@@ -633,7 +643,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
         // Dispatch the reading to the worker class for this format
         // Dispatch the reading to the worker class for this format
         const aiImporterDesc *desc( imp->GetInfo() );
         const aiImporterDesc *desc( imp->GetInfo() );
         std::string ext( "unknown" );
         std::string ext( "unknown" );
-        if ( NULL != desc ) {
+        if ( nullptr != desc ) {
             ext = desc->mName;
             ext = desc->mName;
         }
         }
         ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." );
         ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." );
@@ -654,15 +664,20 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 
 
         // If successful, apply all active post processing steps to the imported data
         // If successful, apply all active post processing steps to the imported data
         if( pimpl->mScene)  {
         if( pimpl->mScene)  {
+            if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
+                if (!pimpl->mScene->mMetaData) {
+                    pimpl->mScene->mMetaData = new aiMetadata;
+                }
+                pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext));
+            }
 
 
 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
             // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
             // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
-            if (pFlags & aiProcess_ValidateDataStructure)
-            {
+            if (pFlags & aiProcess_ValidateDataStructure) {
                 ValidateDSProcess ds;
                 ValidateDSProcess ds;
                 ds.ExecuteOnScene (this);
                 ds.ExecuteOnScene (this);
                 if (!pimpl->mScene) {
                 if (!pimpl->mScene) {
-                    return NULL;
+                    return nullptr;
                 }
                 }
             }
             }
 #endif // no validation
 #endif // no validation
@@ -695,8 +710,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
         }
         }
     }
     }
 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
-    catch (std::exception &e)
-    {
+    catch (std::exception &e) {
 #if (defined _MSC_VER) &&   (defined _CPPRTTI)
 #if (defined _MSC_VER) &&   (defined _CPPRTTI)
         // if we have RTTI get the full name of the exception that occurred
         // if we have RTTI get the full name of the exception that occurred
         pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
         pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
@@ -705,24 +719,26 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 #endif
 #endif
 
 
         ASSIMP_LOG_ERROR(pimpl->mErrorString);
         ASSIMP_LOG_ERROR(pimpl->mErrorString);
-        delete pimpl->mScene; pimpl->mScene = NULL;
+        delete pimpl->mScene; pimpl->mScene = nullptr;
     }
     }
 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
 
 
     // either successful or failure - the pointer expresses it anyways
     // either successful or failure - the pointer expresses it anyways
-    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
+    
     return pimpl->mScene;
     return pimpl->mScene;
 }
 }
 
 
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Apply post-processing to the currently bound scene
 // Apply post-processing to the currently bound scene
-const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
-{
+const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
+    ai_assert(nullptr != pimpl);
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
     // Return immediately if no scene is active
     // Return immediately if no scene is active
     if (!pimpl->mScene) {
     if (!pimpl->mScene) {
-        return NULL;
+        return nullptr;
     }
     }
 
 
     // If no flags are given, return the current scene with no further action
     // If no flags are given, return the current scene with no further action
@@ -737,12 +753,11 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
     // The ValidateDS process plays an exceptional role. It isn't contained in the global
     // The ValidateDS process plays an exceptional role. It isn't contained in the global
     // list of post-processing steps, so we need to call it manually.
     // list of post-processing steps, so we need to call it manually.
-    if (pFlags & aiProcess_ValidateDataStructure)
-    {
+    if (pFlags & aiProcess_ValidateDataStructure) {
         ValidateDSProcess ds;
         ValidateDSProcess ds;
         ds.ExecuteOnScene (this);
         ds.ExecuteOnScene (this);
         if (!pimpl->mScene) {
         if (!pimpl->mScene) {
-            return NULL;
+            return nullptr;
         }
         }
     }
     }
 #endif // no validation
 #endif // no validation
@@ -762,11 +777,9 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 
 
     std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
     std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
     for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)   {
     for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)   {
-
         BaseProcess* process = pimpl->mPostProcessingSteps[a];
         BaseProcess* process = pimpl->mPostProcessingSteps[a];
         pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
         pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
         if( process->IsActive( pFlags)) {
         if( process->IsActive( pFlags)) {
-
             if (profiler) {
             if (profiler) {
                 profiler->BeginRegion("postprocess");
                 profiler->BeginRegion("postprocess");
             }
             }
@@ -803,24 +816,28 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
         static_cast<int>(pimpl->mPostProcessingSteps.size()) );
         static_cast<int>(pimpl->mPostProcessingSteps.size()) );
 
 
     // update private scene flags
     // update private scene flags
-    if( pimpl->mScene )
+    if( pimpl->mScene ) {
       ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
       ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
+    }
 
 
     // clear any data allocated by post-process steps
     // clear any data allocated by post-process steps
     pimpl->mPPShared->Clean();
     pimpl->mPPShared->Clean();
     ASSIMP_LOG_INFO("Leaving post processing pipeline");
     ASSIMP_LOG_INFO("Leaving post processing pipeline");
 
 
     ASSIMP_END_EXCEPTION_REGION(const aiScene*);
     ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    
     return pimpl->mScene;
     return pimpl->mScene;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) {
 const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) {
+    ai_assert(nullptr != pimpl);
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
     // Return immediately if no scene is active
     // Return immediately if no scene is active
-    if ( NULL == pimpl->mScene ) {
-        return NULL;
+    if ( nullptr == pimpl->mScene ) {
+        return nullptr;
     }
     }
 
 
     // If no flags are given, return the current scene with no further action
     // If no flags are given, return the current scene with no further action
@@ -839,7 +856,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
         ValidateDSProcess ds;
         ValidateDSProcess ds;
         ds.ExecuteOnScene( this );
         ds.ExecuteOnScene( this );
         if ( !pimpl->mScene ) {
         if ( !pimpl->mScene ) {
-            return NULL;
+            return nullptr;
         }
         }
     }
     }
 #endif // no validation
 #endif // no validation
@@ -890,46 +907,50 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Helper function to check whether an extension is supported by ASSIMP
 // Helper function to check whether an extension is supported by ASSIMP
-bool Importer::IsExtensionSupported(const char* szExtension) const
-{
+bool Importer::IsExtensionSupported(const char* szExtension) const {
     return nullptr != GetImporter(szExtension);
     return nullptr != GetImporter(szExtension);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-size_t Importer::GetImporterCount() const
-{
+size_t Importer::GetImporterCount() const {
+    ai_assert(nullptr != pimpl);
+    
     return pimpl->mImporter.size();
     return pimpl->mImporter.size();
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-const aiImporterDesc* Importer::GetImporterInfo(size_t index) const
-{
+const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
+    ai_assert(nullptr != pimpl);
+    
     if (index >= pimpl->mImporter.size()) {
     if (index >= pimpl->mImporter.size()) {
-        return NULL;
+        return nullptr;
     }
     }
     return pimpl->mImporter[index]->GetInfo();
     return pimpl->mImporter[index]->GetInfo();
 }
 }
 
 
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-BaseImporter* Importer::GetImporter (size_t index) const
-{
+BaseImporter* Importer::GetImporter (size_t index) const {
+    ai_assert(nullptr != pimpl);
+    
     if (index >= pimpl->mImporter.size()) {
     if (index >= pimpl->mImporter.size()) {
-        return NULL;
+        return nullptr;
     }
     }
     return pimpl->mImporter[index];
     return pimpl->mImporter[index];
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Find a loader plugin for a given file extension
 // Find a loader plugin for a given file extension
-BaseImporter* Importer::GetImporter (const char* szExtension) const
-{
+BaseImporter* Importer::GetImporter (const char* szExtension) const {
+    ai_assert(nullptr != pimpl);
+    
     return GetImporter(GetImporterIndex(szExtension));
     return GetImporter(GetImporterIndex(szExtension));
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Find a loader plugin for a given file extension
 // Find a loader plugin for a given file extension
 size_t Importer::GetImporterIndex (const char* szExtension) const {
 size_t Importer::GetImporterIndex (const char* szExtension) const {
+    ai_assert(nullptr != pimpl);
     ai_assert(nullptr != szExtension);
     ai_assert(nullptr != szExtension);
 
 
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
@@ -960,8 +981,9 @@ size_t Importer::GetImporterIndex (const char* szExtension) const {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Helper function to build a list of all file extensions supported by ASSIMP
 // Helper function to build a list of all file extensions supported by ASSIMP
-void Importer::GetExtensionList(aiString& szOut) const
-{
+void Importer::GetExtensionList(aiString& szOut) const {
+    ai_assert(nullptr != pimpl);
+    
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
     std::set<std::string> str;
     std::set<std::string> str;
     for (std::vector<BaseImporter*>::const_iterator i =  pimpl->mImporter.begin();i != pimpl->mImporter.end();++i)  {
     for (std::vector<BaseImporter*>::const_iterator i =  pimpl->mImporter.begin();i != pimpl->mImporter.end();++i)  {
@@ -985,8 +1007,9 @@ void Importer::GetExtensionList(aiString& szOut) const
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Set a configuration property
 // Set a configuration property
-bool Importer::SetPropertyInteger(const char* szName, int iValue)
-{
+bool Importer::SetPropertyInteger(const char* szName, int iValue) {
+    ai_assert(nullptr != pimpl);
+    
     bool existing;
     bool existing;
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
         existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
         existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
@@ -996,8 +1019,9 @@ bool Importer::SetPropertyInteger(const char* szName, int iValue)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Set a configuration property
 // Set a configuration property
-bool Importer::SetPropertyFloat(const char* szName, ai_real iValue)
-{
+bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
+    ai_assert(nullptr != pimpl);
+    
     bool existing;
     bool existing;
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
         existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
         existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
@@ -1007,8 +1031,9 @@ bool Importer::SetPropertyFloat(const char* szName, ai_real iValue)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Set a configuration property
 // Set a configuration property
-bool Importer::SetPropertyString(const char* szName, const std::string& value)
-{
+bool Importer::SetPropertyString(const char* szName, const std::string& value) {
+    ai_assert(nullptr != pimpl);
+    
     bool existing;
     bool existing;
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
         existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
         existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
@@ -1018,8 +1043,9 @@ bool Importer::SetPropertyString(const char* szName, const std::string& value)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Set a configuration property
 // Set a configuration property
-bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
-{
+bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
+    ai_assert(nullptr != pimpl);
+    
     bool existing;
     bool existing;
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
         existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value);
         existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value);
@@ -1029,40 +1055,43 @@ bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 // Get a configuration property
-int Importer::GetPropertyInteger(const char* szName,
-    int iErrorReturn /*= 0xffffffff*/) const
-{
+int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
+    ai_assert(nullptr != pimpl);
+    
     return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
     return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 // Get a configuration property
-ai_real Importer::GetPropertyFloat(const char* szName,
-    ai_real iErrorReturn /*= 10e10*/) const
-{
+ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
+    ai_assert(nullptr != pimpl);
+    
     return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
     return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 // Get a configuration property
-const std::string Importer::GetPropertyString(const char* szName,
-    const std::string& iErrorReturn /*= ""*/) const
-{
+std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
+    ai_assert(nullptr != pimpl);
+    
     return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
     return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 // Get a configuration property
-const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName,
-    const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
-{
+aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
+    ai_assert(nullptr != pimpl);
+    
     return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
     return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get the memory requirements of a single node
 // Get the memory requirements of a single node
-inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
-{
+inline 
+void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) {
+    if ( nullptr == pcNode ) {
+        return;
+    }
     iScene += sizeof(aiNode);
     iScene += sizeof(aiNode);
     iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
     iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
     iScene += sizeof(void*) * pcNode->mNumChildren;
     iScene += sizeof(void*) * pcNode->mNumChildren;
@@ -1074,21 +1103,20 @@ inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get the memory requirements of the scene
 // Get the memory requirements of the scene
-void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
-{
+void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
+    ai_assert(nullptr != pimpl);
+    
     in = aiMemoryInfo();
     in = aiMemoryInfo();
     aiScene* mScene = pimpl->mScene;
     aiScene* mScene = pimpl->mScene;
 
 
     // return if we have no scene loaded
     // return if we have no scene loaded
-    if (!pimpl->mScene)
+    if (!mScene)
         return;
         return;
 
 
-
     in.total = sizeof(aiScene);
     in.total = sizeof(aiScene);
 
 
     // add all meshes
     // add all meshes
-    for (unsigned int i = 0; i < mScene->mNumMeshes;++i)
-    {
+    for (unsigned int i = 0; i < mScene->mNumMeshes;++i) {
         in.meshes += sizeof(aiMesh);
         in.meshes += sizeof(aiMesh);
         if (mScene->mMeshes[i]->HasPositions()) {
         if (mScene->mMeshes[i]->HasPositions()) {
             in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
             in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
@@ -1105,14 +1133,16 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
         for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) {
         for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) {
             if (mScene->mMeshes[i]->HasVertexColors(a)) {
             if (mScene->mMeshes[i]->HasVertexColors(a)) {
                 in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
                 in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
+            } else {
+                break;
             }
             }
-            else break;
         }
         }
         for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
         for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
             if (mScene->mMeshes[i]->HasTextureCoords(a)) {
             if (mScene->mMeshes[i]->HasTextureCoords(a)) {
                 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
                 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
+            } else {
+                break;
             }
             }
-            else break;
         }
         }
         if (mScene->mMeshes[i]->HasBones()) {
         if (mScene->mMeshes[i]->HasBones()) {
             in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
             in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
@@ -1131,8 +1161,9 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
         in.textures += sizeof(aiTexture);
         in.textures += sizeof(aiTexture);
         if (pc->mHeight) {
         if (pc->mHeight) {
             in.textures += 4 * pc->mHeight * pc->mWidth;
             in.textures += 4 * pc->mHeight * pc->mWidth;
+        } else {
+            in.textures += pc->mWidth;
         }
         }
-        else in.textures += pc->mWidth;
     }
     }
     in.total += in.textures;
     in.total += in.textures;
 
 
@@ -1170,5 +1201,6 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
             in.materials += pc->mProperties[a]->mDataLength;
             in.materials += pc->mProperties[a]->mDataLength;
         }
         }
     }
     }
+
     in.total += in.materials;
     in.total += in.materials;
 }
 }

+ 1 - 1
code/Common/Importer.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 
 
-Copyright (c) 2006-2019, assimp team
+Copyright (c) 2006-2020, assimp team
 
 
 
 
 All rights reserved.
 All rights reserved.

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно