ソースを参照

Merge branch 'master' of https://github.com/assimp/assimp

Marco Di Benedetto 7 年 前
コミット
d33cc8ac5a
100 ファイル変更2127 行追加931 行削除
  1. 3 0
      .gitignore
  2. 29 6
      .travis.sh
  3. 17 11
      .travis.yml
  4. 27 5
      CMakeLists.txt
  5. 8 0
      CREDITS
  6. 2 2
      Readme.md
  7. 43 22
      appveyor.yml
  8. 1 1
      assimp.pc.in
  9. 2 2
      cmake-modules/CoverallsGenerateGcov.cmake
  10. 7 2
      code/3DSExporter.cpp
  11. 7 10
      code/3DSExporter.h
  12. 9 7
      code/3DSHelper.h
  13. 89 0
      code/3MFXmlTags.h
  14. 2 2
      code/AMFImporter.hpp
  15. 1 1
      code/AMFImporter_Node.hpp
  16. 6 3
      code/AMFImporter_Postprocess.cpp
  17. 1 0
      code/ASELoader.cpp
  18. 2 1
      code/AssbinExporter.cpp
  19. 11 0
      code/AssbinLoader.cpp
  20. 1 1
      code/AssxmlExporter.cpp
  21. 41 21
      code/B3DImporter.cpp
  22. 5 4
      code/B3DImporter.h
  23. 3 4
      code/BaseImporter.cpp
  24. 0 36
      code/BaseImporter.h
  25. 2 2
      code/Bitmap.cpp
  26. 6 0
      code/BlenderDNA.h
  27. 5 2
      code/BlenderDNA.inl
  28. 1 1
      code/BlenderIntermediate.h
  29. 7 7
      code/BlenderLoader.cpp
  30. 3 1
      code/BlenderModifier.cpp
  31. 31 12
      code/BlenderScene.cpp
  32. 8 0
      code/BlenderScene.h
  33. 4 4
      code/C4DImporter.cpp
  34. 42 5
      code/CMakeLists.txt
  35. 260 8
      code/ColladaExporter.cpp
  36. 8 1
      code/ColladaExporter.h
  37. 1 1
      code/ColladaHelper.h
  38. 6 1
      code/ColladaLoader.cpp
  39. 2 3
      code/ColladaParser.cpp
  40. 1 1
      code/ColladaParser.h
  41. 328 0
      code/D3MFExporter.cpp
  42. 103 0
      code/D3MFExporter.h
  43. 29 66
      code/D3MFImporter.cpp
  44. 5 7
      code/D3MFImporter.h
  45. 78 141
      code/D3MFOpcPackage.cpp
  46. 12 7
      code/D3MFOpcPackage.h
  47. 1 1
      code/DeboneProcess.h
  48. 2 1
      code/DefaultIOStream.cpp
  49. 75 31
      code/DefaultIOSystem.cpp
  50. 147 0
      code/EmbedTexturesProcess.cpp
  51. 84 0
      code/EmbedTexturesProcess.h
  52. 24 13
      code/Exporter.cpp
  53. 23 22
      code/FBXBinaryTokenizer.cpp
  54. 38 38
      code/FBXConverter.cpp
  55. 2 2
      code/FBXDocument.cpp
  56. 4 4
      code/FBXImportSettings.h
  57. 1 1
      code/FBXImporter.cpp
  58. 28 28
      code/FBXMaterial.cpp
  59. 8 2
      code/FBXMeshGeometry.cpp
  60. 9 0
      code/FBXParser.cpp
  61. 2 0
      code/FBXParser.h
  62. 26 17
      code/FIReader.cpp
  63. 19 4
      code/FIReader.hpp
  64. 76 36
      code/FindDegenerates.cpp
  65. 40 19
      code/FindDegenerates.h
  66. 15 10
      code/FindInvalidDataProcess.cpp
  67. 1 4
      code/FixNormalsStep.h
  68. 1 1
      code/IFCBoolean.cpp
  69. 51 100
      code/IFCCurve.cpp
  70. 5 5
      code/IFCGeometry.cpp
  71. 1 40
      code/IFCOpenings.cpp
  72. 4 3
      code/IFCReaderGen1.cpp
  73. 1 1
      code/IRRLoader.cpp
  74. 2 4
      code/Importer.cpp
  75. 1 0
      code/ImproveCacheLocality.cpp
  76. 1 3
      code/LWOAnimation.cpp
  77. 1 1
      code/LWOMaterial.cpp
  78. 1 1
      code/LWSLoader.cpp
  79. 8 12
      code/LineSplitter.h
  80. 4 4
      code/LogAux.h
  81. 3 5
      code/MD2Loader.cpp
  82. 3 3
      code/MD3Loader.cpp
  83. 1 1
      code/MD5Loader.h
  84. 6 11
      code/MDCLoader.cpp
  85. 7 0
      code/MDLLoader.cpp
  86. 13 13
      code/MDLMaterialLoader.cpp
  87. 8 8
      code/MMDImporter.cpp
  88. 1 1
      code/MMDPmxParser.cpp
  89. 1 0
      code/MMDPmxParser.h
  90. 1 1
      code/MMDVmdParser.h
  91. 11 8
      code/NFFLoader.cpp
  92. 45 15
      code/ObjExporter.cpp
  93. 2 2
      code/ObjExporter.h
  94. 13 10
      code/ObjFileImporter.cpp
  95. 12 16
      code/ObjFileParser.cpp
  96. 2 1
      code/ObjFileParser.h
  97. 1 1
      code/OgreMaterial.cpp
  98. 1 1
      code/OpenGEXExporter.cpp
  99. 25 11
      code/OpenGEXImporter.cpp
  100. 6 4
      code/OptimizeGraph.cpp

+ 3 - 0
.gitignore

@@ -60,6 +60,7 @@ test/gtest/src/gtest-stamp/Debug/gtest-build
 *.lib
 *.lib
 test/gtest/src/gtest-stamp/Debug/
 test/gtest/src/gtest-stamp/Debug/
 tools/assimp_view/assimp_viewer.vcxproj.user
 tools/assimp_view/assimp_viewer.vcxproj.user
+*.pyc
 
 
 # Unix editor backups
 # Unix editor backups
 *~
 *~
@@ -81,3 +82,5 @@ lib64/assimp-vc120-mtd.ilk
 lib64/assimp-vc120-mtd.exp
 lib64/assimp-vc120-mtd.exp
 lib64/assimp-vc120-mt.exp
 lib64/assimp-vc120-mt.exp
 xcuserdata
 xcuserdata
+
+cmake-build-debug

+ 29 - 6
.travis.sh

@@ -1,5 +1,11 @@
-function generate()
-{
+#---------------------------------------------------------------------------
+#Open Asset Import Library (assimp)
+#---------------------------------------------------------------------------
+# Copyright (c) 2006-2017, assimp team
+#
+# License see LICENSE file
+#
+function generate() {
     OPTIONS="-DASSIMP_WERROR=ON"
     OPTIONS="-DASSIMP_WERROR=ON"
 
 
     if [ "$DISABLE_EXPORTERS" = "YES" ] ; then
     if [ "$DISABLE_EXPORTERS" = "YES" ] ; then
@@ -26,18 +32,35 @@ function generate()
         OPTIONS="$OPTIONS -DASSIMP_ASAN=OFF"
         OPTIONS="$OPTIONS -DASSIMP_ASAN=OFF"
     fi
     fi
 
 
+    if [ "$UBSAN" = "ON" ] ; then
+        OPTIONS="$OPTIONS -DASSIMP_UBSAN=ON"
+    fi
+
     cmake -G "Unix Makefiles" $OPTIONS
     cmake -G "Unix Makefiles" $OPTIONS
 }
 }
-
+# build and run unittests, if not android
 if [ $ANDROID ]; then
 if [ $ANDROID ]; then
     ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
     ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni
 fi
 fi
 if [ "$TRAVIS_OS_NAME" = "linux" ]; then
 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 \
     generate \
     && make -j4 \
     && make -j4 \
     && sudo make install \
     && sudo make install \
     && sudo ldconfig \
     && 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
 fi

+ 17 - 11
.travis.yml

@@ -4,7 +4,7 @@ language: cpp
 cache: ccache
 cache: ccache
 
 
 before_install:
 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" = "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 [ "$TRAVIS_OS_NAME" = "osx" ];  then
        if brew ls --versions cmake > /dev/null; then
        if brew ls --versions cmake > /dev/null; then
          echo cmake already installed.;
          echo cmake already installed.;
@@ -18,10 +18,6 @@ before_install:
   # install latest LCOV (1.9 was failing)
   # 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
   - 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:
 os:
   - linux
   - linux
 
 
@@ -37,17 +33,27 @@ env:
 
 
 matrix:
 matrix:
   include:
   include:
-    - os: linux
-      compiler: gcc
-      env: DISABLE_EXPORTERS=YES ENABLE_COVERALLS=ON
-    - os: linux
-      compiler: gcc
-      env: SHARED_BUILD=ON
+    # disabled until clang 5.0 analyzer issues are fixed
+    # - os: linux
+    #   compiler: clang
+    #   env: ANALYZE=ON
     - os: linux
     - os: linux
       compiler: clang
       compiler: clang
       env: ASAN=ON
       env: ASAN=ON
     - os: linux
     - os: linux
       compiler: clang
       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: DISABLE_EXPORTERS=YES ENABLE_COVERALLS=ON
+    - os: linux
+      compiler: gcc
       env: SHARED_BUILD=ON
       env: SHARED_BUILD=ON
 
 
 install:
 install:

+ 27 - 5
CMakeLists.txt

@@ -42,6 +42,10 @@ OPTION( BUILD_SHARED_LIBS
   "Build package with shared libraries."
   "Build package with shared libraries."
   ON
   ON
 )
 )
+OPTION( BUILD_FRAMEWORK
+  "Build package as Mac OS X Framework bundle."
+  OFF
+)
 OPTION( ASSIMP_DOUBLE_PRECISION
 OPTION( ASSIMP_DOUBLE_PRECISION
   "Set to ON to enable double precision processing"
   "Set to ON to enable double precision processing"
   OFF
   OFF
@@ -86,6 +90,10 @@ OPTION ( ASSIMP_ASAN
   "Enable AddressSanitizer."
   "Enable AddressSanitizer."
   OFF
   OFF
 )
 )
+OPTION ( ASSIMP_UBSAN
+  "Enable Undefined Behavior sanitizer."
+  OFF
+)
 OPTION ( SYSTEM_IRRXML
 OPTION ( SYSTEM_IRRXML
   "Use system installed Irrlicht/IrrXML library."
   "Use system installed Irrlicht/IrrXML library."
   OFF
   OFF
@@ -95,6 +103,7 @@ OPTION ( BUILD_DOCS
   OFF
   OFF
 )
 )
 
 
+# Use subset of Windows.h
 if (WIN32)
 if (WIN32)
   ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
   ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN )
 endif()
 endif()
@@ -107,6 +116,11 @@ IF(MSVC)
   )
   )
 ENDIF(MSVC)
 ENDIF(MSVC)
 
 
+IF (BUILD_FRAMEWORK)
+  SET (BUILD_SHARED_LIBS ON)
+  MESSAGE(STATUS "Framework bundle building enabled")
+ENDIF(BUILD_FRAMEWORK)
+
 IF(NOT BUILD_SHARED_LIBS)
 IF(NOT BUILD_SHARED_LIBS)
   MESSAGE(STATUS "Shared libraries disabled")
   MESSAGE(STATUS "Shared libraries disabled")
   SET(LINK_SEARCH_START_STATIC TRUE)
   SET(LINK_SEARCH_START_STATIC TRUE)
@@ -116,8 +130,8 @@ ENDIF(NOT BUILD_SHARED_LIBS)
 
 
 # Define here the needed parameters
 # Define here the needed parameters
 SET (ASSIMP_VERSION_MAJOR 4)
 SET (ASSIMP_VERSION_MAJOR 4)
-SET (ASSIMP_VERSION_MINOR 0)
-SET (ASSIMP_VERSION_PATCH 1)
+SET (ASSIMP_VERSION_MINOR 1)
+SET (ASSIMP_VERSION_PATCH 0)
 SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
 SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH})
 SET (ASSIMP_SOVERSION 4)
 SET (ASSIMP_SOVERSION 4)
 SET (PROJECT_VERSION "${ASSIMP_VERSION}")
 SET (PROJECT_VERSION "${ASSIMP_VERSION}")
@@ -179,15 +193,17 @@ SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
 
 
 IF( UNIX )
 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
   # 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 )
+  IF( ${OPERATING_SYSTEM} MATCHES "Android")
+  ELSE()
+    IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
+      #ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
+    ENDIF()
   ENDIF()
   ENDIF()
 
 
   # Use GNUInstallDirs for Unix predefined directories
   # Use GNUInstallDirs for Unix predefined directories
   INCLUDE(GNUInstallDirs)
   INCLUDE(GNUInstallDirs)
 ENDIF( UNIX )
 ENDIF( UNIX )
 
 
-
 # Grouped compiler settings
 # Grouped compiler settings
 IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
 IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
   # hide all not-exported symbols
   # hide all not-exported symbols
@@ -239,6 +255,12 @@ if (ASSIMP_ASAN)
     SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
     SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
 endif()
 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 (FindPkgMacros)
 INCLUDE (PrecompiledHeader)
 INCLUDE (PrecompiledHeader)
 
 

+ 8 - 0
CREDITS

@@ -158,3 +158,11 @@ Contributed X File exporter
 Contributed Step (stp) exporter
 Contributed Step (stp) exporter
 
 
 For a more detailed list just check: https://github.com/assimp/assimp/network/members
 For a more detailed list just check: https://github.com/assimp/assimp/network/members
+
+Patreons:
+- migenius
+- Marcus
+- Cort
+- elect
+- Steffen
+

+ 2 - 2
Readme.md

@@ -119,8 +119,8 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak
 * [.NET](port/AssimpNET/Readme.md)
 * [.NET](port/AssimpNET/Readme.md)
 * [Pascal](port/AssimpPascal/Readme.md)
 * [Pascal](port/AssimpPascal/Readme.md)
 * [Javascript (Alpha)](https://github.com/makc/assimp2json)
 * [Javascript (Alpha)](https://github.com/makc/assimp2json)
-* [Unity 3d Plugin] (https://www.assetstore.unity3d.com/en/#!/content/91777)
-* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (currently supported obj, ply, stl, ~collada)
+* [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
+* [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (currently supported obj, ply, stl, collada, md2)
 
 
 ### Other tools ###
 ### Other tools ###
 [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.
 [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.

+ 43 - 22
appveyor.yml

@@ -10,33 +10,54 @@ branches:
   only:
   only:
     - master
     - master
 
 
+matrix:
+  fast_finish: true
+    
+image:
+  - Visual Studio 2013
+  - Visual Studio 2015
+  - Visual Studio 2017
+    
 platform:
 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:
 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 -DASSIMP_WERROR=ON -G "Visual Studio %Configuration% Win64")
-- if "%platform%" equ "x86" (cmake CMakeLists.txt -DASSIMP_WERROR=ON -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%"
+  
+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:
 after_build:
-  - 7z a assimp.7z c:\projects\assimp\bin\release\* c:\projects\assimp\lib\release\*
+  - 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:
 artifacts:
   - path: assimp.7z
   - path: assimp.7z
     name: assimp_lib
     name: assimp_lib

+ 1 - 1
assimp.pc.in

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

+ 2 - 2
cmake-modules/CoverallsGenerateGcov.cmake

@@ -310,7 +310,7 @@ foreach (GCOV_FILE ${GCOV_FILES})
 	message("MD5: ${GCOV_SRC_PATH} = ${GCOV_CONTENTS_MD5}")
 	message("MD5: ${GCOV_SRC_PATH} = ${GCOV_CONTENTS_MD5}")
 
 
 	# Loads the gcov file as a list of lines.
 	# 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...
 	#  because CMake will fail to parse a line containing unmatched brackets...
 	#  also the \ to escaped \n in macros screws up things.)
 	#  also the \ to escaped \n in macros screws up things.)
 	# https://public.kitware.com/Bug/view.php?id=15369
 	# 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
 	# Instead of trying to parse the source from the
 	# gcov file, simply read the file contents from the source file.
 	# 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
 	# (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)
 	file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE)
 
 
 	string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")
 	string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}")

+ 7 - 2
code/3DSExporter.cpp

@@ -39,7 +39,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
-
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_EXPORT
 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
 
 
@@ -151,7 +150,7 @@ namespace {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to 3DS. Prototyped and registered in Exporter.cpp
 // 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"));
     std::shared_ptr<IOStream> outfile (pIOSystem->Open(pFile, "wb"));
     if(!outfile) {
     if(!outfile) {
@@ -210,6 +209,12 @@ Discreet3DSExporter:: Discreet3DSExporter(std::shared_ptr<IOStream> outfile, con
     }
     }
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+Discreet3DSExporter::~Discreet3DSExporter() {
+    // empty
+}
+
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
 int Discreet3DSExporter::WriteHierarchy(const aiNode& node, int seq, int sibling_level)
 {
 {

+ 7 - 10
code/3DSExporter.h

@@ -60,23 +60,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:
 public:
     Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* pScene);
     Discreet3DSExporter(std::shared_ptr<IOStream> outfile, const aiScene* pScene);
+    ~Discreet3DSExporter();
 
 
 private:
 private:
-
     void WriteMeshes();
     void WriteMeshes();
     void WriteMaterials();
     void WriteMaterials();
     void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
     void WriteTexture(const aiMaterial& mat, aiTextureType type, uint16_t chunk_flags);
-
     void WriteFaceMaterialChunk(const aiMesh& mesh);
     void WriteFaceMaterialChunk(const aiMesh& mesh);
-
     int WriteHierarchy(const aiNode& node, int level, int sibling_level);
     int WriteHierarchy(const aiNode& node, int level, int sibling_level);
-
     void WriteString(const std::string& s);
     void WriteString(const std::string& s);
     void WriteString(const aiString& s);
     void WriteString(const aiString& s);
     void WriteColor(const aiColor3D& color);
     void WriteColor(const aiColor3D& color);
@@ -84,7 +82,6 @@ private:
     void WritePercentChunk(double f);
     void WritePercentChunk(double f);
 
 
 private:
 private:
-
     const aiScene* const scene;
     const aiScene* const scene;
     StreamWriterLE writer;
     StreamWriterLE writer;
 
 
@@ -95,6 +92,6 @@ private:
 
 
 };
 };
 
 
-}
+} // Namespace Assimp
 
 
-#endif
+#endif // AI_3DSEXPORTER_H_INC

+ 9 - 7
code/3DSHelper.h

@@ -44,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_3DSFILEHELPER_H_INC
 #ifndef AI_3DSFILEHELPER_H_INC
 #define AI_3DSFILEHELPER_H_INC
 #define AI_3DSFILEHELPER_H_INC
 
 
-
 #include "SpatialSort.h"
 #include "SpatialSort.h"
 #include "SmoothingGroups.h"
 #include "SmoothingGroups.h"
 #include "StringUtils.h"
 #include "StringUtils.h"
@@ -64,16 +63,19 @@ namespace D3DS  {
 /** Discreet3DS class: Helper class for loading 3ds files. Defines chunks
 /** Discreet3DS class: Helper class for loading 3ds files. Defines chunks
 *  and data structures.
 *  and data structures.
 */
 */
-class Discreet3DS
-{
+class Discreet3DS {
 private:
 private:
-    inline Discreet3DS() {}
+    Discreet3DS() {
+        // empty
+    }
 
 
-public:
+    ~Discreet3DS() {
+        // empty
+    }
 
 
+public:
     //! data structure for a single chunk in a .3ds file
     //! data structure for a single chunk in a .3ds file
-    struct Chunk
-    {
+    struct Chunk {
         uint16_t    Flag;
         uint16_t    Flag;
         uint32_t    Size;
         uint32_t    Size;
     } PACK_STRUCT;
     } PACK_STRUCT;

+ 89 - 0
code/3MFXmlTags.h

@@ -0,0 +1,89 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, 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 {
+    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 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";
+
+    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

+ 2 - 2
code/AMFImporter.hpp

@@ -249,7 +249,7 @@ private:
 
 
 	/// \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)
 	/// \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
 	/// 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.
 	/// 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.
 	/// Any of source ID's can be absent(empty string) or even one ID only specified. But at least one ID must be specified.
 	/// \param [in] pID_R - ID of source "red" texture.
 	/// \param [in] pID_R - ID of source "red" texture.
@@ -378,7 +378,7 @@ private:
 	void XML_CheckNode_MustHaveChildren();
 	void XML_CheckNode_MustHaveChildren();
 
 
 	/// \fn bool XML_CheckNode_NameEqual(const std::string& pNodeName)
 	/// \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.
 	/// \param [in] pNodeName - name for checking.
 	/// return true if current node name is equal to pNodeName, else - false.
 	/// return true if current node name is equal to pNodeName, else - false.
 	bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }
 	bool XML_CheckNode_NameEqual(const std::string& pNodeName) { return mReader->getNodeName() == pNodeName; }

+ 1 - 1
code/AMFImporter_Node.hpp

@@ -137,7 +137,7 @@ struct CAMFImporter_NodeElement_Instance : public CAMFImporter_NodeElement
 {
 {
 	/****************** Variables ******************/
 	/****************** Variables ******************/
 
 
-	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
 	/// \var Delta - The distance of translation in the x, y, or z direction, respectively, in the referenced object's coordinate system, to
 	/// create an instance of the object in the current constellation.
 	/// create an instance of the object in the current constellation.
 	aiVector3D Delta;
 	aiVector3D Delta;

+ 6 - 3
code/AMFImporter_Postprocess.cpp

@@ -60,7 +60,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp
 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;
     aiColor4D tcol;
 
 
@@ -281,8 +281,11 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string&
 	{
 	{
 		if(!pID.empty())
 		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
 	};// auto CopyTextureData = [&](const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void
 
 

+ 1 - 0
code/ASELoader.cpp

@@ -1021,6 +1021,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
 
 
                             // convert bones, if existing
                             // convert bones, if existing
                             if (!mesh.mBones.empty()) {
                             if (!mesh.mBones.empty()) {
+                                ai_assert(avOutputBones);
                                 // check whether there is a vertex weight for this vertex index
                                 // check whether there is a vertex weight for this vertex index
                                 if (iIndex2 < mesh.mBoneVertices.size())    {
                                 if (iIndex2 < mesh.mBoneVertices.size())    {
 
 

+ 2 - 1
code/AssbinExporter.cpp

@@ -171,6 +171,7 @@ inline size_t Write<aiQuaternion>(IOStream * stream, const aiQuaternion& v)
     t += Write<float>(stream,v.x);
     t += Write<float>(stream,v.x);
     t += Write<float>(stream,v.y);
     t += Write<float>(stream,v.y);
     t += Write<float>(stream,v.z);
     t += Write<float>(stream,v.z);
+    ai_assert(t == 16);
     return 16;
     return 16;
 }
 }
 
 
@@ -810,7 +811,7 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size)
         }
         }
     };
     };
 
 
-void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties)
+void ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/)
 {
 {
     AssbinExport exporter;
     AssbinExport exporter;
     exporter.WriteBinaryDump( pFile, pIOSystem, pScene );
     exporter.WriteBinaryDump( pFile, pIOSystem, pScene );

+ 11 - 0
code/AssbinLoader.cpp

@@ -200,6 +200,7 @@ template <typename T> void ReadBounds( IOStream * stream, T* /*p*/, unsigned int
 
 
 void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* parent ) {
 void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* parent ) {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AINODE);
     ai_assert(chunkID == ASSBIN_CHUNK_AINODE);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -274,6 +275,7 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* p
 void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b )
 void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b )
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIBONE);
     ai_assert(chunkID == ASSBIN_CHUNK_AIBONE);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -298,6 +300,7 @@ void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b )
 void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
 void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIMESH);
     ai_assert(chunkID == ASSBIN_CHUNK_AIMESH);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -423,6 +426,7 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
 void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop)
 void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop)
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY);
     ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -440,6 +444,7 @@ void AssbinImporter::ReadBinaryMaterialProperty(IOStream * stream, aiMaterialPro
 void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat)
 void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat)
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIAL);
     ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIAL);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -462,6 +467,7 @@ void AssbinImporter::ReadBinaryMaterial(IOStream * stream, aiMaterial* mat)
 void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
 void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AINODEANIM);
     ai_assert(chunkID == ASSBIN_CHUNK_AINODEANIM);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -511,6 +517,7 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
 void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
 void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIANIMATION);
     ai_assert(chunkID == ASSBIN_CHUNK_AIANIMATION);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -532,6 +539,7 @@ void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
 void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex)
 void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex)
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AITEXTURE);
     ai_assert(chunkID == ASSBIN_CHUNK_AITEXTURE);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -556,6 +564,7 @@ void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex)
 void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
 void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AILIGHT);
     ai_assert(chunkID == ASSBIN_CHUNK_AILIGHT);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -583,6 +592,7 @@ void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
 void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
 void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AICAMERA);
     ai_assert(chunkID == ASSBIN_CHUNK_AICAMERA);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 
