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

Merge pull request #14 from assimp/master

Update
Madrich 6 жил өмнө
parent
commit
990dc9453e
100 өөрчлөгдсөн 5944 нэмэгдсэн , 2907 устгасан
  1. 7 0
      .gitattributes
  2. 14 0
      .gitignore
  3. 56 7
      .travis.sh
  4. 40 22
      .travis.yml
  5. 0 21
      AssimpConfig.cmake.in
  6. 73 0
      Build.md
  7. 408 6
      CHANGES
  8. 250 138
      CMakeLists.txt
  9. 10 0
      CONTRIBUTING.md
  10. 23 0
      CREDITS
  11. 10 4
      INSTALL
  12. 70 37
      Readme.md
  13. 53 22
      appveyor.yml
  14. 1 81
      assimp-config.cmake.in
  15. 1 1
      assimp.pc.in
  16. 78 0
      assimpTargets-debug.cmake.in
  17. 75 0
      assimpTargets-release.cmake.in
  18. 101 0
      assimpTargets.cmake.in
  19. 2 2
      cmake-modules/CoverallsGenerateGcov.cmake
  20. 25 20
      code/3DSConverter.cpp
  21. 12 6
      code/3DSExporter.cpp
  22. 11 13
      code/3DSExporter.h
  23. 113 54
      code/3DSHelper.h
  24. 63 64
      code/3DSLoader.cpp
  25. 4 3
      code/3DSLoader.h
  26. 104 0
      code/3MFXmlTags.h
  27. 25 24
      code/ACLoader.cpp
  28. 3 2
      code/ACLoader.h
  29. 4 3
      code/AMFImporter.cpp
  30. 70 201
      code/AMFImporter.hpp
  31. 2 1
      code/AMFImporter_Geometry.cpp
  32. 6 5
      code/AMFImporter_Macro.hpp
  33. 61 42
      code/AMFImporter_Material.cpp
  34. 65 125
      code/AMFImporter_Node.hpp
  35. 16 12
      code/AMFImporter_Postprocess.cpp
  36. 22 21
      code/ASELoader.cpp
  37. 3 2
      code/ASELoader.h
  38. 36 34
      code/ASEParser.cpp
  39. 131 107
      code/ASEParser.h
  40. 552 512
      code/AssbinExporter.cpp
  41. 10 2
      code/AssbinExporter.h
  42. 213 209
      code/AssbinLoader.cpp
  43. 25 24
      code/AssbinLoader.h
  44. 7 6
      code/Assimp.cpp
  45. 2 2
      code/AssimpCExport.cpp
  46. 14 9
      code/AssxmlExporter.cpp
  47. 2 1
      code/AssxmlExporter.h
  48. 63 22
      code/B3DImporter.cpp
  49. 10 6
      code/B3DImporter.h
  50. 79 46
      code/BVHLoader.cpp
  51. 7 3
      code/BVHLoader.h
  52. 73 59
      code/BaseImporter.cpp
  53. 5 4
      code/BaseProcess.cpp
  54. 5 8
      code/BaseProcess.h
  55. 8 6
      code/Bitmap.cpp
  56. 5 1
      code/BlenderBMesh.cpp
  57. 1 1
      code/BlenderBMesh.h
  58. 189 0
      code/BlenderCustomData.cpp
  59. 89 0
      code/BlenderCustomData.h
  60. 15 16
      code/BlenderDNA.cpp
  61. 48 8
      code/BlenderDNA.h
  62. 112 8
      code/BlenderDNA.inl
  63. 9 4
      code/BlenderIntermediate.h
  64. 93 37
      code/BlenderLoader.cpp
  65. 4 3
      code/BlenderLoader.h
  66. 6 31
      code/BlenderModifier.cpp
  67. 30 32
      code/BlenderModifier.h
  68. 76 13
      code/BlenderScene.cpp
  69. 89 2
      code/BlenderScene.h
  70. 11 0
      code/BlenderSceneGen.h
  71. 12 3
      code/BlenderTessellator.cpp
  72. 4 3
      code/BlenderTessellator.h
  73. 68 97
      code/C4DImporter.cpp
  74. 9 15
      code/C4DImporter.h
  75. 2 1
      code/CInterfaceIOWrapper.cpp
  76. 2 1
      code/CInterfaceIOWrapper.h
  77. 314 99
      code/CMakeLists.txt
  78. 41 93
      code/COBLoader.cpp
  79. 5 24
      code/COBLoader.h
  80. 3 2
      code/COBScene.h
  81. 8 7
      code/CSMLoader.cpp
  82. 3 2
      code/CSMLoader.h
  83. 11 10
      code/CalcTangentsProcess.cpp
  84. 2 1
      code/CalcTangentsProcess.h
  85. 328 31
      code/ColladaExporter.cpp
  86. 16 5
      code/ColladaExporter.h
  87. 7 5
      code/ColladaHelper.h
  88. 154 113
      code/ColladaLoader.cpp
  89. 4 2
      code/ColladaLoader.h
  90. 139 41
      code/ColladaParser.cpp
  91. 23 4
      code/ColladaParser.h
  92. 9 8
      code/ComputeUVMappingProcess.cpp
  93. 2 1
      code/ComputeUVMappingProcess.h
  94. 111 29
      code/ConvertToLHProcess.cpp
  95. 2 1
      code/ConvertToLHProcess.h
  96. 1 1
      code/CreateAnimMesh.cpp
  97. 398 0
      code/D3MFExporter.cpp
  98. 106 0
      code/D3MFExporter.h
  99. 252 144
      code/D3MFImporter.cpp
  100. 8 9
      code/D3MFImporter.h

+ 7 - 0
.gitattributes

@@ -13,3 +13,10 @@ CHANGES text eol=lf
 CREDITS text eol=lf
 LICENSE text eol=lf
 Readme.md text eol=lf
+# make sure that repo-specific settings (.gitignore, CI-setup,...)
+# are excluded from the source-package generated via 'git archive'
+.git*      	export-ignore
+/.travis*	export-ignore
+/.coveralls*	export-ignore
+appveyor.yml	export-ignore
+

+ 14 - 0
.gitignore

@@ -12,13 +12,17 @@ build
 bin/
 lib/
 
+# QtCreator
+CMakeLists.txt.user
 
 # Generated
 assimp.pc
+assimp.aps
 revision.h
 contrib/zlib/zconf.h
 contrib/zlib/zlib.pc
 include/assimp/config.h
+unit.vcxproj.user
 
 # CMake
 CMakeCache.txt
@@ -38,6 +42,7 @@ tools/assimp_cmd/Makefile
 
 # Tests
 test/results
+test/readlinetest*
 
 # Python
 __pycache__
@@ -60,6 +65,7 @@ test/gtest/src/gtest-stamp/Debug/gtest-build
 *.lib
 test/gtest/src/gtest-stamp/Debug/
 tools/assimp_view/assimp_viewer.vcxproj.user
+*.pyc
 
 # Unix editor backups
 *~
@@ -81,3 +87,11 @@ lib64/assimp-vc120-mtd.ilk
 lib64/assimp-vc120-mtd.exp
 lib64/assimp-vc120-mt.exp
 xcuserdata
+
+cmake-build-debug
+install_manifest.txt
+tools/assimp_qt_viewer/moc_glview.cpp
+tools/assimp_qt_viewer/moc_glview.cpp_parameters
+tools/assimp_qt_viewer/moc_mainwindow.cpp
+tools/assimp_qt_viewer/moc_mainwindow.cpp_parameters
+tools/assimp_qt_viewer/ui_mainwindow.h

+ 56 - 7
.travis.sh

@@ -1,17 +1,66 @@
-function generate()
-{
-    cmake -G "Unix Makefiles" -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -DBUILD_SHARED_LIBS=$SHARED_BUILD -DASSIMP_COVERALLS=$ENABLE_COVERALLS
-}
+#---------------------------------------------------------------------------
+#Open Asset Import Library (assimp)
+#---------------------------------------------------------------------------
+# Copyright (c) 2006-2017, assimp team
+#
+# License see LICENSE file
+#
+function generate() {
+    OPTIONS="-DASSIMP_WERROR=ON"
+
+    if [ "$DISABLE_EXPORTERS" = "YES" ] ; then
+        OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES"
+    else
+        OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO"
+    fi
+
+    if [ "$SHARED_BUILD" = "ON" ] ; then
+        OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=ON"
+    else
+        OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=OFF"
+    fi
+
+    if [ "$ENABLE_COVERALLS" = "ON" ] ; then
+        OPTIONS="$OPTIONS -DASSIMP_COVERALLS=ON"
+    else
+        OPTIONS="$OPTIONS -DASSIMP_COVERALLS=OFF"
+    fi
 
+    if [ "$ASAN" = "ON" ] ; then
+        OPTIONS="$OPTIONS -DASSIMP_ASAN=ON"
+    else
+        OPTIONS="$OPTIONS -DASSIMP_ASAN=OFF"
+    fi
+
+    if [ "$UBSAN" = "ON" ] ; then
+        OPTIONS="$OPTIONS -DASSIMP_UBSAN=ON"
+    fi
+
+    cmake -G "Unix Makefiles" $OPTIONS
+}
+# build and run unittests, if not android
 if [ $ANDROID ]; then
     ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
 fi
 if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+  if [ $ANALYZE = "ON" ] ; then
+    if [ "$CC" = "clang" ]; then
+        scan-build cmake -G "Unix Makefiles" -DBUILD_SHARED_LIBS=OFF -DASSIMP_BUILD_TESTS=OFF
+        scan-build --status-bugs make -j2
+    else
+        cppcheck --version
+        generate \
+        && cppcheck --error-exitcode=1 -j2 -Iinclude -Icode code 2> cppcheck.txt
+        if [ -s cppcheck.txt ]; then
+            cat cppcheck.txt
+            exit 1
+        fi
+    fi
+  else
     generate \
     && make -j4 \
     && sudo make install \
     && sudo ldconfig \
-    && (cd test/unit; ../../bin/unit) \
-    #&& (cd test/regression; chmod 755 run.py; ./run.py ../../bin/assimp; \
-	#   chmod 755 result_checker.py; ./result_checker.py)
+    && (cd test/unit; ../../bin/unit)
+  fi
 fi

+ 40 - 22
.travis.yml

@@ -1,48 +1,66 @@
 sudo: required
 language: cpp
 
+cache: ccache
+
 before_install:
-  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi
-  - if [ "$TRAVIS_OS_NAME" =   "osx" ]; then brew install cmake python3 homebrew/x11/freeglut; fi
+  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake cppcheck && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi
+  - 'if [ "$TRAVIS_OS_NAME" = "osx" ];  then
+       if brew ls --versions cmake > /dev/null; then
+         echo cmake already installed.;
+       else
+         brew install cmake;
+       fi;
+       brew install python3;
+       brew install homebrew/x11/freeglut; 
+    fi'
   - echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h
   # install latest LCOV (1.9 was failing)
   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz && tar xf lcov_1.11.orig.tar.gz && sudo make -C lcov-1.11/ install && gem install coveralls-lcov && lcov --version && g++ --version ; fi
 
-branches:
-  only:
-    - master
+os:
+  - linux
 
-osx_image: xcode8.3
+compiler:
+  - gcc
+  - clang
 
 env:
   global:
-  # COVERITY_SCAN_TOKEN
     - 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}
-  matrix:
-    - LINUX=1 TRAVIS_NO_EXPORT=YES ENABLE_COVERALLS=ON
-    - LINUX=1 TRAVIS_NO_EXPORT=NO  ENABLE_COVERALLS=OFF
-    - LINUX=1 SHARED_BUILD=ON      ENABLE_COVERALLS=OFF
-    - LINUX=1 SHARED_BUILD=OFF     ENABLE_COVERALLS=OFF
 
-compiler:
-  - gcc
-  - clang
+matrix:
+  include:
+    - os: linux
+      compiler: clang
+      env: ASAN=ON
+    - os: linux
+      compiler: clang
+      env: UBSAN=ON
+    - os: linux
+      compiler: clang
+      env: SHARED_BUILD=ON
+    - os: linux
+      compiler: gcc
+      env: ANALYZE=ON
+    - os: linux
+      compiler: gcc
+      env: ENABLE_COVERALLS=ON
+    - os: linux
+      compiler: gcc
+      env: SHARED_BUILD=ON
 
 install:
   - if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi
 
 before_script:
-  # init coverage to 0 (optional)
-  - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --zerocounters ; fi
+  cmake . -DASSIMP_ENABLE_BOOST_WORKAROUND=YES
 
 script:
   - export COVERALLS_SERVICE_NAME=travis-ci
   - export COVERALLS_REPO_TOKEN=abc12345
   - . ./.travis.sh
-os:
-  - linux
-  - osx
  
 after_success:
   - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --capture --output-file coverage.info && lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info && lcov --list coverage.info && coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info ; fi
@@ -52,6 +70,6 @@ addons:
     project:
       name: "assimp/assimp"
     notification_email: [email protected]
-    build_command_prepend: "cmake"
-    build_command: "make"
+    build_command_prepend: "cmake ./"
+    build_command: "make -j4"
     branch_pattern: coverity_scan

+ 0 - 21
AssimpConfig.cmake.in

@@ -1,21 +0,0 @@
-# - Config file for the FooBar package
-# It defines the following variables
-#  FOOBAR_INCLUDE_DIRS - include directories for FooBar
-#  FOOBAR_LIBRARIES    - libraries to link against
-#  FOOBAR_EXECUTABLE   - the bar executable
-
-# Compute paths
-get_filename_component(FOOBAR_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-if(EXISTS "${FOOBAR_CMAKE_DIR}/CMakeCache.txt")
-  # In build tree
-  include("${FOOBAR_CMAKE_DIR}/FooBarBuildTreeSettings.cmake")
-else()
-  set(FOOBAR_INCLUDE_DIRS "${FOOBAR_CMAKE_DIR}/@CONF_REL_INCLUDE_DIR@")
-endif()
-
-# Our library dependencies (contains definitions for IMPORTED targets)
-include("${FOOBAR_CMAKE_DIR}/FooBarLibraryDepends.cmake")
-
-# These are IMPORTED targets created by FooBarLibraryDepends.cmake
-set(FOOBAR_LIBRARIES foo)
-set(FOOBAR_EXECUTABLE bar)

+ 73 - 0
Build.md

@@ -0,0 +1,73 @@
+# Build Instructions
+## Install CMake
+Asset-Importer-Lib can be build for a lot of different platforms. We are using cmake to generate the build environment for these via cmake. So you have to make sure that you have a working cmake-installation on your system. You can download it at https://cmake.org/ or for linux install it via
+```bash
+sudo apt-get install cmake
+```
+
+## Get the source
+Make sure you have a working git-installation. Open a command prompt and clone the Asset-Importer-Lib via:
+```bash
+git clone https://github.com/assimp/assimp.git
+```
+
+## Build instructions for Windows with Visual-Studio
+
+First you have to install Visual-Studio on your windows-system. You can get the Community-Version for free here: https://visualstudio.microsoft.com/de/downloads/
+To generate the build environment for your IDE open a command prompt, navigate to your repo and type:
+```bash
+cmake CMakeLists.txt
+```
+This will generate the project files for the visual studio. All dependencies used to build Asset-IMporter-Lib shall be part of the repo. If you want to use you own zlib.installation this is possible as well. Check the options for it.
+
+## Build instructions for Windows with UWP
+See <https://stackoverflow.com/questions/40803170/cmake-uwp-using-cmake-to-build-universal-windows-app>
+
+## Build instructions for Linux / Unix
+Open a terminal and got to your repository. You can generate the makefiles and build the library via:
+
+```bash
+cmake CMakeLists.txt
+make -j4
+```
+The option -j descripes the number of parallel processes for the build. In this case make will try to use 4 cores for the build.
+
+If you want to use a IDE for linux you can try QTCreator for instance. 
+
+## Build instructions for MinGW
+ Older versions of MinGW's compiler (e.g. 5.1.0) do not support the -mbig_obj flag 
+required to compile some of assimp's files, especially for debug builds.
+Version 7.3.0 of g++-mingw-w64 & gcc-mingw-w64 appears to work.
+
+Please see [CMake Cross Compiling](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling) for general information on CMake Toolchains.
+
+Some users have had success building assimp using MinGW on Linux using [polly](https://github.com/ruslo/polly/).
+
+The following toolchain, which is not maintained by assimp, seems to work on Linux: [linux-mingw-w64-gnuxx11.cmake](https://github.com/ruslo/polly/blob/master/linux-mingw-w64-gnuxx11.cmake)
+
+The following toolchain may or may not be helpful for building assimp using MinGW on Windows (untested):
+ [mingw-cxx17.cmake](https://github.com/ruslo/polly/blob/master/mingw-cxx17.cmake)
+
+Besides the toolchain, compilation should be the same as for Linux / Unix.
+
+## CMake build options
+The cmake-build-environment provides options to configure the build. The following options can be used:
+- **BUILD_SHARED_LIBS ( default ON )**: Generation of shared libs ( dll for windows, so for Linux ). Set this to OFF to get a static lib.
+- **BUILD_FRAMEWORK ( default OFF, MacOnly)**: Build package as Mac OS X Framework bundle
+- **ASSIMP_DOUBLE_PRECISION( default OFF )**: All data will be stored as double values.
+- **ASSIMP_OPT_BUILD_PACKAGES ( default OFF)**: Set to ON to generate CPack configuration files and packaging targets
+- **ASSIMP_ANDROID_JNIIOSYSTEM ( default OFF )**: Android JNI IOSystem support is active
+- **ASSIMP_NO_EXPORT ( default OFF )**: Disable Assimp's export functionality
+- **ASSIMP_BUILD_ZLIB ( default OFF )**: Build your own zlib
+- **ASSIMP_BUILD_ASSIMP_TOOLS ( default ON )**: If the supplementary tools for Assimp are built in addition to the library.
+- **ASSIMP_BUILD_SAMPLES ( default OFF )**: If the official samples are built as well (needs Glut).
+- **ASSIMP_BUILD_TESTS ( default ON )**: If the test suite for Assimp is built in addition to the library.
+- **ASSIMP_COVERALLS ( default OFF )**: Enable this to measure test coverage.
+- **ASSIMP_WERROR( default OFF )**: Treat warnings as errors.
+- **ASSIMP_ASAN ( default OFF )**: Enable AddressSanitizer.
+- **ASSIMP_UBSAN ( default OFF )**: Enable Undefined Behavior sanitizer.
+- **SYSTEM_IRRXML ( default OFF )**: Use system installed Irrlicht/IrrXML library.
+- **BUILD_DOCS ( default OFF )**: Build documentation using Doxygen.
+- **INJECT_DEBUG_POSTFIX( default ON )**: Inject debug postfix in .a/.so lib names
+- **IGNORE_GIT_HASH ( default OFF )**: Don't call git to get the hash.
+- **ASSIMP_INSTALL_PDB ( default ON )**: Install MSVC debug files.

+ 408 - 6
CHANGES

@@ -1,6 +1,413 @@
 ----------------------------------------------------------------------
 CHANGELOG
 ----------------------------------------------------------------------
+4.1.0 (2017-12):
+- FEATURES:
+ - Export 3MF ( experimental )
+ - Import / Export glTF 2
+ - Introduce new zib-lib to eb able to export zip-archives
+- FIXES/HOUSEKEEPING:
+ - Added missing include to stdlib.h and remove load library call
+ - Fix install for builds with MSVC compiler and NMake.
+ - Update list of supported file formats.
+ - Add TriLib to the official list of supported ports.
+ - Re-enabling PACK_STRUCT for MDL files.
+ - Use std.::unique_ptr
+ - Update D3MFExporter.h
+ - Update MD3Loader.cpp, using index
+ - Fix all warnings on MSVC14
+ - Copy assimp dll to unit folder on windows
+ - Update jvm port supported formats
+ - Add support for building Mac OS X Framework bundles
+ - Check for nullptr dereferencing before copying scene data
+ - Update ValidateDataStructure.h, typo
+ - Enable data structure validation in cases where it doesn't cause failures
+ - Remove some dead assignments
+ - fast_atof: Silence some uninitialized variable warnings
+ - Check for area test if the face is a triangle.
+ - Set mNumUVComponents to 0 when deleting texture coordinate sets
+ - Only scale the root node because this will rescale all children nodes as well.
+ - Issue 1514: Fix frame pointer arithmetic
+ - Prevent failing stringstream to crash the export process
+ - powf -> pow
+ - add Defines.h to include folder for install.
+ - Android:
+  - Fix android build
+  - Fix assimp for cross compile for android
+  - Use define for D_FILE_OFFSET_BITS only for not-android systems.
+ - FBX:
+  - Fix handling with embedded textures
+  - FBX 7500 Binary reading
+  - Remove dead assignment
+  - Fix export of deleted meshes; Add LazyDict::Remove method
+  - Log an error instead of letting the fbx-importer crash. ( issue 213 )
+  - Replace bad pointer casting with memcpy
+  - Remove useless const qualifier from return value
+  - Add explicit instantiation of log_prefix so other FBX source files can see it
+  - add missing inversion of postrotation matrix for fbx.
+  - FIReader: Silence uninitialized variable warning
+  - Update version check in FBX reader to check for version >= 7500
+  - Use actual min/max of anim keys when start/stop time is missing
+- GLTF1:
+ - Fix output of glTF 1 version string
+ - Fix delete / delete[] mismatch in glTFAsset
+ - Don’t ignore rgba(1,1,1,1) color properties
+ - glTF2 primitives fixes
+ - Don’t ignore rgba(1,1,1,1) color properties
+ - Fix delete / delete[] mismatch in glTFAsset
+ - Remove KHR_binary_glTF code
+ - glTF nodes can only hold one mesh. this simply assigns to and check’s a Node’s Mesh
+ - version in glb header is stored as uint32_t
+- GLTF2:
+ - node name conflict fix
+ - Fix transform matrices multiplication order
+ - Preserve node names when importing
+ - Add support for tangents in import
+ - Fix typo on gltf2 camera parameters
+ - Moved byteStride from accessor to bufferView
+ - Implemented reading binary glTF2 (glb) files
+ - Fix signed/unsigned warning
+ - Add postprocess step for scaling
+ - Fix shininess to roughness conversion
+ - Prefer “BLEND” over “MASK” as an alphaMode default
+ - Approximate specularity / glossiness in metallicRoughness materials
+ - Diffuse color and diffuse texture import and export improvements
+ - Addressed some mismatched news/deletes caused by the new glTF2 sources.
+ - Fix delete / delete[] mismatches in glTF2 importer
+ - use correct name of exporter to gltf2
+ - Fix possible infinite loop when exporting to gltf2
+ - Fix glTF2::Asset::FindUniqueID() when the input string is >= 256 chars
+ - Fix glTF2 alphaMode storage and reading
+ - Fix glTF 2.0 multi-primitive support
+ - Load gltf .bin files from correct directory
+ - Add support for importing both glTF and glTF2 files
+ - ampler improvements; Add new LazyDict method
+ - Changes to GLTF2 materials
+ - Remove Light, Technique references
+ - Start removing materials common, and adding pbrSpecularGlossiness
+ - Use !ObjectEmpty() vs. MemberCount() > 0
+ - Working read, import, export, and write of gltf2 (pbr) material
+ - Check in gltf2 models to test directory
+ - Remove un-needed test models
+ - Start managing and importing gltf2 pbr materials
+ - Update glTF2 Asset to use indexes
+ - Duplicate gltfImporter as gltf2Importer; Include glTF2 importer in CMake List
+ - glTF2: Fix animation export
+ - use opacity for diffuse alpha + alphaMode
+- STL:
+ - Restore import of multi mesh binary STLs
+- Blender:
+ - Silence warning about uninitialized member
+- MDLImporter:
+ - Don't take address of packed struct member
+- assimp_cmd:
+ - Fix strict-aliasing warnings
+- Open3DGC:
+ - Fix strict-aliasing warnings
+ - Add assertions to silence static analyzer warnings
+ - Remove redundant const qualifiers from return types
+ - Fix some uninitialized variable warnings
+ - Remove OPEN3DGC and compression references
+- unzip:
+ - Remove dead assignment
+ - Bail on bad compression method
+ - Fix possibly uninitialized variables
+- clipper:
+ - Add assertion to silence a static analyzer warning
+- OpenDDLExport:
+ - Reduce scope of a variable
+ - Remove dead variable
+ - Remove dead assignment
+ - Fix another potential memory leak
+- X3DImporter:
+ - Add assertions to silence static analyzer warnings
+ - Add missing unittest
+ - Workaround for buggy Android NDK (issue #1361)
+- TerragenLoader:
+ - Remove unused variable
+- SIBImporter:
+ - Add assertions to silence static analyzer warnings
+- IFC:
+ - Remove dead code
+ - Add explicit instantiation of log_prefix so IFCMaterial.cpp can see it
+- PLY:
+ - Remove dead assignment and reduce scope of a variable
+ - fix vertex attribute lookup.
+- OpenGEX:
+ - Add assertion to silence a static analyzer warning
+ - Fix for TextureFile with number in file name
+ - Return early when element is TextureFile
+- NFF:
+ - Add assertions to silence static analyzer warnings
+ - Split up some complicated assignments
+- Raw: Fix misleading indentation warning
+ - Reduce scope of a variable
+- LWO
+ - Reduce scope of a variable
+- IRRLoader:
+ - Fix confusing boolean casting
+- AssbinExporter:
+ - Add assertion to silence a static analyzer warning
+- ASE:
+ - Add assertion to silence a static analyzer warning
+- AMFImporter:
+ - Add assertion to silence a static analyzer warning
+ - Add a block
+- OptimizeGraph:
+ - Fix possible null pointer dereference
+ - RemoveRedundantMaterials:
+ - Add assertion to silence a static analyzer warning
+- ImproveCacheLocality:
+ - Add assertion to silence a static analyzer warning
+- RemoveRedundantMaterials:
+ - Set pointer to nullptr after deleting it
+- Travis:
+ - Disable unit tests in scan-build config
+ - Move slower builds earlier to improve parallelization
+ - Add static analysis to build
+ - Remove unused branch rule for travis.
+ - Add Clang UBSan build configuration
+ - Treat warnings as errors, without typos this time
+- Unittests:
+ - Add VS-based source groups for the unittests.
+- Collada:
+ - export <library_animations> tag
+ - Update ColladaExporter.cpp
+ - Silence uninitialized variable warning
+ - Add support for line strip primitives
+- Obj Wavefront:
+ - check in exporting against out-of-bounds-access .
+ - Issue 1351: use correct name for obj-meshname export for groups.
+ - fix mem-lead: face will be not released in case of an error.
+ - Anatoscope obj exporter nomtl
+ - Raise exception when obj file contains invalid face indices
+ - Added alternative displacement texture token in OBJ MTL material.
+ - Obj: rename attribute from exporter.
+ - Fix OBJ discarding all material names if the material library is missing
+- Step:
+ - use correct lookup for utf32
+- MD2:
+ - Fix MD2 frames containing garbage
+- STL
+ - add missing const.
+ - Fix memory-alignment bug.
+ - Fix issue 104: deal with more solids in one STL file.
+- CMake
+ - Fix issue 213: use correct include folder for assimp
+- Doxygen
+ - Fix issue 1513: put irrXML onto exclucde list for doxygen run
+- PyAssimp:
+ - Search for libassimp.so in LD_LIBRARY_PATH if available.
+ - Fix operator precedence issue in header check
+ - Split setup.py into multiple lines
+ - Detect if Anaconda and fixed 3d_viewer for Python 3
+ - created a python3 version of the 3dviewer and fixed the / = float in py3
+- Blender:
+ - Fix invalid access to mesh array when the array is empty.
+ - Fix short overflow.
+ - Silence warning about inline function which is declared but not defined
+- JAssimp
+ - Changed license header for IHMC contributions from Apache 2.0 to BSD
+ - Add Node metadata to the Jassmip Java API
+ - Added supported for custom IO Systems in Java. Implemented ClassLoader IO System
+ - Added a link to pure jvm assimp port
+- Clang sanitizer:
+ - Undefined Behavior sanitizer
+ - Fixed a divide by zero error in IFCBoolean that was latent, but nevertheless a bug
+- B3DImporter:
+ - Replace bad pointer casting with memcpy
+- AppVeyor:
+ - Cleanup and Addition of VS 2017 and running Tests
+ - Fixed File Size reported as 0 in tests that use temporary files
+ - x86 isn't a valid VS platform. Win32 it is, then.
+ - Replaced the worker image name, which doesn't work as generator name, with a manually created generator name.
+ - Cleaned up appveyor setup, added VS 2017 to the build matrix and attempted to add running of tests.
+ - Treat warnings as errors on Appveyor
+ - Disable warning 4351 on MSVC 2013
+- OpenGEXImporter:
+ - Copy materials to scene
+ - Store RefInfo in unique_ptr so they get automatically cleaned up
+ - Fix IOStream leak
+ - Store ChildInfo in unique_ptr so they get automatically cleaned up
+ - improve logging to be able to detect error-prone situations.
+-  AMFImporter:
+ - Fix memory leak
+- UnrealLoader:
+ - Fix IOStream leak
+- Upgrade RapidJSON to get rid of a clang warning
+- zlib:
+ - Update zlib contribution
+ - Removed unnecessary files from zlib contribution
+ - Replaced unsigned long for the crc table to z_crc_t, to match what is returned by get-crc_table
+- MakeVerboseFormat:
+  - Fix delete / delete[] mismatches in MakeVerboseFormat
+- MaterialSystem:
+ - Fix out-of-bounds read in MaterialSystem unit test
+- SIB:
+ - Added support for SIB models from Silo 2.5
+- AssbinExporter:
+ - Fix strict aliasing violation
+ - Add Write specialization for aiColor3D
+- DefaultLogger:
+ - Whitespace cleanup to fix GCC misleading indentation warning
+- MDP:
+ - Fix encoding issues.
+ - PreTransformVertices:
+ - fix name lost in mesh and nodes when load with flag
+- C4D:
+ - Fixes for C4D importer
+- Unzip:
+ - Latest greatest.
+
+4.0.1 (2017-07-28)
+    - FIXES/HOUSEKEEPING:
+    - fix version test.
+    - Not compiling when using ASSIMP_DOUBLE_PRECISION
+    - Added support for python3
+    - Check if cmake is installed with brew
+    - Low performance in OptimizeMeshesProcess::ProcessNode with huge numbers of meshes
+    - Elapsed seconds not shown correctly
+    - StreamReader: fix out-of-range exception
+    - PPdPmdParser: fix compilation for clang
+
+
+4.0.0 (2017-07-18)
+
+FEATURES:
+    - Double precision support provided ( available via cmake option )
+	- QT-Widget based assimp-viewer ( works for windows, linux, osx )
+	- Open3DGC codec supported by glFT-importer
+	- glTF: Read and write transparency values
+	- Add Triangulate post-processing step to glTF exporters
+	- Update rapidjson to v1.0.2
+	- Added method to append new metadata to structure
+	- Unittests: intoduce a prototype model differ
+	- X3D support
+	- AMF support
+	- Lugdunum3D support
+	- Obj-Importer: obj-homogeneous_coords support
+	- Obj-Importer: new streaming handling
+	- Added support for 64 bit version header introduced in FbxSdk2016
+	- Travis: enable coverall support.
+	- PyAssimp: New version of the pyASSIMP 3D viewer, with much improved 3D controls
+    - Morph animation support for collada	
+	- Added support for parameters Ni and Tf in OBJ/MTL file format
+	- aiScene: add method to add children
+	- Added new option to IFC importer to control tessellation angle + removed unused IFC option
+	- aiMetaData: introduce aiMetaData::Dealloc
+	- Samples: add a DX11 example
+	- travis ci: test on OXS ( XCode 6.3 ) as well
+	- travis ci: enable sudo support.
+	- openddlparser: integrate release v0.4.0
+	- aiMetaData: Added support for metadata in assbin format
+	
+FIXES/HOUSEKEEPING:
+    - Introduce usage of #pragma statement
+	- Put cmake-scripts into their own folder
+	- Fix install pathes ( issue 938 )
+	- Fix object_compare in blender importer( issue 946 )
+	- Fix OSX compilation error
+	- Fix unzip path when no other version was found ( issue 967 )
+	- Set _FILE_OFFSET_BITS=64 for 32-bit linux ( issue 975 )
+	- Fix constructor for radjson on OSX
+	- Use Assimp namespace to fix build for big-endian architectures
+	- Add -fPIC to C Flags for 64bit linux Shared Object builds
+	- MDLLoader: fix resource leak.
+	- MakeVerboseFormat: fix invalid delete statement
+	- IFC: fix possible use after free access bug
+	- ComputeUVMappingprocess: add missing initialization for scalar value
+    - Fix invalid release of mat + mesh
+	- IrrImporter: Fix release functions
+	- Split mesh before exporting gltf ( issue 995 )
+	- 3MFImporter: add source group for visual studio
+	- IFC: Switch generated file to 2 files to fix issue related to <mingw4.9 ( Thanks Qt! )
+	- ObjImporter: fix test for vertices import
+    - export scene combiner ( issues177 )
+	- FBX: make lookup test less strict ( issues 994 )
+	- OpenGEX-Importer: add import of vertex colors ( issue 954 )
+	- fix bug when exporting mRotationKeys data
+	- fix mingw build (mingw supports stat64 nowadays)
+	- cfileio: fix leaks by not closing files in the destructor
+	- Fix OBJ parser mtllib statement parsing bug.
+	- Q3BSP-Importer: remove dead code
+	- Fix BlenderDNA for clang cross compiler.
+	- ScenePreprocessor: fix invalid index counter.
+	- Fix compiler warnings ( issue 957 )
+	- Fix obj .mtl file loading
+	- Fixed a compile error on MSVC14 x64 caused by the /bigobj flag failing to be set for the 1 and 2-suffixed versions introduced in commit 0a25b076b8968b7ea2aa96d7d1b4381be2d72ce6
+	- Fixed build warnings on MSVC14 x64
+	- Remove scaling of specular exponent in OBJFileImporter.cpp
+	- use ai_assert instead of assert ( issue 1076 )
+	- Added a preprocessor definition for MSVC to silence safety warnings regarding C library functions. This addresses all warnings for MSVC x86 and x64 when building zlib, tools and viewer as a static lib
+	- fix parsing of texture name ( issue 899 )
+	- add warning when detecting invalid mat definition ( issue 1111 )
+	- copy aiTexture type declaration instead of using decltype for declaration to fix iOS build( issue 1101 )
+	- FBX: Add additional material properties
+	- FBX: Correct camera position and clip planes
+    - FBX: Add correct light locations and falloff values
+	- fix typo ( issue 1141 )
+	- Fix collada export. Don't duplicate TEXCOORD/NORMALS/COLORS in <vertices> and <polylist> ( issue 1084 )
+	- OBJParser: set material index when changing current material
+	- OBJ: check for null mesh before updating material index
+	- add vertex color export support ( issue 809 )
+	- Fix memory leak in Collada importer ( issue 1169 )
+	- add stp to the list of supported extensions for step-files ( issue 1183 )
+	- fix clang build ( Issue-1169 ) 
+	- fix for FreeBSD
+	- Import FindPkgMacros to main CMake Configuration
+	- Extended support for tessellation parameter to more IFC shapes
+	- defensice handling of utf-8 decode issues ( issue 1211 )
+	- Fixed compiler error on clang 4.0 running on OSX
+	- use test extension for exported test files ( issue 1228 )
+	- Set UVW index material properties for OBJ files
+	- Fixed no member named 'atop' in global namespace issue for Android NDK compilation
+	- Apply mechanism to decide use for IrrXML external or internal
+	- Fix static init ordering bug in OpenGEX importer
+	- GLTF exporter: ensure animation accessors have same count
+	- GLTF exporter: convert animation time from ticks to seconds
+	- Add support for reading texture coordinates from PLY meshes with properties named 'texture_u' and 'texture_v'
+	- Added TokensForSearch in BlenderLoader to allow CanRead return true for in-memory files.
+	- fix wrong delete ( issue 1266 )
+	- OpenGEX: fix invalid handling with color4 token ( issue 1262 )
+	- LWOLoader: fix link in loader description
+	- Fix error when custom CMAKE_C_FLAGS is specified
+	- Fast-atof: log overflow errors
+	- Obj-Importer: do not break when detecting an overflow ( issue 1244 )
+	- Obj-Importer: fix parsing of multible line data definitions
+	- Fixed bug where IFC models with multiple IFCSite only loaded 1 site instead of the complete model
+	- PLYImporter: - optimize memory and speed on ply importer / change parser to use a file stream - manage texture path in ply 
+	  import - manage texture coords on faces in ply import - correction on point cloud faces generation
+	- Utf8: integrate new lib ( issue 1158 )
+	- fixed CMAKE_MODULE_PATH overwriting previous values
+	- OpenGEX: Fixed bug in material color processing ( issue 1271 )
+	- SceneCombiner: move header for scenecombiner to public folder.
+	- GLTF exporter: ensure buffer view byte offsets are correctly aligned
+	- X3D importer: Added EXPORT and IMPORT to the list of ignored XML tags
+    - X3D Exporter: fixed missing attributes
+    - X3D importer: Fixed import of normals for the single index / normal per vertex case
+    - X3D importer: Fixed handling of inlined files
+    - X3D importer: fixed whitespace handling (issue 1202)
+	- X3D importer: Fixed iterator on MSVC 2015
+    - X3D importer: Fixed problems with auto, override and regex on older compilers
+    - X3D importer: Fixed missing header file
+    - X3D importer: Fixed path handling
+	- X3D importer: Implemented support for binary X3D files
+    - fix build without 3DS ( issue 1319 )
+	- pyassimp: Fixed indices for IndexedTriangleFanSet, IndexedTriangleSet and IndexedTriangleStripSet
+	- Fixes parameters to pyassimp.load
+	- Obj-Importe: Fixed texture bug due simultaneously using 'usemtl' and 'usemap' attributes
+	- check if all exporters are disabled ( issue 1320 )
+	- Remove std functions deprecated by C++11.
+	- X-Importer: make it deal with lines
+	- use correct path for compilers ( issue 1335 )
+	- Collada: add workaround to deal with polygon with holes 
+	- update python readme
+	- Use unique node names when loading Collada files
+	- Fixed many FBX bugs
+
+API COMPATIBILITY:
+    - Changed ABI-compatibility to v3.3.1, please rebuild your precompiled libraries ( see issue 1182 )
+	- VS2010 outdated
 
 3.3.1 (2016-07-08)
 
@@ -121,8 +528,6 @@ API COMPATIBILITY:
    - Note: 3.0 is not binary compatible with 2.0
 
 
-
-
 2.0 (2010-11-21)
 
 FEATURES:
@@ -159,10 +564,7 @@ API CHANGES:
      currently used, however ...)
    - Some Assimp::Importer methods are const now.
 
-
-
-
-
+   
 1.1 (2010-04-17)
 This is the list of relevant changes from the 1.0 (r412) release to 1.1 (r700).
 

+ 250 - 138
CMakeLists.txt

@@ -1,6 +1,7 @@
 # Open Asset Import Library (assimp)
 # ----------------------------------------------------------------------
-# Copyright (c) 2006-2017, assimp team
+# Copyright (c) 2006-2019, assimp team
+
 # All rights reserved.
 #
 # Redistribution and use of this software in source and binary forms,
@@ -34,14 +35,20 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #----------------------------------------------------------------------
 SET(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required
-cmake_minimum_required( VERSION 2.8 )
+CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )
 PROJECT( Assimp )
 
 # All supported options ###############################################
+
 OPTION( BUILD_SHARED_LIBS
   "Build package with shared libraries."
   ON
 )
+
+OPTION( BUILD_FRAMEWORK
+  "Build package as Mac OS X Framework bundle."
+  OFF
+)
 OPTION( ASSIMP_DOUBLE_PRECISION
   "Set to ON to enable double precision processing"
   OFF
@@ -60,13 +67,13 @@ OPTION( ASSIMP_NO_EXPORT
 )
 OPTION( ASSIMP_BUILD_ZLIB
   "Build your own zlib"
-  OFF
+  OFF  
 )
-option( ASSIMP_BUILD_ASSIMP_TOOLS
+OPTION( ASSIMP_BUILD_ASSIMP_TOOLS
   "If the supplementary tools for Assimp are built in addition to the library."
   ON
 )
-option ( ASSIMP_BUILD_SAMPLES
+OPTION ( ASSIMP_BUILD_SAMPLES
   "If the official samples are built as well (needs Glut)."
   OFF
 )
@@ -75,95 +82,130 @@ OPTION ( ASSIMP_BUILD_TESTS
   ON
 )
 OPTION ( ASSIMP_COVERALLS
-   "Eańable this to measure test coverage."
-   OFF
+  "Enable this to measure test coverage."
+  OFF
 )
-option ( SYSTEM_IRRXML
-    "Use system installed Irrlicht/IrrXML library."
-    OFF
+OPTION ( ASSIMP_WERROR
+  "Treat warnings as errors."
+  OFF
+)
+OPTION ( ASSIMP_ASAN
+  "Enable AddressSanitizer."
+  OFF
+)
+OPTION ( ASSIMP_UBSAN
+  "Enable Undefined Behavior sanitizer."
+  OFF
+)
+OPTION ( SYSTEM_IRRXML
+  "Use system installed Irrlicht/IrrXML library."
+  OFF
 )
 OPTION ( BUILD_DOCS
-   "Build documentation using Doxygen."
+  "Build documentation using Doxygen."
+  OFF
+)
+OPTION( INJECT_DEBUG_POSTFIX
+  "Inject debug postfix in .a/.so/.dll lib names"
+  ON
+)
+
+OPTION ( IGNORE_GIT_HASH
+   "Don't call git to get the hash."
    OFF
 )
 
+IF (IOS)
+  IF (NOT CMAKE_BUILD_TYPE)
+    SET(CMAKE_BUILD_TYPE "Release")
+  ENDIF (NOT CMAKE_BUILD_TYPE)
+  ADD_DEFINITIONS(-DENABLE_BITCODE)
+ENDIF (IOS)
+
+# Use subset of Windows.h
 if (WIN32)
-    add_definitions( -DWIN32_LEAN_AND_MEAN )
+  ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
 endif()
 
 IF(MSVC)
-  set (CMAKE_PREFIX_PATH "D:\\libs\\devil")
   OPTION( ASSIMP_INSTALL_PDB
     "Install MSVC debug files."
     ON
   )
+  IF(NOT (MSVC_VERSION LESS 1900))
+    # Multibyte character set is deprecated since at least MSVC2015 (possibly earlier)
+    ADD_DEFINITIONS( -DUNICODE -D_UNICODE )
+  ENDIF()
 ENDIF(MSVC)
 
+IF (BUILD_FRAMEWORK)
+  SET (BUILD_SHARED_LIBS ON)
+  MESSAGE(STATUS "Framework bundle building enabled")
+ENDIF(BUILD_FRAMEWORK)
+
 IF(NOT BUILD_SHARED_LIBS)
+  MESSAGE(STATUS "Shared libraries disabled")
   SET(LINK_SEARCH_START_STATIC TRUE)
+ELSE()
+  MESSAGE(STATUS "Shared libraries enabled")
 ENDIF(NOT BUILD_SHARED_LIBS)
 
 # Define here the needed parameters
-SET (ASSIMP_VERSION_MAJOR 3)
-SET (ASSIMP_VERSION_MINOR 3)
-SET (ASSIMP_VERSION_PATCH 1) # subversion revision?
+SET (ASSIMP_VERSION_MAJOR 4)
+SET (ASSIMP_VERSION_MINOR 1)
+SET (ASSIMP_VERSION_PATCH 0)
 SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
-SET (ASSIMP_SOVERSION 3)
+SET (ASSIMP_SOVERSION 4)
 SET (PROJECT_VERSION "${ASSIMP_VERSION}")
 
-SET(ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources")
+SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
 
-# Needed for openddl_parser config, no use of c++11 at this moment
-add_definitions( -DOPENDDL_NO_USE_CPP11 )
+# Enable C++11 support globally
 set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
 
-# Get the current working branch
-EXECUTE_PROCESS(
-  COMMAND git rev-parse --abbrev-ref HEAD
-  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-  OUTPUT_VARIABLE GIT_BRANCH
-  OUTPUT_STRIP_TRAILING_WHITESPACE
-  ERROR_QUIET
-)
+IF(NOT IGNORE_GIT_HASH)
+  # Get the current working branch
+  EXECUTE_PROCESS(
+    COMMAND git rev-parse --abbrev-ref HEAD
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+    OUTPUT_VARIABLE GIT_BRANCH
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    ERROR_QUIET
+  )
 
-# Get the latest abbreviated commit hash of the working branch
-EXECUTE_PROCESS(
-  COMMAND git log -1 --format=%h
-  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-  OUTPUT_VARIABLE GIT_COMMIT_HASH
-  OUTPUT_STRIP_TRAILING_WHITESPACE
-  ERROR_QUIET
-)
+  # Get the latest abbreviated commit hash of the working branch
+  EXECUTE_PROCESS(
+    COMMAND git rev-parse --short=8 HEAD
+    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+    OUTPUT_VARIABLE GIT_COMMIT_HASH
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    ERROR_QUIET
+  )
+ENDIF()
 
 IF(NOT GIT_COMMIT_HASH)
   SET(GIT_COMMIT_HASH 0)
 ENDIF(NOT GIT_COMMIT_HASH)
 
 IF(ASSIMP_DOUBLE_PRECISION)
-  ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
+    ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION)
 ENDIF(ASSIMP_DOUBLE_PRECISION)
 
-# Check for OpenMP support
-find_package(OpenMP)
-if (OPENMP_FOUND)
-    set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
-    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
-endif()
-
-configure_file(
+CONFIGURE_FILE(
   ${CMAKE_CURRENT_LIST_DIR}/revision.h.in
   ${CMAKE_CURRENT_BINARY_DIR}/revision.h
 )
 
-configure_file(
+CONFIGURE_FILE(
   ${CMAKE_CURRENT_LIST_DIR}/include/assimp/config.h.in
   ${CMAKE_CURRENT_BINARY_DIR}/include/assimp/config.h
 )
 
-include_directories(
-    ./
-    ${CMAKE_CURRENT_BINARY_DIR}
-    ${CMAKE_CURRENT_BINARY_DIR}/include
+INCLUDE_DIRECTORIES( BEFORE
+  ./
+  include
+  ${CMAKE_CURRENT_BINARY_DIR}
+  ${CMAKE_CURRENT_BINARY_DIR}/include
 )
 
 LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" )
@@ -173,39 +215,78 @@ SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPO
 SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
 
 IF( UNIX )
-  # Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
-  IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
-    ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
-  ENDIF()
-
   # Use GNUInstallDirs for Unix predefined directories
-  include(GNUInstallDirs)
+  INCLUDE(GNUInstallDirs)
 ENDIF( UNIX )
 
-
 # Grouped compiler settings
 IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
   # hide all not-exported symbols
-  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -std=c++0x")
-  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -std=c++0x ${CMAKE_CXX_FLAGS}")
+  SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}")
   SET(LIBSTDC++_LIBRARIES -lstdc++)
 ELSEIF(MSVC)
   # enable multi-core compilation with MSVC
-  add_compile_options(/MP)
+  ADD_COMPILE_OPTIONS(/MP)
+  ADD_COMPILE_OPTIONS( /bigobj )
+  # disable "elements of array '' will be default initialized" warning on MSVC2013
+  IF(MSVC12)
+    ADD_COMPILE_OPTIONS(/wd4351)
+  ENDIF()
 ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -pedantic -std=c++11" )
+  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 ${CMAKE_CXX_FLAGS}" )
+  SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}")
 ELSEIF( CMAKE_COMPILER_IS_MINGW )
-  SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wno-long-long -pedantic -std=c++11" )
-  add_definitions( -U__STRICT_ANSI__ )
+  IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0)
+    message(FATAL_ERROR "MinGW is too old to be supported. Please update MinGW and try again.")
+  ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3)
+    message(WARNING "MinGW is old, if you experience errors, update MinGW.")
+  ENDIF()
+  SET( CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}" )
+  SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS} ")
+  ADD_DEFINITIONS( -U__STRICT_ANSI__ )
 ENDIF()
 
-if (ASSIMP_COVERALLS)
-    include(Coveralls)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
-endif()
+IF ( IOS )
+
+IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og")
+ELSE()
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
+ENDIF()
+
+ENDIF( IOS )
+
+IF (ASSIMP_COVERALLS)
+  MESSAGE(STATUS "Coveralls enabled")
+  INCLUDE(Coveralls)
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
+ENDIF()
+
+IF (ASSIMP_WERROR)
+  MESSAGE(STATUS "Treating warnings as errors")
+  IF (MSVC)
+    ADD_COMPILE_OPTIONS(/WX)
+  ELSE()
+    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
+    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
+  ENDIF()
+ENDIF()
 
-INCLUDE_DIRECTORIES( include )
+IF (ASSIMP_ASAN)
+  MESSAGE(STATUS "AddressSanitizer enabled")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
+ENDIF()
+
+IF (ASSIMP_UBSAN)
+  MESSAGE(STATUS "Undefined Behavior sanitizer enabled")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
+ENDIF()
 
 INCLUDE (FindPkgMacros)
 INCLUDE (PrecompiledHeader)
@@ -228,7 +309,9 @@ SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING
 SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
   "Path the tool executables are installed to." )
 
-IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
+get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
+
+IF (is_multi_config OR (CMAKE_BUILD_TYPE STREQUAL "Debug"))
   SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools")
 ELSE()
   SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools")
@@ -237,50 +320,81 @@ ENDIF()
 # Only generate this target if no higher-level project already has
 IF (NOT TARGET uninstall)
   # add make uninstall capability
-  configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
-  add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
+  CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
+  ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
 ENDIF()
 
 # cmake configuration files
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
-configure_file("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
-install(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake"             "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
+CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
+CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in"         "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
+CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in"   "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE)
+CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE)
+CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
+#we should generated these scripts after CMake VERSION 3.0.2 using export(EXPORT ...) and write_basic_package_version_file(...)
+INSTALL(FILES 
+  "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake"
+  "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake"
+  "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake"
+  "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake"
+  "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake"
+  DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
 
 FIND_PACKAGE( DirectX )
 
 IF( BUILD_DOCS )
-    add_subdirectory(doc)
+  ADD_SUBDIRECTORY(doc)
 ENDIF( BUILD_DOCS )
 
 # Look for system installed irrXML
 IF ( SYSTEM_IRRXML )
-    find_package( IrrXML REQUIRED )
+  FIND_PACKAGE( IrrXML REQUIRED )
 ENDIF( SYSTEM_IRRXML )
 
 # Search for external dependencies, and build them from source if not found
 # Search for zlib
 IF ( NOT ASSIMP_BUILD_ZLIB )
-    find_package(ZLIB)
+  FIND_PACKAGE(ZLIB)
 ENDIF( NOT ASSIMP_BUILD_ZLIB )
 
 IF( NOT ZLIB_FOUND )
-  message(STATUS "compiling zlib from souces")
-  include(CheckIncludeFile)
-  include(CheckTypeSize)
-  include(CheckFunctionExists)
+  MESSAGE(STATUS "compiling zlib from sources")
+  INCLUDE(CheckIncludeFile)
+  INCLUDE(CheckTypeSize)
+  INCLUDE(CheckFunctionExists)
+
+  # Explicitly turn off ASM686 and AMD64 cmake options.
+  # The AMD64 option causes a build failure on MSVC and the ASM builds seem to have problems:
+  #		https://github.com/madler/zlib/issues/41#issuecomment-125848075
+  # Also prevents these options from "polluting" the cmake options if assimp is being
+  # included as a submodule.
+  set( ASM686 FALSE CACHE INTERNAL "Override ZLIB flag to turn off assembly" FORCE )
+  set( AMD64 FALSE CACHE INTERNAL "Override ZLIB flag to turn off assembly" FORCE )
+
   # compile from sources
-  add_subdirectory(contrib/zlib)
+  ADD_SUBDIRECTORY(contrib/zlib)
   SET(ZLIB_FOUND 1)
   SET(ZLIB_LIBRARIES zlibstatic)
   SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
-else(NOT ZLIB_FOUND)
+  # need to ensure we don't link with system zlib or minizip as well.
+  SET(ASSIMP_BUILD_MINIZIP 1)
+ELSE(NOT ZLIB_FOUND)
   ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
   SET(ZLIB_LIBRARIES_LINKED -lz)
 ENDIF(NOT ZLIB_FOUND)
 INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
 
 # Search for unzip
-use_pkgconfig(UNZIP minizip)
+IF ( NOT IOS )
+  IF( NOT ASSIMP_BUILD_MINIZIP )
+	  use_pkgconfig(UNZIP minizip)
+  ENDIF( NOT ASSIMP_BUILD_MINIZIP )
+ELSE ( NOT IOS )
+	IF(NOT BUILD_SHARED_LIBS)
+    IF( NOT ASSIMP_BUILD_MINIZIP )
+		  use_pkgconfig(UNZIP minizip)
+    ENDIF( NOT ASSIMP_BUILD_MINIZIP )
+	ENDIF (NOT BUILD_SHARED_LIBS)
+ENDIF ( NOT IOS )
 
 IF ( ASSIMP_NO_EXPORT )
   ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT)
@@ -315,7 +429,9 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
     SET(C4D_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/contrib/Melange/includes")
 
     # pick the correct prebuilt library
-    IF(MSVC14)
+    IF(MSVC15)
+      SET(C4D_LIB_POSTFIX "_2017")
+    ELSEIF(MSVC14)
       SET(C4D_LIB_POSTFIX "_2015")
     ELSEIF(MSVC12)
       SET(C4D_LIB_POSTFIX "_2013")
@@ -356,44 +472,22 @@ ADD_SUBDIRECTORY(contrib)
 ADD_SUBDIRECTORY( code/ )
 IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
   IF ( WIN32 AND DirectX_D3DX9_LIBRARY )
-    option ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
+    OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
     IF ( ASSIMP_BUILD_ASSIMP_VIEW )
       ADD_SUBDIRECTORY( tools/assimp_view/ )
     ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW )
   ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY )
 
   ADD_SUBDIRECTORY( tools/assimp_cmd/ )
-
-  # Check dependencies for assimp_qt_viewer.
-  # Why here? Maybe user do not want Qt viewer and have no Qt.
-  # Why assimp_qt_viewer/CMakeLists.txt still contain similar check?
-  # Because viewer can be build independently of Assimp.
-  FIND_PACKAGE(Qt5Widgets QUIET)
-  FIND_PACKAGE(DevIL QUIET)
-  FIND_PACKAGE(OpenGL QUIET)
-  IF ( Qt5Widgets_FOUND AND IL_FOUND AND OPENGL_FOUND)
-    ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
-  ELSE()
-    SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "")
-    IF (NOT Qt5_FOUND)
-      SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} Qt5")
-    ENDIF (NOT Qt5_FOUND)
-
-    IF (NOT IL_FOUND)
-      SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} DevIL")
-    ENDIF (NOT IL_FOUND)
-
-    IF (NOT OPENGL_FOUND)
-      SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} OpengGL")
-    ENDIF (NOT OPENGL_FOUND)
-
-    MESSAGE (WARNING "Build of assimp_qt_viewer is disabled. Unsatisfied dendencies: ${ASSIMP_QT_VIEWER_DEPENDENCIES}")
-  ENDIF ( Qt5Widgets_FOUND AND IL_FOUND AND OPENGL_FOUND)
+IF (NOT IOS)
+  ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
+ENDIF (NOT IOS)
 ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
 
 IF ( ASSIMP_BUILD_SAMPLES)
   IF ( WIN32 )
     ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ )
+    ADD_SUBDIRECTORY( samples/SimpleTexturedDirectx11 )
   ENDIF ( WIN32 )
   ADD_SUBDIRECTORY( samples/SimpleOpenGL/ )
 ENDIF ( ASSIMP_BUILD_SAMPLES )
@@ -408,7 +502,7 @@ INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTAL
 
 IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
   # Packing information
-  SET(CPACK_PACKAGE_NAME                    "assimp{ASSIMP_VERSION_MAJOR}")
+  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}")
@@ -420,8 +514,8 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
   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")
+  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}" )
@@ -438,8 +532,8 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
   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/cppunit-1.12.1 contrib/cppunit_note.txt contrib/zlib workspaces test doc obj samples packaging)
+  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
@@ -451,34 +545,52 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
     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)
+  INCLUDE(CPack)
+  INCLUDE(DebSourcePPA)
 ENDIF()
 
 if(WIN32)
   if (CMAKE_SIZEOF_VOID_P EQUAL 8)
     SET(BIN_DIR "${PROJECT_SOURCE_DIR}/bin64/")
     SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib64/")
-  elseif()
+  else()
     SET(BIN_DIR "${PROJECT_SOURCE_DIR}/bin32/")
     SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/")
   ENDIF()
 
-  if(MSVC12)
-    SET(ASSIMP_MSVC_VERSION "vc120")
-  elseif(MSVC14)
-    SET(ASSIMP_MSVC_VERSION "vc140")
-  ENDIF(MSVC12)
-
-  if(MSVC12 OR MSVC14)
-    add_custom_target(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM)
-    add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll	${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM)
-    add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp	${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM)
-    add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.lib	${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.lib VERBATIM)
-    add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll		${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.dll  VERBATIM)
-    add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.exp		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.exp VERBATIM)
-    add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk VERBATIM)
-    add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.lib		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.lib VERBATIM)
-    add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
-  ENDIF(MSVC12 OR MSVC14)
+  IF(MSVC_TOOLSET_VERSION)
+    set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
+  ELSE()
+    IF(MSVC12)
+      SET(ASSIMP_MSVC_VERSION "vc120")
+    ELSEIF(MSVC14)
+      SET(ASSIMP_MSVC_VERSION "vc140")
+    ELSEIF(MSVC15)
+      SET(ASSIMP_MSVC_VERSION "vc141")
+    ENDIF(MSVC12)
+  ENDIF()
+
+  IF(MSVC12 OR MSVC14 OR MSVC15 )
+    ADD_CUSTOM_TARGET(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM)
+    IF(CMAKE_GENERATOR MATCHES "^Visual Studio")
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll	${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp	${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.lib	${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.lib VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll		${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.dll  VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.exp		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.exp VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.lib		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.lib VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
+    ELSE()
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mt.dll	${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mt.exp	${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mt.lib	${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.lib VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll		${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.dll  VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.exp		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.exp VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.lib		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.lib VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
+      ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb		${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM)
+    ENDIF()
+  ENDIF(MSVC12 OR MSVC14 OR MSVC15 )
 ENDIF (WIN32)

+ 10 - 0
CONTRIBUTING.md

@@ -0,0 +1,10 @@
+# How to contribute
+
+If you want to contribute, follow these steps:
+
+- First, create your own clone of assimp.
+- When you want to fix a bug or add a new feature, create a branch on your own fork following [these instructions](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
+- Push it to your fork of the repository and open a pull request.
+- A pull request will start our continuous integration service, which checks if the build works for Linux and Windows.
+  It will check for memory leaks, compiler warnings and memory alignment issues. If any of these tests fail, fix it and the tests will be restarted automatically.
+  - At the end, we will perform a code review and merge your branch to the master branch.

+ 23 - 0
CREDITS

@@ -157,4 +157,27 @@ Contributed ExportProperties interface
 Contributed X File exporter
 Contributed Step (stp) exporter
 
+- Thomas Iorns (mesilliac)
+Initial FBX Export support
 
+For a more detailed list just check: https://github.com/assimp/assimp/network/members
+
+
+========
+Patreons
+========
+
+Huge thanks to our Patreons!
+
+- migenius
+- Marcus
+- Cort
+- elect
+- Steffen
+
+
+===================
+Commercial Sponsors
+===================
+
+- MyDidimo (mydidimo.com): Sponsored development of FBX Export support

+ 10 - 4
INSTALL

@@ -35,10 +35,16 @@ http://www.cmake.org/.
 
 For Unix:
 
-1. cmake CMakeLists.txt -G 'Unix Makefiles'
-2. make
+1. mkdir build && cd build
+2. cmake .. -G 'Unix Makefiles'
+3. make -j4
 
 For Windows:
 1. Open a command prompt
-2. cmake CMakeLists.txt
-2. Open your default IDE and build it
+2. mkdir build
+3. cd build
+4. cmake ..
+5. cmake --build .
+
+For iOS:
+Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS

+ 70 - 37
Readme.md

@@ -1,23 +1,33 @@
 Open Asset Import Library (assimp)
 ==================================
-### Current build status ###
+A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data.
+### Current project status ###
 [![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp)
 [![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp)
 <a href="https://scan.coverity.com/projects/5607">
   <img alt="Coverity Scan Build Status"
        src="https://scan.coverity.com/projects/5607/badge.svg"/>
 </a>
-<span class="badge-patreon"><a href="https://www.patreon.com/assimp" title="Donate to this project using Patreon"><img src="https://img.shields.io/badge/patreon-donate-yellow.svg" alt="Patreon donate button" /></a></span>
 [![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master)
 [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue")
+[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5be56faac64f46fc941ac890fb4febef)](https://www.codacy.com/app/kimkulling/assimp?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=assimp/assimp&amp;utm_campaign=Badge_Grade)
+[![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
 <br>
 
 APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
 
+[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/).
+
 Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
 
 This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
 
+Monthly donations via Patreon:
+<br>[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/assimp)
+
+<br>
+
 One-off donations via PayPal:
 <br>[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4)
 
@@ -25,54 +35,73 @@ One-off donations via PayPal:
 
 Please check our Wiki as well: https://github.com/assimp/assimp/wiki
 
+If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
+
 #### Supported file formats ####
 
-A full list [is here](http://assimp.org/main_features_formats.html).
 __Importers__:
 
-- 3DS
-- BLEND (Blender)
-- DAE/Collada
-- FBX
-- IFC-STEP
+- 3D
+- [3DS](https://en.wikipedia.org/wiki/.3ds)
+- [3MF](https://en.wikipedia.org/wiki/3D_Manufacturing_Format)
+- AC
+- [AC3D](https://en.wikipedia.org/wiki/AC3D)
+- ACC
+- AMJ
 - ASE
-- DXF
-- HMP
+- ASK
+- B3D
+- [BLEND](https://en.wikipedia.org/wiki/.blend_(file_format))
+- [BVH](https://en.wikipedia.org/wiki/Biovision_Hierarchy)
+- CMS
+- COB
+- [DAE/Collada](https://en.wikipedia.org/wiki/COLLADA)
+- [DXF](https://en.wikipedia.org/wiki/AutoCAD_DXF)
+- ENFF
+- [FBX](https://en.wikipedia.org/wiki/FBX)
+- [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB
+- [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0)
+- HMB
+- IFC-STEP
+- IRR / IRRMESH
+- [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
+- LWS
+- LXO
 - MD2
 - MD3
 - MD5
 - MDC
 - MDL
+- MESH / MESH.XML
+- MOT
+- MS3D
+- NDO
 - NFF
-- PLY
-- STL
-- X
-- OBJ
-- OpenGEX
+- [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file)
+- [OFF](https://en.wikipedia.org/wiki/OFF_(file_format))
+- [OGEX](https://en.wikipedia.org/wiki/Open_Game_Engine_Exchange)
+- [PLY](https://en.wikipedia.org/wiki/PLY_(file_format))
+- PMX
+- PRJ
+- Q3O
+- Q3S
+- RAW
+- SCN
+- SIB
 - SMD
-- LWO
-- LXO
-- LWS  
+- [STP](https://en.wikipedia.org/wiki/ISO_10303-21)
+- [STL](https://en.wikipedia.org/wiki/STL_(file_format))
 - TER
-- AC3D
-- MS3D
-- COB
-- Q3BSP
+- UC
+- VTA
+- X
+- [X3D](https://en.wikipedia.org/wiki/X3D)
 - XGL
-- CSM
-- BVH
-- B3D
-- NDO
-- Ogre Binary
-- Ogre XML
-- Q3D
-- ASSBIN (Assimp custom format)
-- glTF (partial)
-- 3MF
+- ZGL
 
 Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default):
 
-- C4D (https://github.com/acgessler/assimp-cinema4d)
+- [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) IMporting geometry + node hierarchy are currently supported
 
 __Exporters__:
 
@@ -85,10 +114,13 @@ __Exporters__:
 - JSON (for WebGl, via https://github.com/acgessler/assimp2json)
 - ASSBIN
 - STEP
-- glTF (partial)
+- glTF 1.0 (partial)
+- glTF 2.0 (partial)
+- 3MF ( experimental )
+- FBX ( experimental )
 
 ### Building ###
-Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.
+Take a look into the https://github.com/assimp/assimp/blob/master/Build.md file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.
 
 ### Ports ###
 * [Android](port/AndroidJNI/README.md)
@@ -96,6 +128,9 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak
 * [.NET](port/AssimpNET/Readme.md)
 * [Pascal](port/AssimpPascal/Readme.md)
 * [Javascript (Alpha)](https://github.com/makc/assimp2json)
+* [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
+* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status))
+* [HAXE-Port](https://github.com/longde123/assimp-haxe) The Assimp-HAXE-port.
 
 ### Other tools ###
 [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.
@@ -113,8 +148,6 @@ Open Asset Import Library is implemented in C++. The directory structure is:
 	/tools		Tools (old assimp viewer, command line `assimp`)
 	/samples	A small number of samples to illustrate possible
                         use cases for Assimp
-	/workspaces	Build environments for vc,xcode,... (deprecated,
-			CMake has superseeded all legacy build options!)
 
 
 ### Where to get help ###

+ 53 - 22
appveyor.yml

@@ -10,33 +10,64 @@ branches:
   only:
     - master
 
+matrix:
+  fast_finish: true
+    
+image:
+  - Visual Studio 2013
+  - Visual Studio 2015
+  - Visual Studio 2017
+    
 platform:
-    - x86
-    - x64
-
-configuration:
-  - 14 2015
-  - 12 2013
-  #- MinGW
-  #- 10 2010 # only works for x86
-
-init:
-- if "%platform%" EQU "x64" ( for %%a in (2008 2010 MinGW) do ( if "%Configuration%"=="%%a" (echo "Skipping unsupported configuration" && exit /b 1 ) ) )
+  - Win32
+  - x64
+  
+configuration: Release
 
 install:
-# Make compiler command line tools available
-- call c:\projects\assimp\scripts\appveyor\compiler_setup.bat
-
-build_script:
-- cd c:\projects\assimp
-- if "%platform%" equ "x64" (cmake CMakeLists.txt -G "Visual Studio %Configuration% Win64")
-- if "%platform%" equ "x86" (cmake CMakeLists.txt -G "Visual Studio %Configuration%")
-- if "%platform%" equ "x64" (msbuild /m /p:Configuration=Release /p:Platform="x64" Assimp.sln)
-- if "%platform%" equ "x86" (msbuild /m /p:Configuration=Release /p:Platform="Win32" Assimp.sln)
-
+  - set PATH=C:\Ruby24-x64\bin;%PATH%
+  - set CMAKE_DEFINES -DASSIMP_WERROR=ON
+  - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" set CMAKE_GENERATOR_NAME=Visual Studio 12 2013
+  - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015
+  - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017
+  - if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% Win64
+  - cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" .
+  - set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5"
+  - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/5/7/b/57b2947c-7221-4f33-b35e-2fc78cb10df4/vc_redist.x64.exe -OutFile .\packaging\windows-innosetup\vc_redist.x64.exe
+  - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/1/d/8/1d8137db-b5bb-4925-8c5d-927424a2e4de/vc_redist.x86.exe -OutFile .\packaging\windows-innosetup\vc_redist.x86.exe
+  
+cache:
+  - code\assimp.dir\%CONFIGURATION%
+  - contrib\zlib\zlibstatic.dir\%CONFIGURATION%
+  - contrib\zlib\zlib.dir\%CONFIGURATION%
+  - tools\assimp_cmd\assimp_cmd.dir\%CONFIGURATION%
+  - tools\assimp_view\assimp_viewer.dir\%CONFIGURATION%
+  - test\unit.dir\%CONFIGURATION%
+  - bin\.mtime_cache
+  
+before_build:
+  - ruby scripts\AppVeyor\mtime_cache -g scripts\AppVeyor\cacheglobs.txt -c bin\.mtime_cache\cache.json
+  
+build:
+  parallel: true
+  project: Assimp.sln
+  
 after_build:
-  - 7z a assimp.7z c:\projects\assimp\bin\release\* c:\projects\assimp\lib\release\*
+  - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
+        if "%platform%"=="x64" (
+            iscc packaging\windows-innosetup\script_x64.iss
+        ) else (
+            iscc packaging\windows-innosetup\script_x86.iss
+        )
+    )
+  - 7z a assimp.7z bin\%CONFIGURATION%\* lib\%CONFIGURATION%\*
+
+test_script:
+  - cmd: bin\%CONFIGURATION%\unit.exe --gtest_output=xml:testout.xml
 
+on_finish:
+  - ps: (new-object net.webclient).UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\testout.xml))
+  
 artifacts:
   - path: assimp.7z
     name: assimp_lib

+ 1 - 81
assimp-config.cmake.in

@@ -1,81 +1 @@
-# - Find Assimp Installation
-#
-# Users can set the following variables before calling the module:
-#  ASSIMP_DIR - The preferred installation prefix for searching for ASSIMP. Set by the user.
-#
-# ASSIMP_ROOT_DIR - the root directory where the installation can be found
-# ASSIMP_CXX_FLAGS - extra flags for compilation
-# ASSIMP_LINK_FLAGS - extra flags for linking
-# ASSIMP_INCLUDE_DIRS - include directories
-# ASSIMP_LIBRARY_DIRS - link directories
-# ASSIMP_LIBRARIES - libraries to link plugins with
-# ASSIMP_Boost_VERSION - the boost version assimp was compiled with
-get_filename_component(_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
-get_filename_component(_PREFIX "${_PREFIX}" PATH)
-get_filename_component(_PREFIX "${_PREFIX}" PATH)
-get_filename_component(ASSIMP_ROOT_DIR "${_PREFIX}" PATH)
-
-if( MSVC )
-  # in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix
-  if( MSVC70 OR MSVC71 )
-    set(MSVC_PREFIX "vc70")
-  elseif( MSVC80 )
-    set(MSVC_PREFIX "vc80")
-  elseif( MSVC90 )
-    set(MSVC_PREFIX "vc90")
-  elseif( MSVC10 )
-    set(MSVC_PREFIX "vc100")
-  elseif( MSVC11 )
-    set(MSVC_PREFIX "vc110")
-  elseif( MSVC12 )
-    set(MSVC_PREFIX "vc120")
-  elseif( MSVC14 )
-    set(MSVC_PREFIX "vc140")
-  else()
-    set(MSVC_PREFIX "vc150")
-  endif()
-  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" FORCE)
-else()
-  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" FORCE)
-endif()
-
-set( ASSIMP_CXX_FLAGS ) # dynamically linked library
-if( WIN32 )
-  # for visual studio linking, most of the time boost dlls will be used
-  set( ASSIMP_CXX_FLAGS " -DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB")
-endif()
-set( ASSIMP_LINK_FLAGS "" )
-set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
-set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
-set( ASSIMP_LIBRARIES assimp${ASSIMP_LIBRARY_SUFFIX})
-set( ASSIMP_LIBRARIES ${ASSIMP_LIBRARIES}@CMAKE_DEBUG_POSTFIX@)
-
-# search for the boost version assimp was compiled with
-#set(Boost_USE_MULTITHREAD ON)
-#set(Boost_USE_STATIC_LIBS OFF)
-#set(Boost_USE_STATIC_RUNTIME OFF)
-#find_package(Boost ${ASSIMP_Boost_VERSION} EXACT COMPONENTS thread date_time)
-#if(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0")
-#	set( ASSIMP_INCLUDE_DIRS "${ASSIMP_INCLUDE_DIRS}" ${Boost_INCLUDE_DIRS})
-#else(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0")
-#	message(WARNING "Failed to find Boost ${ASSIMP_Boost_VERSION} necessary for assimp")
-#endif(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0")
-
-# the boost version assimp was compiled with
-set( ASSIMP_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@")
-
-# for compatibility with pkg-config
-set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
-set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
-
-MARK_AS_ADVANCED(
-  ASSIMP_ROOT_DIR
-  ASSIMP_CXX_FLAGS
-  ASSIMP_LINK_FLAGS
-  ASSIMP_INCLUDE_DIRS
-  ASSIMP_LIBRARIES
-  ASSIMP_Boost_VERSION
-  ASSIMP_CFLAGS_OTHER
-  ASSIMP_LDFLAGS_OTHER
-  ASSIMP_LIBRARY_SUFFIX
-)
+include(${CMAKE_CURRENT_LIST_DIR}/assimpTargets.cmake)

+ 1 - 1
assimp.pc.in

@@ -1,7 +1,7 @@
 prefix=@CMAKE_INSTALL_PREFIX@
 exec_prefix=@CMAKE_INSTALL_PREFIX@/
 libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@
-includedir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_INCLUDE_INSTALL_DIR@/assimp
+includedir=@CMAKE_INSTALL_PREFIX@/../include/@ASSIMP_INCLUDE_INSTALL_DIR@
 
 Name: @CMAKE_PROJECT_NAME@
 Description: Import various well-known 3D model formats in an uniform manner.

+ 78 - 0
assimpTargets-debug.cmake.in

@@ -0,0 +1,78 @@
+#----------------------------------------------------------------
+# Generated CMake target import file for configuration "Debug".
+#----------------------------------------------------------------
+
+# Commands may need to know the format version.
+set(CMAKE_IMPORT_FILE_VERSION 1)
+
+if(MSVC)
+  if( MSVC70 OR MSVC71 )
+    set(MSVC_PREFIX "vc70")
+  elseif( MSVC80 )
+    set(MSVC_PREFIX "vc80")
+  elseif( MSVC90 )
+    set(MSVC_PREFIX "vc90")
+  elseif( MSVC10 )
+    set(MSVC_PREFIX "vc100")
+  elseif( MSVC11 )
+    set(MSVC_PREFIX "vc110")
+  elseif( MSVC12 )
+    set(MSVC_PREFIX "vc120")
+  elseif( MSVC14 )
+    set(MSVC_PREFIX "vc140")
+  else()
+    set(MSVC_PREFIX "vc150")
+  endif()
+  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
+
+  set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
+  set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
+
+  # Import target "assimp::assimp" for configuration "Debug"
+  set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
+  set_target_properties(assimp::assimp PROPERTIES
+    IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/${importLibraryName}"
+    IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
+    ) 
+  list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
+  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
+
+else()
+  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" )
+  set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
+  set_target_properties(assimp::assimp PROPERTIES
+    IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
+    IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
+    )
+  list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
+endif()
+
+
+
+
+# Commands beyond this point should not need to know the version.
+set(CMAKE_IMPORT_FILE_VERSION)
+
+get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
+set( ASSIMP_CXX_FLAGS ) # dynamically linked library
+set( ASSIMP_LINK_FLAGS "" )
+set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
+set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
+set( ASSIMP_LIBRARIES ${sharedLibraryName})
+
+# for compatibility with pkg-config
+set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
+set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
+
+MARK_AS_ADVANCED(
+  ASSIMP_ROOT_DIR
+  ASSIMP_CXX_FLAGS
+  ASSIMP_LINK_FLAGS
+  ASSIMP_INCLUDE_DIRS
+  ASSIMP_LIBRARIES
+  ASSIMP_CFLAGS_OTHER
+  ASSIMP_LDFLAGS_OTHER
+  ASSIMP_LIBRARY_SUFFIX
+)

+ 75 - 0
assimpTargets-release.cmake.in

@@ -0,0 +1,75 @@
+#----------------------------------------------------------------
+# Generated CMake target import file for configuration "Release".
+#----------------------------------------------------------------
+
+# Commands may need to know the format version.
+set(CMAKE_IMPORT_FILE_VERSION 1)
+
+if(MSVC)
+  if( MSVC70 OR MSVC71 )
+    set(MSVC_PREFIX "vc70")
+  elseif( MSVC80 )
+    set(MSVC_PREFIX "vc80")
+  elseif( MSVC90 )
+    set(MSVC_PREFIX "vc90")
+  elseif( MSVC10 )
+    set(MSVC_PREFIX "vc100")
+  elseif( MSVC11 )
+    set(MSVC_PREFIX "vc110")
+  elseif( MSVC12 )
+    set(MSVC_PREFIX "vc120")
+  elseif( MSVC14 )
+    set(MSVC_PREFIX "vc140")
+  else()
+    set(MSVC_PREFIX "vc150")
+  endif()
+  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
+
+  set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
+  set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@")
+
+  # Import target "assimp::assimp" for configuration "Release"
+  set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
+  set_target_properties(assimp::assimp PROPERTIES
+    IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/${importLibraryName}"
+    IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/${sharedLibraryName}"
+    )
+  list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}")
+  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" )
+
+else()
+  set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" )
+  set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
+  set_target_properties(assimp::assimp PROPERTIES
+    IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
+    IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
+    )
+  list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
+  list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" )
+endif()
+
+# Commands beyond this point should not need to know the version.
+set(CMAKE_IMPORT_FILE_VERSION)
+
+get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
+set( ASSIMP_CXX_FLAGS ) # dynamically linked library
+set( ASSIMP_LINK_FLAGS "" )
+set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@")
+set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@")
+set( ASSIMP_LIBRARIES ${sharedLibraryName})
+
+# for compatibility with pkg-config
+set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}")
+set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}")
+
+MARK_AS_ADVANCED(
+  ASSIMP_ROOT_DIR
+  ASSIMP_CXX_FLAGS
+  ASSIMP_LINK_FLAGS
+  ASSIMP_INCLUDE_DIRS
+  ASSIMP_LIBRARIES
+  ASSIMP_CFLAGS_OTHER
+  ASSIMP_LDFLAGS_OTHER
+  ASSIMP_LIBRARY_SUFFIX
+)

+ 101 - 0
assimpTargets.cmake.in

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

+ 2 - 2
cmake-modules/CoverallsGenerateGcov.cmake

@@ -310,7 +310,7 @@ foreach (GCOV_FILE ${GCOV_FILES})
 	message("MD5: ${GCOV_SRC_PATH} = ${GCOV_CONTENTS_MD5}")
 
 	# Loads the gcov file as a list of lines.
-	# (We first open the file and replace all occurences of [] with _
+	# (We first open the file and replace all occurrences of [] with _
 	#  because CMake will fail to parse a line containing unmatched brackets...
 	#  also the \ to escaped \n in macros screws up things.)
 	# https://public.kitware.com/Bug/view.php?id=15369
@@ -329,7 +329,7 @@ foreach (GCOV_FILE ${GCOV_FILES})
 	# Instead of trying to parse the source from the
 	# gcov file, simply read the file contents from the source file.
 	# (Parsing it from the gcov is hard because C-code uses ; in many places
-	#  which also happens to be the same as the CMake list delimeter).
+	#  which also happens to be the same as the CMake list delimiter).
 	file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE)
 
 	string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")

+ 25 - 20
code/3DSConverter.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -50,27 +51,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "TargetAnimation.h"
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
-#include "StringComparison.h"
+#include <assimp/StringComparison.h>
 #include <memory>
 #include <cctype>
 
 using namespace Assimp;
 
+static const unsigned int NotSet = 0xcdcdcdcd;
+
 // ------------------------------------------------------------------------------------------------
 // Setup final material indices, generae a default material if necessary
 void Discreet3DSImporter::ReplaceDefaultMaterial()
 {
-
     // Try to find an existing material that matches the
     // typical default material setting:
     // - no textures
     // - diffuse color (in grey!)
     // NOTE: This is here to workaround the fact that some
     // exporters are writing a default material, too.
-    unsigned int idx = 0xcdcdcdcd;
+    unsigned int idx( NotSet );
     for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
     {
-        std::string s = mScene->mMaterials[i].mName;
+        std::string &s = mScene->mMaterials[i].mName;
         for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) {
             *it = static_cast< char >( ::tolower( *it ) );
         }
@@ -93,7 +95,9 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
         }
         idx = i;
     }
-    if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size();
+    if ( NotSet == idx ) {
+        idx = ( unsigned int )mScene->mMaterials.size();
+    }
 
     // now iterate through all meshes and through all faces and
     // find all faces that are using the default material
@@ -116,7 +120,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
             else if ( (*a) >= mScene->mMaterials.size())
             {
                 (*a) = idx;
-                DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material");
+                ASSIMP_LOG_WARN("Material index overflow in 3DS file. Using default material");
                 ++cnt;
             }
         }
@@ -124,12 +128,11 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
     if (cnt && idx == mScene->mMaterials.size())
     {
         // We need to create our own default material
-        D3DS::Material sMat;
+        D3DS::Material sMat("%%%DEFAULT");
         sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
-        sMat.mName = "%%%DEFAULT";
         mScene->mMaterials.push_back(sMat);
 
-        DefaultLogger::get()->info("3DS: Generating default material");
+        ASSIMP_LOG_INFO("3DS: Generating default material");
     }
 }
 
@@ -144,12 +147,12 @@ void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
         {
             if ((*i).mIndices[a] >= sMesh.mPositions.size())
             {
-                DefaultLogger::get()->warn("3DS: Vertex index overflow)");
+                ASSIMP_LOG_WARN("3DS: Vertex index overflow)");
                 (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
             }
             if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
             {
-                DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)");
+                ASSIMP_LOG_WARN("3DS: Texture coordinate index overflow)");
                 (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
             }
         }
@@ -201,8 +204,9 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
         mat.AddProperty<ai_real>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
 
     // Setup the texture mapping mode
-    mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
-    mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
+    int mapMode = static_cast<int>(texture.mMapMode);
+    mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
+    mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
 
     // Mirroring - double the scaling values
     // FIXME: this is not really correct ...
@@ -310,7 +314,8 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
         case D3DS::Discreet3DS::Blinn :
             eShading = aiShadingMode_Blinn; break;
     }
-    mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
+    int eShading_ = static_cast<int>(eShading);
+    mat.AddProperty<int>(&eShading_, 1, AI_MATKEY_SHADING_MODEL);
 
     // DIFFUSE texture
     if( oldMat.sTexDiffuse.mMapName.length() > 0)
@@ -494,7 +499,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
                         pvCurrent->x *= -1.f;
                         t2->x *= -1.f;
                     }
-                    DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
+                    ASSIMP_LOG_INFO("3DS: Flipping mesh X-Axis");
                 }
 
                 // Handle pivot point
@@ -570,11 +575,11 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
         pcIn->aTargetPositionKeys.size() > 1)
     {
         aiAnimation* anim = pcSOut->mAnimations[0];
-        ai_assert(NULL != anim);
+        ai_assert(nullptr != anim);
 
         if (pcIn->aCameraRollKeys.size() > 1)
         {
-            DefaultLogger::get()->debug("3DS: Converting camera roll track ...");
+            ASSIMP_LOG_DEBUG("3DS: Converting camera roll track ...");
 
             // Camera roll keys - in fact they're just rotations
             // around the camera's z axis. The angles are given
@@ -594,7 +599,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
 #if 0
         if (pcIn->aTargetPositionKeys.size() > 1)
         {
-            DefaultLogger::get()->debug("3DS: Converting target track ...");
+            ASSIMP_LOG_DEBUG("3DS: Converting target track ...");
 
             // Camera or spot light - need to convert the separate
             // target position channel to our representation
@@ -740,7 +745,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
         //   |       |       |            |         |
         // MESH_0  MESH_1  MESH_2  ...  MESH_N    CAMERA_0 ....
         //
-        DefaultLogger::get()->warn("No hierarchy information has been found in the file. ");
+        ASSIMP_LOG_WARN("No hierarchy information has been found in the file. ");
 
         pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes +
             static_cast<unsigned int>(mScene->mCameras.size() + mScene->mLights.size());

+ 12 - 6
code/3DSExporter.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -39,7 +40,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
-
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
 
@@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "3DSHelper.h"
 #include <assimp/SceneCombiner.h>
 #include "SplitLargeMeshes.h"
-#include "StringComparison.h"
+#include <assimp/StringComparison.h>
 #include <assimp/IOSystem.hpp>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Exporter.hpp>
@@ -151,7 +151,7 @@ namespace {
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
-void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
+void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
 {
     std::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
     if(!outfile) {
@@ -184,7 +184,7 @@ void ExportScene3DS(const char* pFile, IOSystem* pIOSystem, const aiScene* pScen
 } // end of namespace Assimp
 
 // ------------------------------------------------------------------------------------------------
-Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* scene)
+Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* scene)
 : scene(scene)
 , writer(outfile)
 {
@@ -210,6 +210,12 @@ Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> outfile, con
     }
 }
 
+// ------------------------------------------------------------------------------------------------
+Discreet3DSExporter::~Discreet3DSExporter() {
+    // empty
+}
+
+
 // ------------------------------------------------------------------------------------------------
 int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
 {
@@ -375,7 +381,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
 
     // TODO: handle embedded textures properly
     if (path.data[0] == '*') {
-        DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str()));
+        ASSIMP_LOG_ERROR("Ignoring embedded texture for export: " + std::string(path.C_Str()));
         return;
     }
 

+ 11 - 13
code/3DSExporter.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -48,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <map>
 #include <memory>
 
-#include "StreamWriter.h"
+#include <assimp/StreamWriter.h>
 #include <assimp/material.h>
 
 struct aiScene;
@@ -60,23 +61,21 @@ namespace Assimp
 {
 
 // ------------------------------------------------------------------------------------------------
-/** Helper class to export a given scene to a 3DS file. */
+/**
+ *  @brief  Helper class to export a given scene to a 3DS file.
+ */
 // ------------------------------------------------------------------------------------------------
-class Discreet3DSExporter
-{
+class Discreet3DSExporter {
 public:
-    Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* pScene);
+    Discreet3DSExporter(std::shared_ptr<IOStream> &outfile, const aiScene* pScene);
+    ~Discreet3DSExporter();
 
 private:
-
     void WriteMeshes();
     void WriteMaterials();
     void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
-
     void WriteFaceMaterialChunk(const aiMesh& mesh);
-
     int WriteHierarchy(const aiNode& node, int level, int sibling_level);
-
     void WriteString(const std::string& s);
     void WriteString(const aiString& s);
     void WriteColor(const aiColor3D& color);
@@ -84,7 +83,6 @@ private:
     void WritePercentChunk(double f);
 
 private:
-
     const aiScene* const scene;
     StreamWriterLE writer;
 
@@ -95,6 +93,6 @@ private:
 
 };
 
-}
+} // Namespace Assimp
 
-#endif
+#endif // AI_3DSEXPORTER_H_INC

+ 113 - 54
code/3DSHelper.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -44,11 +45,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_3DSFILEHELPER_H_INC
 #define AI_3DSFILEHELPER_H_INC
 
-
-#include "SpatialSort.h"
-#include "SmoothingGroups.h"
-#include "StringUtils.h"
-#include "qnan.h"
+#include <assimp/SpatialSort.h>
+#include <assimp/SmoothingGroups.h>
+#include <assimp/StringUtils.h>
+#include <assimp/qnan.h>
 #include <assimp/material.h>
 #include <assimp/camera.h>
 #include <assimp/light.h>
@@ -58,22 +58,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp    {
 namespace D3DS  {
 
-#include "./../include/assimp/Compiler/pushpack1.h"
+#include <assimp/Compiler/pushpack1.h>
 
 // ---------------------------------------------------------------------------
 /** Discreet3DS class: Helper class for loading 3ds files. Defines chunks
 *  and data structures.
 */
-class Discreet3DS
-{
+class Discreet3DS {
 private:
-    inline Discreet3DS() {}
+    Discreet3DS() AI_NO_EXCEPT {
+        // empty
+    }
 
-public:
+    ~Discreet3DS() {
+        // empty
+    }
 
+public:
     //! data structure for a single chunk in a .3ds file
-    struct Chunk
-    {
+    struct Chunk {
         uint16_t    Flag;
         uint32_t    Size;
     } PACK_STRUCT;
@@ -325,19 +328,17 @@ struct Face : public FaceWithSmoothingGroup
 
 // ---------------------------------------------------------------------------
 /** Helper structure representing a texture */
-struct Texture
-{
+struct Texture {
     //! Default constructor
-    Texture()
-        : mOffsetU  (0.0)
-        , mOffsetV  (0.0)
-        , mScaleU   (1.0)
-        , mScaleV   (1.0)
-        , mRotation (0.0)
-        , mMapMode  (aiTextureMapMode_Wrap)
-        , bPrivate()
-        , iUVSrc    (0)
-    {
+    Texture() AI_NO_EXCEPT
+    : mOffsetU  (0.0)
+    , mOffsetV  (0.0)
+    , mScaleU   (1.0)
+    , mScaleV   (1.0)
+    , mRotation (0.0)
+    , mMapMode  (aiTextureMapMode_Wrap)
+    , bPrivate()
+    , iUVSrc    (0) {
         mTextureBlend = get_qnan();
     }
 
@@ -362,15 +363,20 @@ struct Texture
     int iUVSrc;
 };
 
-#include "./../include/assimp/Compiler/poppack1.h"
+#include <assimp/Compiler/poppack1.h>
 
 // ---------------------------------------------------------------------------
 /** Helper structure representing a 3ds material */
 struct Material
 {
-    //! Default constructor. Builds a default name for the material
-    Material()
-    : mDiffuse            ( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ) ) // FIX ... we won't want object to be black
+    //! Default constructor has been deleted
+    Material() = delete;
+
+
+    //! Constructor with explicit name
+    explicit Material(const std::string &name)
+    : mName(name)
+    , mDiffuse            ( ai_real( 0.6 ), ai_real( 0.6 ), ai_real( 0.6 ) ) // FIX ... we won't want object to be black
     , mSpecularExponent   ( ai_real( 0.0 ) )
     , mShininessStrength  ( ai_real( 1.0 ) )
     , mShading(Discreet3DS::Gouraud)
@@ -378,13 +384,70 @@ struct Material
     , mBumpHeight         ( ai_real( 1.0 ) )
     , mTwoSided           (false)
     {
-        static int iCnt = 0;
+    }
+
+
+    Material(const Material &other)            = default;
+    Material &operator=(const Material &other) = default;
+
+
+    //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
+    Material(Material &&other) AI_NO_EXCEPT
+    : mName(std::move(other.mName))
+    , mDiffuse(std::move(other.mDiffuse))
+    , mSpecularExponent(std::move(other.mSpecularExponent))
+    , mShininessStrength(std::move(other.mShininessStrength))
+    , mSpecular(std::move(other.mSpecular))
+    , mAmbient(std::move(other.mAmbient))
+    , mShading(std::move(other.mShading))
+    , mTransparency(std::move(other.mTransparency))
+    , sTexDiffuse(std::move(other.sTexDiffuse))
+    , sTexOpacity(std::move(other.sTexOpacity))
+    , sTexSpecular(std::move(other.sTexSpecular))
+    , sTexReflective(std::move(other.sTexReflective))
+    , sTexBump(std::move(other.sTexBump))
+    , sTexEmissive(std::move(other.sTexEmissive))
+    , sTexShininess(std::move(other.sTexShininess))
+    , mBumpHeight(std::move(other.mBumpHeight))
+    , mEmissive(std::move(other.mEmissive))
+    , sTexAmbient(std::move(other.sTexAmbient))
+    , mTwoSided(std::move(other.mTwoSided))
+    {
+    }
+
+
+    Material &operator=(Material &&other) AI_NO_EXCEPT {
+        if (this == &other) {
+            return *this;
+        }
+
+        mName = std::move(other.mName);
+        mDiffuse = std::move(other.mDiffuse);
+        mSpecularExponent = std::move(other.mSpecularExponent);
+        mShininessStrength = std::move(other.mShininessStrength),
+        mSpecular = std::move(other.mSpecular);
+        mAmbient = std::move(other.mAmbient);
+        mShading = std::move(other.mShading);
+        mTransparency = std::move(other.mTransparency);
+        sTexDiffuse = std::move(other.sTexDiffuse);
+        sTexOpacity = std::move(other.sTexOpacity);
+        sTexSpecular = std::move(other.sTexSpecular);
+        sTexReflective = std::move(other.sTexReflective);
+        sTexBump = std::move(other.sTexBump);
+        sTexEmissive = std::move(other.sTexEmissive);
+        sTexShininess = std::move(other.sTexShininess);
+        mBumpHeight = std::move(other.mBumpHeight);
+        mEmissive = std::move(other.mEmissive);
+        sTexAmbient = std::move(other.sTexAmbient);
+        mTwoSided = std::move(other.mTwoSided);
 
-        char szTemp[128];
-        ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
-        mName = szTemp;
+        return *this;
     }
 
+
+    virtual ~Material() {}
+
+
     //! Name of the material
     std::string mName;
     //! Diffuse color of the material
@@ -430,17 +493,16 @@ struct Material
 /** Helper structure to represent a 3ds file mesh */
 struct Mesh : public MeshWithSmoothingGroups<D3DS::Face>
 {
-    //! Default constructor
-    Mesh()
-    {
-        static int iCnt = 0;
+    //! Default constructor has been deleted
+    Mesh() = delete;
 
-        // Generate a default name for the mesh
-        char szTemp[128];
-        ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
-        mName = szTemp;
+    //! Constructor with explicit name
+    explicit Mesh(const std::string &name)
+    : mName(name)
+    {
     }
 
+
     //! Name of the mesh
     std::string mName;
 
@@ -486,25 +548,22 @@ struct aiFloatKey
 /** Helper structure to represent a 3ds file node */
 struct Node
 {
-    Node():
-    	mParent(NULL)
-		,	mInstanceNumber(0)
-		,	mHierarchyPos		(0)
-		,	mHierarchyIndex		(0)
-		,	mInstanceCount		(1)
+    Node() = delete;
+
+    explicit Node(const std::string &name)
+    : mParent(NULL)
+    , mName(name)
+    , mInstanceNumber(0)
+    , mHierarchyPos       (0)
+    , mHierarchyIndex     (0)
+    , mInstanceCount      (1)
     {
-        static int iCnt = 0;
-
-        // Generate a default name for the node
-        char szTemp[128];
-        ::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
-        mName = szTemp;
-
         aRotationKeys.reserve (20);
         aPositionKeys.reserve (20);
         aScalingKeys.reserve  (20);
     }
 
+
     ~Node()
     {
         for (unsigned int i = 0; i < mChildren.size();++i)

+ 63 - 64
code/3DSLoader.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -51,12 +52,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "3DSLoader.h"
-#include "Macros.h"
+#include <assimp/Macros.h>
 #include <assimp/IOSystem.hpp>
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/importerdesc.h>
-#include "StringComparison.h"
+#include <assimp/StringComparison.h>
 
 using namespace Assimp;
 
@@ -70,7 +71,7 @@ static const aiImporterDesc desc = {
     0,
     0,
     0,
-    "3ds prj"
+	"3ds prj"
 };
 
 
@@ -105,29 +106,31 @@ static const aiImporterDesc desc = {
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 Discreet3DSImporter::Discreet3DSImporter()
-    : stream(),
-    mLastNodeIndex(),
-    mCurrentNode(),
-    mRootNode(),
-    mScene(),
-    mMasterScale(),
-    bHasBG(),
-    bIsPrj()
-{}
+: stream()
+, mLastNodeIndex()
+, mCurrentNode()
+, mRootNode()
+, mScene()
+, mMasterScale()
+, bHasBG()
+, bIsPrj() {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
-Discreet3DSImporter::~Discreet3DSImporter()
-{}
+Discreet3DSImporter::~Discreet3DSImporter() {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
-{
+bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
     std::string extension = GetExtension(pFile);
-    if(extension == "3ds" || extension == "prj" ) {
+	if(extension == "3ds" || extension == "prj") {
         return true;
     }
+
     if (!extension.length() || checkSig) {
         uint16_t token[3];
         token[0] = 0x4d4d;
@@ -158,19 +161,21 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
     aiScene* pScene, IOSystem* pIOHandler)
 {
     StreamReaderLE stream(pIOHandler->Open(pFile,"rb"));
-    this->stream = &stream;
 
     // We should have at least one chunk
     if (stream.GetRemainingSize() < 16) {
         throw DeadlyImportError("3DS file is either empty or corrupt: " + pFile);
     }
+    this->stream = &stream;
 
     // Allocate our temporary 3DS representation
-    mScene = new D3DS::Scene();
+    D3DS::Scene _scene;
+    mScene = &_scene;
 
     // Initialize members
+    D3DS::Node _rootNode("UNNAMED");
     mLastNodeIndex             = -1;
-    mCurrentNode               = new D3DS::Node();
+    mCurrentNode               = &_rootNode;
     mRootNode                  = mCurrentNode;
     mRootNode->mHierarchyPos   = -1;
     mRootNode->mHierarchyIndex = -1;
@@ -190,7 +195,6 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
     // file.
     for (auto &mesh : mScene->mMeshes) {
         if (mesh.mFaces.size() > 0 && mesh.mPositions.size() == 0)  {
-            delete mScene;
             throw DeadlyImportError("3DS file contains faces but no vertices: " + pFile);
         }
         CheckIndices(mesh);
@@ -198,7 +202,7 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
         ComputeNormalsWithSmoothingsGroups<D3DS::Face>(mesh);
     }
 
-    // Replace all occurrences of the default material with a
+    // Replace all occurences of the default material with a
     // valid material. Generate it if no material containing
     // DEFAULT in its name has been found in the file
     ReplaceDefaultMaterial();
@@ -209,16 +213,14 @@ void Discreet3DSImporter::InternReadFile( const std::string& pFile,
     ConvertScene(pScene);
 
     // Generate the node graph for the scene. This is a little bit
-    // tricky since we'll need to split some meshes into submeshes
+    // tricky since we'll need to split some meshes into sub-meshes
     GenerateNodeGraph(pScene);
 
     // Now apply the master scaling factor to the scene
     ApplyMasterScale(pScene);
 
-    // Delete our internal scene representation and the root
-    // node, so the whole hierarchy will follow
-    delete mRootNode;
-    delete mScene;
+    // Our internal scene representation and the root
+    // node will be automatically deleted, so the whole hierarchy will follow
 
     AI_DEBUG_INVALIDATE_PTR(mRootNode);
     AI_DEBUG_INVALIDATE_PTR(mScene);
@@ -247,16 +249,18 @@ void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene)
 // Reads a new chunk from the file
 void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
 {
-    ai_assert(pcOut != NULL);
+    ai_assert(pcOut != nullptr);
 
     pcOut->Flag = stream->GetI2();
     pcOut->Size = stream->GetI4();
 
-    if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize())
+    if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize()) {
         throw DeadlyImportError("Chunk is too large");
+    }
 
-    if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit())
-        DefaultLogger::get()->error("3DS: Chunk overflow");
+    if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit()) {
+        ASSIMP_LOG_ERROR("3DS: Chunk overflow");
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -317,7 +321,7 @@ void Discreet3DSImporter::ParseEditorChunk()
         // print the version number
         char buff[10];
         ASSIMP_itoa10(buff,stream->GetI2());
-        DefaultLogger::get()->info(std::string("3DS file format version: ") + buff);
+        ASSIMP_LOG_INFO_F(std::string("3DS file format version: "), buff);
         }
         break;
     };
@@ -346,7 +350,7 @@ void Discreet3DSImporter::ParseObjectChunk()
     case Discreet3DS::CHUNK_MAT_MATERIAL:
 
         // Add a new material to the list
-        mScene->mMaterials.push_back(D3DS::Material());
+        mScene->mMaterials.push_back(D3DS::Material(std::string("UNNAMED_" + to_string(mScene->mMaterials.size()))));
         ParseMaterialChunk();
         break;
 
@@ -358,7 +362,7 @@ void Discreet3DSImporter::ParseObjectChunk()
         if (is_qnan(mClrAmbient.r))
         {
             // We failed to read the ambient base color.
-            DefaultLogger::get()->error("3DS: Failed to read ambient base color");
+            ASSIMP_LOG_ERROR("3DS: Failed to read ambient base color");
             mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
         }
         break;
@@ -402,11 +406,7 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
     case Discreet3DS::CHUNK_TRIMESH:
         {
         // this starts a new triangle mesh
-        mScene->mMeshes.push_back(D3DS::Mesh());
-        D3DS::Mesh& m = mScene->mMeshes.back();
-
-        // Setup the name of the mesh
-        m.mName = std::string(name, num);
+        mScene->mMeshes.push_back(D3DS::Mesh(std::string(name, num)));
 
         // Read mesh chunks
         ParseMeshChunk();
@@ -464,7 +464,7 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
         if (len < 1e-5) {
 
             // There are some files with lookat == position. Don't know why or whether it's ok or not.
-            DefaultLogger::get()->error("3DS: Unable to read proper camera look-at vector");
+            ASSIMP_LOG_ERROR("3DS: Unable to read proper camera look-at vector");
             camera->mLookAt = aiVector3D(0.0,1.0,0.0);
 
         }
@@ -630,9 +630,9 @@ void Discreet3DSImporter::SkipTCBInfo()
     if (!flags) {
         // Currently we can't do anything with these values. They occur
         // quite rare, so it wouldn't be worth the effort implementing
-        // them. 3DS ist not really suitable for complex animations,
+        // them. 3DS is not really suitable for complex animations,
         // so full support is not required.
-        DefaultLogger::get()->warn("3DS: Skipping TCB animation info");
+        ASSIMP_LOG_WARN("3DS: Skipping TCB animation info");
     }
 
     if (flags & Discreet3DS::KEY_USE_TENS) {
@@ -690,8 +690,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
             pcNode->mInstanceCount++;
             instanceNumber = pcNode->mInstanceCount;
         }
-        pcNode = new D3DS::Node();
-        pcNode->mName = name;
+        pcNode = new D3DS::Node(name);
         pcNode->mInstanceNumber = instanceNumber;
 
         // There are two unknown values which we can safely ignore
@@ -734,7 +733,6 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
 
             // If object name is DUMMY, take this one instead
             if (mCurrentNode->mName == "$$$DUMMY")  {
-                //DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object");
                 mCurrentNode->mName = std::string(sz);
                 break;
             }
@@ -745,7 +743,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
 
         if ( Discreet3DS::CHUNK_TRACKINFO != parent)
         {
-            DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object");
+            ASSIMP_LOG_WARN("3DS: Skipping pivot subchunk for non usual object");
             break;
         }
 
@@ -807,7 +805,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
         {
         // roll keys are accepted for cameras only
         if (parent != Discreet3DS::CHUNK_TRACKCAMERA)   {
-            DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object");
+            ASSIMP_LOG_WARN("3DS: Ignoring roll track for non-camera object");
             break;
         }
         bool sortKeys = false;
@@ -847,7 +845,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
         // CAMERA FOV KEYFRAME
     case Discreet3DS::CHUNK_TRACKFOV:
         {
-            DefaultLogger::get()->error("3DS: Skipping FOV animation track. "
+            ASSIMP_LOG_ERROR("3DS: Skipping FOV animation track. "
                 "This is not supported");
         }
         break;
@@ -987,7 +985,7 @@ void Discreet3DSImporter::ParseFaceChunk()
             }
         }
         if (0xcdcdcdcd == idx)  {
-            DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz);
+            ASSIMP_LOG_ERROR_F( "3DS: Unknown material: ", sz);
         }
 
         // Now continue and read all material indices
@@ -997,7 +995,7 @@ void Discreet3DSImporter::ParseFaceChunk()
 
             // check range
             if (fidx >= mMesh.mFaceMaterials.size())    {
-                DefaultLogger::get()->error("3DS: Invalid face index in face material list");
+                ASSIMP_LOG_ERROR("3DS: Invalid face index in face material list");
             }
             else mMesh.mFaceMaterials[fidx] = idx;
         }}
@@ -1112,7 +1110,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
 
         if (!cnt)   {
             // This may not be, we use the default name instead
-            DefaultLogger::get()->error("3DS: Empty material name");
+            ASSIMP_LOG_ERROR("3DS: Empty material name");
         }
         else mScene->mMaterials.back().mName = std::string(sz,cnt);
         }
@@ -1125,7 +1123,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
         ParseColorChunk(pc);
         if (is_qnan(pc->r)) {
             // color chunk is invalid. Simply ignore it
-            DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk");
+            ASSIMP_LOG_ERROR("3DS: Unable to read DIFFUSE chunk");
             pc->r = pc->g = pc->b = 1.0f;
         }}
         break;
@@ -1137,7 +1135,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
         ParseColorChunk(pc);
         if (is_qnan(pc->r)) {
             // color chunk is invalid. Simply ignore it
-            DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk");
+            ASSIMP_LOG_ERROR("3DS: Unable to read SPECULAR chunk");
             pc->r = pc->g = pc->b = 1.0f;
         }}
         break;
@@ -1149,7 +1147,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
         ParseColorChunk(pc);
         if (is_qnan(pc->r)) {
             // color chunk is invalid. Simply ignore it
-            DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk");
+            ASSIMP_LOG_ERROR("3DS: Unable to read AMBIENT chunk");
             pc->r = pc->g = pc->b = 0.0f;
         }}
         break;
@@ -1161,7 +1159,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
         ParseColorChunk(pc);
         if (is_qnan(pc->r)) {
             // color chunk is invalid. Simply ignore it
-            DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk");
+            ASSIMP_LOG_ERROR("3DS: Unable to read EMISSIVE chunk");
             pc->r = pc->g = pc->b = 0.0f;
         }}
         break;
@@ -1295,7 +1293,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
         pcOut->mScaleU = stream->GetF4();
         if (0.0f == pcOut->mScaleU)
         {
-            DefaultLogger::get()->warn("Texture coordinate scaling in the x direction is zero. Assuming 1.");
+            ASSIMP_LOG_WARN("Texture coordinate scaling in the x direction is zero. Assuming 1.");
             pcOut->mScaleU = 1.0f;
         }
         break;
@@ -1304,7 +1302,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
         pcOut->mScaleV = stream->GetF4();
         if (0.0f == pcOut->mScaleV)
         {
-            DefaultLogger::get()->warn("Texture coordinate scaling in the y direction is zero. Assuming 1.");
+            ASSIMP_LOG_WARN("Texture coordinate scaling in the y direction is zero. Assuming 1.");
             pcOut->mScaleV = 1.0f;
         }
         break;
@@ -1346,15 +1344,16 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
 
 // ------------------------------------------------------------------------------------------------
 // Read a percentage chunk
-ai_real Discreet3DSImporter::ParsePercentageChunk()
-{
+ai_real Discreet3DSImporter::ParsePercentageChunk() {
     Discreet3DS::Chunk chunk;
     ReadChunk(&chunk);
 
-    if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag)
-        return stream->GetF4();
-    else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag)
+    if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag) {
+        return stream->GetF4() * ai_real(100) / ai_real(0xFFFF);
+    } else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag) {
         return (ai_real)((uint16_t)stream->GetI2()) / (ai_real)0xFFFF;
+    }
+
     return get_qnan();
 }
 
@@ -1381,7 +1380,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent )
         bGamma = true;
 
     case Discreet3DS::CHUNK_RGBF:
-        if (sizeof(ai_real) * 3 > diff)   {
+        if (sizeof(float) * 3 > diff)   {
             *out = clrError;
             return;
         }

+ 4 - 3
code/3DSLoader.h

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -46,13 +47,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_3DSIMPORTER_H_INC
 #define AI_3DSIMPORTER_H_INC
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 #include <assimp/types.h>
 
 #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
 
 #include "3DSHelper.h"
-#include "StreamReader.h"
+#include <assimp/StreamReader.h>
 
 struct aiNode;
 

+ 104 - 0
code/3MFXmlTags.h

@@ -0,0 +1,104 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#pragma once
+
+namespace Assimp {
+namespace D3MF {
+
+namespace XmlTag {
+    // Meta-data
+    static const std::string meta = "metadata";
+    static const std::string meta_name = "name";
+
+    // Model-data specific tags
+    static const std::string model = "model";
+    static const std::string model_unit = "unit";
+    static const std::string metadata = "metadata";
+    static const std::string resources = "resources";
+    static const std::string object = "object";
+    static const std::string mesh = "mesh";
+    static const std::string vertices = "vertices";
+    static const std::string vertex = "vertex";
+    static const std::string triangles = "triangles";
+    static const std::string triangle = "triangle";
+    static const std::string x = "x";
+    static const std::string y = "y";
+    static const std::string z = "z";
+    static const std::string v1 = "v1";
+    static const std::string v2 = "v2";
+    static const std::string v3 = "v3";
+    static const std::string id = "id";
+    static const std::string pid = "pid";
+    static const std::string p1 = "p1";
+    static const std::string name = "name";
+    static const std::string type = "type";
+    static const std::string build = "build";
+    static const std::string item = "item";
+    static const std::string objectid = "objectid";
+    static const std::string transform = "transform";
+
+    // Material definitions
+    static const std::string basematerials = "basematerials";
+    static const std::string basematerials_id = "id";
+    static const std::string basematerials_base = "base";
+    static const std::string basematerials_name = "name";
+    static const std::string basematerials_displaycolor = "displaycolor";
+
+    // Meta info tags
+    static const std::string CONTENT_TYPES_ARCHIVE = "[Content_Types].xml";
+    static const std::string ROOT_RELATIONSHIPS_ARCHIVE = "_rels/.rels";
+    static const std::string SCHEMA_CONTENTTYPES = "http://schemas.openxmlformats.org/package/2006/content-types";
+    static const std::string SCHEMA_RELATIONSHIPS = "http://schemas.openxmlformats.org/package/2006/relationships";
+    static const std::string RELS_RELATIONSHIP_CONTAINER = "Relationships";
+    static const std::string RELS_RELATIONSHIP_NODE = "Relationship";
+    static const std::string RELS_ATTRIB_TARGET = "Target";
+    static const std::string RELS_ATTRIB_TYPE = "Type";
+    static const std::string RELS_ATTRIB_ID = "Id";
+    static const std::string PACKAGE_START_PART_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel";
+    static const std::string PACKAGE_PRINT_TICKET_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/printticket";
+    static const std::string PACKAGE_TEXTURE_RELATIONSHIP_TYPE = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dtexture";
+    static const std::string PACKAGE_CORE_PROPERTIES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
+    static const std::string PACKAGE_THUMBNAIL_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail";
+}
+
+} // Namespace D3MF
+} // Namespace Assimp

+ 25 - 24
code/ACLoader.cpp

@@ -4,7 +4,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -49,11 +50,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "ACLoader.h"
-#include "ParsingUtils.h"
-#include "fast_atof.h"
-#include "Subdivision.h"
+#include <assimp/ParsingUtils.h>
+#include <assimp/fast_atof.h>
+#include <assimp/Subdivision.h>
 #include "Importer.h"
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 #include <assimp/Importer.hpp>
 #include <assimp/light.h>
 #include <assimp/DefaultLogger.hpp>
@@ -84,7 +85,7 @@ static const aiImporterDesc desc = {
 #define AI_AC_SKIP_TO_NEXT_TOKEN() \
     if (!SkipSpaces(&buffer)) \
     { \
-        DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \
+        ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); \
         continue; \
     }
 
@@ -100,7 +101,7 @@ static const aiImporterDesc desc = {
     { \
         if (IsLineEnd( *buffer )) \
         { \
-            DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \
+            ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string"); \
             out = "ERROR"; \
             break; \
         } \
@@ -119,7 +120,7 @@ static const aiImporterDesc desc = {
     { \
         if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \
         { \
-            DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \
+            ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " name " was expected."); \
             continue; \
         } \
         buffer += name_length+1; \
@@ -216,7 +217,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
         light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i",static_cast<unsigned int>(mLights->size())-1);
         obj.name = std::string( light->mName.data );
 
-        DefaultLogger::get()->debug("AC3D: Light source encountered");
+        ASSIMP_LOG_DEBUG("AC3D: Light source encountered");
         obj.type = Object::Light;
     }
     else if (!ASSIMP_strincmp(buffer,"group",5))
@@ -306,12 +307,12 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
             {
                 if (!GetNextLine())
                 {
-                    DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet");
+                    ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet");
                     break;
                 }
                 else if (!IsNumeric(*buffer))
                 {
-                    DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet");
+                    ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet");
                     --buffer; // make sure the line is processed a second time
                     break;
                 }
@@ -337,8 +338,8 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
                     // example writes no surf chunks
                     if (!Q3DWorkAround)
                     {
-                        DefaultLogger::get()->warn("AC3D: SURF token was expected");
-                        DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled");
+                        ASSIMP_LOG_WARN("AC3D: SURF token was expected");
+                        ASSIMP_LOG_DEBUG("Continuing with Quick3D Workaround enabled");
                     }
                     --buffer; // make sure the line is processed a second time
                     // break; --- see fix notes above
@@ -383,7 +384,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
                         {
                             if(!GetNextLine())
                             {
-                                DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete");
+                                ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: surface references are incomplete");
                                 break;
                             }
                             surf.entries.push_back(Surface::SurfaceEntry());
@@ -404,7 +405,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
             }
         }
     }
-    DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected");
+    ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: \'kids\' line was expected");
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -477,7 +478,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
                  therefore: if no surfaces are defined return point data only
              */
 
-            DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, "
+            ASSIMP_LOG_INFO("AC3D: No surfaces defined in object definition, "
                 "a point list is returned");
 
             meshes.push_back(new aiMesh());
@@ -518,12 +519,12 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
                 unsigned int idx = (*it).mat;
                 if (idx >= needMat.size())
                 {
-                    DefaultLogger::get()->error("AC3D: material index is out of range");
+                    ASSIMP_LOG_ERROR("AC3D: material index is out of range");
                     idx = 0;
                 }
                 if ((*it).entries.empty())
                 {
-                    DefaultLogger::get()->warn("AC3D: surface her zero vertex references");
+                    ASSIMP_LOG_WARN("AC3D: surface her zero vertex references");
                 }
 
                 // validate all vertex indices to make sure we won't crash here
@@ -532,7 +533,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
                 {
                     if ((*it2).first >= object.vertices.size())
                     {
-                        DefaultLogger::get()->warn("AC3D: Invalid vertex reference");
+                        ASSIMP_LOG_WARN("AC3D: Invalid vertex reference");
                         (*it2).first = 0;
                     }
                 }
@@ -560,7 +561,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
 
                     if ((*it).flags & 0xf)
                     {
-                        DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown");
+                        ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
                         (*it).flags &= ~(0xf);
                     }
 
@@ -711,7 +712,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
             if (object.subDiv)  {
                 if (configEvalSubdivision) {
                     std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
-                    DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name);
+                    ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: "+object.name);
 
                     std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL);
                     div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true);
@@ -720,7 +721,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
                     // previous meshes are deleted vy Subdivide().
                 }
                 else {
-                    DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: "
+                    ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: "
                         +object.name);
                 }
             }
@@ -812,7 +813,7 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
     unsigned int version = HexDigitToDecimal( buffer[4] );
     char msg[3];
     ASSIMP_itoa10(msg,3,version);
-    DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg);
+    ASSIMP_LOG_INFO_F("AC3D file format version: ", msg);
 
     std::vector<Material> materials;
     materials.reserve(5);
@@ -856,7 +857,7 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
     }
     if (materials.empty())
     {
-        DefaultLogger::get()->warn("AC3D: No material has been found");
+        ASSIMP_LOG_WARN("AC3D: No material has been found");
         materials.push_back(Material());
     }
 

+ 3 - 2
code/ACLoader.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -47,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <vector>
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 #include <assimp/types.h>
 
 struct aiNode;

+ 4 - 3
code/AMFImporter.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -51,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "AMFImporter.hpp"
 #include "AMFImporter_Macro.hpp"
 
-#include "fast_atof.h"
+#include <assimp/fast_atof.h>
 #include <assimp/DefaultIOSystem.h>
 
 // Header files, stdlib.
@@ -229,7 +230,7 @@ casu_cres:
 	if(!skipped_before[sk_idx])
 	{
 		skipped_before[sk_idx] = true;
-		LogWarning("Skipping node \"" + nn + "\" in " + pParentNodeName + ".");
+        ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, ".");
 	}
 }
 

+ 70 - 201
code/AMFImporter.hpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -56,14 +57,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/importerdesc.h>
 #include "assimp/types.h"
-#include "BaseImporter.h"
-#include "irrXMLWrapper.h"
+#include <assimp/BaseImporter.h>
+#include <assimp/irrXMLWrapper.h>
 
 // Header files, stdlib.
 #include <set>
 
-namespace Assimp
-{
+namespace Assimp {
+
 /// \class AMFImporter
 /// Class that holding scene graph which include: geometry, metadata, materials etc.
 ///
@@ -98,100 +99,49 @@ namespace Assimp
 ///            new - <texmap> and children <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>
 ///            old - <map> and children <u1>, <u2>, <u3>, <v1>, <v2>, <v3>
 ///
-class AMFImporter : public BaseImporter
-{
-	/***********************************************/
-	/******************** Types ********************/
-	/***********************************************/
-
-private:
-
-	struct SPP_Material;// forward declaration
-
-	/// \struct SPP_Composite
-	/// Data type for postprocessing step. More suitable container for part of material's composition.
-	struct SPP_Composite
-	{
-		SPP_Material* Material;///< Pointer to material - part of composition.
-		std::string Formula;///< Formula for calculating ratio of \ref Material.
-	};
-
-	/// \struct SPP_Material
-	/// Data type for postprocessing step. More suitable container for material.
-	struct SPP_Material
-	{
-		std::string ID;///< Material ID.
-		std::list<CAMFImporter_NodeElement_Metadata*> Metadata;///< Metadata of material.
-		CAMFImporter_NodeElement_Color* Color;///< Color of material.
-		std::list<SPP_Composite> Composition;///< List of child materials if current material is composition of few another.
-
-		/// \fn aiColor4D GetColor(const float pX, const float pY, const float pZ) const
-		/// Return color calculated for specified coordinate.
-		/// \param [in] pX - "x" coordinate.
-		/// \param [in] pY - "y" coordinate.
-		/// \param [in] pZ - "z" coordinate.
-		/// \return calculated color.
-		aiColor4D GetColor(const float pX, const float pY, const float pZ) const;
-	};
-
-	/// \struct SPP_Texture
-	/// Data type for post-processing step. More suitable container for texture.
-	struct SPP_Texture
-	{
-		std::string ID;
-		size_t      Width, Height, Depth;
-		bool        Tiled;
-        char        FormatHint[ 9 ];// 8 for string + 1 for terminator.
-		uint8_t    *Data;
-	};
-
-	///	\struct SComplexFace
-	/// Data type for post-processing step. Contain face data.
-	struct SComplexFace
-	{
-		aiFace Face;///< Face vertices.
-		const CAMFImporter_NodeElement_Color* Color;///< Face color. Equal to nullptr if color is not set for the face.
-		const CAMFImporter_NodeElement_TexMap* TexMap;///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face.
-	};
-
-
-
-	/***********************************************/
-	/****************** Constants ******************/
-	/***********************************************/
-
+class AMFImporter : public BaseImporter {
 private:
+    struct SPP_Material;// forward declaration
+
+                        /// \struct SPP_Composite
+                        /// Data type for post-processing step. More suitable container for part of material's composition.
+    struct SPP_Composite {
+        SPP_Material* Material;///< Pointer to material - part of composition.
+        std::string Formula;///< Formula for calculating ratio of \ref Material.
+    };
+
+    /// \struct SPP_Material
+    /// Data type for post-processing step. More suitable container for material.
+    struct SPP_Material {
+        std::string ID;///< Material ID.
+        std::list<CAMFImporter_NodeElement_Metadata*> Metadata;///< Metadata of material.
+        CAMFImporter_NodeElement_Color* Color;///< Color of material.
+        std::list<SPP_Composite> Composition;///< List of child materials if current material is composition of few another.
+
+        /// Return color calculated for specified coordinate.
+        /// \param [in] pX - "x" coordinate.
+        /// \param [in] pY - "y" coordinate.
+        /// \param [in] pZ - "z" coordinate.
+        /// \return calculated color.
+        aiColor4D GetColor(const float pX, const float pY, const float pZ) const;
+    };
+
+    /// Data type for post-processing step. More suitable container for texture.
+    struct SPP_Texture {
+        std::string ID;
+        size_t      Width, Height, Depth;
+        bool        Tiled;
+        char        FormatHint[9];// 8 for string + 1 for terminator.
+        uint8_t    *Data;
+    };
+
+    /// Data type for post-processing step. Contain face data.
+    struct SComplexFace {
+        aiFace Face;///< Face vertices.
+        const CAMFImporter_NodeElement_Color* Color;///< Face color. Equal to nullptr if color is not set for the face.
+        const CAMFImporter_NodeElement_TexMap* TexMap;///< Face texture mapping data. Equal to nullptr if texture mapping is not set for the face.
+    };
 
-	static const aiImporterDesc Description;
-
-	/***********************************************/
-	/****************** Variables ******************/
-	/***********************************************/
-
-private:
-
-    CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element.
-    std::list<CAMFImporter_NodeElement*> mNodeElement_List;///< All elements of scene graph.
-	irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object
-	std::string mUnit;
-	std::list<SPP_Material> mMaterial_Converted;///< List of converted materials for postprocessing step.
-	std::list<SPP_Texture> mTexture_Converted;///< List of converted textures for postprocessing step.
-
-	/***********************************************/
-	/****************** Functions ******************/
-	/***********************************************/
-
-private:
-
-	/// \fn AMFImporter(const AMFImporter& pScene)
-	/// Disabled copy constructor.
-	AMFImporter(const AMFImporter& pScene);
-
-	/// \fn AMFImporter& operator=(const AMFImporter& pScene)
-	/// Disabled assign operator.
-	AMFImporter& operator=(const AMFImporter& pScene);
-
-	/// \fn void Clear()
 	/// Clear all temporary data.
 	void Clear();
 
@@ -199,7 +149,6 @@ private:
 	/************* Functions: find set *************/
 	/***********************************************/
 
-	/// \fn bool Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, aiNode** pNode) const
 	/// Find specified node element in node elements list ( \ref mNodeElement_List).
 	/// \param [in] pID - ID(name) of requested node element.
 	/// \param [in] pType - type of node element.
@@ -207,7 +156,6 @@ private:
 	/// \return true - if the node element is found, else - false.
 	bool Find_NodeElement(const std::string& pID, const CAMFImporter_NodeElement::EType pType, CAMFImporter_NodeElement** pNodeElement) const;
 
-	/// \fn bool Find_ConvertedNode(const std::string& pID, std::list<aiNode*>& pNodeList, aiNode** pNode) const
 	/// Find requested aiNode in node list.
 	/// \param [in] pID - ID(name) of requested node.
 	/// \param [in] pNodeList - list of nodes where to find the node.
@@ -215,15 +163,13 @@ private:
 	/// \return true - if the node is found, else - false.
 	bool Find_ConvertedNode(const std::string& pID, std::list<aiNode*>& pNodeList, aiNode** pNode) const;
 
-	/// \fn bool Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const
 	/// Find material in list for converted materials. Use at postprocessing step.
 	/// \param [in] pID - material ID.
 	/// \param [out] pConvertedMaterial - pointer to found converted material (\ref SPP_Material).
 	/// \return true - if the material is found, else - false.
 	bool Find_ConvertedMaterial(const std::string& pID, const SPP_Material** pConvertedMaterial) const;
 
-	/// \fn bool Find_ConvertedTexture(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A, uint32_t* pConvertedTextureIndex = nullptr) const
-	/// Find texture in list of converted textures. Use at postprocessing step,
+    /// Find texture in list of converted textures. Use at postprocessing step,
 	/// \param [in] pID_R - ID of source "red" texture.
 	/// \param [in] pID_G - ID of source "green" texture.
 	/// \param [in] pID_B - ID of source "blue" texture.
@@ -234,11 +180,7 @@ private:
 	bool Find_ConvertedTexture(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A,
 								uint32_t* pConvertedTextureIndex = nullptr) const;
 
-	/***********************************************/
-	/********* Functions: postprocess set **********/
-	/***********************************************/
 
-	/// \fn void PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector<aiVector3D>& pVertexCoordinateArray, std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray) const
 	/// Get data stored in <vertices> and place it to arrays.
 	/// \param [in] pNodeElement - reference to node element which kept <object> data.
 	/// \param [in] pVertexCoordinateArray - reference to vertices coordinates kept in <vertices>.
@@ -247,9 +189,8 @@ private:
 	void PostprocessHelper_CreateMeshDataArray(const CAMFImporter_NodeElement_Mesh& pNodeElement, std::vector<aiVector3D>& pVertexCoordinateArray,
 												std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray) const;
 
-	/// \fn size_t PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A)
 	/// Return converted texture ID which related to specified source textures ID's. If converted texture does not exist then it will be created and ID on new
-	/// converted texture will be returned. Convertion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
+	/// converted texture will be returned. Conversion: set of textures from \ref CAMFImporter_NodeElement_Texture to one \ref SPP_Texture and place it
 	/// to converted textures list.
 	/// Any of source ID's can be absent(empty string) or even one ID only specified. But at least one ID must be specified.
 	/// \param [in] pID_R - ID of source "red" texture.
@@ -259,27 +200,23 @@ private:
 	/// \return index of the texture in array of the converted textures.
 	size_t PostprocessHelper_GetTextureID_Or_Create(const std::string& pID_R, const std::string& pID_G, const std::string& pID_B, const std::string& pID_A);
 
-	/// \fn void PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace>& pInputList, std::list<std::list<SComplexFace> > pOutputList_Separated)
 	/// Separate input list by texture IDs. This step is needed because aiMesh can contain mesh which is use only one texture (or set: diffuse, bump etc).
 	/// \param [in] pInputList - input list with faces. Some of them can contain color or texture mapping, or both of them, or nothing. Will be cleared after
 	/// processing.
 	/// \param [out] pOutputList_Separated - output list of the faces lists. Separated faces list by used texture IDs. Will be cleared before processing.
 	void PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace>& pInputList, std::list<std::list<SComplexFace> >& pOutputList_Separated);
 
-	/// \fn void Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& pMetadataList, aiNode& pSceneNode) const
 	/// Check if child elements of node element is metadata and add it to scene node.
 	/// \param [in] pMetadataList - reference to list with collected metadata.
 	/// \param [out] pSceneNode - scene node in which metadata will be added.
 	void Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& pMetadataList, aiNode& pSceneNode) const;
 
-	/// \fn void Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list<aiMesh*>& pMeshList, aiNode** pSceneNode)
 	/// To create aiMesh and aiNode for it from <object>.
 	/// \param [in] pNodeElement - reference to node element which kept <object> data.
 	/// \param [out] pMeshList - reference to a list with all aiMesh of the scene.
 	/// \param [out] pSceneNode - pointer to place where new aiNode will be created.
 	void Postprocess_BuildNodeAndObject(const CAMFImporter_NodeElement_Object& pNodeElement, std::list<aiMesh*>& pMeshList, aiNode** pSceneNode);
 
-	/// \fn void Postprocess_BuildMeshSet(const CAMFImporter_NodeElement_Mesh& pNodeElement, const std::vector<aiVector3D>& pVertexCoordinateArray, const std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray, const CAMFImporter_NodeElement_Color* pObjectColor, std::list<aiMesh*>& pMeshList, aiNode& pSceneNode)
 	/// Create mesh for every <volume> in <mesh>.
 	/// \param [in] pNodeElement - reference to node element which kept <mesh> data.
 	/// \param [in] pVertexCoordinateArray - reference to vertices coordinates for all <volume>'s.
@@ -293,27 +230,20 @@ private:
 									const std::vector<CAMFImporter_NodeElement_Color*>& pVertexColorArray, const CAMFImporter_NodeElement_Color* pObjectColor,
 									std::list<aiMesh*>& pMeshList, aiNode& pSceneNode);
 
-	/// \fn void Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial)
 	/// Convert material from \ref CAMFImporter_NodeElement_Material to \ref SPP_Material.
 	/// \param [in] pMaterial - source CAMFImporter_NodeElement_Material.
 	void Postprocess_BuildMaterial(const CAMFImporter_NodeElement_Material& pMaterial);
 
-	/// \fn void Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list<aiNode*>& pNodeList) const
 	/// Create and add to aiNode's list new part of scene graph defined by <constellation>.
 	/// \param [in] pConstellation - reference to <constellation> node.
 	/// \param [out] pNodeList - reference to aiNode's list.
 	void Postprocess_BuildConstellation(CAMFImporter_NodeElement_Constellation& pConstellation, std::list<aiNode*>& pNodeList) const;
 
-	/// \fn void Postprocess_BuildScene()
 	/// Build Assimp scene graph in aiScene from collected data.
 	/// \param [out] pScene - pointer to aiScene where tree will be built.
 	void Postprocess_BuildScene(aiScene* pScene);
 
-	/***********************************************/
-	/************* Functions: throw set ************/
-	/***********************************************/
 
-	/// \fn void Throw_CloseNotFound(const std::string& pNode)
 	/// Call that function when close tag of node not found and exception must be raised.
 	/// E.g.:
 	/// <amf>
@@ -323,19 +253,16 @@ private:
 	/// \param [in] pNode - node name in which exception happened.
 	void Throw_CloseNotFound(const std::string& pNode);
 
-	/// \fn void Throw_IncorrectAttr(const std::string& pAttrName)
 	/// Call that function when attribute name is incorrect and exception must be raised.
 	/// \param [in] pAttrName - attribute name.
 	/// \throw DeadlyImportError.
 	void Throw_IncorrectAttr(const std::string& pAttrName);
 
-	/// \fn void Throw_IncorrectAttrValue(const std::string& pAttrName)
 	/// Call that function when attribute value is incorrect and exception must be raised.
 	/// \param [in] pAttrName - attribute name.
 	/// \throw DeadlyImportError.
 	void Throw_IncorrectAttrValue(const std::string& pAttrName);
 
-	/// \fn void Throw_MoreThanOnceDefined(const std::string& pNode, const std::string& pDescription)
 	/// Call that function when some type of nodes are defined twice or more when must be used only once and exception must be raised.
 	/// E.g.:
 	/// <object>
@@ -347,216 +274,158 @@ private:
 	/// \param [in] pDescription - message about error. E.g. what the node defined while exception raised.
 	void Throw_MoreThanOnceDefined(const std::string& pNodeType, const std::string& pDescription);
 
-	/// \fn void Throw_ID_NotFound(const std::string& pID) const
 	/// Call that function when referenced element ID are not found in graph and exception must be raised.
 	/// \param [in] pID - ID of of element which not found.
 	/// \throw DeadlyImportError.
 	void Throw_ID_NotFound(const std::string& pID) const;
 
-	/***********************************************/
-	/************** Functions: LOG set *************/
-	/***********************************************/
-
-	/// \fn void LogInfo(const std::string& pMessage)
-	/// Short variant for calling \ref DefaultLogger::get()->info()
-	void LogInfo(const std::string& pMessage) { DefaultLogger::get()->info(pMessage); }
-
-	/// \fn void LogWarning(const std::string& pMessage)
-	/// Short variant for calling \ref DefaultLogger::get()->warn()
-	void LogWarning(const std::string& pMessage) { DefaultLogger::get()->warn(pMessage); }
-
-	/// \fn void LogError(const std::string& pMessage)
-	/// Short variant for calling \ref DefaultLogger::get()->error()
-	void LogError(const std::string& pMessage) { DefaultLogger::get()->error(pMessage); }
-
-	/***********************************************/
-	/************** Functions: XML set *************/
-	/***********************************************/
-
-	/// \fn void XML_CheckNode_MustHaveChildren()
 	/// Check if current node have children: <node>...</node>. If not then exception will throwed.
 	void XML_CheckNode_MustHaveChildren();
 
-	/// \fn bool XML_CheckNode_NameEqual(const std::string& pNodeName)
-	/// Chek if current node name is equal to pNodeName.
+	/// Check if current node name is equal to pNodeName.
 	/// \param [in] pNodeName - name for checking.
 	/// return true if current node name is equal to pNodeName, else - false.
 	bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }
 
-	/// \fn void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName)
 	/// Skip unsupported node and report about that. Depend on node name can be skipped begin tag of node all whole node.
 	/// \param [in] pParentNodeName - parent node name. Used for reporting.
 	void XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName);
 
-	/// \fn bool XML_SearchNode(const std::string& pNodeName)
 	/// Search for specified node in file. XML file read pointer(mReader) will point to found node or file end after search is end.
 	/// \param [in] pNodeName - requested node name.
 	/// return true - if node is found, else - false.
 	bool XML_SearchNode(const std::string& pNodeName);
 
-	/// \fn bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx)
 	/// Read attribute value.
 	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
 	/// \return read data.
 	bool XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx);
 
-	/// \fn float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx)
 	/// Read attribute value.
 	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
 	/// \return read data.
 	float XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx);
 
-	/// \fn uint32_t XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx)
 	/// Read attribute value.
 	/// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set).
 	/// \return read data.
 	uint32_t XML_ReadNode_GetAttrVal_AsU32(const int pAttrIdx);
 
-	/// \fn float XML_ReadNode_GetVal_AsFloat()
 	/// Read node value.
 	/// \return read data.
 	float XML_ReadNode_GetVal_AsFloat();
 
-	/// \fn uint32_t XML_ReadNode_GetVal_AsU32()
 	/// Read node value.
 	/// \return read data.
 	uint32_t XML_ReadNode_GetVal_AsU32();
 
-	/// \fn void XML_ReadNode_GetVal_AsString(std::string& pValue)
 	/// Read node value.
 	/// \return read data.
 	void XML_ReadNode_GetVal_AsString(std::string& pValue);
 
-	/***********************************************/
-	/******** Functions: parse set private *********/
-	/***********************************************/
-
-	/// \fn void ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode)
 	/// Make pNode as current and enter deeper for parsing child nodes. At end \ref ParseHelper_Node_Exit must be called.
 	/// \param [in] pNode - new current node.
 	void ParseHelper_Node_Enter(CAMFImporter_NodeElement* pNode);
 
-	/// \fn void ParseHelper_Group_End()
 	/// This function must be called when exiting from grouping node. \ref ParseHelper_Group_Begin.
 	void ParseHelper_Node_Exit();
 
-	/// \fn void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString)
 	/// Attribute values of floating point types can take form ".x"(without leading zero). irrXMLReader can not read this form of values and it
 	/// must be converted to right form - "0.xxx".
 	/// \param [in] pInStr - pointer to input string which can contain incorrect form of values.
 	/// \param [out[ pOutString - output string with right form of values.
 	void ParseHelper_FixTruncatedFloatString(const char* pInStr, std::string& pOutString);
 
-	/// \fn void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const
 	/// Decode Base64-encoded data.
 	/// \param [in] pInputBase64 - reference to input Base64-encoded string.
 	/// \param [out] pOutputData - reference to output array for decoded data.
 	void ParseHelper_Decode_Base64(const std::string& pInputBase64, std::vector<uint8_t>& pOutputData) const;
 
-	/// \fn void ParseNode_Root()
 	/// Parse <AMF> node of the file.
 	void ParseNode_Root();
 
-	/******** Functions: top nodes *********/
-
-	/// \fn void ParseNode_Constellation()
 	/// Parse <constellation> node of the file.
 	void ParseNode_Constellation();
 
-	/// \fn void ParseNode_Constellation()
 	/// Parse <instance> node of the file.
 	void ParseNode_Instance();
 
-	/// \fn void ParseNode_Material()
 	/// Parse <material> node of the file.
 	void ParseNode_Material();
 
-	/// \fn void ParseNode_Metadata()
 	/// Parse <metadata> node.
 	void ParseNode_Metadata();
 
-	/// \fn void ParseNode_Object()
 	/// Parse <object> node of the file.
 	void ParseNode_Object();
 
-	/// \fn void ParseNode_Texture()
 	/// Parse <texture> node of the file.
 	void ParseNode_Texture();
 
-	/******** Functions: geometry nodes *********/
-
-	/// \fn void ParseNode_Coordinates()
 	/// Parse <coordinates> node of the file.
 	void ParseNode_Coordinates();
 
-	/// \fn void ParseNode_Edge()
 	/// Parse <edge> node of the file.
 	void ParseNode_Edge();
 
-	/// \fn void ParseNode_Mesh()
 	/// Parse <mesh> node of the file.
 	void ParseNode_Mesh();
 
-	/// \fn void ParseNode_Triangle()
 	/// Parse <triangle> node of the file.
 	void ParseNode_Triangle();
 
-	/// \fn void ParseNode_Vertex()
 	/// Parse <vertex> node of the file.
 	void ParseNode_Vertex();
 
-	/// \fn void ParseNode_Vertices()
 	/// Parse <vertices> node of the file.
 	void ParseNode_Vertices();
 
-	/// \fn void ParseNode_Volume()
 	/// Parse <volume> node of the file.
 	void ParseNode_Volume();
 
-	/******** Functions: material nodes *********/
-
-	/// \fn void ParseNode_Color()
 	/// Parse <color> node of the file.
 	void ParseNode_Color();
 
-	/// \fn void ParseNode_TexMap(const bool pUseOldName = false)
 	/// Parse <texmap> of <map> node of the file.
 	/// \param [in] pUseOldName - if true then use old name of node(and children) - <map>, instead of new name - <texmap>.
 	void ParseNode_TexMap(const bool pUseOldName = false);
 
 public:
-
-	/// \fn AMFImporter()
 	/// Default constructor.
-	AMFImporter()
-		: mNodeElement_Cur(nullptr), mReader(nullptr)
-	{}
+	AMFImporter() AI_NO_EXCEPT
+    : mNodeElement_Cur(nullptr)
+    , mReader(nullptr) {
+        // empty
+    }
 
-	/// \fn ~AMFImporter()
 	/// Default destructor.
 	~AMFImporter();
 
-	/***********************************************/
-	/******** Functions: parse set, public *********/
-	/***********************************************/
-
-	/// \fn void ParseFile(const std::string& pFile, IOSystem* pIOHandler)
 	/// Parse AMF file and fill scene graph. The function has no return value. Result can be found by analyzing the generated graph.
-	/// Also exception can be throwed if trouble will found.
+	/// Also exception can be thrown if trouble will found.
 	/// \param [in] pFile - name of file to be parsed.
 	/// \param [in] pIOHandler - pointer to IO helper object.
 	void ParseFile(const std::string& pFile, IOSystem* pIOHandler);
 
-	/***********************************************/
-	/********* Functions: BaseImporter set *********/
-	/***********************************************/
-
 	bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool pCheckSig) const;
 	void GetExtensionList(std::set<std::string>& pExtensionList);
 	void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
 	const aiImporterDesc* GetInfo ()const;
 
-};// class AMFImporter
+    AMFImporter(const AMFImporter& pScene) = delete;
+    AMFImporter& operator=(const AMFImporter& pScene) = delete;
+
+private:
+    static const aiImporterDesc Description;
+
+    CAMFImporter_NodeElement* mNodeElement_Cur;///< Current element.
+    std::list<CAMFImporter_NodeElement*> mNodeElement_List;///< All elements of scene graph.
+    irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object
+    std::string mUnit;
+    std::list<SPP_Material> mMaterial_Converted;///< List of converted materials for postprocessing step.
+    std::list<SPP_Texture> mTexture_Converted;///< List of converted textures for postprocessing step.
+
+};
 
 }// namespace Assimp
 

+ 2 - 1
code/AMFImporter_Geometry.cpp

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

+ 6 - 5
code/AMFImporter_Macro.hpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -70,7 +71,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 	}
 
 /// \def MACRO_ATTRREAD_CHECK_REF
-/// Check curent attribute name and if it equal to requested then read value. Result write to output variable by reference. If result was read then
+/// Check current attribute name and if it equal to requested then read value. Result write to output variable by reference. If result was read then
 /// "continue" will called.
 /// \param [in] pAttrName - attribute name.
 /// \param [out] pVarName - output variable name.
@@ -83,7 +84,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 	}
 
 /// \def MACRO_ATTRREAD_CHECK_RET
-/// Check curent attribute name and if it equal to requested then read value. Result write to output variable using return value of \ref pFunction.
+/// Check current attribute name and if it equal to requested then read value. Result write to output variable using return value of \ref pFunction.
 /// If result was read then  "continue" will called.
 /// \param [in] pAttrName - attribute name.
 /// \param [out] pVarName - output variable name.
@@ -129,7 +130,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 	} while(false)
 
 /// \def MACRO_NODECHECK_READCOMP_F
-/// Check curent node name and if it equal to requested then read value. Result write to output variable of type "float".
+/// Check current node name and if it equal to requested then read value. Result write to output variable of type "float".
 /// If result was read then  "continue" will called. Also check if node data already read then raise exception.
 /// \param [in] pNodeName - node name.
 /// \param [in, out] pReadFlag - read flag.
@@ -146,7 +147,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 	}
 
 /// \def MACRO_NODECHECK_READCOMP_U32
-/// Check curent node name and if it equal to requested then read value. Result write to output variable of type "uint32_t".
+/// Check current node name and if it equal to requested then read value. Result write to output variable of type "uint32_t".
 /// If result was read then  "continue" will called. Also check if node data already read then raise exception.
 /// \param [in] pNodeName - node name.
 /// \param [in, out] pReadFlag - read flag.

+ 61 - 42
code/AMFImporter_Material.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -67,10 +68,9 @@ namespace Assimp
 //   Multi elements - No.
 //   Red, Greed, Blue and Alpha (transparency) component of a color in sRGB space, values ranging from 0 to 1. The
 //   values can be specified as constants, or as a formula depending on the coordinates.
-void AMFImporter::ParseNode_Color()
-{
-std::string profile;
-CAMFImporter_NodeElement* ne;
+void AMFImporter::ParseNode_Color() {
+    std::string profile;
+    CAMFImporter_NodeElement* ne;
 
 	// Read attributes for node <color>.
 	MACRO_ATTRREAD_LOOPBEG;
@@ -97,15 +97,19 @@ CAMFImporter_NodeElement* ne;
 		MACRO_NODECHECK_LOOPEND("color");
 		ParseHelper_Node_Exit();
 		// check that all components was defined
-		if(!(read_flag[0] && read_flag[1] && read_flag[2])) throw DeadlyImportError("Not all color components are defined.");
-		// check if <a> is absent. Then manualy add "a == 1".
-		if(!read_flag[3]) als.Color.a = 1;
-
-	}// if(!mReader->isEmptyElement())
+        if (!(read_flag[0] && read_flag[1] && read_flag[2])) {
+            throw DeadlyImportError("Not all color components are defined.");
+        }
+
+        // check if <a> is absent. Then manually add "a == 1".
+        if (!read_flag[3]) {
+            als.Color.a = 1;
+        }
+	}
 	else
 	{
 		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
+	}
 
 	als.Composed = false;
 	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
@@ -118,10 +122,9 @@ CAMFImporter_NodeElement* ne;
 // An available material.
 // Multi elements - Yes.
 // Parent element - <amf>.
-void AMFImporter::ParseNode_Material()
-{
-std::string id;
-CAMFImporter_NodeElement* ne;
+void AMFImporter::ParseNode_Material() {
+    std::string id;
+    CAMFImporter_NodeElement* ne;
 
 	// Read attributes for node <color>.
 	MACRO_ATTRREAD_LOOPBEG;
@@ -130,9 +133,11 @@ CAMFImporter_NodeElement* ne;
 
 	// create new object.
 	ne = new CAMFImporter_NodeElement_Material(mNodeElement_Cur);
-	// and assign read data
+
+    // and assign read data
 	((CAMFImporter_NodeElement_Material*)ne)->ID = id;
-	// Check for child nodes
+
+    // Check for child nodes
 	if(!mReader->isEmptyElement())
 	{
 		bool col_read = false;
@@ -153,11 +158,11 @@ CAMFImporter_NodeElement* ne;
 			if(XML_CheckNode_NameEqual("metadata")) { ParseNode_Metadata(); continue; }
 		MACRO_NODECHECK_LOOPEND("material");
 		ParseHelper_Node_Exit();
-	}// if(!mReader->isEmptyElement())
+	}
 	else
 	{
 		mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
-	}// if(!mReader->isEmptyElement()) else
+	}
 
 	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
 }
@@ -180,14 +185,13 @@ CAMFImporter_NodeElement* ne;
 // Parent element - <amf>.
 void AMFImporter::ParseNode_Texture()
 {
-std::string id;
-uint32_t width = 0;
-uint32_t height = 0;
-uint32_t depth = 1;
-std::string type;
-bool tiled = false;
-std::string enc64_data;
-CAMFImporter_NodeElement* ne;
+    std::string id;
+    uint32_t width = 0;
+    uint32_t height = 0;
+    uint32_t depth = 1;
+    std::string type;
+    bool tiled = false;
+    std::string enc64_data;
 
 	// Read attributes for node <color>.
 	MACRO_ATTRREAD_LOOPBEG;
@@ -200,20 +204,34 @@ CAMFImporter_NodeElement* ne;
 	MACRO_ATTRREAD_LOOPEND;
 
 	// create new texture object.
-	ne = new CAMFImporter_NodeElement_Texture(mNodeElement_Cur);
+    CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_Texture(mNodeElement_Cur);
 
 	CAMFImporter_NodeElement_Texture& als = *((CAMFImporter_NodeElement_Texture*)ne);// alias for convenience
 
 	// Check for child nodes
-	if(!mReader->isEmptyElement()) XML_ReadNode_GetVal_AsString(enc64_data);
+    if (!mReader->isEmptyElement()) {
+        XML_ReadNode_GetVal_AsString(enc64_data);
+    }
 
 	// check that all components was defined
-	if(id.empty()) throw DeadlyImportError("ID for texture must be defined.");
-	if(width < 1) Throw_IncorrectAttrValue("width");
-	if(height < 1) Throw_IncorrectAttrValue("height");
-	if(depth < 1) Throw_IncorrectAttrValue("depth");
-	if(type != "grayscale") Throw_IncorrectAttrValue("type");
-	if(enc64_data.empty()) throw DeadlyImportError("Texture data not defined.");
+    if (id.empty()) {
+        throw DeadlyImportError("ID for texture must be defined.");
+    }
+    if (width < 1) {
+        Throw_IncorrectAttrValue("width");
+    }
+    if (height < 1) {
+        Throw_IncorrectAttrValue("height");
+    }
+    if (depth < 1) {
+        Throw_IncorrectAttrValue("depth");
+    }
+    if (type != "grayscale") {
+        Throw_IncorrectAttrValue("type");
+    }
+    if (enc64_data.empty()) {
+        throw DeadlyImportError("Texture data not defined.");
+    }
 	// copy data
 	als.ID = id;
 	als.Width = width;
@@ -221,8 +239,11 @@ CAMFImporter_NodeElement* ne;
 	als.Depth = depth;
 	als.Tiled = tiled;
 	ParseHelper_Decode_Base64(enc64_data, als.Data);
-	// check data size
-	if((width * height * depth) != als.Data.size()) throw DeadlyImportError("Texture has incorrect data size.");
+
+    // check data size
+    if ((width * height * depth) != als.Data.size()) {
+        throw DeadlyImportError("Texture has incorrect data size.");
+    }
 
 	mNodeElement_Cur->Child.push_back(ne);// Add element to child list of current element
 	mNodeElement_List.push_back(ne);// and to node element list because its a new object in graph.
@@ -242,10 +263,8 @@ CAMFImporter_NodeElement* ne;
 //   <utex1>, <utex2>, <utex3>, <vtex1>, <vtex2>, <vtex3>. Old name: <u1>, <u2>, <u3>, <v1>, <v2>, <v3>.
 //   Multi elements - No.
 //   Texture coordinates for every vertex of triangle.
-void AMFImporter::ParseNode_TexMap(const bool pUseOldName)
-{
-std::string rtexid, gtexid, btexid, atexid;
-CAMFImporter_NodeElement* ne;
+void AMFImporter::ParseNode_TexMap(const bool pUseOldName) {
+    std::string rtexid, gtexid, btexid, atexid;
 
 	// Read attributes for node <color>.
 	MACRO_ATTRREAD_LOOPBEG;
@@ -256,7 +275,7 @@ CAMFImporter_NodeElement* ne;
 	MACRO_ATTRREAD_LOOPEND;
 
 	// create new texture coordinates object.
-	ne = new CAMFImporter_NodeElement_TexMap(mNodeElement_Cur);
+    CAMFImporter_NodeElement *ne = new CAMFImporter_NodeElement_TexMap(mNodeElement_Cur);
 
 	CAMFImporter_NodeElement_TexMap& als = *((CAMFImporter_NodeElement_TexMap*)ne);// alias for convenience
 	// check data

+ 65 - 125
code/AMFImporter_Node.hpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -61,7 +62,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /// \class CAMFImporter_NodeElement
 /// Base class for elements of nodes.
 class CAMFImporter_NodeElement {
-
 public:
 	/// Define what data type contain node element.
 	enum EType {
@@ -95,15 +95,11 @@ public:                                               /// Destructor, virtual..
         // empty
     }
 
-private:
-	/// Disabled copy constructor.
-	CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement);
-
-	/// Disabled assign operator.
-	CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement);
-
-	/// Disabled default constructor.
-	CAMFImporter_NodeElement();
+	/// Disabled copy constructor and co.
+	CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement) = delete;
+    CAMFImporter_NodeElement(CAMFImporter_NodeElement&&) = delete;
+    CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement) = delete;
+	CAMFImporter_NodeElement() = delete;
 
 protected:
 	/// In constructor inheritor must set element type.
@@ -120,9 +116,7 @@ protected:
 
 /// \struct CAMFImporter_NodeElement_Constellation
 /// A collection of objects or constellations with specific relative locations.
-struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement
-{
-	/// \fn CAMFImporter_NodeElement_Constellation(CAMFImporter_NodeElement* pParent)
+struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement {
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Constellation(CAMFImporter_NodeElement* pParent)
@@ -133,11 +127,9 @@ struct CAMFImporter_NodeElement_Constellation : public CAMFImporter_NodeElement
 
 /// \struct CAMFImporter_NodeElement_Instance
 /// Part of constellation.
-struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement
-{
-	/****************** Variables ******************/
+struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement {
 
-	std::string ObjectID;///< ID of object for instanciation.
+	std::string ObjectID;///< ID of object for instantiation.
 	/// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to
 	/// create an instance of the object in the current constellation.
 	aiVector3D Delta;
@@ -146,237 +138,185 @@ struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement
 	/// instance of the object in the current constellation. Rotations shall be executed in order of x first, then y, then z.
 	aiVector3D Rotation;
 
-	/****************** Functions ******************/
-
-	/// \fn CAMFImporter_NodeElement_Instance(CAMFImporter_NodeElement* pParent)
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Instance(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Instance, pParent)
 	{}
-
-};// struct CAMFImporter_NodeElement_Instance
+};
 
 /// \struct CAMFImporter_NodeElement_Metadata
 /// Structure that define metadata node.
-struct CAMFImporter_NodeElement_Metadata : public CAMFImporter_NodeElement
-{
-	/****************** Variables ******************/
+struct CAMFImporter_NodeElement_Metadata : public CAMFImporter_NodeElement {
 
-	std::string Type;///< Type of "Value".
+	std::string Type;///< Type of "Value". 
 	std::string Value;///< Value.
 
-	/****************** Functions ******************/
-
-	/// \fn CAMFImporter_NodeElement_Metadata(CAMFImporter_NodeElement* pParent)
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Metadata(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Metadata, pParent)
 	{}
-
-};// struct CAMFImporter_NodeElement_Metadata
+};
 
 /// \struct CAMFImporter_NodeElement_Root
 /// Structure that define root node.
-struct CAMFImporter_NodeElement_Root : public CAMFImporter_NodeElement
-{
-	/****************** Variables ******************/
+struct CAMFImporter_NodeElement_Root : public CAMFImporter_NodeElement {
 
 	std::string Unit;///< The units to be used. May be "inch", "millimeter", "meter", "feet", or "micron".
 	std::string Version;///< Version of format.
 
-	/****************** Functions ******************/
-
-	/// \fn CAMFImporter_NodeElement_Root(CAMFImporter_NodeElement* pParent)
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Root(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Root, pParent)
 	{}
-
-};// struct CAMFImporter_NodeElement_Root
+};
 
 /// \struct CAMFImporter_NodeElement_Color
 /// Structure that define object node.
-struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement
-{
-	/****************** Variables ******************/
-
-	bool Composed;///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color.
-	std::string Color_Composed[4];///< By components formulas of composed color. [0..3] => RGBA.
-	aiColor4D Color;///< Constant color.
-	std::string Profile;///< The ICC color space used to interpret the three color channels <r>, <g> and <b>..
-
-	/****************** Functions ******************/
-
-	/// \fn CAMFImporter_NodeElement_Color(CAMFImporter_NodeElement* pParent)
-	/// Constructor.
-	/// \param [in] pParent - pointer to parent node.
+struct CAMFImporter_NodeElement_Color : public CAMFImporter_NodeElement {
+	bool Composed;                  ///< Type of color stored: if true then look for formula in \ref Color_Composed[4], else - in \ref Color.
+	std::string Color_Composed[4];  ///< By components formulas of composed color. [0..3] - RGBA.
+	aiColor4D Color;                ///< Constant color.
+	std::string Profile;            ///< The ICC color space used to interpret the three color channels r, g and b..
+
+	/// @brief  Constructor.
+	/// @param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Color(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Color, pParent)
-	{}
-
-};// struct CAMFImporter_NodeElement_Color
+	: CAMFImporter_NodeElement(ENET_Color, pParent)
+    , Composed( false )
+    , Color()
+    , Profile() {
+        // empty
+    }
+};
 
 /// \struct CAMFImporter_NodeElement_Material
 /// Structure that define material node.
-struct CAMFImporter_NodeElement_Material : public CAMFImporter_NodeElement
-{
-	/// \fn CAMFImporter_NodeElement_Material(CAMFImporter_NodeElement* pParent)
+struct CAMFImporter_NodeElement_Material : public CAMFImporter_NodeElement {
+	
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Material(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Material, pParent)
 	{}
 
-};// struct CAMFImporter_NodeElement_Material
+};
 
 /// \struct CAMFImporter_NodeElement_Object
 /// Structure that define object node.
-struct CAMFImporter_NodeElement_Object : public CAMFImporter_NodeElement
-{
-	/// \fn CAMFImporter_NodeElement_Object(CAMFImporter_NodeElement* pParent)
-	/// Constructor.
+struct CAMFImporter_NodeElement_Object : public CAMFImporter_NodeElement {
+
+    /// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Object(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Object, pParent)
 	{}
-
-};// struct CAMFImporter_NodeElement_Object
+};
 
 /// \struct CAMFImporter_NodeElement_Mesh
 /// Structure that define mesh node.
-struct CAMFImporter_NodeElement_Mesh : public CAMFImporter_NodeElement
-{
-	/// \fn CAMFImporter_NodeElement_Mesh(CAMFImporter_NodeElement* pParent)
+struct CAMFImporter_NodeElement_Mesh : public CAMFImporter_NodeElement {
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Mesh(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Mesh, pParent)
 	{}
-
-};// struct CAMFImporter_NodeElement_Mesh
+};
 
 /// \struct CAMFImporter_NodeElement_Vertex
 /// Structure that define vertex node.
-struct CAMFImporter_NodeElement_Vertex : public CAMFImporter_NodeElement
-{
-	/// \fn CAMFImporter_NodeElement_Vertex(CAMFImporter_NodeElement* pParent)
+struct CAMFImporter_NodeElement_Vertex : public CAMFImporter_NodeElement {
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Vertex(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Vertex, pParent)
 	{}
-
-};// struct CAMFImporter_NodeElement_Vertex
+};
 
 /// \struct CAMFImporter_NodeElement_Edge
 /// Structure that define edge node.
-struct CAMFImporter_NodeElement_Edge : public CAMFImporter_NodeElement
-{
-	/// \fn CAMFImporter_NodeElement_Edge(CAMFImporter_NodeElement* pParent)
+struct CAMFImporter_NodeElement_Edge : public CAMFImporter_NodeElement {
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Edge(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Edge, pParent)
 	{}
 
-};// struct CAMFImporter_NodeElement_Vertex
+};
 
 /// \struct CAMFImporter_NodeElement_Vertices
 /// Structure that define vertices node.
-struct CAMFImporter_NodeElement_Vertices : public CAMFImporter_NodeElement
-{
-	/// \fn CAMFImporter_NodeElement_Vertices(CAMFImporter_NodeElement* pParent)
+struct CAMFImporter_NodeElement_Vertices : public CAMFImporter_NodeElement {
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Vertices(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Vertices, pParent)
 	{}
-
-};// struct CAMFImporter_NodeElement_Vertices
+};
 
 /// \struct CAMFImporter_NodeElement_Volume
 /// Structure that define volume node.
-struct CAMFImporter_NodeElement_Volume : public CAMFImporter_NodeElement
-{
-	/****************** Variables ******************/
-
+struct CAMFImporter_NodeElement_Volume : public CAMFImporter_NodeElement {
 	std::string MaterialID;///< Which material to use.
 	std::string Type;///< What this volume describes can be “region” or “support”. If none specified, “object” is assumed.
 
-	/****************** Functions ******************/
-
-	/// \fn CAMFImporter_NodeElement_Volume(CAMFImporter_NodeElement* pParent)
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Volume(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Volume, pParent)
 	{}
-
-};// struct CAMFImporter_NodeElement_Volume
+};
 
 /// \struct CAMFImporter_NodeElement_Coordinates
 /// Structure that define coordinates node.
 struct CAMFImporter_NodeElement_Coordinates : public CAMFImporter_NodeElement
 {
-	/****************** Variables ******************/
-
 	aiVector3D Coordinate;///< Coordinate.
 
-	/****************** Functions ******************/
-
-	/// \fn CAMFImporter_NodeElement_Coordinates(CAMFImporter_NodeElement* pParent)
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Coordinates(CAMFImporter_NodeElement* pParent)
 		: CAMFImporter_NodeElement(ENET_Coordinates, pParent)
 	{}
 
-};// struct CAMFImporter_NodeElement_Coordinates
+};
 
 /// \struct CAMFImporter_NodeElement_TexMap
 /// Structure that define texture coordinates node.
-struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement
-{
-	/****************** Variables ******************/
-
+struct CAMFImporter_NodeElement_TexMap : public CAMFImporter_NodeElement {
 	aiVector3D TextureCoordinate[3];///< Texture coordinates.
 	std::string TextureID_R;///< Texture ID for red color component.
 	std::string TextureID_G;///< Texture ID for green color component.
 	std::string TextureID_B;///< Texture ID for blue color component.
 	std::string TextureID_A;///< Texture ID for alpha color component.
 
-	/****************** Functions ******************/
-
-	/// \fn CAMFImporter_NodeElement_TexMap(CAMFImporter_NodeElement* pParent)
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_TexMap(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_TexMap, pParent)
-	{}
-
-};// struct CAMFImporter_NodeElement_TexMap
+	: CAMFImporter_NodeElement(ENET_TexMap, pParent)
+    , TextureCoordinate{}
+    , TextureID_R()
+    , TextureID_G()
+    , TextureID_B()
+    , TextureID_A()	{
+        // empty
+    }
+};
 
 /// \struct CAMFImporter_NodeElement_Triangle
 /// Structure that define triangle node.
-struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement
-{
-	/****************** Variables ******************/
-
+struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement {
 	size_t V[3];///< Triangle vertices.
 
-	/****************** Functions ******************/
-
-	/// \fn CAMFImporter_NodeElement_Triangle(CAMFImporter_NodeElement* pParent)
 	/// Constructor.
 	/// \param [in] pParent - pointer to parent node.
 	CAMFImporter_NodeElement_Triangle(CAMFImporter_NodeElement* pParent)
-		: CAMFImporter_NodeElement(ENET_Triangle, pParent)
-	{}
-
-};// struct CAMFImporter_NodeElement_Triangle
+	: CAMFImporter_NodeElement(ENET_Triangle, pParent) {
+        // empty
+    }
+};
 
 /// Structure that define texture node.
 struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement {
@@ -395,6 +335,6 @@ struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement {
     , Tiled( false ){
         // empty
     }
-};// struct CAMFImporter_NodeElement_Texture
+};
 
 #endif // INCLUDED_AI_AMF_IMPORTER_NODE_H

+ 16 - 12
code/AMFImporter_Postprocess.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -51,8 +52,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // Header files, Assimp.
 #include <assimp/SceneCombiner.h>
-#include "StandardShapes.h"
-#include "StringUtils.h"
+#include <assimp/StandardShapes.h>
+#include <assimp/StringUtils.h>
 
 // Header files, stdlib.
 #include <iterator>
@@ -60,7 +61,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp
 {
 
-aiColor4D AMFImporter::SPP_Material::GetColor(const float pX, const float pY, const float pZ) const
+aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*pY*/, const float /*pZ*/) const
 {
     aiColor4D tcol;
 
@@ -155,10 +156,11 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string&
 	TextureConverted_Index = 0;
 	for(const SPP_Texture& tex_convd: mTexture_Converted)
 	{
-		if(tex_convd.ID == TextureConverted_ID)
-			return TextureConverted_Index;
-		else
-			TextureConverted_Index++;
+        if ( tex_convd.ID == TextureConverted_ID ) {
+            return TextureConverted_Index;
+        } else {
+            ++TextureConverted_Index;
+        }
 	}
 
 	//
@@ -281,8 +283,11 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string&
 	{
 		if(!pID.empty())
 		{
-			for(size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++)
-				converted_texture.Data[idx_target] = src_texture[pSrcTexNum]->Data.at(idx_src);
+			for(size_t idx_target = pOffset, idx_src = 0; idx_target < tex_size; idx_target += pStep, idx_src++) {
+				CAMFImporter_NodeElement_Texture* tex = src_texture[pSrcTexNum];
+				ai_assert(tex);
+				converted_texture.Data[idx_target] = tex->Data.at(idx_src);
+			}
 		}
 	};// auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
 
@@ -686,7 +691,6 @@ std::list<unsigned int> mesh_idx;
 				tmesh->mNumVertices = static_cast<unsigned int>(vert_arr.size());
 				tmesh->mVertices = new aiVector3D[tmesh->mNumVertices];
 				tmesh->mColors[0] = new aiColor4D[tmesh->mNumVertices];
-				tmesh->mFaces = new aiFace[face_list_cur.size()];
 
 				memcpy(tmesh->mVertices, vert_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D));
 				memcpy(tmesh->mColors[0], col_arr.data(), tmesh->mNumVertices * sizeof(aiColor4D));
@@ -766,7 +770,7 @@ std::list<aiNode*> ch_node;
 		// find referenced object
 		if(!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID);
 
-		// create node for apllying transformation
+		// create node for applying transformation
 		t_node = new aiNode;
 		t_node->mParent = con_node;
 		// apply transformation

+ 22 - 21
code/ASELoader.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -50,8 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // internal headers
 #include "ASELoader.h"
-#include "StringComparison.h"
-#include "SkeletonMeshBuilder.h"
+#include <assimp/StringComparison.h>
+#include <assimp/SkeletonMeshBuilder.h>
 #include "TargetAnimation.h"
 #include <assimp/Importer.hpp>
 #include <assimp/IOSystem.hpp>
@@ -62,7 +63,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <memory>
 
 // utilities
-#include "fast_atof.h"
+#include <assimp/fast_atof.h>
 
 using namespace Assimp;
 using namespace Assimp::ASE;
@@ -83,11 +84,11 @@ static const aiImporterDesc desc = {
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 ASEImporter::ASEImporter()
-    : mParser(),
-    mBuffer(),
-    pcScene(),
-    configRecomputeNormals(),
-    noSkeletonMesh()
+: mParser()
+, mBuffer()
+, pcScene()
+, configRecomputeNormals()
+, noSkeletonMesh()
 {}
 
 // ------------------------------------------------------------------------------------------------
@@ -199,7 +200,7 @@ void ASEImporter::InternReadFile( const std::string& pFile,
             ConvertMeshes(*i,avOutMeshes);
         }
         if (tookNormals)    {
-            DefaultLogger::get()->debug("ASE: Taking normals from the file. Use "
+            ASSIMP_LOG_DEBUG("ASE: Taking normals from the file. Use "
                 "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you "
                 "experience problems");
         }
@@ -276,14 +277,13 @@ void ASEImporter::GenerateDefaultMaterial()
     }
     if (bHas || mParser->m_vMaterials.empty())  {
         // add a simple material without submaterials to the parser's list
-        mParser->m_vMaterials.push_back ( ASE::Material() );
+        mParser->m_vMaterials.push_back ( ASE::Material(AI_DEFAULT_MATERIAL_NAME) );
         ASE::Material& mat = mParser->m_vMaterials.back();
 
         mat.mDiffuse  = aiColor3D(0.6f,0.6f,0.6f);
         mat.mSpecular = aiColor3D(1.0f,1.0f,1.0f);
         mat.mAmbient  = aiColor3D(0.05f,0.05f,0.05f);
         mat.mShading  = Discreet3DS::Gouraud;
-        mat.mName     = AI_DEFAULT_MATERIAL_NAME;
     }
 }
 
@@ -297,15 +297,15 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
 
         // TODO: Implement Bezier & TCB support
         if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) {
-            DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
+            ASSIMP_LOG_WARN("ASE: Position controller uses Bezier/TCB keys. "
                 "This is not supported.");
         }
         if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) {
-            DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. "
+            ASSIMP_LOG_WARN("ASE: Rotation controller uses Bezier/TCB keys. "
                 "This is not supported.");
         }
         if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK)  {
-            DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. "
+            ASSIMP_LOG_WARN("ASE: Position controller uses Bezier/TCB keys. "
                 "This is not supported.");
         }
 
@@ -583,7 +583,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
         node->mTransformation = mParentAdjust*snode->mTransform;
 
         // Add sub nodes - prevent stack overflow due to recursive parenting
-        if (node->mName != node->mParent->mName) {
+        if (node->mName != node->mParent->mName && node->mName != node->mParent->mParent->mName ) {
             AddNodes(nodes,node,node->mName.data,snode->mTransform);
         }
 
@@ -624,7 +624,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
             node->mNumChildren++;
 
             // What we did is so great, it is at least worth a debug message
-            DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")");
+            ASSIMP_LOG_DEBUG("ASE: Generating separate target node ("+snode->mName+")");
         }
     }
 
@@ -947,7 +947,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
     // validate the material index of the mesh
     if (mesh.iMaterialIndex >= mParser->m_vMaterials.size())    {
         mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1;
-        DefaultLogger::get()->warn("Material index is out of range");
+        ASSIMP_LOG_WARN("Material index is out of range");
     }
 
     // If the material the mesh is assigned to is consisting of submeshes, split it
@@ -957,11 +957,11 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 
         std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
 
-        // build a list of all faces per submaterial
+        // build a list of all faces per sub-material
         for (unsigned int i = 0; i < mesh.mFaces.size();++i)    {
             // check range
             if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) {
-                DefaultLogger::get()->warn("Submaterial index is out of range");
+                ASSIMP_LOG_WARN("Submaterial index is out of range");
 
                 // use the last material instead
                 aiSplit[vSubMaterials.size()-1].push_back(i);
@@ -1021,6 +1021,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 
                             // convert bones, if existing
                             if (!mesh.mBones.empty()) {
+                                ai_assert(avOutputBones);
                                 // check whether there is a vertex weight for this vertex index
                                 if (iIndex2 < mesh.mBoneVertices.size())    {
 
@@ -1298,7 +1299,7 @@ void ASEImporter::BuildMaterialIndices()
         }
     }
 
-    // Dekete our temporary array
+    // Delete our temporary array
     delete[] pcIntMaterials;
 }
 

+ 3 - 2
code/ASELoader.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -45,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_ASELOADER_H_INCLUDED
 #define AI_ASELOADER_H_INCLUDED
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 #include <assimp/types.h>
 #include "ASEParser.h"
 

+ 36 - 34
code/ASEParser.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -44,14 +45,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Implementation of the ASE parser class
  */
 
-
 #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
 #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
 
 // internal headers
 #include "TextureTransform.h"
 #include "ASELoader.h"
-#include "fast_atof.h"
+#include <assimp/fast_atof.h>
 #include <assimp/DefaultLogger.hpp>
 
 using namespace Assimp;
@@ -150,7 +150,7 @@ void Parser::LogWarning(const char* szWarn)
 #endif
 
     // output the warning to the logger ...
-    DefaultLogger::get()->warn(szTemp);
+    ASSIMP_LOG_WARN(szTemp);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -166,7 +166,7 @@ void Parser::LogInfo(const char* szWarn)
 #endif
 
     // output the information to the logger ...
-    DefaultLogger::get()->info(szTemp);
+    ASSIMP_LOG_INFO(szTemp);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -266,7 +266,9 @@ void Parser::Parse()
                 // at the file extension (ASE, ASK, ASC)
                 // *************************************************************
 
-                if (fmt)iFileFormat = fmt;
+                if ( fmt ) {
+                    iFileFormat = fmt;
+                }
                 continue;
             }
             // main scene information
@@ -292,7 +294,7 @@ void Parser::Parse()
             if (TokenMatch(filePtr,"GEOMOBJECT",10))
 
             {
-                m_vMeshes.push_back(Mesh());
+                m_vMeshes.push_back(Mesh("UNNAMED"));
                 ParseLV1ObjectBlock(m_vMeshes.back());
                 continue;
             }
@@ -308,14 +310,14 @@ void Parser::Parse()
             if (TokenMatch(filePtr,"LIGHTOBJECT",11))
 
             {
-                m_vLights.push_back(Light());
+                m_vLights.push_back(Light("UNNAMED"));
                 ParseLV1ObjectBlock(m_vLights.back());
                 continue;
             }
             // camera object
             if (TokenMatch(filePtr,"CAMERAOBJECT",12))
             {
-                m_vCameras.push_back(Camera());
+                m_vCameras.push_back(Camera("UNNAMED"));
                 ParseLV1ObjectBlock(m_vCameras.back());
                 continue;
             }
@@ -426,28 +428,25 @@ void Parser::ParseLV1SoftSkinBlock()
                         // Reserve enough storage
                         vert.mBoneWeights.reserve(numWeights);
 
-                        for (unsigned int w = 0; w < numWeights;++w)
-                        {
-                            std::string bone;
+                        std::string bone;
+                        for (unsigned int w = 0; w < numWeights;++w) {
+                            bone.clear();
                             ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
 
                             // Find the bone in the mesh's list
                             std::pair<int,ai_real> me;
                             me.first = -1;
 
-                            for (unsigned int n = 0; n < curMesh->mBones.size();++n)
-                            {
-                                if (curMesh->mBones[n].mName == bone)
-                                {
+                            for (unsigned int n = 0; n < curMesh->mBones.size();++n) {
+                                if (curMesh->mBones[n].mName == bone) {
                                     me.first = n;
                                     break;
                                 }
                             }
-                            if (-1 == me.first)
-                            {
+                            if (-1 == me.first) {
                                 // We don't have this bone yet, so add it to the list
-                                me.first = (int)curMesh->mBones.size();
-                                curMesh->mBones.push_back(ASE::Bone(bone));
+                                me.first = static_cast<int>( curMesh->mBones.size() );
+                                curMesh->mBones.push_back( ASE::Bone( bone ) );
                             }
                             ParseLV4MeshFloat( me.second );
 
@@ -528,7 +527,7 @@ void Parser::ParseLV1MaterialListBlock()
                 ParseLV4MeshLong(iMaterialCount);
 
                 // now allocate enough storage to hold all materials
-                m_vMaterials.resize(iOldMaterialCount+iMaterialCount);
+                m_vMaterials.resize(iOldMaterialCount+iMaterialCount, Material("INVALID"));
                 continue;
             }
             if (TokenMatch(filePtr,"MATERIAL",8))
@@ -706,7 +705,7 @@ void Parser::ParseLV2MaterialBlock(ASE::Material& mat)
                 ParseLV4MeshLong(iNumSubMaterials);
 
                 // allocate enough storage
-                mat.avSubMaterials.resize(iNumSubMaterials);
+                mat.avSubMaterials.resize(iNumSubMaterials, Material("INVALID SUBMATERIAL"));
             }
             // submaterial chunks
             if (TokenMatch(filePtr,"SUBMATERIAL",11))
@@ -744,6 +743,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
     // empty the texture won't be used later.
     // ***********************************************************
     bool parsePath = true;
+    std::string temp;
     while (true)
     {
         if ('*' == *filePtr)
@@ -752,12 +752,12 @@ void Parser::ParseLV3MapBlock(Texture& map)
             // type of map
             if (TokenMatch(filePtr,"MAP_CLASS" ,9))
             {
-                std::string temp;
+                temp.clear();
                 if(!ParseString(temp,"*MAP_CLASS"))
                     SkipToNextToken();
                 if (temp != "Bitmap" && temp != "Normal Bump")
                 {
-                    DefaultLogger::get()->warn("ASE: Skipping unknown map type: " + temp);
+                    ASSIMP_LOG_WARN_F("ASE: Skipping unknown map type: ", temp);
                     parsePath = false;
                 }
                 continue;
@@ -772,7 +772,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
                 {
                     // Files with 'None' as map name are produced by
                     // an Maja to ASE exporter which name I forgot ..
-                    DefaultLogger::get()->warn("ASE: Skipping invalid map entry");
+                    ASSIMP_LOG_WARN("ASE: Skipping invalid map entry");
                     map.mMapName = "";
                 }
 
@@ -1071,7 +1071,7 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh)
                         ( mesh.mType != BaseNode::Light  || ((ASE::Light&)mesh).mLightType   != ASE::Light::TARGET))
                     {
 
-                        DefaultLogger::get()->error("ASE: Found target animation channel "
+                        ASSIMP_LOG_ERROR("ASE: Found target animation channel "
                             "but the node is neither a camera nor a spot light");
                         anim = NULL;
                     }
@@ -1097,7 +1097,7 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh)
                 if (!anim || anim == &mesh.mTargetAnim)
                 {
                     // Target animation channels may have no rotation channels
-                    DefaultLogger::get()->error("ASE: Ignoring scaling channel in target animation");
+                    ASSIMP_LOG_ERROR("ASE: Ignoring scaling channel in target animation");
                     SkipSection();
                 }
                 else ParseLV3ScaleAnimationBlock(*anim);
@@ -1111,7 +1111,7 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh)
                 if (!anim || anim == &mesh.mTargetAnim)
                 {
                     // Target animation channels may have no rotation channels
-                    DefaultLogger::get()->error("ASE: Ignoring rotation channel in target animation");
+                    ASSIMP_LOG_ERROR("ASE: Ignoring rotation channel in target animation");
                     SkipSection();
                 }
                 else ParseLV3RotAnimationBlock(*anim);
@@ -1294,12 +1294,14 @@ void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode& mesh)
                     {
                         mode = 2;
                     }
-                    else DefaultLogger::get()->error("ASE: Ignoring target transform, "
-                        "this is no spot light or target camera");
+                    else {
+                        ASSIMP_LOG_ERROR("ASE: Ignoring target transform, "
+                            "this is no spot light or target camera");
+                    }
                 }
                 else
                 {
-                    DefaultLogger::get()->error("ASE: Unknown node transformation: " + temp);
+                    ASSIMP_LOG_ERROR("ASE: Unknown node transformation: " + temp);
                     // mode = 0
                 }
                 continue;
@@ -1553,7 +1555,7 @@ void Parser::ParseLV3MeshWeightsBlock(ASE::Mesh& mesh)
 void Parser::ParseLV4MeshBones(unsigned int iNumBones,ASE::Mesh& mesh)
 {
     AI_ASE_PARSER_INIT();
-    mesh.mBones.resize(iNumBones);
+    mesh.mBones.resize(iNumBones, Bone("UNNAMED"));
     while (true)
     {
         if ('*' == *filePtr)
@@ -1915,7 +1917,7 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
                 else if (index == face.mIndices[2])
                     index = 2;
                 else    {
-                    DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
+                    ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
                     continue;
                 }
                 // We'll renormalize later
@@ -1927,7 +1929,7 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
                 ParseLV4MeshFloatTriple(&vNormal.x,faceIdx);
 
                 if (faceIdx >= sMesh.mFaces.size()) {
-                    DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section");
+                    ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_FACENORMAL section");
                     continue;
                 }
 

+ 131 - 107
code/ASEParser.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -52,8 +53,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
 
 // for some helper routines like IsSpace()
-#include "ParsingUtils.h"
-#include "qnan.h"
+#include <assimp/ParsingUtils.h>
+#include <assimp/qnan.h>
 
 // ASE is quite similar to 3ds. We can reuse some structures
 #include "3DSLoader.h"
@@ -67,9 +68,51 @@ using namespace D3DS;
 /** Helper structure representing an ASE material */
 struct Material : public D3DS::Material
 {
-    //! Default constructor
-    Material() : pcInstance(NULL), bNeed (false)
-    {}
+    //! Default constructor has been deleted
+    Material() = delete;
+
+    //! Constructor with explicit name
+    explicit Material(const std::string &name)
+    : D3DS::Material(name)
+    , pcInstance(NULL)
+    , bNeed (false) {
+        // empty
+    }
+
+    Material(const Material &other)            = default;
+    Material &operator=(const Material &other) = default;
+
+
+    //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
+    Material(Material &&other) AI_NO_EXCEPT
+    : D3DS::Material(std::move(other))
+    , avSubMaterials(std::move(other.avSubMaterials))
+    , pcInstance(std::move(other.pcInstance))
+    , bNeed(std::move(other.bNeed))
+    {
+        other.pcInstance = nullptr;
+    }
+
+
+    Material &operator=(Material &&other) AI_NO_EXCEPT {
+        if (this == &other) {
+            return *this;
+        }
+
+        D3DS::Material::operator=(std::move(other));
+
+        avSubMaterials = std::move(other.avSubMaterials);
+        pcInstance = std::move(other.pcInstance);
+        bNeed = std::move(other.bNeed);
+
+        other.pcInstance = nullptr;
+
+        return *this;
+    }
+
+
+    ~Material() {}
+
 
     //! Contains all sub materials of this material
     std::vector<Material> avSubMaterials;
@@ -83,19 +126,12 @@ struct Material : public D3DS::Material
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file face */
-struct Face : public FaceWithSmoothingGroup
-{
+struct Face : public FaceWithSmoothingGroup {
     //! Default constructor. Initializes everything with 0
-    Face()
-    {
-        mColorIndices[0] = mColorIndices[1] = mColorIndices[2] = 0;
-        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
-        {
-            amUVIndices[i][0] = amUVIndices[i][1] = amUVIndices[i][2] = 0;
-        }
-
-        iMaterial = DEFAULT_MATINDEX;
-        iFace = 0;
+    Face() AI_NO_EXCEPT
+    : iMaterial(DEFAULT_MATINDEX)
+    , iFace(0) {
+        // empty
     }
 
     //! special value to indicate that no material index has
@@ -103,8 +139,6 @@ struct Face : public FaceWithSmoothingGroup
     //! will replace this value later.
     static const unsigned int DEFAULT_MATINDEX = 0xFFFFFFFF;
 
-
-
     //! Indices into each list of texture coordinates
     unsigned int amUVIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS][3];
 
@@ -122,23 +156,15 @@ struct Face : public FaceWithSmoothingGroup
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file bone */
-struct Bone
-{
+struct Bone {
     //! Constructor
-    Bone()
-    {
-        static int iCnt = 0;
-
-        // Generate a default name for the bone
-        char szTemp[128];
-        ::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
-        mName = szTemp;
-    }
+    Bone() = delete;
 
     //! Construction from an existing name
     explicit Bone( const std::string& name)
-        :   mName   (name)
-    {}
+    : mName(name) {
+        // empty
+    }
 
     //! Name of the bone
     std::string mName;
@@ -146,33 +172,27 @@ struct Bone
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file bone vertex */
-struct BoneVertex
-{
+struct BoneVertex {
     //! Bone and corresponding vertex weight.
     //! -1 for unrequired bones ....
     std::vector<std::pair<int,float> > mBoneWeights;
-
-    //! Position of the bone vertex.
-    //! MUST be identical to the vertex position
-    //aiVector3D mPosition;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file animation */
-struct Animation
-{
-    enum Type
-    {
+struct Animation {
+    enum Type {
         TRACK   = 0x0,
         BEZIER  = 0x1,
         TCB     = 0x2
     } mRotationType, mScalingType, mPositionType;
 
-    Animation()
-        :   mRotationType   (TRACK)
-        ,   mScalingType    (TRACK)
-        ,   mPositionType   (TRACK)
-    {}
+    Animation() AI_NO_EXCEPT
+    :   mRotationType   (TRACK)
+    ,   mScalingType    (TRACK)
+    ,   mPositionType   (TRACK) {
+        // empty
+    }
 
     //! List of track rotation keyframes
     std::vector< aiQuatKey > akeyRotations;
@@ -182,19 +202,16 @@ struct Animation
 
     //! List of track scaling keyframes
     std::vector< aiVectorKey > akeyScaling;
-
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent the inheritance information of an ASE node */
-struct InheritanceInfo
-{
+struct InheritanceInfo {
     //! Default constructor
-    InheritanceInfo()
-    {
-        // set the inheritance flag for all axes by default to true
-        for (unsigned int i = 0; i < 3;++i)
+    InheritanceInfo() AI_NO_EXCEPT {
+        for ( size_t i=0; i<3; ++i ) {
             abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true;
+        }
     }
 
     //! Inherit the parent's position?, axis order is x,y,z
@@ -209,21 +226,19 @@ struct InheritanceInfo
 
 // ---------------------------------------------------------------------------
 /** Represents an ASE file node. Base class for mesh, light and cameras */
-struct BaseNode
-{
-    enum Type {Light, Camera, Mesh, Dummy} mType;
-
-    //! Constructor. Creates a default name for the node
-    explicit BaseNode(Type _mType)
-        : mType         (_mType)
-        , mProcessed    (false)
-    {
-        // generate a default name for the  node
-        static int iCnt = 0;
-        char szTemp[128]; // should be sufficiently large
-        ::ai_snprintf(szTemp, 128, "UNNAMED_%i",iCnt++);
-        mName = szTemp;
+struct BaseNode {
+    enum Type {
+        Light, 
+        Camera, 
+        Mesh, 
+        Dummy
+    } mType;
 
+    //! Construction from an existing name
+    BaseNode(Type _mType, const std::string &name)
+    : mType         (_mType)
+    , mName         (name)
+    , mProcessed    (false) {
         // Set mTargetPosition to qnan
         const ai_real qnan = get_qnan();
         mTargetPosition.x = qnan;
@@ -258,19 +273,21 @@ struct BaseNode
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file mesh */
-struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode
-{
-    //! Constructor.
-    Mesh()
-        : BaseNode  (BaseNode::Mesh)
-        , bSkip     (false)
-    {
-        // use 2 texture vertex components by default
-        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
-            this->mNumUVComponents[c] = 2;
+struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode {
+    //! Default constructor has been deleted
+    Mesh() = delete;
 
-        // setup the default material index by default
-        iMaterialIndex = Face::DEFAULT_MATINDEX;
+    //! Construction from an existing name
+    explicit Mesh(const std::string &name)
+    : BaseNode( BaseNode::Mesh, name )
+    , mVertexColors()
+    , mBoneVertices()
+    , mBones()
+    , iMaterialIndex(Face::DEFAULT_MATINDEX)
+    , bSkip     (false) {
+        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
+            this->mNumUVComponents[c] = 2;
+        }
     }
 
     //! List of all texture coordinate sets
@@ -307,17 +324,21 @@ struct Light : public BaseNode
         DIRECTIONAL
     };
 
-    //! Constructor.
-    Light()
-        : BaseNode   (BaseNode::Light)
-        , mLightType (OMNI)
-        , mColor     (1.f,1.f,1.f)
-        , mIntensity (1.f) // light is white by default
-        , mAngle     (45.f)
-        , mFalloff   (0.f)
+    //! Default constructor has been deleted
+    Light() = delete;
+
+    //! Construction from an existing name
+    explicit Light(const std::string &name)
+    : BaseNode   (BaseNode::Light, name)
+    , mLightType (OMNI)
+    , mColor     (1.f,1.f,1.f)
+    , mIntensity (1.f) // light is white by default
+    , mAngle     (45.f)
+    , mFalloff   (0.f)
     {
     }
 
+
     LightType mLightType;
     aiColor3D mColor;
     ai_real mIntensity;
@@ -335,28 +356,32 @@ struct Camera : public BaseNode
         TARGET
     };
 
-    //! Constructor
-    Camera()
-        : BaseNode    (BaseNode::Camera)
-        , mFOV        (0.75f)   // in radians
-        , mNear       (0.1f)
-        , mFar        (1000.f)  // could be zero
-        , mCameraType (FREE)
+    //! Default constructor has been deleted
+    Camera() = delete;
+
+
+    //! Construction from an existing name
+    explicit Camera(const std::string &name)
+    : BaseNode    (BaseNode::Camera, name)
+    , mFOV        (0.75f)   // in radians
+    , mNear       (0.1f)
+    , mFar        (1000.f)  // could be zero
+    , mCameraType (FREE)
     {
     }
 
+
     ai_real mFOV, mNear, mFar;
     CameraType mCameraType;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE helper object (dummy) */
-struct Dummy : public BaseNode
-{
+struct Dummy : public BaseNode {
     //! Constructor
-    Dummy()
-        : BaseNode  (BaseNode::Dummy)
-    {
+    Dummy() AI_NO_EXCEPT
+    : BaseNode  (BaseNode::Dummy, "DUMMY") {
+        // empty
     }
 };
 
@@ -371,18 +396,17 @@ struct Dummy : public BaseNode
 // -------------------------------------------------------------------------------
 /** \brief Class to parse ASE files
  */
-class Parser
-{
-
+class Parser {
 private:
-
-    Parser() {}
+    Parser() AI_NO_EXCEPT {
+        // empty
+    }
 
 public:
 
     // -------------------------------------------------------------------
     //! Construct a parser from a given input file which is
-    //! guaranted to be terminated with zero.
+    //! guaranteed to be terminated with zero.
     //! @param szFile Input file
     //! @param fileFormatDefault Assumed file format version. If the
     //!   file format is specified in the file the new value replaces

+ 552 - 512
code/AssbinExporter.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -41,13 +42,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /** @file  AssbinExporter.cpp
  *  ASSBIN exporter main code
  */
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
+
 #include "assbin_chunks.h"
 #include <assimp/version.h>
 #include <assimp/IOStream.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/Exporter.hpp>
 #include "ProcessHelper.h"
-#include "Exceptional.h"
+#include <assimp/Exceptional.h>
 
 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
 #   include <zlib.h>
@@ -57,140 +62,154 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <time.h>
 
-
-#ifndef ASSIMP_BUILD_NO_EXPORT
-#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
-
-using namespace Assimp;
-
-namespace Assimp    {
+namespace Assimp {
 
 template <typename T>
-size_t Write(IOStream * stream, const T& v)
-{
+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)
-{
+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)
-{
+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 new DeadlyExportError("loss of data due to 64 -> 32 bit integer conversion");
+        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)
-{
+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)
-{
+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)
-{
+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)
-{
+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<aiColor4D>(IOStream * stream, const aiColor4D& v)
-{
+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)
-{
+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)
-{
+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)
-{
+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)
-{
+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);
 }
@@ -198,16 +217,16 @@ inline size_t Write<aiVectorKey>(IOStream * stream, const aiVectorKey& v)
 // -----------------------------------------------------------------------------------
 // Serialize an aiQuatKey
 template <>
-inline size_t Write<aiQuatKey>(IOStream * stream, const aiQuatKey& v)
-{
+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;
+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);
@@ -217,585 +236,606 @@ inline size_t WriteBounds(IOStream * stream, const T* in, unsigned int size)
 // 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)
-{
+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;
+// ----------------------------------------------------------------------------------
+/** @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:
 
-    private:
-        // -------------------------------------------------------------------
-        void Grow(size_t need = 0)
-        {
-            size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
+    uint8_t* buffer;
+    uint32_t magic;
+    IOStream * container;
+    size_t cur_size, cursor, initial;
 
-            const uint8_t* const old = buffer;
-            buffer = new uint8_t[new_size];
+private:
+    // -------------------------------------------------------------------
+    void Grow(size_t need = 0)
+    {
+        size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) ));
 
-            if (old) {
-                memcpy(buffer,old,cur_size);
-                delete[] old;
-            }
+        const uint8_t* const old = buffer;
+        buffer = new uint8_t[new_size];
 
-            cur_size = new_size;
+        if (old) {
+            memcpy(buffer,old,cur_size);
+            delete[] old;
         }
 
-    public:
+        cur_size = new_size;
+    }
 
-        AssbinChunkWriter( IOStream * container, uint32_t magic, size_t initial = 4096)
-            : buffer(NULL), magic(magic), container(container), cur_size(0), cursor(0), initial(initial)
-        {
-        }
+public:
 
-        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;
+    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; }
 
-        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 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() { }
+    virtual size_t FileSize() const {
+        return cursor;
+    }
 
-        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);
         }
 
-        // -------------------------------------------------------------------
-        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;
 
-            memcpy(buffer+cursor, pvBuffer, pSize);
-            cursor += pSize;
+        return pCount;
+    }
 
-            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;
 
-    // ----------------------------------------------------------------------------------
-    /** @class  AssbinExport
-     *  @brief  Assbin exporter class
-     *
-     *  This class performs the .assbin exporting, and is responsible for the file layout.
-     */
-    class AssbinExport
+protected:
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryNode( IOStream * container, const aiNode* node)
     {
-    private:
-        bool shortened;
-        bool compressed;
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
 
-    protected:
+        unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
 
-        // -----------------------------------------------------------------------------------
-        void WriteBinaryNode( IOStream * container, const aiNode* node)
-        {
-            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE );
+        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);
 
-			size_t nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0);
+        for (unsigned int i = 0; i < node->mNumMeshes;++i) {
+            Write<unsigned int>(&chunk,node->mMeshes[i]);
+        }
 
-            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->mNumChildren;++i) {
+            WriteBinaryNode( &chunk, node->mChildren[i] );
+        }
 
-            for (unsigned int i = 0; i < node->mNumMeshes;++i) {
-                Write<unsigned int>(&chunk,node->mMeshes[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);
 
-            for (unsigned int i = 0; i < node->mNumChildren;++i) {
-                WriteBinaryNode( &chunk, node->mChildren[i] );
+            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;
             }
+        }
+    }
 
-			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;
-				}
-			}
-        }
-
-        // -----------------------------------------------------------------------------------
-        void WriteBinaryTexture(IOStream * container, const aiTexture* tex)
-        {
-            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AITEXTURE );
+    // -----------------------------------------------------------------------------------
+    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 );
+        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);
-                }
+        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);
+    // -----------------------------------------------------------------------------------
+    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);
+    }
 
-            // 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;
         }
-
-        // -----------------------------------------------------------------------------------
-        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->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;
             }
-            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);
-                }
+            c |= ASSBIN_MESH_HAS_TEXCOORD(n);
+        }
+        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+            if (!mesh->mColors[n]) {
+                break;
             }
-            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);
 
-                if (shortened) {
-                    WriteBounds(&chunk,mesh->mColors[n],mesh->mNumVertices);
-                } // else write as usual
-                else WriteArray<aiColor4D>(&chunk,mesh->mColors[n],mesh->mNumVertices);
+        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_TEXTURECOORDS;++n) {
-                if (!mesh->mTextureCoords[n])
-                    break;
+        }
+        for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+            if (!mesh->mColors[n])
+                break;
 
-                // write number of UV components
-                Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
+            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;
 
-                if (shortened) {
-                    WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
-                } // else write as usual
-                else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
-            }
+            // write number of UV components
+            Write<unsigned int>(&chunk,mesh->mNumUVComponents[n]);
 
-            // 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) {
+                WriteBounds(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
+            } // else write as usual
+            else WriteArray<aiVector3D>(&chunk,mesh->mTextureCoords[n],mesh->mNumVertices);
+        }
 
-                        const aiFace& f = mesh->mFaces[processed+a];
-                        uint32_t tmp = f.mNumIndices;
+        // 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);
-                        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);
                 }
+                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]);
+        }
+        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);
-                }
+        // 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 );
+    // -----------------------------------------------------------------------------------
+    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<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);
-        }
+        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);
+    // -----------------------------------------------------------------------------------
+    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]);
-            }
+        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 );
+    // -----------------------------------------------------------------------------------
+    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);
+        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);
+        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<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<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);
-            }
+            } // 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 );
+    // -----------------------------------------------------------------------------------
+    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);
+        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);
-            }
+        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<aiVector3D>(&chunk,(const aiVector3D&)l->mColorDiffuse);
-            Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorSpecular);
-            Write<aiVector3D>(&chunk,(const aiVector3D&)l->mColorAmbient);
+    // -----------------------------------------------------------------------------------
+    void WriteBinaryLight( IOStream * container, const aiLight* l )
+    {
+        AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AILIGHT );
 
-            if (l->mType == aiLightSource_SPOT) {
-                Write<float>(&chunk,l->mAngleInnerCone);
-                Write<float>(&chunk,l->mAngleOuterCone);
-            }
+        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);
         }
 
-        // -----------------------------------------------------------------------------------
-        void WriteBinaryCamera( IOStream * container, const aiCamera* cam )
-        {
-            AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AICAMERA );
+        Write<aiColor3D>(&chunk,l->mColorDiffuse);
+        Write<aiColor3D>(&chunk,l->mColorSpecular);
+        Write<aiColor3D>(&chunk,l->mColorAmbient);
 
-            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);
+        if (l->mType == aiLightSource_SPOT) {
+            Write<float>(&chunk,l->mAngleInnerCone);
+            Write<float>(&chunk,l->mAngleOuterCone);
         }
 
-        // -----------------------------------------------------------------------------------
-        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);
-            }
+    // -----------------------------------------------------------------------------------
+    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);
+    }
 
-            // write all animations
-            for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
-                const aiAnimation* anim = scene->mAnimations[i];
-                WriteBinaryAnim(&chunk,anim);
-            }
+    // -----------------------------------------------------------------------------------
+    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 textures
-            for (unsigned int i = 0; i < scene->mNumTextures;++i) {
-                const aiTexture* mesh = scene->mTextures[i];
-                WriteBinaryTexture(&chunk,mesh);
-            }
+        // write all animations
+        for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
+            const aiAnimation* anim = scene->mAnimations[i];
+            WriteBinaryAnim(&chunk,anim);
+        }
 
-            // 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);
-            }
+        // 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);
         }
 
-    public:
-        AssbinExport()
-            : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters
-        {
+        // write cameras
+        for (unsigned int i = 0; i < scene->mNumCameras;++i) {
+            const aiCamera* cam = scene->mCameras[i];
+            WriteBinaryCamera(&chunk,cam);
         }
 
-        // -----------------------------------------------------------------------------------
-        // 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);
-            tm* p     = gmtime(&tt);
+public:
+    AssbinExport()
+        : shortened(false), compressed(false) // temporary settings until properties are introduced for exporters
+    {
+    }
 
-            // header
-            char s[64];
-            memset( s, 0, 64 );
-#if _MSC_VER >= 1400
-            sprintf_s(s,"ASSIMP.binary-dump.%s",asctime(p));
+    // -----------------------------------------------------------------------------------
+    // 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
-            ai_snprintf(s,64,"ASSIMP.binary-dump.%s",asctime(p));
+        struct tm now;
+        tm* p = gmtime_r(&tt, &now);
 #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)(uncompressedStream.Tell() * 1.001 + 12.);
-                uint8_t* compressedBuffer = new uint8_t[ compressedSize ];
 
-                compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 );
+        // 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 );
 
-                out->Write( &uncompressedSize, sizeof(uint32_t), 1 );
-                out->Write( compressedBuffer, sizeof(char), compressedSize );
+            uLongf uncompressedSize = static_cast<uLongf>(uncompressedStream.Tell());
+            uLongf compressedSize = (uLongf)compressBound(uncompressedSize);
+            uint8_t* compressedBuffer = new uint8_t[ compressedSize ];
 
-                delete[] compressedBuffer;
-            }
-            else
+            int res = compress2( compressedBuffer, &compressedSize, (const Bytef*)uncompressedStream.GetBufferPointer(), uncompressedSize, 9 );
+            if(res != Z_OK)
             {
-                WriteBinaryScene( out, pScene );
+                delete [] compressedBuffer;
+                pIOSystem->Close(out);
+                throw DeadlyExportError("Compression failed.");
             }
 
-            pIOSystem->Close( out );
+            out->Write( &uncompressedSize, sizeof(uint32_t), 1 );
+            out->Write( compressedBuffer, sizeof(char), compressedSize );
+
+            delete[] compressedBuffer;
+        }
+        else
+        {
+            WriteBinaryScene( out, pScene );
         }
-    };
 
-void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
-{
+        pIOSystem->Close( out );
+    }
+};
+
+void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) {
     AssbinExport exporter;
     exporter.WriteBinaryDump( pFile, pIOSystem, pScene );
 }

+ 10 - 2
code/AssbinExporter.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -45,6 +46,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_ASSBINEXPORTER_H_INC
 #define AI_ASSBINEXPORTER_H_INC
 
+#include <assimp/defs.h>
+
 // nothing really needed here - reserved for future use like properties
+namespace Assimp {
+
+void ASSIMP_API ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/);
+
+}
 
-#endif
+#endif // AI_ASSBINEXPORTER_H_INC

+ 213 - 209
code/AssbinLoader.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -51,11 +52,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // internal headers
 #include "AssbinLoader.h"
 #include "assbin_chunks.h"
-#include "MemoryIOWrapper.h"
+#include <assimp/MemoryIOWrapper.h>
 #include <assimp/mesh.h>
 #include <assimp/anim.h>
 #include <assimp/scene.h>
 #include <assimp/importerdesc.h>
+#include <memory>
 
 #ifdef ASSIMP_BUILD_NO_OWN_ZLIB
 #   include <zlib.h>
@@ -66,7 +68,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 
 static const aiImporterDesc desc = {
-    ".assbin Importer",
+    "Assimp Binary Importer",
     "Gargaj / Conspiracy",
     "",
     "",
@@ -78,16 +80,17 @@ static const aiImporterDesc desc = {
     "assbin"
 };
 
-const aiImporterDesc* AssbinImporter::GetInfo() const
-{
+// -----------------------------------------------------------------------------------
+const aiImporterDesc* AssbinImporter::GetInfo() const {
     return &desc;
 }
 
-bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const
-{
+// -----------------------------------------------------------------------------------
+bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
     IOStream * in = pIOHandler->Open(pFile);
-    if (!in)
+    if (nullptr == in) {
         return false;
+    }
 
     char s[32];
     in->Read( s, sizeof(char), 32 );
@@ -97,17 +100,19 @@ bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bo
     return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0;
 }
 
+// -----------------------------------------------------------------------------------
 template <typename T>
-T Read(IOStream * stream)
-{
+T Read(IOStream * stream) {
     T t;
-    stream->Read( &t, sizeof(T), 1 );
+    size_t res = stream->Read( &t, sizeof(T), 1 );
+    if(res != 1)
+        throw DeadlyImportError("Unexpected EOF");
     return t;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiVector3D Read<aiVector3D>(IOStream * stream)
-{
+aiVector3D Read<aiVector3D>(IOStream * stream) {
     aiVector3D v;
     v.x = Read<float>(stream);
     v.y = Read<float>(stream);
@@ -115,9 +120,9 @@ aiVector3D Read<aiVector3D>(IOStream * stream)
     return v;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiColor4D Read<aiColor4D>(IOStream * stream)
-{
+aiColor4D Read<aiColor4D>(IOStream * stream) {
     aiColor4D c;
     c.r = Read<float>(stream);
     c.g = Read<float>(stream);
@@ -126,9 +131,9 @@ aiColor4D Read<aiColor4D>(IOStream * stream)
     return c;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiQuaternion Read<aiQuaternion>(IOStream * stream)
-{
+aiQuaternion Read<aiQuaternion>(IOStream * stream) {
     aiQuaternion v;
     v.w = Read<float>(stream);
     v.x = Read<float>(stream);
@@ -137,28 +142,29 @@ aiQuaternion Read<aiQuaternion>(IOStream * stream)
     return v;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiString Read<aiString>(IOStream * stream)
-{
+aiString Read<aiString>(IOStream * stream) {
     aiString s;
     stream->Read(&s.length,4,1);
-    stream->Read(s.data,s.length,1);
+    if(s.length)
+        stream->Read(s.data,s.length,1);
     s.data[s.length] = 0;
     return s;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiVertexWeight Read<aiVertexWeight>(IOStream * stream)
-{
+aiVertexWeight Read<aiVertexWeight>(IOStream * stream) {
     aiVertexWeight w;
     w.mVertexId = Read<unsigned int>(stream);
     w.mWeight = Read<float>(stream);
     return w;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream)
-{
+aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream) {
     aiMatrix4x4 m;
     for (unsigned int i = 0; i < 4;++i) {
         for (unsigned int i2 = 0; i2 < 4;++i2) {
@@ -168,113 +174,123 @@ aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream)
     return m;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiVectorKey Read<aiVectorKey>(IOStream * stream)
-{
+aiVectorKey Read<aiVectorKey>(IOStream * stream) {
     aiVectorKey v;
     v.mTime = Read<double>(stream);
     v.mValue = Read<aiVector3D>(stream);
     return v;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiQuatKey Read<aiQuatKey>(IOStream * stream)
-{
+aiQuatKey Read<aiQuatKey>(IOStream * stream) {
     aiQuatKey v;
     v.mTime = Read<double>(stream);
     v.mValue = Read<aiQuaternion>(stream);
     return v;
 }
 
+// -----------------------------------------------------------------------------------
 template <typename T>
-void ReadArray(IOStream * stream, T * out, unsigned int size)
-{
-    for (unsigned int i=0; i<size; i++) out[i] = Read<T>(stream);
+void ReadArray( IOStream *stream, T * out, unsigned int size) {
+    ai_assert( nullptr != stream );
+    ai_assert( nullptr != out );
+
+    for (unsigned int i=0; i<size; i++) {
+        out[i] = Read<T>(stream);
+    }
 }
 
-template <typename T> void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n )
-{
+// -----------------------------------------------------------------------------------
+template <typename T>
+void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n ) {
     // not sure what to do here, the data isn't really useful.
     stream->Seek( sizeof(T) * n, aiOrigin_CUR );
 }
 
-void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* parent )
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AINODE);
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** onode, aiNode* parent ) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODE)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
-    *node = new aiNode();
+    std::unique_ptr<aiNode> node(new aiNode());
 
-    (*node)->mName = Read<aiString>(stream);
-    (*node)->mTransformation = Read<aiMatrix4x4>(stream);
-    (*node)->mNumChildren = Read<unsigned int>(stream);
-    (*node)->mNumMeshes = Read<unsigned int>(stream);
+    node->mName = Read<aiString>(stream);
+    node->mTransformation = Read<aiMatrix4x4>(stream);
+    unsigned numChildren = Read<unsigned int>(stream);
+    unsigned numMeshes = Read<unsigned int>(stream);
 	unsigned int nb_metadata = Read<unsigned int>(stream);
 
-    if(parent)
-    {
-        (*node)->mParent = parent;
+    if(parent) {
+        node->mParent = parent;
     }
 
-    if ((*node)->mNumMeshes)
+    if (numMeshes)
     {
-        (*node)->mMeshes = new unsigned int[(*node)->mNumMeshes];
-        for (unsigned int i = 0; i < (*node)->mNumMeshes; ++i) {
-            (*node)->mMeshes[i] = Read<unsigned int>(stream);
+        node->mMeshes = new unsigned int[numMeshes];
+        for (unsigned int i = 0; i < numMeshes; ++i) {
+            node->mMeshes[i] = Read<unsigned int>(stream);
+            node->mNumMeshes++;
         }
     }
 
-    if ((*node)->mNumChildren)
-    {
-        (*node)->mChildren = new aiNode*[(*node)->mNumChildren];
-        for (unsigned int i = 0; i < (*node)->mNumChildren; ++i) {
-            ReadBinaryNode( stream, &(*node)->mChildren[i], *node );
+    if (numChildren) {
+        node->mChildren = new aiNode*[numChildren];
+        for (unsigned int i = 0; i < numChildren; ++i) {
+            ReadBinaryNode( stream, &node->mChildren[i], node.get() );
+            node->mNumChildren++;
         }
     }
 
-	if (nb_metadata)
-	{
-		(*node)->mMetaData = aiMetadata::Alloc(nb_metadata);
-		for (unsigned int i = 0; i < nb_metadata; ++i) {
-			(*node)->mMetaData->mKeys[i] = Read<aiString>(stream);
-			(*node)->mMetaData->mValues[i].mType = (aiMetadataType) Read<uint16_t>(stream);
-			void* data = NULL;
-
-			switch ((*node)->mMetaData->mValues[i].mType) {
-			case AI_BOOL:
-				data = new bool(Read<bool>(stream));
-				break;
-			case AI_INT32:
-				data = new int32_t(Read<int32_t>(stream));
-				break;
-			case AI_UINT64:
-				data = new uint64_t(Read<uint64_t>(stream));
-				break;
-			case AI_FLOAT:
-				data = new float(Read<float>(stream));
-				break;
-			case AI_DOUBLE:
-				data = new double(Read<double>(stream));
-				break;
-			case AI_AISTRING:
-				data = new aiString(Read<aiString>(stream));
-				break;
-			case AI_AIVECTOR3D:
-				data = new aiVector3D(Read<aiVector3D>(stream));
-				break;
-			}
-
-			(*node)->mMetaData->mValues[i].mData = data;
+    if ( nb_metadata > 0 ) {
+        node->mMetaData = aiMetadata::Alloc(nb_metadata);
+        for (unsigned int i = 0; i < nb_metadata; ++i) {
+            node->mMetaData->mKeys[i] = Read<aiString>(stream);
+            node->mMetaData->mValues[i].mType = (aiMetadataType) Read<uint16_t>(stream);
+            void* data = nullptr;
+
+            switch (node->mMetaData->mValues[i].mType) {
+                case AI_BOOL:
+                    data = new bool(Read<bool>(stream));
+                    break;
+                case AI_INT32:
+                    data = new int32_t(Read<int32_t>(stream));
+                    break;
+                case AI_UINT64:
+                    data = new uint64_t(Read<uint64_t>(stream));
+                    break;
+                case AI_FLOAT:
+                    data = new float(Read<float>(stream));
+                    break;
+                case AI_DOUBLE:
+                    data = new double(Read<double>(stream));
+                    break;
+                case AI_AISTRING:
+                    data = new aiString(Read<aiString>(stream));
+                    break;
+                case AI_AIVECTOR3D:
+                    data = new aiVector3D(Read<aiVector3D>(stream));
+                    break;
+#ifndef SWIG
+                case FORCE_32BIT:
+#endif // SWIG
+                default:
+                    break;
+            }
+
+			node->mMetaData->mValues[i].mData = data;
 		}
 	}
+    *onode = node.release();
 }
 
 // -----------------------------------------------------------------------------------
-void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b )
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AIBONE);
+void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b ) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIBONE)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     b->mName = Read<aiString>(stream);
@@ -283,22 +299,23 @@ void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b )
 
     // 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)
-    {
+    if (shortened) {
         ReadBounds(stream,b->mWeights,b->mNumWeights);
-    } // else write as usual
-    else
-    {
+    } else {
+        // else write as usual
         b->mWeights = new aiVertexWeight[b->mNumWeights];
         ReadArray<aiVertexWeight>(stream,b->mWeights,b->mNumWeights);
     }
 }
 
-
-void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AIMESH);
+// -----------------------------------------------------------------------------------
+static bool fitsIntoUI16(unsigned int mNumVertices) {
+    return ( mNumVertices < (1u<<16) );
+}
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMESH)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     mesh->mPrimitiveTypes = Read<unsigned int>(stream);
@@ -310,70 +327,61 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
     // first of all, write bits for all existent vertex components
     unsigned int c = Read<unsigned int>(stream);
 
-    if (c & ASSBIN_MESH_HAS_POSITIONS)
-    {
+    if (c & ASSBIN_MESH_HAS_POSITIONS) {
         if (shortened) {
             ReadBounds(stream,mesh->mVertices,mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mVertices = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mVertices,mesh->mNumVertices);
         }
     }
-    if (c & ASSBIN_MESH_HAS_NORMALS)
-    {
+    if (c & ASSBIN_MESH_HAS_NORMALS) {
         if (shortened) {
             ReadBounds(stream,mesh->mNormals,mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mNormals = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mNormals,mesh->mNumVertices);
         }
     }
-    if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS)
-    {
+    if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) {
         if (shortened) {
             ReadBounds(stream,mesh->mTangents,mesh->mNumVertices);
             ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mTangents = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mTangents,mesh->mNumVertices);
             mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mBitangents,mesh->mNumVertices);
         }
     }
-    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n)
-    {
-        if (!(c & ASSBIN_MESH_HAS_COLOR(n)))
+    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+        if (!(c & ASSBIN_MESH_HAS_COLOR(n))) {
             break;
+        }
 
-        if (shortened)
-        {
+        if (shortened) {
             ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
             ReadArray<aiColor4D>(stream,mesh->mColors[n],mesh->mNumVertices);
         }
     }
-    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
-    {
-        if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n)))
+    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
+        if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) {
             break;
+        }
 
         // write number of UV components
         mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
 
         if (shortened) {
             ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
         }
@@ -385,9 +393,8 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
     // using Assimp's standard hashing function.
     if (shortened) {
         Read<unsigned int>(stream);
-    }
-    else // else write as usual
-    {
+    } else  {
+        // else write as usual
         // if there are less than 2^16 vertices, we can simply use 16 bit integers ...
         mesh->mFaces = new aiFace[mesh->mNumFaces];
         for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
@@ -398,12 +405,10 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
             f.mIndices = new unsigned int[f.mNumIndices];
 
             for (unsigned int a = 0; a < f.mNumIndices;++a) {
-                if (mesh->mNumVertices < (1u<<16))
-                {
+                // Check if unsigned  short ( 16 bit  ) are big enought for the indices
+                if ( fitsIntoUI16( mesh->mNumVertices ) ) {
                     f.mIndices[a] = Read<uint16_t>(stream);
-                }
-                else
-                {
+                } else {
                     f.mIndices[a] = Read<unsigned int>(stream);
                 }
             }
@@ -420,10 +425,10 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
     }
 }
 
-void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop)
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY);
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIALPROPERTY)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     prop->mKey = Read<aiString>(stream);
@@ -437,10 +442,9 @@ void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialPro
 }
 
 // -----------------------------------------------------------------------------------
-void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat)
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIAL);
+void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIMATERIAL)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     mat->mNumAllocated = mat->mNumProperties = Read<unsigned int>(stream);
@@ -459,10 +463,9 @@ void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat)
 }
 
 // -----------------------------------------------------------------------------------
-void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AINODEANIM);
+void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AINODEANIM)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     nd->mNodeName = Read<aiString>(stream);
@@ -486,9 +489,8 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
         if (shortened) {
             ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys);
 
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
             ReadArray<aiQuatKey>(stream,nd->mRotationKeys,nd->mNumRotationKeys);
         }
@@ -497,21 +499,18 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
         if (shortened) {
             ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys);
 
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
             ReadArray<aiVectorKey>(stream,nd->mScalingKeys,nd->mNumScalingKeys);
         }
     }
 }
 
-
 // -----------------------------------------------------------------------------------
-void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AIANIMATION);
+void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AIANIMATION)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     anim->mName = Read<aiString> (stream);
@@ -519,8 +518,7 @@ void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
     anim->mTicksPerSecond = Read<double> (stream);
     anim->mNumChannels = Read<unsigned int>(stream);
 
-    if (anim->mNumChannels)
-    {
+    if (anim->mNumChannels) {
         anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ];
         for (unsigned int a = 0; a < anim->mNumChannels;++a) {
             anim->mChannels[a] = new aiNodeAnim();
@@ -529,10 +527,10 @@ void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
     }
 }
 
-void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex)
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AITEXTURE);
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AITEXTURE)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     tex->mWidth = Read<unsigned int>(stream);
@@ -543,20 +541,17 @@ void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex)
         if (!tex->mHeight) {
             tex->pcData = new aiTexel[ tex->mWidth ];
             stream->Read(tex->pcData,1,tex->mWidth);
-        }
-        else {
+        } else {
             tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ];
             stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4);
         }
     }
-
 }
 
 // -----------------------------------------------------------------------------------
-void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AILIGHT);
+void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AILIGHT)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     l->mName = Read<aiString>(stream);
@@ -576,14 +571,12 @@ void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
         l->mAngleInnerCone = Read<float>(stream);
         l->mAngleOuterCone = Read<float>(stream);
     }
-
 }
 
 // -----------------------------------------------------------------------------------
-void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AICAMERA);
+void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AICAMERA)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     cam->mName = Read<aiString>(stream);
@@ -596,10 +589,10 @@ void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
     cam->mAspect = Read<float>(stream);
 }
 
-void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
-{
-    uint32_t chunkID = Read<uint32_t>(stream);
-    ai_assert(chunkID == ASSBIN_CHUNK_AISCENE);
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) {
+    if(Read<uint32_t>(stream) != ASSBIN_CHUNK_AISCENE)
+        throw DeadlyImportError("Magic chunk identifiers are wrong!");
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
     scene->mFlags         = Read<unsigned int>(stream);
@@ -611,13 +604,13 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     scene->mNumCameras    = Read<unsigned int>(stream);
 
     // Read node graph
-    scene->mRootNode = new aiNode[1];
+    //scene->mRootNode = new aiNode[1];
     ReadBinaryNode( stream, &scene->mRootNode, (aiNode*)NULL );
 
     // Read all meshes
-    if (scene->mNumMeshes)
-    {
+    if (scene->mNumMeshes) {
         scene->mMeshes = new aiMesh*[scene->mNumMeshes];
+        memset(scene->mMeshes, 0, scene->mNumMeshes*sizeof(aiMesh*));
         for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
             scene->mMeshes[i] = new aiMesh();
             ReadBinaryMesh( stream,scene->mMeshes[i]);
@@ -625,9 +618,9 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read materials
-    if (scene->mNumMaterials)
-    {
+    if (scene->mNumMaterials) {
         scene->mMaterials = new aiMaterial*[scene->mNumMaterials];
+        memset(scene->mMaterials, 0, scene->mNumMaterials*sizeof(aiMaterial*));
         for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
             scene->mMaterials[i] = new aiMaterial();
             ReadBinaryMaterial(stream,scene->mMaterials[i]);
@@ -635,9 +628,9 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read all animations
-    if (scene->mNumAnimations)
-    {
+    if (scene->mNumAnimations) {
         scene->mAnimations = new aiAnimation*[scene->mNumAnimations];
+        memset(scene->mAnimations, 0, scene->mNumAnimations*sizeof(aiAnimation*));
         for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
             scene->mAnimations[i] = new aiAnimation();
             ReadBinaryAnim(stream,scene->mAnimations[i]);
@@ -645,9 +638,9 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read all textures
-    if (scene->mNumTextures)
-    {
+    if (scene->mNumTextures) {
         scene->mTextures = new aiTexture*[scene->mNumTextures];
+        memset(scene->mTextures, 0, scene->mNumTextures*sizeof(aiTexture*));
         for (unsigned int i = 0; i < scene->mNumTextures;++i) {
             scene->mTextures[i] = new aiTexture();
             ReadBinaryTexture(stream,scene->mTextures[i]);
@@ -655,9 +648,9 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read lights
-    if (scene->mNumLights)
-    {
+    if (scene->mNumLights) {
         scene->mLights = new aiLight*[scene->mNumLights];
+        memset(scene->mLights, 0, scene->mNumLights*sizeof(aiLight*));
         for (unsigned int i = 0; i < scene->mNumLights;++i) {
             scene->mLights[i] = new aiLight();
             ReadBinaryLight(stream,scene->mLights[i]);
@@ -665,9 +658,9 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read cameras
-    if (scene->mNumCameras)
-    {
+    if (scene->mNumCameras) {
         scene->mCameras = new aiCamera*[scene->mNumCameras];
+        memset(scene->mCameras, 0, scene->mNumCameras*sizeof(aiCamera*));
         for (unsigned int i = 0; i < scene->mNumCameras;++i) {
             scene->mCameras[i] = new aiCamera();
             ReadBinaryCamera(stream,scene->mCameras[i]);
@@ -676,16 +669,22 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
 
 }
 
-void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler )
-{
+// -----------------------------------------------------------------------------------
+void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) {
     IOStream * stream = pIOHandler->Open(pFile,"rb");
-    if (!stream)
+    if (nullptr == stream) {
         return;
+    }
 
-    stream->Seek( 44, aiOrigin_CUR ); // signature
+    // signature
+    stream->Seek( 44, aiOrigin_CUR );
+
+    unsigned int versionMajor = Read<unsigned int>(stream);
+    unsigned int versionMinor = Read<unsigned int>(stream);
+    if (versionMinor != ASSBIN_VERSION_MINOR || versionMajor != ASSBIN_VERSION_MAJOR) {
+        throw DeadlyImportError( "Invalid version, data format not compatible!" );
+    }
 
-    /*unsigned int versionMajor =*/ Read<unsigned int>(stream);
-    /*unsigned int versionMinor =*/ Read<unsigned int>(stream);
     /*unsigned int versionRevision =*/ Read<unsigned int>(stream);
     /*unsigned int compileFlags =*/ Read<unsigned int>(stream);
 
@@ -699,17 +698,24 @@ void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
     stream->Seek( 128, aiOrigin_CUR ); // options
     stream->Seek( 64, aiOrigin_CUR ); // padding
 
-    if (compressed)
-    {
+    if (compressed) {
         uLongf uncompressedSize = Read<uint32_t>(stream);
         uLongf compressedSize = static_cast<uLongf>(stream->FileSize() - stream->Tell());
 
         unsigned char * compressedData = new unsigned char[ compressedSize ];
-        stream->Read( compressedData, 1, compressedSize );
+        size_t len = stream->Read( compressedData, 1, compressedSize );
+        ai_assert(len == compressedSize);
 
         unsigned char * uncompressedData = new unsigned char[ uncompressedSize ];
 
-        uncompress( uncompressedData, &uncompressedSize, compressedData, compressedSize );
+        int res = uncompress( uncompressedData, &uncompressedSize, compressedData, (uLong) len );
+        if(res != Z_OK)
+        {
+            delete [] uncompressedData;
+            delete [] compressedData;
+            pIOHandler->Close(stream);
+            throw DeadlyImportError("Zlib decompression failed.");
+        }
 
         MemoryIOStream io( uncompressedData, uncompressedSize );
 
@@ -717,9 +723,7 @@ void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
 
         delete[] uncompressedData;
         delete[] compressedData;
-    }
-    else
-    {
+    } else {
         ReadBinaryScene(stream,pScene);
     }
 

+ 25 - 24
code/AssbinLoader.h

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -46,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_ASSBINIMPORTER_H_INC
 #define AI_ASSBINIMPORTER_H_INC
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 
 struct aiMesh;
 struct aiNode;
@@ -69,33 +70,33 @@ namespace Assimp    {
 class AssbinImporter : public BaseImporter
 {
 private:
-  bool shortened;
-  bool compressed;
-protected:
+    bool shortened;
+    bool compressed;
 
 public:
-  virtual bool CanRead(
-    const std::string& pFile,
-    IOSystem* pIOHandler,
-    bool checkSig
+    virtual bool CanRead(
+        const std::string& pFile,
+        IOSystem* pIOHandler,
+        bool checkSig
     ) const;
-  virtual const aiImporterDesc* GetInfo() const;
-  virtual void InternReadFile(
+    virtual const aiImporterDesc* GetInfo() const;
+    virtual void InternReadFile(
     const std::string& pFile,
-    aiScene* pScene,
-    IOSystem* pIOHandler
+        aiScene* pScene,
+        IOSystem* pIOHandler
     );
-  void ReadBinaryScene( IOStream * stream, aiScene* pScene );
-  void ReadBinaryNode( IOStream * stream, aiNode** mRootNode, aiNode* parent );
-  void ReadBinaryMesh( IOStream * stream, aiMesh* mesh );
-  void ReadBinaryBone( IOStream * stream, aiBone* bone );
-  void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat);
-  void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop);
-  void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd);
-  void ReadBinaryAnim( IOStream * stream, aiAnimation* anim );
-  void ReadBinaryTexture(IOStream * stream, aiTexture* tex);
-  void ReadBinaryLight( IOStream * stream, aiLight* l );
-  void ReadBinaryCamera( IOStream * stream, aiCamera* cam );
+    void ReadHeader();
+    void ReadBinaryScene( IOStream * stream, aiScene* pScene );
+    void ReadBinaryNode( IOStream * stream, aiNode** mRootNode, aiNode* parent );
+    void ReadBinaryMesh( IOStream * stream, aiMesh* mesh );
+    void ReadBinaryBone( IOStream * stream, aiBone* bone );
+    void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat);
+    void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop);
+    void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd);
+    void ReadBinaryAnim( IOStream * stream, aiAnimation* anim );
+    void ReadBinaryTexture(IOStream * stream, aiTexture* tex);
+    void ReadBinaryLight( IOStream * stream, aiLight* l );
+    void ReadBinaryCamera( IOStream * stream, aiCamera* cam );
 };
 
 } // end of namespace Assimp

+ 7 - 6
code/Assimp.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -49,13 +50,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Importer.hpp>
 #include <assimp/importerdesc.h>
 #include <assimp/scene.h>
+#include <assimp/GenericProperty.h>
+#include <assimp/Exceptional.h>
+#include <assimp/BaseImporter.h>
 
-#include "GenericProperty.h"
 #include "CInterfaceIOWrapper.h"
 #include "Importer.h"
-#include "Exceptional.h"
 #include "ScenePrivate.h"
-#include "BaseImporter.h"
+
 #include <list>
 
 // ------------------------------------------------------------------------------------------------
@@ -106,7 +108,6 @@ namespace Assimp {
 static std::mutex gLogStreamMutex;
 #endif
 
-
 // ------------------------------------------------------------------------------------------------
 // Custom LogStream implementation for the C-API
 class LogToCallbackRedirector : public LogStream {
@@ -145,7 +146,7 @@ private:
 
 // ------------------------------------------------------------------------------------------------
 void ReportSceneNotFoundError() {
-    DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
+    ASSIMP_LOG_ERROR("Unable to find the Assimp::Importer for this aiScene. "
         "The C-API does not accept scenes produced by the C++ API and vice versa");
 
     ai_assert(false);

+ 2 - 2
code/AssimpCExport.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -59,7 +60,6 @@ ASSIMP_API size_t aiGetExportFormatCount(void)
     return Exporter().GetExportFormatCount();
 }
 
-
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index)
 {

+ 14 - 9
code/AssxmlExporter.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -41,6 +42,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 /** @file  AssxmlExporter.cpp
  *  ASSXML exporter main code
  */
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
+
 #include <stdarg.h>
 #include <assimp/version.h>
 #include "ProcessHelper.h"
@@ -57,9 +62,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <time.h>
 #include <stdio.h>
 
-#ifndef ASSIMP_BUILD_NO_EXPORT
-#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
-
 using namespace Assimp;
 
 namespace Assimp    {
@@ -182,8 +184,13 @@ static std::string encodeXML(const std::string& data) {
 static
 void WriteDump(const aiScene* scene, IOStream* io, bool shortened) {
     time_t tt = ::time( NULL );
-    tm* p     = ::gmtime( &tt );
-    ai_assert( nullptr != p );
+#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(
@@ -548,8 +555,6 @@ void WriteDump(const aiScene* scene, IOStream* io, bool shortened) {
                             mesh->mNormals[n].z);
                     }
                 }
-                else {
-                }
                 ioprintf(io,"\t\t</Normals>\n");
             }
 
@@ -631,7 +636,7 @@ void WriteDump(const aiScene* scene, IOStream* io, bool shortened) {
 
 } // 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;

+ 2 - 1
code/AssxmlExporter.h

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

+ 63 - 22
code/B3DImporter.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -51,7 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "B3DImporter.h"
 #include "TextureTransform.h"
 #include "ConvertToLHProcess.h"
-#include "StringUtils.h"
+#include <assimp/StringUtils.h>
 #include <memory>
 #include <assimp/IOSystem.hpp>
 #include <assimp/anim.h>
@@ -82,6 +83,19 @@ static const aiImporterDesc desc = {
 
 //#define DEBUG_B3D
 
+template<typename T>
+void DeleteAllBarePointers(std::vector<T>& x)
+{
+    for(auto p : x)
+    {
+        delete p;
+    }
+}
+
+B3DImporter::~B3DImporter()
+{
+}
+
 // ------------------------------------------------------------------------------------------------
 bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{
 
@@ -157,7 +171,8 @@ int B3DImporter::ReadByte(){
 // ------------------------------------------------------------------------------------------------
 int B3DImporter::ReadInt(){
     if( _pos+4<=_buf.size() ){
-        int n=*(int*)&_buf[_pos];
+        int n;
+        memcpy(&n, &_buf[_pos], 4);
         _pos+=4;
         return n;
     }
@@ -168,7 +183,8 @@ int B3DImporter::ReadInt(){
 // ------------------------------------------------------------------------------------------------
 float B3DImporter::ReadFloat(){
     if( _pos+4<=_buf.size() ){
-        float n=*(float*)&_buf[_pos];
+        float n;
+        memcpy(&n, &_buf[_pos], 4);
         _pos+=4;
         return n;
     }
@@ -251,6 +267,21 @@ T *B3DImporter::to_array( const vector<T> &v ){
     return p;
 }
 
+
+// ------------------------------------------------------------------------------------------------
+template<class T>
+T **unique_to_array( vector<std::unique_ptr<T> > &v ){
+    if( v.empty() ) {
+        return 0;
+    }
+    T **p = new T*[ v.size() ];
+    for( size_t i = 0; i < v.size(); ++i ){
+        p[i] = v[i].release();
+    }
+    return p;
+}
+
+
 // ------------------------------------------------------------------------------------------------
 void B3DImporter::ReadTEXS(){
     while( ChunkSize() ){
@@ -279,8 +310,7 @@ void B3DImporter::ReadBRUS(){
         /*int blend=**/ReadInt();
         int fx=ReadInt();
 
-        aiMaterial *mat=new aiMaterial;
-        _materials.push_back( mat );
+        std::unique_ptr<aiMaterial> mat(new aiMaterial);
 
         // Name
         aiString ainame( name );
@@ -317,6 +347,7 @@ void B3DImporter::ReadBRUS(){
                 mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) );
             }
         }
+        _materials.emplace_back( std::move(mat) );
     }
 }
 
@@ -370,8 +401,7 @@ void B3DImporter::ReadTRIS( int v0 ){
         Fail( "Bad material id" );
     }
 
-    aiMesh *mesh=new aiMesh;
-    _meshes.push_back( mesh );
+    std::unique_ptr<aiMesh> mesh(new aiMesh);
 
     mesh->mMaterialIndex=matid;
     mesh->mNumFaces=0;
@@ -399,6 +429,8 @@ void B3DImporter::ReadTRIS( int v0 ){
         ++mesh->mNumFaces;
         ++face;
     }
+
+    _meshes.emplace_back( std::move(mesh) );
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -484,11 +516,11 @@ void B3DImporter::ReadANIM(){
     int frames=ReadInt();
     float fps=ReadFloat();
 
-    aiAnimation *anim=new aiAnimation;
-    _animations.push_back( anim );
+    std::unique_ptr<aiAnimation> anim(new aiAnimation);
 
     anim->mDuration=frames;
     anim->mTicksPerSecond=fps;
+    _animations.emplace_back( std::move(anim) );
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -515,7 +547,7 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){
     node->mParent=parent;
     node->mTransformation=tform;
 
-    aiNodeAnim *nodeAnim=0;
+    std::unique_ptr<aiNodeAnim> nodeAnim;
     vector<unsigned> meshes;
     vector<aiNode*> children;
 
@@ -533,11 +565,10 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){
             ReadANIM();
         }else if( t=="KEYS" ){
             if( !nodeAnim ){
-                nodeAnim=new aiNodeAnim;
-                _nodeAnims.push_back( nodeAnim );
+                nodeAnim.reset(new aiNodeAnim);
                 nodeAnim->mNodeName=node->mName;
             }
-            ReadKEYS( nodeAnim );
+            ReadKEYS( nodeAnim.get() );
         }else if( t=="NODE" ){
             aiNode *child=ReadNODE( node );
             children.push_back( child );
@@ -545,6 +576,10 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){
         ExitChunk();
     }
 
+    if (nodeAnim) {
+        _nodeAnims.emplace_back( std::move(nodeAnim) );
+    }
+
     node->mNumMeshes= static_cast<unsigned int>(meshes.size());
     node->mMeshes=to_array( meshes );
 
@@ -558,13 +593,18 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){
 void B3DImporter::ReadBB3D( aiScene *scene ){
 
     _textures.clear();
+
     _materials.clear();
 
     _vertices.clear();
+
     _meshes.clear();
 
+    DeleteAllBarePointers(_nodes);
     _nodes.clear();
+
     _nodeAnims.clear();
+
     _animations.clear();
 
     string t=ReadChunk();
@@ -574,7 +614,7 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
         if (!DefaultLogger::isNullLogger()) {
             char dmp[128];
             ai_snprintf(dmp, 128, "B3D file format version: %i",version);
-            DefaultLogger::get()->info(dmp);
+            ASSIMP_LOG_INFO(dmp);
         }
 
         while( ChunkSize() ){
@@ -600,7 +640,7 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
         aiNode *node=_nodes[i];
 
         for( size_t j=0;j<node->mNumMeshes;++j ){
-            aiMesh *mesh=_meshes[node->mMeshes[j]];
+            aiMesh *mesh = _meshes[node->mMeshes[j]].get();
 
             int n_tris=mesh->mNumFaces;
             int n_verts=mesh->mNumVertices=n_tris * 3;
@@ -663,27 +703,28 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
 
     //nodes
     scene->mRootNode=_nodes[0];
+    _nodes.clear();  // node ownership now belongs to scene
 
     //material
     if( !_materials.size() ){
-        _materials.push_back( new aiMaterial );
+        _materials.emplace_back( std::unique_ptr<aiMaterial>(new aiMaterial) );
     }
     scene->mNumMaterials= static_cast<unsigned int>(_materials.size());
-    scene->mMaterials=to_array( _materials );
+    scene->mMaterials = unique_to_array( _materials );
 
     //meshes
     scene->mNumMeshes= static_cast<unsigned int>(_meshes.size());
-    scene->mMeshes=to_array( _meshes );
+    scene->mMeshes = unique_to_array( _meshes );
 
     //animations
     if( _animations.size()==1 && _nodeAnims.size() ){
 
-        aiAnimation *anim=_animations.back();
+        aiAnimation *anim = _animations.back().get();
         anim->mNumChannels=static_cast<unsigned int>(_nodeAnims.size());
-        anim->mChannels=to_array( _nodeAnims );
+        anim->mChannels = unique_to_array( _nodeAnims );
 
         scene->mNumAnimations=static_cast<unsigned int>(_animations.size());
-        scene->mAnimations=to_array( _animations );
+        scene->mAnimations=unique_to_array( _animations );
     }
 
     // convert to RH

+ 10 - 6
code/B3DImporter.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -47,8 +48,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/types.h>
 #include <assimp/mesh.h>
 #include <assimp/material.h>
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 
+#include <memory>
 #include <vector>
 
 struct aiNodeAnim;
@@ -59,6 +61,8 @@ namespace Assimp{
 
 class B3DImporter : public BaseImporter{
 public:
+    B3DImporter() = default;
+    virtual ~B3DImporter();
 
     virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
 
@@ -114,15 +118,15 @@ private:
     std::vector<unsigned> _stack;
 
     std::vector<std::string> _textures;
-    std::vector<aiMaterial*> _materials;
+    std::vector<std::unique_ptr<aiMaterial> > _materials;
 
     int _vflags,_tcsets,_tcsize;
     std::vector<Vertex> _vertices;
 
     std::vector<aiNode*> _nodes;
-    std::vector<aiMesh*> _meshes;
-    std::vector<aiNodeAnim*> _nodeAnims;
-    std::vector<aiAnimation*> _animations;
+    std::vector<std::unique_ptr<aiMesh> > _meshes;
+    std::vector<std::unique_ptr<aiNodeAnim> > _nodeAnims;
+    std::vector<std::unique_ptr<aiAnimation> > _animations;
 };
 
 }

+ 79 - 46
code/BVHLoader.cpp

@@ -4,7 +4,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -45,14 +46,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
 
 #include "BVHLoader.h"
-#include "fast_atof.h"
-#include "SkeletonMeshBuilder.h"
+#include <assimp/fast_atof.h>
+#include <assimp/SkeletonMeshBuilder.h>
 #include <assimp/Importer.hpp>
 #include <memory>
-#include "TinyFormatter.h"
+#include <assimp/TinyFormatter.h>
 #include <assimp/IOSystem.hpp>
 #include <assimp/scene.h>
 #include <assimp/importerdesc.h>
+#include <map>
 
 using namespace Assimp;
 using namespace Assimp::Formatter;
@@ -198,6 +200,7 @@ aiNode* BVHLoader::ReadNode()
     Node& internNode = mNodes.back();
 
     // now read the node's contents
+    std::string siteToken;
     while( 1)
     {
         std::string token = GetNextToken();
@@ -217,7 +220,8 @@ aiNode* BVHLoader::ReadNode()
         else if( token == "End")
         {
             // The real symbol is "End Site". Second part comes in a separate token
-            std::string siteToken = GetNextToken();
+            siteToken.clear();
+            siteToken = GetNextToken();
             if( siteToken != "Site")
                 ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
 
@@ -261,21 +265,18 @@ aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
     aiNode* node = new aiNode( "EndSite_" + pParentName);
 
     // now read the node's contents. Only possible entry is "OFFSET"
-    while( 1)
-    {
-        std::string token = GetNextToken();
+    std::string token;
+    while( 1) {
+        token.clear();
+        token = GetNextToken();
 
         // end node's offset
-        if( token == "OFFSET")
-        {
+        if( token == "OFFSET") {
             ReadNodeOffset( node);
-        }
-        else if( token == "}")
-        {
+        } else if( token == "}") {
             // we're done with the end node
             break;
-        } else
-        {
+        } else {
             // everything else is a parse error
             ThrowException( format() << "Unknown keyword \"" << token << "\"." );
         }
@@ -295,8 +296,10 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
     offset.z = GetNextTokenAsFloat();
 
     // build a transformation matrix from it
-    pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
-        0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
+    pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x,
+                                          0.0f, 1.0f, 0.0f, offset.y,
+                                          0.0f, 0.0f, 1.0f, offset.z,
+                                          0.0f, 0.0f, 0.0f, 1.0f);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -459,6 +462,13 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
         aiNodeAnim* nodeAnim = new aiNodeAnim;
         anim->mChannels[a] = nodeAnim;
         nodeAnim->mNodeName.Set( nodeName);
+		std::map<BVHLoader::ChannelType, int> channelMap;
+
+		//Build map of channels 
+		for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel)
+		{
+			channelMap[node.mChannels[channel]] = channel;
+		}
 
         // translational part, if given
         if( node.mChannels.size() == 6)
@@ -470,16 +480,32 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
             {
                 poskey->mTime = double( fr);
 
-                // Now compute all translations in the right order
-                for( unsigned int channel = 0; channel < 3; ++channel)
+                // Now compute all translations 
+                for(BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel +1))
                 {
-                    switch( node.mChannels[channel])
-                    {
-                    case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
-                    case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
-                    case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
-                    default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
-                    }
+					//Find channel in node
+					std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
+
+					if (mapIter == channelMap.end())
+						throw DeadlyImportError("Missing position channel in node " + nodeName);
+					else {
+						int channelIdx = mapIter->second;
+						switch (channel) {
+						    case Channel_PositionX: 
+                                poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; 
+                                break;
+						    case Channel_PositionY: 
+                                poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; 
+                                break;
+						    case Channel_PositionZ: 
+                                poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; 
+                                break;
+                                
+                            default:
+                                break;
+						}
+
+					}
                 }
                 ++poskey;
             }
@@ -495,12 +521,6 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
 
         // rotation part. Always present. First find value offsets
         {
-            unsigned int rotOffset  = 0;
-            if( node.mChannels.size() == 6)
-            {
-                // Offset all further calculations
-                rotOffset = 3;
-            }
 
             // Then create the number of rotation keys
             nodeAnim->mNumRotationKeys = mAnimNumFrames;
@@ -510,20 +530,33 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
             {
                 aiMatrix4x4 temp;
                 aiMatrix3x3 rotMatrix;
-
-                for( unsigned int channel = 0; channel < 3; ++channel)
-                {
-                    // translate ZXY euler angels into a quaternion
-                    const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f;
-
-                    // Compute rotation transformations in the right order
-                    switch (node.mChannels[rotOffset+channel])
-                    {
-                    case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
-                    case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);  break;
-                    case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
-                    default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
-                    }
+				for (BVHLoader::ChannelType channel = Channel_RotationX; channel <= Channel_RotationZ; channel = (BVHLoader::ChannelType)(channel + 1))
+				{
+					//Find channel in node
+					std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
+
+					if (mapIter == channelMap.end())
+						throw DeadlyImportError("Missing rotation channel in node " + nodeName);
+					else {
+						int channelIdx = mapIter->second;
+						// translate ZXY euler angels into a quaternion
+						const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
+
+						// Compute rotation transformations in the right order
+						switch (channel)
+						{
+							case Channel_RotationX: 
+                                aiMatrix4x4::RotationX(angle, temp); rotMatrix *= aiMatrix3x3(temp); 
+                                break;
+							case Channel_RotationY: 
+                                aiMatrix4x4::RotationY(angle, temp); rotMatrix *= aiMatrix3x3(temp);  
+                                break;
+							case Channel_RotationZ: aiMatrix4x4::RotationZ(angle, temp); rotMatrix *= aiMatrix3x3(temp); 
+                                break;
+                            default:
+                                break;
+						}
+					}
                 }
 
                 rotkey->mTime = double( fr);

+ 7 - 3
code/BVHLoader.h

@@ -4,7 +4,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -48,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_BVHLOADER_H_INC
 #define AI_BVHLOADER_H_INC
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 
 struct aiNode;
 
@@ -83,7 +84,10 @@ class BVHLoader : public BaseImporter
         std::vector<ChannelType> mChannels;
         std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames
 
-        Node() { }
+        Node()
+        : mNode(nullptr)
+        { }
+
         explicit Node( const aiNode* pNode) : mNode( pNode) { }
     };
 

+ 73 - 59
code/BaseImporter.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -44,14 +45,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Implementation of BaseImporter
  */
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
+#include <assimp/ParsingUtils.h>
 #include "FileSystemFilter.h"
 #include "Importer.h"
-#include "ByteSwapper.h"
+#include <assimp/ByteSwapper.h>
 #include <assimp/scene.h>
 #include <assimp/Importer.hpp>
 #include <assimp/postprocess.h>
 #include <assimp/importerdesc.h>
+
 #include <ios>
 #include <list>
 #include <memory>
@@ -62,24 +65,25 @@ using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-BaseImporter::BaseImporter()
-: m_progress()
-{
+BaseImporter::BaseImporter() AI_NO_EXCEPT
+: m_progress() {
     // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
-BaseImporter::~BaseImporter()
-{
+BaseImporter::~BaseImporter() {
     // nothing to do here
 }
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file and returns the imported data.
-aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler)
-{
+aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) {
     m_progress = pImp->GetProgressHandler();
+    if (nullptr == m_progress) {
+        return nullptr;
+    }
+
     ai_assert(m_progress);
 
     // Gather configuration properties for this run
@@ -89,23 +93,22 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
     FileSystemFilter filter(pFile,pIOHandler);
 
     // create a scene object to hold the data
-    ScopeGuard<aiScene> sc(new aiScene());
+    std::unique_ptr<aiScene> sc(new aiScene());
 
     // dispatch importing
     try
     {
-        InternReadFile( pFile, sc, &filter);
+        InternReadFile( pFile, sc.get(), &filter);
 
     } catch( const std::exception& err )    {
         // extract error description
         m_ErrorText = err.what();
-        DefaultLogger::get()->error(m_ErrorText);
-        return NULL;
+        ASSIMP_LOG_ERROR(m_ErrorText);
+        return nullptr;
     }
 
     // return what we gathered from the import.
-    sc.dismiss();
-    return sc;
+    return sc.release();
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -115,13 +118,12 @@ void BaseImporter::SetupProperties(const Importer* /*pImp*/)
 }
 
 // ------------------------------------------------------------------------------------------------
-void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
-{
+void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
     const aiImporterDesc* desc = GetInfo();
-    ai_assert(desc != NULL);
+    ai_assert(desc != nullptr);
 
     const char* ext = desc->mFileExtensions;
-    ai_assert(ext != NULL);
+    ai_assert(ext != nullptr );
 
     const char* last = ext;
     do {
@@ -143,31 +145,29 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
     const char**        tokens,
     unsigned int        numTokens,
     unsigned int        searchBytes /* = 200 */,
-    bool                tokensSol /* false */)
+    bool                tokensSol /* false */,
+    bool                noAlphaBeforeTokens /* false */)
 {
-    ai_assert( NULL != tokens );
+    ai_assert( nullptr != tokens );
     ai_assert( 0 != numTokens );
     ai_assert( 0 != searchBytes);
 
-    if (!pIOHandler)
+    if ( nullptr == pIOHandler ) {
         return false;
+    }
 
     std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile));
     if (pStream.get() ) {
         // read 200 characters from the file
         std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]);
-        char* buffer = _buffer.get();
-        if( NULL == buffer ) {
-            return false;
-        }
-
-        const size_t read = pStream->Read(buffer,1,searchBytes);
-        if( !read ) {
+        char *buffer( _buffer.get() );
+        const size_t read( pStream->Read(buffer,1,searchBytes) );
+        if( 0 == read ) {
             return false;
         }
 
         for( size_t i = 0; i < read; ++i ) {
-            buffer[ i ] = ::tolower( buffer[ i ] );
+            buffer[ i ] = static_cast<char>( ::tolower( buffer[ i ] ) );
         }
 
         // It is not a proper handling of unicode files here ...
@@ -181,16 +181,29 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
         }
         *cur2 = '\0';
 
-        for (unsigned int i = 0; i < numTokens;++i) {
-            ai_assert(NULL != tokens[i]);
-            const char* r = strstr(buffer,tokens[i]);
+        std::string token;
+        for (unsigned int i = 0; i < numTokens; ++i ) {
+            ai_assert( nullptr != tokens[i] );
+            const size_t len( strlen( tokens[ i ] ) );
+            token.clear();
+            const char *ptr( tokens[ i ] );
+            for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) {
+                token.push_back( static_cast<char>( tolower( *ptr ) ) );
+                ++ptr;
+            }
+            const char* r = strstr( buffer, token.c_str() );
             if( !r ) {
                 continue;
             }
+            // We need to make sure that we didn't accidentially identify the end of another token as our token,
+            // e.g. in a previous version the "gltf " present in some gltf files was detected as "f "
+            if (noAlphaBeforeTokens && (r != buffer && isalpha(r[-1]))) {
+                continue;
+            }
             // We got a match, either we don't care where it is, or it happens to
             // be in the beginning of the file / line
             if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
-                DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]);
+                ASSIMP_LOG_DEBUG_F( "Found positive match for header keyword: ", tokens[i] );
                 return true;
             }
         }
@@ -228,16 +241,19 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
 
 // ------------------------------------------------------------------------------------------------
 // Get file extension from path
-/*static*/ std::string BaseImporter::GetExtension (const std::string& pFile)
-{
-    std::string::size_type pos = pFile.find_last_of('.');
+std::string BaseImporter::GetExtension( const std::string& file ) {
+    std::string::size_type pos = file.find_last_of('.');
 
     // no file extension at all
-    if( pos == std::string::npos)
+    if (pos == std::string::npos) {
         return "";
+    }
+
+
+    // thanks to Andy Maloney for the hint
+    std::string ret = file.substr( pos + 1 );
+    std::transform( ret.begin(), ret.end(), ret.begin(), ToLower<char>);
 
-    std::string ret = pFile.substr(pos+1);
-    std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint
     return ret;
 }
 
@@ -246,7 +262,8 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
 /* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
     const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
 {
-    ai_assert(size <= 16 && _magic);
+    ai_assert( size <= 16 );
+    ai_assert( _magic );
 
     if (!pIOHandler) {
         return false;
@@ -316,7 +333,7 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
 
     // UTF 8 with BOM
     if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
-        DefaultLogger::get()->debug("Found UTF-8 BOM ...");
+        ASSIMP_LOG_DEBUG("Found UTF-8 BOM ...");
 
         std::copy(data.begin()+3,data.end(),data.begin());
         data.resize(data.size()-3);
@@ -335,7 +352,7 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
 
     // UTF 32 LE with BOM
     if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
-        DefaultLogger::get()->debug("Found UTF-32 BOM ...");
+        ASSIMP_LOG_DEBUG("Found UTF-32 BOM ...");
 
         std::vector<char> output;
         int *ptr = (int*)&data[ 0 ];
@@ -355,7 +372,7 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
 
     // UTF 16 LE with BOM
     if(*((uint16_t*)&data.front()) == 0xFEFF) {
-        DefaultLogger::get()->debug("Found UTF-16 BOM ...");
+        ASSIMP_LOG_DEBUG("Found UTF-16 BOM ...");
 
         std::vector<unsigned char> output;
         utf8::utf16to8(data.begin(), data.end(), back_inserter(output));
@@ -380,16 +397,14 @@ void BaseImporter::ConvertUTF8toISO8859_1(std::string& data)
                 data[j] = ((unsigned char) data[++i] + 0x40);
             } else {
                 std::stringstream stream;
-
                 stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
-
-                DefaultLogger::get()->error(stream.str());
+                ASSIMP_LOG_ERROR( stream.str() );
 
                 data[j++] = data[i++];
                 data[j] = data[i];
             }
         } else {
-            DefaultLogger::get()->error("UTF8 code but only one character remaining");
+            ASSIMP_LOG_ERROR("UTF8 code but only one character remaining");
 
             data[j] = data[i];
         }
@@ -405,7 +420,7 @@ void BaseImporter::TextFileToBuffer(IOStream* stream,
     std::vector<char>& data,
     TextFileMode mode)
 {
-    ai_assert(NULL != stream);
+    ai_assert(nullptr != stream);
 
     const size_t fileSize = stream->FileSize();
     if (mode == FORBID_EMPTY) {
@@ -466,14 +481,14 @@ struct Assimp::BatchData {
     , pImporter( nullptr )
     , next_id(0xffff)
     , validate( validate ) {
-        ai_assert( NULL != pIO );
+        ai_assert( nullptr != pIO );
         
         pImporter = new Importer();
         pImporter->SetIOHandler( pIO );
     }
 
     ~BatchData() {
-        pImporter->SetIOHandler( NULL ); /* get pointer back into our possession */
+        pImporter->SetIOHandler( nullptr ); /* get pointer back into our possession */
         delete pImporter;
     }
 
@@ -499,9 +514,8 @@ struct Assimp::BatchData {
 typedef std::list<LoadRequest>::iterator LoadReqIt;
 
 // ------------------------------------------------------------------------------------------------
-BatchLoader::BatchLoader(IOSystem* pIO, bool validate )
-{
-    ai_assert(NULL != pIO);
+BatchLoader::BatchLoader(IOSystem* pIO, bool validate ) {
+    ai_assert(nullptr != pIO);
 
     m_data = new BatchData( pIO, validate );
 }
@@ -567,7 +581,7 @@ aiScene* BatchLoader::GetImport( unsigned int which )
             return sc;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -590,13 +604,13 @@ void BatchLoader::LoadAll()
 
         if (!DefaultLogger::isNullLogger())
         {
-            DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%");
-            DefaultLogger::get()->info("File: " + (*it).file);
+            ASSIMP_LOG_INFO("%%% BEGIN EXTERNAL FILE %%%");
+            ASSIMP_LOG_INFO_F("File: ", (*it).file);
         }
         m_data->pImporter->ReadFile((*it).file,pp);
         (*it).scene = m_data->pImporter->GetOrphanedScene();
         (*it).loaded = true;
 
-        DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%");
+        ASSIMP_LOG_INFO("%%% END EXTERNAL FILE %%%");
     }
 }

+ 5 - 4
code/BaseProcess.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -42,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 /** @file Implementation of BaseProcess */
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 #include "BaseProcess.h"
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/scene.h>
@@ -52,7 +53,7 @@ using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-BaseProcess::BaseProcess()
+BaseProcess::BaseProcess() AI_NO_EXCEPT
 : shared()
 , progress()
 {
@@ -84,7 +85,7 @@ void BaseProcess::ExecuteOnScene( Importer* pImp)
 
         // extract error description
         pImp->Pimpl()->mErrorString = err.what();
-        DefaultLogger::get()->error(pImp->Pimpl()->mErrorString);
+        ASSIMP_LOG_ERROR(pImp->Pimpl()->mErrorString);
 
         // and kill the partially imported data
         delete pImp->Pimpl()->mScene;

+ 5 - 8
code/BaseProcess.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -44,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define INCLUDED_AI_BASEPROCESS_H
 
 #include <map>
-#include "GenericProperty.h"
+#include <assimp/GenericProperty.h>
 
 struct aiScene;
 
@@ -210,20 +211,16 @@ private:
  * should be executed. If the function returns true, the class' Execute()
  * function is called subsequently.
  */
-class ASSIMP_API_WINONLY BaseProcess
-{
+class ASSIMP_API_WINONLY BaseProcess {
     friend class Importer;
 
 public:
-
     /** Constructor to be privately used by Importer */
-    BaseProcess();
+    BaseProcess() AI_NO_EXCEPT;
 
     /** Destructor, private as well */
     virtual ~BaseProcess();
 
-public:
-
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag.
      * @param pFlags The processing flags the importer was called with. A

+ 8 - 6
code/Bitmap.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -47,10 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 
-#include "Bitmap.h"
+#include <assimp/Bitmap.h>
 #include <assimp/texture.h>
 #include <assimp/IOStream.hpp>
-#include "ByteSwapper.h"
+#include <assimp/ByteSwapper.h>
 
 namespace Assimp {
 
@@ -84,7 +85,8 @@ namespace Assimp {
     }
 
     template<typename T>
-    inline std::size_t Copy(uint8_t* data, T& field) {
+    inline 
+    std::size_t Copy(uint8_t* data, const T &field) {
 #ifdef AI_BUILD_BIG_ENDIAN
         T field_swapped=AI_BE(field);
         std::memcpy(data, &field_swapped, sizeof(field)); return sizeof(field);
@@ -102,7 +104,7 @@ namespace Assimp {
         offset += Copy(&data[offset], header.size);
         offset += Copy(&data[offset], header.reserved1);
         offset += Copy(&data[offset], header.reserved2);
-        offset += Copy(&data[offset], header.offset);
+                  Copy(&data[offset], header.offset);
 
         file->Write(data, Header::header_size, 1);
     }
@@ -122,7 +124,7 @@ namespace Assimp {
         offset += Copy(&data[offset], dib.x_resolution);
         offset += Copy(&data[offset], dib.y_resolution);
         offset += Copy(&data[offset], dib.nb_colors);
-        offset += Copy(&data[offset], dib.nb_important_colors);
+                  Copy(&data[offset], dib.nb_important_colors);
 
         file->Write(data, DIB::dib_size, 1);
     }

+ 5 - 1
code/BlenderBMesh.cpp

@@ -52,7 +52,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp
 {
-    template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: ";
+    template< > const char* LogFunctions< BlenderBMeshConverter >::Prefix()
+    {
+        static auto prefix = "BLEND_BMESH: ";
+        return prefix;
+    }
 }
 
 using namespace Assimp;

+ 1 - 1
code/BlenderBMesh.h

@@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_BLEND_BMESH_H
 #define INCLUDED_AI_BLEND_BMESH_H
 
-#include "LogAux.h"
+#include <assimp/LogAux.h>
 
 namespace Assimp
 {

+ 189 - 0
code/BlenderCustomData.cpp

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

+ 89 - 0
code/BlenderCustomData.h

@@ -0,0 +1,89 @@
+#pragma once
+
+#include "BlenderDNA.h"
+#include "BlenderScene.h"
+#include <memory>
+
+namespace Assimp {
+    namespace Blender {
+        /* CustomData.type from Blender (2.79b) */
+        enum CustomDataType {
+            CD_AUTO_FROM_NAME = -1,
+            CD_MVERT = 0,
+#ifdef DNA_DEPRECATED
+            CD_MSTICKY = 1,  /* DEPRECATED */
+#endif
+            CD_MDEFORMVERT = 2,
+            CD_MEDGE = 3,
+            CD_MFACE = 4,
+            CD_MTFACE = 5,
+            CD_MCOL = 6,
+            CD_ORIGINDEX = 7,
+            CD_NORMAL = 8,
+            /*	CD_POLYINDEX        = 9, */
+            CD_PROP_FLT = 10,
+            CD_PROP_INT = 11,
+            CD_PROP_STR = 12,
+            CD_ORIGSPACE = 13,  /* for modifier stack face location mapping */
+            CD_ORCO = 14,
+            CD_MTEXPOLY = 15,
+            CD_MLOOPUV = 16,
+            CD_MLOOPCOL = 17,
+            CD_TANGENT = 18,
+            CD_MDISPS = 19,
+            CD_PREVIEW_MCOL = 20,  /* for displaying weightpaint colors */
+            /*	CD_ID_MCOL          = 21, */
+            CD_TEXTURE_MLOOPCOL = 22,
+            CD_CLOTH_ORCO = 23,
+            CD_RECAST = 24,
+
+            /* BMESH ONLY START */
+            CD_MPOLY = 25,
+            CD_MLOOP = 26,
+            CD_SHAPE_KEYINDEX = 27,
+            CD_SHAPEKEY = 28,
+            CD_BWEIGHT = 29,
+            CD_CREASE = 30,
+            CD_ORIGSPACE_MLOOP = 31,
+            CD_PREVIEW_MLOOPCOL = 32,
+            CD_BM_ELEM_PYPTR = 33,
+            /* BMESH ONLY END */
+
+            CD_PAINT_MASK = 34,
+            CD_GRID_PAINT_MASK = 35,
+            CD_MVERT_SKIN = 36,
+            CD_FREESTYLE_EDGE = 37,
+            CD_FREESTYLE_FACE = 38,
+            CD_MLOOPTANGENT = 39,
+            CD_TESSLOOPNORMAL = 40,
+            CD_CUSTOMLOOPNORMAL = 41,
+
+            CD_NUMTYPES = 42
+        };
+
+        /**
+        *   @brief  check if given cdtype is valid (ie >= 0 and < CD_NUMTYPES)
+        *   @param[in]  cdtype to check
+        *   @return true when valid
+        */
+        bool isValidCustomDataType(const int cdtype);
+
+        /**
+        *   @brief  returns CustomDataLayer ptr for given cdtype and name
+        *   @param[in]  customdata CustomData to search for wanted layer
+        *   @param[in]  cdtype to search for
+        *   @param[in]  name to search for
+        *   @return CustomDataLayer * or nullptr if not found
+        */
+        std::shared_ptr<CustomDataLayer> getCustomDataLayer(const CustomData &customdata, CustomDataType cdtype, const std::string &name);
+
+        /**
+        *   @brief  returns CustomDataLayer data ptr for given cdtype and name
+        *   @param[in]  customdata CustomData to search for wanted layer
+        *   @param[in]  cdtype to search for
+        *   @param[in]  name to search for
+        *   @return * to struct data or nullptr if not found
+        */
+        const ElemBase * getCustomDataLayerData(const CustomData &customdata, CustomDataType cdtype, const std::string &name);
+    }
+}

+ 15 - 16
code/BlenderDNA.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -47,9 +48,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
 #include "BlenderDNA.h"
-#include "StreamReader.h"
-#include "fast_atof.h"
-#include "TinyFormatter.h"
+#include <assimp/StreamReader.h>
+#include <assimp/fast_atof.h>
+#include <assimp/TinyFormatter.h>
 
 using namespace Assimp;
 using namespace Assimp::Blender;
@@ -57,12 +58,11 @@ using namespace Assimp::Formatter;
 
 static bool match4(StreamReaderAny& stream, const char* string) {
     ai_assert( nullptr != string );
-    char tmp[] = {
-        (const char)(stream).GetI1(),
-        (const char)(stream).GetI1(),
-        (const char)(stream).GetI1(),
-        (const char)(stream).GetI1()
-    };
+    char tmp[4];
+    tmp[ 0 ] = ( stream ).GetI1();
+    tmp[ 1 ] = ( stream ).GetI1();
+    tmp[ 2 ] = ( stream ).GetI1();
+    tmp[ 3 ] = ( stream ).GetI1();
     return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
 }
 
@@ -210,8 +210,7 @@ void DNAParser::Parse ()
         s.size = offset;
     }
 
-    DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
-        " structures with totally ",fields," fields"));
+    ASSIMP_LOG_DEBUG_F( "BlenderDNA: Got ", dna.structures.size()," structures with totally ",fields," fields");
 
 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
     dna.DumpToFile();
@@ -228,12 +227,12 @@ void DNAParser::Parse ()
 // ------------------------------------------------------------------------------------------------
 void DNA :: DumpToFile()
 {
-    // we dont't bother using the VFS here for this is only for debugging.
+    // we don't bother using the VFS here for this is only for debugging.
     // (and all your bases are belong to us).
 
     std::ofstream f("dna.txt");
     if (f.fail()) {
-        DefaultLogger::get()->error("Could not dump dna to dna.txt");
+        ASSIMP_LOG_ERROR("Could not dump dna to dna.txt");
         return;
     }
     f << "Field format: type name offset size" << "\n";
@@ -248,7 +247,7 @@ void DNA :: DumpToFile()
     }
     f << std::flush;
 
-    DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
+    ASSIMP_LOG_INFO("BlenderDNA: Dumped dna to dna.txt");
 }
 #endif
 
@@ -367,7 +366,7 @@ void SectionParser :: Next()
     }
 
 #ifdef ASSIMP_BUILD_BLENDER_DEBUG
-    DefaultLogger::get()->debug(current.id);
+    ASSIMP_LOG_DEBUG(current.id);
 #endif
 }
 

+ 48 - 8
code/BlenderDNA.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -46,8 +47,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_BLEND_DNA_H
 #define INCLUDED_AI_BLEND_DNA_H
 
-#include "BaseImporter.h"
-#include "StreamReader.h"
+#include <assimp/BaseImporter.h>
+#include <assimp/StreamReader.h>
 #include <assimp/DefaultLogger.hpp>
 #include <stdint.h>
 #include <memory>
@@ -92,6 +93,12 @@ struct Error : DeadlyImportError {
  *  descendents. It serves as base class for all data structure fields. */
 // -------------------------------------------------------------------------------
 struct ElemBase {
+    ElemBase()
+    : dna_type(nullptr)
+    {
+        // empty
+    }
+
     virtual ~ElemBase() {
         // empty
     }
@@ -198,7 +205,7 @@ enum ErrorPolicy {
 
 // -------------------------------------------------------------------------------
 /** Represents a data structure in a BLEND file. A Structure defines n fields
- *  and their locatios and encodings the input stream. Usually, every
+ *  and their locations and encodings the input stream. Usually, every
  *  Structure instance pertains to one equally-named data structure in the
  *  BlenderScene.h header. This class defines various utilities to map a
  *  binary `blob` read from the file to such a structure instance with
@@ -253,7 +260,7 @@ public:
      *  a compiler complain is the result.
      *  @param dest Destination value to be written
      *  @param db File database, including input stream. */
-    template <typename T> inline void Convert (T& dest, const FileDatabase& db) const;
+    template <typename T> void Convert (T& dest, const FileDatabase& db) const;
 
     // --------------------------------------------------------
     // generic converter
@@ -302,6 +309,28 @@ public:
     void ReadField(T& out, const char* name,
         const FileDatabase& db) const;
 
+    // --------------------------------------------------------
+    /**
+    *   @brief  field parsing for dynamic vectors
+    *   @param[in]  out vector of struct to be filled
+    *   @param[in]  name of field
+    *   @param[in]  db to access the file, dna, ...
+    *   @return true when read was successful
+    */
+    template <int error_policy, template <typename> class TOUT, typename T>
+    bool ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const;
+
+    /**
+    *   @brief  parses raw customdata
+    *   @param[in]  out shared_ptr to be filled
+    *   @param[in]  cdtype customdata type to read
+    *   @param[in]  name of field ptr
+    *   @param[in]  db to access the file, dna, ...
+    *   @return true when read was successful
+    */
+    template <int error_policy>
+    bool ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const;
+
 private:
 
     // --------------------------------------------------------
@@ -374,7 +403,7 @@ template <>  struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
 
     template <typename T>
     void operator ()(T& out, const char* reason = "<add reason>") {
-        DefaultLogger::get()->warn(reason);
+        ASSIMP_LOG_WARN(reason);
 
         // ... and let the show go on
         _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
@@ -387,7 +416,7 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> {
     void operator ()(T& /*out*/,const char* = "") {
         // obviously, it is crucial that _DefaultInitializer is used
         // only from within a catch clause.
-        throw;
+        throw DeadlyImportError("Constructing BlenderDNA Structure encountered an error");
     }
 };
 
@@ -656,7 +685,7 @@ public:
     /** Check whether a specific item is in the cache.
      *  @param s Data type of the item
      *  @param out Output pointer. Unchanged if the
-     *   cache doens't know the item yet.
+     *   cache doesn't know the item yet.
      *  @param ptr Item address to look for. */
     template <typename T> void get (
         const Structure& s,
@@ -796,6 +825,17 @@ private:
     FileDatabase& db;
 };
 
+/**
+*   @brief  read CustomData's data to ptr to mem
+*   @param[out] out memory ptr to set
+*   @param[in]  cdtype  to read
+*   @param[in]  cnt cnt of elements to read
+*   @param[in]  db to read elements from
+*   @return true when ok
+*/
+bool readCustomData(std::shared_ptr<ElemBase> &out, int cdtype, size_t cnt, const FileDatabase &db);
+
+
     } // end Blend
 } // end Assimp
 

+ 112 - 8
code/BlenderDNA.inl

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -47,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define INCLUDED_AI_BLEND_DNA_INL
 
 #include <memory>
-#include "TinyFormatter.h"
+#include <assimp/TinyFormatter.h>
 
 namespace Assimp {
 namespace Blender {
@@ -306,6 +307,108 @@ void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) co
 }
 
 
+//--------------------------------------------------------------------------------
+// field parsing for raw untyped data (like CustomDataLayer.data)
+template <int error_policy>
+bool Structure::ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const {
+
+	const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+
+	Pointer ptrval;
+	const Field* f;
+	try	{
+		f = &(*this)[name];
+
+		// sanity check, should never happen if the genblenddna script is right
+		if (!(f->flags & FieldFlag_Pointer)) {
+			throw Error((Formatter::format(), "Field `", name, "` of structure `",
+				this->name, "` ought to be a pointer"));
+		}
+
+		db.reader->IncPtr(f->offset);
+		Convert(ptrval, db);
+		// actually it is meaningless on which Structure the Convert is called
+		// because the `Pointer` argument triggers a special implementation.
+	}
+	catch (const Error& e) {
+		_defaultInitializer<error_policy>()(out, e.what());
+		out.reset();
+	}
+
+	bool readOk = true;
+	if (ptrval.val)	{
+		// get block for ptr
+		const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
+		db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
+		// read block->num instances of given type to out
+		readOk = readCustomData(out, cdtype, block->num, db);
+	}
+
+	// and recover the previous stream position
+	db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+	++db.stats().fields_read;
+#endif
+
+	return readOk;
+}
+
+//--------------------------------------------------------------------------------
+template <int error_policy, template <typename> class TOUT, typename T>
+bool Structure::ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const {
+	out.clear();
+
+	const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+
+	Pointer ptrval;
+	const Field* f;
+	try	{
+		f = &(*this)[name];
+
+		// sanity check, should never happen if the genblenddna script is right
+		if (!(f->flags & FieldFlag_Pointer)) {
+			throw Error((Formatter::format(), "Field `", name, "` of structure `",
+				this->name, "` ought to be a pointer"));
+		}
+
+		db.reader->IncPtr(f->offset);
+		Convert(ptrval, db);
+		// actually it is meaningless on which Structure the Convert is called
+		// because the `Pointer` argument triggers a special implementation.
+	}
+	catch (const Error& e) {
+		_defaultInitializer<error_policy>()(out, e.what());
+		out.clear();
+		return false;
+	}
+
+
+	if (ptrval.val)	{
+		// find the file block the pointer is pointing to
+		const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
+		db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
+		// FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
+		// I really ought to improve StreamReader to work with 64 bit indices exclusively.
+
+		const Structure& s = db.dna[f->type];
+		for (size_t i = 0; i < block->num; ++i)	{
+			TOUT<T> p(new T);
+			s.Convert(*p, db);
+			out.push_back(p);
+		}
+	}
+
+	db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+	++db.stats().fields_read;
+#endif
+
+	return true;
+}
+
+
 //--------------------------------------------------------------------------------
 template <template <typename> class TOUT, typename T>
 bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const FileDatabase& db,
@@ -467,9 +570,7 @@ template <> bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shar
         // this might happen if DNA::RegisterConverters hasn't been called so far
         // or if the target type is not contained in `our` DNA.
         out.reset();
-        DefaultLogger::get()->warn((Formatter::format(),
-            "Failed to find a converter for the `",s.name,"` structure"
-            ));
+        ASSIMP_LOG_WARN_F( "Failed to find a converter for the `",s.name,"` structure" );
         return false;
     }
 
@@ -501,7 +602,7 @@ const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrv
 {
     // the file blocks appear in list sorted by
     // with ascending base addresses so we can run a
-    // binary search to locate the pointee quickly.
+    // binary search to locate the pointer quickly.
 
     // NOTE: Blender seems to distinguish between side-by-side
     // data (stored in the same data block) and far pointers,
@@ -585,11 +686,14 @@ template <> inline void Structure :: Convert<int>    (int& dest,const FileDataba
 }
 
 // ------------------------------------------------------------------------------------------------
-template <> inline void Structure :: Convert<short>  (short& dest,const FileDatabase& db) const
+template<> inline void Structure :: Convert<short>  (short& dest,const FileDatabase& db) const
 {
     // automatic rescaling from short to float and vice versa (seems to be used by normals)
     if (name == "float") {
-        dest = static_cast<short>(db.reader->GetF4() * 32767.f);
+        float f = db.reader->GetF4();
+        if ( f > 1.0f )
+            f = 1.0f;
+        dest = static_cast<short>( f * 32767.f);
         //db.reader->IncPtr(-4);
         return;
     }

+ 9 - 4
code/BlenderIntermediate.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -110,7 +111,7 @@ namespace Blender {
         void operator= (const TempArray&)  {
         }
 
-        TempArray(const TempArray& arr) {
+        TempArray(const TempArray& /*arr*/) {
         }
 
     private:
@@ -121,9 +122,11 @@ namespace Blender {
 #   pragma warning(disable:4351)
 #endif
 
+    // As counter-intuitive as it may seem, a comparator must return false for equal values.
+    // The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
     struct ObjectCompare {
         bool operator() (const Object* left, const Object* right) const {
-            return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) == 0;
+            return ::strncmp(left->id.name, right->id.name, strlen( left->id.name ) ) < 0;
         }
     };
 
@@ -142,9 +145,11 @@ namespace Blender {
             , db(db)
         {}
 
+        // As counter-intuitive as it may seem, a comparator must return false for equal values.
+        // The C++ standard defines and expects this behavior: true if lhs < rhs, false otherwise.
         struct ObjectCompare {
             bool operator() (const Object* left, const Object* right) const {
-                return ::strncmp( left->id.name, right->id.name, strlen( left->id.name ) ) == 0;
+                return ::strncmp( left->id.name, right->id.name, strlen( left->id.name ) ) < 0;
             }
         };
 

+ 93 - 37
code/BlenderLoader.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -53,13 +54,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BlenderIntermediate.h"
 #include "BlenderModifier.h"
 #include "BlenderBMesh.h"
-#include "StringUtils.h"
+#include "BlenderCustomData.h"
+#include <assimp/StringUtils.h>
 #include <assimp/scene.h>
 #include <assimp/importerdesc.h>
 
-#include "StringComparison.h"
-#include "StreamReader.h"
-#include "MemoryIOWrapper.h"
+#include <assimp/StringComparison.h>
+#include <assimp/StreamReader.h>
+#include <assimp/MemoryIOWrapper.h>
 
 #include <cctype>
 
@@ -74,7 +76,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endif
 
 namespace Assimp {
-    template<> const std::string LogFunctions<BlenderImporter>::log_prefix = "BLEND: ";
+    template<> const char* LogFunctions<BlenderImporter>::Prefix()
+    {
+        static auto prefix = "BLEND: ";
+        return prefix;
+    }
 }
 
 using namespace Assimp;
@@ -149,14 +155,6 @@ void BlenderImporter::SetupProperties(const Importer* /*pImp*/)
     // nothing to be done for the moment
 }
 
-struct free_it {
-    free_it(void* free) : free(free) {}
-    ~free_it() {
-        ::free(this->free);
-    }
-
-    void* free;
-};
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
@@ -164,8 +162,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
     aiScene* pScene, IOSystem* pIOHandler)
 {
 #ifndef ASSIMP_BUILD_NO_COMPRESSED_BLEND
-    Bytef* dest = NULL;
-    free_it free_it_really(dest);
+    std::vector<Bytef> uncompressed;
 #endif
 
 
@@ -213,6 +210,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
 
         size_t total = 0l;
 
+        // TODO: be smarter about this, decompress directly into heap buffer
         // and decompress the data .... do 1k chunks in the hope that we won't kill the stack
 #define MYBLOCK 1024
         Bytef block[MYBLOCK];
@@ -227,8 +225,8 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
             }
             const size_t have = MYBLOCK - zstream.avail_out;
             total += have;
-            dest = reinterpret_cast<Bytef*>( realloc(dest,total) );
-            memcpy(dest + total - have,block,have);
+            uncompressed.resize(total);
+            memcpy(uncompressed.data() + total - have,block,have);
         }
         while (ret != Z_STREAM_END);
 
@@ -236,7 +234,7 @@ void BlenderImporter::InternReadFile( const std::string& pFile,
         inflateEnd(&zstream);
 
         // replace the input stream with a memory stream
-        stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(dest),total));
+        stream.reset(new MemoryIOStream(reinterpret_cast<uint8_t*>(uncompressed.data()),total));
 
         // .. and retry
         stream->Read(magic,7,1);
@@ -330,12 +328,12 @@ void BlenderImporter::ExtractScene(Scene& out, const FileDatabase& file)
     ss.Convert(out,file);
 
 #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
-    DefaultLogger::get()->info((format(),
+    ASSIMP_LOG_INFO_F(
         "(Stats) Fields read: " ,file.stats().fields_read,
         ", pointers resolved: " ,file.stats().pointers_resolved,
         ", cache hits: "        ,file.stats().cache_hits,
         ", cached objects: "    ,file.stats().cached_objects
-    ));
+    );
 #endif
 }
 
@@ -1024,6 +1022,34 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
         }
     }
 
+    // TODO should we create the TextureUVMapping map in Convert<Material> to prevent redundant processing?
+
+    // create texture <-> uvname mapping for all materials
+    // key is texture number, value is data *
+    typedef std::map<uint32_t, const MLoopUV *> TextureUVMapping;
+    // key is material number, value is the TextureUVMapping for the material
+    typedef std::map<uint32_t, TextureUVMapping> MaterialTextureUVMappings;
+    MaterialTextureUVMappings matTexUvMappings;
+    const uint32_t maxMat = static_cast<const uint32_t>(mesh->mat.size());
+    for (uint32_t m = 0; m < maxMat; ++m) {
+        // get material by index
+        const std::shared_ptr<Material> pMat = mesh->mat[m];
+        TextureUVMapping texuv;
+        const uint32_t maxTex = sizeof(pMat->mtex) / sizeof(pMat->mtex[0]);
+        for (uint32_t t = 0; t < maxTex; ++t) {
+            if (pMat->mtex[t] && pMat->mtex[t]->uvname[0]) {
+                // get the CustomData layer for given uvname and correct type
+                const ElemBase *pLoop = getCustomDataLayerData(mesh->ldata, CD_MLOOPUV, pMat->mtex[t]->uvname);
+                if (pLoop) {
+                    texuv.insert(std::make_pair(t, dynamic_cast<const MLoopUV *>(pLoop)));
+                }
+            }
+        }
+        if (texuv.size()) {
+            matTexUvMappings.insert(std::make_pair(m, texuv));
+        }
+    }
+
     // collect texture coordinates, they're stored in a separate per-face buffer
     if (mesh->mtface || mesh->mloopuv) {
         if (mesh->totface > static_cast<int> ( mesh->mtface.size())) {
@@ -1031,8 +1057,17 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
         }
         for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
             ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
-
-            (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
+            const auto itMatTexUvMapping = matTexUvMappings.find((*it)->mMaterialIndex);
+            if (itMatTexUvMapping == matTexUvMappings.end()) {
+                // default behaviour like before
+                (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
+            }
+            else {
+                // create texture coords for every mapped tex
+                for (uint32_t i = 0; i < itMatTexUvMapping->second.size(); ++i) {
+                    (*it)->mTextureCoords[i] = new aiVector3D[(*it)->mNumVertices];
+                }
+            }
             (*it)->mNumFaces = (*it)->mNumVertices = 0;
         }
 
@@ -1054,13 +1089,34 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
             aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ];
             const aiFace& f = out->mFaces[out->mNumFaces++];
 
-            aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
-            for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
-                const MLoopUV& uv = mesh->mloopuv[v.loopstart + j];
-                vo->x = uv.uv[0];
-                vo->y = uv.uv[1];
+            const auto itMatTexUvMapping = matTexUvMappings.find(v.mat_nr);
+            if (itMatTexUvMapping == matTexUvMappings.end()) {
+                // old behavior
+                aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
+                for (unsigned int j = 0; j < f.mNumIndices; ++j, ++vo, ++out->mNumVertices) {
+                    const MLoopUV& uv = mesh->mloopuv[v.loopstart + j];
+                    vo->x = uv.uv[0];
+                    vo->y = uv.uv[1];
+                }
+            }
+            else {
+                // create textureCoords for every mapped tex
+                for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++m) {
+                    const MLoopUV *tm = itMatTexUvMapping->second[m];
+                    aiVector3D* vo = &out->mTextureCoords[m][out->mNumVertices];
+                    uint32_t j = 0;
+                    for (; j < f.mNumIndices; ++j, ++vo) {
+                        const MLoopUV& uv = tm[v.loopstart + j];
+                        vo->x = uv.uv[0];
+                        vo->y = uv.uv[1];
+                    }
+                    // only update written mNumVertices in last loop
+                    // TODO why must the numVertices be incremented here?
+                    if (m == itMatTexUvMapping->second.size() - 1) {
+                        out->mNumVertices += j;
+                    }
+                }
             }
-
         }
     }
 
@@ -1144,24 +1200,24 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
 // ------------------------------------------------------------------------------------------------
 aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj, const Camera* cam, ConversionData& /*conv_data*/)
 {
-    ScopeGuard<aiCamera> out(new aiCamera());
+    std::unique_ptr<aiCamera> out(new aiCamera());
     out->mName = obj->id.name+2;
     out->mPosition = aiVector3D(0.f, 0.f, 0.f);
     out->mUp = aiVector3D(0.f, 1.f, 0.f);
     out->mLookAt = aiVector3D(0.f, 0.f, -1.f);
     if (cam->sensor_x && cam->lens) {
-        out->mHorizontalFOV = std::atan2(cam->sensor_x,  2.f * cam->lens);
+        out->mHorizontalFOV = 2.f * std::atan2(cam->sensor_x,  2.f * cam->lens);
     }
     out->mClipPlaneNear = cam->clipsta;
     out->mClipPlaneFar = cam->clipend;
 
-    return out.dismiss();
+    return out.release();
 }
 
 // ------------------------------------------------------------------------------------------------
 aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, const Lamp* lamp, ConversionData& /*conv_data*/)
 {
-    ScopeGuard<aiLight> out(new aiLight());
+    std::unique_ptr<aiLight> out(new aiLight());
     out->mName = obj->id.name+2;
 
     switch (lamp->type)
@@ -1199,7 +1255,7 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
     out->mColorAmbient = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
     out->mColorSpecular = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
     out->mColorDiffuse = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
-    return out.dismiss();
+    return out.release();
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -1217,7 +1273,7 @@ aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, Convers
         ++it;
     }
 
-    ScopeGuard<aiNode> node(new aiNode(obj->id.name+2)); // skip over the name prefix 'OB'
+    std::unique_ptr<aiNode> node(new aiNode(obj->id.name+2)); // skip over the name prefix 'OB'
     if (obj->data) {
         switch (obj->type)
         {
@@ -1301,14 +1357,14 @@ aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, Convers
         aiNode** nd = node->mChildren = new aiNode*[node->mNumChildren]();
         for (const Object* nobj :children) {
             *nd = ConvertNode(in,nobj,conv_data,node->mTransformation * parentTransform);
-            (*nd++)->mParent = node;
+            (*nd++)->mParent = node.get();
         }
     }
 
     // apply modifiers
     modifier_cache->ApplyModifiers(*node,conv_data,in,*obj);
 
-    return node.dismiss();
+    return node.release();
 }
 
 #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 4 - 3
code/BlenderLoader.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -45,8 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_BLEND_LOADER_H
 #define INCLUDED_AI_BLEND_LOADER_H
 
-#include "BaseImporter.h"
-#include "LogAux.h"
+#include <assimp/BaseImporter.h>
+#include <assimp/LogAux.h>
 #include <memory>
 
 struct aiNode;

+ 6 - 31
code/BlenderModifier.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -47,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "BlenderModifier.h"
 #include <assimp/SceneCombiner.h>
-#include "Subdivision.h"
+#include <assimp/Subdivision.h>
 #include <assimp/scene.h>
 #include <memory>
 
@@ -69,34 +70,6 @@ static const fpCreateModifier creators[] = {
         NULL // sentinel
 };
 
-// ------------------------------------------------------------------------------------------------
-// just testing out some new macros to simplify logging
-#define ASSIMP_LOG_WARN_F(string,...)\
-    DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
-
-#define ASSIMP_LOG_ERROR_F(string,...)\
-    DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
-
-#define ASSIMP_LOG_DEBUG_F(string,...)\
-    DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
-
-#define ASSIMP_LOG_INFO_F(string,...)\
-    DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
-
-
-#define ASSIMP_LOG_WARN(string)\
-    DefaultLogger::get()->warn(string)
-
-#define ASSIMP_LOG_ERROR(string)\
-    DefaultLogger::get()->error(string)
-
-#define ASSIMP_LOG_DEBUG(string)\
-    DefaultLogger::get()->debug(string)
-
-#define ASSIMP_LOG_INFO(string)\
-    DefaultLogger::get()->info(string)
-
-
 // ------------------------------------------------------------------------------------------------
 struct SharedModifierData : ElemBase
 {
@@ -310,7 +283,9 @@ void  BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data
 
     std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
     ai_assert(subd);
-
+    if ( conv_data.meshes->empty() ) {
+        return;
+    }
     aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
     std::unique_ptr<aiMesh*[]> tempmeshes(new aiMesh*[out.mNumMeshes]());
 

+ 30 - 32
code/BlenderModifier.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -46,53 +47,57 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define INCLUDED_AI_BLEND_MODIFIER_H
 
 #include "BlenderIntermediate.h"
-#include "TinyFormatter.h"
 
 namespace Assimp {
 namespace Blender {
 
 // -------------------------------------------------------------------------------------------
-/** Dummy base class for all blender modifiers. Modifiers are reused between imports, so
- *  they should be stateless and not try to cache model data. */
+/** 
+ *  Dummy base class for all blender modifiers. Modifiers are reused between imports, so
+ *  they should be stateless and not try to cache model data. 
+ */
 // -------------------------------------------------------------------------------------------
-class BlenderModifier
-{
+class BlenderModifier {
 public:
+    /**
+     *  The class destructor, virtual.
+     */
     virtual ~BlenderModifier() {
         // empty
     }
 
-public:
-
     // --------------------
-    /** Check if *this* modifier is active, given a ModifierData& block.*/
+    /** 
+     *  Check if *this* modifier is active, given a ModifierData& block.
+     */
     virtual bool IsActive( const ModifierData& /*modin*/) {
         return false;
     }
 
     // --------------------
-    /** Apply the modifier to a given output node. The original data used
+    /** 
+     *  Apply the modifier to a given output node. The original data used
      *  to construct the node is given as well. Not called unless IsActive()
-     *  was called and gave positive response. */
+     *  was called and gave positive response. 
+     */
     virtual void DoIt(aiNode& /*out*/,
         ConversionData& /*conv_data*/,
         const ElemBase& orig_modifier,
         const Scene& /*in*/,
         const Object& /*orig_object*/
     ) {
-        DefaultLogger::get()->warn((Formatter::format("This modifier is not supported, skipping: "),orig_modifier.dna_type));
+        ASSIMP_LOG_INFO_F("This modifier is not supported, skipping: ",orig_modifier.dna_type );
         return;
     }
 };
 
-
 // -------------------------------------------------------------------------------------------
-/** Manage all known modifiers and instance and apply them if necessary */
+/** 
+ *  Manage all known modifiers and instance and apply them if necessary 
+ */
 // -------------------------------------------------------------------------------------------
-class BlenderModifierShowcase
-{
+class BlenderModifierShowcase {
 public:
-
     // --------------------
     /** Apply all requested modifiers provided we support them. */
     void ApplyModifiers(aiNode& out,
@@ -102,25 +107,18 @@ public:
     );
 
 private:
-
     TempArray< std::vector,BlenderModifier > cached_modifiers;
 };
 
-
-
-
-
-// MODIFIERS
-
-
+// MODIFIERS /////////////////////////////////////////////////////////////////////////////////
 
 // -------------------------------------------------------------------------------------------
-/** Mirror modifier. Status: implemented. */
+/** 
+ *  Mirror modifier. Status: implemented. 
+ */
 // -------------------------------------------------------------------------------------------
-class BlenderModifier_Mirror : public BlenderModifier
-{
+class BlenderModifier_Mirror : public BlenderModifier {
 public:
-
     // --------------------
     virtual bool IsActive( const ModifierData& modin);
 
@@ -136,8 +134,7 @@ public:
 // -------------------------------------------------------------------------------------------
 /** Subdivision modifier. Status: dummy. */
 // -------------------------------------------------------------------------------------------
-class BlenderModifier_Subdivision : public BlenderModifier
-{
+class BlenderModifier_Subdivision : public BlenderModifier {
 public:
 
     // --------------------
@@ -152,6 +149,7 @@ public:
     ) ;
 };
 
+}
+}
 
-}}
 #endif // !INCLUDED_AI_BLEND_MODIFIER_H

+ 76 - 13
code/BlenderScene.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BlenderScene.h"
 #include "BlenderSceneGen.h"
 #include "BlenderDNA.h"
+#include "BlenderCustomData.h"
 
 using namespace Assimp;
 using namespace Assimp::Blender;
@@ -59,7 +60,9 @@ template <> void Structure :: Convert<Object> (
 {
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
-    ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
+    int temp = 0;
+    ReadField<ErrorPolicy_Fail>(temp,"type",db);
+    dest.type = static_cast<Assimp::Blender::Object::Type>(temp);
     ReadFieldArray2<ErrorPolicy_Warn>(dest.obmat,"obmat",db);
     ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv,"parentinv",db);
     ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr,"parsubstr",db);
@@ -100,14 +103,21 @@ template <> void Structure :: Convert<MTex> (
     ) const
 {
 
-    ReadField<ErrorPolicy_Igno>((short&)dest.mapto,"mapto",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.blendtype,"blendtype",db);
+    int temp_short = 0;
+    ReadField<ErrorPolicy_Igno>(temp_short,"mapto",db);
+    dest.mapto = static_cast<Assimp::Blender::MTex::MapType>(temp_short);
+    int temp = 0;
+    ReadField<ErrorPolicy_Igno>(temp,"blendtype",db);
+    dest.blendtype = static_cast<Assimp::Blender::MTex::BlendType>(temp);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.object,"*object",db);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.tex,"*tex",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.uvname,"uvname",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.projx,"projx",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.projy,"projy",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.projz,"projz",db);
+    ReadField<ErrorPolicy_Igno>(temp,"projx",db);
+    dest.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
+    ReadField<ErrorPolicy_Igno>(temp,"projy",db);
+    dest.projy = static_cast<Assimp::Blender::MTex::Projection>(temp);
+    ReadField<ErrorPolicy_Igno>(temp,"projz",db);
+    dest.projz = static_cast<Assimp::Blender::MTex::Projection>(temp);
     ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);
@@ -190,8 +200,10 @@ template <> void Structure :: Convert<Lamp> (
 {
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
-    ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
-    ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db);
+    int temp = 0;
+    ReadField<ErrorPolicy_Fail>(temp,"type",db);
+    dest.type = static_cast<Assimp::Blender::Lamp::Type>(temp);
+    ReadField<ErrorPolicy_Igno>(dest.flags,"flag",db);
     ReadField<ErrorPolicy_Igno>(dest.colormodel,"colormodel",db);
     ReadField<ErrorPolicy_Igno>(dest.totex,"totex",db);
     ReadField<ErrorPolicy_Warn>(dest.r,"r",db);
@@ -204,7 +216,8 @@ template <> void Structure :: Convert<Lamp> (
     ReadField<ErrorPolicy_Igno>(dest.spotblend,"spotblend",db);
     ReadField<ErrorPolicy_Igno>(dest.att1,"att1",db);
     ReadField<ErrorPolicy_Igno>(dest.att2,"att2",db);
-    ReadField<ErrorPolicy_Igno>((int&)dest.falloff_type,"falloff_type",db);
+    ReadField<ErrorPolicy_Igno>(temp,"falloff_type",db);
+    dest.falloff_type = static_cast<Assimp::Blender::Lamp::FalloffType>(temp);
     ReadField<ErrorPolicy_Igno>(dest.sun_brightness,"sun_brightness",db);
     ReadField<ErrorPolicy_Igno>(dest.area_size,"area_size",db);
     ReadField<ErrorPolicy_Igno>(dest.area_sizey,"area_sizey",db);
@@ -469,6 +482,12 @@ template <> void Structure :: Convert<Mesh> (
     ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol,"*mcol",db);
     ReadFieldPtr<ErrorPolicy_Fail>(dest.mat,"**mat",db);
 
+    ReadField<ErrorPolicy_Igno>(dest.vdata, "vdata", db);
+    ReadField<ErrorPolicy_Igno>(dest.edata, "edata", db);
+    ReadField<ErrorPolicy_Igno>(dest.fdata, "fdata", db);
+    ReadField<ErrorPolicy_Igno>(dest.pdata, "pdata", db);
+    ReadField<ErrorPolicy_Warn>(dest.ldata, "ldata", db);
+
     db.reader->IncPtr(size);
 }
 
@@ -693,8 +712,12 @@ template <> void Structure :: Convert<Tex> (
     const FileDatabase& db
     ) const
 {
-    ReadField<ErrorPolicy_Igno>((short&)dest.imaflag,"imaflag",db);
-    ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db);
+    short temp_short = 0;
+    ReadField<ErrorPolicy_Igno>(temp_short,"imaflag",db);
+    dest.imaflag = static_cast<Assimp::Blender::Tex::ImageFlags>(temp_short);
+    int temp = 0;
+    ReadField<ErrorPolicy_Fail>(temp,"type",db);
+    dest.type = static_cast<Assimp::Blender::Tex::Type>(temp);
     ReadFieldPtr<ErrorPolicy_Warn>(dest.ima,"*ima",db);
 
     db.reader->IncPtr(size);
@@ -708,8 +731,11 @@ template <> void Structure :: Convert<Camera> (
 {
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
-    ReadField<ErrorPolicy_Warn>((int&)dest.type,"type",db);
-    ReadField<ErrorPolicy_Warn>((int&)dest.flag,"flag",db);
+    int temp = 0;
+    ReadField<ErrorPolicy_Warn>(temp,"type",db);
+    dest.type = static_cast<Assimp::Blender::Camera::Type>(temp);
+    ReadField<ErrorPolicy_Warn>(temp,"flag",db);
+    dest.flag = static_cast<Assimp::Blender::Camera::Type>(temp);
     ReadField<ErrorPolicy_Warn>(dest.lens,"lens",db);
     ReadField<ErrorPolicy_Warn>(dest.sensor_x,"sensor_x",db);
     ReadField<ErrorPolicy_Igno>(dest.clipsta,"clipsta",db);
@@ -767,6 +793,41 @@ template <> void Structure :: Convert<Image> (
     db.reader->IncPtr(size);
 }
 
+//--------------------------------------------------------------------------------
+template <> void Structure::Convert<CustomData>(
+    CustomData& dest,
+    const FileDatabase& db
+    ) const
+{
+    ReadFieldArray<ErrorPolicy_Warn>(dest.typemap, "typemap", db);
+    ReadField<ErrorPolicy_Warn>(dest.totlayer, "totlayer", db);
+    ReadField<ErrorPolicy_Warn>(dest.maxlayer, "maxlayer", db);
+    ReadField<ErrorPolicy_Warn>(dest.totsize, "totsize", db);
+    ReadFieldPtrVector<ErrorPolicy_Warn>(dest.layers, "*layers", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <> void Structure::Convert<CustomDataLayer>(
+    CustomDataLayer& dest,
+    const FileDatabase& db
+    ) const
+{
+    ReadField<ErrorPolicy_Fail>(dest.type, "type", db);
+    ReadField<ErrorPolicy_Fail>(dest.offset, "offset", db);
+    ReadField<ErrorPolicy_Fail>(dest.flag, "flag", db);
+    ReadField<ErrorPolicy_Fail>(dest.active, "active", db);
+    ReadField<ErrorPolicy_Fail>(dest.active_rnd, "active_rnd", db);
+    ReadField<ErrorPolicy_Fail>(dest.active_clone, "active_clone", db);
+    ReadField<ErrorPolicy_Fail>(dest.active_mask, "active_mask", db);
+    ReadField<ErrorPolicy_Fail>(dest.uid, "uid", db);
+    ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
+    ReadCustomDataPtr<ErrorPolicy_Fail>(dest.data, dest.type, "*data", db);
+
+    db.reader->IncPtr(size);
+}
+
 //--------------------------------------------------------------------------------
 void DNA::RegisterConverters() {
 
@@ -803,6 +864,8 @@ void DNA::RegisterConverters() {
     converters["Camera"] = DNA::FactoryPair( &Structure::Allocate<Camera>, &Structure::Convert<Camera> );
     converters["MirrorModifierData"] = DNA::FactoryPair( &Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData> );
     converters["Image"] = DNA::FactoryPair( &Structure::Allocate<Image>, &Structure::Convert<Image> );
+    converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
+    converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
 }
 
 #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 89 - 2
code/BlenderScene.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -156,10 +157,16 @@ struct World : ElemBase {
 // -------------------------------------------------------------------------------
 struct MVert : ElemBase {
     float co[3] FAIL;
-    float no[3] FAIL;
+    float no[3] FAIL;       // readed as short and divided through / 32767.f
     char flag;
     int mat_nr WARN;
     int bweight;
+
+    MVert() : ElemBase()
+        , flag(0)
+        , mat_nr(0)
+        , bweight(0)
+    {}
 };
 
 // -------------------------------------------------------------------------------
@@ -225,6 +232,14 @@ struct TFace : ElemBase {
 
 // -------------------------------------------------------------------------------
 struct MTFace : ElemBase {
+	MTFace()
+	: flag(0)
+	, mode(0)
+	, tile(0)
+	, unwrap(0)
+	{
+	}
+
     float uv[4][2] FAIL;
     char flag;
     short mode;
@@ -360,6 +375,72 @@ struct Material : ElemBase {
     std::shared_ptr<MTex> mtex[18];
 };
 
+/*
+CustomDataLayer 104
+
+    int type 0 4
+    int offset 4 4
+    int flag 8 4
+    int active 12 4
+    int active_rnd 16 4
+    int active_clone 20 4
+    int active_mask 24 4
+    int uid 28 4
+    char name 32 64
+    void *data 96 8
+*/
+struct CustomDataLayer : ElemBase {
+    int type;
+    int offset;
+    int flag;
+    int active;
+    int active_rnd;
+    int active_clone;
+    int active_mask;
+    int uid;
+    char name[64];
+    std::shared_ptr<ElemBase> data;     // must be converted to real type according type member
+
+    CustomDataLayer()
+        : ElemBase()
+        , type(0)
+        , offset(0)
+        , flag(0)
+        , active(0)
+        , active_rnd(0)
+        , active_clone(0)
+        , active_mask(0)
+        , uid(0)
+        , data(nullptr)
+    {
+        memset(name, 0, sizeof name);
+    }
+};
+
+/*
+CustomData 208
+
+    CustomDataLayer *layers 0 8
+    int typemap 8 168
+    int pad_i1 176 4
+    int totlayer 180 4
+    int maxlayer 184 4
+    int totsize 188 4
+    BLI_mempool *pool 192 8
+    CustomDataExternal *external 200 8
+*/
+struct CustomData : ElemBase {
+    vector<std::shared_ptr<struct CustomDataLayer> > layers;
+    int typemap[42];    // CD_NUMTYPES
+    int totlayer;
+    int maxlayer;
+    int totsize;
+    /*
+    std::shared_ptr<BLI_mempool> pool;
+    std::shared_ptr<CustomDataExternal> external;
+    */
+};
+
 // -------------------------------------------------------------------------------
 struct Mesh : ElemBase {
     ID id FAIL;
@@ -389,6 +470,12 @@ struct Mesh : ElemBase {
     vector<MCol> mcol;
 
     vector< std::shared_ptr<Material> > mat FAIL;
+
+    struct CustomData vdata;
+    struct CustomData edata;
+    struct CustomData fdata;
+    struct CustomData pdata;
+    struct CustomData ldata;
 };
 
 // -------------------------------------------------------------------------------

+ 11 - 0
code/BlenderSceneGen.h

@@ -248,6 +248,17 @@ template <> void Structure :: Convert<Image> (
     ) const
 ;
 
+template <> void Structure::Convert<CustomData>(
+    CustomData& dest,
+    const FileDatabase& db
+    ) const
+    ;
+
+template <> void Structure::Convert<CustomDataLayer>(
+    CustomDataLayer& dest,
+    const FileDatabase& db
+    ) const
+    ;
 
     }
 }

+ 12 - 3
code/BlenderTessellator.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -59,7 +60,11 @@ static const unsigned int BLEND_TESS_MAGIC = 0x83ed9ac3;
 
 namspace Assimp
 {
-    template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
+    template< > const char* LogFunctions< BlenderTessellatorGL >::Prefix()
+    {
+        static auto prefix = "BLEND_TESS_GL: ";
+        return prefix;
+    }
 }
 
 using namespace Assimp;
@@ -252,7 +257,11 @@ void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* )
 
 namespace Assimp
 {
-    template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: ";
+    template< > const char* LogFunctions< BlenderTessellatorP2T >::Prefix()
+    {
+        static auto prefix = "BLEND_TESS_P2T: ";
+        return prefix;
+    }
 }
 
 using namespace Assimp;

+ 4 - 3
code/BlenderTessellator.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -46,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define INCLUDED_AI_BLEND_TESSELLATOR_H
 
 // Use these to toggle between GLU Tessellate or poly2tri
-// Note (acg) keep GLU Tesselate disabled by default - if it is turned on,
+// Note (acg) keep GLU Tessellate disabled by default - if it is turned on,
 // assimp needs to be linked against GLU, which is currently not yet
 // made configurable in CMake and potentially not wanted by most users
 // as it requires a Gl environment.
@@ -58,7 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #   define ASSIMP_BLEND_WITH_POLY_2_TRI 1
 #endif
 
-#include "LogAux.h"
+#include <assimp/LogAux.h>
 
 #if ASSIMP_BLEND_WITH_GLU_TESSELLATE
 

+ 68 - 97
code/C4DImporter.cpp

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2012, assimp team
+Copyright (c) 2006-2019, assimp team
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #endif
 
 #include "C4DImporter.h"
-#include "TinyFormatter.h"
+#include <assimp/TinyFormatter.h>
 #include <memory>
 #include <assimp/IOSystem.hpp>
 #include <assimp/scene.h>
@@ -68,8 +68,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace melange;
 
 // overload this function and fill in your own unique data
-void GetWriterInfo(int &id, String &appname)
-{
+void GetWriterInfo(int &id, String &appname) {
     id = 2424226;
     appname = "Open Asset Import Library";
 }
@@ -78,7 +77,10 @@ using namespace Assimp;
 using namespace Assimp::Formatter;
 
 namespace Assimp {
-    template<> const std::string LogFunctions<C4DImporter>::log_prefix = "C4D: ";
+    template<> const char* LogFunctions<C4DImporter>::Prefix() {
+        static auto prefix = "C4D: ";
+        return prefix;
+    }
 }
 
 static const aiImporterDesc desc = {
@@ -97,47 +99,44 @@ static const aiImporterDesc desc = {
 
 // ------------------------------------------------------------------------------------------------
 C4DImporter::C4DImporter()
-{}
+: BaseImporter() {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
-C4DImporter::~C4DImporter()
-{}
+C4DImporter::~C4DImporter() {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
-bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
-{
+bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
     const std::string& extension = GetExtension(pFile);
     if (extension == "c4d") {
         return true;
-    }
-
-    else if ((!extension.length() || checkSig) && pIOHandler)   {
+    } else if ((!extension.length() || checkSig) && pIOHandler)   {
         // TODO
     }
+
     return false;
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiImporterDesc* C4DImporter::GetInfo () const
-{
+const aiImporterDesc* C4DImporter::GetInfo () const {
     return &desc;
 }
 
 // ------------------------------------------------------------------------------------------------
-void C4DImporter::SetupProperties(const Importer* /*pImp*/)
-{
+void C4DImporter::SetupProperties(const Importer* /*pImp*/) {
     // nothing to be done for the moment
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
-void C4DImporter::InternReadFile( const std::string& pFile,
-    aiScene* pScene, IOSystem* pIOHandler)
-{
+void C4DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
     std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
 
-    if( file.get() == NULL) {
+    if( file.get() == nullptr ) {
         ThrowException("failed to open file " + pFile);
     }
 
@@ -151,7 +150,7 @@ void C4DImporter::InternReadFile( const std::string& pFile,
 
     // open document first
     BaseDocument* doc = LoadDocument(f, SCENEFILTER_OBJECTS | SCENEFILTER_MATERIALS);
-    if(doc == NULL) {
+    if(doc == nullptr ) {
         ThrowException("failed to read document " + pFile);
     }
 
@@ -160,11 +159,10 @@ void C4DImporter::InternReadFile( const std::string& pFile,
     // first convert all materials
     ReadMaterials(doc->GetFirstMaterial());
 
-    // process C4D scenegraph recursively
+    // process C4D scene-graph recursively
     try {
         RecurseHierarchy(doc->GetFirstObject(), pScene->mRootNode);
-    }
-    catch(...) {
+    } catch(...) {
         for(aiMesh* mesh : meshes) {
             delete mesh;
         }
@@ -185,11 +183,11 @@ void C4DImporter::InternReadFile( const std::string& pFile,
         if(mesh->mMaterialIndex >= mat_count) {
             ++mat_count;
 
-            ScopeGuard<aiMaterial> def_material(new aiMaterial());
+            std::unique_ptr<aiMaterial> def_material(new aiMaterial());
             const aiString name(AI_DEFAULT_MATERIAL_NAME);
             def_material->AddProperty(&name, AI_MATKEY_NAME);
 
-            materials.push_back(def_material.dismiss());
+            materials.push_back(def_material.release());
             break;
         }
     }
@@ -201,8 +199,7 @@ void C4DImporter::InternReadFile( const std::string& pFile,
 
 
 // ------------------------------------------------------------------------------------------------
-bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader)
-{
+bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader) {
     // based on Melange sample code (C4DImportExport.cpp)
     while(shader) {
         if(shader->GetType() == Xlayer) {
@@ -220,15 +217,12 @@ bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader)
             // Ignore the actual layer blending - models for real-time rendering should not
             // use them in a non-trivial way. Just try to find textures that we can apply
             // to the model.
-            while (lsl)
-            {
-                if (lsl->GetType() == TypeFolder)
-                {
+            while (lsl) {
+                if (lsl->GetType() == TypeFolder) {
                     BlendFolder* const folder = dynamic_cast<BlendFolder*>(lsl);
                     LayerShaderLayer *subLsl = dynamic_cast<LayerShaderLayer*>(folder->m_Children.GetObject(0));
 
-                    while (subLsl)
-                    {
+                    while (subLsl) {
                         if (subLsl->GetType() == TypeShader) {
                             BlendShader* const shader = dynamic_cast<BlendShader*>(subLsl);
                             if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
@@ -238,8 +232,7 @@ bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader)
 
                         subLsl = subLsl->GetNext();
                     }
-                }
-                else if (lsl->GetType() == TypeShader) {
+                } else if (lsl->GetType() == TypeShader) {
                     BlendShader* const shader = dynamic_cast<BlendShader*>(lsl);
                     if(ReadShader(out, static_cast<BaseShader*>(shader->m_pLink->GetLink()))) {
                         return true;
@@ -248,33 +241,27 @@ bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader)
 
                 lsl = lsl->GetNext();
             }
-        }
-        else if ( shader->GetType() == Xbitmap )
-        {
+        } else if ( shader->GetType() == Xbitmap ) {
             aiString path;
             shader->GetFileName().GetString().GetCString(path.data, MAXLEN-1);
             path.length = ::strlen(path.data);
             out->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0));
             return true;
-        }
-        else {
+        } else {
             LogWarn("ignoring shader type: " + std::string(GetObjectTypeName(shader->GetType())));
         }
         shader = shader->GetNext();
     }
+
     return false;
 }
 
-
 // ------------------------------------------------------------------------------------------------
-void C4DImporter::ReadMaterials(melange::BaseMaterial* mat)
-{
+void C4DImporter::ReadMaterials(melange::BaseMaterial* mat) {
     // based on Melange sample code
-    while (mat)
-    {
+    while (mat) {
         const String& name = mat->GetName();
-        if (mat->GetType() == Mmaterial)
-        {
+        if (mat->GetType() == Mmaterial) {
             aiMaterial* out = new aiMaterial();
             material_mapping[mat] = static_cast<unsigned int>(materials.size());
             materials.push_back(out);
@@ -286,8 +273,7 @@ void C4DImporter::ReadMaterials(melange::BaseMaterial* mat)
 
             Material& m = dynamic_cast<Material&>(*mat);
 
-            if (m.GetChannelState(CHANNEL_COLOR))
-            {
+            if (m.GetChannelState(CHANNEL_COLOR)) {
                 GeData data;
                 mat->GetParameter(MATERIAL_COLOR_COLOR, data);
                 Vector color = data.GetVector();
@@ -307,9 +293,7 @@ void C4DImporter::ReadMaterials(melange::BaseMaterial* mat)
             if(shader) {
                 ReadShader(out, shader);
             }
-        }
-        else
-        {
+        } else {
             LogWarn("ignoring plugin material: " + std::string(GetObjectTypeName(mat->GetType())));
         }
         mat = mat->GetNext();
@@ -317,14 +301,12 @@ void C4DImporter::ReadMaterials(melange::BaseMaterial* mat)
 }
 
 // ------------------------------------------------------------------------------------------------
-void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent)
-{
-    ai_assert(parent != NULL);
+void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) {
+    ai_assert(parent != nullptr );
     std::vector<aiNode*> nodes;
 
     // based on Melange sample code
-    while (object)
-    {
+    while (object) {
         const String& name = object->GetName();
         const LONG type = object->GetType();
         const Matrix& ml = object->GetMl();
@@ -356,26 +338,20 @@ void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent)
         nodes.push_back(nd);
 
         GeData data;
-        if (type == Ocamera)
-        {
+        if (type == Ocamera) {
             object->GetParameter(CAMERAOBJECT_FOV, data);
             // TODO: read camera
-        }
-        else if (type == Olight)
-        {
+        } else if (type == Olight) {
             // TODO: read light
-        }
-        else if (type == Opolygon)
-        {
+        } else if (type == Opolygon) {
             aiMesh* const mesh = ReadMesh(object);
-            if(mesh != NULL) {
+            if(mesh != nullptr) {
                 nd->mNumMeshes = 1;
                 nd->mMeshes = new unsigned int[1];
                 nd->mMeshes[0] = static_cast<unsigned int>(meshes.size());
                 meshes.push_back(mesh);
             }
-        }
-        else {
+        } else {
             LogWarn("ignoring object: " + std::string(GetObjectTypeName(type)));
         }
 
@@ -389,30 +365,29 @@ void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent)
     std::copy(nodes.begin(), nodes.end(), parent->mChildren);
 }
 
-
 // ------------------------------------------------------------------------------------------------
-aiMesh* C4DImporter::ReadMesh(BaseObject* object)
-{
-    assert(object != NULL && object->GetType() == Opolygon);
+aiMesh* C4DImporter::ReadMesh(BaseObject* object) {
+    ai_assert(object != nullptr);
+    ai_assert( object->GetType() == Opolygon );
 
     // based on Melange sample code
     PolygonObject* const polyObject = dynamic_cast<PolygonObject*>(object);
-    ai_assert(polyObject != NULL);
+    ai_assert(polyObject != nullptr);
 
     const LONG pointCount = polyObject->GetPointCount();
     const LONG polyCount = polyObject->GetPolygonCount();
     if(!polyObject || !pointCount) {
         LogWarn("ignoring mesh with zero vertices or faces");
-        return NULL;
+        return nullptr;
     }
 
     const Vector* points = polyObject->GetPointR();
-    ai_assert(points != NULL);
+    ai_assert(points != nullptr);
 
     const CPolygon* polys = polyObject->GetPolygonR();
-    ai_assert(polys != NULL);
+    ai_assert(polys != nullptr);
 
-    ScopeGuard<aiMesh> mesh(new aiMesh());
+    std::unique_ptr<aiMesh> mesh(new aiMesh());
     mesh->mNumFaces = static_cast<unsigned int>(polyCount);
     aiFace* face = mesh->mFaces = new aiFace[mesh->mNumFaces]();
 
@@ -443,14 +418,14 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object)
 
     // check if there are normals, tangents or UVW coordinates
     BaseTag* tag = object->GetTag(Tnormal);
-    NormalTag* normals_src = NULL;
+    NormalTag* normals_src = nullptr;
     if(tag) {
         normals_src = dynamic_cast<NormalTag*>(tag);
         normals = mesh->mNormals = new aiVector3D[mesh->mNumVertices]();
     }
 
     tag = object->GetTag(Ttangent);
-    TangentTag* tangents_src = NULL;
+    TangentTag* tangents_src = nullptr;
     if(tag) {
         tangents_src = dynamic_cast<TangentTag*>(tag);
         tangents = mesh->mTangents = new aiVector3D[mesh->mNumVertices]();
@@ -458,15 +433,14 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object)
     }
 
     tag = object->GetTag(Tuvw);
-    UVWTag* uvs_src = NULL;
+    UVWTag* uvs_src = nullptr;
     if(tag) {
         uvs_src = dynamic_cast<UVWTag*>(tag);
         uvs = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]();
     }
 
     // copy vertices and extra channels over and populate faces
-    for (LONG i = 0; i < polyCount; ++i, ++face)
-    {
+    for (LONG i = 0; i < polyCount; ++i, ++face) {
         ai_assert(polys[i].a < pointCount && polys[i].a >= 0);
         const Vector& pointA = points[polys[i].a];
         verts->x = pointA.x;
@@ -489,8 +463,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object)
         ++verts;
 
         // TODO: do we also need to handle lines or points with similar checks?
-        if (polys[i].c != polys[i].d)
-        {
+        if (polys[i].c != polys[i].d) {
             ai_assert(polys[i].d < pointCount && polys[i].d >= 0);
 
             face->mNumIndices = 4;
@@ -500,8 +473,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object)
             verts->y = pointD.y;
             verts->z = pointD.z;
             ++verts;
-        }
-        else {
+        } else {
             face->mNumIndices = 3;
         }
         face->mIndices = new unsigned int[face->mNumIndices];
@@ -513,8 +485,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object)
         if (normals_src) {
             if(i >= normals_src->GetDataCount()) {
                 LogError("unexpected number of normals, ignoring");
-            }
-            else {
+            } else {
                 ConstNormalHandle normal_handle = normals_src->GetDataAddressR();
                 NormalStruct nor;
                 NormalTag::Get(normal_handle, i, nor);
@@ -616,26 +587,25 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object)
     }
 
     mesh->mMaterialIndex = ResolveMaterial(polyObject);
-    return mesh.dismiss();
-}
 
+    return mesh.release();
+}
 
 // ------------------------------------------------------------------------------------------------
-unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj)
-{
-    ai_assert(obj != NULL);
+unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj) {
+    ai_assert(obj != nullptr);
 
     const unsigned int mat_count = static_cast<unsigned int>(materials.size());
 
     BaseTag* tag = obj->GetTag(Ttexture);
-    if(tag == NULL) {
+    if(tag == nullptr) {
         return mat_count;
     }
 
     TextureTag& ttag = dynamic_cast<TextureTag&>(*tag);
 
     BaseMaterial* const mat = ttag.GetMaterial();
-    assert(mat != NULL);
+    ai_assert(mat != nullptr);
 
     const MaterialMap::const_iterator it = material_mapping.find(mat);
     if(it == material_mapping.end()) {
@@ -643,6 +613,7 @@ unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj)
     }
 
     ai_assert((*it).second < mat_count);
+
     return (*it).second;
 }
 

+ 9 - 15
code/C4DImporter.h

@@ -2,7 +2,7 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2012, assimp team
+Copyright (c) 2006-2019, assimp team
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -44,10 +44,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_CINEMA_4D_LOADER_H
 #define INCLUDED_AI_CINEMA_4D_LOADER_H
 
-#include "BaseImporter.h"
-#include "LogAux.h"
+#include <assimp/BaseImporter.h>
+#include <assimp/LogAux.h>
 
-#include <set>
+#include <map>
+
+// Forward declarations
 struct aiNode;
 struct aiMesh;
 struct aiMaterial;
@@ -61,8 +63,7 @@ namespace melange {
     class BaseShader;
 }
 
-namespace Assimp    {
-
+namespace Assimp  {
     // TinyFormatter.h
     namespace Formatter {
         template <typename T,typename TR, typename A> class basic_formatter;
@@ -75,17 +76,10 @@ namespace Assimp    {
  *
  *  Note that Melange is not free software. */
 // -------------------------------------------------------------------------------------------
-class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter>
-{
+class C4DImporter : public BaseImporter, public LogFunctions<C4DImporter> {
 public:
-
     C4DImporter();
     ~C4DImporter();
-
-
-public:
-
-    // --------------------
     bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
         bool checkSig) const;
 
@@ -119,5 +113,5 @@ private:
 }; // !class C4DImporter
 
 } // end of namespace Assimp
-#endif // INCLUDED_AI_CINEMA_4D_LOADER_H
 
+#endif // INCLUDED_AI_CINEMA_4D_LOADER_H

+ 2 - 1
code/CInterfaceIOWrapper.cpp

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

+ 2 - 1
code/CInterfaceIOWrapper.h

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

+ 314 - 99
code/CMakeLists.txt

@@ -1,7 +1,8 @@
 # Open Asset Import Library (assimp)
 # ----------------------------------------------------------------------
 #
-# Copyright (c) 2006-2017, assimp team
+# Copyright (c) 2006-2019, assimp team
+
 
 # All rights reserved.
 #
@@ -46,6 +47,11 @@
 cmake_minimum_required( VERSION 2.6 )
 SET( HEADER_PATH ../include/assimp )
 
+if(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
+    message(WARNING "Requesting Android JNI I/O-System in non-Android toolchain. Resetting ASSIMP_ANDROID_JNIIOSYSTEM to OFF.")
+    set(ASSIMP_ANDROID_JNIIOSYSTEM OFF)
+endif(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
+
 SET( COMPILER_HEADERS
   ${HEADER_PATH}/Compiler/pushpack1.h
   ${HEADER_PATH}/Compiler/poppack1.h
@@ -61,6 +67,7 @@ SET( PUBLIC_HEADERS
   ${HEADER_PATH}/color4.inl
   ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h
   ${HEADER_PATH}/defs.h
+  ${HEADER_PATH}/Defines.h
   ${HEADER_PATH}/cfileio.h
   ${HEADER_PATH}/light.h
   ${HEADER_PATH}/material.h
@@ -70,6 +77,7 @@ SET( PUBLIC_HEADERS
   ${HEADER_PATH}/matrix4x4.h
   ${HEADER_PATH}/matrix4x4.inl
   ${HEADER_PATH}/mesh.h
+  ${HEADER_PATH}/pbrmaterial.h
   ${HEADER_PATH}/postprocess.h
   ${HEADER_PATH}/quaternion.h
   ${HEADER_PATH}/quaternion.inl
@@ -97,12 +105,50 @@ SET( PUBLIC_HEADERS
   ${HEADER_PATH}/DefaultIOStream.h
   ${HEADER_PATH}/DefaultIOSystem.h
   ${HEADER_PATH}/SceneCombiner.h
+  ${HEADER_PATH}/fast_atof.h
+  ${HEADER_PATH}/qnan.h
+  ${HEADER_PATH}/BaseImporter.h
+  ${HEADER_PATH}/Hash.h
+  ${HEADER_PATH}/MemoryIOWrapper.h
+  ${HEADER_PATH}/ParsingUtils.h
+  ${HEADER_PATH}/StreamReader.h
+  ${HEADER_PATH}/StreamWriter.h
+  ${HEADER_PATH}/StringComparison.h
+  ${HEADER_PATH}/StringUtils.h
+  ${HEADER_PATH}/SGSpatialSort.h
+  ${HEADER_PATH}/GenericProperty.h
+  ${HEADER_PATH}/SpatialSort.h
+  ${HEADER_PATH}/SkeletonMeshBuilder.h
+  ${HEADER_PATH}/SmoothingGroups.h
+  ${HEADER_PATH}/SmoothingGroups.inl
+  ${HEADER_PATH}/StandardShapes.h
+  ${HEADER_PATH}/RemoveComments.h
+  ${HEADER_PATH}/Subdivision.h
+  ${HEADER_PATH}/Vertex.h
+  ${HEADER_PATH}/LineSplitter.h
+  ${HEADER_PATH}/TinyFormatter.h
+  ${HEADER_PATH}/Profiler.h
+  ${HEADER_PATH}/LogAux.h
+  ${HEADER_PATH}/Bitmap.h
+  ${HEADER_PATH}/XMLTools.h
+  ${HEADER_PATH}/IOStreamBuffer.h
+  ${HEADER_PATH}/CreateAnimMesh.h
+  ${HEADER_PATH}/irrXMLWrapper.h
+  ${HEADER_PATH}/BlobIOSystem.h
+  ${HEADER_PATH}/MathFunctions.h
+  ${HEADER_PATH}/Macros.h
+  ${HEADER_PATH}/Exceptional.h
+  ${HEADER_PATH}/ByteSwapper.h
 )
 
 SET( Core_SRCS
   Assimp.cpp
 )
 
+IF(MSVC)
+  list(APPEND Core_SRCS "res/assimp.rc")
+ENDIF(MSVC)
+
 SET( Logging_SRCS
   ${HEADER_PATH}/DefaultLogger.hpp
   ${HEADER_PATH}/LogStream.hpp
@@ -116,70 +162,52 @@ SET( Logging_SRCS
 SOURCE_GROUP(Logging FILES ${Logging_SRCS})
 
 SET( Common_SRCS
-  fast_atof.h
-  qnan.h
   BaseImporter.cpp
-  BaseImporter.h
   BaseProcess.cpp
   BaseProcess.h
   Importer.h
   ScenePrivate.h
   PostStepRegistry.cpp
   ImporterRegistry.cpp
-  ByteSwapper.h
   DefaultProgressHandler.h
   DefaultIOStream.cpp
   DefaultIOSystem.cpp
   CInterfaceIOWrapper.cpp
   CInterfaceIOWrapper.h
-  Hash.h
   Importer.cpp
   IFF.h
-  MemoryIOWrapper.h
-  ParsingUtils.h
-  StreamReader.h
-  StreamWriter.h
-  StringComparison.h
-  StringUtils.h
   SGSpatialSort.cpp
-  SGSpatialSort.h
   VertexTriangleAdjacency.cpp
   VertexTriangleAdjacency.h
-  GenericProperty.h
   SpatialSort.cpp
-  SpatialSort.h
   SceneCombiner.cpp
   ScenePreprocessor.cpp
   ScenePreprocessor.h
   SkeletonMeshBuilder.cpp
-  SkeletonMeshBuilder.h
   SplitByBoneCountProcess.cpp
   SplitByBoneCountProcess.h
-  SmoothingGroups.h
   StandardShapes.cpp
-  StandardShapes.h
   TargetAnimation.cpp
   TargetAnimation.h
   RemoveComments.cpp
-  RemoveComments.h
   Subdivision.cpp
-  Subdivision.h
   scene.cpp
-  Vertex.h
-  LineSplitter.h
-  TinyFormatter.h
-  Profiler.h
-  LogAux.h
   Bitmap.cpp
-  Bitmap.h
-  XMLTools.h
   Version.cpp
-  IOStreamBuffer.h
-  CreateAnimMesh.h
   CreateAnimMesh.cpp
+  simd.h
+  simd.cpp
 )
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 
+SET( STEPParser_SRCS
+  Importer/STEPParser/STEPFileReader.h
+  Importer/STEPParser/STEPFileReader.cpp
+  Importer/STEPParser/STEPFileEncoding.cpp
+  Importer/STEPParser/STEPFileEncoding.h
+)
+SOURCE_GROUP(STEPParser FILES ${STEPParser_SRCS})
+
 IF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER )
   SET( C4D_SRCS
     C4DImporter.cpp
@@ -192,28 +220,67 @@ ENDIF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER )
 # ASSIMP_BUILD_XXX_IMPORTER to FALSE for each importer
 # if this variable is set to FALSE, the user can manually enable importers by setting
 # ASSIMP_BUILD_XXX_IMPORTER to TRUE for each importer
-OPTION(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_IMPORTER value" TRUE)
+OPTION(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_IMPORTER values" TRUE)
 
 # macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader
 # this way selective loaders can be compiled (reduces filesize + compile time)
 MACRO(ADD_ASSIMP_IMPORTER name)
-  OPTION(ASSIMP_BUILD_${name}_IMPORTER "build the ${name} importer" ${ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT})
-  IF(ASSIMP_BUILD_${name}_IMPORTER)
+  IF (ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT)
+    set(ASSIMP_IMPORTER_ENABLED TRUE)
+    IF (DEFINED ASSIMP_BUILD_${name}_IMPORTER AND NOT ASSIMP_BUILD_${name}_IMPORTER)
+      set(ASSIMP_IMPORTER_ENABLED FALSE)
+    ENDIF ()
+  ELSE ()
+    set(ASSIMP_IMPORTER_ENABLED ${ASSIMP_BUILD_${name}_IMPORTER})
+  ENDIF ()
+  IF (ASSIMP_IMPORTER_ENABLED)
     LIST(APPEND ASSIMP_LOADER_SRCS ${ARGN})
     SET(ASSIMP_IMPORTERS_ENABLED "${ASSIMP_IMPORTERS_ENABLED} ${name}")
-    SET(${name}_SRCS ${ARGN})
     SOURCE_GROUP(${name} FILES ${ARGN})
   ELSE()
     SET(${name}_SRC "")
     SET(ASSIMP_IMPORTERS_DISABLED "${ASSIMP_IMPORTERS_DISABLED} ${name}")
     add_definitions(-DASSIMP_BUILD_NO_${name}_IMPORTER)
+  ENDIF()
+ENDMACRO()
+
+# if this variable is set to TRUE, the user can manually disable exporters by setting
+# ASSIMP_BUILD_XXX_EXPORTER to FALSE for each exporter
+# if this variable is set to FALSE, the user can manually enable exporters by setting
+# ASSIMP_BUILD_XXX_EXPORTER to TRUE for each exporter
+OPTION(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_EXPORTER values" TRUE)
+
+# macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader
+# this way selective loaders can be compiled (reduces filesize + compile time)
+MACRO(ADD_ASSIMP_EXPORTER name)
+  IF (ASSIMP_NO_EXPORT)
+	set(ASSIMP_EXPORTER_ENABLED FALSE)
+  ELSEIF (ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT)
+    set(ASSIMP_EXPORTER_ENABLED TRUE)
+    IF (DEFINED ASSIMP_BUILD_${name}_EXPORTER AND NOT ASSIMP_BUILD_${name}_EXPORTER)
+      set(ASSIMP_EXPORTER_ENABLED FALSE)
+    ENDIF ()
+  ELSE ()
+    set(ASSIMP_EXPORTER_ENABLED ${ASSIMP_BUILD_${name}_EXPORTER})
+  ENDIF ()
+  
+  IF (ASSIMP_EXPORTER_ENABLED)
+    SET(ASSIMP_EXPORTERS_ENABLED "${ASSIMP_EXPORTERS_ENABLED} ${name}")
+	LIST(APPEND ASSIMP_EXPORTER_SRCS ${ARGN})
+    SOURCE_GROUP(${name}_EXPORTER FILES ${ARGN})
+  ELSE()
+    SET(ASSIMP_EXPORTERS_DISABLED "${ASSIMP_EXPORTERS_DISABLED} ${name}")
     add_definitions(-DASSIMP_BUILD_NO_${name}_EXPORTER)
   ENDIF()
 ENDMACRO()
 
 SET(ASSIMP_LOADER_SRCS "")
 SET(ASSIMP_IMPORTERS_ENABLED "") # list of enabled importers
-SET(ASSIMP_IMPORTERS_DISABLED "") # disabled list (used to print)
+SET(ASSIMP_IMPORTERS_DISABLED "") # disabled importers list (used to print)
+
+SET(ASSIMP_EXPORTER_SRCS "")
+SET(ASSIMP_EXPORTERS_ENABLED "") # list of enabled exporters
+SET(ASSIMP_EXPORTERS_DISABLED "") # disabled exporters list (used to print)
 
 ADD_ASSIMP_IMPORTER( AMF
   AMFImporter.hpp
@@ -230,6 +297,9 @@ ADD_ASSIMP_IMPORTER( 3DS
   3DSHelper.h
   3DSLoader.cpp
   3DSLoader.h
+)
+
+ADD_ASSIMP_EXPORTER( 3DS
   3DSExporter.h
   3DSExporter.cpp
 )
@@ -247,12 +317,15 @@ ADD_ASSIMP_IMPORTER( ASE
 )
 
 ADD_ASSIMP_IMPORTER( ASSBIN
-  AssbinExporter.h
-  AssbinExporter.cpp
   AssbinLoader.h
   AssbinLoader.cpp
 )
 
+ADD_ASSIMP_EXPORTER( ASSBIN
+  AssbinExporter.h
+  AssbinExporter.cpp
+)
+
 ADD_ASSIMP_IMPORTER( ASSXML
   AssxmlExporter.h
   AssxmlExporter.cpp
@@ -274,6 +347,9 @@ ADD_ASSIMP_IMPORTER( COLLADA
   ColladaLoader.h
   ColladaParser.cpp
   ColladaParser.h
+)
+
+ADD_ASSIMP_EXPORTER( COLLADA
   ColladaExporter.h
   ColladaExporter.cpp
 )
@@ -390,6 +466,9 @@ ADD_ASSIMP_IMPORTER( OBJ
   ObjFileParser.cpp
   ObjFileParser.h
   ObjTools.h
+)
+
+ADD_ASSIMP_EXPORTER( OBJ
   ObjExporter.h
   ObjExporter.cpp
 )
@@ -408,18 +487,24 @@ ADD_ASSIMP_IMPORTER( OGRE
 )
 
 ADD_ASSIMP_IMPORTER( OPENGEX
-  OpenGEXExporter.cpp
-  OpenGEXExporter.h
   OpenGEXImporter.cpp
   OpenGEXImporter.h
   OpenGEXStructs.h
 )
 
+ADD_ASSIMP_EXPORTER( OPENGEX
+  OpenGEXExporter.cpp
+  OpenGEXExporter.h
+)
+
 ADD_ASSIMP_IMPORTER( PLY
   PlyLoader.cpp
   PlyLoader.h
   PlyParser.cpp
   PlyParser.h
+)
+
+ADD_ASSIMP_EXPORTER( PLY
   PlyExporter.cpp
   PlyExporter.h
 )
@@ -451,33 +536,31 @@ ADD_ASSIMP_IMPORTER( BLEND
   BlenderBMesh.cpp
   BlenderTessellator.h
   BlenderTessellator.cpp
+  BlenderCustomData.h
+  BlenderCustomData.cpp
 )
 
 ADD_ASSIMP_IMPORTER( IFC
-  IFCLoader.cpp
-  IFCLoader.h
-  IFCReaderGen1.cpp
-  IFCReaderGen2.cpp
-  IFCReaderGen.h
-  IFCUtil.h
-  IFCUtil.cpp
-  IFCGeometry.cpp
-  IFCMaterial.cpp
-  IFCProfile.cpp
-  IFCCurve.cpp
-  IFCBoolean.cpp
-  IFCOpenings.cpp
-  STEPFile.h
-  STEPFileReader.h
-  STEPFileReader.cpp
-  STEPFileEncoding.cpp
-  STEPFileEncoding.h
+  Importer/IFC/IFCLoader.cpp
+  Importer/IFC/IFCLoader.h
+  Importer/IFC/IFCReaderGen1_2x3.cpp
+  Importer/IFC/IFCReaderGen2_2x3.cpp
+  Importer/IFC/IFCReaderGen_2x3.h
+  Importer/IFC/IFCUtil.h
+  Importer/IFC/IFCUtil.cpp
+  Importer/IFC/IFCGeometry.cpp
+  Importer/IFC/IFCMaterial.cpp
+  Importer/IFC/IFCProfile.cpp
+  Importer/IFC/IFCCurve.cpp
+  Importer/IFC/IFCBoolean.cpp
+  Importer/IFC/IFCOpenings.cpp
 )
+
 if (ASSIMP_BUILD_IFC_IMPORTER)
   if (MSVC)
-    set_source_files_properties(IFCReaderGen1.cpp IFCReaderGen2.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
+    set_source_files_properties(Importer/IFC/IFCReaderGen1_2x3.cpp Importer/IFC/IFCReaderGen2_2x3.cpp PROPERTIES COMPILE_FLAGS "/bigobj")
   elseif(CMAKE_COMPILER_IS_MINGW)
-    set_source_files_properties(IFCReaderGen1.cpp IFCReaderGen2.cpp PROPERTIES COMPILE_FLAGS "-O2 -Wa,-mbig-obj")
+    set_source_files_properties(Importer/IFC/IFCReaderGen1_2x3.cpp Importer/IFC/IFCReaderGen2_2x3.cpp PROPERTIES COMPILE_FLAGS "-O2 -Wa,-mbig-obj")
   endif()
 endif (ASSIMP_BUILD_IFC_IMPORTER)
 
@@ -486,7 +569,6 @@ ADD_ASSIMP_IMPORTER( XGL
   XGLLoader.h
 )
 
-
 ADD_ASSIMP_IMPORTER( FBX
   FBXImporter.cpp
   FBXCompileConfig.h
@@ -513,6 +595,16 @@ ADD_ASSIMP_IMPORTER( FBX
   FBXDeformer.cpp
   FBXBinaryTokenizer.cpp
   FBXDocumentUtil.cpp
+  FBXCommon.h
+)
+
+ADD_ASSIMP_EXPORTER( FBX
+  FBXExporter.h
+  FBXExporter.cpp
+  FBXExportNode.h
+  FBXExportNode.cpp
+  FBXExportProperty.h
+  FBXExportProperty.cpp
 )
 
 SET( PostProcessing_SRCS
@@ -522,6 +614,8 @@ SET( PostProcessing_SRCS
   ComputeUVMappingProcess.h
   ConvertToLHProcess.cpp
   ConvertToLHProcess.h
+  EmbedTexturesProcess.cpp
+  EmbedTexturesProcess.h
   FindDegenerates.cpp
   FindDegenerates.h
   FindInstancesProcess.cpp
@@ -530,6 +624,8 @@ SET( PostProcessing_SRCS
   FindInvalidDataProcess.h
   FixNormalsStep.cpp
   FixNormalsStep.h
+  DropFaceNormalsProcess.cpp
+  DropFaceNormalsProcess.h
   GenFaceNormalsProcess.cpp
   GenFaceNormalsProcess.h
   GenVertexNormalsProcess.cpp
@@ -567,10 +663,12 @@ SET( PostProcessing_SRCS
   PolyTools.h
   MakeVerboseFormat.cpp
   MakeVerboseFormat.h
+  ScaleProcess.cpp
+  ScaleProcess.h
 )
 SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS})
 
-SET( IrrXML_SRCS irrXMLWrapper.h )
+SET( IrrXML_SRCS ${HEADER_PATH}/irrXMLWrapper.h )
 SOURCE_GROUP( IrrXML FILES ${IrrXML_SRCS})
 
 ADD_ASSIMP_IMPORTER( Q3D
@@ -606,6 +704,9 @@ ADD_ASSIMP_IMPORTER( SMD
 ADD_ASSIMP_IMPORTER( STL
   STLLoader.cpp
   STLLoader.h
+)
+
+ADD_ASSIMP_EXPORTER( STL
   STLExporter.h
   STLExporter.cpp
 )
@@ -626,13 +727,14 @@ ADD_ASSIMP_IMPORTER( X
   XFileImporter.h
   XFileParser.cpp
   XFileParser.h
+)
+
+ADD_ASSIMP_EXPORTER( X
   XFileExporter.h
   XFileExporter.cpp
 )
 
-ADD_ASSIMP_IMPORTER(X3D
-  X3DExporter.cpp
-  X3DExporter.hpp
+ADD_ASSIMP_IMPORTER( X3D
   X3DImporter.cpp
   X3DImporter.hpp
   X3DImporter_Geometry2D.cpp
@@ -652,6 +754,11 @@ ADD_ASSIMP_IMPORTER(X3D
   X3DVocabulary.cpp
 )
 
+ADD_ASSIMP_EXPORTER( X3D
+  X3DExporter.cpp
+  X3DExporter.hpp
+)
+
 ADD_ASSIMP_IMPORTER( GLTF
   glTFAsset.h
   glTFAsset.inl
@@ -659,15 +766,32 @@ ADD_ASSIMP_IMPORTER( GLTF
   glTFAssetWriter.inl
   glTFImporter.cpp
   glTFImporter.h
+  glTF2Asset.h
+  glTF2Asset.inl
+  glTF2AssetWriter.h
+  glTF2AssetWriter.inl
+  glTF2Importer.cpp
+  glTF2Importer.h
+)
+
+ADD_ASSIMP_EXPORTER( GLTF
   glTFExporter.h
   glTFExporter.cpp
+  glTF2Exporter.h
+  glTF2Exporter.cpp
 )
 
 ADD_ASSIMP_IMPORTER( 3MF
-    D3MFImporter.h
+	D3MFImporter.h
     D3MFImporter.cpp
-    D3MFOpcPackage.h
+	D3MFOpcPackage.h
     D3MFOpcPackage.cpp
+    3MFXmlTags.h
+)
+
+ADD_ASSIMP_EXPORTER( 3MF
+    D3MFExporter.h
+    D3MFExporter.cpp
 )
 
 ADD_ASSIMP_IMPORTER( MMD
@@ -680,30 +804,52 @@ ADD_ASSIMP_IMPORTER( MMD
   MMDVmdParser.h
 )
 
-SET( Step_SRCS
-  StepExporter.h
-  StepExporter.cpp
+# Workaround for issue #2406 - force problematic large file to be optimized to prevent string table overflow error
+# Used -Os instead of -O2 as previous issues had mentioned, since -Os is roughly speaking -O2, excluding any
+# optimizations that take up extra space. Given that the issue is a string table overflowing, -Os seemed appropriate
+# Also, I'm not positive if both link & compile flags are needed, but this hopefully ensures that the issue should not
+# recur for edge cases such as static builds.
+if ((CMAKE_COMPILER_IS_MINGW) AND (CMAKE_BUILD_TYPE MATCHES Debug))
+  message("-- Applying MinGW StepFileGen1.cpp Debug Workaround")
+  SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES COMPILE_FLAGS -Os )
+  SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES LINK_FLAGS -Os )
+  SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES STATIC_LIBRARY_FLAGS -Os )
+endif()
+
+ADD_ASSIMP_IMPORTER( STEP
+    STEPFile.h
+    Importer/StepFile/StepFileImporter.h
+    Importer/StepFile/StepFileImporter.cpp
+    Importer/StepFile/StepFileGen1.cpp
+    Importer/StepFile/StepFileGen2.cpp
+    Importer/StepFile/StepFileGen3.cpp
+    Importer/StepFile/StepReaderGen.h
 )
-SOURCE_GROUP( Step FILES ${Step_SRCS})
 
-SET( Exporter_SRCS
-  Exporter.cpp
-  AssimpCExport.cpp
-  BlobIOSystem.h
+ADD_ASSIMP_EXPORTER( STEP
+    StepExporter.h
+    StepExporter.cpp
 )
-SOURCE_GROUP( Exporter FILES ${Exporter_SRCS})
+
+if ((NOT ASSIMP_NO_EXPORT) OR (NOT ASSIMP_EXPORTERS_ENABLED STREQUAL ""))
+	SET( Exporter_SRCS
+	  Exporter.cpp
+	  AssimpCExport.cpp
+	  ${HEADER_PATH}/BlobIOSystem.h
+	)
+	SOURCE_GROUP( Exporter FILES ${Exporter_SRCS})
+endif()
 
 SET( Extra_SRCS
   MD4FileData.h
 )
 SOURCE_GROUP( Extra FILES ${Extra_SRCS})
 
-
 SET( Clipper_SRCS
   ../contrib/clipper/clipper.hpp
   ../contrib/clipper/clipper.cpp
 )
-SOURCE_GROUP( Clipper FILES ${Clipper_SRCS})
+SOURCE_GROUP( Contrib\\Clipper FILES ${Clipper_SRCS})
 
 SET( Poly2Tri_SRCS
   ../contrib/poly2tri/poly2tri/common/shapes.cc
@@ -718,7 +864,7 @@ SET( Poly2Tri_SRCS
   ../contrib/poly2tri/poly2tri/sweep/sweep_context.cc
   ../contrib/poly2tri/poly2tri/sweep/sweep_context.h
 )
-SOURCE_GROUP( Poly2Tri FILES ${Poly2Tri_SRCS})
+SOURCE_GROUP( Contrib\\Poly2Tri FILES ${Poly2Tri_SRCS})
 
 SET( unzip_SRCS
   ../contrib/unzip/crypt.h
@@ -727,7 +873,22 @@ SET( unzip_SRCS
   ../contrib/unzip/unzip.c
   ../contrib/unzip/unzip.h
 )
-SOURCE_GROUP( unzip FILES ${unzip_SRCS})
+SOURCE_GROUP(Contrib\\unzip FILES ${unzip_SRCS})
+
+SET( ziplib_SRCS
+  ../contrib/zip/src/miniz.h
+  ../contrib/zip/src/zip.c
+  ../contrib/zip/src/zip.h
+)
+
+# TODO if cmake required version has been updated to >3.12.0, collapse this to the second case only
+if(${CMAKE_VERSION} VERSION_LESS "3.12.0")
+	add_definitions(-DMINIZ_USE_UNALIGNED_LOADS_AND_STORES=0)
+else()
+	add_compile_definitions(MINIZ_USE_UNALIGNED_LOADS_AND_STORES=0)
+endif()
+
+SOURCE_GROUP( ziplib FILES ${ziplib_SRCS} )
 
 SET ( openddl_parser_SRCS
   ../contrib/openddlparser/code/OpenDDLParser.cpp
@@ -744,7 +905,7 @@ SET ( openddl_parser_SRCS
   ../contrib/openddlparser/include/openddlparser/DDLNode.h
   ../contrib/openddlparser/include/openddlparser/Value.h
 )
-SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS})
+SOURCE_GROUP( Contrib\\openddl_parser FILES ${openddl_parser_SRCS})
 
 SET ( open3dgc_SRCS
   ../contrib/Open3DGC/o3dgcAdjacencyInfo.h
@@ -777,7 +938,7 @@ SET ( open3dgc_SRCS
   ../contrib/Open3DGC/o3dgcVector.h
   ../contrib/Open3DGC/o3dgcVector.inl
 )
-SOURCE_GROUP( open3dgc FILES ${open3dgc_SRCS})
+SOURCE_GROUP( Contrib\\open3dgc FILES ${open3dgc_SRCS})
 
 # Check dependencies for glTF importer with Open3DGC-compression.
 # RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file
@@ -817,8 +978,11 @@ else (UNZIP_FOUND)
   INCLUDE_DIRECTORIES( "../contrib/unzip/" )
 endif (UNZIP_FOUND)
 
-MESSAGE(STATUS "Enabled formats:${ASSIMP_IMPORTERS_ENABLED}")
-MESSAGE(STATUS "Disabled formats:${ASSIMP_IMPORTERS_DISABLED}")
+MESSAGE(STATUS "Enabled importer formats:${ASSIMP_IMPORTERS_ENABLED}")
+MESSAGE(STATUS "Disabled importer formats:${ASSIMP_IMPORTERS_DISABLED}")
+
+MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}")
+MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}")
 
 SET( assimp_src
   # Assimp Files
@@ -828,10 +992,12 @@ SET( assimp_src
   ${Exporter_SRCS}
   ${PostProcessing_SRCS}
   ${MaterialSystem_SRCS}
-  ${Step_SRCS}
+  ${STEPParser_SRCS}
+#  ${Step_SRCS} check if we need a different approach
 
   # Model Support
   ${ASSIMP_LOADER_SRCS}
+  ${ASSIMP_EXPORTER_SRCS}
 
   # Third-party libraries
   ${IrrXML_SRCS}
@@ -840,11 +1006,11 @@ SET( assimp_src
   ${Clipper_SRCS}
   ${openddl_parser_SRCS}
   ${open3dgc_SRCS}
+  ${ziplib_SRCS}
   # Necessary to show the headers in the project when using the VC++ generator:
 
   ${PUBLIC_HEADERS}
   ${COMPILER_HEADERS}
-
 )
 ADD_DEFINITIONS( -DOPENDDLPARSER_BUILD )
 
@@ -859,14 +1025,21 @@ IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
 ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
 
 ADD_LIBRARY( assimp ${assimp_src} )
+ADD_LIBRARY(assimp::assimp ALIAS assimp)
+
+TARGET_INCLUDE_DIRECTORIES ( assimp PUBLIC
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/../include>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
+)
 
 TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ${IRRXML_LIBRARY} )
 
-if(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
+if(ASSIMP_ANDROID_JNIIOSYSTEM)
   set(ASSIMP_ANDROID_JNIIOSYSTEM_PATH port/AndroidJNI)
   add_subdirectory(../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/ ../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/)
   target_link_libraries(assimp android_jniiosystem)
-endif(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)
+endif(ASSIMP_ANDROID_JNIIOSYSTEM)
 
 IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
   TARGET_LINK_LIBRARIES(assimp optimized ${C4D_RELEASE_LIBRARIES})
@@ -876,6 +1049,10 @@ ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
 
 if( MSVC )
   # in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix
+  # CMake 3.12 added a variable for this
+  if(MSVC_TOOLSET_VERSION)
+    set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}")
+  else()
   if( MSVC70 OR MSVC71 )
     set(MSVC_PREFIX "vc70")
   elseif( MSVC80 )
@@ -890,12 +1067,18 @@ if( MSVC )
     set(MSVC_PREFIX "vc120")
   elseif( MSVC14 )
     set(MSVC_PREFIX "vc140")
+  elseif( MSVC15 )
+    set(MSVC_PREFIX "vc141")
   else()
     set(MSVC_PREFIX "vc150")
   endif()
+  endif()
   set(LIBRARY_SUFFIX "${ASSIMP_LIBRARY_SUFFIX}-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library")
 endif()
 
+if (${CMAKE_SYSTEM_NAME} MATCHES "WindowsStore")
+    set(WindowsStore TRUE)
+endif()
 SET_TARGET_PROPERTIES( assimp PROPERTIES
   VERSION ${ASSIMP_VERSION}
   SOVERSION ${ASSIMP_SOVERSION} # use full version
@@ -903,8 +1086,27 @@ SET_TARGET_PROPERTIES( assimp PROPERTIES
 )
 
 if (APPLE)
-  SET_TARGET_PROPERTIES( assimp PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR}")
-endif()
+  SET_TARGET_PROPERTIES( assimp PROPERTIES
+    INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${ASSIMP_LIB_INSTALL_DIR}"
+  )
+
+  if (BUILD_FRAMEWORK)
+    SET_TARGET_PROPERTIES( assimp PROPERTIES
+      FRAMEWORK TRUE
+      FRAMEWORK_VERSION C
+      MACOSX_FRAMEWORK_IDENTIFIER net.sf.assimp
+      PUBLIC_HEADER "${PUBLIC_HEADERS}"
+    )
+
+    # PUBLIC_HEADER option does not support directory structure creation
+    # add ./Compiler/*.h to assimp.framework via copy command
+    ADD_CUSTOM_COMMAND(TARGET assimp POST_BUILD
+      COMMAND "${CMAKE_COMMAND}" -E copy_directory
+         "../${HEADER_PATH}/Compiler"
+         assimp.framework/Headers/Compiler
+      COMMENT "Copying public ./Compiler/ header files to framework bundle's Headers/Compiler/")
+  ENDIF(BUILD_FRAMEWORK)
+ENDIF(APPLE)
 
 # Build against external unzip, or add ../contrib/unzip so
 # assimp can #include "unzip.h"
@@ -924,25 +1126,38 @@ INSTALL( TARGETS assimp
   LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR}
+  FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   COMPONENT ${LIBASSIMP_COMPONENT})
 INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)
 INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev)
+
 if (ASSIMP_ANDROID_JNIIOSYSTEM)
   INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h
     DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
     COMPONENT assimp-dev)
-endif(ASSIMP_ANDROID_JNIIOSYSTEM)
+ENDIF(ASSIMP_ANDROID_JNIIOSYSTEM)
 
 if(MSVC AND ASSIMP_INSTALL_PDB)
-  install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
-    DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
-    CONFIGURATIONS Debug
-  )
-  install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp${LIBRARY_SUFFIX}.pdb
-    DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
-    CONFIGURATIONS RelWithDebInfo
-  )
-endif ()
+  IF(CMAKE_GENERATOR MATCHES "^Visual Studio")
+    install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
+      DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
+      CONFIGURATIONS Debug
+    )
+    install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp${LIBRARY_SUFFIX}.pdb
+      DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
+      CONFIGURATIONS RelWithDebInfo
+    )
+  ELSE()
+    install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb
+      DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
+      CONFIGURATIONS Debug
+    )
+    install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}.pdb
+      DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
+      CONFIGURATIONS RelWithDebInfo
+    )
+  ENDIF()
+ENDIF ()
 
 if (ASSIMP_COVERALLS)
     include(Coveralls)
@@ -954,4 +1169,4 @@ if (ASSIMP_COVERALLS)
         "${COVERAGE_SRCS}" # The source files.
         ON                 # If we should upload.
         "${PROJECT_SOURCE_DIR}/cmake-modules/") # (Optional) Alternate project cmake module path.
-endif()
+ENDIF()

+ 41 - 93
code/COBLoader.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -46,13 +47,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_COB_IMPORTER
 #include "COBLoader.h"
 #include "COBScene.h"
-
-#include "StreamReader.h"
-#include "ParsingUtils.h"
-#include "fast_atof.h"
-
-#include "LineSplitter.h"
-#include "TinyFormatter.h"
+#include "ConvertToLHProcess.h"
+#include <assimp/StreamReader.h>
+#include <assimp/ParsingUtils.h>
+#include <assimp/fast_atof.h>
+#include <assimp/LineSplitter.h>
+#include <assimp/TinyFormatter.h>
 #include <memory>
 #include <assimp/IOSystem.hpp>
 #include <assimp/DefaultLogger.hpp>
@@ -104,7 +104,7 @@ COBImporter::~COBImporter()
 bool COBImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
 {
     const std::string& extension = GetExtension(pFile);
-    if (extension == "cob" || extension == "scn") {
+    if (extension == "cob" || extension == "scn" || extension == "COB" || extension == "SCN") {
         return true;
     }
 
@@ -137,20 +137,18 @@ void COBImporter::SetupProperties(const Importer* /*pImp*/)
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
-void COBImporter::InternReadFile( const std::string& pFile,
-    aiScene* pScene, IOSystem* pIOHandler)
-{
+void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
     COB::Scene scene;
     std::unique_ptr<StreamReaderLE> stream(new StreamReaderLE( pIOHandler->Open(pFile,"rb")) );
 
     // check header
     char head[32];
     stream->CopyAndAdvance(head,32);
-    if (strncmp(head,"Caligari ",9)) {
+    if (strncmp(head,"Caligari ",9) != 0) {
         ThrowException("Could not found magic id: `Caligari`");
     }
 
-    DefaultLogger::get()->info("File format tag: "+std::string(head+9,6));
+    ASSIMP_LOG_INFO_F("File format tag: ",std::string(head+9,6));
     if (head[16]!='L') {
         ThrowException("File is big-endian, which is not supported");
     }
@@ -224,6 +222,9 @@ void COBImporter::InternReadFile( const std::string& pFile,
     }
 
     pScene->mRootNode = BuildNodes(*root.get(),scene,pScene);
+	//flip normals after import
+    FlipWindingOrderProcess flip;
+    flip.Execute( pScene );
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -300,7 +301,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
                     }
                     std::unique_ptr<const Material> defmat;
                     if(!min) {
-                        DefaultLogger::get()->debug(format()<<"Could not resolve material index "
+                        ASSIMP_LOG_DEBUG(format()<<"Could not resolve material index "
                             <<reflist.first<<" - creating default material for this slot");
 
                         defmat.reset(min=new Material());
@@ -472,7 +473,7 @@ void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo
 
     // we can recover if the chunk size was specified.
     if(nfo.size != static_cast<unsigned int>(-1)) {
-        DefaultLogger::get()->error(error);
+        ASSIMP_LOG_ERROR(error);
 
         // (HACK) - our current position in the stream is the beginning of the
         // head line of the next chunk. That's fine, but the caller is going
@@ -484,46 +485,6 @@ void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo
     else ThrowException(error);
 }
 
-// ------------------------------------------------------------------------------------------------
-void COBImporter::LogWarn_Ascii(const LineSplitter& splitter, const format& message)    {
-    LogWarn_Ascii(message << " [at line "<< splitter.get_index()<<"]");
-}
-
-// ------------------------------------------------------------------------------------------------
-void COBImporter::LogError_Ascii(const LineSplitter& splitter, const format& message)   {
-    LogError_Ascii(message << " [at line "<< splitter.get_index()<<"]");
-}
-
-// ------------------------------------------------------------------------------------------------
-void COBImporter::LogInfo_Ascii(const LineSplitter& splitter, const format& message)    {
-    LogInfo_Ascii(message << " [at line "<< splitter.get_index()<<"]");
-}
-
-// ------------------------------------------------------------------------------------------------
-void COBImporter::LogDebug_Ascii(const LineSplitter& splitter, const format& message)   {
-    LogDebug_Ascii(message << " [at line "<< splitter.get_index()<<"]");
-}
-
-// ------------------------------------------------------------------------------------------------
-void COBImporter::LogWarn_Ascii(const Formatter::format& message)   {
-    DefaultLogger::get()->warn(std::string("COB: ")+=message);
-}
-
-// ------------------------------------------------------------------------------------------------
-void COBImporter::LogError_Ascii(const Formatter::format& message)  {
-    DefaultLogger::get()->error(std::string("COB: ")+=message);
-}
-
-// ------------------------------------------------------------------------------------------------
-void COBImporter::LogInfo_Ascii(const Formatter::format& message)   {
-    DefaultLogger::get()->info(std::string("COB: ")+=message);
-}
-
-// ------------------------------------------------------------------------------------------------
-void COBImporter::LogDebug_Ascii(const Formatter::format& message)  {
-    DefaultLogger::get()->debug(std::string("COB: ")+=message);
-}
-
 // ------------------------------------------------------------------------------------------------
 void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& /*nfo*/)
 {
@@ -573,8 +534,7 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
 
     ++splitter;
     if (!splitter.match_start("mat# ")) {
-        LogWarn_Ascii(splitter,format()<<
-            "Expected `mat#` line in `Mat1` chunk "<<nfo.id);
+        ASSIMP_LOG_WARN_F( "Expected `mat#` line in `Mat1` chunk ", nfo.id );
         return;
     }
 
@@ -586,8 +546,7 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
     ++splitter;
 
     if (!splitter.match_start("shader: ")) {
-        LogWarn_Ascii(splitter,format()<<
-            "Expected `mat#` line in `Mat1` chunk "<<nfo.id);
+        ASSIMP_LOG_WARN_F( "Expected `mat#` line in `Mat1` chunk ", nfo.id);
         return;
     }
     std::string shader = std::string(splitter[1]);
@@ -600,14 +559,12 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
         mat.shader = Material::PHONG;
     }
     else if (shader != "flat") {
-        LogWarn_Ascii(splitter,format()<<
-            "Unknown value for `shader` in `Mat1` chunk "<<nfo.id);
+        ASSIMP_LOG_WARN_F( "Unknown value for `shader` in `Mat1` chunk ", nfo.id );
     }
 
     ++splitter;
     if (!splitter.match_start("rgb ")) {
-        LogWarn_Ascii(splitter,format()<<
-            "Expected `rgb` line in `Mat1` chunk "<<nfo.id);
+        ASSIMP_LOG_WARN_F( "Expected `rgb` line in `Mat1` chunk ", nfo.id);
     }
 
     const char* rgb = splitter[1];
@@ -615,8 +572,7 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
 
     ++splitter;
     if (!splitter.match_start("alpha ")) {
-        LogWarn_Ascii(splitter,format()<<
-            "Expected `alpha` line in `Mat1` chunk "<<nfo.id);
+        ASSIMP_LOG_WARN_F( "Expected `alpha` line in `Mat1` chunk ", nfo.id);
     }
 
     const char* tokens[10];
@@ -637,8 +593,7 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
     }
     ++splitter;
     if (!splitter.match_start("Units ")) {
-        LogWarn_Ascii(splitter,format()<<
-            "Expected `Units` line in `Unit` chunk "<<nfo.id);
+        ASSIMP_LOG_WARN_F( "Expected `Units` line in `Unit` chunk ", nfo.id);
         return;
     }
 
@@ -649,13 +604,12 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
             const unsigned int t=strtoul10(splitter[1]);
 
             nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?(
-                LogWarn_Ascii(splitter,format()<<t<<" is not a valid value for `Units` attribute in `Unit chunk` "<<nfo.id)
+                ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
                 ,1.f):units[t];
             return;
         }
     }
-    LogWarn_Ascii(splitter,format()<<"`Unit` chunk "<<nfo.id<<" is a child of "
-        <<nfo.parent_id<<" which does not exist");
+    ASSIMP_LOG_WARN_F( "`Unit` chunk ", nfo.id, " is a child of ", nfo.parent_id, " which does not exist");
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -689,32 +643,28 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk
         msh.ltype = Light::SPOT;
     }
     else {
-        LogWarn_Ascii(splitter,format()<<
-            "Unknown kind of light source in `Lght` chunk "<<nfo.id<<" : "<<*splitter);
+        ASSIMP_LOG_WARN_F( "Unknown kind of light source in `Lght` chunk ", nfo.id, " : ", *splitter );
         msh.ltype = Light::SPOT;
     }
 
     ++splitter;
     if (!splitter.match_start("color ")) {
-        LogWarn_Ascii(splitter,format()<<
-            "Expected `color` line in `Lght` chunk "<<nfo.id);
+        ASSIMP_LOG_WARN_F( "Expected `color` line in `Lght` chunk ", nfo.id );
     }
 
     const char* rgb = splitter[1];
     ReadFloat3Tuple_Ascii(msh.color ,&rgb);
 
     SkipSpaces(&rgb);
-    if (strncmp(rgb,"cone angle",10)) {
-        LogWarn_Ascii(splitter,format()<<
-            "Expected `cone angle` entity in `color` line in `Lght` chunk "<<nfo.id);
+    if (strncmp(rgb,"cone angle",10) != 0) {
+        ASSIMP_LOG_WARN_F( "Expected `cone angle` entity in `color` line in `Lght` chunk ", nfo.id );
     }
     SkipSpaces(rgb+10,&rgb);
     msh.angle = fast_atof(&rgb);
 
     SkipSpaces(&rgb);
-    if (strncmp(rgb,"inner angle",11)) {
-        LogWarn_Ascii(splitter,format()<<
-            "Expected `inner angle` entity in `color` line in `Lght` chunk "<<nfo.id);
+    if (strncmp(rgb,"inner angle",11) != 0) {
+        ASSIMP_LOG_WARN_F( "Expected `inner angle` entity in `color` line in `Lght` chunk ", nfo.id);
     }
     SkipSpaces(rgb+11,&rgb);
     msh.inner_angle = fast_atof(&rgb);
@@ -825,7 +775,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
 
             for(unsigned int cur = 0; cur < cnt && ++splitter ;++cur) {
                 if (splitter.match_start("Hole")) {
-                    LogWarn_Ascii(splitter,"Skipping unsupported `Hole` line");
+                    ASSIMP_LOG_WARN( "Skipping unsupported `Hole` line" );
                     continue;
                 }
 
@@ -885,7 +835,7 @@ void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const C
 
     const unsigned int head = strtoul10((++splitter)[1]);
     if (head != sizeof(Bitmap::BitmapHeader)) {
-        LogWarn_Ascii(splitter,"Unexpected ThumbNailHdrSize, skipping this chunk");
+        ASSIMP_LOG_WARN("Unexpected ThumbNailHdrSize, skipping this chunk");
         return;
     }
 
@@ -932,7 +882,7 @@ void COBImporter::UnsupportedChunk_Binary( StreamReaderLE& reader, const ChunkIn
 
     // we can recover if the chunk size was specified.
     if(nfo.size != static_cast<unsigned int>(-1)) {
-        DefaultLogger::get()->error(error);
+        ASSIMP_LOG_ERROR(error);
         reader.IncPtr(nfo.size);
     }
     else ThrowException(error);
@@ -953,7 +903,7 @@ public:
         if(nfo.size != static_cast<unsigned int>(-1)) {
             try {
                 reader.IncPtr( static_cast< int >( nfo.size ) - reader.GetCurrentPos() + cur );
-            } catch ( DeadlyImportError e ) {
+            } catch (const DeadlyImportError& e ) {
                 // out of limit so correct the value
                 reader.IncPtr( reader.GetReadLimit() );
             }
@@ -1139,7 +1089,7 @@ void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const
             mat.type = Material::METAL;
             break;
         default:
-            LogError_Ascii(format("Unrecognized shader type in `Mat1` chunk with id ")<<nfo.id);
+            ASSIMP_LOG_ERROR_F( "Unrecognized shader type in `Mat1` chunk with id ", nfo.id );
             mat.type = Material::FLAT;
     }
 
@@ -1154,7 +1104,7 @@ void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const
             mat.autofacet = Material::SMOOTH;
             break;
         default:
-            LogError_Ascii(format("Unrecognized faceting mode in `Mat1` chunk with id ")<<nfo.id);
+            ASSIMP_LOG_ERROR_F( "Unrecognized faceting mode in `Mat1` chunk with id ", nfo.id );
             mat.autofacet = Material::FACETED;
     }
     mat.autofacet_angle = static_cast<float>(reader.GetI1());
@@ -1264,7 +1214,7 @@ void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const
 
     const chunk_guard cn(nfo,reader);
 
-    out.nodes.push_back(std::shared_ptr<Group>(new Group()));
+    out.nodes.push_back(std::make_shared<Group>());
     Group& msh = (Group&)(*out.nodes.back().get());
     msh = nfo;
 
@@ -1286,15 +1236,13 @@ void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const
         if (nd->id == nfo.parent_id) {
             const unsigned int t=reader.GetI2();
             nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?(
-                LogWarn_Ascii(format()<<t<<" is not a valid value for `Units` attribute in `Unit chunk` "<<nfo.id)
+                ASSIMP_LOG_WARN_F(t," is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
                 ,1.f):units[t];
 
             return;
         }
     }
-    LogWarn_Ascii(format()<<"`Unit` chunk "<<nfo.id<<" is a child of "
-        <<nfo.parent_id<<" which does not exist");
+    ASSIMP_LOG_WARN_F( "`Unit` chunk ", nfo.id, " is a child of ", nfo.parent_id, " which does not exist");
 }
 
-
-#endif
+#endif // ASSIMP_BUILD_NO_COB_IMPORTER

+ 5 - 24
code/COBLoader.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -45,8 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_COB_LOADER_H
 #define INCLUDED_AI_COB_LOADER_H
 
-#include "BaseImporter.h"
-#include "StreamReader.h"
+#include <assimp/BaseImporter.h>
+#include <assimp/StreamReader.h>
 
 struct aiNode;
 
@@ -76,10 +77,7 @@ class COBImporter : public BaseImporter
 public:
     COBImporter();
     ~COBImporter();
-
-
-public:
-
+    
     // --------------------
     bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
         bool checkSig) const;
@@ -114,15 +112,11 @@ private:
      *  @param stream Stream to read from.  */
     void ReadBinaryFile(COB::Scene& out, StreamReaderLE* stream);
 
-
-private:
-
     // Conversion to Assimp output format
 
     aiNode* BuildNodes(const COB::Node& root,const COB::Scene& scin,aiScene* fill);
 
 private:
-
     // ASCII file support
 
     void UnsupportedChunk_Ascii(LineSplitter& splitter, const COB::ChunkInfo& nfo, const char* name);
@@ -141,19 +135,6 @@ private:
     void ReadChan_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
 
 
-    // ASCII file logging stuff to add proper line numbers to messages
-
-    static void LogWarn_Ascii (const LineSplitter& splitter, const Formatter::format& message);
-    static void LogError_Ascii(const LineSplitter& splitter, const Formatter::format& message);
-    static void LogInfo_Ascii (const LineSplitter& splitter, const Formatter::format& message);
-    static void LogDebug_Ascii(const LineSplitter& splitter, const Formatter::format& message);
-
-    static void LogWarn_Ascii  (const Formatter::format& message);
-    static void LogError_Ascii (const Formatter::format& message);
-    static void LogInfo_Ascii  (const Formatter::format& message);
-    static void LogDebug_Ascii (const Formatter::format& message);
-
-
     // Binary file support
 
     void UnsupportedChunk_Binary(StreamReaderLE& reader, const COB::ChunkInfo& nfo, const char* name);

+ 3 - 2
code/COBScene.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -49,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <deque>
 #include <map>
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 #include <assimp/material.h>
 
 namespace Assimp {

+ 8 - 7
code/CSMLoader.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -49,9 +50,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_CSM_IMPORTER
 
 #include "CSMLoader.h"
-#include "SkeletonMeshBuilder.h"
-#include "ParsingUtils.h"
-#include "fast_atof.h"
+#include <assimp/SkeletonMeshBuilder.h>
+#include <assimp/ParsingUtils.h>
+#include <assimp/fast_atof.h>
 #include <assimp/Importer.hpp>
 #include <memory>
 #include <assimp/IOSystem.hpp>
@@ -135,7 +136,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
     TextFileToBuffer(file.get(),mBuffer2);
     const char* buffer = &mBuffer2[0];
 
-    aiAnimation* anim = new aiAnimation();
+    std::unique_ptr<aiAnimation> anim(new aiAnimation());
     int first = 0, last = 0x00ffffff;
 
     // now process the file and look out for '$' sections
@@ -232,7 +233,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
 
                         if (TokenMatchI(buffer, "DROPOUT", 7))  {
                             // seems this is invalid marker data; at least the doc says it's possible
-                            DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)");
+                            ASSIMP_LOG_WARN("CSM: Encountered invalid marker data (DROPOUT)");
                         }
                         else    {
                             aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;
@@ -293,8 +294,8 @@ void CSMImporter::InternReadFile( const std::string& pFile,
 
     // Store the one and only animation in the scene
     pScene->mAnimations    = new aiAnimation*[pScene->mNumAnimations=1];
-    pScene->mAnimations[0] = anim;
     anim->mName.Set("$CSM_MasterAnim");
+    pScene->mAnimations[0] = anim.release();
 
     // mark the scene as incomplete and run SkeletonMeshBuilder on it
     pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;

+ 3 - 2
code/CSMLoader.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -45,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_CSM_LOADER_H
 #define INCLUDED_AI_CSM_LOADER_H
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 
 namespace Assimp    {
 

+ 11 - 10
code/CalcTangentsProcess.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -47,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // internal headers
 #include "CalcTangentsProcess.h"
 #include "ProcessHelper.h"
-#include "TinyFormatter.h"
-#include "qnan.h"
+#include <assimp/TinyFormatter.h>
+#include <assimp/qnan.h>
 
 using namespace Assimp;
 
@@ -94,7 +95,7 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
 {
     ai_assert( NULL != pScene );
 
-    DefaultLogger::get()->debug("CalcTangentsProcess begin");
+    ASSIMP_LOG_DEBUG("CalcTangentsProcess begin");
 
     bool bHas = false;
     for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
@@ -102,9 +103,9 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
     }
 
     if ( bHas ) {
-        DefaultLogger::get()->info("CalcTangentsProcess finished. Tangents have been calculated");
+        ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated");
     } else {
-        DefaultLogger::get()->debug("CalcTangentsProcess finished");
+        ASSIMP_LOG_DEBUG("CalcTangentsProcess finished");
     }
 }
 
@@ -125,19 +126,19 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
     // are undefined.
     if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
     {
-        DefaultLogger::get()->info("Tangents are undefined for line and point meshes");
+        ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes");
         return false;
     }
 
     // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
     if( pMesh->mNormals == NULL)
     {
-        DefaultLogger::get()->error("Failed to compute tangents; need normals");
+        ASSIMP_LOG_ERROR("Failed to compute tangents; need normals");
         return false;
     }
     if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] )
     {
-        DefaultLogger::get()->error((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
+        ASSIMP_LOG_ERROR((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
         return false;
     }
 
@@ -189,7 +190,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
         float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
         float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
         // when t1, t2, t3 in same position in UV space, just use default UV direction.
-        if ( 0 == sx && 0 ==sy && 0 == tx && 0 == ty ) {
+        if (  sx * ty == sy * tx ) {
             sx = 0.0; sy = 1.0;
             tx = 1.0; ty = 0.0;
         }

+ 2 - 1
code/CalcTangentsProcess.h

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

+ 328 - 31
code/ColladaExporter.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -43,17 +44,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
 
 #include "ColladaExporter.h"
-#include "Bitmap.h"
-#include "fast_atof.h"
+#include <assimp/Bitmap.h>
+#include <assimp/fast_atof.h>
 #include <assimp/SceneCombiner.h>
-#include "StringUtils.h"
-#include "XMLTools.h"
+#include <assimp/StringUtils.h>
+#include <assimp/XMLTools.h>
 #include <assimp/DefaultIOSystem.h>
 #include <assimp/IOSystem.hpp>
 #include <assimp/Exporter.hpp>
 #include <assimp/scene.h>
 
-#include "Exceptional.h"
+#include <assimp/Exceptional.h>
 
 #include <memory>
 #include <ctime>
@@ -68,13 +69,17 @@ namespace Assimp
 
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
-void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
+void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
 {
     std::string path = DefaultIOSystem::absolutePath(std::string(pFile));
     std::string file = DefaultIOSystem::completeBaseName(std::string(pFile));
 
     // invoke the exporter
     ColladaExporter iDoTheExportThing( pScene, pIOSystem, path, file);
+    
+    if (iDoTheExportThing.mOutput.fail()) {
+        throw DeadlyExportError("output data creation failed. Most likely the file became too large: " + std::string(pFile));
+    }
 
     // we're still here - export successfully completed. Write result to the given IOSYstem
     std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
@@ -104,7 +109,7 @@ ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, co
     // set up strings
     endstr = "\n";
 
-    // start writing
+    // start writing the file
     WriteFile();
 }
 
@@ -137,6 +142,9 @@ void ColladaExporter::WriteFile()
     WriteControllerLibrary();
 
     WriteSceneLibrary();
+	
+	// customized, Writes the animation library
+	WriteAnimationsLibrary();
 
     // useless Collada fu at the end, just in case we haven't had enough indirections, yet.
     mOutput << startstr << "<scene>" << endstr;
@@ -230,7 +238,11 @@ void ColladaExporter::WriteHeader()
     mOutput << startstr << "<contributor>" << endstr;
     PushTag();
 
-    aiMetadata* meta = mScene->mRootNode->mMetaData;
+    // If no Scene metadata, use root node metadata
+    aiMetadata* meta = mScene->mMetaData;
+    if (!meta)
+        meta = mScene->mRootNode->mMetaData;
+
     aiString value;
     if (!meta || !meta->Get("Author", value))
         mOutput << startstr << "<author>" << "Assimp" << "</author>" << endstr;
@@ -242,13 +254,39 @@ void ColladaExporter::WriteHeader()
     else
         mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
 
-    //mOutput << startstr << "<author>" << mScene->author.C_Str() << "</author>" << endstr;
-    //mOutput << startstr << "<authoring_tool>" << mScene->authoringTool.C_Str() << "</authoring_tool>" << endstr;
+    if (meta)
+    {
+        if (meta->Get("Comments", value))
+            mOutput << startstr << "<comments>" << XMLEscape(value.C_Str()) << "</comments>" << endstr;
+        if (meta->Get("Copyright", value))
+            mOutput << startstr << "<copyright>" << XMLEscape(value.C_Str()) << "</copyright>" << endstr;
+        if (meta->Get("SourceData", value))
+            mOutput << startstr << "<source_data>" << XMLEscape(value.C_Str()) << "</source_data>" << endstr;
+    }
 
     PopTag();
     mOutput << startstr << "</contributor>" << endstr;
-    mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
+
+    if (!meta || !meta->Get("Created", value))
+        mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
+    else
+        mOutput << startstr << "<created>" << XMLEscape(value.C_Str()) << "</created>" << endstr;
+
+    // Modified date is always the date saved
     mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr;
+
+    if (meta)
+    {
+        if (meta->Get("Keywords", value))
+            mOutput << startstr << "<keywords>" << XMLEscape(value.C_Str()) << "</keywords>" << endstr;
+        if (meta->Get("Revision", value))
+            mOutput << startstr << "<revision>" << XMLEscape(value.C_Str()) << "</revision>" << endstr;
+        if (meta->Get("Subject", value))
+            mOutput << startstr << "<subject>" << XMLEscape(value.C_Str()) << "</subject>" << endstr;
+        if (meta->Get("Title", value))
+            mOutput << startstr << "<title>" << XMLEscape(value.C_Str()) << "</title>" << endstr;
+    }
+
     mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr;
     mOutput << startstr << "<up_axis>" << up_axis << "</up_axis>" << endstr;
     PopTag();
@@ -866,8 +904,8 @@ void ColladaExporter::WriteController( size_t pIndex)
 
     std::vector<ai_real> bind_poses;
     bind_poses.reserve(mesh->mNumBones * 16);
-    for( size_t i = 0; i < mesh->mNumBones; ++i)
-        for( size_t j = 0; j < 4; ++j)
+    for(unsigned int i = 0; i < mesh->mNumBones; ++i)
+        for( unsigned int j = 0; j < 4; ++j)
             bind_poses.insert(bind_poses.end(), mesh->mBones[i]->mOffsetMatrix[j], mesh->mBones[i]->mOffsetMatrix[j] + 4);
 
     WriteFloatArray( idstr + "-skin-bind_poses", FloatType_Mat4x4, (const ai_real*) bind_poses.data(), bind_poses.size() / 16);
@@ -924,11 +962,11 @@ void ColladaExporter::WriteController( size_t pIndex)
 
     ai_uint weight_index = 0;
     std::vector<ai_int> joint_weight_indices(2 * joint_weight_indices_length, (ai_int)-1);
-    for( size_t i = 0; i < mesh->mNumBones; ++i)
-        for( size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j)
+    for( unsigned int i = 0; i < mesh->mNumBones; ++i)
+        for( unsigned j = 0; j < mesh->mBones[i]->mNumWeights; ++j)
         {
             unsigned int vId = mesh->mBones[i]->mWeights[j].mVertexId;
-            for( size_t k = 0; k < num_influences[vId]; ++k)
+            for( ai_uint k = 0; k < num_influences[vId]; ++k)
             {
                 if (joint_weight_indices[2 * (accum_influences[vId] + k)] == -1)
                 {
@@ -1125,6 +1163,7 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
         case FloatType_Color: floatsPerElement = 3; break;
         case FloatType_Mat4x4: floatsPerElement = 16; break;
         case FloatType_Weight: floatsPerElement = 1; break;
+		case FloatType_Time: floatsPerElement = 1; break;
         default:
             return;
     }
@@ -1201,7 +1240,13 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
         case FloatType_Weight:
             mOutput << startstr << "<param name=\"WEIGHT\" type=\"float\" />" << endstr;
             break;
-    }
+
+		// customized, add animation related
+		case FloatType_Time:
+			mOutput << startstr << "<param name=\"TIME\" type=\"float\" />" << endstr;
+			break;
+
+	}
 
     PopTag();
     mOutput << startstr << "</accessor>" << endstr;
@@ -1231,7 +1276,176 @@ void ColladaExporter::WriteSceneLibrary()
     PopTag();
     mOutput << startstr << "</library_visual_scenes>" << endstr;
 }
-
+// ------------------------------------------------------------------------------------------------
+void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
+{
+	const aiAnimation * anim = mScene->mAnimations[pIndex];
+	
+	if ( anim->mNumChannels == 0 && anim->mNumMeshChannels == 0 && anim->mNumMorphMeshChannels ==0 )
+		return;
+	
+	const std::string animation_name_escaped = XMLEscape( anim->mName.C_Str() );
+	std::string idstr = anim->mName.C_Str();
+	std::string ending = std::string( "AnimId" ) + to_string(pIndex);
+	if (idstr.length() >= ending.length()) {
+		if (0 != idstr.compare (idstr.length() - ending.length(), ending.length(), ending)) {
+			idstr = idstr + ending;
+		}
+	} else {
+		idstr = idstr + ending;
+	}
+
+	const std::string idstrEscaped = XMLEscape(idstr);
+	
+	mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr;
+	PushTag();
+
+    std::string node_idstr;
+	for (size_t a = 0; a < anim->mNumChannels; ++a) {
+		const aiNodeAnim * nodeAnim = anim->mChannels[a];
+		
+		// sanity check
+		if ( nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys ||  nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys ) continue;
+		
+		{
+            node_idstr.clear();
+            node_idstr += nodeAnim->mNodeName.data;
+            node_idstr += std::string( "_matrix-input" );
+
+			std::vector<ai_real> frames;
+			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
+				frames.push_back(static_cast<ai_real>(nodeAnim->mPositionKeys[i].mTime));
+			}
+			
+			WriteFloatArray( node_idstr , FloatType_Time, (const ai_real*) frames.data(), frames.size());
+			frames.clear();
+		}
+		
+		{
+            node_idstr.clear();
+
+            node_idstr += nodeAnim->mNodeName.data;
+            node_idstr += std::string("_matrix-output");
+			
+			std::vector<ai_real> keyframes;
+			keyframes.reserve(nodeAnim->mNumPositionKeys * 16);
+			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
+				aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue;
+				aiMatrix4x4 ScalingM;  // identity
+				ScalingM[0][0] = Scaling.x; ScalingM[1][1] = Scaling.y; ScalingM[2][2] = Scaling.z;
+				
+				aiQuaternion RotationQ = nodeAnim->mRotationKeys[i].mValue;
+				aiMatrix4x4 s = aiMatrix4x4( RotationQ.GetMatrix() );
+				aiMatrix4x4 RotationM(s.a1, s.a2, s.a3, 0, s.b1, s.b2, s.b3, 0, s.c1, s.c2, s.c3, 0, 0, 0, 0, 1);
+				
+				aiVector3D Translation = nodeAnim->mPositionKeys[i].mValue;
+				aiMatrix4x4 TranslationM;	// identity
+				TranslationM[0][3] = Translation.x; TranslationM[1][3] = Translation.y; TranslationM[2][3] = Translation.z;
+				
+				// Combine the above transformations
+				aiMatrix4x4 mat = TranslationM * RotationM * ScalingM;
+				
+				for( unsigned int j = 0; j < 4; ++j) {
+					keyframes.insert(keyframes.end(), mat[j], mat[j] + 4);
+                }
+			}
+			
+			WriteFloatArray( node_idstr, FloatType_Mat4x4, (const ai_real*) keyframes.data(), keyframes.size() / 16);
+		}
+		
+		{
+			std::vector<std::string> names;
+			for ( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
+				if ( nodeAnim->mPreState == aiAnimBehaviour_DEFAULT
+					|| nodeAnim->mPreState == aiAnimBehaviour_LINEAR
+					|| nodeAnim->mPreState == aiAnimBehaviour_REPEAT
+					) {
+					names.push_back( "LINEAR" );
+				} else if (nodeAnim->mPostState == aiAnimBehaviour_CONSTANT) {
+					names.push_back( "STEP" );
+				}
+			}
+			
+			const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-interpolation");
+			std::string arrayId = node_idstr + "-array";
+			
+			mOutput << startstr << "<source id=\"" << XMLEscape(node_idstr) << "\">" << endstr;
+			PushTag();
+			
+			// source array
+			mOutput << startstr << "<Name_array id=\"" << XMLEscape(arrayId) << "\" count=\"" << names.size() << "\"> ";
+			for( size_t a = 0; a < names.size(); ++a ) {
+				mOutput << names[a] << " ";
+            }
+			mOutput << "</Name_array>" << endstr;
+			
+			mOutput << startstr << "<technique_common>" << endstr;
+			PushTag();
+
+			mOutput << startstr << "<accessor source=\"#" << XMLEscape(arrayId) << "\" count=\"" << names.size() << "\" stride=\"" << 1 << "\">" << endstr;
+			PushTag();
+			
+			mOutput << startstr << "<param name=\"INTERPOLATION\" type=\"name\"></param>" << endstr;
+			
+			PopTag();
+			mOutput << startstr << "</accessor>" << endstr;
+			
+			PopTag();
+			mOutput << startstr << "</technique_common>" << endstr;
+
+			PopTag();
+			mOutput << startstr << "</source>" << endstr;
+		}
+	}
+	
+	for (size_t a = 0; a < anim->mNumChannels; ++a) {
+		const aiNodeAnim * nodeAnim = anim->mChannels[a];
+		
+		{
+		// samplers
+			const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-sampler");
+			mOutput << startstr << "<sampler id=\"" << XMLEscape(node_idstr) << "\">" << endstr;
+			PushTag();
+			
+			mOutput << startstr << "<input semantic=\"INPUT\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-input") ) << "\"/>" << endstr;
+			mOutput << startstr << "<input semantic=\"OUTPUT\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-output") ) << "\"/>" << endstr;
+			mOutput << startstr << "<input semantic=\"INTERPOLATION\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-interpolation") ) << "\"/>" << endstr;
+			
+			PopTag();
+			mOutput << startstr << "</sampler>" << endstr;
+		}
+	}
+	
+	for (size_t a = 0; a < anim->mNumChannels; ++a) {
+		const aiNodeAnim * nodeAnim = anim->mChannels[a];
+		
+		{
+		// channels
+			mOutput << startstr << "<channel source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-sampler") ) << "\" target=\"" << XMLEscape(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr;
+		}
+	}
+	
+	PopTag();
+	mOutput << startstr << "</animation>" << endstr;
+	
+}
+// ------------------------------------------------------------------------------------------------
+void ColladaExporter::WriteAnimationsLibrary()
+{
+	const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str());
+	
+	if ( mScene->mNumAnimations > 0 ) {
+		mOutput << startstr << "<library_animations>" << endstr;
+		PushTag();
+		
+		// start recursive write at the root node
+		for( size_t a = 0; a < mScene->mNumAnimations; ++a)
+			WriteAnimationLibrary( a );
+
+		PopTag();
+		mOutput << startstr << "</library_animations>" << endstr;
+	}
+}
 // ------------------------------------------------------------------------------------------------
 // Helper to find a bone by name in the scene
 aiBone* findBone( const aiScene* scene, const char * name) {
@@ -1247,6 +1461,59 @@ aiBone* findBone( const aiScene* scene, const char * name) {
     return NULL;
 }
 
+// ------------------------------------------------------------------------------------------------
+const aiNode * findBoneNode( const aiNode* aNode, const aiBone* bone)
+{
+	if ( aNode && bone && aNode->mName == bone->mName ) {
+		return aNode;
+	}
+	
+	if ( aNode && bone ) {
+		for (unsigned int i=0; i < aNode->mNumChildren; ++i) {
+			aiNode * aChild = aNode->mChildren[i];
+			const aiNode * foundFromChild = 0;
+			if ( aChild ) {
+				foundFromChild = findBoneNode( aChild, bone );
+				if ( foundFromChild ) return foundFromChild;
+			}
+		}
+	}
+	
+	return NULL;
+}
+
+const aiNode * findSkeletonRootNode( const aiScene* scene, const aiMesh * mesh)
+{
+	std::set<const aiNode*> topParentBoneNodes;
+	if ( mesh && mesh->mNumBones > 0 ) {
+		for (unsigned int i=0; i < mesh->mNumBones; ++i) {
+			aiBone * bone = mesh->mBones[i];
+
+			const aiNode * node = findBoneNode( scene->mRootNode, bone);
+			if ( node ) {
+				while ( node->mParent && findBone(scene, node->mParent->mName.C_Str() ) != 0 ) {
+					node = node->mParent;
+				}
+				topParentBoneNodes.insert( node );
+			}
+		}
+	}
+	
+	if ( !topParentBoneNodes.empty() ) {
+		const aiNode * parentBoneNode = *topParentBoneNodes.begin();
+		if ( topParentBoneNodes.size() == 1 ) {
+			return parentBoneNode;
+		} else {
+			for (auto it : topParentBoneNodes) {
+				if ( it->mParent ) return it->mParent;
+			}
+			return parentBoneNode;
+		}
+	}
+	
+	return NULL;
+}
+
 // ------------------------------------------------------------------------------------------------
 // Recursively writes the given node
 void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
@@ -1263,31 +1530,55 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
     // otherwise it is a normal node (NODE)
     const char * node_type;
     bool is_joint, is_skeleton_root = false;
-    if (NULL == findBone(pScene, pNode->mName.C_Str())) {
+    if (nullptr == findBone(pScene, pNode->mName.C_Str())) {
         node_type = "NODE";
         is_joint = false;
     } else {
         node_type = "JOINT";
         is_joint = true;
-        if(!pNode->mParent || NULL == findBone(pScene, pNode->mParent->mName.C_Str()))
+        if (!pNode->mParent || nullptr == findBone(pScene, pNode->mParent->mName.C_Str())) {
             is_skeleton_root = true;
+        }
     }
 
     const std::string node_name_escaped = XMLEscape(pNode->mName.data);
-    mOutput << startstr
-            << "<node ";
-    if(is_skeleton_root)
-        mOutput << "id=\"" << "skeleton_root" << "\" "; // For now, only support one skeleton in a scene.
-    mOutput << (is_joint ? "s" : "") << "id=\"" << node_name_escaped;
-    mOutput << "\" name=\"" << node_name_escaped
+	mOutput << startstr << "<node ";
+	if(is_skeleton_root) {
+		mOutput << "id=\"" << node_name_escaped << "\" " << (is_joint ? "sid=\"" + node_name_escaped +"\"" : "") ; // For now, only support one skeleton in a scene.
+		mFoundSkeletonRootNodeID = node_name_escaped;
+	} else {
+		mOutput << "id=\"" << node_name_escaped << "\" " << (is_joint ? "sid=\"" + node_name_escaped +"\"": "") ;
+	}
+	
+    mOutput << " name=\"" << node_name_escaped
             << "\" type=\"" << node_type
             << "\">" << endstr;
     PushTag();
 
     // write transformation - we can directly put the matrix there
     // TODO: (thom) decompose into scale - rot - quad to allow addressing it by animations afterwards
-    const aiMatrix4x4& mat = pNode->mTransformation;
-    mOutput << startstr << "<matrix sid=\"transform\">";
+    aiMatrix4x4 mat = pNode->mTransformation;
+
+    // If this node is a Camera node, the camera coordinate system needs to be multiplied in.
+    // When importing from Collada, the mLookAt is set to 0, 0, -1, and the node transform is unchanged.
+    // When importing from a different format, mLookAt is set to 0, 0, 1. Therefore, the local camera
+    // coordinate system must be changed to matche the Collada specification.
+    for (size_t i = 0; i<mScene->mNumCameras; i++){
+        if (mScene->mCameras[i]->mName == pNode->mName){
+            aiMatrix4x4 sourceView;
+            mScene->mCameras[i]->GetCameraMatrix(sourceView);
+
+            aiMatrix4x4 colladaView;
+            colladaView.a1 = colladaView.c3 = -1; // move into -z space.
+            mat *= (sourceView * colladaView);
+            break;
+        }
+    }
+	
+	// customized, sid should be 'matrix' to match with loader code.
+    //mOutput << startstr << "<matrix sid=\"transform\">";
+	mOutput << startstr << "<matrix sid=\"matrix\">";
+	
     mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
     mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " ";
     mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " ";
@@ -1315,7 +1606,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
     for( size_t a = 0; a < pNode->mNumMeshes; ++a )
     {
         const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]];
-        // do not instanciate mesh if empty. I wonder how this could happen
+        // do not instantiate mesh if empty. I wonder how this could happen
         if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
             continue;
 
@@ -1331,7 +1622,13 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
                     << endstr;
             PushTag();
 
-            mOutput << startstr << "<skeleton>#skeleton_root</skeleton>" << endstr;
+			// note! this mFoundSkeletonRootNodeID some how affects animation, it makes the mesh attaches to armature skeleton root node.
+			// use the first bone to find skeleton root
+			const aiNode * skeletonRootBoneNode = findSkeletonRootNode( pScene, mesh );
+			if ( skeletonRootBoneNode ) {
+				mFoundSkeletonRootNodeID = XMLEscape( skeletonRootBoneNode->mName.C_Str() );
+			}
+            mOutput << startstr << "<skeleton>#" << mFoundSkeletonRootNodeID << "</skeleton>" << endstr;
         }
         mOutput << startstr << "<bind_material>" << endstr;
         PushTag();

+ 16 - 5
code/ColladaExporter.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -54,7 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <vector>
 #include <map>
 
-#include "StringUtils.h"
+#include <assimp/StringUtils.h>
 
 struct aiScene;
 struct aiNode;
@@ -114,7 +115,9 @@ protected:
     /// Writes the given mesh
     void WriteGeometry( size_t pIndex);
 
-    enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight };
+    //enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight };
+    // customized to add animation related type
+	enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight, FloatType_Time };
 
     /// Writes a float array of the given type
     void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const ai_real* pData, size_t pElementCount);
@@ -122,13 +125,21 @@ protected:
     /// Writes the scene library
     void WriteSceneLibrary();
 
+	// customized, Writes the animation library
+	void WriteAnimationsLibrary();
+	void WriteAnimationLibrary( size_t pIndex);
+	std::string mFoundSkeletonRootNodeID = "skeleton_root";	 	// will be replaced by found node id in the WriteNode call.
+	
     /// Recursively writes the given node
     void WriteNode( const aiScene* scene, aiNode* pNode);
 
     /// Enters a new xml element, which increases the indentation
     void PushTag() { startstr.append( "  "); }
     /// Leaves an element, decreasing the indentation
-    void PopTag() { ai_assert( startstr.length() > 1); startstr.erase( startstr.length() - 2); }
+    void PopTag() { 
+        ai_assert( startstr.length() > 1); 
+        startstr.erase( startstr.length() - 2); 
+    }
 
     /// Creates a mesh ID for the given mesh
     std::string GetMeshId( size_t pIndex) const {
@@ -178,7 +189,7 @@ protected:
      {}
   };
 
-  // summarize a material in an convinient way.
+  // summarize a material in an convenient way.
   struct Material
   {
     std::string name;

+ 7 - 5
code/ColladaHelper.h

@@ -4,7 +4,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -271,12 +272,13 @@ struct Node
     /** Node instances at this node */
     std::vector<NodeInstance> mNodeInstances;
 
-    /** Rootnodes: Name of primary camera, if any */
+    /** Root-nodes: Name of primary camera, if any */
     std::string mPrimaryCamera;
 
     //! Constructor. Begin with a zero parent
-    Node() {
-        mParent = NULL;
+    Node()
+    : mParent( nullptr ){
+        // empty
     }
 
     //! Destructor: delete all children subsequently
@@ -302,7 +304,7 @@ struct Accessor
     size_t mOffset;  // in number of values
     size_t mStride;  // Stride in number of values
     std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
-    size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on.
+    size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, that's XYZ, for a color RGBA and so on.
                           // For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
     std::string mSource;   // URL of the source array
     mutable const Data* mData; // Pointer to the source array, if resolved. NULL else

+ 154 - 113
code/ColladaLoader.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -46,23 +47,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
 
 #include "ColladaLoader.h"
+#include "ColladaParser.h"
+
 #include <assimp/anim.h>
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Importer.hpp>
 #include <assimp/importerdesc.h>
+#include <assimp/Defines.h>
 
-#include "ColladaParser.h"
-#include "fast_atof.h"
-#include "ParsingUtils.h"
-#include "SkeletonMeshBuilder.h"
-#include "CreateAnimMesh.h"
+#include <assimp/fast_atof.h>
+#include <assimp/ParsingUtils.h>
+#include <assimp/SkeletonMeshBuilder.h>
+#include <assimp/CreateAnimMesh.h>
 
 #include "time.h"
 #include "math.h"
 #include <algorithm>
 #include <numeric>
-#include <assimp/Defines.h>
 
 using namespace Assimp;
 using namespace Assimp::Formatter;
@@ -83,34 +85,37 @@ static const aiImporterDesc desc = {
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 ColladaLoader::ColladaLoader()
-    : mFileName()
-	, mMeshIndexByID()
-	, mMaterialIndexByName()
-	, mMeshes()
-	, newMats()
-	, mCameras()
-	, mLights()
-	, mTextures()
-	, mAnims()
-	, noSkeletonMesh( false )
-    , ignoreUpDirection(false)
-    , mNodeNameCounter( 0 )
-{}
+: mFileName()
+, mMeshIndexByID()
+, mMaterialIndexByName()
+, mMeshes()
+, newMats()
+, mCameras()
+, mLights()
+, mTextures()
+, mAnims()
+, noSkeletonMesh( false )
+, ignoreUpDirection(false)
+, useColladaName( false )
+, mNodeNameCounter( 0 ) {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
-ColladaLoader::~ColladaLoader()
-{}
+ColladaLoader::~ColladaLoader() {
+    // empty
+}
 
 // ------------------------------------------------------------------------------------------------
 // Returns whether the class can handle the format of the given file.
-bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
-{
+bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
     // check file extension
     std::string extension = GetExtension(pFile);
 
-    if( extension == "dae")
+    if (extension == "dae") {
         return true;
+    }
 
     // XML - too generic, we need to open the file and search for typical keywords
     if( extension == "xml" || !extension.length() || checkSig)  {
@@ -118,10 +123,13 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo
          *  support a specific file extension in general pIOHandler
          *  might be NULL and it's our duty to return true here.
          */
-        if (!pIOHandler)return true;
-        const char* tokens[] = {"collada"};
+        if (!pIOHandler) {
+            return true;
+        }
+        const char* tokens[] = {"<collada"};
         return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
     }
+
     return false;
 }
 
@@ -130,6 +138,7 @@ void ColladaLoader::SetupProperties(const Importer* pImp)
 {
     noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
     ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0;
+    useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES,0) != 0;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -141,8 +150,7 @@ const aiImporterDesc* ColladaLoader::GetInfo () const
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
-void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
-{
+void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
     mFileName = pFile;
 
     // clean all member arrays - just for safety, it should work even if we did not
@@ -178,26 +186,38 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
     // ... then fill the materials with the now adjusted settings
     FillMaterials(parser, pScene);
 
-        // Apply unitsize scale calculation
-        pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0,  0,  0,
-                                                          0,  parser.mUnitSize,  0,  0,
-                                                          0,  0,  parser.mUnitSize,  0,
-                                                          0,  0,  0,  1);
-        if( !ignoreUpDirection ) {
-        // Convert to Y_UP, if different orientation
-        if( parser.mUpDirection == ColladaParser::UP_X)
-            pScene->mRootNode->mTransformation *= aiMatrix4x4(
-                 0, -1,  0,  0,
-                 1,  0,  0,  0,
-                 0,  0,  1,  0,
-                 0,  0,  0,  1);
-        else if( parser.mUpDirection == ColladaParser::UP_Z)
-            pScene->mRootNode->mTransformation *= aiMatrix4x4(
-                 1,  0,  0,  0,
-                 0,  0,  1,  0,
-                 0, -1,  0,  0,
-                 0,  0,  0,  1);
+    // Apply unit-size scale calculation
+    pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0,  0,  0,
+                                                        0,  parser.mUnitSize,  0,  0,
+                                                        0,  0,  parser.mUnitSize,  0,
+                                                        0,  0,  0,  1);
+    if( !ignoreUpDirection ) {
+    // Convert to Y_UP, if different orientation
+    if( parser.mUpDirection == ColladaParser::UP_X)
+        pScene->mRootNode->mTransformation *= aiMatrix4x4(
+                0, -1,  0,  0,
+                1,  0,  0,  0,
+                0,  0,  1,  0,
+                0,  0,  0,  1);
+    else if( parser.mUpDirection == ColladaParser::UP_Z)
+        pScene->mRootNode->mTransformation *= aiMatrix4x4(
+                1,  0,  0,  0,
+                0,  0,  1,  0,
+                0, -1,  0,  0,
+                0,  0,  0,  1);
+    }
+
+    // Store scene metadata
+    if (!parser.mAssetMetaData.empty()) {
+        const size_t numMeta(parser.mAssetMetaData.size());
+        pScene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>(numMeta));
+        size_t i = 0;
+        for (auto it = parser.mAssetMetaData.cbegin(); it != parser.mAssetMetaData.cend(); ++it, ++i)
+        {
+            pScene->mMetaData->Set(static_cast<unsigned int>(i), (*it).first, (*it).second);
         }
+    }
+
     // store all meshes
     StoreSceneMeshes( pScene);
 
@@ -291,7 +311,7 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
             nd = FindNode(pParser.mRootNode, nodeInst.mNode);
         }
         if (!nd)
-            DefaultLogger::get()->error("Collada: Unable to resolve reference to instanced node " + nodeInst.mNode);
+            ASSIMP_LOG_ERROR_F("Collada: Unable to resolve reference to instanced node ", nodeInst.mNode);
 
         else {
             //  attach this node to the list of children
@@ -308,7 +328,7 @@ void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler
     std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
     if (it != table.mMap.end()) {
         if (it->second.mType != Collada::IT_Texcoord)
-            DefaultLogger::get()->error("Collada: Unexpected effect input mapping");
+            ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
 
         sampler.mUVId = it->second.mSet;
     }
@@ -324,7 +344,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
         ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find( lid.mLight);
         if( srcLightIt == pParser.mLightLibrary.end())
         {
-            DefaultLogger::get()->warn("Collada: Unable to find light for ID \"" + lid.mLight + "\". Skipping.");
+            ASSIMP_LOG_WARN_F("Collada: Unable to find light for ID \"" , lid.mLight , "\". Skipping.");
             continue;
         }
         const Collada::Light* srcLight = &srcLightIt->second;
@@ -392,14 +412,14 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
         ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find( cid.mCamera);
         if( srcCameraIt == pParser.mCameraLibrary.end())
         {
-            DefaultLogger::get()->warn("Collada: Unable to find camera for ID \"" + cid.mCamera + "\". Skipping.");
+            ASSIMP_LOG_WARN_F("Collada: Unable to find camera for ID \"" , cid.mCamera , "\". Skipping.");
             continue;
         }
         const Collada::Camera* srcCamera = &srcCameraIt->second;
 
         // orthographic cameras not yet supported in Assimp
         if (srcCamera->mOrtho) {
-            DefaultLogger::get()->warn("Collada: Orthographic cameras are not supported.");
+            ASSIMP_LOG_WARN("Collada: Orthographic cameras are not supported.");
         }
 
         // now fill our ai data structure
@@ -469,7 +489,7 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
 
             if( !srcMesh)
             {
-                DefaultLogger::get()->warn( format() << "Collada: Unable to find geometry for ID \"" << mid.mMeshOrController << "\". Skipping." );
+                ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." );
                 continue;
             }
         } else
@@ -498,7 +518,8 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
             }
             else
             {
-                DefaultLogger::get()->warn( format() << "Collada: No material specified for subgroup <" << submesh.mMaterial << "> in geometry <" << mid.mMeshOrController << ">." );
+                ASSIMP_LOG_WARN_F( "Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <",
+                    mid.mMeshOrController, ">." );
                 if( !mid.mMaterials.empty() )
                     meshMaterial = mid.mMaterials.begin()->second.mMatName;
             }
@@ -674,7 +695,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
     // create morph target meshes if any
     std::vector<aiMesh*> targetMeshes;
     std::vector<float> targetWeights;
-    Collada::MorphMethod method;
+    Collada::MorphMethod method = Collada::Normalized;
 
     for(std::map<std::string, Collada::Controller>::const_iterator it = pParser.mControllerLibrary.begin();
         it != pParser.mControllerLibrary.end(); it++)
@@ -720,15 +741,18 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
         std::vector<aiAnimMesh*> animMeshes;
         for (unsigned int i = 0; i < targetMeshes.size(); i++)
         {
-            aiAnimMesh *animMesh = aiCreateAnimMesh(targetMeshes.at(i));
-            animMesh->mWeight = targetWeights[i];
+            aiMesh* targetMesh = targetMeshes.at(i);
+            aiAnimMesh *animMesh = aiCreateAnimMesh(targetMesh);
+            float weight = targetWeights[i];
+            animMesh->mWeight = weight == 0 ? 1.0f : weight;
+            animMesh->mName = targetMesh->mName;
             animMeshes.push_back(animMesh);
         }
         dstMesh->mMethod = (method == Collada::Relative)
                                 ? aiMorphingMethod_MORPH_RELATIVE
                                 : aiMorphingMethod_MORPH_NORMALIZED;
         dstMesh->mAnimMeshes = new aiAnimMesh*[animMeshes.size()];
-        dstMesh->mNumAnimMeshes = animMeshes.size();
+        dstMesh->mNumAnimMeshes = static_cast<unsigned int>(animMeshes.size());
         for (unsigned int i = 0; i < animMeshes.size(); i++)
             dstMesh->mAnimMeshes[i] = animMeshes.at(i);
     }
@@ -736,10 +760,6 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
     // create bones if given
     if( pSrcController && pSrcController->mType == Collada::Skin)
     {
-        // refuse if the vertex count does not match
-//      if( pSrcController->mWeightCounts.size() != dstMesh->mNumVertices)
-//          throw DeadlyImportError( "Joint Controller vertex count does not match mesh vertex count");
-
         // resolve references - joint names
         const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointNameSource);
         const Collada::Data& jointNames = pParser.ResolveLibraryReference( pParser.mDataLibrary, jointNamesAcc.mSource);
@@ -871,7 +891,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
             if( bnode)
                 bone->mName.Set( FindNameForNode( bnode));
             else
-                DefaultLogger::get()->warn( format() << "ColladaLoader::CreateMesh(): could not find corresponding node for joint \"" << bone->mName.data << "\"." );
+                ASSIMP_LOG_WARN_F( "ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\"." );
 
             // and insert bone
             dstMesh->mBones[boneCount++] = bone;
@@ -952,7 +972,7 @@ void ColladaLoader::StoreSceneMaterials( aiScene* pScene)
 // Stores all animations
 void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser)
 {
-    // recursivly collect all animations from the collada scene
+    // recursively collect all animations from the collada scene
     StoreAnimations( pScene, pParser, &pParser.mAnims, "");
 
     // catch special case: many animations with the same length, each affecting only a single node.
@@ -967,7 +987,8 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
             for( size_t b = a+1; b < mAnims.size(); ++b)
             {
                 aiAnimation* other = mAnims[b];
-                if( other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && other->mTicksPerSecond == templateAnim->mTicksPerSecond )
+                if( other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && 
+                        other->mTicksPerSecond == templateAnim->mTicksPerSecond )
                     collectedAnimIndices.push_back( b);
             }
 
@@ -1119,6 +1140,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
             continue;
 
         // now check all channels if they affect the current node
+        std::string targetID, subElement;
         for( std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
             cit != pSrcAnim->mChannels.end(); ++cit)
         {
@@ -1145,7 +1167,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
             }
             if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos)
                 continue;
-            std::string targetID = srcChannel.mTarget.substr( 0, slashPos);
+
+            targetID.clear();
+            targetID = srcChannel.mTarget.substr( 0, slashPos);
             if( targetID != srcNode->mID)
                 continue;
 
@@ -1158,7 +1182,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
 
                 entry.mTransformId = srcChannel.mTarget.substr( slashPos+1, dotPos - slashPos - 1);
 
-                std::string subElement = srcChannel.mTarget.substr( dotPos+1);
+                subElement.clear();
+                subElement = srcChannel.mTarget.substr( dotPos+1);
                 if( subElement == "ANGLE")
                     entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle
                 else if( subElement == "X")
@@ -1168,9 +1193,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
                 else if( subElement == "Z")
                     entry.mSubElement = 2;
                 else
-                    DefaultLogger::get()->warn( format() << "Unknown anim subelement <" << subElement << ">. Ignoring" );
-            } else
-            {
+                    ASSIMP_LOG_WARN_F( "Unknown anim subelement <", subElement, ">. Ignoring" );
+            } else {
                 // no subelement following, transformId is remaining string
                 entry.mTransformId = srcChannel.mTarget.substr( slashPos+1);
             }
@@ -1179,7 +1203,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
             if (bracketPos != std::string::npos)
             {
                 entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
-                std::string subElement = srcChannel.mTarget.substr(bracketPos);
+                subElement.clear();
+                subElement = srcChannel.mTarget.substr(bracketPos);
 
                 if (subElement == "(0)(0)")
                     entry.mSubElement = 0;
@@ -1213,7 +1238,6 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
                     entry.mSubElement = 14;
                 else if (subElement == "(3)(3)")
                     entry.mSubElement = 15;
-
             }
 
             // determine which transform step is affected by this channel
@@ -1377,9 +1401,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
         {
               aiNodeAnim* dstAnim = new aiNodeAnim;
               dstAnim->mNodeName = nodeName;
-              dstAnim->mNumPositionKeys = resultTrafos.size();
-              dstAnim->mNumRotationKeys= resultTrafos.size();
-              dstAnim->mNumScalingKeys = resultTrafos.size();
+              dstAnim->mNumPositionKeys = static_cast<unsigned int>(resultTrafos.size());
+              dstAnim->mNumRotationKeys = static_cast<unsigned int>(resultTrafos.size());
+              dstAnim->mNumScalingKeys = static_cast<unsigned int>(resultTrafos.size());
               dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()];
               dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()];
               dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()];
@@ -1399,7 +1423,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
               anims.push_back( dstAnim);
         } else
         {
-          DefaultLogger::get()->warn( "Collada loader: found empty animation channel, ignored. Please check your exporter.");
+            ASSIMP_LOG_WARN( "Collada loader: found empty animation channel, ignored. Please check your exporter.");
         }
 
         if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 )
@@ -1445,11 +1469,11 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
                     ++morphAnimChannelIndex;
                 }
 
-                morphAnim->mNumKeys = morphTimeValues.size();
+                morphAnim->mNumKeys = static_cast<unsigned int>(morphTimeValues.size());
                 morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys];
                 for (unsigned int key = 0; key < morphAnim->mNumKeys; key++)
                 {
-                    morphAnim->mKeys[key].mNumValuesAndWeights = morphChannels.size();
+                    morphAnim->mKeys[key].mNumValuesAndWeights = static_cast<unsigned int>(morphChannels.size());
                     morphAnim->mKeys[key].mValues = new unsigned int [morphChannels.size()];
                     morphAnim->mKeys[key].mWeights = new double [morphChannels.size()];
 
@@ -1470,13 +1494,13 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
     {
         aiAnimation* anim = new aiAnimation;
         anim->mName.Set( pName);
-        anim->mNumChannels = anims.size();
+        anim->mNumChannels = static_cast<unsigned int>(anims.size());
         if (anim->mNumChannels > 0)
         {
             anim->mChannels = new aiNodeAnim*[anims.size()];
             std::copy( anims.begin(), anims.end(), anim->mChannels);
         }
-        anim->mNumMorphMeshChannels = morphAnims.size();
+        anim->mNumMorphMeshChannels = static_cast<unsigned int>(morphAnims.size());
         if (anim->mNumMorphMeshChannels > 0)
         {
             anim->mMorphMeshChannels = new aiMeshMorphAnim*[anim->mNumMorphMeshChannels];
@@ -1554,7 +1578,7 @@ void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
             }
         }
         if (-1 == map) {
-            DefaultLogger::get()->warn("Collada: unable to determine UV channel for texture");
+            ASSIMP_LOG_WARN("Collada: unable to determine UV channel for texture");
             map = 0;
         }
     }
@@ -1591,7 +1615,7 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
                 break;
 
             default:
-                DefaultLogger::get()->warn("Collada: Unrecognized shading mode, using gouraud shading");
+                ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading");
                 shadeMode = aiShadingMode_Gouraud;
                 break;
             }
@@ -1619,7 +1643,7 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
         mat.AddProperty( &effect.mRefractIndex, 1, AI_MATKEY_REFRACTI);
 
         // transparency, a very hard one. seemingly not all files are following the
-        // specification here (1.0 transparency => completly opaque)...
+        // specification here (1.0 transparency => completely opaque)...
         // therefore, we let the opportunity for the user to manually invert
         // the transparency if necessary and we add preliminary support for RGB_ZERO mode
         if(effect.mTransparency >= 0.f && effect.mTransparency <= 1.f) {
@@ -1650,9 +1674,10 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
         }
 
         // add textures, if given
-        if( !effect.mTexAmbient.mName.empty())
-             /* It is merely a lightmap */
-            AddTexture( mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP);
+        if (!effect.mTexAmbient.mName.empty()) {
+            // It is merely a light-map
+            AddTexture(mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP);
+        }
 
         if( !effect.mTexEmissive.mName.empty())
             AddTexture( mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE);
@@ -1680,8 +1705,8 @@ void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/)
 {
     newMats.reserve(pParser.mMaterialLibrary.size());
 
-    for( ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin(); matIt != pParser.mMaterialLibrary.end(); ++matIt)
-    {
+    for( ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin(); 
+        matIt != pParser.mMaterialLibrary.end(); ++matIt) {
         const Collada::Material& material = matIt->second;
         // a material is only a reference to an effect
         ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find( material.mEffect);
@@ -1745,11 +1770,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
     ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name);
     if( imIt == pParser.mImageLibrary.end())
     {
-        //missing texture should not stop the conversion
-        //throw DeadlyImportError( format() <<
-        //    "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." );
-
-        DefaultLogger::get()->warn("Collada: Unable to resolve effect texture entry \"" + pName + "\", ended up at ID \"" + name + "\".");
+        ASSIMP_LOG_WARN_F("Collada: Unable to resolve effect texture entry \"", pName, "\", ended up at ID \"", name, "\".");
 
         //set default texture file name
         result.Set(name + ".jpg");
@@ -1768,7 +1789,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
 
         // setup format hint
         if (imIt->second.mEmbeddedFormat.length() > 3) {
-            DefaultLogger::get()->warn("Collada: texture format hint is too long, truncating to 3 characters");
+            ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
         }
         strncpy(tex->achFormatHint,imIt->second.mEmbeddedFormat.c_str(),3);
 
@@ -1778,6 +1799,11 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
         tex->pcData = (aiTexel*)new char[tex->mWidth];
         memcpy(tex->pcData,&imIt->second.mImageData[0],tex->mWidth);
 
+        // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
+        // In FBX files textures are now stored internally by Assimp with their filename included
+        // Now Assimp can lookup through the loaded textures after all data is processed
+        // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
+        // This may occur on this case too, it has to be studied
         // setup texture reference string
         result.data[0] = '*';
         result.length = 1 + ASSIMP_itoa10(result.data+1,static_cast<unsigned int>(MAXLEN-1),static_cast<int32_t>(mTextures.size()));
@@ -1799,7 +1825,7 @@ void ColladaLoader::ConvertPath (aiString& ss)
 {
     // TODO: collada spec, p 22. Handle URI correctly.
     // For the moment we're just stripping the file:// away to make it work.
-    // Windoes doesn't seem to be able to find stuff like
+    // Windows doesn't seem to be able to find stuff like
     // 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg'
     if (0 == strncmp(ss.data,"file://",7))
     {
@@ -1810,10 +1836,13 @@ void ColladaLoader::ConvertPath (aiString& ss)
 
   // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
   // I need to filter it without destroying linux paths starting with "/somewhere"
-  if( ss.data[0] == '/' && isalpha( ss.data[1]) && ss.data[2] == ':' )
-  {
-    ss.length--;
-    memmove( ss.data, ss.data+1, ss.length);
+#if defined( _MSC_VER )
+    if( ss.data[0] == '/' && isalpha( (unsigned char) ss.data[1]) && ss.data[2] == ':' ) {
+#else
+    if (ss.data[ 0 ] == '/' && isalpha( ss.data[ 1 ] ) && ss.data[ 2 ] == ':') {
+#endif
+    --ss.length;
+    ::memmove( ss.data, ss.data+1, ss.length);
     ss.data[ss.length] = 0;
   }
 
@@ -1863,9 +1892,9 @@ const std::string& ColladaLoader::ReadString( const Collada::Accessor& pAccessor
 void ColladaLoader::CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const
 {
     poNodes.push_back( pNode);
-
-    for( size_t a = 0; a < pNode->mNumChildren; ++a)
-        CollectNodes( pNode->mChildren[a], poNodes);
+    for (size_t a = 0; a < pNode->mNumChildren; ++a) {
+        CollectNodes(pNode->mChildren[a], poNodes);
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -1907,17 +1936,29 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c
 // The name must be unique for proper node-bone association.
 std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode)
 {
-    // Now setup the name of the assimp node. The collada name might not be
-    // unique, so we use the collada ID.
-    if (!pNode->mID.empty())
-        return pNode->mID;
-    else if (!pNode->mSID.empty())
-    return pNode->mSID;
-  else
+    // If explicitly requested, just use the collada name.
+    if (useColladaName)
     {
-        // No need to worry. Unnamed nodes are no problem at all, except
-        // if cameras or lights need to be assigned to them.
-    return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
+        if (!pNode->mName.empty()) {
+            return pNode->mName;
+        } else {
+            return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
+        }
+    }
+    else
+    {
+        // Now setup the name of the assimp node. The collada name might not be
+        // unique, so we use the collada ID.
+        if (!pNode->mID.empty())
+            return pNode->mID;
+        else if (!pNode->mSID.empty())
+            return pNode->mSID;
+        else
+        {
+            // No need to worry. Unnamed nodes are no problem at all, except
+            // if cameras or lights need to be assigned to them.
+            return format() << "$ColladaAutoName$_" << mNodeNameCounter++;
+        }
     }
 }
 

+ 4 - 2
code/ColladaLoader.h

@@ -4,7 +4,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -44,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_COLLADALOADER_H_INC
 #define AI_COLLADALOADER_H_INC
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 #include "ColladaParser.h"
 
 struct aiNode;
@@ -247,6 +248,7 @@ protected:
 
     bool noSkeletonMesh;
     bool ignoreUpDirection;
+    bool useColladaName;
 
     /** Used by FindNameForNode() to generate unique node names */
     unsigned int mNodeNameCounter;

+ 139 - 41
code/ColladaParser.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -49,13 +50,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <sstream>
 #include <stdarg.h>
 #include "ColladaParser.h"
-#include "fast_atof.h"
-#include "ParsingUtils.h"
-#include "StringUtils.h"
+#include <assimp/fast_atof.h>
+#include <assimp/ParsingUtils.h>
+#include <assimp/StringUtils.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/IOSystem.hpp>
 #include <assimp/light.h>
-#include "TinyFormatter.h"
+#include <assimp/TinyFormatter.h>
 
 #include <memory>
 
@@ -67,7 +68,7 @@ using namespace Assimp::Formatter;
 // Constructor to be privately used by Importer
 ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
     : mFileName( pFile )
-    , mReader( NULL )
+    , mReader( nullptr )
     , mDataLibrary()
     , mAccessorLibrary()
     , mMeshLibrary()
@@ -78,20 +79,20 @@ ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
     , mLightLibrary()
     , mCameraLibrary()
     , mControllerLibrary()
-    , mRootNode( NULL )
+    , mRootNode( nullptr )
     , mAnims()
     , mUnitSize( 1.0f )
     , mUpDirection( UP_Y )
     , mFormat(FV_1_5_n )    // We assume the newest file format by default
 {
     // validate io-handler instance
-    if ( NULL == pIOHandler ) {
+    if (nullptr == pIOHandler ) {
         throw DeadlyImportError("IOSystem is NULL." );
     }
 
     // open the file
     std::unique_ptr<IOStream> file( pIOHandler->Open(pFile ) );
-    if (file.get() == NULL) {
+    if (file.get() == nullptr) {
         throw DeadlyImportError( "Failed to open file " + pFile + "." );
     }
 
@@ -151,22 +152,22 @@ void ColladaParser::ReadContents()
 
                     if (!::strncmp(version,"1.5",3)) {
                         mFormat =  FV_1_5_n;
-                        DefaultLogger::get()->debug("Collada schema version is 1.5.n");
+                        ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n");
                     }
                     else if (!::strncmp(version,"1.4",3)) {
                         mFormat =  FV_1_4_n;
-                        DefaultLogger::get()->debug("Collada schema version is 1.4.n");
+                        ASSIMP_LOG_DEBUG("Collada schema version is 1.4.n");
                     }
                     else if (!::strncmp(version,"1.3",3)) {
                         mFormat =  FV_1_3_n;
-                        DefaultLogger::get()->debug("Collada schema version is 1.3.n");
+                        ASSIMP_LOG_DEBUG("Collada schema version is 1.3.n");
                     }
                 }
 
                 ReadStructure();
             } else
             {
-                DefaultLogger::get()->debug( format() << "Ignoring global element <" << mReader->getNodeName() << ">." );
+                ASSIMP_LOG_DEBUG_F( "Ignoring global element <", mReader->getNodeName(), ">." );
                 SkipElement();
             }
         } else
@@ -221,10 +222,11 @@ void ColladaParser::ReadStructure()
     }
 
 	PostProcessRootAnimations();
+    PostProcessControllers();
 }
 
 // ------------------------------------------------------------------------------------------------
-// Reads asset informations such as coordinate system informations and legal blah
+// Reads asset information such as coordinate system information and legal blah
 void ColladaParser::ReadAssetInfo()
 {
     if( mReader->isEmptyElement())
@@ -262,14 +264,19 @@ void ColladaParser::ReadAssetInfo()
 
                 // check element end
                 TestClosing( "up_axis");
-            } else
+            }
+            else if(IsElement("contributor"))
             {
-                SkipElement();
+                ReadContributorInfo();
+            }
+            else
+            {
+                ReadMetaDataItem(mAssetMetaData);
             }
         }
         else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
         {
-            if( strcmp( mReader->getNodeName(), "asset") != 0)
+            if (strcmp( mReader->getNodeName(), "asset") != 0)
                 ThrowException( "Expected end of <asset> element.");
 
             break;
@@ -277,6 +284,75 @@ void ColladaParser::ReadAssetInfo()
     }
 }
 
+// ------------------------------------------------------------------------------------------------
+// Reads the contributor info
+void ColladaParser::ReadContributorInfo()
+{
+    if (mReader->isEmptyElement())
+        return;
+
+    while (mReader->read())
+    {
+        if (mReader->getNodeType() == irr::io::EXN_ELEMENT)
+        {
+            ReadMetaDataItem(mAssetMetaData);
+        }
+        else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END)
+        {
+            if (strcmp(mReader->getNodeName(), "contributor") != 0)
+                ThrowException("Expected end of <contributor> element.");
+            break;
+        }
+    }
+}
+
+// ------------------------------------------------------------------------------------------------
+// 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)
+    {
+        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);
+            aiString aistr;
+            aistr.Set(value_char);
+            metadata.emplace(camel_key_str, aistr);
+            TestClosing(key_str.c_str());
+        }
+        else
+            SkipElement();
+    }
+    else
+        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
 void ColladaParser::ReadAnimationClipLibrary()
@@ -359,6 +435,21 @@ void ColladaParser::ReadAnimationClipLibrary()
 	}
 }
 
+void ColladaParser::PostProcessControllers()
+{
+    std::string meshId;
+    for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it) {
+        meshId = it->second.mMeshId;
+        ControllerLibrary::iterator findItr = mControllerLibrary.find(meshId);
+        while(findItr != mControllerLibrary.end()) {
+            meshId = findItr->second.mMeshId;
+            findItr = mControllerLibrary.find(meshId);
+        }
+    
+        it->second.mMeshId = meshId;
+    }
+}
+
 // ------------------------------------------------------------------------------------------------
 // Re-build animations from animation clip library, if present, otherwise combine single-channel animations
 void ColladaParser::PostProcessRootAnimations()
@@ -967,13 +1058,13 @@ void ColladaParser::ReadImage( Collada::Image& pImage)
                     // they're not skipped.
                     int attrib = TestAttribute("array_index");
                     if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
-                        DefaultLogger::get()->warn("Collada: Ignoring texture array index");
+                        ASSIMP_LOG_WARN("Collada: Ignoring texture array index");
                         continue;
                     }
 
                     attrib = TestAttribute("mip_index");
                     if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
-                        DefaultLogger::get()->warn("Collada: Ignoring MIP map layer");
+                        ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer");
                         continue;
                     }
 
@@ -994,7 +1085,7 @@ void ColladaParser::ReadImage( Collada::Image& pImage)
                     // embedded image. get format
                     const int attrib = TestAttribute("format");
                     if (-1 == attrib)
-                        DefaultLogger::get()->warn("Collada: Unknown image file format");
+                        ASSIMP_LOG_WARN("Collada: Unknown image file format");
                     else pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib);
 
                     const char* data = GetTextContent();
@@ -1573,7 +1664,7 @@ void ColladaParser::ReadSamplerProperties( Sampler& out )
                     out.mOp = aiTextureOp_Multiply;
 
                 else  {
-                    DefaultLogger::get()->warn("Collada: Unsupported MAYA texture blend mode");
+                    ASSIMP_LOG_WARN("Collada: Unsupported MAYA texture blend mode");
                 }
                 TestClosing( "blend_mode");
             }
@@ -2231,7 +2322,7 @@ void ColladaParser::ReadIndexData( Mesh* pMesh)
     }
 
 #ifdef ASSIMP_BUILD_DEBUG
-	if (primType != Prim_TriFans && primType != Prim_TriStrips &&
+	if (primType != Prim_TriFans && primType != Prim_TriStrips && primType != Prim_LineStrip &&
         primType != Prim_Lines) { // this is ONLY to workaround a bug in SketchUp 15.3.331 where it writes the wrong 'count' when it writes out the 'lines'.
         ai_assert(actualPrimitives == numPrimitives);
     }
@@ -2345,7 +2436,7 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pP
     if( expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets) {
         if (pPrimType == Prim_Lines) {
             // HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines'
-            ReportWarning( "Expected different index count in <p> element, %d instead of %d.", indices.size(), expectedPointCount * numOffsets);
+            ReportWarning( "Expected different index count in <p> element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets);
             pNumPrimitives = (indices.size() / numOffsets) / 2;
         } else
             ThrowException( "Expected different index count in <p> element.");
@@ -2400,6 +2491,10 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pP
         size_t numberOfVertices = indices.size() / numOffsets;
         numPrimitives = numberOfVertices - 2;
     }
+    if (pPrimType == Prim_LineStrip) {
+        size_t numberOfVertices = indices.size() / numOffsets;
+        numPrimitives = numberOfVertices - 1;
+    }
 
     pMesh->mFaceSize.reserve( numPrimitives);
     pMesh->mFacePosIndices.reserve( indices.size() / numOffsets);
@@ -2416,6 +2511,11 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector<InputChannel>& pP
                 for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
                     CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
                 break;
+            case Prim_LineStrip:
+                numPoints = 2;
+                for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
+                    CopyVertex(currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices);
+                break;
             case Prim_Triangles:
                 numPoints = 3;
                 for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++)
@@ -2460,8 +2560,7 @@ void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t n
     size_t baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets;
 
     // don't overrun the boundaries of the index list
-    size_t maxIndexRequested = baseOffset + numOffsets - 1;
-    ai_assert(maxIndexRequested < indices.size());
+    ai_assert((baseOffset + numOffsets - 1) < indices.size());
 
     // extract per-vertex channels using the global per-vertex offset
     for (std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
@@ -2516,7 +2615,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
             if( pInput.mIndex == 0)
                 pMesh->mPositions.push_back( aiVector3D( obj[0], obj[1], obj[2]));
             else
-                DefaultLogger::get()->error("Collada: just one vertex position stream supported");
+                ASSIMP_LOG_ERROR("Collada: just one vertex position stream supported");
             break;
         case IT_Normal:
             // pad to current vertex count if necessary
@@ -2527,7 +2626,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
             if( pInput.mIndex == 0)
                 pMesh->mNormals.push_back( aiVector3D( obj[0], obj[1], obj[2]));
             else
-                DefaultLogger::get()->error("Collada: just one vertex normal stream supported");
+                ASSIMP_LOG_ERROR("Collada: just one vertex normal stream supported");
             break;
         case IT_Tangent:
             // pad to current vertex count if necessary
@@ -2538,7 +2637,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
             if( pInput.mIndex == 0)
                 pMesh->mTangents.push_back( aiVector3D( obj[0], obj[1], obj[2]));
             else
-                DefaultLogger::get()->error("Collada: just one vertex tangent stream supported");
+                ASSIMP_LOG_ERROR("Collada: just one vertex tangent stream supported");
             break;
         case IT_Bitangent:
             // pad to current vertex count if necessary
@@ -2549,7 +2648,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
             if( pInput.mIndex == 0)
                 pMesh->mBitangents.push_back( aiVector3D( obj[0], obj[1], obj[2]));
             else
-                DefaultLogger::get()->error("Collada: just one vertex bitangent stream supported");
+                ASSIMP_LOG_ERROR("Collada: just one vertex bitangent stream supported");
             break;
         case IT_Texcoord:
             // up to 4 texture coord sets are fine, ignore the others
@@ -2565,7 +2664,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
                     pMesh->mNumUVComponents[pInput.mIndex]=3;
             }   else
             {
-                DefaultLogger::get()->error("Collada: too many texture coordinate sets. Skipping.");
+                ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping.");
             }
             break;
         case IT_Color:
@@ -2585,7 +2684,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
                 pMesh->mColors[pInput.mIndex].push_back(result);
             } else
             {
-                DefaultLogger::get()->error("Collada: too many vertex color sets. Skipping.");
+                ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping.");
             }
 
             break;
@@ -2714,7 +2813,7 @@ void ColladaParser::ReadSceneNode( Node* pNode)
                 {
                     const char* s = mReader->getAttributeValue(attrId);
                     if (s[0] != '#')
-                        DefaultLogger::get()->error("Collada: Unresolved reference format of camera");
+                        ASSIMP_LOG_ERROR("Collada: Unresolved reference format of camera");
                     else
                         pNode->mPrimaryCamera = s+1;
                 }
@@ -2727,7 +2826,7 @@ void ColladaParser::ReadSceneNode( Node* pNode)
                 {
                     const char* s = mReader->getAttributeValue(attrID);
                     if (s[0] != '#')
-                        DefaultLogger::get()->error("Collada: Unresolved reference format of node");
+                        ASSIMP_LOG_ERROR("Collada: Unresolved reference format of node");
                     else
                     {
                         pNode->mNodeInstances.push_back(NodeInstance());
@@ -2745,7 +2844,7 @@ void ColladaParser::ReadSceneNode( Node* pNode)
                 // Reference to a light, name given in 'url' attribute
                 int attrID = TestAttribute("url");
                 if (-1 == attrID)
-                    DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_light> element");
+                    ASSIMP_LOG_WARN("Collada: Expected url attribute in <instance_light> element");
                 else
                 {
                     const char* url = mReader->getAttributeValue( attrID);
@@ -2761,7 +2860,7 @@ void ColladaParser::ReadSceneNode( Node* pNode)
                 // Reference to a camera, name given in 'url' attribute
                 int attrID = TestAttribute("url");
                 if (-1 == attrID)
-                    DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_camera> element");
+                    ASSIMP_LOG_WARN("Collada: Expected url attribute in <instance_camera> element");
                 else
                 {
                     const char* url = mReader->getAttributeValue( attrID);
@@ -2848,7 +2947,7 @@ void ColladaParser::ReadMaterialVertexInputBinding( Collada::SemanticMappingTabl
                 tbl.mMap[s] = vn;
             }
             else if( IsElement( "bind")) {
-                DefaultLogger::get()->warn("Collada: Found unsupported <bind> element");
+                ASSIMP_LOG_WARN("Collada: Found unsupported <bind> element");
             }
         }
         else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END)    {
@@ -2967,10 +3066,9 @@ void ColladaParser::ReportWarning(const char* msg,...)
     ai_assert(iLen > 0);
 
     va_end(args);
-    DefaultLogger::get()->warn("Validation warning: " + std::string(szBuffer,iLen));
+    ASSIMP_LOG_WARN_F("Validation warning: ", std::string(szBuffer,iLen));
 }
 
-
 // ------------------------------------------------------------------------------------------------
 // Skips all data until the end node of the current element
 void ColladaParser::SkipElement()
@@ -3081,7 +3179,7 @@ const char* ColladaParser::TestTextContent()
     // read contents of the element
     if( !mReader->read() )
         return NULL;
-    if( mReader->getNodeType() != irr::io::EXN_TEXT)
+    if( mReader->getNodeType() != irr::io::EXN_TEXT && mReader->getNodeType() != irr::io::EXN_CDATA)
         return NULL;
 
     // skip leading whitespace
@@ -3165,7 +3263,7 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform
 Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& semantic)
 {
     if ( semantic.empty() ) {
-        DefaultLogger::get()->warn( format() << "Vertex input type is empty." );
+        ASSIMP_LOG_WARN("Vertex input type is empty." );
         return IT_Invalid;
     }
 
@@ -3184,7 +3282,7 @@ Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& semanti
     else if( semantic == "TANGENT" || semantic == "TEXTANGENT")
         return IT_Tangent;
 
-    DefaultLogger::get()->warn( format() << "Unknown vertex input type \"" << semantic << "\". Ignoring." );
+    ASSIMP_LOG_WARN_F( "Unknown vertex input type \"", semantic, "\". Ignoring." );
     return IT_Invalid;
 }
 

+ 23 - 4
code/ColladaParser.h

@@ -2,7 +2,8 @@
  Open Asset Import Library (assimp)
  ----------------------------------------------------------------------
 
- Copyright (c) 2006-2017, assimp team
+ Copyright (c) 2006-2019, assimp team
+
 
  All rights reserved.
 
@@ -46,10 +47,10 @@
 #ifndef AI_COLLADAPARSER_H_INC
 #define AI_COLLADAPARSER_H_INC
 
-#include "irrXMLWrapper.h"
+#include <assimp/irrXMLWrapper.h>
 #include "ColladaHelper.h"
 #include <assimp/ai_assert.h>
-#include "TinyFormatter.h"
+#include <assimp/TinyFormatter.h>
 
 namespace Assimp
 {
@@ -65,6 +66,9 @@ namespace Assimp
         friend class ColladaLoader;
 
     protected:
+        /** Map for generic metadata as aiString */
+        typedef std::map<std::string, aiString> StringMetaData;
+
         /** Constructor from XML file */
         ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
 
@@ -77,15 +81,27 @@ namespace Assimp
         /** Reads the structure of the file */
         void ReadStructure();
 
-        /** Reads asset informations such as coordinate system informations and legal blah */
+        /** Reads asset information such as coordinate system information and legal blah */
         void ReadAssetInfo();
 
+        /** Reads contributor information such as author and legal blah */
+        void ReadContributorInfo();
+
+        /** Reads generic metadata into provided map */
+        void ReadMetaDataItem(StringMetaData &metadata);
+
+        /** Convert underscore_seperated to CamelCase "authoring_tool" becomes "AuthoringTool" */
+        static void ToCamelCase(std::string &text);
+
         /** Reads the animation library */
         void ReadAnimationLibrary();
 
 		/** Reads the animation clip library */
 		void ReadAnimationClipLibrary();
 
+        /** Unwrap controllers dependency hierarchy */
+        void PostProcessControllers();
+    
 		/** Re-build animations from animation clip library, if present, otherwise combine single-channel animations */
 		void PostProcessRootAnimations();
 
@@ -339,6 +355,9 @@ namespace Assimp
         /** Which is the up vector */
         enum { UP_X, UP_Y, UP_Z } mUpDirection;
 
+        /** Asset metadata (global for scene) */
+        StringMetaData mAssetMetaData;
+
         /** Collada file format version */
         Collada::FormatVersion mFormat;
     };

+ 9 - 8
code/ComputeUVMappingProcess.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -44,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "ComputeUVMappingProcess.h"
 #include "ProcessHelper.h"
-#include "Exceptional.h"
+#include <assimp/Exceptional.h>
 
 using namespace Assimp;
 
@@ -98,7 +99,7 @@ inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
     for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
         if (!mesh->mTextureCoords[m])return m;
 
-    DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found");
+    ASSIMP_LOG_ERROR("Unable to compute UV coordinates, no free UV slot found");
     return UINT_MAX;
 }
 
@@ -383,13 +384,13 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
 // ------------------------------------------------------------------------------------------------
 void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* )
 {
-    DefaultLogger::get()->error("Mapping type currently not implemented");
+    ASSIMP_LOG_ERROR("Mapping type currently not implemented");
 }
 
 // ------------------------------------------------------------------------------------------------
 void ComputeUVMappingProcess::Execute( aiScene* pScene)
 {
-    DefaultLogger::get()->debug("GenUVCoordsProcess begin");
+    ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
     char buffer[1024];
 
     if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
@@ -417,7 +418,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
                             TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
                             MappingTypeToString(mapping));
 
-                        DefaultLogger::get()->info(buffer);
+                        ASSIMP_LOG_INFO(buffer);
                     }
 
                     if (aiTextureMapping_OTHER == mapping)
@@ -484,7 +485,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
                             }
                             if (m && idx != outIdx)
                             {
-                                DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to "
+                                ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to "
                                     "this material have equal numbers of UV channels. The UV index stored in  "
                                     "the material structure does therefore not apply for all meshes. ");
                             }
@@ -501,5 +502,5 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
             }
         }
     }
-    DefaultLogger::get()->debug("GenUVCoordsProcess finished");
+    ASSIMP_LOG_DEBUG("GenUVCoordsProcess finished");
 }

+ 2 - 1
code/ComputeUVMappingProcess.h

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

+ 111 - 29
code/ConvertToLHProcess.cpp

@@ -3,7 +3,8 @@
 Open Asset Import Library (assimp)
 ---------------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 
 All rights reserved.
@@ -58,6 +59,25 @@ using namespace Assimp;
 
 #ifndef ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
 
+namespace {
+
+template <typename aiMeshType>
+void flipUVs(aiMeshType* pMesh) {
+    if (pMesh == nullptr) { return; }
+    // mirror texture y coordinate
+    for (unsigned int tcIdx = 0; tcIdx < AI_MAX_NUMBER_OF_TEXTURECOORDS; tcIdx++) {
+        if (!pMesh->HasTextureCoords(tcIdx)) {
+            break;
+        }
+
+        for (unsigned int vIdx = 0; vIdx < pMesh->mNumVertices; vIdx++) {
+            pMesh->mTextureCoords[tcIdx][vIdx].y = 1.0f - pMesh->mTextureCoords[tcIdx][vIdx].y;
+        }
+    }
+}
+
+} // namespace
+
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 MakeLeftHandedProcess::MakeLeftHandedProcess()
@@ -84,18 +104,20 @@ void MakeLeftHandedProcess::Execute( aiScene* pScene)
 {
     // Check for an existent root node to proceed
     ai_assert(pScene->mRootNode != NULL);
-    DefaultLogger::get()->debug("MakeLeftHandedProcess begin");
+    ASSIMP_LOG_DEBUG("MakeLeftHandedProcess begin");
 
     // recursively convert all the nodes
     ProcessNode( pScene->mRootNode, aiMatrix4x4());
 
     // process the meshes accordingly
-    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
-        ProcessMesh( pScene->mMeshes[a]);
+    for ( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
+        ProcessMesh( pScene->mMeshes[ a ] );
+    }
 
     // process the materials accordingly
-    for( unsigned int a = 0; a < pScene->mNumMaterials; ++a)
-        ProcessMaterial( pScene->mMaterials[a]);
+    for ( unsigned int a = 0; a < pScene->mNumMaterials; ++a ) {
+        ProcessMaterial( pScene->mMaterials[ a ] );
+    }
 
     // transform all animation channels as well
     for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
@@ -107,7 +129,7 @@ void MakeLeftHandedProcess::Execute( aiScene* pScene)
             ProcessAnimation( nodeAnim);
         }
     }
-    DefaultLogger::get()->debug("MakeLeftHandedProcess finished");
+    ASSIMP_LOG_DEBUG("MakeLeftHandedProcess finished");
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -135,14 +157,18 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare
 
 // ------------------------------------------------------------------------------------------------
 // Converts a single mesh to left handed coordinates.
-void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
-{
+void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) {
+    if ( nullptr == pMesh ) {
+        ASSIMP_LOG_ERROR( "Nullptr to mesh found." );
+        return;
+    }
     // mirror positions, normals and stuff along the Z axis
     for( size_t a = 0; a < pMesh->mNumVertices; ++a)
     {
         pMesh->mVertices[a].z *= -1.0f;
-        if( pMesh->HasNormals())
+        if (pMesh->HasNormals()) {
             pMesh->mNormals[a].z *= -1.0f;
+        }
         if( pMesh->HasTangentsAndBitangents())
         {
             pMesh->mTangents[a].z *= -1.0f;
@@ -150,6 +176,23 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
         }
     }
 
+    // mirror anim meshes positions, normals and stuff along the Z axis
+    for (size_t m = 0; m < pMesh->mNumAnimMeshes; ++m)
+    {
+        for (size_t a = 0; a < pMesh->mAnimMeshes[m]->mNumVertices; ++a)
+        {
+            pMesh->mAnimMeshes[m]->mVertices[a].z *= -1.0f;
+            if (pMesh->mAnimMeshes[m]->HasNormals()) {
+                pMesh->mAnimMeshes[m]->mNormals[a].z *= -1.0f;
+            }
+            if (pMesh->mAnimMeshes[m]->HasTangentsAndBitangents())
+            {
+                pMesh->mAnimMeshes[m]->mTangents[a].z *= -1.0f;
+                pMesh->mAnimMeshes[m]->mBitangents[a].z *= -1.0f;
+            }
+        }
+    }
+
     // mirror offset matrices of all bones
     for( size_t a = 0; a < pMesh->mNumBones; ++a)
     {
@@ -172,8 +215,12 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh)
 
 // ------------------------------------------------------------------------------------------------
 // Converts a single material to left handed coordinates.
-void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
-{
+void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) {
+    if ( nullptr == _mat ) {
+        ASSIMP_LOG_ERROR( "Nullptr to aiMaterial found." );
+        return;
+    }
+
     aiMaterial* mat = (aiMaterial*)_mat;
     for (unsigned int a = 0; a < mat->mNumProperties;++a)   {
         aiMaterialProperty* prop = mat->mProperties[a];
@@ -182,7 +229,6 @@ void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat)
         if (!::strcmp( prop->mKey.data, "$tex.mapaxis"))    {
             ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
             aiVector3D* pff = (aiVector3D*)prop->mData;
-
             pff->z *= -1.f;
         }
     }
@@ -236,13 +282,13 @@ bool FlipUVsProcess::IsActive( unsigned int pFlags) const
 // Executes the post processing step on the given imported data.
 void FlipUVsProcess::Execute( aiScene* pScene)
 {
-    DefaultLogger::get()->debug("FlipUVsProcess begin");
+    ASSIMP_LOG_DEBUG("FlipUVsProcess begin");
     for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
         ProcessMesh(pScene->mMeshes[i]);
 
     for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
         ProcessMaterial(pScene->mMaterials[i]);
-    DefaultLogger::get()->debug("FlipUVsProcess finished");
+    ASSIMP_LOG_DEBUG("FlipUVsProcess finished");
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -253,7 +299,7 @@ void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
     for (unsigned int a = 0; a < mat->mNumProperties;++a)   {
         aiMaterialProperty* prop = mat->mProperties[a];
         if( !prop ) {
-            DefaultLogger::get()->debug( "Property is null" );
+            ASSIMP_LOG_DEBUG( "Property is null" );
             continue;
         }
 
@@ -273,15 +319,9 @@ void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
 // Converts a single mesh
 void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
 {
-    // mirror texture y coordinate
-    for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)   {
-        if( !pMesh->HasTextureCoords( a ) ) {
-            break;
-        }
-
-        for( unsigned int b = 0; b < pMesh->mNumVertices; b++ ) {
-            pMesh->mTextureCoords[ a ][ b ].y = 1.0f - pMesh->mTextureCoords[ a ][ b ].y;
-        }
+    flipUVs(pMesh);
+    for (unsigned int idx = 0; idx < pMesh->mNumAnimMeshes; idx++) {
+        flipUVs(pMesh->mAnimMeshes[idx]);
     }
 }
 
@@ -310,10 +350,10 @@ bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const
 // Executes the post processing step on the given imported data.
 void FlipWindingOrderProcess::Execute( aiScene* pScene)
 {
-    DefaultLogger::get()->debug("FlipWindingOrderProcess begin");
+    ASSIMP_LOG_DEBUG("FlipWindingOrderProcess begin");
     for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
         ProcessMesh(pScene->mMeshes[i]);
-    DefaultLogger::get()->debug("FlipWindingOrderProcess finished");
+    ASSIMP_LOG_DEBUG("FlipWindingOrderProcess finished");
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -324,8 +364,50 @@ void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh)
     for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
     {
         aiFace& face = pMesh->mFaces[a];
-        for( unsigned int b = 0; b < face.mNumIndices / 2; b++)
-            std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]);
+        for (unsigned int b = 0; b < face.mNumIndices / 2; b++) {
+            std::swap(face.mIndices[b], face.mIndices[face.mNumIndices - 1 - b]);
+        }
+    }
+
+    // invert the order of all components in this mesh anim meshes
+    for (unsigned int m = 0; m < pMesh->mNumAnimMeshes; m++) {
+        aiAnimMesh* animMesh = pMesh->mAnimMeshes[m];
+        unsigned int numVertices = animMesh->mNumVertices;
+        if (animMesh->HasPositions()) {
+            for (unsigned int a = 0; a < numVertices; a++)
+            {
+                std::swap(animMesh->mVertices[a], animMesh->mVertices[numVertices - 1 - a]);
+            }
+        }
+        if (animMesh->HasNormals()) {
+            for (unsigned int a = 0; a < numVertices; a++)
+            {
+                std::swap(animMesh->mNormals[a], animMesh->mNormals[numVertices - 1 - a]);
+            }
+        }
+        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) {
+            if (animMesh->HasTextureCoords(i)) {
+                for (unsigned int a = 0; a < numVertices; a++)
+                {
+                    std::swap(animMesh->mTextureCoords[i][a], animMesh->mTextureCoords[i][numVertices - 1 - a]);
+                }
+            }
+        }
+        if (animMesh->HasTangentsAndBitangents()) {
+            for (unsigned int a = 0; a < numVertices; a++)
+            {
+                std::swap(animMesh->mTangents[a], animMesh->mTangents[numVertices - 1 - a]);
+                std::swap(animMesh->mBitangents[a], animMesh->mBitangents[numVertices - 1 - a]);
+            }
+        }
+        for (unsigned int v = 0; v < AI_MAX_NUMBER_OF_COLOR_SETS; v++) {
+            if (animMesh->HasVertexColors(v)) {
+                for (unsigned int a = 0; a < numVertices; a++)
+                {
+                    std::swap(animMesh->mColors[v][a], animMesh->mColors[v][numVertices - 1 - a]);
+                }
+            }
+        }
     }
 }
 

+ 2 - 1
code/ConvertToLHProcess.h

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

+ 1 - 1
code/CreateAnimMesh.cpp

@@ -40,7 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ---------------------------------------------------------------------------
 */
 
-#include "CreateAnimMesh.h"
+#include <assimp/CreateAnimMesh.h>
 
 namespace Assimp    {
 

+ 398 - 0
code/D3MFExporter.cpp

@@ -0,0 +1,398 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#ifndef ASSIMP_BUILD_NO_EXPORT
+#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
+
+#include "D3MFExporter.h"
+
+#include <assimp/scene.h>
+#include <assimp/IOSystem.hpp>
+#include <assimp/IOStream.hpp>
+#include <assimp/Exporter.hpp>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/StringUtils.h>
+#include <assimp/Exceptional.h>
+
+#include "3MFXmlTags.h"
+#include "D3MFOpcPackage.h"
+
+#include <contrib/zip/src/zip.h>
+
+namespace Assimp {
+
+void ExportScene3MF( const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/ ) {
+    if ( nullptr == pIOSystem ) {
+        throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
+    }
+    D3MF::D3MFExporter myExporter( pFile, pScene );
+    if ( myExporter.validate() ) {
+        if ( pIOSystem->Exists( pFile ) ) {
+            if ( !pIOSystem->DeleteFile( pFile ) ) {
+                throw DeadlyExportError( "File exists, cannot override : " + std::string( pFile ) );
+            }
+        }
+        bool ok = myExporter.exportArchive(pFile);
+        if ( !ok ) {
+            throw DeadlyExportError( "Could not export 3MP archive: " + std::string( pFile ) );
+        }
+    }
+}
+
+namespace D3MF {
+
+D3MFExporter::D3MFExporter( const char* pFile, const aiScene* pScene )
+: mArchiveName( pFile )
+, m_zipArchive( nullptr )
+, mScene( pScene )
+, mModelOutput()
+, mRelOutput()
+, mContentOutput()
+, mBuildItems()
+, mRelations() {
+    // empty
+}
+
+D3MFExporter::~D3MFExporter() {
+    for ( size_t i = 0; i < mRelations.size(); ++i ) {
+        delete mRelations[ i ];
+    }
+    mRelations.clear();
+}
+
+bool D3MFExporter::validate() {
+    if ( mArchiveName.empty() ) {
+        return false;
+    }
+
+    if ( nullptr == mScene ) {
+        return false;
+    }
+
+    return true;
+}
+
+bool D3MFExporter::exportArchive( const char *file ) {
+    bool ok( true );
+
+    m_zipArchive = zip_open( file, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w' );
+    if ( nullptr == m_zipArchive ) {
+        return false;
+    }
+
+    ok |= exportContentTypes();
+    ok |= export3DModel();
+    ok |= exportRelations();
+
+    zip_close( m_zipArchive );
+    m_zipArchive = nullptr;
+
+    return ok;
+}
+
+bool D3MFExporter::exportContentTypes() {
+    mContentOutput.clear();
+
+    mContentOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+    mContentOutput << std::endl;
+    mContentOutput << "<Types xmlns = \"http://schemas.openxmlformats.org/package/2006/content-types\">";
+    mContentOutput << std::endl;
+    mContentOutput << "<Default Extension = \"rels\" ContentType = \"application/vnd.openxmlformats-package.relationships+xml\" />";
+    mContentOutput << std::endl;
+    mContentOutput << "<Default Extension = \"model\" ContentType = \"application/vnd.ms-package.3dmanufacturing-3dmodel+xml\" />";
+    mContentOutput << std::endl;
+    mContentOutput << "</Types>";
+    mContentOutput << std::endl;
+    exportContentTyp( XmlTag::CONTENT_TYPES_ARCHIVE );
+
+    return true;
+}
+
+bool D3MFExporter::exportRelations() {
+    mRelOutput.clear();
+
+    mRelOutput << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+    mRelOutput << std::endl;
+    mRelOutput << "<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">";
+
+    for ( size_t i = 0; i < mRelations.size(); ++i ) {
+        if ( mRelations[ i ]->target[ 0 ] == '/' ) {
+            mRelOutput << "<Relationship Target=\"" << mRelations[ i ]->target << "\" ";
+        } else {
+            mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
+        }
+        mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
+        mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
+        mRelOutput << std::endl;
+    }
+    mRelOutput << "</Relationships>";
+    mRelOutput << std::endl;
+
+    writeRelInfoToFile( "_rels", ".rels" );
+    mRelOutput.flush();
+
+    return true;
+}
+
+bool D3MFExporter::export3DModel() {
+    mModelOutput.clear();
+
+    writeHeader();
+    mModelOutput << "<" << XmlTag::model << " " << XmlTag::model_unit << "=\"millimeter\""
+            << "xmlns=\"http://schemas.microsoft.com/3dmanufacturing/core/2015/02\">"
+            << std::endl;
+    mModelOutput << "<" << XmlTag::resources << ">";
+    mModelOutput << std::endl;
+
+    writeMetaData();
+
+    writeBaseMaterials();
+
+    writeObjects();
+
+
+    mModelOutput << "</" << XmlTag::resources << ">";
+    mModelOutput << std::endl;
+    writeBuild();
+
+    mModelOutput << "</" << XmlTag::model << ">\n";
+
+    OpcPackageRelationship *info = new OpcPackageRelationship;
+    info->id = "rel0";
+    info->target = "/3D/3DModel.model";
+    info->type = XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
+    mRelations.push_back( info );
+
+    writeModelToArchive( "3D", "3DModel.model" );
+    mModelOutput.flush();
+
+    return true;
+}
+
+void D3MFExporter::writeHeader() {
+    mModelOutput << "<?xml version=\"1.0\" encoding=\"UTF - 8\"?>";
+    mModelOutput << std::endl;
+}
+
+void D3MFExporter::writeMetaData() {
+    if ( nullptr == mScene->mMetaData ) {
+        return;
+    }
+
+    const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
+    if ( 0 == numMetaEntries ) {
+        return;
+    }
+
+	const aiString *key = nullptr;
+    const aiMetadataEntry *entry(nullptr);
+    for ( size_t i = 0; i < numMetaEntries; ++i ) {
+        mScene->mMetaData->Get( i, key, entry );
+        std::string k( key->C_Str() );
+        aiString value;
+        mScene->mMetaData->Get(  k, value );
+        mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
+        mModelOutput << value.C_Str();
+        mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
+    }
+}
+
+void D3MFExporter::writeBaseMaterials() {
+    mModelOutput << "<basematerials id=\"1\">\n";
+    std::string strName, hexDiffuseColor , tmp;
+    for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
+        aiMaterial *mat = mScene->mMaterials[ i ];
+        aiString name;
+        if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
+            strName = "basemat_" + to_string( i );
+        } else {
+            strName = name.C_Str();
+        }
+        aiColor4D color;
+        if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
+            hexDiffuseColor.clear();
+            tmp.clear();
+            hexDiffuseColor = "#";
+            
+            tmp = DecimalToHexa( color.r );
+            hexDiffuseColor += tmp;
+            tmp = DecimalToHexa( color.g );
+            hexDiffuseColor += tmp;
+            tmp = DecimalToHexa( color.b );
+            hexDiffuseColor += tmp;
+            tmp = DecimalToHexa( color.a );
+            hexDiffuseColor += tmp;
+        } else {
+            hexDiffuseColor = "#FFFFFFFF";
+        }
+
+        mModelOutput << "<base name=\""+strName+"\" "+" displaycolor=\""+hexDiffuseColor+"\" />\n";
+    }
+    mModelOutput << "</basematerials>\n";
+}
+
+void D3MFExporter::writeObjects() {
+    if ( nullptr == mScene->mRootNode ) {
+        return;
+    }
+
+    aiNode *root = mScene->mRootNode;
+    for ( unsigned int i = 0; i < root->mNumChildren; ++i ) {
+        aiNode *currentNode( root->mChildren[ i ] );
+        if ( nullptr == currentNode ) {
+            continue;
+        }
+        mModelOutput << "<" << XmlTag::object << " id=\"" << currentNode->mName.C_Str() << "\" type=\"model\">";
+        mModelOutput << std::endl;
+        for ( unsigned int j = 0; j < currentNode->mNumMeshes; ++j ) {
+            aiMesh *currentMesh = mScene->mMeshes[ currentNode->mMeshes[ j ] ];
+            if ( nullptr == currentMesh ) {
+                continue;
+            }
+            writeMesh( currentMesh );
+        }
+        mBuildItems.push_back( i );
+
+        mModelOutput << "</" << XmlTag::object << ">";
+        mModelOutput << std::endl;
+    }
+}
+
+void D3MFExporter::writeMesh( aiMesh *mesh ) {
+    if ( nullptr == mesh ) {
+        return;
+    }
+
+    mModelOutput << "<" << XmlTag::mesh << ">" << std::endl;
+    mModelOutput << "<" << XmlTag::vertices << ">" << std::endl;
+    for ( unsigned int i = 0; i < mesh->mNumVertices; ++i ) {
+        writeVertex( mesh->mVertices[ i ] );
+    }
+    mModelOutput << "</" << XmlTag::vertices << ">" << std::endl;
+
+    const unsigned int matIdx( mesh->mMaterialIndex );
+
+    writeFaces( mesh, matIdx );
+
+    mModelOutput << "</" << XmlTag::mesh << ">" << std::endl;
+}
+
+void D3MFExporter::writeVertex( const aiVector3D &pos ) {
+    mModelOutput << "<" << XmlTag::vertex << " x=\"" << pos.x << "\" y=\"" << pos.y << "\" z=\"" << pos.z << "\" />";
+    mModelOutput << std::endl;
+}
+
+void D3MFExporter::writeFaces( aiMesh *mesh, unsigned int matIdx ) {
+    if ( nullptr == mesh ) {
+        return;
+    }
+
+    if ( !mesh->HasFaces() ) {
+        return;
+    }
+    mModelOutput << "<" << XmlTag::triangles << ">" << std::endl;
+    for ( unsigned int i = 0; i < mesh->mNumFaces; ++i ) {
+        aiFace &currentFace = mesh->mFaces[ i ];
+        mModelOutput << "<" << XmlTag::triangle << " v1=\"" << currentFace.mIndices[ 0 ] << "\" v2=\""
+                << currentFace.mIndices[ 1 ] << "\" v3=\"" << currentFace.mIndices[ 2 ]
+                << "\" pid=\"1\" p1=\""+to_string(matIdx)+"\" />";
+        mModelOutput << std::endl;
+    }
+    mModelOutput << "</" << XmlTag::triangles << ">";
+    mModelOutput << std::endl;
+}
+
+void D3MFExporter::writeBuild() {
+    mModelOutput << "<" << XmlTag::build << ">" << std::endl;
+
+    for ( size_t i = 0; i < mBuildItems.size(); ++i ) {
+        mModelOutput << "<" << XmlTag::item << " objectid=\"" << i + 1 << "\"/>";
+        mModelOutput << std::endl;
+    }
+    mModelOutput << "</" << XmlTag::build << ">";
+    mModelOutput << std::endl;
+}
+
+void D3MFExporter::exportContentTyp( const std::string &filename ) {
+    if ( nullptr == m_zipArchive ) {
+        throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
+    }
+    const std::string entry = filename;
+    zip_entry_open( m_zipArchive, entry.c_str() );
+
+    const std::string &exportTxt( mContentOutput.str() );
+    zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
+
+    zip_entry_close( m_zipArchive );
+}
+
+void D3MFExporter::writeModelToArchive( const std::string &folder, const std::string &modelName ) {
+    if ( nullptr == m_zipArchive ) {
+        throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
+    }
+    const std::string entry = folder + "/" + modelName;
+    zip_entry_open( m_zipArchive, entry.c_str() );
+
+    const std::string &exportTxt( mModelOutput.str() );
+    zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
+
+    zip_entry_close( m_zipArchive );
+}
+
+void D3MFExporter::writeRelInfoToFile( const std::string &folder, const std::string &relName ) {
+    if ( nullptr == m_zipArchive ) {
+        throw DeadlyExportError( "3MF-Export: Zip archive not valid, nullptr." );
+    }
+    const std::string entry = folder + "/" + relName;
+    zip_entry_open( m_zipArchive, entry.c_str() );
+
+    const std::string &exportTxt( mRelOutput.str() );
+    zip_entry_write( m_zipArchive, exportTxt.c_str(), exportTxt.size() );
+
+    zip_entry_close( m_zipArchive );
+}
+
+
+} // Namespace D3MF
+} // Namespace Assimp
+
+#endif // ASSIMP_BUILD_NO_3MF_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT

+ 106 - 0
code/D3MFExporter.h

@@ -0,0 +1,106 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+#pragma once
+
+#include <memory>
+#include <sstream>
+#include <vector>
+#include <assimp/vector3.h>
+
+struct aiScene;
+struct aiNode;
+struct aiMaterial;
+struct aiMesh;
+
+struct zip_t;
+
+namespace Assimp {
+
+class IOStream;
+
+namespace D3MF {
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
+
+struct OpcPackageRelationship;
+
+class D3MFExporter {
+public:
+    D3MFExporter( const char* pFile, const aiScene* pScene );
+    ~D3MFExporter();
+    bool validate();
+    bool exportArchive( const char *file );
+    bool exportContentTypes();
+    bool exportRelations();
+    bool export3DModel();
+
+protected:
+    void writeHeader();
+    void writeMetaData();
+    void writeBaseMaterials();
+    void writeObjects();
+    void writeMesh( aiMesh *mesh );
+    void writeVertex( const aiVector3D &pos );
+    void writeFaces( aiMesh *mesh, unsigned int matIdx );
+    void writeBuild();
+    void exportContentTyp( const std::string &filename );
+    void writeModelToArchive( const std::string &folder, const std::string &modelName );
+    void writeRelInfoToFile( const std::string &folder, const std::string &relName );
+
+private:
+    std::string mArchiveName;
+    zip_t *m_zipArchive;
+    const aiScene *mScene;
+    std::ostringstream mModelOutput;
+    std::ostringstream mRelOutput;
+    std::ostringstream mContentOutput;
+    std::vector<unsigned int> mBuildItems;
+    std::vector<OpcPackageRelationship*> mRelations;
+};
+
+#endif // ASSIMP_BUILD_NO_3MF_EXPORTER
+#endif // ASSIMP_BUILD_NO_EXPORT
+
+} // Namespace D3MF
+} // Namespace Assimp
+

+ 252 - 144
code/D3MFImporter.cpp

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -47,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/IOSystem.hpp>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/importerdesc.h>
-#include "StringComparison.h"
-#include "StringUtils.h"
+#include <assimp/StringComparison.h>
+#include <assimp/StringUtils.h>
 
 #include <string>
 #include <vector>
@@ -57,98 +58,101 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <memory>
 
 #include "D3MFOpcPackage.h"
-#include <contrib/unzip/unzip.h>
-#include "irrXMLWrapper.h"
+#include <unzip.h>
+#include <assimp/irrXMLWrapper.h>
+#include "3MFXmlTags.h"
+#include <assimp/fast_atof.h>
+
+#include <iomanip>
 
 namespace Assimp {
 namespace D3MF {
 
-namespace XmlTag {
-    static const std::string model     = "model";
-    static const std::string metadata  = "metadata";
-    static const std::string resources = "resources";
-    static const std::string object    = "object";
-    static const std::string mesh      = "mesh";
-    static const std::string vertices  = "vertices";
-    static const std::string vertex    = "vertex";
-    static const std::string triangles = "triangles";
-    static const std::string triangle  = "triangle";
-    static const std::string x         = "x";
-    static const std::string y         = "y";
-    static const std::string z         = "z";
-    static const std::string v1        = "v1";
-    static const std::string v2        = "v2";
-    static const std::string v3        = "v3";
-    static const std::string id        = "id";
-    static const std::string name      = "name";
-    static const std::string type      = "type";
-    static const std::string build     = "build";
-    static const std::string item      = "item";
-    static const std::string objectid  = "objectid";
-    static const std::string transform = "transform";
-}
-
-
-class XmlSerializer
-{
+class XmlSerializer {
 public:
-    XmlSerializer(XmlReader* xmlReader)
-        : xmlReader(xmlReader)
-    {
+    using MatArray = std::vector<aiMaterial*>;
+    using MatId2MatArray = std::map<unsigned int, std::vector<unsigned int>>;
 
+    XmlSerializer(XmlReader* xmlReader)
+    : mMeshes()
+    , mMatArray()
+    , mActiveMatGroup( 99999999 )
+    , mMatId2MatArray()
+    , xmlReader(xmlReader){
+		// empty
     }
 
-    void ImportXml(aiScene* scene)
-    {
+    ~XmlSerializer() {
+        // empty
+    }
 
-        scene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
+    void ImportXml(aiScene* scene) {
+        if ( nullptr == scene ) {
+            return;
+        }
 
         scene->mRootNode = new aiNode();
         std::vector<aiNode*> children;
 
-        while(ReadToEndElement(D3MF::XmlTag::model))
-        {
-
-            if(xmlReader->getNodeName() == D3MF::XmlTag::object)
-            {
+        std::string nodeName;
+        while(ReadToEndElement(D3MF::XmlTag::model)) {
+            nodeName = xmlReader->getNodeName();
+            if( nodeName == D3MF::XmlTag::object) {
                 children.push_back(ReadObject(scene));
-            }
-            else if(xmlReader->getNodeName() == D3MF::XmlTag::build)
-            {
-
+            } else if( nodeName == D3MF::XmlTag::build) {
+                // 
+            } else if ( nodeName == D3MF::XmlTag::basematerials ) {
+                ReadBaseMaterials();
+            } else if ( nodeName == D3MF::XmlTag::meta ) {
+                ReadMetadata();
             }
         }
 
-        if(scene->mRootNode->mName.length == 0)
-            scene->mRootNode->mName.Set("3MF");
+        if ( scene->mRootNode->mName.length == 0 ) {
+            scene->mRootNode->mName.Set( "3MF" );
+        }
 
+        // import the metadata
+        if ( !mMetaData.empty() ) {
+            const size_t numMeta( mMetaData.size() );
+            scene->mMetaData = aiMetadata::Alloc(static_cast<unsigned int>( numMeta ) );
+            for ( size_t i = 0; i < numMeta; ++i ) {
+                aiString val( mMetaData[ i ].value );
+                scene->mMetaData->Set(static_cast<unsigned int>( i ), mMetaData[ i ].name, val );
+            }
+        }
 
-        scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
+        // import the meshes
+        scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
         scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
+        std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
 
-        std::copy(meshes.begin(), meshes.end(), scene->mMeshes);
+        // import the materials
+        scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
+        if ( 0 != scene->mNumMaterials ) {
+            scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
+            std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
+        }
 
+        // create the scenegraph
         scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
         scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
-
         std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
-
     }
 
 private:
-    aiNode* ReadObject(aiScene* scene)
-    {
-        ScopeGuard<aiNode> node(new aiNode());
+    aiNode* ReadObject(aiScene* scene) {
+        std::unique_ptr<aiNode> node(new aiNode());
 
         std::vector<unsigned long> meshIds;
 
         const char *attrib( nullptr );
         std::string name, type;
-        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() );
+        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
         if ( nullptr != attrib ) {
             name = attrib;
         }
-        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() );
+        attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
         if ( nullptr != attrib ) {
             type = attrib;
         }
@@ -156,19 +160,16 @@ private:
         node->mParent = scene->mRootNode;
         node->mName.Set(name);
 
-        size_t meshIdx = meshes.size();
+        size_t meshIdx = mMeshes.size();
 
-        while(ReadToEndElement(D3MF::XmlTag::object))
-        {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::mesh)
-            {
+        while(ReadToEndElement(D3MF::XmlTag::object)) {
+            if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
                 auto mesh = ReadMesh();
 
                 mesh->mName.Set(name);
-                meshes.push_back(mesh);
+                mMeshes.push_back(mesh);
                 meshIds.push_back(static_cast<unsigned long>(meshIdx));
-                meshIdx++;
-
+                ++meshIdx;
             }
         }
 
@@ -178,39 +179,41 @@ private:
 
         std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
 
-        return node.dismiss();
-
+        return node.release();
     }
 
-    aiMesh* ReadMesh()
-    {
+    aiMesh *ReadMesh() {
         aiMesh* mesh = new aiMesh();
-
-        while(ReadToEndElement(D3MF::XmlTag::mesh))
-        {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::vertices)
-            {
+        while(ReadToEndElement(D3MF::XmlTag::mesh)) {
+            if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
                 ImportVertices(mesh);
-            }
-            else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles)
-            {
+            } else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
                 ImportTriangles(mesh);
             }
-
         }
 
-
         return mesh;
     }
 
-    void ImportVertices(aiMesh* mesh)
-    {
-        std::vector<aiVector3D> vertices;
+    void ReadMetadata() {
+        const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
+        xmlReader->read();
+        const std::string value = xmlReader->getNodeData();
 
-        while(ReadToEndElement(D3MF::XmlTag::vertices))
-        {
-            if(xmlReader->getNodeName() == D3MF::XmlTag::vertex)
-            {
+        if ( name.empty() ) {
+            return;
+        }
+
+        MetaEntry entry;
+        entry.name = name;
+        entry.value = value;
+        mMetaData.push_back( entry );
+    }
+
+    void ImportVertices(aiMesh* mesh) {
+        std::vector<aiVector3D> vertices;
+        while(ReadToEndElement(D3MF::XmlTag::vertices)) {
+            if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
                 vertices.push_back(ReadVertex());
             }
         }
@@ -218,10 +221,9 @@ private:
         mesh->mVertices = new aiVector3D[mesh->mNumVertices];
 
         std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
-
     }
-    aiVector3D ReadVertex()
-    {
+
+    aiVector3D ReadVertex() {
         aiVector3D vertex;
 
         vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
@@ -231,16 +233,18 @@ private:
         return vertex;
     }
 
-    void ImportTriangles(aiMesh* mesh)
-    {
+    void ImportTriangles(aiMesh* mesh) {
          std::vector<aiFace> faces;
 
-
-         while(ReadToEndElement(D3MF::XmlTag::triangles))
-         {
-             if(xmlReader->getNodeName() == D3MF::XmlTag::triangle)
-             {
+         while(ReadToEndElement(D3MF::XmlTag::triangles)) {
+             const std::string nodeName( xmlReader->getNodeName() );
+             if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
                  faces.push_back(ReadTriangle());
+                 const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) );
+                 if ( nullptr != pidToken ) {
+                     int matIdx( std::atoi( pidToken ) );
+                     mesh->mMaterialIndex = matIdx;
+                 }
              }
          }
 
@@ -251,8 +255,7 @@ private:
         std::copy(faces.begin(), faces.end(), mesh->mFaces);
     }
 
-    aiFace ReadTriangle()
-    {
+    aiFace ReadTriangle() {
         aiFace face;
 
         face.mNumIndices = 3;
@@ -264,52 +267,158 @@ private:
         return face;
     }
 
-private:
+    void ReadBaseMaterials() {
+        std::vector<unsigned int> MatIdArray;
+        const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) );
+        if ( nullptr != baseMaterialId ) {
+            unsigned int id = std::atoi( baseMaterialId );
+            const size_t newMatIdx( mMatArray.size() );
+            if ( id != mActiveMatGroup ) {
+                mActiveMatGroup = id;
+                MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) );
+                if ( mMatId2MatArray.end() == it ) {
+                    MatIdArray.clear();
+                    mMatId2MatArray[ id ] = MatIdArray;
+                } else {
+                    MatIdArray = it->second;
+                }
+            }
+            MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
+            mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
+        }
 
-    bool ReadToStartElement(const std::string& startTag)
-    {
-        while(xmlReader->read())
-        {
-            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && xmlReader->getNodeName() == startTag)
-            {
-                return true;
+        while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
+            mMatArray.push_back( readMaterialDef() );
+        }
+    }
+
+    bool parseColor( const char *color, aiColor4D &diffuse ) {
+        if ( nullptr == color ) {
+            return false;
+        }
+
+        //format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
+        const size_t len( strlen( color ) );
+        if ( 9 != len && 7 != len) {
+            return false;
+        }
+
+        const char *buf( color );
+        if ( '#' != *buf ) {
+            return false;
+        }
+        ++buf;
+        char comp[ 3 ] = { 0,0,'\0' };
+
+        comp[ 0 ] = *buf;
+        ++buf;
+        comp[ 1 ] = *buf;
+        ++buf;
+        diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
+
+
+        comp[ 0 ] = *buf;
+        ++buf;
+        comp[ 1 ] = *buf;
+        ++buf;
+        diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
+
+        comp[ 0 ] = *buf;
+        ++buf;
+        comp[ 1 ] = *buf;
+        ++buf;
+        diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
+
+        if(7 == len)
+            return true;
+        comp[ 0 ] = *buf;
+        ++buf;
+        comp[ 1 ] = *buf;
+        ++buf;
+        diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / ai_real(255.0);
+
+        return true;
+    }
+
+    void assignDiffuseColor( aiMaterial *mat ) {
+        const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
+        aiColor4D diffuse;
+        if ( parseColor( color, diffuse ) ) {
+            mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
+        }
+
+    }
+    aiMaterial *readMaterialDef() {
+        aiMaterial *mat( nullptr );
+        const char *name( nullptr );
+        const std::string nodeName( xmlReader->getNodeName() );
+        if ( nodeName == D3MF::XmlTag::basematerials_base ) {
+            name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
+            std::string stdMatName;
+            aiString matName;
+            std::string strId( to_string( mActiveMatGroup ) );
+            stdMatName += "id";
+            stdMatName += strId;
+            stdMatName += "_";
+            if ( nullptr != name ) {
+                stdMatName += std::string( name );
+            } else {
+                stdMatName += "basemat";
             }
-            else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END &&
-                     xmlReader->getNodeName() == startTag)
-            {
+            matName.Set( stdMatName );
+
+            mat = new aiMaterial;
+            mat->AddProperty( &matName, AI_MATKEY_NAME );
+
+            assignDiffuseColor( mat );
+        }
+
+        return mat;
+    }
+
+private:
+    bool ReadToStartElement(const std::string& startTag) {
+        while(xmlReader->read()) {
+            const std::string &nodeName( xmlReader->getNodeName() );
+            if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
+                return true;
+            } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
                 return false;
             }
         }
-        //DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
+
         return false;
     }
 
-    bool ReadToEndElement(const std::string& closeTag)
-    {
-        while(xmlReader->read())
-        {
+    bool ReadToEndElement(const std::string& closeTag) {
+        while(xmlReader->read()) {
+            const std::string &nodeName( xmlReader->getNodeName() );
             if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
                 return true;
-            }
-            else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END
-                     && xmlReader->getNodeName() == closeTag)
-            {
+            } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
                 return false;
             }
         }
-        DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
+        ASSIMP_LOG_ERROR("unexpected EOF, expected closing <" + closeTag + "> tag");
+
         return false;
     }
 
-
 private:
-    std::vector<aiMesh*> meshes;
+    struct MetaEntry {
+        std::string name;
+        std::string value;
+    };
+    std::vector<MetaEntry> mMetaData;
+    std::vector<aiMesh*> mMeshes;
+    MatArray mMatArray;
+    unsigned int mActiveMatGroup;
+    MatId2MatArray mMatId2MatArray;
     XmlReader* xmlReader;
 };
 
 } //namespace D3MF
 
-
 static const aiImporterDesc desc = {
     "3mf Importer",
     "",
@@ -323,44 +432,43 @@ static const aiImporterDesc desc = {
     "3mf"
 };
 
-
 D3MFImporter::D3MFImporter()
-{
-
+: BaseImporter() {
+    // empty
 }
 
-D3MFImporter::~D3MFImporter()
-{
-
+D3MFImporter::~D3MFImporter() {
+    // empty
 }
 
-bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const
-{
-    const std::string extension = GetExtension(pFile);
-    if(extension == "3mf") {
+bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bool checkSig) const {
+    const std::string extension( GetExtension( filename ) );
+    if(extension == desc.mFileExtensions ) {
         return true;
     } else if ( !extension.length() || checkSig ) {
-        if (nullptr == pIOHandler ) {
-            return true;
+        if ( nullptr == pIOHandler ) {
+            return false;
         }
+        if ( !D3MF::D3MFOpcPackage::isZipArchive( pIOHandler, filename ) ) {
+            return false;
+        }
+        D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
+        return opcPackage.validate();
     }
 
     return false;
 }
 
-void D3MFImporter::SetupProperties(const Importer *pImp)
-{
-
+void D3MFImporter::SetupProperties(const Importer * /*pImp*/) {
+    // empty
 }
 
-const aiImporterDesc *D3MFImporter::GetInfo() const
-{
+const aiImporterDesc *D3MFImporter::GetInfo() const {
     return &desc;
 }
 
-void D3MFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler)
-{
-    D3MF::D3MFOpcPackage opcPackage(pIOHandler, pFile);
+void D3MFImporter::InternReadFile( const std::string &filename, aiScene *pScene, IOSystem *pIOHandler ) {
+    D3MF::D3MFOpcPackage opcPackage(pIOHandler, filename);
 
     std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
     std::unique_ptr<D3MF::XmlReader> xmlReader(irr::io::createIrrXMLReader(xmlStream.get()));

+ 8 - 9
code/D3MFImporter.h

@@ -2,7 +2,8 @@
 Open Asset Import Library (assimp)
 ----------------------------------------------------------------------
 
-Copyright (c) 2006-2017, assimp team
+Copyright (c) 2006-2019, assimp team
+
 
 All rights reserved.
 
@@ -42,25 +43,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_D3MFLOADER_H_INCLUDED
 #define AI_D3MFLOADER_H_INCLUDED
 
-#include "BaseImporter.h"
+#include <assimp/BaseImporter.h>
 
 namespace Assimp {
 
-class D3MFImporter : public BaseImporter
-{
+class D3MFImporter : public BaseImporter {
 public:
+    // BaseImporter interface
     D3MFImporter();
     ~D3MFImporter();
-
-    // BaseImporter interface
-public:
     bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
     void SetupProperties(const Importer *pImp);
     const aiImporterDesc *GetInfo() const;
 
 protected:
     void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
-
 };
-}
+
+} // Namespace Assimp
+
 #endif // AI_D3MFLOADER_H_INCLUDED

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