@@ -599,6 +609,7 @@ void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
 void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
 void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
 {
 {
     uint32_t chunkID = Read<uint32_t>(stream);
     uint32_t chunkID = Read<uint32_t>(stream);
+    (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AISCENE);
     ai_assert(chunkID == ASSBIN_CHUNK_AISCENE);
     /*uint32_t size =*/ Read<uint32_t>(stream);
     /*uint32_t size =*/ Read<uint32_t>(stream);
 
 

+ 1 - 1
code/AssxmlExporter.cpp

@@ -631,7 +631,7 @@ void WriteDump(const aiScene* scene, IOStream* io, bool shortened) {
 
 
 } // end of namespace AssxmlExport
 } // 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" );
     IOStream * out = pIOSystem->Open( pFile, "wt" );
     if (!out) return;
     if (!out) return;

+ 41 - 21
code/B3DImporter.cpp

@@ -93,7 +93,6 @@ void DeleteAllBarePointers(std::vector<T>& x)
 
 
 B3DImporter::~B3DImporter()
 B3DImporter::~B3DImporter()
 {
 {
-    DeleteAllBarePointers(_animations);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -171,7 +170,8 @@ int B3DImporter::ReadByte(){
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 int B3DImporter::ReadInt(){
 int B3DImporter::ReadInt(){
     if( _pos+4<=_buf.size() ){
     if( _pos+4<=_buf.size() ){
-        int n=*(int*)&_buf[_pos];
+        int n;
+        memcpy(&n, &_buf[_pos], 4);
         _pos+=4;
         _pos+=4;
         return n;
         return n;
     }
     }
@@ -182,7 +182,8 @@ int B3DImporter::ReadInt(){
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 float B3DImporter::ReadFloat(){
 float B3DImporter::ReadFloat(){
     if( _pos+4<=_buf.size() ){
     if( _pos+4<=_buf.size() ){
-        float n=*(float*)&_buf[_pos];
+        float n;
+        memcpy(&n, &_buf[_pos], 4);
         _pos+=4;
         _pos+=4;
         return n;
         return n;
     }
     }
@@ -265,6 +266,21 @@ T *B3DImporter::to_array( const vector<T> &v ){
     return p;
     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(){
 void B3DImporter::ReadTEXS(){
     while( ChunkSize() ){
     while( ChunkSize() ){
@@ -293,8 +309,7 @@ void B3DImporter::ReadBRUS(){
         /*int blend=**/ReadInt();
         /*int blend=**/ReadInt();
         int fx=ReadInt();
         int fx=ReadInt();
 
 
-        aiMaterial *mat=new aiMaterial;
-        _materials.push_back( mat );
+        std::unique_ptr<aiMaterial> mat(new aiMaterial);
 
 
         // Name
         // Name
         aiString ainame( name );
         aiString ainame( name );
@@ -331,6 +346,7 @@ void B3DImporter::ReadBRUS(){
                 mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) );
                 mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) );
             }
             }
         }
         }
+        _materials.emplace_back( std::move(mat) );
     }
     }
 }
 }
 
 
@@ -384,8 +400,7 @@ void B3DImporter::ReadTRIS( int v0 ){
         Fail( "Bad material id" );
         Fail( "Bad material id" );
     }
     }
 
 
-    aiMesh *mesh=new aiMesh;
-    _meshes.push_back( mesh );
+    std::unique_ptr<aiMesh> mesh(new aiMesh);
 
 
     mesh->mMaterialIndex=matid;
     mesh->mMaterialIndex=matid;
     mesh->mNumFaces=0;
     mesh->mNumFaces=0;
@@ -413,6 +428,8 @@ void B3DImporter::ReadTRIS( int v0 ){
         ++mesh->mNumFaces;
         ++mesh->mNumFaces;
         ++face;
         ++face;
     }
     }
+
+    _meshes.emplace_back( std::move(mesh) );
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -498,11 +515,11 @@ void B3DImporter::ReadANIM(){
     int frames=ReadInt();
     int frames=ReadInt();
     float fps=ReadFloat();
     float fps=ReadFloat();
 
 
-    aiAnimation *anim=new aiAnimation;
-    _animations.push_back( anim );
+    std::unique_ptr<aiAnimation> anim(new aiAnimation);
 
 
     anim->mDuration=frames;
     anim->mDuration=frames;
     anim->mTicksPerSecond=fps;
     anim->mTicksPerSecond=fps;
+    _animations.emplace_back( std::move(anim) );
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -529,7 +546,7 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){
     node->mParent=parent;
     node->mParent=parent;
     node->mTransformation=tform;
     node->mTransformation=tform;
 
 
-    aiNodeAnim *nodeAnim=0;
+    std::unique_ptr<aiNodeAnim> nodeAnim;
     vector<unsigned> meshes;
     vector<unsigned> meshes;
     vector<aiNode*> children;
     vector<aiNode*> children;
 
 
@@ -547,11 +564,10 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){
             ReadANIM();
             ReadANIM();
         }else if( t=="KEYS" ){
         }else if( t=="KEYS" ){
             if( !nodeAnim ){
             if( !nodeAnim ){
-                nodeAnim=new aiNodeAnim;
-                _nodeAnims.push_back( nodeAnim );
+                nodeAnim.reset(new aiNodeAnim);
                 nodeAnim->mNodeName=node->mName;
                 nodeAnim->mNodeName=node->mName;
             }
             }
-            ReadKEYS( nodeAnim );
+            ReadKEYS( nodeAnim.get() );
         }else if( t=="NODE" ){
         }else if( t=="NODE" ){
             aiNode *child=ReadNODE( node );
             aiNode *child=ReadNODE( node );
             children.push_back( child );
             children.push_back( child );
@@ -559,6 +575,10 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){
         ExitChunk();
         ExitChunk();
     }
     }
 
 
+    if (nodeAnim) {
+        _nodeAnims.emplace_back( std::move(nodeAnim) );
+    }
+
     node->mNumMeshes= static_cast<unsigned int>(meshes.size());
     node->mNumMeshes= static_cast<unsigned int>(meshes.size());
     node->mMeshes=to_array( meshes );
     node->mMeshes=to_array( meshes );
 
 
@@ -584,7 +604,6 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
 
 
     _nodeAnims.clear();
     _nodeAnims.clear();
 
 
-    DeleteAllBarePointers(_animations);
     _animations.clear();
     _animations.clear();
 
 
     string t=ReadChunk();
     string t=ReadChunk();
@@ -620,7 +639,7 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
         aiNode *node=_nodes[i];
         aiNode *node=_nodes[i];
 
 
         for( size_t j=0;j<node->mNumMeshes;++j ){
         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_tris=mesh->mNumFaces;
             int n_verts=mesh->mNumVertices=n_tris * 3;
             int n_verts=mesh->mNumVertices=n_tris * 3;
@@ -683,27 +702,28 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
 
 
     //nodes
     //nodes
     scene->mRootNode=_nodes[0];
     scene->mRootNode=_nodes[0];
+    _nodes.clear();  // node ownership now belongs to scene
 
 
     //material
     //material
     if( !_materials.size() ){
     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->mNumMaterials= static_cast<unsigned int>(_materials.size());
-    scene->mMaterials=to_array( _materials );
+    scene->mMaterials = unique_to_array( _materials );
 
 
     //meshes
     //meshes
     scene->mNumMeshes= static_cast<unsigned int>(_meshes.size());
     scene->mNumMeshes= static_cast<unsigned int>(_meshes.size());
-    scene->mMeshes=to_array( _meshes );
+    scene->mMeshes = unique_to_array( _meshes );
 
 
     //animations
     //animations
     if( _animations.size()==1 && _nodeAnims.size() ){
     if( _animations.size()==1 && _nodeAnims.size() ){
 
 
-        aiAnimation *anim=_animations.back();
+        aiAnimation *anim = _animations.back().get();
         anim->mNumChannels=static_cast<unsigned int>(_nodeAnims.size());
         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->mNumAnimations=static_cast<unsigned int>(_animations.size());
-        scene->mAnimations=to_array( _animations );
+        scene->mAnimations=unique_to_array( _animations );
     }
     }
 
 
     // convert to RH
     // convert to RH

+ 5 - 4
code/B3DImporter.h

@@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/material.h>
 #include <assimp/material.h>
 #include "BaseImporter.h"
 #include "BaseImporter.h"
 
 
+#include <memory>
 #include <vector>
 #include <vector>
 
 
 struct aiNodeAnim;
 struct aiNodeAnim;
@@ -116,15 +117,15 @@ private:
     std::vector<unsigned> _stack;
     std::vector<unsigned> _stack;
 
 
     std::vector<std::string> _textures;
     std::vector<std::string> _textures;
-    std::vector<aiMaterial*> _materials;
+    std::vector<std::unique_ptr<aiMaterial> > _materials;
 
 
     int _vflags,_tcsets,_tcsize;
     int _vflags,_tcsets,_tcsize;
     std::vector<Vertex> _vertices;
     std::vector<Vertex> _vertices;
 
 
     std::vector<aiNode*> _nodes;
     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;
 };
 };
 
 
 }
 }

+ 3 - 4
code/BaseImporter.cpp

@@ -89,12 +89,12 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
     FileSystemFilter filter(pFile,pIOHandler);
     FileSystemFilter filter(pFile,pIOHandler);
 
 
     // create a scene object to hold the data
     // create a scene object to hold the data
-    ScopeGuard<aiScene> sc(new aiScene());
+    std::unique_ptr<aiScene> sc(new aiScene());
 
 
     // dispatch importing
     // dispatch importing
     try
     try
     {
     {
-        InternReadFile( pFile, sc, &filter);
+        InternReadFile( pFile, sc.get(), &filter);
 
 
     } catch( const std::exception& err )    {
     } catch( const std::exception& err )    {
         // extract error description
         // extract error description
@@ -104,8 +104,7 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
     }
     }
 
 
     // return what we gathered from the import.
     // return what we gathered from the import.
-    sc.dismiss();
-    return sc;
+    return sc.release();
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 0 - 36
code/BaseImporter.h

@@ -65,42 +65,6 @@ class IOStream;
 #define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \
 #define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \
     (string[1] << 16) + (string[2] << 8) + string[3]))
     (string[1] << 16) + (string[2] << 8) + string[3]))
 
 
-// ---------------------------------------------------------------------------
-template <typename T>
-struct ScopeGuard
-{
-    explicit ScopeGuard(T* obj) : obj(obj), mdismiss() {}
-    ~ScopeGuard () throw() {
-        if (!mdismiss) {
-            delete obj;
-        }
-        obj = NULL;
-    }
-
-    T* dismiss() {
-        mdismiss=true;
-        return obj;
-    }
-
-    operator T*() {
-        return obj;
-    }
-
-    T* operator -> () {
-        return obj;
-    }
-
-private:
-    // no copying allowed.
-    ScopeGuard();
-    ScopeGuard( const ScopeGuard & );
-    ScopeGuard &operator = ( const ScopeGuard & );
-
-    T* obj;
-    bool mdismiss;
-};
-
-
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** FOR IMPORTER PLUGINS ONLY: The BaseImporter defines a common interface
 /** FOR IMPORTER PLUGINS ONLY: The BaseImporter defines a common interface

+ 2 - 2
code/Bitmap.cpp

@@ -102,7 +102,7 @@ namespace Assimp {
         offset += Copy(&data[offset], header.size);
         offset += Copy(&data[offset], header.size);
         offset += Copy(&data[offset], header.reserved1);
         offset += Copy(&data[offset], header.reserved1);
         offset += Copy(&data[offset], header.reserved2);
         offset += Copy(&data[offset], header.reserved2);
-        offset += Copy(&data[offset], header.offset);
+                  Copy(&data[offset], header.offset);
 
 
         file->Write(data, Header::header_size, 1);
         file->Write(data, Header::header_size, 1);
     }
     }
@@ -122,7 +122,7 @@ namespace Assimp {
         offset += Copy(&data[offset], dib.x_resolution);
         offset += Copy(&data[offset], dib.x_resolution);
         offset += Copy(&data[offset], dib.y_resolution);
         offset += Copy(&data[offset], dib.y_resolution);
         offset += Copy(&data[offset], dib.nb_colors);
         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);
         file->Write(data, DIB::dib_size, 1);
     }
     }

+ 6 - 0
code/BlenderDNA.h

@@ -92,6 +92,12 @@ struct Error : DeadlyImportError {
  *  descendents. It serves as base class for all data structure fields. */
  *  descendents. It serves as base class for all data structure fields. */
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct ElemBase {
 struct ElemBase {
+    ElemBase()
+    : dna_type(nullptr)
+    {
+        // empty
+    }
+
     virtual ~ElemBase() {
     virtual ~ElemBase() {
         // empty
         // empty
     }
     }

+ 5 - 2
code/BlenderDNA.inl

@@ -585,11 +585,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)
     // automatic rescaling from short to float and vice versa (seems to be used by normals)
     if (name == "float") {
     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);
         //db.reader->IncPtr(-4);
         return;
         return;
     }
     }

+ 1 - 1
code/BlenderIntermediate.h

@@ -110,7 +110,7 @@ namespace Blender {
         void operator= (const TempArray&)  {
         void operator= (const TempArray&)  {
         }
         }
 
 
-        TempArray(const TempArray& arr) {
+        TempArray(const TempArray& /*arr*/) {
         }
         }
 
 
     private:
     private:

+ 7 - 7
code/BlenderLoader.cpp

@@ -1148,7 +1148,7 @@ 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*/)
 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->mName = obj->id.name+2;
     out->mPosition = aiVector3D(0.f, 0.f, 0.f);
     out->mPosition = aiVector3D(0.f, 0.f, 0.f);
     out->mUp = aiVector3D(0.f, 1.f, 0.f);
     out->mUp = aiVector3D(0.f, 1.f, 0.f);
@@ -1159,13 +1159,13 @@ aiCamera* BlenderImporter::ConvertCamera(const Scene& /*in*/, const Object* obj,
     out->mClipPlaneNear = cam->clipsta;
     out->mClipPlaneNear = cam->clipsta;
     out->mClipPlaneFar = cam->clipend;
     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*/)
 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;
     out->mName = obj->id.name+2;
 
 
     switch (lamp->type)
     switch (lamp->type)
@@ -1203,7 +1203,7 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c
     out->mColorAmbient = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
     out->mColorAmbient = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
     out->mColorSpecular = 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;
     out->mColorDiffuse = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy;
-    return out.dismiss();
+    return out.release();
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -1221,7 +1221,7 @@ aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, Convers
         ++it;
         ++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) {
     if (obj->data) {
         switch (obj->type)
         switch (obj->type)
         {
         {
@@ -1305,14 +1305,14 @@ aiNode* BlenderImporter::ConvertNode(const Scene& in, const Object* obj, Convers
         aiNode** nd = node->mChildren = new aiNode*[node->mNumChildren]();
         aiNode** nd = node->mChildren = new aiNode*[node->mNumChildren]();
         for (const Object* nobj :children) {
         for (const Object* nobj :children) {
             *nd = ConvertNode(in,nobj,conv_data,node->mTransformation * parentTransform);
             *nd = ConvertNode(in,nobj,conv_data,node->mTransformation * parentTransform);
-            (*nd++)->mParent = node;
+            (*nd++)->mParent = node.get();
         }
         }
     }
     }
 
 
     // apply modifiers
     // apply modifiers
     modifier_cache->ApplyModifiers(*node,conv_data,in,*obj);
     modifier_cache->ApplyModifiers(*node,conv_data,in,*obj);
 
 
-    return node.dismiss();
+    return node.release();
 }
 }
 
 
 #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER
 #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 3 - 1
code/BlenderModifier.cpp

@@ -310,7 +310,9 @@ void  BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data
 
 
     std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
     std::unique_ptr<Subdivider> subd(Subdivider::Create(algo));
     ai_assert(subd);
     ai_assert(subd);
-
+    if ( conv_data.meshes->empty() ) {
+        return;
+    }
     aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
     aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes];
     std::unique_ptr<aiMesh*[]> tempmeshes(new aiMesh*[out.mNumMeshes]());
     std::unique_ptr<aiMesh*[]> tempmeshes(new aiMesh*[out.mNumMeshes]());
 
 

+ 31 - 12
code/BlenderScene.cpp

@@ -59,7 +59,9 @@ template <> void Structure :: Convert<Object> (
 {
 {
 
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
     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.obmat,"obmat",db);
     ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv,"parentinv",db);
     ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv,"parentinv",db);
     ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr,"parsubstr",db);
     ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr,"parsubstr",db);
@@ -100,14 +102,21 @@ template <> void Structure :: Convert<MTex> (
     ) const
     ) 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.object,"*object",db);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.tex,"*tex",db);
     ReadFieldPtr<ErrorPolicy_Igno>(dest.tex,"*tex",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.uvname,"uvname",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.projx = static_cast<Assimp::Blender::MTex::Projection>(temp);
     ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
     ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);
     ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db);
@@ -190,7 +199,9 @@ template <> void Structure :: Convert<Lamp> (
 {
 {
 
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
     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::Lamp::Type>(temp);
     ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db);
     ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db);
     ReadField<ErrorPolicy_Igno>(dest.colormodel,"colormodel",db);
     ReadField<ErrorPolicy_Igno>(dest.colormodel,"colormodel",db);
     ReadField<ErrorPolicy_Igno>(dest.totex,"totex",db);
     ReadField<ErrorPolicy_Igno>(dest.totex,"totex",db);
@@ -204,7 +215,8 @@ template <> void Structure :: Convert<Lamp> (
     ReadField<ErrorPolicy_Igno>(dest.spotblend,"spotblend",db);
     ReadField<ErrorPolicy_Igno>(dest.spotblend,"spotblend",db);
     ReadField<ErrorPolicy_Igno>(dest.att1,"att1",db);
     ReadField<ErrorPolicy_Igno>(dest.att1,"att1",db);
     ReadField<ErrorPolicy_Igno>(dest.att2,"att2",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.sun_brightness,"sun_brightness",db);
     ReadField<ErrorPolicy_Igno>(dest.area_size,"area_size",db);
     ReadField<ErrorPolicy_Igno>(dest.area_size,"area_size",db);
     ReadField<ErrorPolicy_Igno>(dest.area_sizey,"area_sizey",db);
     ReadField<ErrorPolicy_Igno>(dest.area_sizey,"area_sizey",db);
@@ -693,8 +705,12 @@ template <> void Structure :: Convert<Tex> (
     const FileDatabase& db
     const FileDatabase& db
     ) const
     ) 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);
     ReadFieldPtr<ErrorPolicy_Warn>(dest.ima,"*ima",db);
 
 
     db.reader->IncPtr(size);
     db.reader->IncPtr(size);
@@ -708,8 +724,11 @@ template <> void Structure :: Convert<Camera> (
 {
 {
 
 
     ReadField<ErrorPolicy_Fail>(dest.id,"id",db);
     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.lens,"lens",db);
     ReadField<ErrorPolicy_Warn>(dest.sensor_x,"sensor_x",db);
     ReadField<ErrorPolicy_Warn>(dest.sensor_x,"sensor_x",db);
     ReadField<ErrorPolicy_Igno>(dest.clipsta,"clipsta",db);
     ReadField<ErrorPolicy_Igno>(dest.clipsta,"clipsta",db);

+ 8 - 0
code/BlenderScene.h

@@ -225,6 +225,14 @@ struct TFace : ElemBase {
 
 
 // -------------------------------------------------------------------------------
 // -------------------------------------------------------------------------------
 struct MTFace : ElemBase {
 struct MTFace : ElemBase {
+	MTFace()
+	: flag(0)
+	, mode(0)
+	, tile(0)
+	, unwrap(0)
+	{
+	}
+
     float uv[4][2] FAIL;
     float uv[4][2] FAIL;
     char flag;
     char flag;
     short mode;
     short mode;

+ 4 - 4
code/C4DImporter.cpp

@@ -185,11 +185,11 @@ void C4DImporter::InternReadFile( const std::string& pFile,
         if(mesh->mMaterialIndex >= mat_count) {
         if(mesh->mMaterialIndex >= mat_count) {
             ++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);
             const aiString name(AI_DEFAULT_MATERIAL_NAME);
             def_material->AddProperty(&name, AI_MATKEY_NAME);
             def_material->AddProperty(&name, AI_MATKEY_NAME);
 
 
-            materials.push_back(def_material.dismiss());
+            materials.push_back(def_material.release());
             break;
             break;
         }
         }
     }
     }
@@ -412,7 +412,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object)
     const CPolygon* polys = polyObject->GetPolygonR();
     const CPolygon* polys = polyObject->GetPolygonR();
     ai_assert(polys != NULL);
     ai_assert(polys != NULL);
 
 
-    ScopeGuard<aiMesh> mesh(new aiMesh());
+    std::unique_ptr<aiMesh> mesh(new aiMesh());
     mesh->mNumFaces = static_cast<unsigned int>(polyCount);
     mesh->mNumFaces = static_cast<unsigned int>(polyCount);
     aiFace* face = mesh->mFaces = new aiFace[mesh->mNumFaces]();
     aiFace* face = mesh->mFaces = new aiFace[mesh->mNumFaces]();
 
 
@@ -616,7 +616,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object)
     }
     }
 
 
     mesh->mMaterialIndex = ResolveMaterial(polyObject);
     mesh->mMaterialIndex = ResolveMaterial(polyObject);
-    return mesh.dismiss();
+    return mesh.release();
 }
 }
 
 
 
 

+ 42 - 5
code/CMakeLists.txt

@@ -156,6 +156,8 @@ SET( Common_SRCS
   SkeletonMeshBuilder.h
   SkeletonMeshBuilder.h
   SplitByBoneCountProcess.cpp
   SplitByBoneCountProcess.cpp
   SplitByBoneCountProcess.h
   SplitByBoneCountProcess.h
+  ScaleProcess.cpp
+  ScaleProcess.h
   SmoothingGroups.h
   SmoothingGroups.h
   StandardShapes.cpp
   StandardShapes.cpp
   StandardShapes.h
   StandardShapes.h
@@ -523,6 +525,8 @@ SET( PostProcessing_SRCS
   ComputeUVMappingProcess.h
   ComputeUVMappingProcess.h
   ConvertToLHProcess.cpp
   ConvertToLHProcess.cpp
   ConvertToLHProcess.h
   ConvertToLHProcess.h
+  EmbedTexturesProcess.cpp
+  EmbedTexturesProcess.h
   FindDegenerates.cpp
   FindDegenerates.cpp
   FindDegenerates.h
   FindDegenerates.h
   FindInstancesProcess.cpp
   FindInstancesProcess.cpp
@@ -675,8 +679,11 @@ ADD_ASSIMP_IMPORTER( GLTF
 ADD_ASSIMP_IMPORTER( 3MF
 ADD_ASSIMP_IMPORTER( 3MF
     D3MFImporter.h
     D3MFImporter.h
     D3MFImporter.cpp
     D3MFImporter.cpp
+    D3MFExporter.h
+    D3MFExporter.cpp
     D3MFOpcPackage.h
     D3MFOpcPackage.h
     D3MFOpcPackage.cpp
     D3MFOpcPackage.cpp
+    3MFXmlTags.h
 )
 )
 
 
 ADD_ASSIMP_IMPORTER( MMD
 ADD_ASSIMP_IMPORTER( MMD
@@ -738,6 +745,14 @@ SET( unzip_SRCS
 )
 )
 SOURCE_GROUP( unzip FILES ${unzip_SRCS})
 SOURCE_GROUP( unzip FILES ${unzip_SRCS})
 
 
+SET( ziplib_SRCS
+  ../contrib/zip/src/miniz.h
+  ../contrib/zip/src/zip.c
+  ../contrib/zip/src/zip.h
+)
+
+SOURCE_GROUP( ziplib FILES ${ziplib_SRCS} )
+
 SET ( openddl_parser_SRCS
 SET ( openddl_parser_SRCS
   ../contrib/openddlparser/code/OpenDDLParser.cpp
   ../contrib/openddlparser/code/OpenDDLParser.cpp
   ../contrib/openddlparser/code/DDLNode.cpp
   ../contrib/openddlparser/code/DDLNode.cpp
@@ -849,6 +864,7 @@ SET( assimp_src
   ${Clipper_SRCS}
   ${Clipper_SRCS}
   ${openddl_parser_SRCS}
   ${openddl_parser_SRCS}
   ${open3dgc_SRCS}
   ${open3dgc_SRCS}
+  ${ziplib_SRCS}
   # Necessary to show the headers in the project when using the VC++ generator:
   # Necessary to show the headers in the project when using the VC++ generator:
 
 
   ${PUBLIC_HEADERS}
   ${PUBLIC_HEADERS}
@@ -912,8 +928,27 @@ SET_TARGET_PROPERTIES( assimp PROPERTIES
 )
 )
 
 
 if (APPLE)
 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
 # Build against external unzip, or add ../contrib/unzip so
 # assimp can #include "unzip.h"
 # assimp can #include "unzip.h"
@@ -933,14 +968,16 @@ INSTALL( TARGETS assimp
   LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR}
   RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR}
+  FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR}
   COMPONENT ${LIBASSIMP_COMPONENT})
   COMPONENT ${LIBASSIMP_COMPONENT})
 INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev)
 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)
 INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev)
+
 if (ASSIMP_ANDROID_JNIIOSYSTEM)
 if (ASSIMP_ANDROID_JNIIOSYSTEM)
   INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h
   INSTALL(FILES ${HEADER_PATH}/${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/AndroidJNIIOSystem.h
     DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
     DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}
     COMPONENT assimp-dev)
     COMPONENT assimp-dev)
-endif(ASSIMP_ANDROID_JNIIOSYSTEM)
+ENDIF(ASSIMP_ANDROID_JNIIOSYSTEM)
 
 
 if(MSVC AND ASSIMP_INSTALL_PDB)
 if(MSVC AND ASSIMP_INSTALL_PDB)
   IF(CMAKE_GENERATOR MATCHES "^Visual Studio")
   IF(CMAKE_GENERATOR MATCHES "^Visual Studio")
@@ -962,7 +999,7 @@ if(MSVC AND ASSIMP_INSTALL_PDB)
       CONFIGURATIONS RelWithDebInfo
       CONFIGURATIONS RelWithDebInfo
     )
     )
   ENDIF()
   ENDIF()
-endif ()
+ENDIF ()
 
 
 if (ASSIMP_COVERALLS)
 if (ASSIMP_COVERALLS)
     include(Coveralls)
     include(Coveralls)
@@ -974,4 +1011,4 @@ if (ASSIMP_COVERALLS)
         "${COVERAGE_SRCS}" # The source files.
         "${COVERAGE_SRCS}" # The source files.
         ON                 # If we should upload.
         ON                 # If we should upload.
         "${PROJECT_SOURCE_DIR}/cmake-modules/") # (Optional) Alternate project cmake module path.
         "${PROJECT_SOURCE_DIR}/cmake-modules/") # (Optional) Alternate project cmake module path.
-endif()
+ENDIF()

+ 260 - 8
code/ColladaExporter.cpp

@@ -68,13 +68,17 @@ namespace Assimp
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
 // 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 path = DefaultIOSystem::absolutePath(std::string(pFile));
     std::string file = DefaultIOSystem::completeBaseName(std::string(pFile));
     std::string file = DefaultIOSystem::completeBaseName(std::string(pFile));
 
 
     // invoke the exporter
     // invoke the exporter
     ColladaExporter iDoTheExportThing( pScene, pIOSystem, path, file);
     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
     // we're still here - export successfully completed. Write result to the given IOSYstem
     std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
     std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
@@ -104,7 +108,7 @@ ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, co
     // set up strings
     // set up strings
     endstr = "\n";
     endstr = "\n";
 
 
-    // start writing
+    // start writing the file
     WriteFile();
     WriteFile();
 }
 }
 
 
@@ -137,6 +141,9 @@ void ColladaExporter::WriteFile()
     WriteControllerLibrary();
     WriteControllerLibrary();
 
 
     WriteSceneLibrary();
     WriteSceneLibrary();
+	
+	// customized, Writes the animation library
+	WriteAnimationsLibrary();
 
 
     // useless Collada fu at the end, just in case we haven't had enough indirections, yet.
     // useless Collada fu at the end, just in case we haven't had enough indirections, yet.
     mOutput << startstr << "<scene>" << endstr;
     mOutput << startstr << "<scene>" << endstr;
@@ -1125,6 +1132,7 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
         case FloatType_Color: floatsPerElement = 3; break;
         case FloatType_Color: floatsPerElement = 3; break;
         case FloatType_Mat4x4: floatsPerElement = 16; break;
         case FloatType_Mat4x4: floatsPerElement = 16; break;
         case FloatType_Weight: floatsPerElement = 1; break;
         case FloatType_Weight: floatsPerElement = 1; break;
+		case FloatType_Time: floatsPerElement = 1; break;
         default:
         default:
             return;
             return;
     }
     }
@@ -1201,7 +1209,13 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
         case FloatType_Weight:
         case FloatType_Weight:
             mOutput << startstr << "<param name=\"WEIGHT\" type=\"float\" />" << endstr;
             mOutput << startstr << "<param name=\"WEIGHT\" type=\"float\" />" << endstr;
             break;
             break;
-    }
+
+		// customized, add animation related
+		case FloatType_Time:
+			mOutput << startstr << "<param name=\"TIME\" type=\"float\" />" << endstr;
+			break;
+
+	}
 
 
     PopTag();
     PopTag();
     mOutput << startstr << "</accessor>" << endstr;
     mOutput << startstr << "</accessor>" << endstr;
@@ -1231,7 +1245,172 @@ void ColladaExporter::WriteSceneLibrary()
     PopTag();
     PopTag();
     mOutput << startstr << "</library_visual_scenes>" << endstr;
     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();
+	
+	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;
+		
+		{
+			const std::string node_idstr = nodeAnim->mNodeName.data + 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();
+		}
+		
+		{
+			const std::string node_idstr = nodeAnim->mNodeName.data + 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
 // Helper to find a bone by name in the scene
 aiBone* findBone( const aiScene* scene, const char * name) {
 aiBone* findBone( const aiScene* scene, const char * name) {
@@ -1247,6 +1426,59 @@ aiBone* findBone( const aiScene* scene, const char * name) {
     return NULL;
     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
 // Recursively writes the given node
 void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
 void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
@@ -1274,12 +1506,22 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
     }
     }
 
 
     const std::string node_name_escaped = XMLEscape(pNode->mName.data);
     const std::string node_name_escaped = XMLEscape(pNode->mName.data);
+	/* // customized, Note! the id field is crucial for inter-xml look up, it cannot be replaced with sid ?!
     mOutput << startstr
     mOutput << startstr
             << "<node ";
             << "<node ";
     if(is_skeleton_root)
     if(is_skeleton_root)
         mOutput << "id=\"" << "skeleton_root" << "\" "; // For now, only support one skeleton in a scene.
         mOutput << "id=\"" << "skeleton_root" << "\" "; // For now, only support one skeleton in a scene.
     mOutput << (is_joint ? "s" : "") << "id=\"" << node_name_escaped;
     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
             << "\" type=\"" << node_type
             << "\">" << endstr;
             << "\">" << endstr;
     PushTag();
     PushTag();
@@ -1287,7 +1529,11 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
     // write transformation - we can directly put the matrix there
     // write transformation - we can directly put the matrix there
     // TODO: (thom) decompose into scale - rot - quad to allow addressing it by animations afterwards
     // TODO: (thom) decompose into scale - rot - quad to allow addressing it by animations afterwards
     const aiMatrix4x4& mat = pNode->mTransformation;
     const aiMatrix4x4& mat = pNode->mTransformation;
-    mOutput << startstr << "<matrix sid=\"transform\">";
+	
+	// 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.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " ";
     mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " ";
     mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " ";
     mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " ";
     mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " ";
@@ -1315,7 +1561,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
     for( size_t a = 0; a < pNode->mNumMeshes; ++a )
     for( size_t a = 0; a < pNode->mNumMeshes; ++a )
     {
     {
         const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[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 )
         if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
             continue;
             continue;
 
 
@@ -1331,7 +1577,13 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
                     << endstr;
                     << endstr;
             PushTag();
             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;
         mOutput << startstr << "<bind_material>" << endstr;
         PushTag();
         PushTag();

+ 8 - 1
code/ColladaExporter.h

@@ -114,7 +114,9 @@ protected:
     /// Writes the given mesh
     /// Writes the given mesh
     void WriteGeometry( size_t pIndex);
     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
     /// Writes a float array of the given type
     void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const ai_real* pData, size_t pElementCount);
     void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const ai_real* pData, size_t pElementCount);
@@ -122,6 +124,11 @@ protected:
     /// Writes the scene library
     /// Writes the scene library
     void WriteSceneLibrary();
     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
     /// Recursively writes the given node
     void WriteNode( const aiScene* scene, aiNode* pNode);
     void WriteNode( const aiScene* scene, aiNode* pNode);
 
 

+ 1 - 1
code/ColladaHelper.h

@@ -302,7 +302,7 @@ struct Accessor
     size_t mOffset;  // in number of values
     size_t mOffset;  // in number of values
     size_t mStride;  // Stride in number of values
     size_t mStride;  // Stride in number of values
     std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
     std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore.
-    size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, 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.
                           // For example, SubOffset[0] denotes which of the values inside the object is the vector X component.
     std::string mSource;   // URL of the source array
     std::string mSource;   // URL of the source array
     mutable const Data* mData; // Pointer to the source array, if resolved. NULL else
     mutable const Data* mData; // Pointer to the source array, if resolved. NULL else

+ 6 - 1
code/ColladaLoader.cpp

@@ -1619,7 +1619,7 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
         mat.AddProperty( &effect.mRefractIndex, 1, AI_MATKEY_REFRACTI);
         mat.AddProperty( &effect.mRefractIndex, 1, AI_MATKEY_REFRACTI);
 
 
         // transparency, a very hard one. seemingly not all files are following the
         // 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
         // therefore, we let the opportunity for the user to manually invert
         // the transparency if necessary and we add preliminary support for RGB_ZERO mode
         // the transparency if necessary and we add preliminary support for RGB_ZERO mode
         if(effect.mTransparency >= 0.f && effect.mTransparency <= 1.f) {
         if(effect.mTransparency >= 0.f && effect.mTransparency <= 1.f) {
@@ -1778,6 +1778,11 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
         tex->pcData = (aiTexel*)new char[tex->mWidth];
         tex->pcData = (aiTexel*)new char[tex->mWidth];
         memcpy(tex->pcData,&imIt->second.mImageData[0],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 thru 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
         // setup texture reference string
         result.data[0] = '*';
         result.data[0] = '*';
         result.length = 1 + ASSIMP_itoa10(result.data+1,static_cast<unsigned int>(MAXLEN-1),static_cast<int32_t>(mTextures.size()));
         result.length = 1 + ASSIMP_itoa10(result.data+1,static_cast<unsigned int>(MAXLEN-1),static_cast<int32_t>(mTextures.size()));

+ 2 - 3
code/ColladaParser.cpp

@@ -224,7 +224,7 @@ void ColladaParser::ReadStructure()
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-// 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()
 void ColladaParser::ReadAssetInfo()
 {
 {
     if( mReader->isEmptyElement())
     if( mReader->isEmptyElement())
@@ -2469,8 +2469,7 @@ void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t n
     size_t baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets;
     size_t baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets;
 
 
     // don't overrun the boundaries of the index list
     // 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
     // extract per-vertex channels using the global per-vertex offset
     for (std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)
     for (std::vector<InputChannel>::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it)

+ 1 - 1
code/ColladaParser.h

@@ -77,7 +77,7 @@ namespace Assimp
         /** Reads the structure of the file */
         /** Reads the structure of the file */
         void ReadStructure();
         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();
         void ReadAssetInfo();
 
 
         /** Reads the animation library */
         /** Reads the animation library */

+ 328 - 0
code/D3MFExporter.cpp

@@ -0,0 +1,328 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, 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 "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 ) {
+        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;
+
+    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::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;
+
+    writeFaces( mesh );
+
+    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 ) {
+    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 ] << "\"/>";
+        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

+ 103 - 0
code/D3MFExporter.h

@@ -0,0 +1,103 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, 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 writeObjects();
+    void writeMesh( aiMesh *mesh );
+    void writeVertex( const aiVector3D &pos );
+    void writeFaces( aiMesh *mesh );
+    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
+

+ 29 - 66
code/D3MFImporter.cpp

@@ -59,65 +59,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "D3MFOpcPackage.h"
 #include "D3MFOpcPackage.h"
 #include <contrib/unzip/unzip.h>
 #include <contrib/unzip/unzip.h>
 #include "irrXMLWrapper.h"
 #include "irrXMLWrapper.h"
+#include "3MFXmlTags.h"
 
 
 namespace Assimp {
 namespace Assimp {
 namespace D3MF {
 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:
 public:
     XmlSerializer(XmlReader* xmlReader)
     XmlSerializer(XmlReader* xmlReader)
-        : xmlReader(xmlReader)
-    {
+    : xmlReader(xmlReader) {
 		// empty
 		// empty
     }
     }
 
 
+    ~XmlSerializer() {
+        // empty
+    }
+
     void ImportXml(aiScene* scene) {
     void ImportXml(aiScene* scene) {
         scene->mRootNode = new aiNode();
         scene->mRootNode = new aiNode();
         std::vector<aiNode*> children;
         std::vector<aiNode*> children;
 
 
-        while(ReadToEndElement(D3MF::XmlTag::model))
-        {
-
-            if(xmlReader->getNodeName() == D3MF::XmlTag::object)
-            {
+        while(ReadToEndElement(D3MF::XmlTag::model)) {
+            if(xmlReader->getNodeName() == D3MF::XmlTag::object) {
                 children.push_back(ReadObject(scene));
                 children.push_back(ReadObject(scene));
-            }
-            else if(xmlReader->getNodeName() == D3MF::XmlTag::build)
-            {
+            } else if(xmlReader->getNodeName() == D3MF::XmlTag::build) {
 
 
             }
             }
         }
         }
 
 
-        if(scene->mRootNode->mName.length == 0)
-            scene->mRootNode->mName.Set("3MF");
-
+        if ( scene->mRootNode->mName.length == 0 ) {
+            scene->mRootNode->mName.Set( "3MF" );
+        }
 
 
         scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
         scene->mNumMeshes = static_cast<unsigned int>(meshes.size());
         scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
         scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
@@ -128,13 +100,12 @@ public:
         scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
         scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
 
 
         std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
         std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
-
     }
     }
 
 
 private:
 private:
     aiNode* ReadObject(aiScene* scene)
     aiNode* ReadObject(aiScene* scene)
     {
     {
-        ScopeGuard<aiNode> node(new aiNode());
+        std::unique_ptr<aiNode> node(new aiNode());
 
 
         std::vector<unsigned long> meshIds;
         std::vector<unsigned long> meshIds;
 
 
@@ -174,14 +145,12 @@ private:
 
 
         std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
         std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
 
 
-        return node.dismiss();
+        return node.release();
 
 
     }
     }
 
 
-    aiMesh* ReadMesh()
-    {
+    aiMesh* ReadMesh() {
         aiMesh* mesh = new aiMesh();
         aiMesh* mesh = new aiMesh();
-
         while(ReadToEndElement(D3MF::XmlTag::mesh))
         while(ReadToEndElement(D3MF::XmlTag::mesh))
         {
         {
             if(xmlReader->getNodeName() == D3MF::XmlTag::vertices)
             if(xmlReader->getNodeName() == D3MF::XmlTag::vertices)
@@ -192,10 +161,8 @@ private:
             {
             {
                 ImportTriangles(mesh);
                 ImportTriangles(mesh);
             }
             }
-
         }
         }
 
 
-
         return mesh;
         return mesh;
     }
     }
 
 
@@ -216,6 +183,7 @@ private:
         std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
         std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
 
 
     }
     }
+
     aiVector3D ReadVertex()
     aiVector3D ReadVertex()
     {
     {
         aiVector3D vertex;
         aiVector3D vertex;
@@ -261,7 +229,6 @@ private:
     }
     }
 
 
 private:
 private:
-
     bool ReadToStartElement(const std::string& startTag)
     bool ReadToStartElement(const std::string& startTag)
     {
     {
         while(xmlReader->read())
         while(xmlReader->read())
@@ -305,6 +272,7 @@ private:
 
 
 } //namespace D3MF
 } //namespace D3MF
 
 
+static const std::string Extension = "3mf";
 
 
 static const aiImporterDesc desc = {
 static const aiImporterDesc desc = {
     "3mf Importer",
     "3mf Importer",
@@ -316,24 +284,22 @@ static const aiImporterDesc desc = {
     0,
     0,
     0,
     0,
     0,
     0,
-    "3mf"
+    Extension.c_str()
 };
 };
 
 
 
 
 D3MFImporter::D3MFImporter()
 D3MFImporter::D3MFImporter()
-{
-
+: BaseImporter() {
+    // empty
 }
 }
 
 
-D3MFImporter::~D3MFImporter()
-{
-
+D3MFImporter::~D3MFImporter() {
+    // empty
 }
 }
 
 
-bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const
-{
+bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
     const std::string extension = GetExtension(pFile);
     const std::string extension = GetExtension(pFile);
-    if(extension == "3mf") {
+    if(extension == Extension ) {
         return true;
         return true;
     } else if ( !extension.length() || checkSig ) {
     } else if ( !extension.length() || checkSig ) {
         if (nullptr == pIOHandler ) {
         if (nullptr == pIOHandler ) {
@@ -344,18 +310,15 @@ bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool
     return false;
     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;
     return &desc;
 }
 }
 
 
-void D3MFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler)
-{
+void D3MFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
     D3MF::D3MFOpcPackage opcPackage(pIOHandler, pFile);
     D3MF::D3MFOpcPackage opcPackage(pIOHandler, pFile);
 
 
     std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));
     std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream()));

+ 5 - 7
code/D3MFImporter.h

@@ -46,21 +46,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 namespace Assimp {
 namespace Assimp {
 
 
-class D3MFImporter : public BaseImporter
-{
+class D3MFImporter : public BaseImporter {
 public:
 public:
+    // BaseImporter interface
     D3MFImporter();
     D3MFImporter();
     ~D3MFImporter();
     ~D3MFImporter();
-
-    // BaseImporter interface
-public:
     bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
     bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
     void SetupProperties(const Importer *pImp);
     void SetupProperties(const Importer *pImp);
     const aiImporterDesc *GetInfo() const;
     const aiImporterDesc *GetInfo() const;
 
 
 protected:
 protected:
     void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
     void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
-
 };
 };
-}
+
+} // Namespace Assimp
+
 #endif // AI_D3MFLOADER_H_INCLUDED
 #endif // AI_D3MFLOADER_H_INCLUDED

+ 78 - 141
code/D3MFOpcPackage.cpp

@@ -55,49 +55,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <map>
 #include <map>
 #include <algorithm>
 #include <algorithm>
 #include <cassert>
 #include <cassert>
-
 #include <contrib/unzip/unzip.h>
 #include <contrib/unzip/unzip.h>
+#include "3MFXmlTags.h"
 
 
 namespace Assimp {
 namespace Assimp {
 
 
 namespace D3MF {
 namespace D3MF {
 
 
-namespace XmlTag {
-    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";
-}
-
 class IOSystem2Unzip {
 class IOSystem2Unzip {
-
-    public:
-
-        static voidpf open(voidpf opaque, const char* filename, int mode);
-
-        static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
-
-        static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
-
-        static long tell(voidpf opaque, voidpf stream);
-
-        static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
-
-        static int close(voidpf opaque, voidpf stream);
-
-        static int testerror(voidpf opaque, voidpf stream);
-
-        static zlib_filefunc_def get(IOSystem* pIOHandler);
+public:
+    static voidpf open(voidpf opaque, const char* filename, int mode);
+    static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
+    static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
+    static long tell(voidpf opaque, voidpf stream);
+    static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
+    static int close(voidpf opaque, voidpf stream);
+    static int testerror(voidpf opaque, voidpf stream);
+    static zlib_filefunc_def get(IOSystem* pIOHandler);
 };
 };
 
 
 voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
 voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
@@ -116,7 +90,6 @@ voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
         }
         }
     }
     }
 
 
-
     return (voidpf) io_system->Open(filename, mode_fopen);
     return (voidpf) io_system->Open(filename, mode_fopen);
 }
 }
 
 
@@ -186,44 +159,33 @@ zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
     return mapping;
     return mapping;
 }
 }
 
 
-
-class ZipFile : public IOStream
-{
+class ZipFile : public IOStream {
     friend class D3MFZipArchive;
     friend class D3MFZipArchive;
 
 
 public:
 public:
     explicit ZipFile(size_t size);
     explicit ZipFile(size_t size);
-
-    ~ZipFile();
-
+    virtual ~ZipFile();
     size_t Read(void* pvBuffer, size_t pSize, size_t pCount );
     size_t Read(void* pvBuffer, size_t pSize, size_t pCount );
-
     size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/);
     size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/);
-
     size_t FileSize() const;
     size_t FileSize() const;
-
     aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/);
     aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/);
-
     size_t Tell() const;
     size_t Tell() const;
-
     void Flush();
     void Flush();
 
 
 private:
 private:
-
-    void* m_Buffer;
-
+    void *m_Buffer;
     size_t m_Size;
     size_t m_Size;
-
 };
 };
 
 
-ZipFile::ZipFile(size_t size) : m_Size(size) {
+ZipFile::ZipFile(size_t size)
+: m_Buffer( nullptr )
+, m_Size(size) {
     ai_assert(m_Size != 0);
     ai_assert(m_Size != 0);
-
-    m_Buffer = malloc(m_Size);
+    m_Buffer = ::malloc(m_Size);
 }
 }
 
 
 ZipFile::~ZipFile() {
 ZipFile::~ZipFile() {
-    free(m_Buffer);
+    ::free(m_Buffer);
     m_Buffer = NULL;
     m_Buffer = NULL;
 }
 }
 
 
@@ -236,8 +198,12 @@ size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
     return size;
     return size;
 }
 }
 
 
-size_t ZipFile::Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
-    return 0;
+size_t ZipFile::Write(const void* pvBuffer, size_t size, size_t pCount ) {
+    const size_t size_to_write( size * pCount );
+    if ( 0 == size_to_write ) {
+        return 0U;
+    }
+    return 0U;
 }
 }
 
 
 size_t ZipFile::FileSize() const {
 size_t ZipFile::FileSize() const {
@@ -256,55 +222,36 @@ void ZipFile::Flush() {
     // empty
     // empty
 }
 }
 
 
-
-class D3MFZipArchive : public IOSystem
-{
+class D3MFZipArchive : public IOSystem {
 public:
 public:
-
     static const unsigned int FileNameSize = 256;
     static const unsigned int FileNameSize = 256;
 
 
-public:
-
     D3MFZipArchive(IOSystem* pIOHandler, const std::string & rFile);
     D3MFZipArchive(IOSystem* pIOHandler, const std::string & rFile);
-
     ~D3MFZipArchive();
     ~D3MFZipArchive();
-
     bool Exists(const char* pFile) const;
     bool Exists(const char* pFile) const;
-
     char getOsSeparator() const;
     char getOsSeparator() const;
-
     IOStream* Open(const char* pFile, const char* pMode = "rb");
     IOStream* Open(const char* pFile, const char* pMode = "rb");
-
     void Close(IOStream* pFile);
     void Close(IOStream* pFile);
-
     bool isOpen() const;
     bool isOpen() const;
-
     void getFileList(std::vector<std::string> &rFileList);
     void getFileList(std::vector<std::string> &rFileList);
 
 
 private:
 private:
-
     bool mapArchive();
     bool mapArchive();
 
 
 private:
 private:
-
     unzFile m_ZipFileHandle;
     unzFile m_ZipFileHandle;
-
     std::map<std::string, ZipFile*> m_ArchiveMap;
     std::map<std::string, ZipFile*> m_ArchiveMap;
-
 };
 };
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //  Constructor.
 //  Constructor.
 D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile)
 D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile)
-    : m_ZipFileHandle(NULL), m_ArchiveMap()
-{
-    if (! rFile.empty())
-    {                
+: m_ZipFileHandle(NULL)
+, m_ArchiveMap() {
+    if (! rFile.empty()) {                
         zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);            
         zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);            
 
 
         m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
         m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
-
         if(m_ZipFileHandle != NULL) {            
         if(m_ZipFileHandle != NULL) {            
             mapArchive();
             mapArchive();
         }
         }
@@ -379,6 +326,7 @@ IOStream *D3MFZipArchive::Open(const char* pFile, const char* /*pMode*/) {
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //  Close a filestream.
 //  Close a filestream.
 void D3MFZipArchive::Close(IOStream *pFile) {
 void D3MFZipArchive::Close(IOStream *pFile) {
+    (void)(pFile);
     ai_assert(pFile != NULL);
     ai_assert(pFile != NULL);
 
 
     // We don't do anything in case the file would be opened again in the future
     // We don't do anything in case the file would be opened again in the future
@@ -433,24 +381,12 @@ bool D3MFZipArchive::mapArchive() {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 
 
-struct OpcPackageRelationship
-{
-    std::string id;
-    std::string type;
-    std::string target;
-};
-
 typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
 typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
 
 
-class OpcPackageRelationshipReader
-{
+class OpcPackageRelationshipReader {
 public:
 public:
-
-    OpcPackageRelationshipReader(XmlReader* xmlReader)
-    {        
-
-        while(xmlReader->read())
-        {
+    OpcPackageRelationshipReader(XmlReader* xmlReader) {        
+        while(xmlReader->read()) {
             if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
             if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT &&
                xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER)
                xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER)
             {
             {
@@ -473,57 +409,68 @@ public:
         }
         }
     }
     }
 
 
-    void ParseAttributes(XmlReader*)
-    {
+    void ParseAttributes(XmlReader*) {
+        // empty
+    }
 
 
+    bool validateRels( OpcPackageRelationshipPtr &relPtr ) {
+        if ( relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty() ) {
+            return false;
+        }
+        return true;
     }
     }
 
 
-    void ParseChildNode(XmlReader* xmlReader)
-    {        
+    void ParseChildNode(XmlReader* xmlReader) {        
         OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
         OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship());
 
 
-        relPtr->id = xmlReader->getAttributeValue(XmlTag::RELS_ATTRIB_ID.c_str());
-        relPtr->type = xmlReader->getAttributeValue(XmlTag::RELS_ATTRIB_TYPE.c_str());
-        relPtr->target = xmlReader->getAttributeValue(XmlTag::RELS_ATTRIB_TARGET.c_str());
-
-        m_relationShips.push_back(relPtr);
+        relPtr->id = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_ID.c_str());
+        relPtr->type = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TYPE.c_str());
+        relPtr->target = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TARGET.c_str());
+        if ( validateRels( relPtr ) ) {
+            m_relationShips.push_back( relPtr );
+        }
     }
     }
+
     std::vector<OpcPackageRelationshipPtr> m_relationShips;
     std::vector<OpcPackageRelationshipPtr> m_relationShips;
 };
 };
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 
 
 D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
 D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
-    : m_RootStream(nullptr)
-{    
-    zipArchive.reset(new D3MF::D3MFZipArchive( pIOHandler, rFile ));    
-    if(!zipArchive->isOpen()) {
+: mRootStream(nullptr)
+, mZipArchive() {    
+    mZipArchive.reset( new D3MF::D3MFZipArchive( pIOHandler, rFile ) );    
+    if(!mZipArchive->isOpen()) {
         throw DeadlyImportError("Failed to open file " + rFile+ ".");
         throw DeadlyImportError("Failed to open file " + rFile+ ".");
     }
     }
 
 
     std::vector<std::string> fileList;
     std::vector<std::string> fileList;
-    zipArchive->getFileList(fileList);
+    mZipArchive->getFileList(fileList);
 
 
-    for(auto& file: fileList){
+    for (auto& file: fileList) {
         if(file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) {
         if(file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) {
             //PkgRelationshipReader pkgRelReader(file, archive);
             //PkgRelationshipReader pkgRelReader(file, archive);
-            ai_assert(zipArchive->Exists(file.c_str()));
+            ai_assert(mZipArchive->Exists(file.c_str()));
 
 
-            IOStream *fileStream = zipArchive->Open(file.c_str());
+            IOStream *fileStream = mZipArchive->Open(file.c_str());
 
 
             ai_assert(fileStream != nullptr);
             ai_assert(fileStream != nullptr);
 
 
             std::string rootFile = ReadPackageRootRelationship(fileStream);
             std::string rootFile = ReadPackageRootRelationship(fileStream);
-            if(rootFile.size() > 0 && rootFile[0] == '/')
-                rootFile = rootFile.substr(1);
+            if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) {
+                rootFile = rootFile.substr( 1 );
+                if ( rootFile[ 0 ] == '/' ) {
+                    // deal with zipbug
+                    rootFile = rootFile.substr( 1 );
+                }
+            }
 
 
             DefaultLogger::get()->debug(rootFile);
             DefaultLogger::get()->debug(rootFile);
 
 
-            m_RootStream = zipArchive->Open(rootFile.c_str());
-
-            ai_assert(m_RootStream != nullptr);
-
-
-
+            mRootStream = mZipArchive->Open(rootFile.c_str());
+            ai_assert( mRootStream != nullptr );
+            if ( nullptr == mRootStream ) {
+                throw DeadlyExportError( "Cannot open rootfile in archive : " + rootFile );
+            }
 
 
         //    const size_t size = zipArchive->FileSize();
         //    const size_t size = zipArchive->FileSize();
         //    m_Data.resize( size );
         //    m_Data.resize( size );
@@ -534,50 +481,40 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
         //        m_Data.clear();
         //        m_Data.clear();
         //        return false;
         //        return false;
         //    }
         //    }
-            zipArchive->Close( fileStream );
+            mZipArchive->Close( fileStream );
 
 
-        }
-        else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE)
-        {
+        } else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
 
 
         }
         }
     }
     }
 }
 }
 
 
-D3MFOpcPackage::~D3MFOpcPackage()
-{
-
+D3MFOpcPackage::~D3MFOpcPackage() {
+    // empty
 }
 }
 
 
-IOStream* D3MFOpcPackage::RootStream() const
-{
-    return m_RootStream;
+IOStream* D3MFOpcPackage::RootStream() const {
+    return mRootStream;
 }
 }
 
 
-
-std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream)
-{
-
+std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
     std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
     std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
     std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
     std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
 
 
     OpcPackageRelationshipReader reader(xml.get());
     OpcPackageRelationshipReader reader(xml.get());
 
 
-
     auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr& rel){
     auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr& rel){
         return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
         return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE;
     });
     });
 
 
-
-
     if(itr == reader.m_relationShips.end())
     if(itr == reader.m_relationShips.end())
-        throw DeadlyImportError("Cannot find" + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
+        throw DeadlyImportError("Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE);
 
 
     return (*itr)->target;
     return (*itr)->target;
 }
 }
 
 
-} //namespace D3MF
+} // Namespace D3MF
 
 
-}
+} // Namespace Assimp
 
 
 #endif //ASSIMP_BUILD_NO_3MF_IMPORTER
 #endif //ASSIMP_BUILD_NO_3MF_IMPORTER

+ 12 - 7
code/D3MFOpcPackage.h

@@ -48,26 +48,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "irrXMLWrapper.h"
 #include "irrXMLWrapper.h"
 
 
 namespace Assimp {
 namespace Assimp {
-
 namespace D3MF {
 namespace D3MF {
 
 
 typedef irr::io::IrrXMLReader XmlReader;
 typedef irr::io::IrrXMLReader XmlReader;
 typedef std::shared_ptr<XmlReader> XmlReaderPtr;
 typedef std::shared_ptr<XmlReader> XmlReaderPtr;
 
 
+struct OpcPackageRelationship {
+    std::string id;
+    std::string type;
+    std::string target;
+};
+
 class D3MFZipArchive;
 class D3MFZipArchive;
 
 
-class D3MFOpcPackage
-{
+class D3MFOpcPackage {
 public:
 public:
     D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile);
     D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile);
     ~D3MFOpcPackage();
     ~D3MFOpcPackage();
-
     IOStream* RootStream() const;
     IOStream* RootStream() const;
-private:
+
+protected:
     std::string ReadPackageRootRelationship(IOStream* stream);
     std::string ReadPackageRootRelationship(IOStream* stream);
+
 private:
 private:
-    IOStream* m_RootStream;
-    std::unique_ptr<D3MFZipArchive> zipArchive;
+    IOStream* mRootStream;
+    std::unique_ptr<D3MFZipArchive> mZipArchive;
 };
 };
 
 
 }
 }

+ 1 - 1
code/DeboneProcess.h

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

+ 2 - 1
code/DefaultIOStream.cpp

@@ -123,7 +123,8 @@ size_t DefaultIOStream::FileSize() const
         // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
         // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file
 #if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601)
 #if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601)
         struct __stat64 fileStat;
         struct __stat64 fileStat;
-        int err = _stat64(  mFilename.c_str(), &fileStat );
+        //using fileno + fstat avoids having to handle the filename
+        int err = _fstat64(  _fileno(mFile), &fileStat );
         if (0 != err)
         if (0 != err)
             return 0;
             return 0;
         mCachedSize = (size_t) (fileStat.st_size);
         mCachedSize = (size_t) (fileStat.st_size);

+ 75 - 31
code/DefaultIOSystem.cpp

@@ -49,37 +49,54 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/ai_assert.h>
 #include <assimp/ai_assert.h>
 #include <stdlib.h>
 #include <stdlib.h>
 
 
-
 #ifdef __unix__
 #ifdef __unix__
 #include <sys/param.h>
 #include <sys/param.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #endif
 #endif
 
 
-using namespace Assimp;
+#ifdef _WIN32
+#include <windows.h>
+#endif
 
 
-// ------------------------------------------------------------------------------------------------
-// Constructor.
-DefaultIOSystem::DefaultIOSystem()
-{
-    // nothing to do here
-}
+using namespace Assimp;
 
 
-// ------------------------------------------------------------------------------------------------
-// Destructor.
-DefaultIOSystem::~DefaultIOSystem()
-{
-    // nothing to do here
-}
+// maximum path length
+// XXX http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
+#ifdef PATH_MAX
+#   define PATHLIMIT PATH_MAX
+#else
+#   define PATHLIMIT 4096
+#endif
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Tests for the existence of a file at the given path.
 // Tests for the existence of a file at the given path.
 bool DefaultIOSystem::Exists( const char* pFile) const
 bool DefaultIOSystem::Exists( const char* pFile) const
 {
 {
+#ifdef _WIN32
+    wchar_t fileName16[PATHLIMIT];
+
+    bool isUnicode = IsTextUnicode(pFile, strlen(pFile), NULL);
+    if (isUnicode) {
+
+        MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
+        struct _stat64 filestat;
+        if (0 != _wstat64(fileName16, &filestat)) {
+            return false;
+        }
+    } else {
+        FILE* file = ::fopen(pFile, "rb");
+        if (!file)
+            return false;
+
+        ::fclose(file);
+    }
+#else
     FILE* file = ::fopen( pFile, "rb");
     FILE* file = ::fopen( pFile, "rb");
     if( !file)
     if( !file)
         return false;
         return false;
 
 
     ::fclose( file);
     ::fclose( file);
+#endif
     return true;
     return true;
 }
 }
 
 
@@ -89,10 +106,22 @@ IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode)
 {
 {
     ai_assert(NULL != strFile);
     ai_assert(NULL != strFile);
     ai_assert(NULL != strMode);
     ai_assert(NULL != strMode);
-
-    FILE* file = ::fopen( strFile, strMode);
-    if( NULL == file)
-        return NULL;
+    FILE* file;
+#ifdef _WIN32
+    wchar_t fileName16[PATHLIMIT];
+    bool isUnicode = IsTextUnicode(strFile, strlen(strFile), NULL );
+    if (isUnicode) {
+        MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT);
+        std::string mode8(strMode);
+        file = ::_wfopen(fileName16, std::wstring(mode8.begin(), mode8.end()).c_str());
+    } else {
+        file = ::fopen(strFile, strMode);
+    }
+#else
+    file = ::fopen(strFile, strMode);
+#endif
+    if (nullptr == file)
+        return nullptr;
 
 
     return new DefaultIOStream(file, (std::string) strFile);
     return new DefaultIOStream(file, (std::string) strFile);
 }
 }
@@ -122,32 +151,47 @@ bool IOSystem::ComparePaths (const char* one, const char* second) const
     return !ASSIMP_stricmp(one,second);
     return !ASSIMP_stricmp(one,second);
 }
 }
 
 
-// maximum path length
-// XXX http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
-#ifdef PATH_MAX
-#   define PATHLIMIT PATH_MAX
-#else
-#   define PATHLIMIT 4096
-#endif
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Convert a relative path into an absolute path
 // Convert a relative path into an absolute path
-inline void MakeAbsolutePath (const char* in, char* _out)
+inline static void MakeAbsolutePath (const char* in, char* _out)
 {
 {
     ai_assert(in && _out);
     ai_assert(in && _out);
-    char* ret;
 #if defined( _MSC_VER ) || defined( __MINGW32__ )
 #if defined( _MSC_VER ) || defined( __MINGW32__ )
-    ret = ::_fullpath( _out, in, PATHLIMIT );
+    bool isUnicode = IsTextUnicode(in, strlen(in), NULL);
+    if (isUnicode) {
+        wchar_t out16[PATHLIMIT];
+        wchar_t in16[PATHLIMIT];
+        MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, in, -1, out16, PATHLIMIT);
+        wchar_t* ret = ::_wfullpath(out16, in16, PATHLIMIT);
+        if (ret) {
+            WideCharToMultiByte(CP_UTF8, MB_PRECOMPOSED, out16, -1, _out, PATHLIMIT, nullptr, nullptr);
+        }
+        if (!ret) {
+            // preserve the input path, maybe someone else is able to fix
+            // the path before it is accessed (e.g. our file system filter)
+            DefaultLogger::get()->warn("Invalid path: " + std::string(in));
+            strcpy(_out, in);
+        }
+
+    } else {
+        char* ret = :: _fullpath(_out, in, PATHLIMIT);
+        if (!ret) {
+            // preserve the input path, maybe someone else is able to fix
+            // the path before it is accessed (e.g. our file system filter)
+            DefaultLogger::get()->warn("Invalid path: " + std::string(in));
+            strcpy(_out, in);
+        }
+    }
 #else
 #else
     // use realpath
     // use realpath
-    ret = realpath(in, _out);
-#endif
+    char* ret = realpath(in, _out);
     if(!ret) {
     if(!ret) {
         // preserve the input path, maybe someone else is able to fix
         // preserve the input path, maybe someone else is able to fix
         // the path before it is accessed (e.g. our file system filter)
         // the path before it is accessed (e.g. our file system filter)
         DefaultLogger::get()->warn("Invalid path: "+std::string(in));
         DefaultLogger::get()->warn("Invalid path: "+std::string(in));
         strcpy(_out,in);
         strcpy(_out,in);
     }
     }
+#endif
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 147 - 0
code/EmbedTexturesProcess.cpp

@@ -0,0 +1,147 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the
+following conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#include "EmbedTexturesProcess.h"
+#include "ParsingUtils.h"
+#include "ProcessHelper.h"
+
+#include <fstream>
+
+using namespace Assimp;
+
+EmbedTexturesProcess::EmbedTexturesProcess()
+: BaseProcess() {
+}
+
+EmbedTexturesProcess::~EmbedTexturesProcess() {
+}
+
+bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
+    return (pFlags & aiProcess_EmbedTextures) != 0;
+}
+
+void EmbedTexturesProcess::SetupProperties(const Importer* pImp) {
+    mRootPath = pImp->GetPropertyString("sourceFilePath");
+    mRootPath = mRootPath.substr(0, mRootPath.find_last_of("\\/") + 1u);
+}
+
+void EmbedTexturesProcess::Execute(aiScene* pScene) {
+    if (pScene == nullptr || pScene->mRootNode == nullptr) return;
+
+    aiString path;
+
+    uint32_t embeddedTexturesCount = 0u;
+
+    for (auto matId = 0u; matId < pScene->mNumMaterials; ++matId) {
+        auto material = pScene->mMaterials[matId];
+
+        for (auto ttId = 1u; ttId < AI_TEXTURE_TYPE_MAX; ++ttId) {
+            auto tt = static_cast<aiTextureType>(ttId);
+            auto texturesCount = material->GetTextureCount(tt);
+
+            for (auto texId = 0u; texId < texturesCount; ++texId) {
+                material->GetTexture(tt, texId, &path);
+                if (path.data[0] == '*') continue; // Already embedded
+
+                // Indeed embed
+                if (addTexture(pScene, path.data)) {
+                    auto embeddedTextureId = pScene->mNumTextures - 1u;
+                    ::ai_snprintf(path.data, 1024, "*%u", embeddedTextureId);
+                    material->AddProperty(&path, AI_MATKEY_TEXTURE(tt, texId));
+                    embeddedTexturesCount++;
+                }
+            }
+        }
+    }
+
+    char stringBuffer[128];
+    ::ai_snprintf(stringBuffer, 128, "EmbedTexturesProcess finished. Embedded %u textures.", embeddedTexturesCount);
+    DefaultLogger::get()->info(stringBuffer);
+}
+
+bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
+    uint32_t imageSize = 0;
+    std::string imagePath = path;
+
+    // Test path directly
+    std::ifstream file(imagePath, std::ios::binary | std::ios::ate);
+    if ((imageSize = file.tellg()) == -1u) {
+        DefaultLogger::get()->warn("EmbedTexturesProcess: Cannot find image: " + imagePath + ". Will try to find it in root folder.");
+
+        // Test path in root path
+        imagePath = mRootPath + path;
+        file.open(imagePath, std::ios::binary | std::ios::ate);
+        if ((imageSize = file.tellg()) == -1u) {
+            // Test path basename in root path
+            imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u);
+            file.open(imagePath, std::ios::binary | std::ios::ate);
+            if ((imageSize = file.tellg()) == -1u) {
+                DefaultLogger::get()->error("EmbedTexturesProcess: Unable to embed texture: " + path + ".");
+                return false;
+            }
+        }
+    }
+
+    aiTexel* imageContent = new aiTexel[1u + imageSize / sizeof(aiTexel)];
+    file.seekg(0, std::ios::beg);
+    file.read(reinterpret_cast<char*>(imageContent), imageSize);
+
+    // Enlarging the textures table
+    auto textureId = pScene->mNumTextures++;
+    auto oldTextures = pScene->mTextures;
+    pScene->mTextures = new aiTexture*[pScene->mNumTextures];
+    memmove(pScene->mTextures, oldTextures, sizeof(aiTexture*) * (pScene->mNumTextures - 1u));
+
+    // Add the new texture
+    auto pTexture = new aiTexture();
+    pTexture->mHeight = 0; // Means that this is still compressed
+    pTexture->mWidth = imageSize;
+    pTexture->pcData = imageContent;
+
+    auto extension = path.substr(path.find_last_of('.') + 1u);
+    std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
+    if (extension == "jpeg") extension = "jpg";
+    strcpy(pTexture->achFormatHint, extension.c_str());
+
+    pScene->mTextures[textureId] = pTexture;
+
+    return true;
+}

+ 84 - 0
code/EmbedTexturesProcess.h

@@ -0,0 +1,84 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2017, 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 "BaseProcess.h"
+
+#include <string>
+
+struct aiNode;
+
+namespace Assimp {
+
+/**
+ *  Force embedding of textures (using the path = "*1" convention).
+ *  If a texture's file does not exist at the specified path
+ *  (due, for instance, to an absolute path generated on another system),
+ *  it will check if a file with the same name exists at the root folder
+ *  of the imported model. And if so, it uses that.
+ */
+class ASSIMP_API EmbedTexturesProcess : public BaseProcess {
+public:
+    /// The default class constructor.
+    EmbedTexturesProcess();
+
+    /// The class destructor.
+    virtual ~EmbedTexturesProcess();
+
+    /// Overwritten, @see BaseProcess
+    virtual bool IsActive(unsigned int pFlags) const;
+
+    /// Overwritten, @see BaseProcess
+    virtual void SetupProperties(const Importer* pImp);
+
+    /// Overwritten, @see BaseProcess
+    virtual void Execute(aiScene* pScene);
+
+private:
+    // Resolve the path and add the file content to the scene as a texture.
+    bool addTexture(aiScene* pScene, std::string path) const;
+
+private:
+    std::string mRootPath;
+};
+
+} // namespace Assimp

+ 24 - 13
code/Exporter.cpp

@@ -83,6 +83,7 @@ void ExportSceneCollada(const char*,IOSystem*, const aiScene*, const ExportPrope
 void ExportSceneXFile(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneXFile(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneStep(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneStep(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneObj(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneObj(const char*,IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneObjNoMtl(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneSTL(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneSTL(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*);
 void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*);
@@ -91,30 +92,34 @@ void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperti
 void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneGLTF2(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneGLTF2(const char*, IOSystem*, const aiScene*, const ExportProperties*);
+void ExportSceneGLB2(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
+void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // global array of all export formats which Assimp supports in its current build
 // global array of all export formats which Assimp supports in its current build
 Exporter::ExportFormatEntry gExporters[] =
 Exporter::ExportFormatEntry gExporters[] =
 {
 {
 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
-    Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
+    Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada ),
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_X_EXPORTER
 #ifndef ASSIMP_BUILD_NO_X_EXPORTER
     Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
     Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
-        aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs),
+        aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs ),
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
 #ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
-    Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0),
+    Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0 ),
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
 #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
     Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
     Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
-        aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */),
+        aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ),
+    Exporter::ExportFormatEntry( "objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl,
+        aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ),
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_STL_EXPORTER
 #ifndef ASSIMP_BUILD_NO_STL_EXPORTER
@@ -137,28 +142,34 @@ Exporter::ExportFormatEntry gExporters[] =
 
 
 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
     Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS,
     Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS,
-        aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices),
+        aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices ),
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
 #ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
     Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
     Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
-        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType),
+        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
     Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
     Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
-        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType),
+        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
     Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf2", &ExportSceneGLTF2,
     Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf2", &ExportSceneGLTF2,
-        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType),
+        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
+    Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb2", &ExportSceneGLB2,
+        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
-    Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0),
+    Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0 ),
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
 #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
-    Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0),
+    Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0 ),
 #endif
 #endif
 
 
 #ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
 #ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
-	Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0),
+    Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ),
+#endif
+
+#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
+    Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 )
 #endif
 #endif
 };
 };
 
 
@@ -241,7 +252,7 @@ bool Exporter::IsDefaultIOHandler() const {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId,
 const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId,
-                                                unsigned int, const ExportProperties* pProperties ) {
+                                                unsigned int, const ExportProperties* /*pProperties*/ ) {
     if (pimpl->blob) {
     if (pimpl->blob) {
         delete pimpl->blob;
         delete pimpl->blob;
         pimpl->blob = NULL;
         pimpl->blob = NULL;
@@ -412,7 +423,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
 
 
     pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
     pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
     ASSIMP_END_EXCEPTION_REGION(aiReturn);
     ASSIMP_END_EXCEPTION_REGION(aiReturn);
-    
+
     return AI_FAILURE;
     return AI_FAILURE;
 }
 }
 
 

+ 23 - 22
code/FBXBinaryTokenizer.cpp

@@ -129,29 +129,26 @@ AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offse
 
 
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-uint32_t Offset(const char* begin, const char* cursor)
-{
+uint32_t Offset(const char* begin, const char* cursor) {
     ai_assert(begin <= cursor);
     ai_assert(begin <= cursor);
+
     return static_cast<unsigned int>(cursor - begin);
     return static_cast<unsigned int>(cursor - begin);
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void TokenizeError(const std::string& message, const char* begin, const char* cursor)
-{
+void TokenizeError(const std::string& message, const char* begin, const char* cursor) {
     TokenizeError(message, Offset(begin, cursor));
     TokenizeError(message, Offset(begin, cursor));
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-uint32_t ReadWord(const char* input, const char*& cursor, const char* end)
-{
+uint32_t ReadWord(const char* input, const char*& cursor, const char* end) {
     const size_t k_to_read = sizeof( uint32_t );
     const size_t k_to_read = sizeof( uint32_t );
     if(Offset(cursor, end) < k_to_read ) {
     if(Offset(cursor, end) < k_to_read ) {
         TokenizeError("cannot ReadWord, out of bounds",input, cursor);
         TokenizeError("cannot ReadWord, out of bounds",input, cursor);
     }
     }
 
 
-    uint32_t word = *reinterpret_cast<const uint32_t*>(cursor);
+    uint32_t word;
+    ::memcpy(&word, cursor, 4);
     AI_SWAP4(word);
     AI_SWAP4(word);
 
 
     cursor += k_to_read;
     cursor += k_to_read;
@@ -166,7 +163,8 @@ uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end)
         TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor);
         TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor);
     }
     }
 
 
-    uint64_t dword = *reinterpret_cast<const uint64_t*>(cursor);
+    uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/;
+    ::memcpy( &dword, cursor, sizeof( uint64_t ) );
     AI_SWAP8(dword);
     AI_SWAP8(dword);
 
 
     cursor += k_to_read;
     cursor += k_to_read;
@@ -175,24 +173,21 @@ uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end)
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-uint8_t ReadByte(const char* input, const char*& cursor, const char* end)
-{
+uint8_t ReadByte(const char* input, const char*& cursor, const char* end) {
     if(Offset(cursor, end) < sizeof( uint8_t ) ) {
     if(Offset(cursor, end) < sizeof( uint8_t ) ) {
         TokenizeError("cannot ReadByte, out of bounds",input, cursor);
         TokenizeError("cannot ReadByte, out of bounds",input, cursor);
     }
     }
 
 
-    uint8_t word = *reinterpret_cast<const uint8_t*>(cursor);
+    uint8_t word;/* = *reinterpret_cast< const uint8_t* >( cursor )*/
+    ::memcpy( &word, cursor, sizeof( uint8_t ) );
     ++cursor;
     ++cursor;
 
 
     return word;
     return word;
 }
 }
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end,
-    bool long_length = false,
-    bool allow_null = false)
-{
+unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input,
+        const char*& cursor, const char* end, bool long_length = false, bool allow_null = false) {
     const uint32_t len_len = long_length ? 4 : 1;
     const uint32_t len_len = long_length ? 4 : 1;
     if(Offset(cursor, end) < len_len) {
     if(Offset(cursor, end) < len_len) {
         TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
         TokenizeError("cannot ReadString, out of bounds reading length",input, cursor);
@@ -221,8 +216,7 @@ unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const ch
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end)
-{
+void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) {
     if(Offset(cursor, end) < 1) {
     if(Offset(cursor, end) < 1) {
         TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
         TokenizeError("cannot ReadData, out of bounds reading length",input, cursor);
     }
     }
@@ -421,8 +415,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
     return true;
     return true;
 }
 }
 
 
-
-}
+} // anonymous namespace
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
 // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
@@ -434,6 +427,14 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int le
         TokenizeError("file is too short",0);
         TokenizeError("file is too short",0);
     }
     }
 
 
+    //uint32_t offset = 0x15;
+/*    const char* cursor = input + 0x15;
+
+    const uint32_t flags = ReadWord(input, cursor, input + length);
+
+    const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused
+    const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused*/
+
     if (strncmp(input,"Kaydara FBX Binary",18)) {
     if (strncmp(input,"Kaydara FBX Binary",18)) {
         TokenizeError("magic bytes not found",0);
         TokenizeError("magic bytes not found",0);
     }
     }

+ 38 - 38
code/FBXConverter.cpp

@@ -436,19 +436,6 @@ private:
 
 
     aiScene* const out;
     aiScene* const out;
     const FBX::Document& doc;
     const FBX::Document& doc;
-
-	bool FindTextureIndexByFilename(const Video& video, unsigned int& index) {
-		index = 0;
-		const char* videoFileName = video.FileName().c_str();
-		for (auto texture = textures_converted.begin(); texture != textures_converted.end(); ++texture)
-		{
-			if (!strcmp(texture->first->FileName().c_str(), videoFileName)) {
-				return true;
-			}
-			index++;
-		}
-		return false;
-	}
 };
 };
 
 
 Converter::Converter( aiScene* out, const Document& doc )
 Converter::Converter( aiScene* out, const Document& doc )
@@ -566,7 +553,6 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
 
 
                 if ( !name_carrier ) {
                 if ( !name_carrier ) {
                     nodes_chain.push_back( new aiNode( original_name ) );
                     nodes_chain.push_back( new aiNode( original_name ) );
-                    name_carrier = nodes_chain.back();
                 }
                 }
 
 
                 //setup metadata on newest node
                 //setup metadata on newest node
@@ -645,7 +631,6 @@ void Converter::ConvertCameras( const Model& model )
     }
     }
 }
 }
 
 
-
 void Converter::ConvertLight( const Model& model, const Light& light )
 void Converter::ConvertLight( const Model& model, const Light& light )
 {
 {
     lights.push_back( new aiLight() );
     lights.push_back( new aiLight() );
@@ -783,7 +768,6 @@ const char* Converter::NameTransformationComp( TransformationComp comp )
     return NULL;
     return NULL;
 }
 }
 
 
-
 const char* Converter::NameTransformationCompProperty( TransformationComp comp )
 const char* Converter::NameTransformationCompProperty( TransformationComp comp )
 {
 {
     switch ( comp )
     switch ( comp )
@@ -1780,6 +1764,8 @@ unsigned int Converter::ConvertVideo( const Video& video )
         memcpy( out_tex->achFormatHint, ext.c_str(), ext.size() );
         memcpy( out_tex->achFormatHint, ext.c_str(), ext.size() );
     }
     }
 
 
+    out_tex->mFilename.Set(video.FileName().c_str());
+
     return static_cast<unsigned int>( textures.size() - 1 );
     return static_cast<unsigned int>( textures.size() - 1 );
 }
 }
 
 
@@ -1814,15 +1800,19 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
 					textures_converted[media] = index;
 					textures_converted[media] = index;
 					textureReady = true;
 					textureReady = true;
 				}
 				}
-				else if (doc.Settings().searchEmbeddedTextures) { //try to find the texture on the already-loaded textures by the filename, if the flag is on					
-					textureReady = FindTextureIndexByFilename(*media, index);
-				}
 			}
 			}
 
 
 			// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
 			// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
-			if (textureReady) {
-				path.data[0] = '*';
-				path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
+			if (doc.Settings().useLegacyEmbeddedTextureNaming) {
+                if (textureReady) {
+                    // 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 thru 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
+                    path.data[0] = '*';
+                    path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
+                }
 			}
 			}
 		}  
 		}  
 
 
@@ -2239,9 +2229,17 @@ void Converter::ConvertAnimations()
     }
     }
 }
 }
 
 
+void Converter::RenameNode( const std::string& fixed_name, const std::string& new_name ) {
+    if ( node_names.find( fixed_name ) == node_names.end() ) {
+        FBXImporter::LogError( "Cannot rename node " + fixed_name + ", not existing.");
+        return;
+    }
+
+    if ( node_names.find( new_name ) != node_names.end() ) {
+        FBXImporter::LogError( "Cannot rename node " + fixed_name + " to " + new_name +", name already existing." );
+        return;
+    }
 
 
-void Converter::RenameNode( const std::string& fixed_name, const std::string& new_name )
-{
     ai_assert( node_names.find( fixed_name ) != node_names.end() );
     ai_assert( node_names.find( fixed_name ) != node_names.end() );
     ai_assert( node_names.find( new_name ) == node_names.end() );
     ai_assert( node_names.find( new_name ) == node_names.end() );
 
 
@@ -2429,6 +2427,7 @@ void Converter::ConvertAnimationStack( const AnimationStack& st )
     anim->mTicksPerSecond = anim_fps;
     anim->mTicksPerSecond = anim_fps;
 }
 }
 
 
+#ifdef ASSIMP_BUILD_DEBUG
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // sanity check whether the input is ok
 // sanity check whether the input is ok
 static void validateAnimCurveNodes( const std::vector<const AnimationCurveNode*>& curves,
 static void validateAnimCurveNodes( const std::vector<const AnimationCurveNode*>& curves,
@@ -2446,6 +2445,7 @@ static void validateAnimCurveNodes( const std::vector<const AnimationCurveNode*>
         }
         }
     }
     }
 }
 }
+#endif // ASSIMP_BUILD_DEBUG
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
 void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
@@ -2737,10 +2737,10 @@ aiNodeAnim* Converter::GenerateRotationNodeAnim( const std::string& name,
     double& max_time,
     double& max_time,
     double& min_time )
     double& min_time )
 {
 {
-    ScopeGuard<aiNodeAnim> na( new aiNodeAnim() );
+    std::unique_ptr<aiNodeAnim> na( new aiNodeAnim() );
     na->mNodeName.Set( name );
     na->mNodeName.Set( name );
 
 
-    ConvertRotationKeys( na, curves, layer_map, start, stop, max_time, min_time, target.RotationOrder() );
+    ConvertRotationKeys( na.get(), curves, layer_map, start, stop, max_time, min_time, target.RotationOrder() );
 
 
     // dummy scaling key
     // dummy scaling key
     na->mScalingKeys = new aiVectorKey[ 1 ];
     na->mScalingKeys = new aiVectorKey[ 1 ];
@@ -2756,7 +2756,7 @@ aiNodeAnim* Converter::GenerateRotationNodeAnim( const std::string& name,
     na->mPositionKeys[ 0 ].mTime = 0.;
     na->mPositionKeys[ 0 ].mTime = 0.;
     na->mPositionKeys[ 0 ].mValue = aiVector3D();
     na->mPositionKeys[ 0 ].mValue = aiVector3D();
 
 
-    return na.dismiss();
+    return na.release();
 }
 }
 
 
 aiNodeAnim* Converter::GenerateScalingNodeAnim( const std::string& name,
 aiNodeAnim* Converter::GenerateScalingNodeAnim( const std::string& name,
@@ -2767,10 +2767,10 @@ aiNodeAnim* Converter::GenerateScalingNodeAnim( const std::string& name,
     double& max_time,
     double& max_time,
     double& min_time )
     double& min_time )
 {
 {
-    ScopeGuard<aiNodeAnim> na( new aiNodeAnim() );
+    std::unique_ptr<aiNodeAnim> na( new aiNodeAnim() );
     na->mNodeName.Set( name );
     na->mNodeName.Set( name );
 
 
-    ConvertScaleKeys( na, curves, layer_map, start, stop, max_time, min_time );
+    ConvertScaleKeys( na.get(), curves, layer_map, start, stop, max_time, min_time );
 
 
     // dummy rotation key
     // dummy rotation key
     na->mRotationKeys = new aiQuatKey[ 1 ];
     na->mRotationKeys = new aiQuatKey[ 1 ];
@@ -2786,7 +2786,7 @@ aiNodeAnim* Converter::GenerateScalingNodeAnim( const std::string& name,
     na->mPositionKeys[ 0 ].mTime = 0.;
     na->mPositionKeys[ 0 ].mTime = 0.;
     na->mPositionKeys[ 0 ].mValue = aiVector3D();
     na->mPositionKeys[ 0 ].mValue = aiVector3D();
 
 
-    return na.dismiss();
+    return na.release();
 }
 }
 
 
 
 
@@ -2799,10 +2799,10 @@ aiNodeAnim* Converter::GenerateTranslationNodeAnim( const std::string& name,
     double& min_time,
     double& min_time,
     bool inverse )
     bool inverse )
 {
 {
-    ScopeGuard<aiNodeAnim> na( new aiNodeAnim() );
+    std::unique_ptr<aiNodeAnim> na( new aiNodeAnim() );
     na->mNodeName.Set( name );
     na->mNodeName.Set( name );
 
 
-    ConvertTranslationKeys( na, curves, layer_map, start, stop, max_time, min_time );
+    ConvertTranslationKeys( na.get(), curves, layer_map, start, stop, max_time, min_time );
 
 
     if ( inverse ) {
     if ( inverse ) {
         for ( unsigned int i = 0; i < na->mNumPositionKeys; ++i ) {
         for ( unsigned int i = 0; i < na->mNumPositionKeys; ++i ) {
@@ -2824,7 +2824,7 @@ aiNodeAnim* Converter::GenerateTranslationNodeAnim( const std::string& name,
     na->mRotationKeys[ 0 ].mTime = 0.;
     na->mRotationKeys[ 0 ].mTime = 0.;
     na->mRotationKeys[ 0 ].mValue = aiQuaternion();
     na->mRotationKeys[ 0 ].mValue = aiQuaternion();
 
 
-    return na.dismiss();
+    return na.release();
 }
 }
 
 
 aiNodeAnim* Converter::GenerateSimpleNodeAnim( const std::string& name,
 aiNodeAnim* Converter::GenerateSimpleNodeAnim( const std::string& name,
@@ -2838,7 +2838,7 @@ aiNodeAnim* Converter::GenerateSimpleNodeAnim( const std::string& name,
     bool reverse_order )
     bool reverse_order )
 
 
 {
 {
-    ScopeGuard<aiNodeAnim> na( new aiNodeAnim() );
+    std::unique_ptr<aiNodeAnim> na( new aiNodeAnim() );
     na->mNodeName.Set( name );
     na->mNodeName.Set( name );
 
 
     const PropertyTable& props = target.Props();
     const PropertyTable& props = target.Props();
@@ -2910,7 +2910,7 @@ aiNodeAnim* Converter::GenerateSimpleNodeAnim( const std::string& name,
         // which requires all of rotation, scaling and translation
         // which requires all of rotation, scaling and translation
         // to be set.
         // to be set.
         if ( chain[ TransformationComp_Scaling ] != iter_end ) {
         if ( chain[ TransformationComp_Scaling ] != iter_end ) {
-            ConvertScaleKeys( na, ( *chain[ TransformationComp_Scaling ] ).second,
+            ConvertScaleKeys( na.get(), ( *chain[ TransformationComp_Scaling ] ).second,
                 layer_map,
                 layer_map,
                 start, stop,
                 start, stop,
                 max_time,
                 max_time,
@@ -2926,7 +2926,7 @@ aiNodeAnim* Converter::GenerateSimpleNodeAnim( const std::string& name,
         }
         }
 
 
         if ( chain[ TransformationComp_Rotation ] != iter_end ) {
         if ( chain[ TransformationComp_Rotation ] != iter_end ) {
-            ConvertRotationKeys( na, ( *chain[ TransformationComp_Rotation ] ).second,
+            ConvertRotationKeys( na.get(), ( *chain[ TransformationComp_Rotation ] ).second,
                 layer_map,
                 layer_map,
                 start, stop,
                 start, stop,
                 max_time,
                 max_time,
@@ -2944,7 +2944,7 @@ aiNodeAnim* Converter::GenerateSimpleNodeAnim( const std::string& name,
         }
         }
 
 
         if ( chain[ TransformationComp_Translation ] != iter_end ) {
         if ( chain[ TransformationComp_Translation ] != iter_end ) {
-            ConvertTranslationKeys( na, ( *chain[ TransformationComp_Translation ] ).second,
+            ConvertTranslationKeys( na.get(), ( *chain[ TransformationComp_Translation ] ).second,
                 layer_map,
                 layer_map,
                 start, stop,
                 start, stop,
                 max_time,
                 max_time,
@@ -2960,7 +2960,7 @@ aiNodeAnim* Converter::GenerateSimpleNodeAnim( const std::string& name,
         }
         }
 
 
     }
     }
-    return na.dismiss();
+    return na.release();
 }
 }
 
 
 Converter::KeyFrameListList Converter::GetKeyframeList( const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop )
 Converter::KeyFrameListList Converter::GetKeyframeList( const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop )

+ 2 - 2
code/FBXDocument.cpp

@@ -619,10 +619,10 @@ std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t dest, const char* classname) const
+std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t src, const char* classname) const
 {
 {
     const char* arr[] = {classname};
     const char* arr[] = {classname};
-    return GetConnectionsBySourceSequenced(dest, arr,1);
+    return GetConnectionsBySourceSequenced(src, arr,1);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 4 - 4
code/FBXImportSettings.h

@@ -63,7 +63,7 @@ struct ImportSettings
         , readWeights(true)
         , readWeights(true)
         , preservePivots(true)
         , preservePivots(true)
         , optimizeEmptyAnimationCurves(true)
         , optimizeEmptyAnimationCurves(true)
-		, searchEmbeddedTextures(false)
+        , useLegacyEmbeddedTextureNaming(false)
     {}
     {}
 
 
 
 
@@ -139,9 +139,9 @@ struct ImportSettings
      *  The default value is true. */
      *  The default value is true. */
     bool optimizeEmptyAnimationCurves;
     bool optimizeEmptyAnimationCurves;
 
 
-	/** search for embedded loaded textures, where no embedded texture data is provided.
-	*  The default value is false. */
-	bool searchEmbeddedTextures;
+    /** use legacy naming for embedded textures eg: (*0, *1, *2)
+    **/
+    bool useLegacyEmbeddedTextureNaming;
 };
 };
 
 
 
 

+ 1 - 1
code/FBXImporter.cpp

@@ -135,7 +135,7 @@ void FBXImporter::SetupProperties(const Importer* pImp)
     settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
     settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
     settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
     settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
     settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
     settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
-	settings.searchEmbeddedTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES, false);
+    settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 28 - 28
code/FBXMaterial.cpp

@@ -291,40 +291,40 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std
 
 
     if(FileName) {
     if(FileName) {
         fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
         fileName = ParseTokenAsString(GetRequiredToken(*FileName,0));
-	}
+    }
 
 
     if(RelativeFilename) {
     if(RelativeFilename) {
         relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
         relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
     }
     }
 
 
     if(Content) {
     if(Content) {
-		//this field is ommited when the embedded texture is already loaded, let's ignore if it´s not found
-		try {
-			const Token& token = GetRequiredToken(*Content, 0);
-			const char* data = token.begin();
-			if (!token.IsBinary()) {
-				DOMWarning("video content is not binary data, ignoring", &element);
-			}
-			else if (static_cast<size_t>(token.end() - data) < 5) {
-				DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element);
-			}
-			else if (*data != 'R') {
-				DOMWarning("video content is not raw binary data, ignoring", &element);
-			}
-			else {
-				// read number of elements
-				uint32_t len = 0;
-				::memcpy(&len, data + 1, sizeof(len));
-				AI_SWAP4(len);
-
-				contentLength = len;
-
-				content = new uint8_t[len];
-				::memcpy(content, data + 5, len);
-			}
-		} catch (runtime_error runtimeError) {
-			//we don´t need the content data for contents that has already been loaded
-		}
+        //this field is ommited when the embedded texture is already loaded, let's ignore if it's not found
+        try {
+            const Token& token = GetRequiredToken(*Content, 0);
+            const char* data = token.begin();
+            if (!token.IsBinary()) {
+                DOMWarning("video content is not binary data, ignoring", &element);
+            }
+            else if (static_cast<size_t>(token.end() - data) < 5) {
+                DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element);
+            }
+            else if (*data != 'R') {
+                DOMWarning("video content is not raw binary data, ignoring", &element);
+            }
+            else {
+                // read number of elements
+                uint32_t len = 0;
+                ::memcpy(&len, data + 1, sizeof(len));
+                AI_SWAP4(len);
+
+                contentLength = len;
+
+                content = new uint8_t[len];
+                ::memcpy(content, data + 5, len);
+            }
+        } catch (runtime_error runtimeError) {
+            //we don't need the content data for contents that has already been loaded
+        }
     }
     }
 
 
     props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);
     props = GetPropertyTable(doc,"Video.FbxVideo",element,sc);

+ 8 - 2
code/FBXMeshGeometry.cpp

@@ -433,7 +433,11 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
     // deal with this more elegantly and with less redundancy, but right
     // deal with this more elegantly and with less redundancy, but right
     // now it seems unavoidable.
     // now it seems unavoidable.
     if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
     if (MappingInformationType == "ByVertice" && ReferenceInformationType == "Direct") {
-		std::vector<T> tempData;
+        if ( !HasElement( source, indexDataElementName ) ) {
+            return;
+        }
+
+        std::vector<T> tempData;
 		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
 		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
 
 
         data_out.resize(vertex_count);
         data_out.resize(vertex_count);
@@ -450,10 +454,12 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
 		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
 		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
 
 
         data_out.resize(vertex_count);
         data_out.resize(vertex_count);
+        if ( !HasElement( source, indexDataElementName ) ) {
+            return;
+        }
 
 
         std::vector<int> uvIndices;
         std::vector<int> uvIndices;
         ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
         ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName));
-
         for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
         for (size_t i = 0, e = uvIndices.size(); i < e; ++i) {
 
 
             const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];
             const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i];

+ 9 - 0
code/FBXParser.cpp

@@ -103,6 +103,7 @@ namespace {
     T SafeParse(const char* data, const char* end) {
     T SafeParse(const char* data, const char* end) {
         // Actual size validation happens during Tokenization so
         // Actual size validation happens during Tokenization so
         // this is valid as an assertion.
         // this is valid as an assertion.
+        (void)(end);
         ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
         ai_assert(static_cast<size_t>(end - data) >= sizeof(T));
         T result = static_cast<T>(0);
         T result = static_cast<T>(0);
         ::memcpy(&result, data, sizeof(T));
         ::memcpy(&result, data, sizeof(T));
@@ -1196,6 +1197,14 @@ std::string ParseTokenAsString(const Token& t)
     return i;
     return i;
 }
 }
 
 
+bool HasElement( const Scope& sc, const std::string& index ) {
+    const Element* el = sc[ index ];
+    if ( nullptr == el ) {
+        return false;
+    }
+
+    return true;
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // extract a required element from a scope, abort if the element cannot be found
 // extract a required element from a scope, abort if the element cannot be found

+ 2 - 0
code/FBXParser.h

@@ -218,6 +218,8 @@ void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el);
 void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
 void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e);
 void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el);
 void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el);
 
 
+bool HasElement( const Scope& sc, const std::string& index );
+
 // extract a required element from a scope, abort if the element cannot be found
 // extract a required element from a scope, abort if the element cannot be found
 const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL);
 const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL);
 
 

+ 26 - 17
code/FIReader.cpp

@@ -45,19 +45,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
 #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
 
 
+#include "FIReader.hpp"
+#include "StringUtils.h"
+
 // Workaround for issue #1361
 // Workaround for issue #1361
 // https://github.com/assimp/assimp/issues/1361
 // https://github.com/assimp/assimp/issues/1361
 #ifdef __ANDROID__
 #ifdef __ANDROID__
-#define _GLIBCXX_USE_C99 1
+#  define _GLIBCXX_USE_C99 1
 #endif
 #endif
 
 
-#include "FIReader.hpp"
 #include "Exceptional.h"
 #include "Exceptional.h"
 #include <assimp/IOStream.hpp>
 #include <assimp/IOStream.hpp>
 #include <assimp/types.h>
 #include <assimp/types.h>
 #include "MemoryIOWrapper.h"
 #include "MemoryIOWrapper.h"
 #include "irrXMLWrapper.h"
 #include "irrXMLWrapper.h"
 #include "../contrib/utf8cpp/source/utf8.h"
 #include "../contrib/utf8cpp/source/utf8.h"
+#include "fast_atof.h"
 #include <stack>
 #include <stack>
 #include <map>
 #include <map>
 #include <iostream>
 #include <iostream>
@@ -485,7 +488,9 @@ struct FIFloatDecoder: public FIDecoder {
         value.reserve(numFloats);
         value.reserve(numFloats);
         for (size_t i = 0; i < numFloats; ++i) {
         for (size_t i = 0; i < numFloats; ++i) {
             int v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
             int v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
-            value.push_back(*(float*)&v);
+            float f;
+            memcpy(&f, &v, 4);
+            value.push_back(f);
             data += 4;
             data += 4;
         }
         }
         return FIFloatValue::create(std::move(value));
         return FIFloatValue::create(std::move(value));
@@ -503,7 +508,9 @@ struct FIDoubleDecoder: public FIDecoder {
         for (size_t i = 0; i < numDoubles; ++i) {
         for (size_t i = 0; i < numDoubles; ++i) {
             long long b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7];
             long long b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7];
             long long v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
             long long v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
-            value.push_back(*(double*)&v);
+            double f;
+            memcpy(&f, &v, 8);
+            value.push_back(f);
             data += 8;
             data += 8;
         }
         }
         return FIDoubleValue::create(std::move(value));
         return FIDoubleValue::create(std::move(value));
@@ -685,7 +692,7 @@ public:
         if (intValue) {
         if (intValue) {
             return intValue->value.size() == 1 ? intValue->value.front() : 0;
             return intValue->value.size() == 1 ? intValue->value.front() : 0;
         }
         }
-        return stoi(attr->value->toString());
+        return atoi(attr->value->toString().c_str());
     }
     }
 
 
     virtual int getAttributeValueAsInt(int idx) const /*override*/ {
     virtual int getAttributeValueAsInt(int idx) const /*override*/ {
@@ -696,7 +703,7 @@ public:
         if (intValue) {
         if (intValue) {
             return intValue->value.size() == 1 ? intValue->value.front() : 0;
             return intValue->value.size() == 1 ? intValue->value.front() : 0;
         }
         }
-        return stoi(attributes[idx].value->toString());
+        return atoi(attributes[idx].value->toString().c_str());
     }
     }
 
 
     virtual float getAttributeValueAsFloat(const char* name) const /*override*/ {
     virtual float getAttributeValueAsFloat(const char* name) const /*override*/ {
@@ -708,7 +715,8 @@ public:
         if (floatValue) {
         if (floatValue) {
             return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
             return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
         }
         }
-        return stof(attr->value->toString());
+
+        return fast_atof(attr->value->toString().c_str());
     }
     }
 
 
     virtual float getAttributeValueAsFloat(int idx) const /*override*/ {
     virtual float getAttributeValueAsFloat(int idx) const /*override*/ {
@@ -719,7 +727,7 @@ public:
         if (floatValue) {
         if (floatValue) {
             return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
             return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
         }
         }
-        return stof(attributes[idx].value->toString());
+        return fast_atof(attributes[idx].value->toString().c_str());
     }
     }
 
 
     virtual const char* getNodeName() const /*override*/ {
     virtual const char* getNodeName() const /*override*/ {
@@ -984,13 +992,13 @@ private:
         if (index < 32) {
         if (index < 32) {
             FIDecoder *decoder = defaultDecoder[index];
             FIDecoder *decoder = defaultDecoder[index];
             if (!decoder) {
             if (!decoder) {
-                throw DeadlyImportError("Invalid encoding algorithm index " + std::to_string(index));
+                throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index));
             }
             }
             return decoder->decode(dataP, len);
             return decoder->decode(dataP, len);
         }
         }
         else {
         else {
             if (index - 32 >= vocabulary.encodingAlgorithmTable.size()) {
             if (index - 32 >= vocabulary.encodingAlgorithmTable.size()) {
-                throw DeadlyImportError("Invalid encoding algorithm index " + std::to_string(index));
+                throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index));
             }
             }
             std::string uri = vocabulary.encodingAlgorithmTable[index - 32];
             std::string uri = vocabulary.encodingAlgorithmTable[index - 32];
             auto it = decoderMap.find(uri);
             auto it = decoderMap.find(uri);
@@ -1014,12 +1022,12 @@ private:
                 alphabet = "0123456789-:TZ ";
                 alphabet = "0123456789-:TZ ";
                 break;
                 break;
             default:
             default:
-                throw DeadlyImportError("Invalid restricted alphabet index " + std::to_string(index));
+                throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index));
             }
             }
         }
         }
         else {
         else {
             if (index - 16 >= vocabulary.restrictedAlphabetTable.size()) {
             if (index - 16 >= vocabulary.restrictedAlphabetTable.size()) {
-                throw DeadlyImportError("Invalid restricted alphabet index " + std::to_string(index));
+                throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index));
             }
             }
             alphabet = vocabulary.restrictedAlphabetTable[index - 16];
             alphabet = vocabulary.restrictedAlphabetTable[index - 16];
         }
         }
@@ -1027,7 +1035,7 @@ private:
         utf8::utf8to32(alphabet.begin(), alphabet.end(), back_inserter(alphabetUTF32));
         utf8::utf8to32(alphabet.begin(), alphabet.end(), back_inserter(alphabetUTF32));
         std::string::size_type alphabetLength = alphabetUTF32.size();
         std::string::size_type alphabetLength = alphabetUTF32.size();
         if (alphabetLength < 2) {
         if (alphabetLength < 2) {
-            throw DeadlyImportError("Invalid restricted alphabet length " + std::to_string(alphabetLength));
+            throw DeadlyImportError("Invalid restricted alphabet length " + to_string(alphabetLength));
         }
         }
         std::string::size_type bitsPerCharacter = 1;
         std::string::size_type bitsPerCharacter = 1;
         while ((1ull << bitsPerCharacter) <= alphabetLength) {
         while ((1ull << bitsPerCharacter) <= alphabetLength) {
@@ -1776,17 +1784,18 @@ public:
         return reader->getParserFormat();
         return reader->getParserFormat();
     }
     }
 
 
-    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int idx) const /*override*/ {
+    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int /*idx*/) const /*override*/ {
         return nullptr;
         return nullptr;
     }
     }
 
 
-    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char* name) const /*override*/ {
+    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char* /*name*/) const /*override*/ {
         return nullptr;
         return nullptr;
     }
     }
 
 
-    virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr<FIDecoder> decoder) /*override*/ {}
+    virtual void registerDecoder(const std::string & /*algorithmUri*/, std::unique_ptr<FIDecoder> /*decoder*/) /*override*/ {}
+
 
 
-    virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) /*override*/ {}
+    virtual void registerVocabulary(const std::string &/*vocabularyUri*/, const FIVocabulary * /*vocabulary*/) /*override*/ {}
 
 
 private:
 private:
 
 

+ 19 - 4
code/FIReader.hpp

@@ -46,16 +46,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_FI_READER_H
 #ifndef INCLUDED_AI_FI_READER_H
 #define INCLUDED_AI_FI_READER_H
 #define INCLUDED_AI_FI_READER_H
 
 
-#include <irrXML.h>
-#include <memory>
+#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
+
+//#include <wchar.h>
 #include <string>
 #include <string>
+#include <memory>
+#include <cerrno>
+#include <cwchar>
 #include <vector>
 #include <vector>
-#include <cstdint>
+//#include <stdio.h>
+//#include <cstdint>
+#include <irrXML.h>
 
 
 namespace Assimp {
 namespace Assimp {
 
 
 struct FIValue {
 struct FIValue {
     virtual const std::string &toString() const = 0;
     virtual const std::string &toString() const = 0;
+    virtual ~FIValue() {}
 };
 };
 
 
 struct FIStringValue: public FIValue {
 struct FIStringValue: public FIValue {
@@ -115,6 +122,7 @@ struct FICDATAValue: public FIStringValue {
 
 
 struct FIDecoder {
 struct FIDecoder {
     virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) = 0;
     virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) = 0;
+    virtual ~FIDecoder() {}
 };
 };
 
 
 struct FIQName {
 struct FIQName {
@@ -154,7 +162,7 @@ class IOStream;
 
 
 class FIReader: public irr::io::IIrrXMLReader<char, irr::io::IXMLBase> {
 class FIReader: public irr::io::IIrrXMLReader<char, irr::io::IXMLBase> {
 public:
 public:
-
+	virtual ~FIReader();
     virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int idx) const = 0;
     virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int idx) const = 0;
 
 
     virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char *name) const = 0;
     virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char *name) const = 0;
@@ -167,6 +175,13 @@ public:
 
 
 };// class IFIReader
 };// class IFIReader
 
 
+inline
+FIReader::~FIReader() {
+	// empty
+}
+
 }// namespace Assimp
 }// namespace Assimp
 
 
+#endif // #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
+
 #endif // INCLUDED_AI_FI_READER_H
 #endif // INCLUDED_AI_FI_READER_H

+ 76 - 36
code/FindDegenerates.cpp

@@ -56,98 +56,138 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 FindDegeneratesProcess::FindDegeneratesProcess()
 FindDegeneratesProcess::FindDegeneratesProcess()
-: configRemoveDegenerates (false)
-{}
+: mConfigRemoveDegenerates( false )
+, mConfigCheckAreaOfTriangle( false ){
+    // empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Destructor, private as well
 // Destructor, private as well
-FindDegeneratesProcess::~FindDegeneratesProcess()
-{
+FindDegeneratesProcess::~FindDegeneratesProcess() {
     // nothing to do here
     // nothing to do here
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 // Returns whether the processing step is present in the given flag field.
-bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const
-{
+bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const {
     return 0 != (pFlags & aiProcess_FindDegenerates);
     return 0 != (pFlags & aiProcess_FindDegenerates);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Setup import configuration
 // Setup import configuration
-void FindDegeneratesProcess::SetupProperties(const Importer* pImp)
-{
+void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
     // Get the current value of AI_CONFIG_PP_FD_REMOVE
     // Get the current value of AI_CONFIG_PP_FD_REMOVE
-    configRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0));
+    mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0));
+    mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) );
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported data.
 // Executes the post processing step on the given imported data.
-void FindDegeneratesProcess::Execute( aiScene* pScene)
-{
+void FindDegeneratesProcess::Execute( aiScene* pScene) {
     DefaultLogger::get()->debug("FindDegeneratesProcess begin");
     DefaultLogger::get()->debug("FindDegeneratesProcess begin");
     for (unsigned int i = 0; i < pScene->mNumMeshes;++i){
     for (unsigned int i = 0; i < pScene->mNumMeshes;++i){
-        ExecuteOnMesh( pScene->mMeshes[i]);
+        ExecuteOnMesh( pScene->mMeshes[ i ] );
     }
     }
     DefaultLogger::get()->debug("FindDegeneratesProcess finished");
     DefaultLogger::get()->debug("FindDegeneratesProcess finished");
 }
 }
 
 
+static ai_real heron( ai_real a, ai_real b, ai_real c ) {
+    ai_real s = (a + b + c) / 2;
+    ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 );
+    return area;
+}
+
+static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB ) {
+    const ai_real lx = ( vB.x - vA.x );
+    const ai_real ly = ( vB.y - vA.y );
+    const ai_real lz = ( vB.z - vA.z );
+    ai_real a = lx*lx + ly*ly + lz*lz;
+    ai_real d = pow( a, (ai_real)0.5 );
+
+    return d;
+}
+
+static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
+    ai_real area = 0;
+
+    aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] );
+    aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] );
+    aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] );
+
+    ai_real a( distance3D( vA, vB ) );
+    ai_real b( distance3D( vB, vC ) );
+    ai_real c( distance3D( vC, vA ) );
+    area = heron( a, b, c );
+
+    return area;
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Executes the post processing step on the given imported mesh
 // Executes the post processing step on the given imported mesh
-void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh)
-{
+void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
     mesh->mPrimitiveTypes = 0;
     mesh->mPrimitiveTypes = 0;
 
 
     std::vector<bool> remove_me;
     std::vector<bool> remove_me;
-    if (configRemoveDegenerates)
-        remove_me.resize(mesh->mNumFaces,false);
+    if (mConfigRemoveDegenerates) {
+        remove_me.resize( mesh->mNumFaces, false );
+    }
 
 
     unsigned int deg = 0, limit;
     unsigned int deg = 0, limit;
-    for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
-    {
+    for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) {
         aiFace& face = mesh->mFaces[a];
         aiFace& face = mesh->mFaces[a];
         bool first = true;
         bool first = true;
 
 
         // check whether the face contains degenerated entries
         // check whether the face contains degenerated entries
-        for (unsigned int i = 0; i < face.mNumIndices; ++i)
-        {
+        for (unsigned int i = 0; i < face.mNumIndices; ++i) {
             // Polygons with more than 4 points are allowed to have double points, that is
             // Polygons with more than 4 points are allowed to have double points, that is
             // simulating polygons with holes just with concave polygons. However,
             // simulating polygons with holes just with concave polygons. However,
             // double points may not come directly after another.
             // double points may not come directly after another.
             limit = face.mNumIndices;
             limit = face.mNumIndices;
-            if (face.mNumIndices > 4)
-                limit = std::min(limit,i+2);
+            if (face.mNumIndices > 4) {
+                limit = std::min( limit, i+2 );
+            }
 
 
-            for (unsigned int t = i+1; t < limit; ++t)
-            {
-                if (mesh->mVertices[face.mIndices[i]] == mesh->mVertices[face.mIndices[t]])
-                {
+            for (unsigned int t = i+1; t < limit; ++t) {
+                if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) {
                     // we have found a matching vertex position
                     // we have found a matching vertex position
                     // remove the corresponding index from the array
                     // remove the corresponding index from the array
-                    --face.mNumIndices;--limit;
-                    for (unsigned int m = t; m < face.mNumIndices; ++m)
-                    {
-                        face.mIndices[m] = face.mIndices[m+1];
+                    --face.mNumIndices;
+                    --limit;
+                    for (unsigned int m = t; m < face.mNumIndices; ++m) {
+                        face.mIndices[ m ] = face.mIndices[ m+1 ];
                     }
                     }
                     --t;
                     --t;
 
 
                     // NOTE: we set the removed vertex index to an unique value
                     // NOTE: we set the removed vertex index to an unique value
                     // to make sure the developer gets notified when his
                     // to make sure the developer gets notified when his
                     // application attemps to access this data.
                     // application attemps to access this data.
-                    face.mIndices[face.mNumIndices] = 0xdeadbeef;
+                    face.mIndices[ face.mNumIndices ] = 0xdeadbeef;
 
 
-                    if(first)
-                    {
+                    if(first) {
                         ++deg;
                         ++deg;
                         first = false;
                         first = false;
                     }
                     }
 
 
-                    if (configRemoveDegenerates) {
-                        remove_me[a] = true;
+                    if ( mConfigRemoveDegenerates ) {
+                        remove_me[ a ] = true;
                         goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
                         goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby!
                     }
                     }
                 }
                 }
             }
             }
+
+            if ( mConfigCheckAreaOfTriangle ) {
+                if ( face.mNumIndices == 3 ) {
+                    ai_real area = calculateAreaOfTriangle( face, mesh );
+                    if ( area < 1e-6 ) {
+                        if ( mConfigRemoveDegenerates ) {
+                            remove_me[ a ] = true;
+                            goto evil_jump_outside;
+                        }
+
+                        // todo: check for index which is corrupt.
+                    }
+                }
+            }
         }
         }
 
 
         // We need to update the primitive flags array of the mesh.
         // We need to update the primitive flags array of the mesh.
@@ -171,7 +211,7 @@ evil_jump_outside:
     }
     }
 
 
     // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
     // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import
-    if (configRemoveDegenerates && deg) {
+    if (mConfigRemoveDegenerates && deg) {
         unsigned int n = 0;
         unsigned int n = 0;
         for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
         for (unsigned int a = 0; a < mesh->mNumFaces; ++a)
         {
         {

+ 40 - 19
code/FindDegenerates.h

@@ -54,15 +54,11 @@ namespace Assimp    {
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** FindDegeneratesProcess: Searches a mesh for degenerated triangles.
 /** FindDegeneratesProcess: Searches a mesh for degenerated triangles.
 */
 */
-class ASSIMP_API FindDegeneratesProcess : public BaseProcess
-{
+class ASSIMP_API FindDegeneratesProcess : public BaseProcess {
 public:
 public:
-
     FindDegeneratesProcess();
     FindDegeneratesProcess();
     ~FindDegeneratesProcess();
     ~FindDegeneratesProcess();
 
 
-public:
-
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     // Check whether step is active
     // Check whether step is active
     bool IsActive( unsigned int pFlags) const;
     bool IsActive( unsigned int pFlags) const;
@@ -79,28 +75,53 @@ public:
     // Execute step on a given mesh
     // Execute step on a given mesh
     void ExecuteOnMesh( aiMesh* mesh);
     void ExecuteOnMesh( aiMesh* mesh);
 
 
+    // -------------------------------------------------------------------
+    /// @brief Enable the instant removal of degenerated primitives
+    /// @param enabled  true for enabled.
+    void EnableInstantRemoval(bool enabled);
+
+    // -------------------------------------------------------------------
+    /// @brief Check whether instant removal is currently enabled
+    /// @return The instant removal state.
+    bool IsInstantRemoval() const;
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
-    /** @brief Enable the instant removal of degenerated primitives
-     *  @param d hm ... difficult to guess what this means, hu!?
-     */
-    void EnableInstantRemoval(bool d) {
-        configRemoveDegenerates = d;
-    }
+    /// @brief Enable the area check for triangles.
+    /// @param enabled  true for enabled.
+    void EnableAreaCheck( bool enabled );
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
-    /** @brief Check whether instant removal is currently enabled
-     *  @return ...
-     */
-    bool IsInstantRemoval() const {
-        return configRemoveDegenerates;
-    }
+    /// @brief Check whether the area check is enabled.
+    /// @return The area check state.
+    bool isAreaCheckEnabled() const;
 
 
 private:
 private:
-
     //! Configuration option: remove degenerates faces immediately
     //! Configuration option: remove degenerates faces immediately
-    bool configRemoveDegenerates;
+    bool mConfigRemoveDegenerates;
+    //! Configuration option: check for area
+    bool mConfigCheckAreaOfTriangle;
 };
 };
+
+inline
+void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) {
+    mConfigRemoveDegenerates = enabled;
 }
 }
 
 
+inline
+bool FindDegeneratesProcess::IsInstantRemoval() const {
+    return mConfigRemoveDegenerates;
+}
+
+inline
+void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) {
+    mConfigCheckAreaOfTriangle = enabled;
+}
+
+inline
+bool FindDegeneratesProcess::isAreaCheckEnabled() const {
+    return mConfigCheckAreaOfTriangle;
+}
+
+} // Namespace Assimp
+
 #endif // !! AI_FINDDEGENERATESPROCESS_H_INC
 #endif // !! AI_FINDDEGENERATESPROCESS_H_INC

+ 15 - 10
code/FindInvalidDataProcess.cpp

@@ -169,8 +169,8 @@ void FindInvalidDataProcess::Execute( aiScene* pScene)
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <typename T>
 template <typename T>
-inline const char* ValidateArrayContents(const T* arr, unsigned int size,
-    const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true)
+inline const char* ValidateArrayContents(const T* /*arr*/, unsigned int /*size*/,
+    const std::vector<bool>& /*dirtyMask*/, bool /*mayBeIdentical = false*/, bool /*mayBeZero = true*/)
 {
 {
     return NULL;
     return NULL;
 }
 }
@@ -339,32 +339,37 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
 int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
 {
 {
     bool ret = false;
     bool ret = false;
-    std::vector<bool> dirtyMask(pMesh->mNumVertices,(pMesh->mNumFaces ? true : false));
+    std::vector<bool> dirtyMask(pMesh->mNumVertices, pMesh->mNumFaces != 0);
 
 
     // Ignore elements that are not referenced by vertices.
     // Ignore elements that are not referenced by vertices.
     // (they are, for example, caused by the FindDegenerates step)
     // (they are, for example, caused by the FindDegenerates step)
-    for (unsigned int m = 0; m < pMesh->mNumFaces;++m)  {
+    for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
         const aiFace& f = pMesh->mFaces[m];
         const aiFace& f = pMesh->mFaces[m];
 
 
-        for (unsigned int i = 0; i < f.mNumIndices;++i) {
+        for (unsigned int i = 0; i < f.mNumIndices; ++i) {
             dirtyMask[f.mIndices[i]] = false;
             dirtyMask[f.mIndices[i]] = false;
         }
         }
     }
     }
 
 
     // Process vertex positions
     // Process vertex positions
-    if(pMesh->mVertices && ProcessArray(pMesh->mVertices,pMesh->mNumVertices,"positions",dirtyMask))    {
+    if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) {
         DefaultLogger::get()->error("Deleting mesh: Unable to continue without vertex positions");
         DefaultLogger::get()->error("Deleting mesh: Unable to continue without vertex positions");
+
         return 2;
         return 2;
     }
     }
 
 
     // process texture coordinates
     // process texture coordinates
-    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i];++i)    {
-        if (ProcessArray(pMesh->mTextureCoords[i],pMesh->mNumVertices,"uvcoords",dirtyMask))    {
+    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) {
+        if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) {
+            pMesh->mNumUVComponents[i] = 0;
 
 
             // delete all subsequent texture coordinate sets.
             // delete all subsequent texture coordinate sets.
-            for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a)  {
-                delete[] pMesh->mTextureCoords[a]; pMesh->mTextureCoords[a] = NULL;
+            for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
+                delete[] pMesh->mTextureCoords[a];
+                pMesh->mTextureCoords[a] = NULL;
+                pMesh->mNumUVComponents[a] = 0;
             }
             }
+
             ret = true;
             ret = true;
         }
         }
     }
     }

+ 1 - 4
code/FixNormalsStep.h

@@ -56,14 +56,11 @@ namespace Assimp
  * vectors of an object are facing inwards. In this case they will be
  * vectors of an object are facing inwards. In this case they will be
  * flipped.
  * flipped.
  */
  */
-class FixInfacingNormalsProcess : public BaseProcess
-{
+class FixInfacingNormalsProcess : public BaseProcess {
 public:
 public:
-
     FixInfacingNormalsProcess();
     FixInfacingNormalsProcess();
     ~FixInfacingNormalsProcess();
     ~FixInfacingNormalsProcess();
 
 
-public:
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag field.
     /** Returns whether the processing step is present in the given flag field.
      * @param pFlags The processing flags the importer was called with. A bitwise
      * @param pFlags The processing flags the importer was called with. A bitwise

+ 1 - 1
code/IFCBoolean.cpp

@@ -272,7 +272,6 @@ bool IntersectsBoundaryProfile(const IfcVector3& e0, const IfcVector3& e1, const
         const IfcVector3& b0 = boundary[i];
         const IfcVector3& b0 = boundary[i];
         const IfcVector3& b1 = boundary[(i + 1) % bcount];
         const IfcVector3& b1 = boundary[(i + 1) % bcount];
         IfcVector3 b = b1 - b0;
         IfcVector3 b = b1 - b0;
-        IfcFloat b_sqlen_inv = 1.0 / b.SquareLength();
 
 
         // segment-segment intersection
         // segment-segment intersection
         // solve b0 + b*s = e0 + e*t for (s,t)
         // solve b0 + b*s = e0 + e*t for (s,t)
@@ -281,6 +280,7 @@ bool IntersectsBoundaryProfile(const IfcVector3& e0, const IfcVector3& e1, const
             // no solutions (parallel lines)
             // no solutions (parallel lines)
             continue;
             continue;
         }
         }
+        IfcFloat b_sqlen_inv = 1.0 / b.SquareLength();
 
 
         const IfcFloat x = b0.x - e0.x;
         const IfcFloat x = b0.x - e0.x;
         const IfcFloat y = b0.y - e0.y;
         const IfcFloat y = b0.y - e0.y;

+ 51 - 100
code/IFCCurve.cpp

@@ -43,28 +43,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Read profile and curves entities from IFC files
  *  @brief Read profile and curves entities from IFC files
  */
  */
 
 
-
-
 #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
 #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
 #include "IFCUtil.h"
 #include "IFCUtil.h"
 
 
 namespace Assimp {
 namespace Assimp {
-    namespace IFC {
-        namespace {
+namespace IFC {
+namespace {
 
 
 
 
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // Conic is the base class for Circle and Ellipse
 // Conic is the base class for Circle and Ellipse
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
-class Conic : public Curve
-{
-
+class Conic : public Curve {
 public:
 public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     Conic(const IfcConic& entity, ConversionData& conv)
     Conic(const IfcConic& entity, ConversionData& conv)
-        : Curve(entity,conv)
-    {
+    : Curve(entity,conv) {
         IfcMatrix4 trafo;
         IfcMatrix4 trafo;
         ConvertAxisPlacement(trafo,*entity.Position,conv);
         ConvertAxisPlacement(trafo,*entity.Position,conv);
 
 
@@ -75,8 +69,6 @@ public:
         p[2] = IfcVector3(trafo.a3,trafo.b3,trafo.c3);
         p[2] = IfcVector3(trafo.a3,trafo.b3,trafo.c3);
     }
     }
 
 
-public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     bool IsClosed() const {
     bool IsClosed() const {
         return true;
         return true;
@@ -84,7 +76,8 @@ public:
 
 
     // --------------------------------------------------
     // --------------------------------------------------
     size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
     size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
-        ai_assert(InRange(a) && InRange(b));
+        ai_assert( InRange( a ) );
+        ai_assert( InRange( b ) );
 
 
         a *= conv.angle_scale;
         a *= conv.angle_scale;
         b *= conv.angle_scale;
         b *= conv.angle_scale;
@@ -104,15 +97,11 @@ protected:
     IfcVector3 location, p[3];
     IfcVector3 location, p[3];
 };
 };
 
 
-
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // Circle
 // Circle
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
-class Circle : public Conic
-{
-
+class Circle : public Conic {
 public:
 public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     Circle(const IfcCircle& entity, ConversionData& conv)
     Circle(const IfcCircle& entity, ConversionData& conv)
         : Conic(entity,conv)
         : Conic(entity,conv)
@@ -120,8 +109,6 @@ public:
     {
     {
     }
     }
 
 
-public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     IfcVector3 Eval(IfcFloat u) const {
     IfcVector3 Eval(IfcFloat u) const {
         u = -conv.angle_scale * u;
         u = -conv.angle_scale * u;
@@ -137,20 +124,15 @@ private:
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // Ellipse
 // Ellipse
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
-class Ellipse : public Conic
-{
-
+class Ellipse : public Conic {
 public:
 public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     Ellipse(const IfcEllipse& entity, ConversionData& conv)
     Ellipse(const IfcEllipse& entity, ConversionData& conv)
-        : Conic(entity,conv)
-        , entity(entity)
-    {
+    : Conic(entity,conv)
+    , entity(entity) {
+        // empty
     }
     }
 
 
-public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     IfcVector3 Eval(IfcFloat u) const {
     IfcVector3 Eval(IfcFloat u) const {
         u = -conv.angle_scale * u;
         u = -conv.angle_scale * u;
@@ -162,25 +144,18 @@ private:
     const IfcEllipse& entity;
     const IfcEllipse& entity;
 };
 };
 
 
-
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // Line
 // Line
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
-class Line : public Curve
-{
-
+class Line : public Curve {
 public:
 public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     Line(const IfcLine& entity, ConversionData& conv)
     Line(const IfcLine& entity, ConversionData& conv)
-        : Curve(entity,conv)
-    {
+    : Curve(entity,conv) {
         ConvertCartesianPoint(p,entity.Pnt);
         ConvertCartesianPoint(p,entity.Pnt);
         ConvertVector(v,entity.Dir);
         ConvertVector(v,entity.Dir);
     }
     }
 
 
-public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     bool IsClosed() const {
     bool IsClosed() const {
         return false;
         return false;
@@ -193,16 +168,17 @@ public:
 
 
     // --------------------------------------------------
     // --------------------------------------------------
     size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
     size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
-        ai_assert(InRange(a) && InRange(b));
+        ai_assert( InRange( a ) );
+        ai_assert( InRange( b ) );
         // two points are always sufficient for a line segment
         // two points are always sufficient for a line segment
         return a==b ? 1 : 2;
         return a==b ? 1 : 2;
     }
     }
 
 
 
 
     // --------------------------------------------------
     // --------------------------------------------------
-    void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const
-    {
-        ai_assert(InRange(a) && InRange(b));
+    void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const {
+        ai_assert( InRange( a ) );
+        ai_assert( InRange( b ) );
 
 
         if (a == b) {
         if (a == b) {
             out.verts.push_back(Eval(a));
             out.verts.push_back(Eval(a));
@@ -227,18 +203,14 @@ private:
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // CompositeCurve joins multiple smaller, bounded curves
 // CompositeCurve joins multiple smaller, bounded curves
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
-class CompositeCurve : public BoundedCurve
-{
-
+class CompositeCurve : public BoundedCurve {
     typedef std::pair< std::shared_ptr< BoundedCurve >, bool > CurveEntry;
     typedef std::pair< std::shared_ptr< BoundedCurve >, bool > CurveEntry;
 
 
 public:
 public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     CompositeCurve(const IfcCompositeCurve& entity, ConversionData& conv)
     CompositeCurve(const IfcCompositeCurve& entity, ConversionData& conv)
-        : BoundedCurve(entity,conv)
-        , total()
-    {
+    : BoundedCurve(entity,conv)
+    , total() {
         curves.reserve(entity.Segments.size());
         curves.reserve(entity.Segments.size());
         for(const IfcCompositeCurveSegment& curveSegment :entity.Segments) {
         for(const IfcCompositeCurveSegment& curveSegment :entity.Segments) {
             // according to the specification, this must be a bounded curve
             // according to the specification, this must be a bounded curve
@@ -263,8 +235,6 @@ public:
         }
         }
     }
     }
 
 
-public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     IfcVector3 Eval(IfcFloat u) const {
     IfcVector3 Eval(IfcFloat u) const {
         if (curves.empty()) {
         if (curves.empty()) {
@@ -287,7 +257,8 @@ public:
 
 
     // --------------------------------------------------
     // --------------------------------------------------
     size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
     size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
-        ai_assert(InRange(a) && InRange(b));
+        ai_assert( InRange( a ) );
+        ai_assert( InRange( b ) );
         size_t cnt = 0;
         size_t cnt = 0;
 
 
         IfcFloat acc = 0;
         IfcFloat acc = 0;
@@ -306,9 +277,9 @@ public:
     }
     }
 
 
     // --------------------------------------------------
     // --------------------------------------------------
-    void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const
-    {
-        ai_assert(InRange(a) && InRange(b));
+    void SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const {
+        ai_assert( InRange( a ) );
+        ai_assert( InRange( b ) );
 
 
         const size_t cnt = EstimateSampleCount(a,b);
         const size_t cnt = EstimateSampleCount(a,b);
         out.verts.reserve(out.verts.size() + cnt);
         out.verts.reserve(out.verts.size() + cnt);
@@ -330,19 +301,14 @@ public:
 
 
 private:
 private:
     std::vector< CurveEntry > curves;
     std::vector< CurveEntry > curves;
-
     IfcFloat total;
     IfcFloat total;
 };
 };
 
 
-
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // TrimmedCurve can be used to trim an unbounded curve to a bounded range
 // TrimmedCurve can be used to trim an unbounded curve to a bounded range
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
-class TrimmedCurve : public BoundedCurve
-{
-
+class TrimmedCurve : public BoundedCurve {
 public:
 public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     TrimmedCurve(const IfcTrimmedCurve& entity, ConversionData& conv)
     TrimmedCurve(const IfcTrimmedCurve& entity, ConversionData& conv)
         : BoundedCurve(entity,conv)
         : BoundedCurve(entity,conv)
@@ -409,8 +375,6 @@ public:
         ai_assert(maxval >= 0);
         ai_assert(maxval >= 0);
     }
     }
 
 
-public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     IfcVector3 Eval(IfcFloat p) const {
     IfcVector3 Eval(IfcFloat p) const {
         ai_assert(InRange(p));
         ai_assert(InRange(p));
@@ -419,7 +383,8 @@ public:
 
 
     // --------------------------------------------------
     // --------------------------------------------------
     size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
     size_t EstimateSampleCount(IfcFloat a, IfcFloat b) const {
-        ai_assert(InRange(a) && InRange(b));
+        ai_assert( InRange( a ) );
+        ai_assert( InRange( b ) );
         return base->EstimateSampleCount(TrimParam(a),TrimParam(b));
         return base->EstimateSampleCount(TrimParam(a),TrimParam(b));
     }
     }
 
 
@@ -435,13 +400,11 @@ public:
     }
     }
 
 
 private:
 private:
-
     // --------------------------------------------------
     // --------------------------------------------------
     IfcFloat TrimParam(IfcFloat f) const {
     IfcFloat TrimParam(IfcFloat f) const {
         return agree_sense ? f + range.first :  range.second - f;
         return agree_sense ? f + range.first :  range.second - f;
     }
     }
 
 
-
 private:
 private:
     ParamRange range;
     ParamRange range;
     IfcFloat maxval;
     IfcFloat maxval;
@@ -454,11 +417,8 @@ private:
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // PolyLine is a 'curve' defined by linear interpolation over a set of discrete points
 // PolyLine is a 'curve' defined by linear interpolation over a set of discrete points
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
-class PolyLine : public BoundedCurve
-{
-
+class PolyLine : public BoundedCurve {
 public:
 public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     PolyLine(const IfcPolyline& entity, ConversionData& conv)
     PolyLine(const IfcPolyline& entity, ConversionData& conv)
         : BoundedCurve(entity,conv)
         : BoundedCurve(entity,conv)
@@ -472,8 +432,6 @@ public:
         }
         }
     }
     }
 
 
-public:
-
     // --------------------------------------------------
     // --------------------------------------------------
     IfcVector3 Eval(IfcFloat p) const {
     IfcVector3 Eval(IfcFloat p) const {
         ai_assert(InRange(p));
         ai_assert(InRange(p));
@@ -502,13 +460,10 @@ private:
     std::vector<IfcVector3> points;
     std::vector<IfcVector3> points;
 };
 };
 
 
-
 } // anon
 } // anon
 
 
-
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-Curve* Curve :: Convert(const IFC::IfcCurve& curve,ConversionData& conv)
-{
+Curve* Curve::Convert(const IFC::IfcCurve& curve,ConversionData& conv) {
     if(curve.ToPtr<IfcBoundedCurve>()) {
     if(curve.ToPtr<IfcBoundedCurve>()) {
         if(const IfcPolyline* c = curve.ToPtr<IfcPolyline>()) {
         if(const IfcPolyline* c = curve.ToPtr<IfcPolyline>()) {
             return new PolyLine(*c,conv);
             return new PolyLine(*c,conv);
@@ -519,9 +474,6 @@ Curve* Curve :: Convert(const IFC::IfcCurve& curve,ConversionData& conv)
         if(const IfcCompositeCurve* c = curve.ToPtr<IfcCompositeCurve>()) {
         if(const IfcCompositeCurve* c = curve.ToPtr<IfcCompositeCurve>()) {
             return new CompositeCurve(*c,conv);
             return new CompositeCurve(*c,conv);
         }
         }
-        //if(const IfcBSplineCurve* c = curve.ToPtr<IfcBSplineCurve>()) {
-        //  return new BSplineCurve(*c,conv);
-        //}
     }
     }
 
 
     if(curve.ToPtr<IfcConic>()) {
     if(curve.ToPtr<IfcConic>()) {
@@ -543,8 +495,7 @@ Curve* Curve :: Convert(const IFC::IfcCurve& curve,ConversionData& conv)
 
 
 #ifdef ASSIMP_BUILD_DEBUG
 #ifdef ASSIMP_BUILD_DEBUG
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-bool Curve :: InRange(IfcFloat u) const
-{
+bool Curve::InRange(IfcFloat u) const {
     const ParamRange range = GetParametricRange();
     const ParamRange range = GetParametricRange();
     if (IsClosed()) {
     if (IsClosed()) {
         return true;
         return true;
@@ -555,24 +506,24 @@ bool Curve :: InRange(IfcFloat u) const
 #endif
 #endif
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-IfcFloat Curve :: GetParametricRangeDelta() const
-{
+IfcFloat Curve::GetParametricRangeDelta() const {
     const ParamRange& range = GetParametricRange();
     const ParamRange& range = GetParametricRange();
     return std::abs(range.second - range.first);
     return std::abs(range.second - range.first);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-size_t Curve :: EstimateSampleCount(IfcFloat a, IfcFloat b) const
-{
-    ai_assert(InRange(a) && InRange(b));
+size_t Curve::EstimateSampleCount(IfcFloat a, IfcFloat b) const {
+    (void)(a); (void)(b);  
+    ai_assert( InRange( a ) );
+    ai_assert( InRange( b ) );
 
 
     // arbitrary default value, deriving classes should supply better suited values
     // arbitrary default value, deriving classes should supply better suited values
     return 16;
     return 16;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-IfcFloat RecursiveSearch(const Curve* cv, const IfcVector3& val, IfcFloat a, IfcFloat b, unsigned int samples, IfcFloat threshold, unsigned int recurse = 0, unsigned int max_recurse = 15)
-{
+IfcFloat RecursiveSearch(const Curve* cv, const IfcVector3& val, IfcFloat a, IfcFloat b,
+        unsigned int samples, IfcFloat threshold, unsigned int recurse = 0, unsigned int max_recurse = 15) {
     ai_assert(samples>1);
     ai_assert(samples>1);
 
 
     const IfcFloat delta = (b-a)/samples, inf = std::numeric_limits<IfcFloat>::infinity();
     const IfcFloat delta = (b-a)/samples, inf = std::numeric_limits<IfcFloat>::infinity();
@@ -594,7 +545,8 @@ IfcFloat RecursiveSearch(const Curve* cv, const IfcVector3& val, IfcFloat a, Ifc
         }
         }
     }
     }
 
 
-    ai_assert(min_diff[0] != inf && min_diff[1] != inf);
+    ai_assert( min_diff[ 0 ] != inf );
+    ai_assert( min_diff[ 1 ] != inf );
     if ( std::fabs(a-min_point[0]) < threshold || recurse >= max_recurse) {
     if ( std::fabs(a-min_point[0]) < threshold || recurse >= max_recurse) {
         return min_point[0];
         return min_point[0];
     }
     }
@@ -615,15 +567,15 @@ IfcFloat RecursiveSearch(const Curve* cv, const IfcVector3& val, IfcFloat a, Ifc
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-bool Curve :: ReverseEval(const IfcVector3& val, IfcFloat& paramOut) const
+bool Curve::ReverseEval(const IfcVector3& val, IfcFloat& paramOut) const
 {
 {
     // note: the following algorithm is not guaranteed to find the 'right' parameter value
     // note: the following algorithm is not guaranteed to find the 'right' parameter value
     // in all possible cases, but it will always return at least some value so this function
     // in all possible cases, but it will always return at least some value so this function
     // will never fail in the default implementation.
     // will never fail in the default implementation.
 
 
     // XXX derive threshold from curve topology
     // XXX derive threshold from curve topology
-    const IfcFloat threshold = 1e-4f;
-    const unsigned int samples = 16;
+    static const IfcFloat threshold = 1e-4f;
+    static const unsigned int samples = 16;
 
 
     const ParamRange& range = GetParametricRange();
     const ParamRange& range = GetParametricRange();
     paramOut = RecursiveSearch(this,val,range.first,range.second,samples,threshold);
     paramOut = RecursiveSearch(this,val,range.first,range.second,samples,threshold);
@@ -632,9 +584,9 @@ bool Curve :: ReverseEval(const IfcVector3& val, IfcFloat& paramOut) const
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void Curve :: SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const
-{
-    ai_assert(InRange(a) && InRange(b));
+void Curve::SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const {
+    ai_assert( InRange( a ) );
+    ai_assert( InRange( b ) );
 
 
     const size_t cnt = std::max(static_cast<size_t>(0),EstimateSampleCount(a,b));
     const size_t cnt = std::max(static_cast<size_t>(0),EstimateSampleCount(a,b));
     out.verts.reserve( out.verts.size() + cnt + 1);
     out.verts.reserve( out.verts.size() + cnt + 1);
@@ -646,16 +598,15 @@ void Curve :: SampleDiscrete(TempMesh& out,IfcFloat a, IfcFloat b) const
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-bool BoundedCurve :: IsClosed() const
-{
+bool BoundedCurve::IsClosed() const {
     return false;
     return false;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void BoundedCurve :: SampleDiscrete(TempMesh& out) const
-{
+void BoundedCurve::SampleDiscrete(TempMesh& out) const {
     const ParamRange& range = GetParametricRange();
     const ParamRange& range = GetParametricRange();
-    ai_assert(range.first != std::numeric_limits<IfcFloat>::infinity() && range.second != std::numeric_limits<IfcFloat>::infinity());
+    ai_assert( range.first != std::numeric_limits<IfcFloat>::infinity() );
+    ai_assert( range.second != std::numeric_limits<IfcFloat>::infinity() );
 
 
     return SampleDiscrete(out,range.first,range.second);
     return SampleDiscrete(out,range.first,range.second);
 }
 }

+ 5 - 5
code/IFCGeometry.cpp

@@ -330,7 +330,11 @@ void ProcessSweptDiskSolid(const IfcSweptDiskSolid solid, TempMesh& result, Conv
     const unsigned int cnt_segments = conv.settings.cylindricalTessellation;
     const unsigned int cnt_segments = conv.settings.cylindricalTessellation;
     const IfcFloat deltaAngle = AI_MATH_TWO_PI/cnt_segments;
     const IfcFloat deltaAngle = AI_MATH_TWO_PI/cnt_segments;
 
 
-    const size_t samples = curve->EstimateSampleCount(solid.StartParam,solid.EndParam);
+	TempMesh temp;
+	curve->SampleDiscrete(temp, solid.StartParam, solid.EndParam);
+	const std::vector<IfcVector3>& curve_points = temp.verts;
+
+    const size_t samples = curve_points.size();
 
 
     result.verts.reserve(cnt_segments * samples * 4);
     result.verts.reserve(cnt_segments * samples * 4);
     result.vertcnt.reserve((cnt_segments - 1) * samples);
     result.vertcnt.reserve((cnt_segments - 1) * samples);
@@ -338,10 +342,6 @@ void ProcessSweptDiskSolid(const IfcSweptDiskSolid solid, TempMesh& result, Conv
     std::vector<IfcVector3> points;
     std::vector<IfcVector3> points;
     points.reserve(cnt_segments * samples);
     points.reserve(cnt_segments * samples);
 
 
-    TempMesh temp;
-    curve->SampleDiscrete(temp,solid.StartParam,solid.EndParam);
-    const std::vector<IfcVector3>& curve_points = temp.verts;
-
     if(curve_points.empty()) {
     if(curve_points.empty()) {
         IFCImporter::LogWarn("curve evaluation yielded no points (IfcSweptDiskSolid)");
         IFCImporter::LogWarn("curve evaluation yielded no points (IfcSweptDiskSolid)");
         return;
         return;

+ 1 - 40
code/IFCOpenings.cpp

@@ -1499,7 +1499,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
 
 
 
 
     IfcVector3 wall_extrusion;
     IfcVector3 wall_extrusion;
-    bool do_connections = false, first = true;
+    bool first = true;
 
 
     try {
     try {
 
 
@@ -1527,7 +1527,6 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
                 if (first) {
                 if (first) {
                     first = false;
                     first = false;
                     if (dot > 0.f) {
                     if (dot > 0.f) {
-                        do_connections = true;
                         wall_extrusion = t.extrusionDir;
                         wall_extrusion = t.extrusionDir;
                         if (is_extruded_side) {
                         if (is_extruded_side) {
                             wall_extrusion = - wall_extrusion;
                             wall_extrusion = - wall_extrusion;
@@ -1607,44 +1606,6 @@ bool TryAddOpenings_Poly2Tri(const std::vector<TempOpening>& openings,const std:
     old_verts.swap(curmesh.verts);
     old_verts.swap(curmesh.verts);
     old_vertcnt.swap(curmesh.vertcnt);
     old_vertcnt.swap(curmesh.vertcnt);
 
 
-
-    // add connection geometry to close the adjacent 'holes' for the openings
-    // this should only be done from one side of the wall or the polygons
-    // would be emitted twice.
-    if (false && do_connections) {
-
-        std::vector<IfcVector3> tmpvec;
-        for(ClipperLib::Polygon& opening : holes_union) {
-
-            ai_assert(ClipperLib::Orientation(opening));
-
-            tmpvec.clear();
-
-            for(ClipperLib::IntPoint& point : opening) {
-
-                tmpvec.push_back( minv * IfcVector3(
-                    vmin.x + from_int64(point.X) * vmax.x,
-                    vmin.y + from_int64(point.Y) * vmax.y,
-                    coord));
-            }
-
-            for(size_t i = 0, size = tmpvec.size(); i < size; ++i) {
-                const size_t next = (i+1)%size;
-
-                curmesh.vertcnt.push_back(4);
-
-                const IfcVector3& in_world = tmpvec[i];
-                const IfcVector3& next_world = tmpvec[next];
-
-                // Assumptions: no 'partial' openings, wall thickness roughly the same across the wall
-                curmesh.verts.push_back(in_world);
-                curmesh.verts.push_back(in_world+wall_extrusion);
-                curmesh.verts.push_back(next_world+wall_extrusion);
-                curmesh.verts.push_back(next_world);
-            }
-        }
-    }
-
     std::vector< std::vector<p2t::Point*> > contours;
     std::vector< std::vector<p2t::Point*> > contours;
     for(ClipperLib::ExPolygon& clip : clipped) {
     for(ClipperLib::ExPolygon& clip : clipped) {
 
 

+ 4 - 3
code/IFCReaderGen1.cpp

@@ -1045,7 +1045,7 @@ void IFC::GetSchema(EXPRESS::ConversionSchema& out)
 namespace STEP {
 namespace STEP {
 
 
 // -----------------------------------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------------------------------
-template <> size_t GenericFill<NotImplemented>(const STEP::DB& db, const LIST& params, NotImplemented* in)
+template <> size_t GenericFill<NotImplemented>(const STEP::DB& /*db*/, const LIST& /*params*/, NotImplemented* /*in*/)
 {
 {
 	return 0;
 	return 0;
 }
 }
@@ -1253,7 +1253,7 @@ template <> size_t GenericFill<IfcPerformanceHistory>(const DB& db, const LIST&
 	return base;
 	return base;
 }
 }
 // -----------------------------------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------------------------------
-template <> size_t GenericFill<IfcRepresentationItem>(const DB& db, const LIST& params, IfcRepresentationItem* in)
+template <> size_t GenericFill<IfcRepresentationItem>(const DB& /*db*/, const LIST& /*params*/, IfcRepresentationItem* /*in*/)
 {
 {
 	size_t base = 0;
 	size_t base = 0;
 	return base;
 	return base;
@@ -1715,7 +1715,7 @@ template <> size_t GenericFill<IfcPlateType>(const DB& db, const LIST& params, I
 	return base;
 	return base;
 }
 }
 // -----------------------------------------------------------------------------------------------------------
 // -----------------------------------------------------------------------------------------------------------
-template <> size_t GenericFill<IfcObjectPlacement>(const DB& db, const LIST& params, IfcObjectPlacement* in)
+template <> size_t GenericFill<IfcObjectPlacement>(const DB& /*db*/, const LIST& /*params*/, IfcObjectPlacement* /*in*/)
 {
 {
 	size_t base = 0;
 	size_t base = 0;
 	return base;
 	return base;
@@ -2652,6 +2652,7 @@ template <> size_t GenericFill<IfcNamedUnit>(const DB& db, const LIST& params, I
 	size_t base = 0;
 	size_t base = 0;
 	if (params.GetSize() < 2) { throw STEP::TypeError("expected 2 arguments to IfcNamedUnit"); }    do { // convert the 'Dimensions' argument
 	if (params.GetSize() < 2) { throw STEP::TypeError("expected 2 arguments to IfcNamedUnit"); }    do { // convert the 'Dimensions' argument
         std::shared_ptr<const DataType> arg = params[base++];
         std::shared_ptr<const DataType> arg = params[base++];
+		if (dynamic_cast<const UNSET*>(&*arg)) break;
         if (dynamic_cast<const ISDERIVED*>(&*arg)) { in->ObjectHelper<Assimp::IFC::IfcNamedUnit,2>::aux_is_derived[0]=true; break; }
         if (dynamic_cast<const ISDERIVED*>(&*arg)) { in->ObjectHelper<Assimp::IFC::IfcNamedUnit,2>::aux_is_derived[0]=true; break; }
         try { GenericConvert( in->Dimensions, arg, db ); break; } 
         try { GenericConvert( in->Dimensions, arg, db ); break; } 
         catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 0 to IfcNamedUnit to be a `IfcDimensionalExponents`")); }
         catch (const TypeError& t) { throw TypeError(t.what() + std::string(" - expected argument 0 to IfcNamedUnit to be a `IfcDimensionalExponents`")); }

+ 1 - 1
code/IRRLoader.cpp

@@ -394,7 +394,7 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
                 angles[1] %= 360;
                 angles[1] %= 360;
                 angles[2] %= 360;
                 angles[2] %= 360;
 
 
-                if ((angles[0]*angles[1]) && (angles[1]*angles[2]))
+                if ( (angles[0]*angles[1]) != 0 && (angles[1]*angles[2]) != 0 )
                 {
                 {
                     FindSuitableMultiple(angles[0]);
                     FindSuitableMultiple(angles[0]);
                     FindSuitableMultiple(angles[1]);
                     FindSuitableMultiple(angles[1]);

+ 2 - 4
code/Importer.cpp

@@ -274,10 +274,6 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
 
 
     if (it != pimpl->mImporter.end())   {
     if (it != pimpl->mImporter.end())   {
         pimpl->mImporter.erase(it);
         pimpl->mImporter.erase(it);
-
-        std::set<std::string> st;
-        pImp->GetExtensionList(st);
-
         DefaultLogger::get()->info("Unregistering custom importer: ");
         DefaultLogger::get()->info("Unregistering custom importer: ");
         return AI_SUCCESS;
         return AI_SUCCESS;
     }
     }
@@ -681,6 +677,8 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
             profiler->EndRegion("import");
             profiler->EndRegion("import");
         }
         }
 
 
+        SetPropertyString("sourceFilePath", pFile);
+
         // If successful, apply all active post processing steps to the imported data
         // If successful, apply all active post processing steps to the imported data
         if( pimpl->mScene)  {
         if( pimpl->mScene)  {
 
 

+ 1 - 0
code/ImproveCacheLocality.cpp

@@ -223,6 +223,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh
             iMaxRefTris = std::max(iMaxRefTris,*piCur);
             iMaxRefTris = std::max(iMaxRefTris,*piCur);
         }
         }
     }
     }
+    ai_assert(iMaxRefTris > 0);
     unsigned int* piCandidates = new unsigned int[iMaxRefTris*3];
     unsigned int* piCandidates = new unsigned int[iMaxRefTris*3];
     unsigned int iCacheMisses = 0;
     unsigned int iCacheMisses = 0;
 
 

+ 1 - 3
code/LWOAnimation.cpp

@@ -446,8 +446,6 @@ void AnimResolver::GetKeys(std::vector<aiVectorKey>& out,
 
 
     // Iterate through all three arrays at once - it's tricky, but
     // Iterate through all three arrays at once - it's tricky, but
     // rather interesting to implement.
     // rather interesting to implement.
-    double lasttime = std::min(envl_x->keys[0].time,std::min(envl_y->keys[0].time,envl_z->keys[0].time));
-
     cur_x = envl_x->keys.begin();
     cur_x = envl_x->keys.begin();
     cur_y = envl_y->keys.begin();
     cur_y = envl_y->keys.begin();
     cur_z = envl_z->keys.begin();
     cur_z = envl_z->keys.begin();
@@ -503,7 +501,7 @@ void AnimResolver::GetKeys(std::vector<aiVectorKey>& out,
                 InterpolateTrack(out,fill,(end_y ? (*cur_x) : (*cur_y)).time);
                 InterpolateTrack(out,fill,(end_y ? (*cur_x) : (*cur_y)).time);
             }
             }
         }
         }
-        lasttime = fill.mTime;
+        double lasttime = fill.mTime;
         out.push_back(fill);
         out.push_back(fill);
 
 
         if (lasttime >= (*cur_x).time) {
         if (lasttime >= (*cur_x).time) {

+ 1 - 1
code/LWOMaterial.cpp

@@ -483,7 +483,7 @@ void LWOImporter::FindVCChannels(const LWO::Surface& surf, LWO::SortedRep& sorte
         const LWO::VColorChannel& vc = layer.mVColorChannels[i];
         const LWO::VColorChannel& vc = layer.mVColorChannels[i];
 
 
         if (surf.mVCMap == vc.name) {
         if (surf.mVCMap == vc.name) {
-            // The vertex color map is explicitely requested by the surface so we need to take special care of it
+            // The vertex color map is explicitly requested by the surface so we need to take special care of it
             for (unsigned int a = 0; a < std::min(next,AI_MAX_NUMBER_OF_COLOR_SETS-1u); ++a) {
             for (unsigned int a = 0; a < std::min(next,AI_MAX_NUMBER_OF_COLOR_SETS-1u); ++a) {
                 out[a+1] = out[a];
                 out[a+1] = out[a];
             }
             }

+ 1 - 1
code/LWSLoader.cpp

@@ -471,7 +471,7 @@ void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<Attachm
 // Determine the exact location of a LWO file
 // Determine the exact location of a LWO file
 std::string LWSImporter::FindLWOFile(const std::string& in)
 std::string LWSImporter::FindLWOFile(const std::string& in)
 {
 {
-    // insert missing directory seperator if necessary
+    // insert missing directory separator if necessary
     std::string tmp;
     std::string tmp;
     if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/')
     if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/')
     {
     {

+ 8 - 12
code/LineSplitter.h

@@ -69,27 +69,23 @@ for(LineSplitter splitter(stream);splitter;++splitter) {
 
 
     std::cout << "Current line is: " << splitter.get_index() << std::endl;
     std::cout << "Current line is: " << splitter.get_index() << std::endl;
 }
 }
-@endcode */
+@endcode
+*/
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-class LineSplitter
-{
+class LineSplitter {
 public:
 public:
-
     typedef size_t line_idx;
     typedef size_t line_idx;
 
 
-public:
-
     // -----------------------------------------
     // -----------------------------------------
     /** construct from existing stream reader
     /** construct from existing stream reader
     note: trim is *always* assumed true if skyp_empty_lines==true
     note: trim is *always* assumed true if skyp_empty_lines==true
     */
     */
     LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true)
     LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true)
-        : idx( 0 )
-        , stream(stream)
-        , swallow()
-        , skip_empty_lines(skip_empty_lines)
-        , trim(trim)
-    {
+    : idx( 0 )
+    , stream(stream)
+    , swallow()
+    , skip_empty_lines(skip_empty_lines)
+    , trim(trim) {
         cur.reserve(1024);
         cur.reserve(1024);
         operator++();
         operator++();
 
 

+ 4 - 4
code/LogAux.h

@@ -66,28 +66,28 @@ public:
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     static void LogWarn(const Formatter::format& message)   {
     static void LogWarn(const Formatter::format& message)   {
         if (!DefaultLogger::isNullLogger()) {
         if (!DefaultLogger::isNullLogger()) {
-            DefaultLogger::get()->warn(Prefix() +(std::string)message);
+            DefaultLogger::get()->warn(Prefix()+(std::string)message);
         }
         }
     }
     }
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     static void LogError(const Formatter::format& message)  {
     static void LogError(const Formatter::format& message)  {
         if (!DefaultLogger::isNullLogger()) {
         if (!DefaultLogger::isNullLogger()) {
-            DefaultLogger::get()->error(Prefix() +(std::string)message);
+            DefaultLogger::get()->error(Prefix()+(std::string)message);
         }
         }
     }
     }
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     static void LogInfo(const Formatter::format& message)   {
     static void LogInfo(const Formatter::format& message)   {
         if (!DefaultLogger::isNullLogger()) {
         if (!DefaultLogger::isNullLogger()) {
-            DefaultLogger::get()->info(Prefix() +(std::string)message);
+            DefaultLogger::get()->info(Prefix()+(std::string)message);
         }
         }
     }
     }
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     static void LogDebug(const Formatter::format& message)  {
     static void LogDebug(const Formatter::format& message)  {
         if (!DefaultLogger::isNullLogger()) {
         if (!DefaultLogger::isNullLogger()) {
-            DefaultLogger::get()->debug(Prefix() +(std::string)message);
+            DefaultLogger::get()->debug(Prefix()+(std::string)message);
         }
         }
     }
     }
 
 

+ 3 - 5
code/MD2Loader.cpp

@@ -274,11 +274,9 @@ void MD2Importer::InternReadFile( const std::string& pFile,
     aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh();
     aiMesh* pcMesh = pScene->mMeshes[0] = new aiMesh();
     pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
     pcMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
 
 
-    // navigate to the begin of the frame data
-    BE_NCONST MD2::Frame* pcFrame = (BE_NCONST MD2::Frame*) ((uint8_t*)
-        m_pcHeader + m_pcHeader->offsetFrames);
-
-    pcFrame += configFrameID;
+    // navigate to the begin of the current frame data
+	BE_NCONST MD2::Frame* pcFrame = (BE_NCONST MD2::Frame*) ((uint8_t*)
+		m_pcHeader + m_pcHeader->offsetFrames + (m_pcHeader->frameSize * configFrameID));
 
 
     // navigate to the begin of the triangle data
     // navigate to the begin of the triangle data
     MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)
     MD2::Triangle* pcTriangles = (MD2::Triangle*) ((uint8_t*)

+ 3 - 3
code/MD3Loader.cpp

@@ -1018,11 +1018,11 @@ void MD3Importer::InternReadFile( const std::string& pFile,
 
 
                 // Convert the normal vector to uncompressed float3 format
                 // Convert the normal vector to uncompressed float3 format
                 aiVector3D& nor = pcMesh->mNormals[iCurrent];
                 aiVector3D& nor = pcMesh->mNormals[iCurrent];
-                LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL,(ai_real*)&nor);
+                LatLngNormalToVec3(pcVertices[index].NORMAL,(ai_real*)&nor);
 
 
                 // Read texture coordinates
                 // Read texture coordinates
-                pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[ pcTriangles->INDEXES[c]].U;
-                pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[ pcTriangles->INDEXES[c]].V;
+                pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[index].U;
+                pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[index].V;
             }
             }
             // Flip face order if necessary
             // Flip face order if necessary
             if (!shader || shader->cull == Q3Shader::CULL_CW) {
             if (!shader || shader->cull == Q3Shader::CULL_CW) {

+ 1 - 1
code/MD5Loader.h

@@ -145,7 +145,7 @@ protected:
 
 
     // -------------------------------------------------------------------
     // -------------------------------------------------------------------
     /** Load the contents of a specific file into memory and
     /** Load the contents of a specific file into memory and
-     *  alocates a buffer to keep it.
+     *  allocates a buffer to keep it.
      *
      *
      *  mBuffer is modified to point to this buffer.
      *  mBuffer is modified to point to this buffer.
      *  @param pFile File stream to be read
      *  @param pFile File stream to be read

+ 6 - 11
code/MDCLoader.cpp

@@ -283,9 +283,8 @@ void MDCImporter::InternReadFile(
         pcMesh->mNumVertices = pcMesh->mNumFaces * 3;
         pcMesh->mNumVertices = pcMesh->mNumFaces * 3;
 
 
         // store the name of the surface for use as node name.
         // store the name of the surface for use as node name.
-        // FIX: make sure there is a 0 termination
-        const_cast<char&>(pcSurface->ucName[AI_MDC_MAXQPATH-1]) = '\0';
-        pcMesh->mTextureCoords[3] = (aiVector3D*)pcSurface->ucName;
+        pcMesh->mName.Set(std::string(pcSurface->ucName
+                                    , strnlen(pcSurface->ucName, AI_MDC_MAXQPATH - 1)));
 
 
         // go to the first shader in the file. ignore the others.
         // go to the first shader in the file. ignore the others.
         if (pcSurface->ulNumShaders)
         if (pcSurface->ulNumShaders)
@@ -294,8 +293,8 @@ void MDCImporter::InternReadFile(
             pcMesh->mMaterialIndex = (unsigned int)aszShaders.size();
             pcMesh->mMaterialIndex = (unsigned int)aszShaders.size();
 
 
             // create a new shader
             // create a new shader
-            aszShaders.push_back(std::string( pcShader->ucName, std::min(
-                ::strlen(pcShader->ucName),sizeof(pcShader->ucName)) ));
+            aszShaders.push_back(std::string( pcShader->ucName, 
+                ::strnlen(pcShader->ucName, sizeof(pcShader->ucName)) ));
         }
         }
         // need to create a default material
         // need to create a default material
         else if (UINT_MAX == iDefaultMatIndex)
         else if (UINT_MAX == iDefaultMatIndex)
@@ -432,7 +431,7 @@ void MDCImporter::InternReadFile(
     else if (1 == pScene->mNumMeshes)
     else if (1 == pScene->mNumMeshes)
     {
     {
         pScene->mRootNode = new aiNode();
         pScene->mRootNode = new aiNode();
-        pScene->mRootNode->mName.Set(std::string((const char*)pScene->mMeshes[0]->mTextureCoords[3]));
+        pScene->mRootNode->mName = pScene->mMeshes[0]->mName;
         pScene->mRootNode->mNumMeshes = 1;
         pScene->mRootNode->mNumMeshes = 1;
         pScene->mRootNode->mMeshes = new unsigned int[1];
         pScene->mRootNode->mMeshes = new unsigned int[1];
         pScene->mRootNode->mMeshes[0] = 0;
         pScene->mRootNode->mMeshes[0] = 0;
@@ -447,17 +446,13 @@ void MDCImporter::InternReadFile(
         {
         {
             aiNode* pcNode = pScene->mRootNode->mChildren[i] = new aiNode();
             aiNode* pcNode = pScene->mRootNode->mChildren[i] = new aiNode();
             pcNode->mParent = pScene->mRootNode;
             pcNode->mParent = pScene->mRootNode;
-            pcNode->mName.Set(std::string((const char*)pScene->mMeshes[i]->mTextureCoords[3]));
+            pcNode->mName = pScene->mMeshes[i]->mName;
             pcNode->mNumMeshes = 1;
             pcNode->mNumMeshes = 1;
             pcNode->mMeshes = new unsigned int[1];
             pcNode->mMeshes = new unsigned int[1];
             pcNode->mMeshes[0] = i;
             pcNode->mMeshes[0] = i;
         }
         }
     }
     }
 
 
-    // make sure we invalidate the pointer to the mesh name
-    for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
-        pScene->mMeshes[i]->mTextureCoords[3] = NULL;
-
     // create materials
     // create materials
     pScene->mNumMaterials = (unsigned int)aszShaders.size();
     pScene->mNumMaterials = (unsigned int)aszShaders.size();
     pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
     pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];

+ 7 - 0
code/MDLLoader.cpp

@@ -415,8 +415,15 @@ void MDLImporter::InternReadFile_Quake1( )
     else
     else
     {
     {
         // get the first frame in the group
         // get the first frame in the group
+
+#if 1
+        // FIXME: the cast is wrong and causea a warning on clang 5.0
+        // disable thi code for now, fix it later
+        ai_assert(false && "Bad pointer cast");
+#else
         BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*)pcFrames;
         BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*)pcFrames;
         pcFirstFrame = (BE_NCONST MDL::SimpleFrame*)(&pcFrames2->time + pcFrames->type);
         pcFirstFrame = (BE_NCONST MDL::SimpleFrame*)(&pcFrames2->time + pcFrames->type);
+#endif
     }
     }
     BE_NCONST MDL::Vertex* pcVertices = (BE_NCONST MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name));
     BE_NCONST MDL::Vertex* pcVertices = (BE_NCONST MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name));
     VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts));
     VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts));

+ 13 - 13
code/MDLMaterialLoader.cpp

@@ -56,6 +56,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Defines.h>
 #include <assimp/Defines.h>
 #include "qnan.h"
 #include "qnan.h"
 
 
+#include <memory>
+
 
 
 using namespace Assimp;
 using namespace Assimp;
 static aiTexel* const bad_texel = reinterpret_cast<aiTexel*>(SIZE_MAX);
 static aiTexel* const bad_texel = reinterpret_cast<aiTexel*>(SIZE_MAX);
@@ -489,7 +491,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
     unsigned int iWidth,
     unsigned int iWidth,
     unsigned int iHeight)
     unsigned int iHeight)
 {
 {
-    aiTexture* pcNew = nullptr;
+    std::unique_ptr<aiTexture> pcNew;
 
 
     // get the type of the skin
     // get the type of the skin
     unsigned int iMasked = (unsigned int)(iType & 0xF);
     unsigned int iMasked = (unsigned int)(iType & 0xF);
@@ -509,7 +511,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
                 "but texture height is not equal to 1, which is not supported by MED");
                 "but texture height is not equal to 1, which is not supported by MED");
         }
         }
 
 
-        pcNew = new aiTexture();
+        pcNew.reset(new aiTexture());
         pcNew->mHeight = 0;
         pcNew->mHeight = 0;
         pcNew->mWidth = iWidth;
         pcNew->mWidth = iWidth;
 
 
@@ -546,7 +548,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
     }
     }
     else if (iMasked || !iType || (iType && iWidth && iHeight))
     else if (iMasked || !iType || (iType && iWidth && iHeight))
     {
     {
-        pcNew = new aiTexture();
+        pcNew.reset(new aiTexture());
         if (!iHeight || !iWidth)
         if (!iHeight || !iWidth)
         {
         {
             DefaultLogger::get()->warn("Found embedded texture, but its width "
             DefaultLogger::get()->warn("Found embedded texture, but its width "
@@ -577,7 +579,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
             pcNew->mHeight = iHeight;
             pcNew->mHeight = iHeight;
 
 
             unsigned int iSkip = 0;
             unsigned int iSkip = 0;
-            ParseTextureColorData(szCurrent,iMasked,&iSkip,pcNew);
+            ParseTextureColorData(szCurrent,iMasked,&iSkip,pcNew.get());
 
 
             // skip length of texture data
             // skip length of texture data
             szCurrent += iSkip;
             szCurrent += iSkip;
@@ -588,7 +590,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
     // texture instead of material colors ... posssible they have
     // texture instead of material colors ... posssible they have
     // been converted to MDL7 from other formats, such as MDL5
     // been converted to MDL7 from other formats, such as MDL5
     aiColor4D clrTexture;
     aiColor4D clrTexture;
-    if (pcNew)clrTexture = ReplaceTextureWithColor(pcNew);
+    if (pcNew)clrTexture = ReplaceTextureWithColor(pcNew.get());
     else clrTexture.r = get_qnan();
     else clrTexture.r = get_qnan();
 
 
     // check whether a material definition is contained in the skin
     // check whether a material definition is contained in the skin
@@ -665,7 +667,9 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
         if (0.0f != pcMatIn->Power)
         if (0.0f != pcMatIn->Power)
         {
         {
             iShadingMode = (int)aiShadingMode_Phong;
             iShadingMode = (int)aiShadingMode_Phong;
-            pcMatOut->AddProperty<float>(&pcMatIn->Power,1,AI_MATKEY_SHININESS);
+            // pcMatIn is packed, we can't form pointers to its members
+            float power = pcMatIn->Power;
+            pcMatOut->AddProperty<float>(&power,1,AI_MATKEY_SHININESS);
         }
         }
         pcMatOut->AddProperty<int>(&iShadingMode,1,AI_MATKEY_SHADING_MODEL);
         pcMatOut->AddProperty<int>(&iShadingMode,1,AI_MATKEY_SHADING_MODEL);
     }
     }
@@ -678,8 +682,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
     // we don't need the texture anymore
     // we don't need the texture anymore
     if (is_not_qnan(clrTexture.r))
     if (is_not_qnan(clrTexture.r))
     {
     {
-        delete pcNew;
-        pcNew = NULL;
+        pcNew.reset();
     }
     }
 
 
     // If an ASCII effect description (HLSL?) is contained in the file,
     // If an ASCII effect description (HLSL?) is contained in the file,
@@ -714,7 +717,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
         {
         {
             pScene->mNumTextures = 1;
             pScene->mNumTextures = 1;
             pScene->mTextures = new aiTexture*[1];
             pScene->mTextures = new aiTexture*[1];
-            pScene->mTextures[0] = pcNew;
+            pScene->mTextures[0] = pcNew.release();
         }
         }
         else
         else
         {
         {
@@ -724,16 +727,13 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
                 pScene->mTextures[i] = pc[i];
                 pScene->mTextures[i] = pc[i];
             }
             }
 
 
-            pScene->mTextures[pScene->mNumTextures] = pcNew;
+            pScene->mTextures[pScene->mNumTextures] = pcNew.release();
             pScene->mNumTextures++;
             pScene->mNumTextures++;
             delete[] pc;
             delete[] pc;
         }
         }
     }
     }
     VALIDATE_FILE_SIZE(szCurrent);
     VALIDATE_FILE_SIZE(szCurrent);
     *szCurrentOut = szCurrent;
     *szCurrentOut = szCurrent;
-    if ( nullptr != pcNew ) {
-        delete pcNew;
-    }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 8 - 8
code/MMDImporter.cpp

@@ -107,7 +107,7 @@ const aiImporterDesc *MMDImporter::GetInfo() const { return &desc; }
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //  MMD import implementation
 //  MMD import implementation
 void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene,
 void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene,
-                                 IOSystem *pIOHandler) {
+                                 IOSystem * /*pIOHandler*/) {
   // Read file by istream
   // Read file by istream
   std::filebuf fb;
   std::filebuf fb;
   if (!fb.open(file, std::ios::in | std::ios::binary)) {
   if (!fb.open(file, std::ios::in | std::ios::binary)) {
@@ -141,8 +141,6 @@ void MMDImporter::CreateDataFromImport(const pmx::PmxModel *pModel,
   aiNode *pNode = new aiNode;
   aiNode *pNode = new aiNode;
   if (!pModel->model_name.empty()) {
   if (!pModel->model_name.empty()) {
     pNode->mName.Set(pModel->model_name);
     pNode->mName.Set(pModel->model_name);
-  } else {
-    ai_assert(false);
   }
   }
 
 
   pScene->mRootNode = pNode;
   pScene->mRootNode = pNode;
@@ -170,7 +168,7 @@ void MMDImporter::CreateDataFromImport(const pmx::PmxModel *pModel,
   }
   }
 
 
   // create node hierarchy for bone position
   // create node hierarchy for bone position
-  aiNode **ppNode = new aiNode *[pModel->bone_count];
+  std::unique_ptr<aiNode *[]> ppNode(new aiNode *[pModel->bone_count]);
   for (auto i = 0; i < pModel->bone_count; i++) {
   for (auto i = 0; i < pModel->bone_count; i++) {
     ppNode[i] = new aiNode(pModel->bones[i].bone_name);
     ppNode[i] = new aiNode(pModel->bones[i].bone_name);
   }
   }
@@ -179,9 +177,9 @@ void MMDImporter::CreateDataFromImport(const pmx::PmxModel *pModel,
     const pmx::PmxBone &bone = pModel->bones[i];
     const pmx::PmxBone &bone = pModel->bones[i];
 
 
     if (bone.parent_index < 0) {
     if (bone.parent_index < 0) {
-      pScene->mRootNode->addChildren(1, ppNode + i);
+      pScene->mRootNode->addChildren(1, ppNode.get() + i);
     } else {
     } else {
-      ppNode[bone.parent_index]->addChildren(1, ppNode + i);
+      ppNode[bone.parent_index]->addChildren(1, ppNode.get() + i);
 
 
       aiVector3D v3 = aiVector3D(
       aiVector3D v3 = aiVector3D(
           bone.position[0] - pModel->bones[bone.parent_index].position[0],
           bone.position[0] - pModel->bones[bone.parent_index].position[0],
@@ -326,8 +324,10 @@ aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel,
     auto it = bone_vertex_map.find(ii);
     auto it = bone_vertex_map.find(ii);
     if (it != bone_vertex_map.end()) {
     if (it != bone_vertex_map.end()) {
       pBone->mNumWeights = static_cast<unsigned int>(it->second.size());
       pBone->mNumWeights = static_cast<unsigned int>(it->second.size());
-      pBone->mWeights = it->second.data();
-      it->second.swap(*(new vector<aiVertexWeight>));
+      pBone->mWeights = new aiVertexWeight[pBone->mNumWeights];
+      for (unsigned int j = 0; j < pBone->mNumWeights; j++) {
+          pBone->mWeights[j] = it->second[j];
+      }
     }
     }
     bone_ptr_ptr[ii] = pBone;
     bone_ptr_ptr[ii] = pBone;
   }
   }

+ 1 - 1
code/MMDPmxParser.cpp

@@ -471,7 +471,7 @@ namespace pmx
 		stream->read((char*) &this->is_near, sizeof(uint8_t));
 		stream->read((char*) &this->is_near, sizeof(uint8_t));
 	}
 	}
 
 
-	void PmxSoftBody::Read(std::istream *stream, PmxSetting *setting)
+    void PmxSoftBody::Read(std::istream * /*stream*/, PmxSetting * /*setting*/)
 	{
 	{
 		// 未実装
 		// 未実装
 		std::cerr << "Not Implemented Exception" << std::endl;
 		std::cerr << "Not Implemented Exception" << std::endl;

+ 1 - 0
code/MMDPmxParser.h

@@ -87,6 +87,7 @@ namespace pmx
 	{
 	{
 	public:
 	public:
 		virtual void Read(std::istream *stream, PmxSetting *setting) = 0;
 		virtual void Read(std::istream *stream, PmxSetting *setting) = 0;
+		virtual ~PmxVertexSkinning() {}
 	};
 	};
 
 
 	class PmxVertexSkinningBDEF1 : public PmxVertexSkinning
 	class PmxVertexSkinningBDEF1 : public PmxVertexSkinning

+ 1 - 1
code/MMDVmdParser.h

@@ -302,7 +302,7 @@ namespace vmd
 			return result;
 			return result;
 		}
 		}
 
 
-		bool SaveToFile(const std::u16string& filename)
+        bool SaveToFile(const std::u16string& /*filename*/)
 		{
 		{
 			// TODO: How to adapt u16string to string?
 			// TODO: How to adapt u16string to string?
 			/*
 			/*

+ 11 - 8
code/NFFLoader.cpp

@@ -243,8 +243,6 @@ void NFFImporter::InternReadFile( const std::string& pFile,
     if( !file.get())
     if( !file.get())
         throw DeadlyImportError( "Failed to open NFF file " + pFile + ".");
         throw DeadlyImportError( "Failed to open NFF file " + pFile + ".");
 
 
-    unsigned int m = (unsigned int)file->FileSize();
-
     // allocate storage and copy the contents of the file to a memory buffer
     // allocate storage and copy the contents of the file to a memory buffer
     // (terminate it with zero)
     // (terminate it with zero)
     std::vector<char> mBuffer2;
     std::vector<char> mBuffer2;
@@ -469,7 +467,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
                         for (unsigned int a = 0; a < numIdx;++a)
                         for (unsigned int a = 0; a < numIdx;++a)
                         {
                         {
                             SkipSpaces(sz,&sz);
                             SkipSpaces(sz,&sz);
-                            m = ::strtoul10(sz,&sz);
+                            unsigned int m = ::strtoul10(sz,&sz);
                             if (m >= (unsigned int)tempPositions.size())
                             if (m >= (unsigned int)tempPositions.size())
                             {
                             {
                                 DefaultLogger::get()->error("NFF2: Vertex index overflow");
                                 DefaultLogger::get()->error("NFF2: Vertex index overflow");
@@ -635,7 +633,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
                         for (std::vector<unsigned int>::const_iterator it = tempIdx.begin(), end = tempIdx.end();
                         for (std::vector<unsigned int>::const_iterator it = tempIdx.begin(), end = tempIdx.end();
                             it != end;++it)
                             it != end;++it)
                         {
                         {
-                            m = *it;
+                            unsigned int m = *it;
 
 
                             // copy colors -vertex color specifications override polygon color specifications
                             // copy colors -vertex color specifications override polygon color specifications
                             if (hasColor)
                             if (hasColor)
@@ -735,7 +733,7 @@ void NFFImporter::InternReadFile( const std::string& pFile,
                     sz = &line[1];out = currentMesh;
                     sz = &line[1];out = currentMesh;
                 }
                 }
                 SkipSpaces(sz,&sz);
                 SkipSpaces(sz,&sz);
-                m = strtoul10(sz);
+                unsigned int m = strtoul10(sz);
 
 
                 // ---- flip the face order
                 // ---- flip the face order
                 out->vertices.resize(out->vertices.size()+m);
                 out->vertices.resize(out->vertices.size()+m);
@@ -1081,7 +1079,9 @@ void NFFImporter::InternReadFile( const std::string& pFile,
     // generate the camera
     // generate the camera
     if (hasCam)
     if (hasCam)
     {
     {
-        aiNode* nd = *ppcChildren = new aiNode();
+        ai_assert(ppcChildren);
+        aiNode* nd = new aiNode();
+        *ppcChildren = nd;
         nd->mName.Set("<NFF_Camera>");
         nd->mName.Set("<NFF_Camera>");
         nd->mParent = root;
         nd->mParent = root;
 
 
@@ -1105,13 +1105,15 @@ void NFFImporter::InternReadFile( const std::string& pFile,
     // generate light sources
     // generate light sources
     if (!lights.empty())
     if (!lights.empty())
     {
     {
+        ai_assert(ppcChildren);
         pScene->mNumLights = (unsigned int)lights.size();
         pScene->mNumLights = (unsigned int)lights.size();
         pScene->mLights = new aiLight*[pScene->mNumLights];
         pScene->mLights = new aiLight*[pScene->mNumLights];
         for (unsigned int i = 0; i < pScene->mNumLights;++i,++ppcChildren)
         for (unsigned int i = 0; i < pScene->mNumLights;++i,++ppcChildren)
         {
         {
             const Light& l = lights[i];
             const Light& l = lights[i];
 
 
-            aiNode* nd = *ppcChildren  = new aiNode();
+            aiNode* nd = new aiNode();
+            *ppcChildren = nd;
             nd->mParent = root;
             nd->mParent = root;
 
 
             nd->mName.length = ::ai_snprintf(nd->mName.data,1024,"<NFF_Light%u>",i);
             nd->mName.length = ::ai_snprintf(nd->mName.data,1024,"<NFF_Light%u>",i);
@@ -1128,7 +1130,8 @@ void NFFImporter::InternReadFile( const std::string& pFile,
     if (!pScene->mNumMeshes)throw DeadlyImportError("NFF: No meshes loaded");
     if (!pScene->mNumMeshes)throw DeadlyImportError("NFF: No meshes loaded");
     pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
     pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
     pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes];
     pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = pScene->mNumMeshes];
-    for (it = meshes.begin(), m = 0; it != end;++it)
+    unsigned int m = 0;
+    for (it = meshes.begin(); it != end;++it)
     {
     {
         if ((*it).faces.empty())continue;
         if ((*it).faces.empty())continue;
 
 

+ 45 - 15
code/ObjExporter.cpp

@@ -58,10 +58,14 @@ namespace Assimp {
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp
 // Worker function for exporting a scene to Wavefront OBJ. Prototyped and registered in Exporter.cpp
-void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) {
+void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) {
     // invoke the exporter
     // invoke the exporter
     ObjExporter exporter(pFile, pScene);
     ObjExporter exporter(pFile, pScene);
 
 
+    if (exporter.mOutput.fail() || exporter.mOutputMat.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 both the main OBJ file and the material script
     // we're still here - export successfully completed. Write both the main OBJ file and the material script
     {
     {
         std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
         std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
@@ -79,18 +83,40 @@ void ExportSceneObj(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene
     }
     }
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Worker function for exporting a scene to Wavefront OBJ without the material file. Prototyped and registered in Exporter.cpp
+void ExportSceneObjNoMtl(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) {
+    // invoke the exporter
+    ObjExporter exporter(pFile, pScene, true);
+
+    if (exporter.mOutput.fail() || exporter.mOutputMat.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 both the main OBJ file and the material script
+    {
+        std::unique_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
+        if(outfile == NULL) {
+            throw DeadlyExportError("could not open output .obj file: " + std::string(pFile));
+        }
+        outfile->Write( exporter.mOutput.str().c_str(), static_cast<size_t>(exporter.mOutput.tellp()),1);
+    }
+
+
+}
+
 } // end of namespace Assimp
 } // end of namespace Assimp
 
 
 static const std::string MaterialExt = ".mtl";
 static const std::string MaterialExt = ".mtl";
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene)
+ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMtl)
 : filename(_filename)
 : filename(_filename)
 , pScene(pScene)
 , pScene(pScene)
 , vp()
 , vp()
 , vn()
 , vn()
 , vt()
 , vt()
-, vc() 
+, vc()
 , mVpMap()
 , mVpMap()
 , mVnMap()
 , mVnMap()
 , mVtMap()
 , mVtMap()
@@ -104,8 +130,9 @@ ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene)
     mOutputMat.imbue(l);
     mOutputMat.imbue(l);
     mOutputMat.precision(16);
     mOutputMat.precision(16);
 
 
-    WriteGeometryFile();
-    WriteMaterialFile();
+    WriteGeometryFile(noMtl);
+    if (!noMtl)
+        WriteMaterialFile();
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -128,7 +155,7 @@ std::string ObjExporter :: GetMaterialLibName()
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 std::string ObjExporter::GetMaterialLibFileName() {
 std::string ObjExporter::GetMaterialLibFileName() {
-    // Remove existing .obj file extention so that the final material file name will be fileName.mtl and not fileName.obj.mtl
+    // Remove existing .obj file extension so that the final material file name will be fileName.mtl and not fileName.obj.mtl
     size_t lastdot = filename.find_last_of('.');
     size_t lastdot = filename.find_last_of('.');
     if (lastdot != std::string::npos)
     if (lastdot != std::string::npos)
         return filename.substr(0, lastdot) + MaterialExt;
         return filename.substr(0, lastdot) + MaterialExt;
@@ -189,7 +216,7 @@ void ObjExporter::WriteMaterialFile()
         if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_TRANSPARENT,c)) {
         if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_TRANSPARENT,c)) {
             mOutputMat << "Tf " << c.r << " " << c.g << " " << c.b << endl;
             mOutputMat << "Tf " << c.r << " " << c.g << " " << c.b << endl;
         }
         }
-        
+
         ai_real o;
         ai_real o;
         if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {
         if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {
             mOutputMat << "d " << o << endl;
             mOutputMat << "d " << o << endl;
@@ -231,10 +258,10 @@ void ObjExporter::WriteMaterialFile()
     }
     }
 }
 }
 
 
-// ------------------------------------------------------------------------------------------------
-void ObjExporter::WriteGeometryFile() {
+void ObjExporter::WriteGeometryFile(bool noMtl) {
     WriteHeader(mOutput);
     WriteHeader(mOutput);
-    mOutput << "mtllib "  << GetMaterialLibName() << endl << endl;
+    if (!noMtl)
+        mOutput << "mtllib "  << GetMaterialLibName() << endl << endl;
 
 
     // collect mesh geometry
     // collect mesh geometry
     aiMatrix4x4 mBase;
     aiMatrix4x4 mBase;
@@ -252,8 +279,10 @@ void ObjExporter::WriteGeometryFile() {
         mOutput << "# " << vp.size() << " vertex positions and colors" << endl;
         mOutput << "# " << vp.size() << " vertex positions and colors" << endl;
         size_t colIdx = 0;
         size_t colIdx = 0;
         for ( const aiVector3D& v : vp ) {
         for ( const aiVector3D& v : vp ) {
-            mOutput << "v  " << v.x << " " << v.y << " " << v.z << " " << vc[ colIdx ].r << " " << vc[ colIdx ].g << " " << vc[ colIdx ].b << endl;
-            colIdx++;
+            if ( colIdx < vc.size() ) {
+                mOutput << "v  " << v.x << " " << v.y << " " << v.z << " " << vc[ colIdx ].r << " " << vc[ colIdx ].g << " " << vc[ colIdx ].b << endl;
+            }
+            ++colIdx;
         }
         }
     }
     }
     mOutput << endl;
     mOutput << endl;
@@ -280,7 +309,8 @@ void ObjExporter::WriteGeometryFile() {
         if (!m.name.empty()) {
         if (!m.name.empty()) {
             mOutput << "g " << m.name << endl;
             mOutput << "g " << m.name << endl;
         }
         }
-        mOutput << "usemtl " << m.matname << endl;
+        if (!noMtl)
+            mOutput << "usemtl " << m.matname << endl;
 
 
         for(const Face& f : m.faces) {
         for(const Face& f : m.faces) {
             mOutput << f.kind << ' ';
             mOutput << f.kind << ' ';
@@ -337,7 +367,7 @@ int ObjExporter::colIndexMap::getIndex( const aiColor4D& col ) {
     colMap[ col ] = mNextIndex;
     colMap[ col ] = mNextIndex;
     int ret = mNextIndex;
     int ret = mNextIndex;
     mNextIndex++;
     mNextIndex++;
-    
+
     return ret;
     return ret;
 }
 }
 
 
@@ -354,7 +384,7 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4
     mMeshes.push_back(MeshInstance());
     mMeshes.push_back(MeshInstance());
     MeshInstance& mesh = mMeshes.back();
     MeshInstance& mesh = mMeshes.back();
 
 
-    mesh.name = std::string(name.data,name.length) + (m->mName.length ? "_" + std::string(m->mName.data,m->mName.length) : "");
+    mesh.name = std::string( name.data, name.length );
     mesh.matname = GetMaterialName(m->mMaterialIndex);
     mesh.matname = GetMaterialName(m->mMaterialIndex);
 
 
     mesh.faces.resize(m->mNumFaces);
     mesh.faces.resize(m->mNumFaces);

+ 2 - 2
code/ObjExporter.h

@@ -62,7 +62,7 @@ namespace Assimp {
 class ObjExporter {
 class ObjExporter {
 public:
 public:
     /// Constructor for a specific scene to export
     /// Constructor for a specific scene to export
-    ObjExporter(const char* filename, const aiScene* pScene);
+    ObjExporter(const char* filename, const aiScene* pScene, bool noMtl=false);
     ~ObjExporter();
     ~ObjExporter();
     std::string GetMaterialLibName();
     std::string GetMaterialLibName();
     std::string GetMaterialLibFileName();
     std::string GetMaterialLibFileName();
@@ -97,7 +97,7 @@ private:
 
 
     void WriteHeader(std::ostringstream& out);
     void WriteHeader(std::ostringstream& out);
     void WriteMaterialFile();
     void WriteMaterialFile();
-    void WriteGeometryFile();
+    void WriteGeometryFile(bool noMtl=false);
     std::string GetMaterialName(unsigned int index);
     std::string GetMaterialName(unsigned int index);
     void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat);
     void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat);
     void AddNode(const aiNode* nd, const aiMatrix4x4& mParent);
     void AddNode(const aiNode* nd, const aiMatrix4x4& mParent);

+ 13 - 10
code/ObjFileImporter.cpp

@@ -264,8 +264,12 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
     {
     {
         unsigned int meshId = pObject->m_Meshes[ i ];
         unsigned int meshId = pObject->m_Meshes[ i ];
         aiMesh *pMesh = createTopology( pModel, pObject, meshId );
         aiMesh *pMesh = createTopology( pModel, pObject, meshId );
-        if( pMesh && pMesh->mNumFaces > 0 ) {
-            MeshArray.push_back( pMesh );
+        if( pMesh ) {
+            if (pMesh->mNumFaces > 0) {
+                MeshArray.push_back( pMesh );
+            } else {
+                delete pMesh;
+            }
         }
         }
     }
     }
 
 
@@ -317,7 +321,7 @@ aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const Obj
         return NULL;
         return NULL;
     }
     }
 
 
-    aiMesh* pMesh = new aiMesh;
+    std::unique_ptr<aiMesh> pMesh(new aiMesh);
     if( !pObjMesh->m_name.empty() ) {
     if( !pObjMesh->m_name.empty() ) {
         pMesh->mName.Set( pObjMesh->m_name );
         pMesh->mName.Set( pObjMesh->m_name );
     }
     }
@@ -382,9 +386,9 @@ aiMesh *ObjFileImporter::createTopology( const ObjFile::Model* pModel, const Obj
     }
     }
 
 
     // Create mesh vertices
     // Create mesh vertices
-    createVertexArray(pModel, pData, meshIndex, pMesh, uiIdxCount);
+    createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount);
 
 
-    return pMesh;
+    return pMesh.release();
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -444,6 +448,10 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
                 throw DeadlyImportError( "OBJ: vertex index out of range" );
                 throw DeadlyImportError( "OBJ: vertex index out of range" );
             }
             }
 
 
+            if ( pMesh->mNumVertices <= newIndex ) {
+                throw DeadlyImportError("OBJ: bad vertex index");
+            }
+
             pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ];
             pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ];
 
 
             // Copy all normals
             // Copy all normals
@@ -466,7 +474,6 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
             if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_texturCoords.size())
             if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_texturCoords.size())
             {
             {
                 const unsigned int tex = pSourceFace->m_texturCoords.at( vertexIndex );
                 const unsigned int tex = pSourceFace->m_texturCoords.at( vertexIndex );
-                ai_assert( tex < pModel->m_TextureCoord.size() );
 
 
                 if ( tex >= pModel->m_TextureCoord.size() )
                 if ( tex >= pModel->m_TextureCoord.size() )
                     throw DeadlyImportError("OBJ: texture coordinate index out of range");
                     throw DeadlyImportError("OBJ: texture coordinate index out of range");
@@ -475,10 +482,6 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
                 pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord3d.x, coord3d.y, coord3d.z );
                 pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord3d.x, coord3d.y, coord3d.z );
             }
             }
 
 
-            if ( pMesh->mNumVertices <= newIndex ) {
-                throw DeadlyImportError("OBJ: bad vertex index");
-            }
-
             // Get destination face
             // Get destination face
             aiFace *pDestFace = &pMesh->mFaces[ outIndex ];
             aiFace *pDestFace = &pMesh->mFaces[ outIndex ];
 
 

+ 12 - 16
code/ObjFileParser.cpp

@@ -60,7 +60,7 @@ const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME;
 ObjFileParser::ObjFileParser()
 ObjFileParser::ObjFileParser()
 : m_DataIt()
 : m_DataIt()
 , m_DataItEnd()
 , m_DataItEnd()
-, m_pModel( NULL )
+, m_pModel( nullptr )
 , m_uiLine( 0 )
 , m_uiLine( 0 )
 , m_pIO( nullptr )
 , m_pIO( nullptr )
 , m_progress( nullptr )
 , m_progress( nullptr )
@@ -73,7 +73,7 @@ ObjFileParser::ObjFileParser( IOStreamBuffer<char> &streamBuffer, const std::str
                               const std::string &originalObjFileName) :
                               const std::string &originalObjFileName) :
     m_DataIt(),
     m_DataIt(),
     m_DataItEnd(),
     m_DataItEnd(),
-    m_pModel(NULL),
+    m_pModel(nullptr),
     m_uiLine(0),
     m_uiLine(0),
     m_pIO( io ),
     m_pIO( io ),
     m_progress(progress),
     m_progress(progress),
@@ -82,7 +82,7 @@ ObjFileParser::ObjFileParser( IOStreamBuffer<char> &streamBuffer, const std::str
     std::fill_n(m_buffer,Buffersize,0);
     std::fill_n(m_buffer,Buffersize,0);
 
 
     // Create the model instance to store all the data
     // Create the model instance to store all the data
-    m_pModel = new ObjFile::Model();
+    m_pModel.reset(new ObjFile::Model());
     m_pModel->m_ModelName = modelName;
     m_pModel->m_ModelName = modelName;
 
 
     // create default material and store it
     // create default material and store it
@@ -96,8 +96,6 @@ ObjFileParser::ObjFileParser( IOStreamBuffer<char> &streamBuffer, const std::str
 }
 }
 
 
 ObjFileParser::~ObjFileParser() {
 ObjFileParser::~ObjFileParser() {
-    delete m_pModel;
-    m_pModel = NULL;
 }
 }
 
 
 void ObjFileParser::setBuffer( std::vector<char> &buffer ) {
 void ObjFileParser::setBuffer( std::vector<char> &buffer ) {
@@ -106,7 +104,7 @@ void ObjFileParser::setBuffer( std::vector<char> &buffer ) {
 }
 }
 
 
 ObjFile::Model *ObjFileParser::GetModel() const {
 ObjFile::Model *ObjFileParser::GetModel() const {
-    return m_pModel;
+    return m_pModel.get();
 }
 }
 
 
 void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
 void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
@@ -353,14 +351,13 @@ void ObjFileParser::getHomogeneousVector3( std::vector<aiVector3D> &point3d_arra
     copyNextWord( m_buffer, Buffersize );
     copyNextWord( m_buffer, Buffersize );
     w = ( ai_real ) fast_atof( m_buffer );
     w = ( ai_real ) fast_atof( m_buffer );
 
 
-    ai_assert( w != 0 );
+    if (w == 0)
+      throw DeadlyImportError("OBJ: Invalid component in homogeneous vector (Division by zero)");
 
 
     point3d_array.push_back( aiVector3D( x/w, y/w, z/w ) );
     point3d_array.push_back( aiVector3D( x/w, y/w, z/w ) );
     m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
     m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 }
 
 
-// -------------------------------------------------------------------
-//  Get values for two 3D vectors on the same line
 void ObjFileParser::getTwoVectors3( std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b ) {
 void ObjFileParser::getTwoVectors3( std::vector<aiVector3D> &point3d_array_a, std::vector<aiVector3D> &point3d_array_b ) {
     ai_real x, y, z;
     ai_real x, y, z;
     copyNextWord(m_buffer, Buffersize);
     copyNextWord(m_buffer, Buffersize);
@@ -388,8 +385,6 @@ void ObjFileParser::getTwoVectors3( std::vector<aiVector3D> &point3d_array_a, st
     m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
     m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 }
 
 
-// -------------------------------------------------------------------
-//  Get values for a new 2D vector instance
 void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
 void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
     ai_real x, y;
     ai_real x, y;
     copyNextWord(m_buffer, Buffersize);
     copyNextWord(m_buffer, Buffersize);
@@ -405,8 +400,6 @@ void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
 
 
 static const std::string DefaultObjName = "defaultobject";
 static const std::string DefaultObjName = "defaultobject";
 
 
-// -------------------------------------------------------------------
-//  Get values for a new face instance
 void ObjFileParser::getFace( aiPrimitiveType type ) {
 void ObjFileParser::getFace( aiPrimitiveType type ) {
     m_DataIt = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
     m_DataIt = getNextToken<DataArrayIt>( m_DataIt, m_DataItEnd );
     if ( m_DataIt == m_DataItEnd || *m_DataIt == '\0' ) {
     if ( m_DataIt == m_DataItEnd || *m_DataIt == '\0' ) {
@@ -481,7 +474,12 @@ void ObjFileParser::getFace( aiPrimitiveType type ) {
                 } else {
                 } else {
                     reportErrorTokenInFace();
                     reportErrorTokenInFace();
                 }
                 }
+            } else {
+                //On error, std::atoi will return 0 which is not a valid value
+                delete face;
+                throw DeadlyImportError("OBJ: Invalid face indice");
             }
             }
+
         }
         }
         m_DataIt += iStep;
         m_DataIt += iStep;
     }
     }
@@ -522,8 +520,6 @@ void ObjFileParser::getFace( aiPrimitiveType type ) {
     m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
     m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 }
 
 
-// -------------------------------------------------------------------
-//  Get values for a new material description
 void ObjFileParser::getMaterialDesc() {
 void ObjFileParser::getMaterialDesc() {
     // Get next data for material data
     // Get next data for material data
     m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
     m_DataIt = getNextToken<DataArrayIt>(m_DataIt, m_DataItEnd);
@@ -642,7 +638,7 @@ void ObjFileParser::getMaterialLib() {
     m_pIO->Close( pFile );
     m_pIO->Close( pFile );
 
 
     // Importing the material library
     // Importing the material library
-    ObjFileMtlImporter mtlImporter( buffer, strMatName, m_pModel );
+    ObjFileMtlImporter mtlImporter( buffer, strMatName, m_pModel.get() );
 }
 }
 
 
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------

+ 2 - 1
code/ObjFileParser.h

@@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <vector>
 #include <vector>
 #include <string>
 #include <string>
 #include <map>
 #include <map>
+#include <memory>
 #include <assimp/vector2.h>
 #include <assimp/vector2.h>
 #include <assimp/vector3.h>
 #include <assimp/vector3.h>
 #include <assimp/mesh.h>
 #include <assimp/mesh.h>
@@ -145,7 +146,7 @@ private:
     //! Iterator to end position of buffer
     //! Iterator to end position of buffer
     DataArrayIt m_DataItEnd;
     DataArrayIt m_DataItEnd;
     //! Pointer to model instance
     //! Pointer to model instance
-    ObjFile::Model *m_pModel;
+    std::unique_ptr<ObjFile::Model> m_pModel;
     //! Current line (for debugging)
     //! Current line (for debugging)
     unsigned int m_uiLine;
     unsigned int m_uiLine;
     //! Helper buffer
     //! Helper buffer

+ 1 - 1
code/OgreMaterial.cpp

@@ -258,7 +258,7 @@ aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSyste
                 ReadTechnique(Trim(techniqueName), ss, material);
                 ReadTechnique(Trim(techniqueName), ss, material);
             }
             }
 
 
-            // Read informations from a custom material
+            // Read information from a custom material
             /** @todo This "set $x y" does not seem to be a official Ogre material system feature.
             /** @todo This "set $x y" does not seem to be a official Ogre material system feature.
                 Materials can inherit other materials and override texture units by using the (unique)
                 Materials can inherit other materials and override texture units by using the (unique)
                 parent texture unit name in your cloned material.
                 parent texture unit name in your cloned material.

+ 1 - 1
code/OpenGEXExporter.cpp

@@ -51,7 +51,7 @@ OpenGEXExporter::OpenGEXExporter() {
 OpenGEXExporter::~OpenGEXExporter() {
 OpenGEXExporter::~OpenGEXExporter() {
 }
 }
 
 
-bool OpenGEXExporter::exportScene( const char *filename, const aiScene* pScene ) {
+bool OpenGEXExporter::exportScene( const char * /*filename*/, const aiScene* /*pScene*/ ) {
     return true;
     return true;
 }
 }
 
 

+ 25 - 11
code/OpenGEXImporter.cpp

@@ -431,7 +431,7 @@ void OpenGEXImporter::handleNodes( DDLNode *node, aiScene *pScene ) {
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleMetricNode( DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleMetricNode( DDLNode *node, aiScene * /*pScene*/ ) {
     if( nullptr == node || nullptr == m_ctx ) {
     if( nullptr == node || nullptr == m_ctx ) {
         return;
         return;
     }
     }
@@ -467,7 +467,7 @@ void OpenGEXImporter::handleMetricNode( DDLNode *node, aiScene *pScene ) {
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleNameNode( DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleNameNode( DDLNode *node, aiScene * /*pScene*/ ) {
     if( nullptr == m_currentNode ) {
     if( nullptr == m_currentNode ) {
         throw DeadlyImportError( "No current node for name." );
         throw DeadlyImportError( "No current node for name." );
         return;
         return;
@@ -512,7 +512,7 @@ static void getRefNames( DDLNode *node, std::vector<std::string> &names ) {
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleObjectRefNode( DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleObjectRefNode( DDLNode *node, aiScene * /*pScene*/ ) {
     if( nullptr == m_currentNode ) {
     if( nullptr == m_currentNode ) {
         throw DeadlyImportError( "No parent node for name." );
         throw DeadlyImportError( "No parent node for name." );
         return;
         return;
@@ -536,7 +536,7 @@ void OpenGEXImporter::handleObjectRefNode( DDLNode *node, aiScene *pScene ) {
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleMaterialRefNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleMaterialRefNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) {
     if( nullptr == m_currentNode ) {
     if( nullptr == m_currentNode ) {
         throw DeadlyImportError( "No parent node for name." );
         throw DeadlyImportError( "No parent node for name." );
         return;
         return;
@@ -652,6 +652,8 @@ static void setMatrix( aiNode *node, DataArrayList *transformData ) {
         i++;
         i++;
     }
     }
 
 
+    ai_assert(i == 16);
+
     node->mTransformation.a1 = m[ 0 ];
     node->mTransformation.a1 = m[ 0 ];
     node->mTransformation.a2 = m[ 4 ];
     node->mTransformation.a2 = m[ 4 ];
     node->mTransformation.a3 = m[ 8 ];
     node->mTransformation.a3 = m[ 8 ];
@@ -674,7 +676,7 @@ static void setMatrix( aiNode *node, DataArrayList *transformData ) {
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleTransformNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleTransformNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) {
     if( nullptr == m_currentNode ) {
     if( nullptr == m_currentNode ) {
         throw DeadlyImportError( "No parent node for name." );
         throw DeadlyImportError( "No parent node for name." );
         return;
         return;
@@ -776,10 +778,22 @@ static void fillColor4( aiColor4D *col4, Value *vals ) {
     Value *next( vals );
     Value *next( vals );
     col4->r = next->getFloat();
     col4->r = next->getFloat();
     next = next->m_next;
     next = next->m_next;
+    if (!next) {
+        throw DeadlyImportError( "OpenGEX: Not enough values to fill 4-element color, only 1" );
+    }
+
     col4->g = next->getFloat();
     col4->g = next->getFloat();
     next = next->m_next;
     next = next->m_next;
+    if (!next) {
+        throw DeadlyImportError( "OpenGEX: Not enough values to fill 4-element color, only 2" );
+    }
+
     col4->b = next->getFloat();
     col4->b = next->getFloat();
     next = next->m_next;
     next = next->m_next;
+    if (!next) {
+        throw DeadlyImportError( "OpenGEX: Not enough values to fill 4-element color, only 3" );
+    }
+
     col4->a = next->getFloat();
     col4->a = next->getFloat();
 }
 }
 
 
@@ -819,7 +833,7 @@ static void copyColor4DArray( size_t numItems, DataArrayList *vaList, aiColor4D
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) {
     if( nullptr == node ) {
     if( nullptr == node ) {
         throw DeadlyImportError( "No parent node for name." );
         throw DeadlyImportError( "No parent node for name." );
         return;
         return;
@@ -862,7 +876,7 @@ void OpenGEXImporter::handleVertexArrayNode( ODDLParser::DDLNode *node, aiScene
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) {
     if( nullptr == node ) {
     if( nullptr == node ) {
         throw DeadlyImportError( "No parent node for name." );
         throw DeadlyImportError( "No parent node for name." );
         return;
         return;
@@ -1001,7 +1015,7 @@ void OpenGEXImporter::handleMaterialNode( ODDLParser::DDLNode *node, aiScene *pS
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleColorNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleColorNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) {
     if( nullptr == node ) {
     if( nullptr == node ) {
         return;
         return;
     }
     }
@@ -1040,7 +1054,7 @@ void OpenGEXImporter::handleColorNode( ODDLParser::DDLNode *node, aiScene *pScen
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleTextureNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleTextureNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) {
     if( nullptr == node ) {
     if( nullptr == node ) {
         return;
         return;
     }
     }
@@ -1074,7 +1088,7 @@ void OpenGEXImporter::handleTextureNode( ODDLParser::DDLNode *node, aiScene *pSc
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleParamNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleParamNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) {
     if ( nullptr == node ) {
     if ( nullptr == node ) {
         return;
         return;
     }
     }
@@ -1103,7 +1117,7 @@ void OpenGEXImporter::handleParamNode( ODDLParser::DDLNode *node, aiScene *pScen
 }
 }
 
 
 //------------------------------------------------------------------------------------------------
 //------------------------------------------------------------------------------------------------
-void OpenGEXImporter::handleAttenNode( ODDLParser::DDLNode *node, aiScene *pScene ) {
+void OpenGEXImporter::handleAttenNode( ODDLParser::DDLNode *node, aiScene * /*pScene*/ ) {
     if ( nullptr == node ) {
     if ( nullptr == node ) {
         return;
         return;
     }
     }

+ 6 - 4
code/OptimizeGraph.cpp

@@ -233,10 +233,12 @@ void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& no
 
 
     nd->mNumChildren = static_cast<unsigned int>(child_nodes.size());
     nd->mNumChildren = static_cast<unsigned int>(child_nodes.size());
 
 
-    aiNode** tmp = nd->mChildren;
-    for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
-        aiNode* node = *tmp++ = *it;
-        node->mParent = nd;
+    if (nd->mChildren) {
+        aiNode** tmp = nd->mChildren;
+        for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
+            aiNode* node = *tmp++ = *it;
+            node->mParent = nd;
+        }
     }
     }
 
 
     nodes_out += static_cast<unsigned int>(child_nodes.size());
     nodes_out += static_cast<unsigned int>(child_nodes.size());

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません