瀏覽代碼

Merge branch 'master' into fix_gltf2_export_componentType_error

Kim Kulling 7 年之前
父節點
當前提交
cc0b3e1249
共有 100 個文件被更改,包括 3309 次插入2431 次删除
  1. 9 0
      .gitignore
  2. 7 0
      Build.md
  3. 45 37
      CMakeLists.txt
  4. 9 10
      CONTRIBUTING.md
  5. 3 0
      INSTALL
  6. 2 0
      Readme.md
  7. 4 0
      appveyor.yml
  8. 5 3
      code/3DSConverter.cpp
  9. 14 16
      code/3DSHelper.h
  10. 2 2
      code/3DSLoader.cpp
  11. 64 184
      code/AMFImporter.hpp
  12. 59 41
      code/AMFImporter_Material.cpp
  13. 62 123
      code/AMFImporter_Node.hpp
  14. 46 67
      code/ASEParser.h
  15. 524 513
      code/AssbinExporter.cpp
  16. 8 1
      code/AssbinExporter.h
  17. 109 127
      code/AssbinLoader.cpp
  18. 22 21
      code/AssbinLoader.h
  19. 60 29
      code/BVHLoader.cpp
  20. 24 14
      code/BaseImporter.cpp
  21. 1 1
      code/BaseProcess.cpp
  22. 2 6
      code/BaseProcess.h
  23. 185 0
      code/BlenderCustomData.cpp
  24. 89 0
      code/BlenderCustomData.h
  25. 33 0
      code/BlenderDNA.h
  26. 102 0
      code/BlenderDNA.inl
  27. 67 8
      code/BlenderLoader.cpp
  28. 44 0
      code/BlenderScene.cpp
  29. 79 1
      code/BlenderScene.h
  30. 11 0
      code/BlenderSceneGen.h
  31. 8 0
      code/CMakeLists.txt
  32. 1 3
      code/COBLoader.cpp
  33. 4 3
      code/ColladaHelper.h
  34. 23 25
      code/ColladaLoader.cpp
  35. 14 14
      code/ColladaParser.cpp
  36. 22 9
      code/ConvertToLHProcess.cpp
  37. 1 1
      code/D3MFExporter.cpp
  38. 8 5
      code/D3MFImporter.cpp
  39. 1 1
      code/EmbedTexturesProcess.cpp
  40. 4 4
      code/Exporter.cpp
  41. 252 270
      code/FBXConverter.cpp
  42. 9 5
      code/FBXConverter.h
  43. 1 1
      code/FBXDocumentUtil.cpp
  44. 7 3
      code/FBXExporter.cpp
  45. 3 0
      code/FBXMeshGeometry.cpp
  46. 6 6
      code/FileSystemFilter.h
  47. 4 2
      code/GenFaceNormalsProcess.cpp
  48. 2 1
      code/GenFaceNormalsProcess.h
  49. 10 9
      code/GenVertexNormalsProcess.cpp
  50. 1 0
      code/GenVertexNormalsProcess.h
  51. 20 17
      code/Importer.cpp
  52. 2 2
      code/Importer.h
  53. 1 1
      code/Importer/IFC/IFCGeometry.cpp
  54. 18 0
      code/JoinVerticesProcess.cpp
  55. 19 20
      code/LWOAnimation.h
  56. 7 7
      code/LWOFileData.h
  57. 4 2
      code/LWOMaterial.cpp
  58. 1 1
      code/LimitBoneWeightsProcess.h
  59. 2 2
      code/MD3Loader.h
  60. 7 7
      code/MD5Parser.h
  61. 26 38
      code/MDCFileData.h
  62. 6 4
      code/MDCLoader.cpp
  63. 16 21
      code/MDLFileData.h
  64. 9 37
      code/MMDPmxParser.cpp
  65. 39 26
      code/MaterialSystem.cpp
  66. 89 54
      code/ObjFileImporter.cpp
  67. 5 7
      code/ObjFileMtlImporter.cpp
  68. 10 8
      code/OptimizeMeshes.h
  69. 200 222
      code/PlyLoader.cpp
  70. 19 13
      code/PlyParser.h
  71. 6 3
      code/PostStepRegistry.cpp
  72. 21 20
      code/SMDLoader.h
  73. 37 15
      code/STLLoader.cpp
  74. 12 12
      code/SceneCombiner.cpp
  75. 10 6
      code/ScenePrivate.h
  76. 1 1
      code/SpatialSort.cpp
  77. 1 1
      code/SplitByBoneCountProcess.cpp
  78. 16 17
      code/TextureTransform.h
  79. 21 18
      code/TriangulateProcess.cpp
  80. 2 2
      code/ValidateDataStructure.cpp
  81. 5 3
      code/Version.cpp
  82. 76 42
      code/XFileHelper.h
  83. 6 1
      code/XFileImporter.cpp
  84. 8 3
      code/XFileParser.cpp
  85. 7 0
      code/glTF2Asset.h
  86. 52 4
      code/glTF2Asset.inl
  87. 6 23
      code/glTF2Exporter.cpp
  88. 177 31
      code/glTF2Importer.cpp
  89. 71 12
      code/glTFImporter.cpp
  90. 1 2
      contrib/irrXML/irrArray.h
  91. 6 0
      contrib/openddlparser/code/OpenDDLParser.cpp
  92. 4 5
      include/assimp/BaseImporter.h
  93. 2 3
      include/assimp/ByteSwapper.h
  94. 11 13
      include/assimp/DefaultIOStream.h
  95. 1 2
      include/assimp/DefaultIOSystem.h
  96. 2 2
      include/assimp/IOStream.hpp
  97. 2 5
      include/assimp/IOSystem.hpp
  98. 163 122
      include/assimp/LineSplitter.h
  99. 3 3
      include/assimp/LogStream.hpp
  100. 7 5
      include/assimp/Logger.hpp

+ 9 - 0
.gitignore

@@ -12,6 +12,8 @@ build
 bin/
 lib/
 
+# QtCreator
+CMakeLists.txt.user
 
 # Generated
 assimp.pc
@@ -19,6 +21,7 @@ revision.h
 contrib/zlib/zconf.h
 contrib/zlib/zlib.pc
 include/assimp/config.h
+unit.vcxproj.user
 
 # CMake
 CMakeCache.txt
@@ -85,3 +88,9 @@ lib64/assimp-vc120-mt.exp
 xcuserdata
 
 cmake-build-debug
+install_manifest.txt
+tools/assimp_qt_viewer/moc_glview.cpp
+tools/assimp_qt_viewer/moc_glview.cpp_parameters
+tools/assimp_qt_viewer/moc_mainwindow.cpp
+tools/assimp_qt_viewer/moc_mainwindow.cpp_parameters
+tools/assimp_qt_viewer/ui_mainwindow.h

+ 7 - 0
Build.md

@@ -0,0 +1,7 @@
+# Build instructions
+
+> cmake CMakeLists.txt
+make -j4
+
+##UWP
+See https://stackoverflow.com/questions/40803170/cmake-uwp-using-cmake-to-build-universal-windows-app

+ 45 - 37
CMakeLists.txt

@@ -39,10 +39,12 @@ CMAKE_MINIMUM_REQUIRED( VERSION 2.8 )
 PROJECT( Assimp )
 
 # All supported options ###############################################
+
 OPTION( BUILD_SHARED_LIBS
   "Build package with shared libraries."
   ON
 )
+
 OPTION( BUILD_FRAMEWORK
   "Build package as Mac OS X Framework bundle."
   OFF
@@ -103,6 +105,16 @@ OPTION ( BUILD_DOCS
   "Build documentation using Doxygen."
   OFF
 )
+OPTION( INJECT_DEBUG_POSTFIX
+  "Inject debug postfix in .a/.so lib names"
+  ON
+)
+
+IF (IOS)
+  IF (NOT CMAKE_BUILD_TYPE)
+    SET(CMAKE_BUILD_TYPE "Release")
+  ENDIF (NOT CMAKE_BUILD_TYPE)
+ENDIF (IOS)
 
 # Use subset of Windows.h
 if (WIN32)
@@ -152,7 +164,7 @@ EXECUTE_PROCESS(
 
 # Get the latest abbreviated commit hash of the working branch
 EXECUTE_PROCESS(
-  COMMAND git log -1 --format=%h
+  COMMAND git log -1 --format=%h --no-show-signature
   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
   OUTPUT_VARIABLE GIT_COMMIT_HASH
   OUTPUT_STRIP_TRAILING_WHITESPACE
@@ -198,13 +210,13 @@ ENDIF( UNIX )
 # Grouped compiler settings
 IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
   # hide all not-exported symbols
-  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -std=c++0x")
-  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -std=c++0x ${CMAKE_CXX_FLAGS}")
+  SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}")
   SET(LIBSTDC++_LIBRARIES -lstdc++)
 ELSEIF(MSVC)
   # enable multi-core compilation with MSVC
   ADD_COMPILE_OPTIONS(/MP)
-  IF("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
+  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
     ADD_COMPILE_OPTIONS( /bigobj )
   ENDIF()
   # disable "elements of array '' will be default initialized" warning on MSVC2013
@@ -212,19 +224,26 @@ ELSEIF(MSVC)
     ADD_COMPILE_OPTIONS(/wd4351)
   ENDIF()
 ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
-  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" )
-  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+  SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 ${CMAKE_CXX_FLAGS}" )
+  SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}")
 ELSEIF( CMAKE_COMPILER_IS_MINGW )
-  SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wno-long-long -std=c++11" )
-  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+  SET( CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}" )
+  SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS} ")
   ADD_DEFINITIONS( -U__STRICT_ANSI__ )
 ENDIF()
 
-IF (IOS)
-  SET(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -fembed-bitcode -O3")
+IF ( IOS )
+
+IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og")
+ELSE()
+  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
   SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
 ENDIF()
 
+ENDIF( IOS )
+
 IF (ASSIMP_COVERALLS)
   MESSAGE(STATUS "Coveralls enabled")
   INCLUDE(Coveralls)
@@ -320,6 +339,8 @@ IF( NOT ZLIB_FOUND )
   SET(ZLIB_FOUND 1)
   SET(ZLIB_LIBRARIES zlibstatic)
   SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib)
+  # need to ensure we don't link with system zlib or minizip as well.
+  SET(ASSIMP_BUILD_MINIZIP 1)
 ELSE(NOT ZLIB_FOUND)
   ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB)
   SET(ZLIB_LIBRARIES_LINKED -lz)
@@ -327,7 +348,17 @@ ENDIF(NOT ZLIB_FOUND)
 INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR})
 
 # Search for unzip
-use_pkgconfig(UNZIP minizip)
+IF ( NOT IOS )
+  IF( NOT ASSIMP_BUILD_MINIZIP )
+	  use_pkgconfig(UNZIP minizip)
+  ENDIF( NOT ASSIMP_BUILD_MINIZIP )
+ELSE ( NOT IOS )
+	IF(NOT BUILD_SHARED_LIBS)
+    IF( NOT ASSIMP_BUILD_MINIZIP )
+		  use_pkgconfig(UNZIP minizip)
+    ENDIF( NOT ASSIMP_BUILD_MINIZIP )
+	ENDIF (NOT BUILD_SHARED_LIBS)
+ENDIF ( NOT IOS )
 
 IF ( ASSIMP_NO_EXPORT )
   ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT)
@@ -412,32 +443,9 @@ IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
   ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY )
 
   ADD_SUBDIRECTORY( tools/assimp_cmd/ )
-
-  # Check dependencies for assimp_qt_viewer.
-  # Why here? Maybe user do not want Qt viewer and have no Qt.
-  # Why assimp_qt_viewer/CMakeLists.txt still contain similar check?
-  # Because viewer can be build independently of Assimp.
-  FIND_PACKAGE(Qt5Widgets QUIET)
-  FIND_PACKAGE(DevIL QUIET)
-  FIND_PACKAGE(OpenGL QUIET)
-  IF ( Qt5Widgets_FOUND AND IL_FOUND AND OPENGL_FOUND)
-    ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
-  ELSE()
-    SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "")
-    IF (NOT Qt5_FOUND)
-      SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} Qt5")
-    ENDIF (NOT Qt5_FOUND)
-
-    IF (NOT IL_FOUND)
-      SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} DevIL")
-    ENDIF (NOT IL_FOUND)
-
-    IF (NOT OPENGL_FOUND)
-      SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} OpengGL")
-    ENDIF (NOT OPENGL_FOUND)
-
-    MESSAGE (WARNING "Build of assimp_qt_viewer is disabled. Unsatisfied dendencies: ${ASSIMP_QT_VIEWER_DEPENDENCIES}")
-  ENDIF ( Qt5Widgets_FOUND AND IL_FOUND AND OPENGL_FOUND)
+IF (NOT IOS)
+  ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
+ENDIF (NOT IOS)
 ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
 
 IF ( ASSIMP_BUILD_SAMPLES)

+ 9 - 10
CONTRIBUTING.md

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

+ 3 - 0
INSTALL

@@ -42,3 +42,6 @@ For Windows:
 1. Open a command prompt
 2. cmake CMakeLists.txt
 2. Open your default IDE and build it
+
+For iOS:
+Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS

+ 2 - 0
Readme.md

@@ -30,6 +30,8 @@ One-off donations via PayPal:
 
 Please check our Wiki as well: https://github.com/assimp/assimp/wiki
 
+If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
+
 #### Supported file formats ####
 
 __Importers__:

+ 4 - 0
appveyor.yml

@@ -32,6 +32,9 @@ install:
   - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017
   - if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% Win64
   - cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%"
+  - set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5"
+  - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/5/7/b/57b2947c-7221-4f33-b35e-2fc78cb10df4/vc_redist.x64.exe -OutFile .\packaging\windows-innosetup\vc_redist.x64.exe
+  - ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/1/d/8/1d8137db-b5bb-4925-8c5d-927424a2e4de/vc_redist.x86.exe -OutFile .\packaging\windows-innosetup\vc_redist.x86.exe
   
 cache:
   - code\assimp.dir\%CONFIGURATION%
@@ -50,6 +53,7 @@ build:
   project: Assimp.sln
   
 after_build:
+  - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" iscc packaging\windows-innosetup\script.iss
   - 7z a assimp.7z bin\%CONFIGURATION%\* lib\%CONFIGURATION%\*
 
 test_script:

+ 5 - 3
code/3DSConverter.cpp

@@ -204,8 +204,9 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
         mat.AddProperty<ai_real>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
 
     // Setup the texture mapping mode
-    mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
-    mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
+    int mapMode = static_cast<int>(texture.mMapMode);
+    mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
+    mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
 
     // Mirroring - double the scaling values
     // FIXME: this is not really correct ...
@@ -313,7 +314,8 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
         case D3DS::Discreet3DS::Blinn :
             eShading = aiShadingMode_Blinn; break;
     }
-    mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL);
+    int eShading_ = static_cast<int>(eShading);
+    mat.AddProperty<int>(&eShading_, 1, AI_MATKEY_SHADING_MODEL);
 
     // DIFFUSE texture
     if( oldMat.sTexDiffuse.mMapName.length() > 0)

+ 14 - 16
code/3DSHelper.h

@@ -66,7 +66,7 @@ namespace D3DS  {
 */
 class Discreet3DS {
 private:
-    Discreet3DS() {
+    Discreet3DS() AI_NO_EXCEPT {
         // empty
     }
 
@@ -328,19 +328,17 @@ struct Face : public FaceWithSmoothingGroup
 
 // ---------------------------------------------------------------------------
 /** Helper structure representing a texture */
-struct Texture
-{
+struct Texture {
     //! Default constructor
-    Texture()
-        : mOffsetU  (0.0)
-        , mOffsetV  (0.0)
-        , mScaleU   (1.0)
-        , mScaleV   (1.0)
-        , mRotation (0.0)
-        , mMapMode  (aiTextureMapMode_Wrap)
-        , bPrivate()
-        , iUVSrc    (0)
-    {
+    Texture() AI_NO_EXCEPT
+    : mOffsetU  (0.0)
+    , mOffsetV  (0.0)
+    , mScaleU   (1.0)
+    , mScaleV   (1.0)
+    , mRotation (0.0)
+    , mMapMode  (aiTextureMapMode_Wrap)
+    , bPrivate()
+    , iUVSrc    (0) {
         mTextureBlend = get_qnan();
     }
 
@@ -394,7 +392,7 @@ struct Material
 
 
     //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
-    Material(Material &&other)
+    Material(Material &&other) AI_NO_EXCEPT
     : mName(std::move(other.mName))
     , mDiffuse(std::move(other.mDiffuse))
     , mSpecularExponent(std::move(other.mSpecularExponent))
@@ -418,7 +416,7 @@ struct Material
     }
 
 
-    Material &operator=(Material &&other) {
+    Material &operator=(Material &&other) AI_NO_EXCEPT {
         if (this == &other) {
             return *this;
         }
@@ -447,7 +445,7 @@ struct Material
     }
 
 
-    ~Material() {}
+    virtual ~Material() {}
 
 
     //! Name of the material

+ 2 - 2
code/3DSLoader.cpp

@@ -71,7 +71,7 @@ static const aiImporterDesc desc = {
     0,
     0,
     0,
-    "3ds prj 3DS PRJ"
+	"3ds prj"
 };
 
 
@@ -127,7 +127,7 @@ Discreet3DSImporter::~Discreet3DSImporter() {
 // Returns whether the class can handle the format of the given file.
 bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
     std::string extension = GetExtension(pFile);
-    if(extension == "3ds" || extension == "3DS" || extension == "prj"|| extension == "PRJ" ) {
+	if(extension == "3ds" || extension == "prj") {
         return true;
     }
 

+ 64 - 184
code/AMFImporter.hpp

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

+ 59 - 41
code/AMFImporter_Material.cpp

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

+ 62 - 123
code/AMFImporter_Node.hpp

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

+ 46 - 67
code/ASEParser.h

@@ -71,21 +71,20 @@ struct Material : public D3DS::Material
     //! Default constructor has been deleted
     Material() = delete;
 
-
     //! Constructor with explicit name
     explicit Material(const std::string &name)
     : D3DS::Material(name)
     , pcInstance(NULL)
-    , bNeed (false)
-    {}
-
+    , bNeed (false) {
+        // empty
+    }
 
     Material(const Material &other)            = default;
     Material &operator=(const Material &other) = default;
 
 
     //! Move constructor. This is explicitly written because MSVC doesn't support defaulting it
-    Material(Material &&other)
+    Material(Material &&other) AI_NO_EXCEPT
     : D3DS::Material(std::move(other))
     , avSubMaterials(std::move(other.avSubMaterials))
     , pcInstance(std::move(other.pcInstance))
@@ -95,7 +94,7 @@ struct Material : public D3DS::Material
     }
 
 
-    Material &operator=(Material &&other) {
+    Material &operator=(Material &&other) AI_NO_EXCEPT {
         if (this == &other) {
             return *this;
         }
@@ -127,19 +126,12 @@ struct Material : public D3DS::Material
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file face */
-struct Face : public FaceWithSmoothingGroup
-{
+struct Face : public FaceWithSmoothingGroup {
     //! Default constructor. Initializes everything with 0
-    Face()
-    {
-        mColorIndices[0] = mColorIndices[1] = mColorIndices[2] = 0;
-        for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i)
-        {
-            amUVIndices[i][0] = amUVIndices[i][1] = amUVIndices[i][2] = 0;
-        }
-
-        iMaterial = DEFAULT_MATINDEX;
-        iFace = 0;
+    Face() AI_NO_EXCEPT
+    : iMaterial(DEFAULT_MATINDEX)
+    , iFace(0) {
+        // empty
     }
 
     //! special value to indicate that no material index has
@@ -147,8 +139,6 @@ struct Face : public FaceWithSmoothingGroup
     //! will replace this value later.
     static const unsigned int DEFAULT_MATINDEX = 0xFFFFFFFF;
 
-
-
     //! Indices into each list of texture coordinates
     unsigned int amUVIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS][3];
 
@@ -166,15 +156,15 @@ struct Face : public FaceWithSmoothingGroup
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file bone */
-struct Bone
-{
+struct Bone {
     //! Constructor
     Bone() = delete;
 
     //! Construction from an existing name
     explicit Bone( const std::string& name)
-        :   mName   (name)
-    {}
+    : mName(name) {
+        // empty
+    }
 
     //! Name of the bone
     std::string mName;
@@ -182,29 +172,22 @@ struct Bone
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file bone vertex */
-struct BoneVertex
-{
+struct BoneVertex {
     //! Bone and corresponding vertex weight.
     //! -1 for unrequired bones ....
     std::vector<std::pair<int,float> > mBoneWeights;
-
-    //! Position of the bone vertex.
-    //! MUST be identical to the vertex position
-    //aiVector3D mPosition;
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file animation */
-struct Animation
-{
-    enum Type
-    {
+struct Animation {
+    enum Type {
         TRACK   = 0x0,
         BEZIER  = 0x1,
         TCB     = 0x2
     } mRotationType, mScalingType, mPositionType;
 
-    Animation()
+    Animation() AI_NO_EXCEPT
         :   mRotationType   (TRACK)
         ,   mScalingType    (TRACK)
         ,   mPositionType   (TRACK)
@@ -218,19 +201,16 @@ struct Animation
 
     //! List of track scaling keyframes
     std::vector< aiVectorKey > akeyScaling;
-
 };
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent the inheritance information of an ASE node */
-struct InheritanceInfo
-{
+struct InheritanceInfo {
     //! Default constructor
-    InheritanceInfo()
-    {
-        // set the inheritance flag for all axes by default to true
-        for (unsigned int i = 0; i < 3;++i)
+    InheritanceInfo() AI_NO_EXCEPT {
+        for ( size_t i=0; i<3; ++i ) {
             abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true;
+        }
     }
 
     //! Inherit the parent's position?, axis order is x,y,z
@@ -245,17 +225,19 @@ struct InheritanceInfo
 
 // ---------------------------------------------------------------------------
 /** Represents an ASE file node. Base class for mesh, light and cameras */
-struct BaseNode
-{
-    enum Type {Light, Camera, Mesh, Dummy} mType;
-
+struct BaseNode {
+    enum Type {
+        Light, 
+        Camera, 
+        Mesh, 
+        Dummy
+    } mType;
 
     //! Construction from an existing name
     BaseNode(Type _mType, const std::string &name)
     : mType         (_mType)
     , mName         (name)
-    , mProcessed    (false)
-    {
+    , mProcessed    (false) {
         // Set mTargetPosition to qnan
         const ai_real qnan = get_qnan();
         mTargetPosition.x = qnan;
@@ -291,24 +273,23 @@ struct BaseNode
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE file mesh */
-struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode
-{
+struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode {
     //! Default constructor has been deleted
     Mesh() = delete;
 
-
     //! Construction from an existing name
     explicit Mesh(const std::string &name)
-    : BaseNode  (BaseNode::Mesh, name)
+    : BaseNode( BaseNode::Mesh, name )
+    , mVertexColors()
+    , mBoneVertices()
+    , mBones()
     , iMaterialIndex(Face::DEFAULT_MATINDEX)
-    , bSkip     (false)
-    {
-        // use 2 texture vertex components by default
-        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
+    , bSkip     (false) {
+        for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) {
             this->mNumUVComponents[c] = 2;
+        }
     }
 
-
     //! List of all texture coordinate sets
     std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 
@@ -396,12 +377,11 @@ struct Camera : public BaseNode
 
 // ---------------------------------------------------------------------------
 /** Helper structure to represent an ASE helper object (dummy) */
-struct Dummy : public BaseNode
-{
+struct Dummy : public BaseNode {
     //! Constructor
-    Dummy()
-        : BaseNode  (BaseNode::Dummy, "DUMMY")
-    {
+    Dummy() AI_NO_EXCEPT
+    : BaseNode  (BaseNode::Dummy, "DUMMY") {
+        // empty
     }
 };
 
@@ -416,12 +396,11 @@ struct Dummy : public BaseNode
 // -------------------------------------------------------------------------------
 /** \brief Class to parse ASE files
  */
-class Parser
-{
-
+class Parser {
 private:
-
-    Parser() {}
+    Parser() AI_NO_EXCEPT {
+        // empty
+    }
 
 public:
 

+ 524 - 513
code/AssbinExporter.cpp

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

+ 8 - 1
code/AssbinExporter.h

@@ -46,6 +46,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_ASSBINEXPORTER_H_INC
 #define AI_ASSBINEXPORTER_H_INC
 
+#include <assimp/defs.h>
+
 // nothing really needed here - reserved for future use like properties
+namespace Assimp {
+
+void ASSIMP_API ExportSceneAssbin(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/);
+
+}
 
-#endif
+#endif // AI_ASSBINEXPORTER_H_INC

+ 109 - 127
code/AssbinLoader.cpp

@@ -79,16 +79,17 @@ static const aiImporterDesc desc = {
     "assbin"
 };
 
-const aiImporterDesc* AssbinImporter::GetInfo() const
-{
+// -----------------------------------------------------------------------------------
+const aiImporterDesc* AssbinImporter::GetInfo() const {
     return &desc;
 }
 
-bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const
-{
+// -----------------------------------------------------------------------------------
+bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool /*checkSig*/ ) const {
     IOStream * in = pIOHandler->Open(pFile);
-    if (!in)
+    if (nullptr == in) {
         return false;
+    }
 
     char s[32];
     in->Read( s, sizeof(char), 32 );
@@ -98,17 +99,17 @@ bool AssbinImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bo
     return strncmp( s, "ASSIMP.binary-dump.", 19 ) == 0;
 }
 
+// -----------------------------------------------------------------------------------
 template <typename T>
-T Read(IOStream * stream)
-{
+T Read(IOStream * stream) {
     T t;
     stream->Read( &t, sizeof(T), 1 );
     return t;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiVector3D Read<aiVector3D>(IOStream * stream)
-{
+aiVector3D Read<aiVector3D>(IOStream * stream) {
     aiVector3D v;
     v.x = Read<float>(stream);
     v.y = Read<float>(stream);
@@ -116,9 +117,9 @@ aiVector3D Read<aiVector3D>(IOStream * stream)
     return v;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiColor4D Read<aiColor4D>(IOStream * stream)
-{
+aiColor4D Read<aiColor4D>(IOStream * stream) {
     aiColor4D c;
     c.r = Read<float>(stream);
     c.g = Read<float>(stream);
@@ -127,9 +128,9 @@ aiColor4D Read<aiColor4D>(IOStream * stream)
     return c;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiQuaternion Read<aiQuaternion>(IOStream * stream)
-{
+aiQuaternion Read<aiQuaternion>(IOStream * stream) {
     aiQuaternion v;
     v.w = Read<float>(stream);
     v.x = Read<float>(stream);
@@ -138,9 +139,9 @@ aiQuaternion Read<aiQuaternion>(IOStream * stream)
     return v;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiString Read<aiString>(IOStream * stream)
-{
+aiString Read<aiString>(IOStream * stream) {
     aiString s;
     stream->Read(&s.length,4,1);
     stream->Read(s.data,s.length,1);
@@ -148,18 +149,18 @@ aiString Read<aiString>(IOStream * stream)
     return s;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiVertexWeight Read<aiVertexWeight>(IOStream * stream)
-{
+aiVertexWeight Read<aiVertexWeight>(IOStream * stream) {
     aiVertexWeight w;
     w.mVertexId = Read<unsigned int>(stream);
     w.mWeight = Read<float>(stream);
     return w;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream)
-{
+aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream) {
     aiMatrix4x4 m;
     for (unsigned int i = 0; i < 4;++i) {
         for (unsigned int i2 = 0; i2 < 4;++i2) {
@@ -169,36 +170,43 @@ aiMatrix4x4 Read<aiMatrix4x4>(IOStream * stream)
     return m;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiVectorKey Read<aiVectorKey>(IOStream * stream)
-{
+aiVectorKey Read<aiVectorKey>(IOStream * stream) {
     aiVectorKey v;
     v.mTime = Read<double>(stream);
     v.mValue = Read<aiVector3D>(stream);
     return v;
 }
 
+// -----------------------------------------------------------------------------------
 template <>
-aiQuatKey Read<aiQuatKey>(IOStream * stream)
-{
+aiQuatKey Read<aiQuatKey>(IOStream * stream) {
     aiQuatKey v;
     v.mTime = Read<double>(stream);
     v.mValue = Read<aiQuaternion>(stream);
     return v;
 }
 
+// -----------------------------------------------------------------------------------
 template <typename T>
-void ReadArray(IOStream * stream, T * out, unsigned int size)
-{
-    for (unsigned int i=0; i<size; i++) out[i] = Read<T>(stream);
+void ReadArray( IOStream *stream, T * out, unsigned int size) {
+    ai_assert( nullptr != stream );
+    ai_assert( nullptr != out );
+
+    for (unsigned int i=0; i<size; i++) {
+        out[i] = Read<T>(stream);
+    }
 }
 
-template <typename T> void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n )
-{
+// -----------------------------------------------------------------------------------
+template <typename T>
+void ReadBounds( IOStream * stream, T* /*p*/, unsigned int n ) {
     // not sure what to do here, the data isn't really useful.
     stream->Seek( sizeof(T) * n, aiOrigin_CUR );
 }
 
+// -----------------------------------------------------------------------------------
 void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* parent ) {
     uint32_t chunkID = Read<uint32_t>(stream);
     (void)(chunkID);
@@ -273,8 +281,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);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIBONE);
@@ -286,20 +293,22 @@ void AssbinImporter::ReadBinaryBone( IOStream * stream, aiBone* b )
 
     // for the moment we write dumb min/max values for the bones, too.
     // maybe I'll add a better, hash-like solution later
-    if (shortened)
-    {
+    if (shortened) {
         ReadBounds(stream,b->mWeights,b->mNumWeights);
-    } // else write as usual
-    else
-    {
+    } else {
+        // else write as usual
         b->mWeights = new aiVertexWeight[b->mNumWeights];
         ReadArray<aiVertexWeight>(stream,b->mWeights,b->mNumWeights);
     }
 }
 
+// -----------------------------------------------------------------------------------
+static bool fitsIntoUI16(unsigned int mNumVertices) {
+    return ( mNumVertices < (1u<<16) );
+}
 
-void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
-{
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh ) {
     uint32_t chunkID = Read<uint32_t>(stream);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIMESH);
@@ -314,70 +323,61 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
     // first of all, write bits for all existent vertex components
     unsigned int c = Read<unsigned int>(stream);
 
-    if (c & ASSBIN_MESH_HAS_POSITIONS)
-    {
+    if (c & ASSBIN_MESH_HAS_POSITIONS) {
         if (shortened) {
             ReadBounds(stream,mesh->mVertices,mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mVertices = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mVertices,mesh->mNumVertices);
         }
     }
-    if (c & ASSBIN_MESH_HAS_NORMALS)
-    {
+    if (c & ASSBIN_MESH_HAS_NORMALS) {
         if (shortened) {
             ReadBounds(stream,mesh->mNormals,mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mNormals = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mNormals,mesh->mNumVertices);
         }
     }
-    if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS)
-    {
+    if (c & ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS) {
         if (shortened) {
             ReadBounds(stream,mesh->mTangents,mesh->mNumVertices);
             ReadBounds(stream,mesh->mBitangents,mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mTangents = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mTangents,mesh->mNumVertices);
             mesh->mBitangents = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mBitangents,mesh->mNumVertices);
         }
     }
-    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n)
-    {
-        if (!(c & ASSBIN_MESH_HAS_COLOR(n)))
+    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_COLOR_SETS;++n) {
+        if (!(c & ASSBIN_MESH_HAS_COLOR(n))) {
             break;
+        }
 
-        if (shortened)
-        {
+        if (shortened) {
             ReadBounds(stream,mesh->mColors[n],mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mColors[n] = new aiColor4D[mesh->mNumVertices];
             ReadArray<aiColor4D>(stream,mesh->mColors[n],mesh->mNumVertices);
         }
     }
-    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
-    {
-        if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n)))
+    for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) {
+        if (!(c & ASSBIN_MESH_HAS_TEXCOORD(n))) {
             break;
+        }
 
         // write number of UV components
         mesh->mNumUVComponents[n] = Read<unsigned int>(stream);
 
         if (shortened) {
             ReadBounds(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices];
             ReadArray<aiVector3D>(stream,mesh->mTextureCoords[n],mesh->mNumVertices);
         }
@@ -389,9 +389,8 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
     // using Assimp's standard hashing function.
     if (shortened) {
         Read<unsigned int>(stream);
-    }
-    else // else write as usual
-    {
+    } else  {
+        // else write as usual
         // if there are less than 2^16 vertices, we can simply use 16 bit integers ...
         mesh->mFaces = new aiFace[mesh->mNumFaces];
         for (unsigned int i = 0; i < mesh->mNumFaces;++i) {
@@ -402,12 +401,10 @@ void AssbinImporter::ReadBinaryMesh( IOStream * stream, aiMesh* mesh )
             f.mIndices = new unsigned int[f.mNumIndices];
 
             for (unsigned int a = 0; a < f.mNumIndices;++a) {
-                if (mesh->mNumVertices < (1u<<16))
-                {
+                // Check if unsigned  short ( 16 bit  ) are big enought for the indices
+                if ( fitsIntoUI16( mesh->mNumVertices ) ) {
                     f.mIndices[a] = Read<uint16_t>(stream);
-                }
-                else
-                {
+                } else {
                     f.mIndices[a] = Read<unsigned int>(stream);
                 }
             }
@@ -424,8 +421,8 @@ 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);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIALPROPERTY);
@@ -442,8 +439,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);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIMATERIAL);
@@ -465,8 +461,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);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AINODEANIM);
@@ -493,9 +488,8 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
         if (shortened) {
             ReadBounds(stream,nd->mRotationKeys,nd->mNumRotationKeys);
 
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             nd->mRotationKeys = new aiQuatKey[nd->mNumRotationKeys];
             ReadArray<aiQuatKey>(stream,nd->mRotationKeys,nd->mNumRotationKeys);
         }
@@ -504,19 +498,16 @@ void AssbinImporter::ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd)
         if (shortened) {
             ReadBounds(stream,nd->mScalingKeys,nd->mNumScalingKeys);
 
-        } // else write as usual
-        else
-        {
+        }  else {
+            // else write as usual
             nd->mScalingKeys = new aiVectorKey[nd->mNumScalingKeys];
             ReadArray<aiVectorKey>(stream,nd->mScalingKeys,nd->mNumScalingKeys);
         }
     }
 }
 
-
 // -----------------------------------------------------------------------------------
-void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
-{
+void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim ) {
     uint32_t chunkID = Read<uint32_t>(stream);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AIANIMATION);
@@ -527,8 +518,7 @@ void AssbinImporter::ReadBinaryAnim( IOStream * stream, aiAnimation* anim )
     anim->mTicksPerSecond = Read<double> (stream);
     anim->mNumChannels = Read<unsigned int>(stream);
 
-    if (anim->mNumChannels)
-    {
+    if (anim->mNumChannels) {
         anim->mChannels = new aiNodeAnim*[ anim->mNumChannels ];
         for (unsigned int a = 0; a < anim->mNumChannels;++a) {
             anim->mChannels[a] = new aiNodeAnim();
@@ -537,8 +527,8 @@ 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);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AITEXTURE);
@@ -552,18 +542,15 @@ void AssbinImporter::ReadBinaryTexture(IOStream * stream, aiTexture* tex)
         if (!tex->mHeight) {
             tex->pcData = new aiTexel[ tex->mWidth ];
             stream->Read(tex->pcData,1,tex->mWidth);
-        }
-        else {
+        } else {
             tex->pcData = new aiTexel[ tex->mWidth*tex->mHeight ];
             stream->Read(tex->pcData,1,tex->mWidth*tex->mHeight*4);
         }
     }
-
 }
 
 // -----------------------------------------------------------------------------------
-void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
-{
+void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l ) {
     uint32_t chunkID = Read<uint32_t>(stream);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AILIGHT);
@@ -586,12 +573,10 @@ void AssbinImporter::ReadBinaryLight( IOStream * stream, aiLight* l )
         l->mAngleInnerCone = Read<float>(stream);
         l->mAngleOuterCone = Read<float>(stream);
     }
-
 }
 
 // -----------------------------------------------------------------------------------
-void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
-{
+void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam ) {
     uint32_t chunkID = Read<uint32_t>(stream);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AICAMERA);
@@ -607,8 +592,8 @@ void AssbinImporter::ReadBinaryCamera( IOStream * stream, aiCamera* cam )
     cam->mAspect = Read<float>(stream);
 }
 
-void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
-{
+// -----------------------------------------------------------------------------------
+void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) {
     uint32_t chunkID = Read<uint32_t>(stream);
     (void)(chunkID);
     ai_assert(chunkID == ASSBIN_CHUNK_AISCENE);
@@ -623,12 +608,11 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     scene->mNumCameras    = Read<unsigned int>(stream);
 
     // Read node graph
-    scene->mRootNode = new aiNode[1];
+    //scene->mRootNode = new aiNode[1];
     ReadBinaryNode( stream, &scene->mRootNode, (aiNode*)NULL );
 
     // Read all meshes
-    if (scene->mNumMeshes)
-    {
+    if (scene->mNumMeshes) {
         scene->mMeshes = new aiMesh*[scene->mNumMeshes];
         for (unsigned int i = 0; i < scene->mNumMeshes;++i) {
             scene->mMeshes[i] = new aiMesh();
@@ -637,8 +621,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read materials
-    if (scene->mNumMaterials)
-    {
+    if (scene->mNumMaterials) {
         scene->mMaterials = new aiMaterial*[scene->mNumMaterials];
         for (unsigned int i = 0; i< scene->mNumMaterials; ++i) {
             scene->mMaterials[i] = new aiMaterial();
@@ -647,8 +630,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read all animations
-    if (scene->mNumAnimations)
-    {
+    if (scene->mNumAnimations) {
         scene->mAnimations = new aiAnimation*[scene->mNumAnimations];
         for (unsigned int i = 0; i < scene->mNumAnimations;++i) {
             scene->mAnimations[i] = new aiAnimation();
@@ -657,8 +639,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read all textures
-    if (scene->mNumTextures)
-    {
+    if (scene->mNumTextures) {
         scene->mTextures = new aiTexture*[scene->mNumTextures];
         for (unsigned int i = 0; i < scene->mNumTextures;++i) {
             scene->mTextures[i] = new aiTexture();
@@ -667,8 +648,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read lights
-    if (scene->mNumLights)
-    {
+    if (scene->mNumLights) {
         scene->mLights = new aiLight*[scene->mNumLights];
         for (unsigned int i = 0; i < scene->mNumLights;++i) {
             scene->mLights[i] = new aiLight();
@@ -677,8 +657,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
     }
 
     // Read cameras
-    if (scene->mNumCameras)
-    {
+    if (scene->mNumCameras) {
         scene->mCameras = new aiCamera*[scene->mNumCameras];
         for (unsigned int i = 0; i < scene->mNumCameras;++i) {
             scene->mCameras[i] = new aiCamera();
@@ -688,16 +667,22 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene )
 
 }
 
-void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler )
-{
+// -----------------------------------------------------------------------------------
+void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ) {
     IOStream * stream = pIOHandler->Open(pFile,"rb");
-    if (!stream)
+    if (nullptr == stream) {
         return;
+    }
 
-    stream->Seek( 44, aiOrigin_CUR ); // signature
+    // signature
+    stream->Seek( 44, aiOrigin_CUR ); 
+
+    unsigned int versionMajor = Read<unsigned int>(stream);
+    unsigned int versionMinor = Read<unsigned int>(stream);
+    if (versionMinor != ASSBIN_VERSION_MINOR || versionMajor != ASSBIN_VERSION_MAJOR) {
+        throw DeadlyImportError( "Invalid version, data format not compatible!" );
+    }
 
-    /*unsigned int versionMajor =*/ Read<unsigned int>(stream);
-    /*unsigned int versionMinor =*/ Read<unsigned int>(stream);
     /*unsigned int versionRevision =*/ Read<unsigned int>(stream);
     /*unsigned int compileFlags =*/ Read<unsigned int>(stream);
 
@@ -711,8 +696,7 @@ void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
     stream->Seek( 128, aiOrigin_CUR ); // options
     stream->Seek( 64, aiOrigin_CUR ); // padding
 
-    if (compressed)
-    {
+    if (compressed) {
         uLongf uncompressedSize = Read<uint32_t>(stream);
         uLongf compressedSize = static_cast<uLongf>(stream->FileSize() - stream->Tell());
 
@@ -729,9 +713,7 @@ void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
 
         delete[] uncompressedData;
         delete[] compressedData;
-    }
-    else
-    {
+    } else {
         ReadBinaryScene(stream,pScene);
     }
 

+ 22 - 21
code/AssbinLoader.h

@@ -70,32 +70,33 @@ namespace Assimp    {
 class AssbinImporter : public BaseImporter
 {
 private:
-  bool shortened;
-  bool compressed;
+    bool shortened;
+    bool compressed;
 
 public:
-  virtual bool CanRead(
-    const std::string& pFile,
-    IOSystem* pIOHandler,
-    bool checkSig
+    virtual bool CanRead(
+        const std::string& pFile,
+        IOSystem* pIOHandler,
+        bool checkSig
     ) const;
-  virtual const aiImporterDesc* GetInfo() const;
-  virtual void InternReadFile(
+    virtual const aiImporterDesc* GetInfo() const;
+    virtual void InternReadFile(
     const std::string& pFile,
-    aiScene* pScene,
-    IOSystem* pIOHandler
+        aiScene* pScene,
+        IOSystem* pIOHandler
     );
-  void ReadBinaryScene( IOStream * stream, aiScene* pScene );
-  void ReadBinaryNode( IOStream * stream, aiNode** mRootNode, aiNode* parent );
-  void ReadBinaryMesh( IOStream * stream, aiMesh* mesh );
-  void ReadBinaryBone( IOStream * stream, aiBone* bone );
-  void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat);
-  void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop);
-  void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd);
-  void ReadBinaryAnim( IOStream * stream, aiAnimation* anim );
-  void ReadBinaryTexture(IOStream * stream, aiTexture* tex);
-  void ReadBinaryLight( IOStream * stream, aiLight* l );
-  void ReadBinaryCamera( IOStream * stream, aiCamera* cam );
+    void ReadHeader();
+    void ReadBinaryScene( IOStream * stream, aiScene* pScene );
+    void ReadBinaryNode( IOStream * stream, aiNode** mRootNode, aiNode* parent );
+    void ReadBinaryMesh( IOStream * stream, aiMesh* mesh );
+    void ReadBinaryBone( IOStream * stream, aiBone* bone );
+    void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat);
+    void ReadBinaryMaterialProperty(IOStream * stream, aiMaterialProperty* prop);
+    void ReadBinaryNodeAnim(IOStream * stream, aiNodeAnim* nd);
+    void ReadBinaryAnim( IOStream * stream, aiAnimation* anim );
+    void ReadBinaryTexture(IOStream * stream, aiTexture* tex);
+    void ReadBinaryLight( IOStream * stream, aiLight* l );
+    void ReadBinaryCamera( IOStream * stream, aiCamera* cam );
 };
 
 } // end of namespace Assimp

+ 60 - 29
code/BVHLoader.cpp

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/IOSystem.hpp>
 #include <assimp/scene.h>
 #include <assimp/importerdesc.h>
+#include <map>
 
 using namespace Assimp;
 using namespace Assimp::Formatter;
@@ -461,6 +462,13 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
         aiNodeAnim* nodeAnim = new aiNodeAnim;
         anim->mChannels[a] = nodeAnim;
         nodeAnim->mNodeName.Set( nodeName);
+		std::map<BVHLoader::ChannelType, int> channelMap;
+
+		//Build map of channels 
+		for (unsigned int channel = 0; channel < node.mChannels.size(); ++channel)
+		{
+			channelMap[node.mChannels[channel]] = channel;
+		}
 
         // translational part, if given
         if( node.mChannels.size() == 6)
@@ -472,16 +480,32 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
             {
                 poskey->mTime = double( fr);
 
-                // Now compute all translations in the right order
-                for( unsigned int channel = 0; channel < 3; ++channel)
+                // Now compute all translations 
+                for(BVHLoader::ChannelType channel = Channel_PositionX; channel <= Channel_PositionZ; channel = (BVHLoader::ChannelType)(channel +1))
                 {
-                    switch( node.mChannels[channel])
-                    {
-                    case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
-                    case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
-                    case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break;
-                    default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
-                    }
+					//Find channel in node
+					std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
+
+					if (mapIter == channelMap.end())
+						throw DeadlyImportError("Missing position channel in node " + nodeName);
+					else {
+						int channelIdx = mapIter->second;
+						switch (channel) {
+						    case Channel_PositionX: 
+                                poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; 
+                                break;
+						    case Channel_PositionY: 
+                                poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; 
+                                break;
+						    case Channel_PositionZ: 
+                                poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channelIdx]; 
+                                break;
+                                
+                            default:
+                                break;
+						}
+
+					}
                 }
                 ++poskey;
             }
@@ -497,12 +521,6 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
 
         // rotation part. Always present. First find value offsets
         {
-            unsigned int rotOffset  = 0;
-            if( node.mChannels.size() == 6)
-            {
-                // Offset all further calculations
-                rotOffset = 3;
-            }
 
             // Then create the number of rotation keys
             nodeAnim->mNumRotationKeys = mAnimNumFrames;
@@ -512,20 +530,33 @@ void BVHLoader::CreateAnimation( aiScene* pScene)
             {
                 aiMatrix4x4 temp;
                 aiMatrix3x3 rotMatrix;
-
-                for( unsigned int channel = 0; channel < 3; ++channel)
-                {
-                    // translate ZXY euler angels into a quaternion
-                    const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f;
-
-                    // Compute rotation transformations in the right order
-                    switch (node.mChannels[rotOffset+channel])
-                    {
-                    case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
-                    case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp);  break;
-                    case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break;
-                    default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName );
-                    }
+				for (BVHLoader::ChannelType channel = Channel_RotationX; channel <= Channel_RotationZ; channel = (BVHLoader::ChannelType)(channel + 1))
+				{
+					//Find channel in node
+					std::map<BVHLoader::ChannelType, int>::iterator mapIter = channelMap.find(channel);
+
+					if (mapIter == channelMap.end())
+						throw DeadlyImportError("Missing rotation channel in node " + nodeName);
+					else {
+						int channelIdx = mapIter->second;
+						// translate ZXY euler angels into a quaternion
+						const float angle = node.mChannelValues[fr * node.mChannels.size() + channelIdx] * float(AI_MATH_PI) / 180.0f;
+
+						// Compute rotation transformations in the right order
+						switch (channel)
+						{
+							case Channel_RotationX: 
+                                aiMatrix4x4::RotationX(angle, temp); rotMatrix *= aiMatrix3x3(temp); 
+                                break;
+							case Channel_RotationY: 
+                                aiMatrix4x4::RotationY(angle, temp); rotMatrix *= aiMatrix3x3(temp);  
+                                break;
+							case Channel_RotationZ: aiMatrix4x4::RotationZ(angle, temp); rotMatrix *= aiMatrix3x3(temp); 
+                                break;
+                            default:
+                                break;
+						}
+					}
                 }
 
                 rotkey->mTime = double( fr);

+ 24 - 14
code/BaseImporter.cpp

@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include <assimp/BaseImporter.h>
+#include <assimp/ParsingUtils.h>
 #include "FileSystemFilter.h"
 #include "Importer.h"
 #include <assimp/ByteSwapper.h>
@@ -53,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Importer.hpp>
 #include <assimp/postprocess.h>
 #include <assimp/importerdesc.h>
+
 #include <ios>
 #include <list>
 #include <memory>
@@ -63,7 +65,7 @@ using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-BaseImporter::BaseImporter()
+BaseImporter::BaseImporter() AI_NO_EXCEPT
 : m_progress() {
     // nothing to do here
 }
@@ -143,7 +145,8 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
     const char**        tokens,
     unsigned int        numTokens,
     unsigned int        searchBytes /* = 200 */,
-    bool                tokensSol /* false */)
+    bool                tokensSol /* false */,
+    bool                noAlphaBeforeTokens /* false */)
 {
     ai_assert( nullptr != tokens );
     ai_assert( 0 != numTokens );
@@ -157,15 +160,14 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
     if (pStream.get() ) {
         // read 200 characters from the file
         std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]);
-        char* buffer = _buffer.get();
-
-        const size_t read = pStream->Read(buffer,1,searchBytes);
-        if( !read ) {
+        char *buffer( _buffer.get() );
+        const size_t read( pStream->Read(buffer,1,searchBytes) );
+        if( 0 == read ) {
             return false;
         }
 
         for( size_t i = 0; i < read; ++i ) {
-            buffer[ i ] = ::tolower( buffer[ i ] );
+            buffer[ i ] = static_cast<char>( ::tolower( buffer[ i ] ) );
         }
 
         // It is not a proper handling of unicode files here ...
@@ -186,13 +188,18 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
             token.clear();
             const char *ptr( tokens[ i ] );
             for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) {
-                token.push_back( tolower( *ptr ) );
+                token.push_back( static_cast<char>( tolower( *ptr ) ) );
                 ++ptr;
             }
             const char* r = strstr( buffer, token.c_str() );
             if( !r ) {
                 continue;
             }
+            // We need to make sure that we didn't accidentially identify the end of another token as our token,
+            // e.g. in a previous version the "gltf " present in some gltf files was detected as "f "
+            if (noAlphaBeforeTokens && (r != buffer && isalpha(r[-1]))) {
+                continue;
+            }
             // We got a match, either we don't care where it is, or it happens to
             // be in the beginning of the file / line
             if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
@@ -234,16 +241,19 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
 
 // ------------------------------------------------------------------------------------------------
 // Get file extension from path
-/*static*/ std::string BaseImporter::GetExtension (const std::string& pFile)
-{
-    std::string::size_type pos = pFile.find_last_of('.');
+std::string BaseImporter::GetExtension( const std::string& file ) {
+    std::string::size_type pos = file.find_last_of('.');
 
     // no file extension at all
-    if( pos == std::string::npos)
+    if (pos == std::string::npos) {
         return "";
+    }
+
+
+    // thanks to Andy Maloney for the hint
+    std::string ret = file.substr( pos + 1 );
+    std::transform( ret.begin(), ret.end(), ret.begin(), ToLower<char>);
 
-    std::string ret = pFile.substr(pos+1);
-    std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint
     return ret;
 }
 

+ 1 - 1
code/BaseProcess.cpp

@@ -53,7 +53,7 @@ using namespace Assimp;
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-BaseProcess::BaseProcess()
+BaseProcess::BaseProcess() AI_NO_EXCEPT
 : shared()
 , progress()
 {

+ 2 - 6
code/BaseProcess.h

@@ -211,20 +211,16 @@ private:
  * should be executed. If the function returns true, the class' Execute()
  * function is called subsequently.
  */
-class ASSIMP_API_WINONLY BaseProcess
-{
+class ASSIMP_API_WINONLY BaseProcess {
     friend class Importer;
 
 public:
-
     /** Constructor to be privately used by Importer */
-    BaseProcess();
+    BaseProcess() AI_NO_EXCEPT;
 
     /** Destructor, private as well */
     virtual ~BaseProcess();
 
-public:
-
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag.
      * @param pFlags The processing flags the importer was called with. A

+ 185 - 0
code/BlenderCustomData.cpp

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

+ 89 - 0
code/BlenderCustomData.h

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

+ 33 - 0
code/BlenderDNA.h

@@ -309,6 +309,28 @@ public:
     void ReadField(T& out, const char* name,
         const FileDatabase& db) const;
 
+    // --------------------------------------------------------
+    /**
+    *   @brief  field parsing for dynamic vectors
+    *   @param[in]  out vector of struct to be filled
+    *   @param[in]  name of field
+    *   @param[in]  db to access the file, dna, ...
+    *   @return true when read was successful
+    */
+    template <int error_policy, template <typename> class TOUT, typename T>
+    bool ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const;
+
+    /**
+    *   @brief  parses raw customdata
+    *   @param[in]  out shared_ptr to be filled
+    *   @param[in]  cdtype customdata type to read
+    *   @param[in]  name of field ptr
+    *   @param[in]  db to access the file, dna, ...
+    *   @return true when read was successful
+    */
+    template <int error_policy>
+    bool ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const;
+
 private:
 
     // --------------------------------------------------------
@@ -803,6 +825,17 @@ private:
     FileDatabase& db;
 };
 
+/**
+*   @brief  read CustomData's data to ptr to mem
+*   @param[out] out memory ptr to set
+*   @param[in]  cdtype  to read
+*   @param[in]  cnt cnt of elements to read
+*   @param[in]  db to read elements from
+*   @return true when ok
+*/
+bool readCustomData(std::shared_ptr<ElemBase> &out, int cdtype, size_t cnt, const FileDatabase &db);
+
+
     } // end Blend
 } // end Assimp
 

+ 102 - 0
code/BlenderDNA.inl

@@ -307,6 +307,108 @@ void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) co
 }
 
 
+//--------------------------------------------------------------------------------
+// field parsing for raw untyped data (like CustomDataLayer.data)
+template <int error_policy>
+bool Structure::ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const {
+
+	const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+
+	Pointer ptrval;
+	const Field* f;
+	try	{
+		f = &(*this)[name];
+
+		// sanity check, should never happen if the genblenddna script is right
+		if (!(f->flags & FieldFlag_Pointer)) {
+			throw Error((Formatter::format(), "Field `", name, "` of structure `",
+				this->name, "` ought to be a pointer"));
+		}
+
+		db.reader->IncPtr(f->offset);
+		Convert(ptrval, db);
+		// actually it is meaningless on which Structure the Convert is called
+		// because the `Pointer` argument triggers a special implementation.
+	}
+	catch (const Error& e) {
+		_defaultInitializer<error_policy>()(out, e.what());
+		out.reset();
+	}
+
+	bool readOk = true;
+	if (ptrval.val)	{
+		// get block for ptr
+		const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
+		db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
+		// read block->num instances of given type to out
+		readOk = readCustomData(out, cdtype, block->num, db);
+	}
+
+	// and recover the previous stream position
+	db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+	++db.stats().fields_read;
+#endif
+
+	return readOk;
+}
+
+//--------------------------------------------------------------------------------
+template <int error_policy, template <typename> class TOUT, typename T>
+bool Structure::ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const {
+	out.clear();
+
+	const StreamReaderAny::pos old = db.reader->GetCurrentPos();
+
+	Pointer ptrval;
+	const Field* f;
+	try	{
+		f = &(*this)[name];
+
+		// sanity check, should never happen if the genblenddna script is right
+		if (!(f->flags & FieldFlag_Pointer)) {
+			throw Error((Formatter::format(), "Field `", name, "` of structure `",
+				this->name, "` ought to be a pointer"));
+		}
+
+		db.reader->IncPtr(f->offset);
+		Convert(ptrval, db);
+		// actually it is meaningless on which Structure the Convert is called
+		// because the `Pointer` argument triggers a special implementation.
+	}
+	catch (const Error& e) {
+		_defaultInitializer<error_policy>()(out, e.what());
+		out.clear();
+		return false;
+	}
+
+
+	if (ptrval.val)	{
+		// find the file block the pointer is pointing to
+		const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
+		db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
+		// FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
+		// I really ought to improve StreamReader to work with 64 bit indices exclusively.
+
+		const Structure& s = db.dna[f->type];
+		for (size_t i = 0; i < block->num; ++i)	{
+			TOUT<T> p(new T);
+			s.Convert(*p, db);
+			out.push_back(p);
+		}
+	}
+
+	db.reader->SetCurrentPos(old);
+
+#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
+	++db.stats().fields_read;
+#endif
+
+	return false;
+}
+
+
 //--------------------------------------------------------------------------------
 template <template <typename> class TOUT, typename T>
 bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const FileDatabase& db,

+ 67 - 8
code/BlenderLoader.cpp

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BlenderIntermediate.h"
 #include "BlenderModifier.h"
 #include "BlenderBMesh.h"
+#include "BlenderCustomData.h"
 #include <assimp/StringUtils.h>
 #include <assimp/scene.h>
 #include <assimp/importerdesc.h>
@@ -1021,6 +1022,34 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
         }
     }
 
+    // TODO should we create the TextureUVMapping map in Convert<Material> to prevent redundant processing?
+
+    // create texture <-> uvname mapping for all materials
+    // key is texture number, value is data *
+    typedef std::map<uint32_t, const MLoopUV *> TextureUVMapping;
+    // key is material number, value is the TextureUVMapping for the material
+    typedef std::map<uint32_t, TextureUVMapping> MaterialTextureUVMappings;
+    MaterialTextureUVMappings matTexUvMappings;
+    const uint32_t maxMat = static_cast<const uint32_t>(mesh->mat.size());
+    for (uint32_t m = 0; m < maxMat; ++m) {
+        // get material by index
+        const std::shared_ptr<Material> pMat = mesh->mat[m];
+        TextureUVMapping texuv;
+        const uint32_t maxTex = sizeof(pMat->mtex) / sizeof(pMat->mtex[0]);
+        for (uint32_t t = 0; t < maxTex; ++t) {
+            if (pMat->mtex[t] && pMat->mtex[t]->uvname[0]) {
+                // get the CustomData layer for given uvname and correct type
+                const ElemBase *pLoop = getCustomDataLayerData(mesh->ldata, CD_MLOOPUV, pMat->mtex[t]->uvname);
+                if (pLoop) {
+                    texuv.insert(std::make_pair(t, dynamic_cast<const MLoopUV *>(pLoop)));
+                }
+            }
+        }
+        if (texuv.size()) {
+            matTexUvMappings.insert(std::make_pair(m, texuv));
+        }
+    }
+
     // collect texture coordinates, they're stored in a separate per-face buffer
     if (mesh->mtface || mesh->mloopuv) {
         if (mesh->totface > static_cast<int> ( mesh->mtface.size())) {
@@ -1028,8 +1057,17 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
         }
         for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
             ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
-
-            (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
+            const auto itMatTexUvMapping = matTexUvMappings.find((*it)->mMaterialIndex);
+            if (itMatTexUvMapping == matTexUvMappings.end()) {
+                // default behaviour like before
+                (*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
+            }
+            else {
+                // create texture coords for every mapped tex
+                for (uint32_t i = 0; i < itMatTexUvMapping->second.size(); ++i) {
+                    (*it)->mTextureCoords[i] = new aiVector3D[(*it)->mNumVertices];
+                }
+            }
             (*it)->mNumFaces = (*it)->mNumVertices = 0;
         }
 
@@ -1051,13 +1089,34 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
             aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ];
             const aiFace& f = out->mFaces[out->mNumFaces++];
 
-            aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
-            for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) {
-                const MLoopUV& uv = mesh->mloopuv[v.loopstart + j];
-                vo->x = uv.uv[0];
-                vo->y = uv.uv[1];
+            const auto itMatTexUvMapping = matTexUvMappings.find(v.mat_nr);
+            if (itMatTexUvMapping == matTexUvMappings.end()) {
+                // old behavior
+                aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
+                for (unsigned int j = 0; j < f.mNumIndices; ++j, ++vo, ++out->mNumVertices) {
+                    const MLoopUV& uv = mesh->mloopuv[v.loopstart + j];
+                    vo->x = uv.uv[0];
+                    vo->y = uv.uv[1];
+                }
+            }
+            else {
+                // create textureCoords for every mapped tex
+                for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++m) {
+                    const MLoopUV *tm = itMatTexUvMapping->second[m];
+                    aiVector3D* vo = &out->mTextureCoords[m][out->mNumVertices];
+                    uint32_t j = 0;
+                    for (; j < f.mNumIndices; ++j, ++vo) {
+                        const MLoopUV& uv = tm[v.loopstart + j];
+                        vo->x = uv.uv[0];
+                        vo->y = uv.uv[1];
+                    }
+                    // only update written mNumVertices in last loop
+                    // TODO why must the numVertices be incremented here?
+                    if (m == itMatTexUvMapping->second.size() - 1) {
+                        out->mNumVertices += j;
+                    }
+                }
             }
-
         }
     }
 

+ 44 - 0
code/BlenderScene.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BlenderScene.h"
 #include "BlenderSceneGen.h"
 #include "BlenderDNA.h"
+#include "BlenderCustomData.h"
 
 using namespace Assimp;
 using namespace Assimp::Blender;
@@ -481,6 +482,12 @@ template <> void Structure :: Convert<Mesh> (
     ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol,"*mcol",db);
     ReadFieldPtr<ErrorPolicy_Fail>(dest.mat,"**mat",db);
 
+    ReadField<ErrorPolicy_Igno>(dest.vdata, "vdata", db);
+    ReadField<ErrorPolicy_Igno>(dest.edata, "edata", db);
+    ReadField<ErrorPolicy_Igno>(dest.fdata, "fdata", db);
+    ReadField<ErrorPolicy_Igno>(dest.pdata, "pdata", db);
+    ReadField<ErrorPolicy_Warn>(dest.ldata, "ldata", db);
+
     db.reader->IncPtr(size);
 }
 
@@ -786,6 +793,41 @@ template <> void Structure :: Convert<Image> (
     db.reader->IncPtr(size);
 }
 
+//--------------------------------------------------------------------------------
+template <> void Structure::Convert<CustomData>(
+    CustomData& dest,
+    const FileDatabase& db
+    ) const
+{
+    ReadFieldArray<ErrorPolicy_Warn>(dest.typemap, "typemap", db);
+    ReadField<ErrorPolicy_Warn>(dest.totlayer, "totlayer", db);
+    ReadField<ErrorPolicy_Warn>(dest.maxlayer, "maxlayer", db);
+    ReadField<ErrorPolicy_Warn>(dest.totsize, "totsize", db);
+    ReadFieldPtrVector<ErrorPolicy_Warn>(dest.layers, "*layers", db);
+
+    db.reader->IncPtr(size);
+}
+
+//--------------------------------------------------------------------------------
+template <> void Structure::Convert<CustomDataLayer>(
+    CustomDataLayer& dest,
+    const FileDatabase& db
+    ) const
+{
+    ReadField<ErrorPolicy_Fail>(dest.type, "type", db);
+    ReadField<ErrorPolicy_Fail>(dest.offset, "offset", db);
+    ReadField<ErrorPolicy_Fail>(dest.flag, "flag", db);
+    ReadField<ErrorPolicy_Fail>(dest.active, "active", db);
+    ReadField<ErrorPolicy_Fail>(dest.active_rnd, "active_rnd", db);
+    ReadField<ErrorPolicy_Fail>(dest.active_clone, "active_clone", db);
+    ReadField<ErrorPolicy_Fail>(dest.active_mask, "active_mask", db);
+    ReadField<ErrorPolicy_Fail>(dest.uid, "uid", db);
+    ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
+    ReadCustomDataPtr<ErrorPolicy_Fail>(dest.data, dest.type, "*data", db);
+
+    db.reader->IncPtr(size);
+}
+
 //--------------------------------------------------------------------------------
 void DNA::RegisterConverters() {
 
@@ -822,6 +864,8 @@ void DNA::RegisterConverters() {
     converters["Camera"] = DNA::FactoryPair( &Structure::Allocate<Camera>, &Structure::Convert<Camera> );
     converters["MirrorModifierData"] = DNA::FactoryPair( &Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData> );
     converters["Image"] = DNA::FactoryPair( &Structure::Allocate<Image>, &Structure::Convert<Image> );
+    converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
+    converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
 }
 
 #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

+ 79 - 1
code/BlenderScene.h

@@ -157,10 +157,16 @@ struct World : ElemBase {
 // -------------------------------------------------------------------------------
 struct MVert : ElemBase {
     float co[3] FAIL;
-    float no[3] FAIL;
+    float no[3] FAIL;       // readed as short and divided through / 32767.f
     char flag;
     int mat_nr WARN;
     int bweight;
+
+    MVert() : ElemBase()
+        , flag(0)
+        , mat_nr(0)
+        , bweight(0)
+    {}
 };
 
 // -------------------------------------------------------------------------------
@@ -369,6 +375,72 @@ struct Material : ElemBase {
     std::shared_ptr<MTex> mtex[18];
 };
 
+/*
+CustomDataLayer 104
+
+    int type 0 4
+    int offset 4 4
+    int flag 8 4
+    int active 12 4
+    int active_rnd 16 4
+    int active_clone 20 4
+    int active_mask 24 4
+    int uid 28 4
+    char name 32 64
+    void *data 96 8
+*/
+struct CustomDataLayer : ElemBase {
+    int type;
+    int offset;
+    int flag;
+    int active;
+    int active_rnd;
+    int active_clone;
+    int active_mask;
+    int uid;
+    char name[64];
+    std::shared_ptr<ElemBase> data;     // must be converted to real type according type member
+
+    CustomDataLayer()
+        : ElemBase()
+        , type(0)
+        , offset(0)
+        , flag(0)
+        , active(0)
+        , active_rnd(0)
+        , active_clone(0)
+        , active_mask(0)
+        , uid(0)
+        , data(nullptr)
+    {
+        memset(name, 0, sizeof name);
+    }
+};
+
+/*
+CustomData 208
+
+    CustomDataLayer *layers 0 8
+    int typemap 8 168
+    int pad_i1 176 4
+    int totlayer 180 4
+    int maxlayer 184 4
+    int totsize 188 4
+    BLI_mempool *pool 192 8
+    CustomDataExternal *external 200 8
+*/
+struct CustomData : ElemBase {
+    vector<std::shared_ptr<struct CustomDataLayer> > layers;
+    int typemap[42];    // CD_NUMTYPES
+    int totlayer;
+    int maxlayer;
+    int totsize;
+    /*
+    std::shared_ptr<BLI_mempool> pool;
+    std::shared_ptr<CustomDataExternal> external;
+    */
+};
+
 // -------------------------------------------------------------------------------
 struct Mesh : ElemBase {
     ID id FAIL;
@@ -398,6 +470,12 @@ struct Mesh : ElemBase {
     vector<MCol> mcol;
 
     vector< std::shared_ptr<Material> > mat FAIL;
+
+    struct CustomData vdata;
+    struct CustomData edata;
+    struct CustomData fdata;
+    struct CustomData pdata;
+    struct CustomData ldata;
 };
 
 // -------------------------------------------------------------------------------

+ 11 - 0
code/BlenderSceneGen.h

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

+ 8 - 0
code/CMakeLists.txt

@@ -469,6 +469,8 @@ ADD_ASSIMP_IMPORTER( BLEND
   BlenderBMesh.cpp
   BlenderTessellator.h
   BlenderTessellator.cpp
+  BlenderCustomData.h
+  BlenderCustomData.cpp
 )
 
 ADD_ASSIMP_IMPORTER( IFC
@@ -909,6 +911,12 @@ ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER)
 
 ADD_LIBRARY( assimp ${assimp_src} )
 
+TARGET_INCLUDE_DIRECTORIES ( assimp PUBLIC
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include>
+  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/../include>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
+)
+
 TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ${IRRXML_LIBRARY} )
 
 if(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM)

+ 1 - 3
code/COBLoader.cpp

@@ -137,9 +137,7 @@ void COBImporter::SetupProperties(const Importer* /*pImp*/)
 
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
-void COBImporter::InternReadFile( const std::string& pFile,
-    aiScene* pScene, IOSystem* pIOHandler)
-{
+void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
     COB::Scene scene;
     std::unique_ptr<StreamReaderLE> stream(new StreamReaderLE( pIOHandler->Open(pFile,"rb")) );
 

+ 4 - 3
code/ColladaHelper.h

@@ -272,12 +272,13 @@ struct Node
     /** Node instances at this node */
     std::vector<NodeInstance> mNodeInstances;
 
-    /** Rootnodes: Name of primary camera, if any */
+    /** Root-nodes: Name of primary camera, if any */
     std::string mPrimaryCamera;
 
     //! Constructor. Begin with a zero parent
-    Node() {
-        mParent = NULL;
+    Node()
+    : mParent( nullptr ){
+        // empty
     }
 
     //! Destructor: delete all children subsequently

+ 23 - 25
code/ColladaLoader.cpp

@@ -181,26 +181,27 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I
     // ... then fill the materials with the now adjusted settings
     FillMaterials(parser, pScene);
 
-        // Apply unitsize scale calculation
-        pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0,  0,  0,
-                                                          0,  parser.mUnitSize,  0,  0,
-                                                          0,  0,  parser.mUnitSize,  0,
-                                                          0,  0,  0,  1);
-        if( !ignoreUpDirection ) {
-        // Convert to Y_UP, if different orientation
-        if( parser.mUpDirection == ColladaParser::UP_X)
-            pScene->mRootNode->mTransformation *= aiMatrix4x4(
-                 0, -1,  0,  0,
-                 1,  0,  0,  0,
-                 0,  0,  1,  0,
-                 0,  0,  0,  1);
-        else if( parser.mUpDirection == ColladaParser::UP_Z)
-            pScene->mRootNode->mTransformation *= aiMatrix4x4(
-                 1,  0,  0,  0,
-                 0,  0,  1,  0,
-                 0, -1,  0,  0,
-                 0,  0,  0,  1);
-        }
+    // Apply unitsize scale calculation
+    pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0,  0,  0,
+                                                        0,  parser.mUnitSize,  0,  0,
+                                                        0,  0,  parser.mUnitSize,  0,
+                                                        0,  0,  0,  1);
+    if( !ignoreUpDirection ) {
+    // Convert to Y_UP, if different orientation
+    if( parser.mUpDirection == ColladaParser::UP_X)
+        pScene->mRootNode->mTransformation *= aiMatrix4x4(
+                0, -1,  0,  0,
+                1,  0,  0,  0,
+                0,  0,  1,  0,
+                0,  0,  0,  1);
+    else if( parser.mUpDirection == ColladaParser::UP_Z)
+        pScene->mRootNode->mTransformation *= aiMatrix4x4(
+                1,  0,  0,  0,
+                0,  0,  1,  0,
+                0, -1,  0,  0,
+                0,  0,  0,  1);
+    }
+
     // store all meshes
     StoreSceneMeshes( pScene);
 
@@ -740,10 +741,6 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
     // create bones if given
     if( pSrcController && pSrcController->mType == Collada::Skin)
     {
-        // refuse if the vertex count does not match
-//      if( pSrcController->mWeightCounts.size() != dstMesh->mNumVertices)
-//          throw DeadlyImportError( "Joint Controller vertex count does not match mesh vertex count");
-
         // resolve references - joint names
         const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointNameSource);
         const Collada::Data& jointNames = pParser.ResolveLibraryReference( pParser.mDataLibrary, jointNamesAcc.mSource);
@@ -971,7 +968,8 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars
             for( size_t b = a+1; b < mAnims.size(); ++b)
             {
                 aiAnimation* other = mAnims[b];
-                if( other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && other->mTicksPerSecond == templateAnim->mTicksPerSecond )
+                if( other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && 
+                        other->mTicksPerSecond == templateAnim->mTicksPerSecond )
                     collectedAnimIndices.push_back( b);
             }
 

+ 14 - 14
code/ColladaParser.cpp

@@ -68,7 +68,7 @@ using namespace Assimp::Formatter;
 // Constructor to be privately used by Importer
 ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
     : mFileName( pFile )
-    , mReader( NULL )
+    , mReader( nullptr )
     , mDataLibrary()
     , mAccessorLibrary()
     , mMeshLibrary()
@@ -79,20 +79,20 @@ ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile)
     , mLightLibrary()
     , mCameraLibrary()
     , mControllerLibrary()
-    , mRootNode( NULL )
+    , mRootNode( nullptr )
     , mAnims()
     , mUnitSize( 1.0f )
     , mUpDirection( UP_Y )
     , mFormat(FV_1_5_n )    // We assume the newest file format by default
 {
     // validate io-handler instance
-    if ( NULL == pIOHandler ) {
+    if (nullptr == pIOHandler ) {
         throw DeadlyImportError("IOSystem is NULL." );
     }
 
     // open the file
     std::unique_ptr<IOStream> file( pIOHandler->Open(pFile ) );
-    if (file.get() == NULL) {
+    if (file.get() == nullptr) {
         throw DeadlyImportError( "Failed to open file " + pFile + "." );
     }
 
@@ -363,17 +363,17 @@ void ColladaParser::ReadAnimationClipLibrary()
 
 void ColladaParser::PostProcessControllers()
 {
-  for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it)
-  {
-    std::string meshId = it->second.mMeshId;
-    ControllerLibrary::iterator findItr = mControllerLibrary.find(meshId);
-    while(findItr != mControllerLibrary.end()) {
-      meshId = findItr->second.mMeshId;
-      findItr = mControllerLibrary.find(meshId);
-    }
+    std::string meshId;
+    for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it) {
+        meshId = it->second.mMeshId;
+        ControllerLibrary::iterator findItr = mControllerLibrary.find(meshId);
+        while(findItr != mControllerLibrary.end()) {
+            meshId = findItr->second.mMeshId;
+            findItr = mControllerLibrary.find(meshId);
+        }
     
-    it->second.mMeshId = meshId;
-  }
+        it->second.mMeshId = meshId;
+    }
 }
 
 // ------------------------------------------------------------------------------------------------

+ 22 - 9
code/ConvertToLHProcess.cpp

@@ -59,6 +59,25 @@ using namespace Assimp;
 
 #ifndef ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
 
+namespace {
+
+template <typename aiMeshType>
+void flipUVs(aiMeshType* pMesh) {
+    if (pMesh == nullptr) { return; }
+    // mirror texture y coordinate
+    for (unsigned int tcIdx = 0; tcIdx < AI_MAX_NUMBER_OF_TEXTURECOORDS; tcIdx++) {
+        if (!pMesh->HasTextureCoords(tcIdx)) {
+            break;
+        }
+
+        for (unsigned int vIdx = 0; vIdx < pMesh->mNumVertices; vIdx++) {
+            pMesh->mTextureCoords[tcIdx][vIdx].y = 1.0f - pMesh->mTextureCoords[tcIdx][vIdx].y;
+        }
+    }
+}
+
+} // namespace
+
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 MakeLeftHandedProcess::MakeLeftHandedProcess()
@@ -282,15 +301,9 @@ void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
 // Converts a single mesh
 void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
 {
-    // mirror texture y coordinate
-    for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++)   {
-        if( !pMesh->HasTextureCoords( a ) ) {
-            break;
-        }
-
-        for( unsigned int b = 0; b < pMesh->mNumVertices; b++ ) {
-            pMesh->mTextureCoords[ a ][ b ].y = 1.0f - pMesh->mTextureCoords[ a ][ b ].y;
-        }
+    flipUVs(pMesh);
+    for (unsigned int idx = 0; idx < pMesh->mNumAnimMeshes; idx++) {
+        flipUVs(pMesh->mAnimMeshes[idx]);
     }
 }
 

+ 1 - 1
code/D3MFExporter.cpp

@@ -222,7 +222,7 @@ void D3MFExporter::writeMetaData() {
         return;
     }
 
-    const aiString *key;
+	const aiString *key = nullptr;
     const aiMetadataEntry *entry(nullptr);
     for ( size_t i = 0; i < numMetaEntries; ++i ) {
         mScene->mMetaData->Get( i, key, entry );

+ 8 - 5
code/D3MFImporter.cpp

@@ -297,8 +297,9 @@ private:
             return false;
         }
 
+        //format of the color string: #RRGGBBAA or #RRGGBB (3MF Core chapter 5.1.1)
         const size_t len( strlen( color ) );
-        if ( 9 != len ) {
+        if ( 9 != len && 7 != len) {
             return false;
         }
 
@@ -313,26 +314,28 @@ private:
         ++buf;
         comp[ 1 ] = *buf;
         ++buf;
-        diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) );
+        diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) ) / 255.0;
 
 
         comp[ 0 ] = *buf;
         ++buf;
         comp[ 1 ] = *buf;
         ++buf;
-        diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
+        diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / 255.0;
 
         comp[ 0 ] = *buf;
         ++buf;
         comp[ 1 ] = *buf;
         ++buf;
-        diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
+        diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / 255.0;
 
+        if(7 == len)
+            return true;
         comp[ 0 ] = *buf;
         ++buf;
         comp[ 1 ] = *buf;
         ++buf;
-        diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
+        diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) ) / 255.0;
 
         return true;
     }

+ 1 - 1
code/EmbedTexturesProcess.cpp

@@ -119,7 +119,7 @@ bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
         }
     }
 
-    aiTexel* imageContent = new aiTexel[1u + imageSize / sizeof(aiTexel)];
+    aiTexel* imageContent = new aiTexel[ 1ul + static_cast<unsigned long>( imageSize ) / sizeof(aiTexel)];
     file.seekg(0, std::ios::beg);
     file.read(reinterpret_cast<char*>(imageContent), imageSize);
 

+ 4 - 4
code/Exporter.cpp

@@ -150,14 +150,14 @@ Exporter::ExportFormatEntry gExporters[] =
 #endif
 
 #ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
-    Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
-        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
-    Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
-        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
     Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
         aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
     Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
         aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
+    Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
+        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
+    Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
+        aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER

+ 252 - 270
code/FBXConverter.cpp

@@ -73,11 +73,7 @@ using namespace Util;
 
 #define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000L
 
-// XXX vc9's debugger won't step into anonymous namespaces
-//namespace {
-
-
-Converter::Converter( aiScene* out, const Document& doc )
+FBXConverter::FBXConverter( aiScene* out, const Document& doc )
 : defaultMaterialIndex()
 , out( out )
 , doc( doc ) {
@@ -118,7 +114,7 @@ Converter::Converter( aiScene* out, const Document& doc )
 }
 
 
-Converter::~Converter() {
+FBXConverter::~FBXConverter() {
     std::for_each( meshes.begin(), meshes.end(), Util::delete_fun<aiMesh>() );
     std::for_each( materials.begin(), materials.end(), Util::delete_fun<aiMaterial>() );
     std::for_each( animations.begin(), animations.end(), Util::delete_fun<aiAnimation>() );
@@ -127,7 +123,7 @@ Converter::~Converter() {
     std::for_each( textures.begin(), textures.end(), Util::delete_fun<aiTexture>() );
 }
 
-void Converter::ConvertRootNode() {
+void FBXConverter::ConvertRootNode() {
     out->mRootNode = new aiNode();
     out->mRootNode->mName.Set( "RootNode" );
 
@@ -135,7 +131,7 @@ void Converter::ConvertRootNode() {
     ConvertNodes( 0L, *out->mRootNode );
 }
 
-void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform ) {
+void FBXConverter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform ) {
     const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced( id, "Model" );
 
     std::vector<aiNode*> nodes;
@@ -189,12 +185,8 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
                 }
 
                 if ( !name_carrier ) {
-                    NodeNameCache::const_iterator it( std::find( mNodeNames.begin(), mNodeNames.end(), original_name ) );
-                    if ( it != mNodeNames.end() ) {
-                        original_name = original_name + std::string( "001" );
-                    }
-
-                    mNodeNames.push_back( original_name );
+                    std::string old_original_name = original_name;
+                    GetUniqueName(old_original_name, original_name);
                     nodes_chain.push_back( new aiNode( original_name ) );
                 } else {
                     original_name = nodes_chain.back()->mName.C_Str();
@@ -286,7 +278,7 @@ void Converter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& pa
 }
 
 
-void Converter::ConvertLights( const Model& model, const std::string &orig_name ) {
+void FBXConverter::ConvertLights( const Model& model, const std::string &orig_name ) {
     const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
     for( const NodeAttribute* attr : node_attrs ) {
         const Light* const light = dynamic_cast<const Light*>( attr );
@@ -296,7 +288,7 @@ void Converter::ConvertLights( const Model& model, const std::string &orig_name
     }
 }
 
-void Converter::ConvertCameras( const Model& model, const std::string &orig_name ) {
+void FBXConverter::ConvertCameras( const Model& model, const std::string &orig_name ) {
     const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes();
     for( const NodeAttribute* attr : node_attrs ) {
         const Camera* const cam = dynamic_cast<const Camera*>( attr );
@@ -306,7 +298,7 @@ void Converter::ConvertCameras( const Model& model, const std::string &orig_name
     }
 }
 
-void Converter::ConvertLight( const Light& light, const std::string &orig_name ) {
+void FBXConverter::ConvertLight( const Light& light, const std::string &orig_name ) {
     lights.push_back( new aiLight() );
     aiLight* const out_light = lights.back();
 
@@ -383,7 +375,7 @@ void Converter::ConvertLight( const Light& light, const std::string &orig_name )
     }
 }
 
-void Converter::ConvertCamera( const Camera& cam, const std::string &orig_name )
+void FBXConverter::ConvertCamera( const Camera& cam, const std::string &orig_name )
 {
     cameras.push_back( new aiCamera() );
     aiCamera* const out_camera = cameras.back();
@@ -402,133 +394,120 @@ void Converter::ConvertCamera( const Camera& cam, const std::string &orig_name )
     out_camera->mClipPlaneFar = cam.FarPlane();
 }
 
-static bool HasName( NodeNameCache &cache, const std::string &name ) {
-    NodeNameCache::const_iterator it( std::find( cache.begin(), cache.end(), name ) );
-    return it != cache.end();
-
-}
-void Converter::GetUniqueName( const std::string &name, std::string uniqueName ) {
-    if ( !HasName( mNodeNames, name ) ) {
-        uniqueName = name;
-        return;
-    }
-
-    int i( 0 );
-    std::string newName;
-    while ( HasName( mNodeNames, newName ) ) {
+void FBXConverter::GetUniqueName( const std::string &name, std::string &uniqueName )
+{
+    int i = 0;
+    uniqueName = name;
+    while (mNodeNames.find(uniqueName) != mNodeNames.end())
+    {
         ++i;
-        newName.clear();
-        newName += name;
         std::stringstream ext;
-        ext << std::setfill( '0' ) << std::setw( 3 ) << i;
-        newName += ext.str();
+        ext << name << std::setfill('0') << std::setw(3) << i;
+        uniqueName = ext.str();
     }
-    uniqueName = newName;
-    mNodeNames.push_back( uniqueName );
+    mNodeNames.insert(uniqueName);
 }
 
 
-const char* Converter::NameTransformationComp( TransformationComp comp )
-{
-    switch ( comp )
-    {
-    case TransformationComp_Translation:
-        return "Translation";
-    case TransformationComp_RotationOffset:
-        return "RotationOffset";
-    case TransformationComp_RotationPivot:
-        return "RotationPivot";
-    case TransformationComp_PreRotation:
-        return "PreRotation";
-    case TransformationComp_Rotation:
-        return "Rotation";
-    case TransformationComp_PostRotation:
-        return "PostRotation";
-    case TransformationComp_RotationPivotInverse:
-        return "RotationPivotInverse";
-    case TransformationComp_ScalingOffset:
-        return "ScalingOffset";
-    case TransformationComp_ScalingPivot:
-        return "ScalingPivot";
-    case TransformationComp_Scaling:
-        return "Scaling";
-    case TransformationComp_ScalingPivotInverse:
-        return "ScalingPivotInverse";
-    case TransformationComp_GeometricScaling:
-        return "GeometricScaling";
-    case TransformationComp_GeometricRotation:
-        return "GeometricRotation";
-    case TransformationComp_GeometricTranslation:
-        return "GeometricTranslation";
-    case TransformationComp_GeometricScalingInverse:
-        return "GeometricScalingInverse";
-    case TransformationComp_GeometricRotationInverse:
-        return "GeometricRotationInverse";
-    case TransformationComp_GeometricTranslationInverse:
-        return "GeometricTranslationInverse";
-    case TransformationComp_MAXIMUM: // this is to silence compiler warnings
-    default:
-        break;
+const char* FBXConverter::NameTransformationComp( TransformationComp comp ) {
+    switch ( comp ) {
+        case TransformationComp_Translation:
+            return "Translation";
+        case TransformationComp_RotationOffset:
+            return "RotationOffset";
+        case TransformationComp_RotationPivot:
+            return "RotationPivot";
+        case TransformationComp_PreRotation:
+            return "PreRotation";
+        case TransformationComp_Rotation:
+            return "Rotation";
+        case TransformationComp_PostRotation:
+            return "PostRotation";
+        case TransformationComp_RotationPivotInverse:
+            return "RotationPivotInverse";
+        case TransformationComp_ScalingOffset:
+            return "ScalingOffset";
+        case TransformationComp_ScalingPivot:
+            return "ScalingPivot";
+        case TransformationComp_Scaling:
+            return "Scaling";
+        case TransformationComp_ScalingPivotInverse:
+            return "ScalingPivotInverse";
+        case TransformationComp_GeometricScaling:
+            return "GeometricScaling";
+        case TransformationComp_GeometricRotation:
+            return "GeometricRotation";
+        case TransformationComp_GeometricTranslation:
+            return "GeometricTranslation";
+        case TransformationComp_GeometricScalingInverse:
+            return "GeometricScalingInverse";
+        case TransformationComp_GeometricRotationInverse:
+            return "GeometricRotationInverse";
+        case TransformationComp_GeometricTranslationInverse:
+            return "GeometricTranslationInverse";
+        case TransformationComp_MAXIMUM: // this is to silence compiler warnings
+        default:
+            break;
     }
 
     ai_assert( false );
-    return NULL;
+
+    return nullptr;
 }
 
-const char* Converter::NameTransformationCompProperty( TransformationComp comp )
-{
-    switch ( comp )
-    {
-    case TransformationComp_Translation:
-        return "Lcl Translation";
-    case TransformationComp_RotationOffset:
-        return "RotationOffset";
-    case TransformationComp_RotationPivot:
-        return "RotationPivot";
-    case TransformationComp_PreRotation:
-        return "PreRotation";
-    case TransformationComp_Rotation:
-        return "Lcl Rotation";
-    case TransformationComp_PostRotation:
-        return "PostRotation";
-    case TransformationComp_RotationPivotInverse:
-        return "RotationPivotInverse";
-    case TransformationComp_ScalingOffset:
-        return "ScalingOffset";
-    case TransformationComp_ScalingPivot:
-        return "ScalingPivot";
-    case TransformationComp_Scaling:
-        return "Lcl Scaling";
-    case TransformationComp_ScalingPivotInverse:
-        return "ScalingPivotInverse";
-    case TransformationComp_GeometricScaling:
-        return "GeometricScaling";
-    case TransformationComp_GeometricRotation:
-        return "GeometricRotation";
-    case TransformationComp_GeometricTranslation:
-        return "GeometricTranslation";
-    case TransformationComp_GeometricScalingInverse:
-        return "GeometricScalingInverse";
-    case TransformationComp_GeometricRotationInverse:
-        return "GeometricRotationInverse";
-    case TransformationComp_GeometricTranslationInverse:
-        return "GeometricTranslationInverse";
-    case TransformationComp_MAXIMUM: // this is to silence compiler warnings
-        break;
+const char* FBXConverter::NameTransformationCompProperty( TransformationComp comp ) {
+    switch ( comp ) {
+        case TransformationComp_Translation:
+            return "Lcl Translation";
+        case TransformationComp_RotationOffset:
+            return "RotationOffset";
+        case TransformationComp_RotationPivot:
+            return "RotationPivot";
+        case TransformationComp_PreRotation:
+            return "PreRotation";
+        case TransformationComp_Rotation:
+            return "Lcl Rotation";
+        case TransformationComp_PostRotation:
+            return "PostRotation";
+        case TransformationComp_RotationPivotInverse:
+            return "RotationPivotInverse";
+        case TransformationComp_ScalingOffset:
+            return "ScalingOffset";
+        case TransformationComp_ScalingPivot:
+            return "ScalingPivot";
+        case TransformationComp_Scaling:
+            return "Lcl Scaling";
+        case TransformationComp_ScalingPivotInverse:
+            return "ScalingPivotInverse";
+        case TransformationComp_GeometricScaling:
+            return "GeometricScaling";
+        case TransformationComp_GeometricRotation:
+            return "GeometricRotation";
+        case TransformationComp_GeometricTranslation:
+            return "GeometricTranslation";
+        case TransformationComp_GeometricScalingInverse:
+            return "GeometricScalingInverse";
+        case TransformationComp_GeometricRotationInverse:
+            return "GeometricRotationInverse";
+        case TransformationComp_GeometricTranslationInverse:
+            return "GeometricTranslationInverse";
+        case TransformationComp_MAXIMUM: // this is to silence compiler warnings
+            break;
     }
 
     ai_assert( false );
-    return NULL;
+
+    return nullptr;
 }
 
-aiVector3D Converter::TransformationCompDefaultValue( TransformationComp comp )
+aiVector3D FBXConverter::TransformationCompDefaultValue( TransformationComp comp )
 {
     // XXX a neat way to solve the never-ending special cases for scaling
     // would be to do everything in log space!
     return comp == TransformationComp_Scaling ? aiVector3D( 1.f, 1.f, 1.f ) : aiVector3D();
 }
 
-void Converter::GetRotationMatrix( Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out )
+void FBXConverter::GetRotationMatrix( Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out )
 {
     if ( mode == Model::RotOrder_SphericXYZ ) {
         FBXImporter::LogError( "Unsupported RotationMode: SphericXYZ" );
@@ -599,11 +578,15 @@ void Converter::GetRotationMatrix( Model::RotOrder mode, const aiVector3D& rotat
 
     default:
         ai_assert( false );
+        break;
     }
 
-    ai_assert( ( order[ 0 ] >= 0 ) && ( order[ 0 ] <= 2 ) );
-    ai_assert( ( order[ 1 ] >= 0 ) && ( order[ 1 ] <= 2 ) );
-    ai_assert( ( order[ 2 ] >= 0 ) && ( order[ 2 ] <= 2 ) );
+    ai_assert( order[ 0 ] >= 0 );
+    ai_assert( order[ 0 ] <= 2 );
+    ai_assert( order[ 1 ] >= 0 );
+    ai_assert( order[ 1 ] <= 2 );
+    ai_assert( order[ 2 ] >= 0 );
+    ai_assert( order[ 2 ] <= 2 );
 
     if ( !is_id[ order[ 0 ] ] ) {
         out = temp[ order[ 0 ] ];
@@ -618,7 +601,7 @@ void Converter::GetRotationMatrix( Model::RotOrder mode, const aiVector3D& rotat
     }
 }
 
-bool Converter::NeedsComplexTransformationChain( const Model& model )
+bool FBXConverter::NeedsComplexTransformationChain( const Model& model )
 {
     const PropertyTable& props = model.Props();
     bool ok;
@@ -649,13 +632,13 @@ bool Converter::NeedsComplexTransformationChain( const Model& model )
     return false;
 }
 
-std::string Converter::NameTransformationChainNode( const std::string& name, TransformationComp comp )
+std::string FBXConverter::NameTransformationChainNode( const std::string& name, TransformationComp comp )
 {
     return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
 }
 
-void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes )
-{
+void FBXConverter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes,
+        std::vector<aiNode*>& post_output_nodes ) {
     const PropertyTable& props = model.Props();
     const Model::RotOrder rot = model.RotationOrder();
 
@@ -826,7 +809,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
     }
 }
 
-void Converter::SetupNodeMetadata( const Model& model, aiNode& nd )
+void FBXConverter::SetupNodeMetadata( const Model& model, aiNode& nd )
 {
     const PropertyTable& props = model.Props();
     DirectPropertyMap unparsedProperties = props.GetUnparsedProperties();
@@ -863,7 +846,7 @@ void Converter::SetupNodeMetadata( const Model& model, aiNode& nd )
     }
 }
 
-void Converter::ConvertModel( const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform )
+void FBXConverter::ConvertModel( const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform )
 {
     const std::vector<const Geometry*>& geos = model.GetGeometry();
 
@@ -890,7 +873,7 @@ void Converter::ConvertModel( const Model& model, aiNode& nd, const aiMatrix4x4&
     }
 }
 
-std::vector<unsigned int> Converter::ConvertMesh( const MeshGeometry& mesh, const Model& model,
+std::vector<unsigned int> FBXConverter::ConvertMesh( const MeshGeometry& mesh, const Model& model,
     const aiMatrix4x4& node_global_transform, aiNode& nd)
 {
     std::vector<unsigned int> temp;
@@ -925,7 +908,7 @@ std::vector<unsigned int> Converter::ConvertMesh( const MeshGeometry& mesh, cons
     return temp;
 }
 
-aiMesh* Converter::SetupEmptyMesh( const MeshGeometry& mesh, aiNode& nd)
+aiMesh* FBXConverter::SetupEmptyMesh( const MeshGeometry& mesh, aiNode& nd)
 {
     aiMesh* const out_mesh = new aiMesh();
     meshes.push_back( out_mesh );
@@ -948,7 +931,7 @@ aiMesh* Converter::SetupEmptyMesh( const MeshGeometry& mesh, aiNode& nd)
     return out_mesh;
 }
 
-unsigned int Converter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, const Model& model,
+unsigned int FBXConverter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, const Model& model,
     const aiMatrix4x4& node_global_transform, aiNode& nd)
 {
     const MatIndexArray& mindices = mesh.GetMaterialIndices();
@@ -1075,7 +1058,7 @@ unsigned int Converter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, con
     return static_cast<unsigned int>( meshes.size() - 1 );
 }
 
-std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model,
+std::vector<unsigned int> FBXConverter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model,
     const aiMatrix4x4& node_global_transform, aiNode& nd)
 {
     const MatIndexArray& mindices = mesh.GetMaterialIndices();
@@ -1095,7 +1078,7 @@ std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometr
     return indices;
 }
 
-unsigned int Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model,
+unsigned int FBXConverter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model,
     MatIndexArray::value_type index,
     const aiMatrix4x4& node_global_transform,
     aiNode& nd)
@@ -1271,7 +1254,7 @@ unsigned int Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, cons
     return static_cast<unsigned int>( meshes.size() - 1 );
 }
 
-void Converter::ConvertWeights( aiMesh* out, const Model& model, const MeshGeometry& geo,
+void FBXConverter::ConvertWeights( aiMesh* out, const Model& model, const MeshGeometry& geo,
     const aiMatrix4x4& node_global_transform ,
     unsigned int materialIndex,
     std::vector<unsigned int>* outputVertStartIndices  )
@@ -1376,7 +1359,7 @@ void Converter::ConvertWeights( aiMesh* out, const Model& model, const MeshGeome
     std::swap_ranges( bones.begin(), bones.end(), out->mBones );
 }
 
-void Converter::ConvertCluster( std::vector<aiBone*>& bones, const Model& /*model*/, const Cluster& cl,
+void FBXConverter::ConvertCluster( std::vector<aiBone*>& bones, const Model& /*model*/, const Cluster& cl,
         std::vector<size_t>& out_indices,
         std::vector<size_t>& index_out_indices,
         std::vector<size_t>& count_out_indices,
@@ -1417,7 +1400,7 @@ void Converter::ConvertCluster( std::vector<aiBone*>& bones, const Model& /*mode
     }
 }
 
-void Converter::ConvertMaterialForMesh( aiMesh* out, const Model& model, const MeshGeometry& geo,
+void FBXConverter::ConvertMaterialForMesh( aiMesh* out, const Model& model, const MeshGeometry& geo,
     MatIndexArray::value_type materialIndex )
 {
     // locate source materials for this mesh
@@ -1439,7 +1422,7 @@ void Converter::ConvertMaterialForMesh( aiMesh* out, const Model& model, const M
     materials_converted[ mat ] = out->mMaterialIndex;
 }
 
-unsigned int Converter::GetDefaultMaterial()
+unsigned int FBXConverter::GetDefaultMaterial()
 {
     if ( defaultMaterialIndex ) {
         return defaultMaterialIndex - 1;
@@ -1461,7 +1444,7 @@ unsigned int Converter::GetDefaultMaterial()
 }
 
 
-unsigned int Converter::ConvertMaterial( const Material& material, const MeshGeometry* const mesh )
+unsigned int FBXConverter::ConvertMaterial( const Material& material, const MeshGeometry* const mesh )
 {
     const PropertyTable& props = material.Props();
 
@@ -1496,7 +1479,7 @@ unsigned int Converter::ConvertMaterial( const Material& material, const MeshGeo
     return static_cast<unsigned int>( materials.size() - 1 );
 }
 
-unsigned int Converter::ConvertVideo( const Video& video )
+unsigned int FBXConverter::ConvertVideo( const Video& video )
 {
     // generate empty output texture
     aiTexture* out_tex = new aiTexture();
@@ -1526,7 +1509,47 @@ unsigned int Converter::ConvertVideo( const Video& video )
     return static_cast<unsigned int>( textures.size() - 1 );
 }
 
-void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap& textures,
+aiString FBXConverter::GetTexturePath(const Texture* tex)
+{
+    aiString path;
+    path.Set(tex->RelativeFilename());
+
+    const Video* media = tex->Media();
+    if (media != nullptr) {
+        bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
+        unsigned int index;
+
+        VideoMap::const_iterator it = textures_converted.find(media);
+        if (it != textures_converted.end()) {
+            index = (*it).second;
+            textureReady = true;
+        }
+        else {
+            if (media->ContentLength() > 0) {
+                index = ConvertVideo(*media);
+                textures_converted[media] = index;
+                textureReady = true;
+            }
+        }
+
+        // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
+        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 through the loaded textures after all data is processed
+                // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
+                // This may occur on this case too, it has to be studied
+                path.data[0] = '*';
+                path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
+            }
+        }
+    }
+
+    return path;
+}
+
+void FBXConverter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap& textures,
     const std::string& propName,
     aiTextureType target, const MeshGeometry* const mesh )
 {
@@ -1538,41 +1561,7 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
     const Texture* const tex = ( *it ).second;
     if ( tex != 0 )
     {
-        aiString path;
-        path.Set( tex->RelativeFilename() );
-
-        const Video* media = tex->Media();
-        if (media != 0) {
-			bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
-			unsigned int index;
-
-			VideoMap::const_iterator it = textures_converted.find(media);
-			if (it != textures_converted.end()) {
-				index = (*it).second;
-				textureReady = true;
-			}
-			else {
-				if (media->ContentLength() > 0) {
-					index = ConvertVideo(*media);
-					textures_converted[media] = index;
-					textureReady = true;
-				}
-			}
-
-			// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
-			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 through the loaded textures after all data is processed
-                    // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
-                    // This may occur on this case too, it has to be studied
-                    path.data[0] = '*';
-                    path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
-                }
-			}
-		}  
-
+        aiString path = GetTexturePath(tex);
         out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, 0 );
 
         aiUVTransform uvTrafo;
@@ -1678,7 +1667,7 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
     }
 }
 
-void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
+void FBXConverter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
         const std::string& propName,
         aiTextureType target, const MeshGeometry* const mesh ) {
     LayeredTextureMap::const_iterator it = layeredTextures.find( propName );
@@ -1696,9 +1685,7 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextu
     
         const Texture* const tex = ( *it ).second->getTexture(texIndex);
 
-        aiString path;
-        path.Set( tex->RelativeFilename() );
-
+        aiString path = GetTexturePath(tex);
         out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, texIndex );
 
         aiUVTransform uvTrafo;
@@ -1803,7 +1790,7 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextu
     }
 }
 
-void Converter::SetTextureProperties( aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh )
+void FBXConverter::SetTextureProperties( aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh )
 {
     TrySetTextureProperties( out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh );
     TrySetTextureProperties( out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh );
@@ -1818,7 +1805,7 @@ void Converter::SetTextureProperties( aiMaterial* out_mat, const TextureMap& tex
     TrySetTextureProperties( out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh );
 }
 
-void Converter::SetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh )
+void FBXConverter::SetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh )
 {
     TrySetTextureProperties( out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh );
     TrySetTextureProperties( out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh );
@@ -1833,7 +1820,7 @@ void Converter::SetTextureProperties( aiMaterial* out_mat, const LayeredTextureM
     TrySetTextureProperties( out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh );
 }
 
-aiColor3D Converter::GetColorPropertyFactored( const PropertyTable& props, const std::string& colorName,
+aiColor3D FBXConverter::GetColorPropertyFactored( const PropertyTable& props, const std::string& colorName,
     const std::string& factorName, bool& result, bool useTemplate )
 {
     result = true;
@@ -1858,13 +1845,13 @@ aiColor3D Converter::GetColorPropertyFactored( const PropertyTable& props, const
     return aiColor3D( BaseColor.x, BaseColor.y, BaseColor.z );
 }
 
-aiColor3D Converter::GetColorPropertyFromMaterial( const PropertyTable& props, const std::string& baseName,
+aiColor3D FBXConverter::GetColorPropertyFromMaterial( const PropertyTable& props, const std::string& baseName,
     bool& result )
 {
     return GetColorPropertyFactored( props, baseName + "Color", baseName + "Factor", result, true );
 }
 
-aiColor3D Converter::GetColorProperty( const PropertyTable& props, const std::string& colorName,
+aiColor3D FBXConverter::GetColorProperty( const PropertyTable& props, const std::string& colorName,
     bool& result, bool useTemplate )
 {
     result = true;
@@ -1877,7 +1864,7 @@ aiColor3D Converter::GetColorProperty( const PropertyTable& props, const std::st
     return aiColor3D( ColorVec.x, ColorVec.y, ColorVec.z );
 }
 
-void Converter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyTable& props )
+void FBXConverter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyTable& props )
 {
     // Set shading properties.
     // Modern FBX Files have two separate systems for defining these,
@@ -1976,60 +1963,60 @@ void Converter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyT
 }
 
 
-double Converter::FrameRateToDouble( FileGlobalSettings::FrameRate fp, double customFPSVal )
-{
+double FBXConverter::FrameRateToDouble( FileGlobalSettings::FrameRate fp, double customFPSVal ) {
     switch ( fp ) {
-    case FileGlobalSettings::FrameRate_DEFAULT:
-        return 1.0;
+        case FileGlobalSettings::FrameRate_DEFAULT:
+            return 1.0;
 
-    case FileGlobalSettings::FrameRate_120:
-        return 120.0;
+        case FileGlobalSettings::FrameRate_120:
+            return 120.0;
 
-    case FileGlobalSettings::FrameRate_100:
-        return 100.0;
+        case FileGlobalSettings::FrameRate_100:
+            return 100.0;
 
-    case FileGlobalSettings::FrameRate_60:
-        return 60.0;
+        case FileGlobalSettings::FrameRate_60:
+            return 60.0;
 
-    case FileGlobalSettings::FrameRate_50:
-        return 50.0;
+        case FileGlobalSettings::FrameRate_50:
+            return 50.0;
 
-    case FileGlobalSettings::FrameRate_48:
-        return 48.0;
+        case FileGlobalSettings::FrameRate_48:
+            return 48.0;
 
-    case FileGlobalSettings::FrameRate_30:
-    case FileGlobalSettings::FrameRate_30_DROP:
-        return 30.0;
+        case FileGlobalSettings::FrameRate_30:
+        case FileGlobalSettings::FrameRate_30_DROP:
+            return 30.0;
 
-    case FileGlobalSettings::FrameRate_NTSC_DROP_FRAME:
-    case FileGlobalSettings::FrameRate_NTSC_FULL_FRAME:
-        return 29.9700262;
+        case FileGlobalSettings::FrameRate_NTSC_DROP_FRAME:
+        case FileGlobalSettings::FrameRate_NTSC_FULL_FRAME:
+            return 29.9700262;
 
-    case FileGlobalSettings::FrameRate_PAL:
-        return 25.0;
+        case FileGlobalSettings::FrameRate_PAL:
+            return 25.0;
 
-    case FileGlobalSettings::FrameRate_CINEMA:
-        return 24.0;
+        case FileGlobalSettings::FrameRate_CINEMA:
+            return 24.0;
 
-    case FileGlobalSettings::FrameRate_1000:
-        return 1000.0;
+        case FileGlobalSettings::FrameRate_1000:
+            return 1000.0;
 
-    case FileGlobalSettings::FrameRate_CINEMA_ND:
-        return 23.976;
+        case FileGlobalSettings::FrameRate_CINEMA_ND:
+            return 23.976;
 
-    case FileGlobalSettings::FrameRate_CUSTOM:
-        return customFPSVal;
+        case FileGlobalSettings::FrameRate_CUSTOM:
+            return customFPSVal;
 
-    case FileGlobalSettings::FrameRate_MAX: // this is to silence compiler warnings
-        break;
+        case FileGlobalSettings::FrameRate_MAX: // this is to silence compiler warnings
+            break;
     }
 
     ai_assert( false );
+
     return -1.0f;
 }
 
 
-void Converter::ConvertAnimations()
+void FBXConverter::ConvertAnimations()
 {
     // first of all determine framerate
     const FileGlobalSettings::FrameRate fps = doc.GlobalSettings().TimeMode();
@@ -2042,7 +2029,7 @@ void Converter::ConvertAnimations()
     }
 }
 
-std::string Converter::FixNodeName( const std::string& name ) {
+std::string FBXConverter::FixNodeName( const std::string& name ) {
     // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if
     // this causes ambiguities, well possible between empty identifiers,
     // such as "Model::" and ""). Make sure the behaviour is consistent
@@ -2055,7 +2042,7 @@ std::string Converter::FixNodeName( const std::string& name ) {
     return name;
 }
 
-void Converter::ConvertAnimationStack( const AnimationStack& st )
+void FBXConverter::ConvertAnimationStack( const AnimationStack& st )
 {
     const AnimationLayerList& layers = st.Layers();
     if ( layers.empty() ) {
@@ -2197,7 +2184,7 @@ static void validateAnimCurveNodes( const std::vector<const AnimationCurveNode*>
 #endif // ASSIMP_BUILD_DEBUG
 
 // ------------------------------------------------------------------------------------------------
-void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
+void FBXConverter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
     const std::string& fixed_name,
     const std::vector<const AnimationCurveNode*>& curves,
     const LayerMap& layer_map,
@@ -2431,10 +2418,9 @@ void Converter::GenerateNodeAnimations( std::vector<aiNodeAnim*>& node_anims,
     node_anim_chain_bits[ fixed_name ] = flags;
 }
 
-bool Converter::IsRedundantAnimationData( const Model& target,
-    TransformationComp comp,
-    const std::vector<const AnimationCurveNode*>& curves )
-{
+bool FBXConverter::IsRedundantAnimationData( const Model& target,
+        TransformationComp comp,
+        const std::vector<const AnimationCurveNode*>& curves ) {
     ai_assert( curves.size() );
 
     // look for animation nodes with
@@ -2477,7 +2463,7 @@ bool Converter::IsRedundantAnimationData( const Model& target,
 }
 
 
-aiNodeAnim* Converter::GenerateRotationNodeAnim( const std::string& name,
+aiNodeAnim* FBXConverter::GenerateRotationNodeAnim( const std::string& name,
     const Model& target,
     const std::vector<const AnimationCurveNode*>& curves,
     const LayerMap& layer_map,
@@ -2507,7 +2493,7 @@ aiNodeAnim* Converter::GenerateRotationNodeAnim( const std::string& name,
     return na.release();
 }
 
-aiNodeAnim* Converter::GenerateScalingNodeAnim( const std::string& name,
+aiNodeAnim* FBXConverter::GenerateScalingNodeAnim( const std::string& name,
     const Model& /*target*/,
     const std::vector<const AnimationCurveNode*>& curves,
     const LayerMap& layer_map,
@@ -2537,16 +2523,14 @@ aiNodeAnim* Converter::GenerateScalingNodeAnim( const std::string& name,
     return na.release();
 }
 
-
-aiNodeAnim* Converter::GenerateTranslationNodeAnim( const std::string& name,
-    const Model& /*target*/,
-    const std::vector<const AnimationCurveNode*>& curves,
-    const LayerMap& layer_map,
-    int64_t start, int64_t stop,
-    double& max_time,
-    double& min_time,
-    bool inverse )
-{
+aiNodeAnim* FBXConverter::GenerateTranslationNodeAnim( const std::string& name,
+        const Model& /*target*/,
+        const std::vector<const AnimationCurveNode*>& curves,
+        const LayerMap& layer_map,
+        int64_t start, int64_t stop,
+        double& max_time,
+        double& min_time,
+        bool inverse ) {
     std::unique_ptr<aiNodeAnim> na( new aiNodeAnim() );
     na->mNodeName.Set( name );
 
@@ -2575,7 +2559,7 @@ aiNodeAnim* Converter::GenerateTranslationNodeAnim( const std::string& name,
     return na.release();
 }
 
-aiNodeAnim* Converter::GenerateSimpleNodeAnim( const std::string& name,
+aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim( const std::string& name,
     const Model& target,
     NodeMap::const_iterator chain[ TransformationComp_MAXIMUM ],
     NodeMap::const_iterator iter_end,
@@ -2711,7 +2695,7 @@ aiNodeAnim* Converter::GenerateSimpleNodeAnim( const std::string& name,
     return na.release();
 }
 
-Converter::KeyFrameListList Converter::GetKeyframeList( const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop )
+FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList( const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop )
 {
     KeyFrameListList inputs;
     inputs.reserve( nodes.size() * 3 );
@@ -2767,12 +2751,11 @@ Converter::KeyFrameListList Converter::GetKeyframeList( const std::vector<const
 }
 
 
-KeyTimeList Converter::GetKeyTimeList( const KeyFrameListList& inputs )
-{
-    ai_assert( inputs.size() );
+KeyTimeList FBXConverter::GetKeyTimeList( const KeyFrameListList& inputs ) {
+    ai_assert( !inputs.empty() );
 
-    // reserve some space upfront - it is likely that the keyframe lists
-    // have matching time values, so max(of all keyframe lists) should
+    // reserve some space upfront - it is likely that the key-frame lists
+    // have matching time values, so max(of all key-frame lists) should
     // be a good estimate.
     KeyTimeList keys;
 
@@ -2816,17 +2799,15 @@ KeyTimeList Converter::GetKeyTimeList( const KeyFrameListList& inputs )
     return keys;
 }
 
-void Converter::InterpolateKeys( aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
-    const aiVector3D& def_value,
-    double& max_time,
-    double& min_time )
-
-{
-    ai_assert( keys.size() );
-    ai_assert( valOut );
+void FBXConverter::InterpolateKeys( aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
+        const aiVector3D& def_value,
+        double& max_time,
+        double& min_time ) {
+    ai_assert( !keys.empty() );
+    ai_assert( nullptr != valOut );
 
     std::vector<unsigned int> next_pos;
-    const size_t count = inputs.size();
+    const size_t count( inputs.size() );
 
     next_pos.resize( inputs.size(), 0 );
 
@@ -2837,6 +2818,9 @@ void Converter::InterpolateKeys( aiVectorKey* valOut, const KeyTimeList& keys, c
             const KeyFrameList& kfl = inputs[ i ];
 
             const size_t ksize = std::get<0>(kfl)->size();
+            if (ksize == 0) {
+                continue;
+            }
             if ( ksize > next_pos[ i ] && std::get<0>(kfl)->at( next_pos[ i ] ) == time ) {
                 ++next_pos[ i ];
             }
@@ -2871,14 +2855,14 @@ void Converter::InterpolateKeys( aiVectorKey* valOut, const KeyTimeList& keys, c
     }
 }
 
-void Converter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
+void FBXConverter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs,
     const aiVector3D& def_value,
     double& maxTime,
     double& minTime,
     Model::RotOrder order )
 {
-    ai_assert( keys.size() );
-    ai_assert( valOut );
+    ai_assert( !keys.empty() );
+    ai_assert( nullptr != valOut );
 
     std::unique_ptr<aiVectorKey[]> temp( new aiVectorKey[ keys.size() ] );
     InterpolateKeys( temp.get(), keys, inputs, def_value, maxTime, minTime );
@@ -2909,7 +2893,7 @@ void Converter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, con
     }
 }
 
-void Converter::ConvertTransformOrder_TRStoSRT( aiQuatKey* out_quat, aiVectorKey* out_scale,
+void FBXConverter::ConvertTransformOrder_TRStoSRT( aiQuatKey* out_quat, aiVectorKey* out_scale,
     aiVectorKey* out_translation,
     const KeyFrameListList& scaling,
     const KeyFrameListList& translation,
@@ -2967,7 +2951,7 @@ void Converter::ConvertTransformOrder_TRStoSRT( aiQuatKey* out_quat, aiVectorKey
     }
 }
 
-aiQuaternion Converter::EulerToQuaternion( const aiVector3D& rot, Model::RotOrder order )
+aiQuaternion FBXConverter::EulerToQuaternion( const aiVector3D& rot, Model::RotOrder order )
 {
     aiMatrix4x4 m;
     GetRotationMatrix( order, rot, m );
@@ -2975,7 +2959,7 @@ aiQuaternion Converter::EulerToQuaternion( const aiVector3D& rot, Model::RotOrde
     return aiQuaternion( aiMatrix3x3( m ) );
 }
 
-void Converter::ConvertScaleKeys( aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
+void FBXConverter::ConvertScaleKeys( aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/,
     int64_t start, int64_t stop,
     double& maxTime,
     double& minTime )
@@ -2995,7 +2979,7 @@ void Converter::ConvertScaleKeys( aiNodeAnim* na, const std::vector<const Animat
         InterpolateKeys( na->mScalingKeys, keys, inputs, aiVector3D( 1.0f, 1.0f, 1.0f ), maxTime, minTime );
 }
 
-void Converter::ConvertTranslationKeys( aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
+void FBXConverter::ConvertTranslationKeys( aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
     const LayerMap& /*layers*/,
     int64_t start, int64_t stop,
     double& maxTime,
@@ -3013,7 +2997,7 @@ void Converter::ConvertTranslationKeys( aiNodeAnim* na, const std::vector<const
         InterpolateKeys( na->mPositionKeys, keys, inputs, aiVector3D( 0.0f, 0.0f, 0.0f ), maxTime, minTime );
 }
 
-void Converter::ConvertRotationKeys( aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
+void FBXConverter::ConvertRotationKeys( aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
     const LayerMap& /*layers*/,
     int64_t start, int64_t stop,
     double& maxTime,
@@ -3033,7 +3017,7 @@ void Converter::ConvertRotationKeys( aiNodeAnim* na, const std::vector<const Ani
     }
 }
 
-void Converter::ConvertGlobalSettings() {
+void FBXConverter::ConvertGlobalSettings() {
     if (nullptr == out) {
         return;
     }
@@ -3044,7 +3028,7 @@ void Converter::ConvertGlobalSettings() {
     out->mMetaData->Set(index, "UnitScaleFactor", unitScalFactor);
 }
 
-void Converter::TransferDataToScene()
+void FBXConverter::TransferDataToScene()
 {
     ai_assert( !out->mMeshes );
     ai_assert( !out->mNumMeshes );
@@ -3096,12 +3080,10 @@ void Converter::TransferDataToScene()
     }
 }
 
-//} // !anon
-
 // ------------------------------------------------------------------------------------------------
 void ConvertToAssimpScene(aiScene* out, const Document& doc)
 {
-    Converter converter(out,doc);
+    FBXConverter converter(out,doc);
 }
 
 } // !FBX

+ 9 - 5
code/FBXConverter.h

@@ -68,7 +68,7 @@ namespace FBX {
 
 class Document;
 
-using NodeNameCache = std::vector<std::string>;
+using NodeNameCache = std::set<std::string>;
 
 /** 
  *  Convert a FBX #Document to #aiScene
@@ -78,7 +78,7 @@ using NodeNameCache = std::vector<std::string>;
 void ConvertToAssimpScene(aiScene* out, const Document& doc);
 
 /** Dummy class to encapsulate the conversion process */
-class Converter {
+class FBXConverter {
 public:
     /**
     *  The different parts that make up the final local transformation of a fbx-node
@@ -106,8 +106,8 @@ public:
     };
 
 public:
-    Converter(aiScene* out, const Document& doc);
-    ~Converter();
+    FBXConverter(aiScene* out, const Document& doc);
+    ~FBXConverter();
 
 private:
     // ------------------------------------------------------------------------------------------------
@@ -131,7 +131,7 @@ private:
     void ConvertCamera( const Camera& cam, const std::string &orig_name );
 
     // ------------------------------------------------------------------------------------------------
-    void GetUniqueName( const std::string &name, std::string uniqueName );
+    void GetUniqueName( const std::string &name, std::string& uniqueName );
 
     // ------------------------------------------------------------------------------------------------
     // this returns unified names usable within assimp identifiers (i.e. no space characters -
@@ -228,6 +228,10 @@ private:
     // Video -> aiTexture
     unsigned int ConvertVideo(const Video& video);
 
+    // ------------------------------------------------------------------------------------------------
+    // convert embedded texture if necessary and return actual texture path
+    aiString GetTexturePath(const Texture* tex);
+
     // ------------------------------------------------------------------------------------------------
     void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
         const std::string& propName,

+ 1 - 1
code/FBXDocumentUtil.cpp

@@ -115,7 +115,7 @@ std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
         }
     }
 
-    if(!Properties70) {
+    if(!Properties70 || !Properties70->Compound()) {
         if(!no_warn) {
             DOMWarning("property table (Properties70) not found",&element);
         }

+ 7 - 3
code/FBXExporter.cpp

@@ -985,6 +985,10 @@ int64_t to_ktime(double ticks, const aiAnimation* anim) {
     return (static_cast<int64_t>(ticks) / static_cast<int64_t>(anim->mTicksPerSecond)) * FBX::SECOND;
 }
 
+int64_t to_ktime(double time) {
+    return (static_cast<int64_t>(time * FBX::SECOND));
+}
+
 void FBXExporter::WriteObjects ()
 {
     if (!binary) {
@@ -2089,7 +2093,7 @@ void FBXExporter::WriteObjects ()
             // position/translation
             for (size_t ki = 0; ki < na->mNumPositionKeys; ++ki) {
                 const aiVectorKey& k = na->mPositionKeys[ki];
-                times.push_back(to_ktime(k.mTime, anim));
+                times.push_back(to_ktime(k.mTime));
                 xval.push_back(k.mValue.x);
                 yval.push_back(k.mValue.y);
                 zval.push_back(k.mValue.z);
@@ -2103,7 +2107,7 @@ void FBXExporter::WriteObjects ()
             times.clear(); xval.clear(); yval.clear(); zval.clear();
             for (size_t ki = 0; ki < na->mNumRotationKeys; ++ki) {
                 const aiQuatKey& k = na->mRotationKeys[ki];
-                times.push_back(to_ktime(k.mTime, anim));
+                times.push_back(to_ktime(k.mTime));
                 // TODO: aiQuaternion method to convert to Euler...
                 aiMatrix4x4 m(k.mValue.GetMatrix());
                 aiVector3D qs, qr, qt;
@@ -2121,7 +2125,7 @@ void FBXExporter::WriteObjects ()
             times.clear(); xval.clear(); yval.clear(); zval.clear();
             for (size_t ki = 0; ki < na->mNumScalingKeys; ++ki) {
                 const aiVectorKey& k = na->mScalingKeys[ki];
-                times.push_back(to_ktime(k.mTime, anim));
+                times.push_back(to_ktime(k.mTime));
                 xval.push_back(k.mValue.x);
                 yval.push_back(k.mValue.y);
                 zval.push_back(k.mValue.z);

+ 3 - 0
code/FBXMeshGeometry.cpp

@@ -437,6 +437,9 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
     // deal with this more elegantly and with less redundancy, but right
     // now it seems unavoidable.
     if (MappingInformationType == "ByVertice" && isDirect) {
+        if (!HasElement(source, dataElementName)) {
+            return;
+        }
         std::vector<T> tempData;
 		ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName));
 

+ 6 - 6
code/FileSystemFilter.h

@@ -67,7 +67,7 @@ public:
     FileSystemFilter(const std::string& file, IOSystem* old)
     : mWrapped  (old)
     , mSrc_file(file)
-    , sep(mWrapped->getOsSeparator()) {
+    , mSep(mWrapped->getOsSeparator()) {
         ai_assert(nullptr != mWrapped);
 
         // Determine base directory
@@ -116,7 +116,7 @@ public:
     // -------------------------------------------------------------------
     /** Returns the directory separator. */
     char getOsSeparator() const {
-        return sep;
+        return mSep;
     }
 
     // -------------------------------------------------------------------
@@ -256,7 +256,7 @@ private:
 
             while(true) {
                 tmp = mBase;
-                tmp += sep;
+                tmp += mSep;
 
                 std::string::size_type dirsep = in.rfind('/', last_dirsep);
                 if (std::string::npos == dirsep) {
@@ -298,7 +298,7 @@ private:
             in.erase(in.begin(),it+1);
         }
 
-        const char sep = getOsSeparator();
+        const char separator = getOsSeparator();
         for (it = in.begin(); it != in.end(); ++it) {
             // Exclude :// and \\, which remain untouched.
             // https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632
@@ -313,7 +313,7 @@ private:
 
             // Cleanup path delimiters
             if (*it == '/' || (*it) == '\\') {
-                *it = sep;
+                *it = separator;
 
                 // And we're removing double delimiters, frequent issue with
                 // incorrectly composited paths ...
@@ -337,7 +337,7 @@ private:
 private:
     IOSystem *mWrapped;
     std::string mSrc_file, mBase;
-    char sep;
+    char mSep;
 };
 
 } //!ns Assimp

+ 4 - 2
code/GenFaceNormalsProcess.cpp

@@ -73,6 +73,7 @@ GenFaceNormalsProcess::~GenFaceNormalsProcess()
 // ------------------------------------------------------------------------------------------------
 // Returns whether the processing step is present in the given flag field.
 bool GenFaceNormalsProcess::IsActive( unsigned int pFlags) const {
+    force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
     return  (pFlags & aiProcess_GenNormals) != 0;
 }
 
@@ -105,7 +106,8 @@ void GenFaceNormalsProcess::Execute( aiScene* pScene) {
 bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
 {
     if (NULL != pMesh->mNormals) {
-        return false;
+        if (force_) delete[] pMesh->mNormals;
+        else return false;
     }
 
     // If the mesh consists of lines and/or points but not of
@@ -134,7 +136,7 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
         const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
         const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
         const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
-        const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).Normalize();
+        const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
 
         for (unsigned int i = 0;i < face.mNumIndices;++i) {
             pMesh->mNormals[face.mIndices[i]] = vNor;

+ 2 - 1
code/GenFaceNormalsProcess.h

@@ -78,7 +78,8 @@ public:
 
 
 private:
-    bool GenMeshFaceNormals (aiMesh* pcMesh);
+    bool GenMeshFaceNormals(aiMesh* pcMesh);
+    mutable bool force_ = false;
 };
 
 } // end of namespace Assimp

+ 10 - 9
code/GenVertexNormalsProcess.cpp

@@ -72,6 +72,7 @@ GenVertexNormalsProcess::~GenVertexNormalsProcess() {
 // Returns whether the processing step is present in the given flag field.
 bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const
 {
+    force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
     return (pFlags & aiProcess_GenSmoothNormals) != 0;
 }
 
@@ -113,8 +114,10 @@ void GenVertexNormalsProcess::Execute( aiScene* pScene)
 // Executes the post processing step on the given imported data.
 bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex)
 {
-    if (NULL != pMesh->mNormals)
-        return false;
+    if (NULL != pMesh->mNormals) {
+        if (force_) delete[] pMesh->mNormals;
+        else return false;
+    }
 
     // If the mesh consists of lines and/or points but not of
     // triangles or higher-order polygons the normal vectors
@@ -146,7 +149,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
         const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
         const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
         const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
-        const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1));
+        const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
 
         for (unsigned int i = 0;i < face.mNumIndices;++i) {
             pMesh->mNormals[face.mIndices[i]] = vNor;
@@ -214,17 +217,15 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
             vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound);
 
             aiVector3D vr = pMesh->mNormals[i];
-            ai_real vrlen = vr.Length();
 
             aiVector3D pcNor;
             for (unsigned int a = 0; a < verticesFound.size(); ++a) {
                 aiVector3D v = pMesh->mNormals[verticesFound[a]];
 
-                // check whether the angle between the two normals is not too large
-                // HACK: if v.x is qnan the dot product will become qnan, too
-                //   therefore the comparison against fLimit should be false
-                //   in every case.
-                if (v * vr >= fLimit * vrlen * v.Length())
+                // Check whether the angle between the two normals is not too large.
+                // Skip the angle check on our own normal to avoid false negatives
+                // (v*v is not guaranteed to be 1.0 for all unit vectors v)
+                if (is_not_qnan(v.x) && (verticesFound[a] == i || (v * vr >= fLimit)))
                     pcNor += v;
             }
             pcNew[i] = pcNor.NormalizeSafe();

+ 1 - 0
code/GenVertexNormalsProcess.h

@@ -107,6 +107,7 @@ private:
 
     /** Configuration option: maximum smoothing angle, in radians*/
     ai_real configMaxAngle;
+    mutable bool force_ = false;
 };
 
 } // end of namespace Assimp

+ 20 - 17
code/Importer.cpp

@@ -383,6 +383,7 @@ bool _ValidateFlags(unsigned int pFlags)
 void Importer::FreeScene( )
 {
     ASSIMP_BEGIN_EXCEPTION_REGION();
+
     delete pimpl->mScene;
     pimpl->mScene = NULL;
 
@@ -490,9 +491,9 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
     SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength));
 
     // read the file and recover the previous IOSystem
-    static const size_t BufferSize(Importer::MaxLenHint + 28);
-    char fbuff[ BufferSize ];
-    ai_snprintf(fbuff, BufferSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
+    static const size_t BufSize(Importer::MaxLenHint + 28);
+    char fbuff[BufSize];
+    ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
 
     ReadFile(fbuff,pFlags);
     SetIOHandler(io);
@@ -930,20 +931,19 @@ BaseImporter* Importer::GetImporter (const char* szExtension) const
 
 // ------------------------------------------------------------------------------------------------
 // Find a loader plugin for a given file extension
-size_t Importer::GetImporterIndex (const char* szExtension) const
-{
-    ai_assert(szExtension);
+size_t Importer::GetImporterIndex (const char* szExtension) const {
+    ai_assert(nullptr != szExtension);
 
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
     // skip over wildcard and dot characters at string head --
-    for(;*szExtension == '*' || *szExtension == '.'; ++szExtension);
+    for ( ; *szExtension == '*' || *szExtension == '.'; ++szExtension );
 
     std::string ext(szExtension);
     if (ext.empty()) {
         return static_cast<size_t>(-1);
     }
-    std::transform(ext.begin(),ext.end(), ext.begin(), tolower);
+    std::transform( ext.begin(), ext.end(), ext.begin(), ToLower<char> );
 
     std::set<std::string> str;
     for (std::vector<BaseImporter*>::const_iterator i =  pimpl->mImporter.begin();i != pimpl->mImporter.end();++i)  {
@@ -970,15 +970,18 @@ void Importer::GetExtensionList(aiString& szOut) const
         (*i)->GetExtensionList(str);
     }
 
-    for (std::set<std::string>::const_iterator it = str.begin();; ) {
-        szOut.Append("*.");
-        szOut.Append((*it).c_str());
-
-        if (++it == str.end()) {
-            break;
-        }
-        szOut.Append(";");
-    }
+	// List can be empty
+	if( !str.empty() ) {
+		for (std::set<std::string>::const_iterator it = str.begin();; ) {
+			szOut.Append("*.");
+			szOut.Append((*it).c_str());
+
+			if (++it == str.end()) {
+				break;
+			}
+			szOut.Append(";");
+		}
+	}
     ASSIMP_END_EXCEPTION_REGION(void);
 }
 

+ 2 - 2
code/Importer.h

@@ -120,11 +120,11 @@ public:
     SharedPostProcessInfo* mPPShared;
 
     /// The default class constructor.
-    ImporterPimpl();
+    ImporterPimpl() AI_NO_EXCEPT;
 };
 
 inline
-ImporterPimpl::ImporterPimpl()
+ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT
 : mIOHandler( nullptr )
 , mIsDefaultHandler( false )
 , mProgressHandler( nullptr )

+ 1 - 1
code/Importer/IFC/IFCGeometry.cpp

@@ -317,7 +317,7 @@ void ProcessRevolvedAreaSolid(const Schema_2x3::IfcRevolvedAreaSolid& solid, Tem
 }
 
 // ------------------------------------------------------------------------------------------------
-void ProcessSweptDiskSolid(const Schema_2x3::IfcSweptDiskSolid solid, TempMesh& result, ConversionData& conv)
+void ProcessSweptDiskSolid(const Schema_2x3::IfcSweptDiskSolid &solid, TempMesh& result, ConversionData& conv)
 {
     const Curve* const curve = Curve::Convert(*solid.Directrix, conv);
     if(!curve) {

+ 18 - 0
code/JoinVerticesProcess.cpp

@@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Vertex.h>
 #include <assimp/TinyFormatter.h>
 #include <stdio.h>
+#include <unordered_set>
 
 using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
@@ -239,6 +240,19 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
         return 0;
     }
 
+    // We should care only about used vertices, not all of them
+    // (this can happen due to original file vertices buffer being used by
+    // multiple meshes)
+    std::unordered_set<unsigned int> usedVertexIndices;
+    usedVertexIndices.reserve(pMesh->mNumVertices);
+    for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
+    {
+        aiFace& face = pMesh->mFaces[a];
+        for( unsigned int b = 0; b < face.mNumIndices; b++) {
+            usedVertexIndices.insert(face.mIndices[b]);
+        }
+    }
+
     // We'll never have more vertices afterwards.
     std::vector<Vertex> uniqueVertices;
     uniqueVertices.reserve( pMesh->mNumVertices);
@@ -292,6 +306,10 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
 
     // Now check each vertex if it brings something new to the table
     for( unsigned int a = 0; a < pMesh->mNumVertices; a++)  {
+        if (usedVertexIndices.find(a) == usedVertexIndices.end()) {
+            continue;
+        }
+
         // collect the vertex data
         Vertex v(pMesh,a);
 

+ 19 - 20
code/LWOAnimation.h

@@ -113,14 +113,14 @@ enum PrePostBehaviour
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a LWO animation keyframe
  */
-struct Key
-{
-    Key()
-        : time(),
-        value(),
-        inter   (IT_LINE),
-        params()
-    {}
+struct Key {
+    Key() AI_NO_EXCEPT 
+    : time()
+    , value()
+    , inter(IT_LINE)
+    , params() {
+        // empty
+    }
 
     //! Current time
     double time;
@@ -144,17 +144,16 @@ struct Key
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a LWO animation envelope
  */
-struct Envelope
-{
-    Envelope()
-        :   index()
-        ,   type    (EnvelopeType_Unknown)
-        ,   pre     (PrePostBehaviour_Constant)
-        ,   post    (PrePostBehaviour_Constant)
-
-        ,   old_first (0)
-        ,   old_last  (0)
-    {}
+struct Envelope {
+    Envelope() AI_NO_EXCEPT
+    : index()
+    , type(EnvelopeType_Unknown)
+    , pre(PrePostBehaviour_Constant)
+    , post(PrePostBehaviour_Constant)
+    , old_first(0)
+    , old_last(0) {
+        // empty
+    }
 
     //! Index of this envelope
     unsigned int index;
@@ -162,7 +161,7 @@ struct Envelope
     //! Type of envelope
     EnvelopeType type;
 
-    //! Pre and post-behaviour
+    //! Pre- and post-behavior
     PrePostBehaviour pre,post;
 
     //! Keyframes for this envelope

+ 7 - 7
code/LWOFileData.h

@@ -261,14 +261,14 @@ namespace LWO {
  * \note We can't use the code in SmoothingGroups.inl here - the mesh
  *   structures of 3DS/ASE and LWO are too different.
  */
-struct Face : public aiFace
-{
+struct Face : public aiFace {
     //! Default construction
-    Face()
-        : surfaceIndex  (0)
-        , smoothGroup   (0)
-        , type          (AI_LWO_FACE)
-    {}
+    Face() AI_NO_EXCEPT
+    : surfaceIndex( 0 )
+    , smoothGroup( 0 )
+    , type( AI_LWO_FACE ) {
+        // empty
+    }
 
     //! Construction from given type
     explicit Face(uint32_t _type)

+ 4 - 2
code/LWOMaterial.cpp

@@ -253,7 +253,8 @@ bool LWOImporter::HandleTextures(aiMaterial* pcMat, const TextureList& in, aiTex
         pcMat->AddProperty<int>((int*)&temp,1,AI_MATKEY_TEXOP(type,cur));
 
         // setup the mapping mode
-        pcMat->AddProperty<int>((int*)&mapping,1,AI_MATKEY_MAPPING(type,cur));
+        int mapping_ = static_cast<int>(mapping);
+        pcMat->AddProperty<int>(&mapping_, 1, AI_MATKEY_MAPPING(type, cur));
 
         // add the u-wrapping
         temp = (unsigned int)GetMapMode(texture.wrapModeWidth);
@@ -365,7 +366,8 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat)
     }
     if (surf.mMaximumSmoothAngle <= 0.0)
         m = aiShadingMode_Flat;
-    pcMat->AddProperty((int*)&m,1,AI_MATKEY_SHADING_MODEL);
+    int m_ = static_cast<int>(m);
+    pcMat->AddProperty(&m_, 1, AI_MATKEY_SHADING_MODEL);
 
     // (the diffuse value is just a scaling factor)
     // If a diffuse texture is set, we set this value to 1.0

+ 1 - 1
code/LimitBoneWeightsProcess.h

@@ -120,7 +120,7 @@ public:
     {
         unsigned int mBone; ///< Index of the bone
         float mWeight;      ///< Weight of that bone on this vertex
-        Weight()
+        Weight() AI_NO_EXCEPT
         : mBone(0)
         , mWeight(0.0f)
         { }

+ 2 - 2
code/MD3Loader.h

@@ -125,7 +125,7 @@ enum AlphaTestFunc
  */
 struct ShaderMapBlock
 {
-    ShaderMapBlock()
+    ShaderMapBlock() AI_NO_EXCEPT
          :  blend_src   (BLEND_NONE)
          ,  blend_dest  (BLEND_NONE)
          ,  alpha_test  (AT_NONE)
@@ -150,7 +150,7 @@ struct ShaderMapBlock
  */
 struct ShaderDataBlock
 {
-    ShaderDataBlock()
+    ShaderDataBlock() AI_NO_EXCEPT
         :   cull    (CULL_CW)
     {}
 

+ 7 - 7
code/MD5Parser.h

@@ -192,14 +192,14 @@ typedef std::vector< FrameDesc > FrameList;
 // ---------------------------------------------------------------------------
 /** Represents a vertex  descriptor in a MD5 file
 */
-struct VertexDesc
-{
-    VertexDesc()
-        : mFirstWeight  (0)
-        , mNumWeights   (0)
-    {}
+struct VertexDesc {
+    VertexDesc() AI_NO_EXCEPT
+    : mFirstWeight(0)
+    , mNumWeights(0) {
+        // empty
+    }
 
-    //! UV cordinate of the vertex
+    //! UV coordinate of the vertex
     aiVector2D mUV;
 
     //! Index of the first weight of the vertex in

+ 26 - 38
code/MDCFileData.h

@@ -61,7 +61,6 @@ http://themdcfile.planetwolfenstein.gamespy.com/MDC_File_Format.pdf
 namespace Assimp {
 namespace MDC {
 
-
 // to make it easier for us, we test the magic word against both "endianesses"
 #define AI_MDC_MAGIC_NUMBER_BE  AI_MAKE_MAGIC("CPDI")
 #define AI_MDC_MAGIC_NUMBER_LE  AI_MAKE_MAGIC("IDPC")
@@ -79,8 +78,7 @@ namespace MDC {
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a MDC file's main header
  */
-struct Header
-{
+struct Header {
     uint32_t ulIdent ;
     uint32_t ulVersion ;
     char ucName [ AI_MDC_MAXQPATH ] ;
@@ -100,8 +98,7 @@ struct Header
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a MDC file's surface header
  */
-struct Surface
-{
+struct Surface {
     uint32_t ulIdent ;
     char ucName [ AI_MDC_MAXQPATH ] ;
     uint32_t ulFlags ;
@@ -118,23 +115,22 @@ struct Surface
     uint32_t ulOffsetFrameBaseFrames ;
     uint32_t ulOffsetFrameCompFrames ;
     uint32_t ulOffsetEnd;
-    Surface()
-        : ulIdent(),
-        ulFlags(),
-        ulNumCompFrames(),
-        ulNumBaseFrames(),
-        ulNumShaders(),
-        ulNumVertices(),
-        ulNumTriangles(),
-        ulOffsetTriangles(),
-        ulOffsetShaders(),
-        ulOffsetTexCoords(),
-        ulOffsetBaseVerts(),
-        ulOffsetCompVerts(),
-        ulOffsetFrameBaseFrames(),
-        ulOffsetFrameCompFrames(),
-        ulOffsetEnd()
-    {
+    Surface() AI_NO_EXCEPT
+    : ulIdent()
+    , ulFlags()
+    , ulNumCompFrames()
+    , ulNumBaseFrames()
+    , ulNumShaders() 
+    , ulNumVertices()
+    , ulNumTriangles()
+    , ulOffsetTriangles()
+    , ulOffsetShaders()
+    , ulOffsetTexCoords()
+    , ulOffsetBaseVerts() 
+    , ulOffsetCompVerts()
+    , ulOffsetFrameBaseFrames()
+    , ulOffsetFrameCompFrames()
+    , ulOffsetEnd() {
         ucName[AI_MDC_MAXQPATH-1] = '\0';
     }
 } PACK_STRUCT;
@@ -142,8 +138,7 @@ struct Surface
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a MDC frame
  */
-struct Frame
-{
+struct Frame {
     //! bounding box minimum coords
     aiVector3D bboxMin ;
 
@@ -163,24 +158,21 @@ struct Frame
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a MDC triangle
  */
-struct Triangle
-{
+struct Triangle {
     uint32_t aiIndices[3];
 } PACK_STRUCT;
 
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a MDC texture coordinate
  */
-struct TexturCoord
-{
+struct TexturCoord {
     float u,v;
 } PACK_STRUCT;
 
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a MDC base vertex
  */
-struct BaseVertex
-{
+struct BaseVertex {
     int16_t x,y,z;
     uint16_t normal;
 } PACK_STRUCT;
@@ -188,25 +180,20 @@ struct BaseVertex
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a MDC compressed vertex
  */
-struct CompressedVertex
-{
+struct CompressedVertex {
     uint8_t xd,yd,zd,nd;
 } PACK_STRUCT;
 
-
 // ---------------------------------------------------------------------------
 /** \brief Data structure for a MDC shader
  */
-struct Shader
-{
+struct Shader {
     char ucName [ AI_MDC_MAXQPATH ] ;
     uint32_t ulPath;
-
 } PACK_STRUCT;
 
 #include <assimp/Compiler/poppack1.h>
 
-
 // ---------------------------------------------------------------------------
 /** Build a floating point vertex from the compressed data in MDC files
  */
@@ -215,6 +202,7 @@ void BuildVertex(const Frame& frame,
     const CompressedVertex& cvert,
     aiVector3D& vXYZOut,
     aiVector3D& vNorOut);
-}}
+}
+}
 
 #endif // !! AI_MDCFILEHELPER_H_INC

+ 6 - 4
code/MDCLoader.cpp

@@ -434,10 +434,12 @@ void MDCImporter::InternReadFile(
     else if (1 == pScene->mNumMeshes)
     {
         pScene->mRootNode = new aiNode();
-        pScene->mRootNode->mName = pScene->mMeshes[0]->mName;
-        pScene->mRootNode->mNumMeshes = 1;
-        pScene->mRootNode->mMeshes = new unsigned int[1];
-        pScene->mRootNode->mMeshes[0] = 0;
+        if ( nullptr != pScene->mMeshes[0] ) {
+            pScene->mRootNode->mName = pScene->mMeshes[0]->mName;
+            pScene->mRootNode->mNumMeshes = 1;
+            pScene->mRootNode->mMeshes = new unsigned int[1];
+            pScene->mRootNode->mMeshes[0] = 0;
+        }
     }
     else
     {

+ 16 - 21
code/MDLFileData.h

@@ -717,11 +717,9 @@ struct GroupFrame
  */
 struct IntFace_MDL7 {
     // provide a constructor for our own convenience
-    IntFace_MDL7()
-    {
-        // set everything to zero
-        mIndices[0] = mIndices[1] = mIndices[2] = 0;
-        iMatIndex[0] = iMatIndex[1] = 0;
+    IntFace_MDL7() AI_NO_EXCEPT {
+        ::memset( mIndices, 0, sizeof(uint32_t) *3);
+        ::memset( iMatIndex, 0, sizeof( unsigned int) *2);
     }
 
     //! Vertex indices
@@ -737,13 +735,11 @@ struct IntFace_MDL7 {
  *  which has been created from two single materials along with the
  *  original material indices.
  */
-struct IntMaterial_MDL7
-{
+struct IntMaterial_MDL7 {
     // provide a constructor for our own convenience
-    IntMaterial_MDL7()
-    {
-        pcMat = NULL;
-        iOldMatIndices[0] = iOldMatIndices[1] = 0;
+    IntMaterial_MDL7() AI_NO_EXCEPT
+    : pcMat( nullptr ) {
+        ::memset( iOldMatIndices, 0, sizeof(unsigned int) *2);
     }
 
     //! Material instance
@@ -761,7 +757,7 @@ struct IntMaterial_MDL7
 struct IntBone_MDL7 : aiBone
 {
     //! Default constructor
-    IntBone_MDL7() : iParent (0xffff)
+    IntBone_MDL7() AI_NO_EXCEPT : iParent (0xffff)
     {
         pkeyPositions.reserve(30);
         pkeyScalings.reserve(30);
@@ -806,12 +802,12 @@ struct IntFrameInfo_MDL7
 struct IntGroupInfo_MDL7
 {
     //! Default constructor
-    IntGroupInfo_MDL7()
+    IntGroupInfo_MDL7() AI_NO_EXCEPT
         :   iIndex(0)
-        ,   pcGroup(NULL)
-        ,   pcGroupUVs(NULL)
-        ,   pcGroupTris(NULL)
-        ,   pcGroupVerts(NULL)
+        ,   pcGroup(nullptr)
+        ,   pcGroupUVs(nullptr)
+        ,   pcGroupTris(nullptr)
+        ,   pcGroupVerts(nullptr)
         {}
 
     //! Construction from an existing group header
@@ -843,7 +839,7 @@ struct IntGroupInfo_MDL7
 //! Holds the data that belongs to a MDL7 mesh group
 struct IntGroupData_MDL7
 {
-    IntGroupData_MDL7()
+    IntGroupData_MDL7() AI_NO_EXCEPT
         : bNeed2UV(false)
     {}
 
@@ -872,10 +868,9 @@ struct IntGroupData_MDL7
 
 // -------------------------------------------------------------------------------------
 //! Holds data from an MDL7 file that is shared by all mesh groups
-struct IntSharedData_MDL7
-{
+struct IntSharedData_MDL7 {
     //! Default constructor
-    IntSharedData_MDL7()
+    IntSharedData_MDL7() AI_NO_EXCEPT
         : apcOutBones(),
         iNum()
     {

+ 9 - 37
code/MMDPmxParser.cpp

@@ -41,6 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #include <utility>
 #include "MMDPmxParser.h"
+#include <assimp/StringUtils.h>
 #include "../contrib/utf8cpp/source/utf8.h"
 #include <assimp/Exceptional.h>
 
@@ -118,7 +119,7 @@ namespace pmx
 		stream->read((char*) &count, sizeof(uint8_t));
 		if (count < 8)
 		{
-			throw;
+			throw DeadlyImportError("MMD: invalid size");
 		}
 		stream->read((char*) &encoding, sizeof(uint8_t));
 		stream->read((char*) &uv, sizeof(uint8_t));
@@ -395,7 +396,7 @@ namespace pmx
 			}
 			break;
 		default:
-			throw;
+            throw DeadlyImportError("MMD: unknown morth type");
 		}
 	}
 
@@ -476,8 +477,8 @@ namespace pmx
 	{
 		// 未実装
 		std::cerr << "Not Implemented Exception" << std::endl;
-		throw;
-	}
+        throw DeadlyImportError("MMD: Not Implemented Exception");
+    }
 
 	void PmxModel::Init()
 	{
@@ -516,15 +517,15 @@ namespace pmx
 		if (magic[0] != 0x50 || magic[1] != 0x4d || magic[2] != 0x58 || magic[3] != 0x20)
 		{
 			std::cerr << "invalid magic number." << std::endl;
-			throw;
-		}
+            throw DeadlyImportError("MMD: invalid magic number.");
+        }
 		// バージョン
 		stream->read((char*) &version, sizeof(float));
 		if (version != 2.0f && version != 2.1f)
 		{
 			std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl;
-			throw;
-		}
+            throw DeadlyImportError("MMD: this is not ver2.0 or ver2.1 but " + to_string(version));
+        }
 		// ファイル設定
 		this->setting.Read(stream);
 
@@ -605,34 +606,5 @@ namespace pmx
 		{
 			this->joints[i].Read(stream, &setting);
 		}
-
-		//if (this->version == 2.1f)
-		//{
-		//	stream->read((char*) &this->soft_body_count, sizeof(int));
-		//	this->soft_bodies = mmd::make_unique<PmxSoftBody []>(this->soft_body_count);
-		//	for (int i = 0; i < this->soft_body_count; i++)
-		//	{
-		//		this->soft_bodies[i].Read(stream, &setting);
-		//	}
-		//}
 	}
-
-	//std::unique_ptr<PmxModel> ReadFromFile(const char *filename)
-	//{
-	//	auto stream = std::ifstream(filename, std::ios_base::binary);
-	//	auto pmx = PmxModel::ReadFromStream(&stream);
-	//	if (!stream.eof())
-	//	{
-	//		std::cerr << "don't reach the end of file." << std::endl;
-	//	}
-	//	stream.close();
-	//	return pmx;
-	//}
-
-	//std::unique_ptr<PmxModel> ReadFromStream(std::istream *stream)
-	//{
-	//	auto pmx = mmd::make_unique<PmxModel>();
-	//	pmx->Read(stream);
-	//	return pmx;
-	//}
 }

+ 39 - 26
code/MaterialSystem.cpp

@@ -63,9 +63,9 @@ aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
     unsigned int index,
     const aiMaterialProperty** pPropOut)
 {
-    ai_assert (pMat != NULL);
-    ai_assert (pKey != NULL);
-    ai_assert (pPropOut != NULL);
+    ai_assert( pMat != NULL );
+    ai_assert( pKey != NULL );
+    ai_assert( pPropOut != NULL );
 
     /*  Just search for a property with exactly this name ..
      *  could be improved by hashing, but it's possibly
@@ -76,7 +76,7 @@ aiReturn aiGetMaterialProperty(const aiMaterial* pMat,
 
         if (prop /* just for safety ... */
             && 0 == strcmp( prop->mKey.data, pKey )
-            && (UINT_MAX == type  || prop->mSemantic == type) /* UINT_MAX is a wildcard, but this is undocumented :-) */
+            && (UINT_MAX == type  || prop->mSemantic == type) /* UINT_MAX is a wild-card, but this is undocumented :-) */
             && (UINT_MAX == index || prop->mIndex == index))
         {
             *pPropOut = pMat->mProperties[i];
@@ -96,8 +96,8 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
     ai_real* pOut,
     unsigned int* pMax)
 {
-    ai_assert (pOut != NULL);
-    ai_assert (pMat != NULL);
+    ai_assert( pOut != NULL );
+    ai_assert( pMat != NULL );
 
     const aiMaterialProperty* prop;
     aiGetMaterialProperty(pMat,pKey,type,index, (const aiMaterialProperty**) &prop);
@@ -182,8 +182,8 @@ aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat,
     int* pOut,
     unsigned int* pMax)
 {
-    ai_assert (pOut != NULL);
-    ai_assert (pMat != NULL);
+    ai_assert( pOut != NULL );
+    ai_assert( pMat != NULL );
 
     const aiMaterialProperty* prop;
     aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**) &prop);
@@ -274,7 +274,7 @@ aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat,
     aiUVTransform* pOut)
 {
     unsigned int iMax = 4;
-    return  aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax);
+    return aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -314,7 +314,7 @@ aiReturn aiGetMaterialString(const aiMaterial* pMat,
 
 // ------------------------------------------------------------------------------------------------
 // Get the number of textures on a particular texture stack
-ASSIMP_API unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMat,
+unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMat,
     C_ENUM aiTextureType type)
 {
     ai_assert (pMat != NULL);
@@ -347,15 +347,18 @@ aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat,
     unsigned int* flags         /*= NULL*/
     )
 {
-    ai_assert(NULL != mat && NULL != path);
+    ai_assert( NULL != mat );
+    ai_assert( NULL != path );
 
     // Get the path to the texture
     if (AI_SUCCESS != aiGetMaterialString(mat,AI_MATKEY_TEXTURE(type,index),path))  {
         return AI_FAILURE;
     }
+
     // Determine mapping type
-    aiTextureMapping mapping = aiTextureMapping_UV;
-    aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index),(int*)&mapping);
+    int mapping_ = static_cast<int>(aiTextureMapping_UV);
+    aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index), &mapping_);
+    aiTextureMapping mapping = static_cast<aiTextureMapping>(mapping_);
     if (_mapping)
         *_mapping = mapping;
 
@@ -380,15 +383,17 @@ aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat,
     if (flags){
         aiGetMaterialInteger(mat,AI_MATKEY_TEXFLAGS(type,index),(int*)flags);
     }
+
     return AI_SUCCESS;
 }
 
+
 static const unsigned int DefaultNumAllocated = 5;
 
 // ------------------------------------------------------------------------------------------------
 // Construction. Actually the one and only way to get an aiMaterial instance
 aiMaterial::aiMaterial() 
-: mProperties( NULL )
+: mProperties( nullptr )
 , mNumProperties( 0 )
 , mNumAllocated( DefaultNumAllocated ) {
     // Allocate 5 entries by default
@@ -403,12 +408,20 @@ aiMaterial::~aiMaterial()
     delete[] mProperties;
 }
 
+// ------------------------------------------------------------------------------------------------
+aiString aiMaterial::GetName() {
+    aiString name;
+    Get(AI_MATKEY_NAME, name);
+
+    return name;
+}
+
 // ------------------------------------------------------------------------------------------------
 void aiMaterial::Clear()
 {
-    for (unsigned int i = 0; i < mNumProperties;++i)    {
+    for ( unsigned int i = 0; i < mNumProperties; ++i )    {
         // delete this entry
-        delete mProperties[i];
+        delete mProperties[ i ];
         AI_DEBUG_INVALIDATE_PTR(mProperties[i]);
     }
     mNumProperties = 0;
@@ -417,11 +430,9 @@ void aiMaterial::Clear()
 }
 
 // ------------------------------------------------------------------------------------------------
-aiReturn aiMaterial::RemoveProperty (const char* pKey,unsigned int type,
-    unsigned int index
-    )
+aiReturn aiMaterial::RemoveProperty ( const char* pKey,unsigned int type, unsigned int index )
 {
-    ai_assert(NULL != pKey);
+    ai_assert( nullptr != pKey );
 
     for (unsigned int i = 0; i < mNumProperties;++i) {
         aiMaterialProperty* prop = mProperties[i];
@@ -453,17 +464,18 @@ aiReturn aiMaterial::AddBinaryProperty (const void* pInput,
     aiPropertyTypeInfo pType
     )
 {
-    ai_assert (pInput != NULL);
-    ai_assert (pKey != NULL);
-    ai_assert (0 != pSizeInBytes);
+    ai_assert( pInput != NULL );
+    ai_assert( pKey != NULL );
+    ai_assert( 0 != pSizeInBytes );
 
     if ( 0 == pSizeInBytes ) {
 
     }
+
     // first search the list whether there is already an entry with this key
-    unsigned int iOutIndex = UINT_MAX;
-    for (unsigned int i = 0; i < mNumProperties;++i)    {
-        aiMaterialProperty* prop = mProperties[i];
+    unsigned int iOutIndex( UINT_MAX );
+    for ( unsigned int i = 0; i < mNumProperties; ++i ) {
+        aiMaterialProperty *prop( mProperties[ i ] );
 
         if (prop /* just for safety */ && !strcmp( prop->mKey.data, pKey ) &&
             prop->mSemantic == type && prop->mIndex == index){
@@ -515,6 +527,7 @@ aiReturn aiMaterial::AddBinaryProperty (const void* pInput,
     }
     // push back ...
     mProperties[mNumProperties++] = pcNew;
+
     return AI_SUCCESS;
 }
 

+ 89 - 54
code/ObjFileImporter.cpp

@@ -76,41 +76,36 @@ using namespace std;
 
 // ------------------------------------------------------------------------------------------------
 //  Default constructor
-ObjFileImporter::ObjFileImporter() :
-    m_Buffer(),
-    m_pRootObject( NULL ),
-    m_strAbsPath( "" )
-{
+ObjFileImporter::ObjFileImporter()
+: m_Buffer()
+, m_pRootObject( nullptr )
+, m_strAbsPath( "" ) {
     DefaultIOSystem io;
     m_strAbsPath = io.getOsSeparator();
 }
 
 // ------------------------------------------------------------------------------------------------
 //  Destructor.
-ObjFileImporter::~ObjFileImporter()
-{
+ObjFileImporter::~ObjFileImporter() {
     delete m_pRootObject;
-    m_pRootObject = NULL;
+    m_pRootObject = nullptr;
 }
 
 // ------------------------------------------------------------------------------------------------
 //  Returns true, if file is an obj file.
-bool ObjFileImporter::CanRead( const std::string& pFile, IOSystem*  pIOHandler , bool checkSig ) const
-{
-    if(!checkSig) //Check File Extension
-    {
+bool ObjFileImporter::CanRead( const std::string& pFile, IOSystem*  pIOHandler , bool checkSig ) const {
+    if(!checkSig)  {
+        //Check File Extension
         return SimpleExtensionCheck(pFile,"obj");
-    }
-    else //Check file Header
-    {
+    } else {
+        // Check file Header
         static const char *pTokens[] = { "mtllib", "usemtl", "v ", "vt ", "vn ", "o ", "g ", "s ", "f " };
-        return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9 );
+        return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 9, 200, false, true );
     }
 }
 
 // ------------------------------------------------------------------------------------------------
-const aiImporterDesc* ObjFileImporter::GetInfo () const
-{
+const aiImporterDesc* ObjFileImporter::GetInfo () const {
     return &desc;
 }
 
@@ -215,22 +210,80 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene
         ai_assert(false);
     }
 
-    // Create nodes for the whole scene
-    std::vector<aiMesh*> MeshArray;
-    for (size_t index = 0; index < pModel->m_Objects.size(); ++index ) {
-        createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray);
-    }
+    if (pModel->m_Objects.size() > 0) {
 
-    // Create mesh pointer buffer for this scene
-    if (pScene->mNumMeshes > 0) {
-        pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
-        for (size_t index =0; index < MeshArray.size(); ++index ) {
-            pScene->mMeshes[ index ] = MeshArray[ index ];
+        unsigned int meshCount = 0;
+        unsigned int childCount = 0;
+
+        for(size_t index = 0; index < pModel->m_Objects.size(); ++index) {
+            if(pModel->m_Objects[index]) {
+                ++childCount;
+                meshCount += (unsigned int)pModel->m_Objects[index]->m_Meshes.size();
+            }
+        }
+
+        // Allocate space for the child nodes on the root node
+        pScene->mRootNode->mChildren = new aiNode*[ childCount ];
+
+        // Create nodes for the whole scene
+        std::vector<aiMesh*> MeshArray;
+        MeshArray.reserve(meshCount);
+        for (size_t index = 0; index < pModel->m_Objects.size(); ++index) {
+            createNodes(pModel, pModel->m_Objects[index], pScene->mRootNode, pScene, MeshArray);
+        }
+
+        ai_assert(pScene->mRootNode->mNumChildren == childCount);
+
+        // Create mesh pointer buffer for this scene
+        if (pScene->mNumMeshes > 0) {
+            pScene->mMeshes = new aiMesh*[MeshArray.size()];
+            for (size_t index = 0; index < MeshArray.size(); ++index) {
+                pScene->mMeshes[index] = MeshArray[index];
+            }
         }
-    }
 
-    // Create all materials
-    createMaterials( pModel, pScene );
+        // Create all materials
+        createMaterials(pModel, pScene);
+    }else {
+		if (pModel->m_Vertices.empty()){
+			return;
+		}
+
+		std::unique_ptr<aiMesh> mesh( new aiMesh );
+        mesh->mPrimitiveTypes = aiPrimitiveType_POINT;
+        unsigned int n = pModel->m_Vertices.size();
+        mesh->mNumVertices = n;
+
+        mesh->mVertices = new aiVector3D[n];
+        memcpy(mesh->mVertices, pModel->m_Vertices.data(), n*sizeof(aiVector3D) );
+
+        if ( !pModel->m_Normals.empty() ) {
+            mesh->mNormals = new aiVector3D[n];
+            if (pModel->m_Normals.size() < n) {
+                throw DeadlyImportError("OBJ: vertex normal index out of range");
+            }
+            memcpy(mesh->mNormals, pModel->m_Normals.data(), n*sizeof(aiVector3D));
+        }
+
+        if ( !pModel->m_VertexColors.empty() ){
+            mesh->mColors[0] = new aiColor4D[mesh->mNumVertices];
+            for (unsigned int i = 0; i < n; ++i) {
+                if (i < pModel->m_VertexColors.size() ) {
+                    const aiVector3D& color = pModel->m_VertexColors[i];
+                    mesh->mColors[0][i] = aiColor4D(color.x, color.y, color.z, 1.0);
+                }else {
+                    throw DeadlyImportError("OBJ: vertex color index out of range");
+                }
+            }
+        }
+
+        pScene->mRootNode->mNumMeshes = 1;
+        pScene->mRootNode->mMeshes = new unsigned int[1];
+        pScene->mRootNode->mMeshes[0] = 0;
+        pScene->mMeshes = new aiMesh*[1];
+        pScene->mNumMeshes = 1;
+        pScene->mMeshes[0] = mesh.release();
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -251,9 +304,8 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
     pNode->mName = pObject->m_strObjName;
 
     // If we have a parent node, store it
-    if( pParent != NULL ) {
-        appendChildToParentNode( pParent, pNode );
-    }
+    ai_assert( NULL != pParent );
+    appendChildToParentNode( pParent, pNode );
 
     for ( size_t i=0; i< pObject->m_Meshes.size(); ++i ) {
         unsigned int meshId = pObject->m_Meshes[ i ];
@@ -406,8 +458,8 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
     pMesh->mNumVertices = numIndices;
     if (pMesh->mNumVertices == 0) {
         throw DeadlyImportError( "OBJ: no vertices" );
-    } else if (pMesh->mNumVertices > AI_MAX_ALLOC(aiVector3D)) {
-        throw DeadlyImportError( "OBJ: Too many vertices, would run out of memory" );
+    } else if (pMesh->mNumVertices > AI_MAX_VERTICES) {
+        throw DeadlyImportError( "OBJ: Too many vertices" );
     }
     pMesh->mVertices = new aiVector3D[ pMesh->mNumVertices ];
 
@@ -457,7 +509,7 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
             // Copy all vertex colors
             if ( !pModel->m_VertexColors.empty())
             {
-                const aiVector3D color = pModel->m_VertexColors[ vertex ];
+                const aiVector3D& color = pModel->m_VertexColors[ vertex ];
                 pMesh->mColors[0][ newIndex ] = aiColor4D(color.x, color.y, color.z, 1.0);
             }
 
@@ -734,25 +786,8 @@ void ObjFileImporter::appendChildToParentNode(aiNode *pParent, aiNode *pChild)
     // Assign parent to child
     pChild->mParent = pParent;
 
-    // If already children was assigned to the parent node, store them in a
-    std::vector<aiNode*> temp;
-    if (pParent->mChildren != NULL)
-    {
-        ai_assert( 0 != pParent->mNumChildren );
-        for (size_t index = 0; index < pParent->mNumChildren; index++)
-        {
-            temp.push_back(pParent->mChildren [ index ] );
-        }
-        delete [] pParent->mChildren;
-    }
-
     // Copy node instances into parent node
     pParent->mNumChildren++;
-    pParent->mChildren = new aiNode*[ pParent->mNumChildren ];
-    for (size_t index = 0; index < pParent->mNumChildren-1; index++)
-    {
-        pParent->mChildren[ index ] = temp [ index ];
-    }
     pParent->mChildren[ pParent->mNumChildren-1 ] = pChild;
 }
 

+ 5 - 7
code/ObjFileMtlImporter.cpp

@@ -84,8 +84,6 @@ static const std::string BumpOption         = "-bm";
 static const std::string ChannelOption      = "-imfchan";
 static const std::string TypeOption         = "-type";
 
-
-
 // -------------------------------------------------------------------
 //  Constructor
 ObjFileMtlImporter::ObjFileMtlImporter( std::vector<char> &buffer,
@@ -334,6 +332,11 @@ void ObjFileMtlImporter::getTexture() {
         // Specular texture
         out = & m_pModel->m_pCurrentMaterial->textureSpecular;
         clampIndex = ObjFile::Material::TextureSpecularType;
+    } else if ( !ASSIMP_strincmp( pPtr, DisplacementTexture1.c_str(), static_cast<unsigned int>(DisplacementTexture1.size()) ) ||
+                !ASSIMP_strincmp( pPtr, DisplacementTexture2.c_str(), static_cast<unsigned int>(DisplacementTexture2.size()) ) ) {
+        // Displacement texture
+        out = &m_pModel->m_pCurrentMaterial->textureDisp;
+        clampIndex = ObjFile::Material::TextureDispType;
     } else if ( !ASSIMP_strincmp( pPtr, OpacityTexture.c_str(), static_cast<unsigned int>(OpacityTexture.size()) ) ) {
         // Opacity texture
         out = & m_pModel->m_pCurrentMaterial->textureOpacity;
@@ -356,11 +359,6 @@ void ObjFileMtlImporter::getTexture() {
         // Reflection texture(s)
         //Do nothing here
         return;
-    } else if ( !ASSIMP_strincmp( pPtr, DisplacementTexture1.c_str(), static_cast<unsigned int>(DisplacementTexture1.size()) ) ||
-                !ASSIMP_strincmp( pPtr, DisplacementTexture2.c_str(), static_cast<unsigned int>(DisplacementTexture2.size()) ) ) {
-        // Displacement texture
-        out = &m_pModel->m_pCurrentMaterial->textureDisp;
-        clampIndex = ObjFile::Material::TextureDispType;
     } else if ( !ASSIMP_strincmp( pPtr, SpecularityTexture.c_str(), static_cast<unsigned int>(SpecularityTexture.size()) ) ) {
         // Specularity scaling (glossiness)
         out = & m_pModel->m_pCurrentMaterial->textureSpecularity;

+ 10 - 8
code/OptimizeMeshes.h

@@ -67,20 +67,22 @@ namespace Assimp    {
 class OptimizeMeshesProcess : public BaseProcess
 {
 public:
-
+    /// @brief  The class constructor.
     OptimizeMeshesProcess();
+
+    /// @brief  The class destcructor,
     ~OptimizeMeshesProcess();
 
 
     /** @brief Internal utility to store additional mesh info
      */
-    struct MeshInfo
-    {
-        MeshInfo()
-            :   instance_cnt  (0)
-            ,   vertex_format (0)
-            ,   output_id     (0xffffffff)
-        {}
+    struct MeshInfo {
+        MeshInfo() AI_NO_EXCEPT
+        : instance_cnt(0)
+        , vertex_format(0)
+        , output_id(0xffffffff) {
+            // empty
+        }
 
         //! Number of times this mesh is referenced
         unsigned int instance_cnt;

+ 200 - 222
code/PlyLoader.cpp

@@ -55,7 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/scene.h>
 #include <assimp/importerdesc.h>
 
-using namespace Assimp;
+using namespace ::Assimp;
 
 static const aiImporterDesc desc = {
     "Stanford Polygon Library (PLY) Importer",
@@ -73,22 +73,20 @@ static const aiImporterDesc desc = {
 
 // ------------------------------------------------------------------------------------------------
 // Internal stuff
-namespace
-{
-  // ------------------------------------------------------------------------------------------------
-  // Checks that property index is within range
-  template <class T>
-  const T &GetProperty(const std::vector<T> &props, int idx)
-  {
-    if (static_cast<size_t>(idx) >= props.size()) {
-      throw DeadlyImportError("Invalid .ply file: Property index is out of range.");
-    }
+namespace {
+    // ------------------------------------------------------------------------------------------------
+    // Checks that property index is within range
+    template <class T>
+    inline
+    const T &GetProperty(const std::vector<T> &props, int idx) {
+        if (static_cast<size_t>(idx) >= props.size()) {
+            throw DeadlyImportError("Invalid .ply file: Property index is out of range.");
+        }
 
-    return props[idx];
-  }
+        return props[idx];
+    }
 }
 
-
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 PLYImporter::PLYImporter()
@@ -129,7 +127,7 @@ const aiImporterDesc* PLYImporter::GetInfo() const {
 
 // ------------------------------------------------------------------------------------------------
 static bool isBigEndian(const char* szMe) {
-    ai_assert(NULL != szMe);
+    ai_assert(nullptr != szMe);
 
     // binary_little_endian
     // binary_big_endian
@@ -150,7 +148,7 @@ static bool isBigEndian(const char* szMe) {
 // ------------------------------------------------------------------------------------------------
 // Imports the given file into the given scene structure.
 void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) {
-    static const std::string mode = "rb";
+    const std::string mode = "rb";
     std::unique_ptr<IOStream> fileStream(pIOHandler->Open(pFile, mode));
     if (!fileStream.get()) {
         throw DeadlyImportError("Failed to open file " + pFile + ".");
@@ -184,7 +182,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
     char* szMe = (char*)&this->mBuffer[0];
     SkipSpacesAndLineEnd(szMe, (const char**)&szMe);
 
-    // determine the format of the file data and construct the aimesh
+    // determine the format of the file data and construct the aiMesh
     PLY::DOM sPlyDom;   
     this->pcDOM = &sPlyDom;
 
@@ -192,7 +190,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
         if (TokenMatch(szMe, "ascii", 5)) {
             SkipLine(szMe, (const char**)&szMe);
             if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) {
-                if (mGeneratedMesh != NULL) {
+                if (mGeneratedMesh != nullptr) {
                     delete(mGeneratedMesh);
                     mGeneratedMesh = nullptr;
                 }
@@ -206,7 +204,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
 
             // skip the line, parse the rest of the header and build the DOM
             if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) {
-                if (mGeneratedMesh != NULL) {
+                if (mGeneratedMesh != nullptr) {
                     delete(mGeneratedMesh);
                     mGeneratedMesh = nullptr;
                 }
@@ -215,7 +213,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
                 throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)");
             }
         } else {
-            if (mGeneratedMesh != NULL) {
+            if (mGeneratedMesh != nullptr) {
                 delete(mGeneratedMesh);
                 mGeneratedMesh = nullptr;
             }
@@ -225,7 +223,7 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
         }
     } else {
         AI_DEBUG_INVALIDATE_PTR(this->mBuffer);
-        if (mGeneratedMesh != NULL) {
+        if (mGeneratedMesh != nullptr) {
             delete(mGeneratedMesh);
             mGeneratedMesh = nullptr;
         }
@@ -237,13 +235,13 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
     //free the file buffer
     streamedBuffer.close();
 
-    if (mGeneratedMesh == NULL) {
+    if (mGeneratedMesh == nullptr) {
         throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data ");
     }
 
     // if no face list is existing we assume that the vertex
     // list is containing a list of points
-    bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false;
+    bool pointsOnly = mGeneratedMesh->mFaces == nullptr ? true : false;
     if (pointsOnly) {
       mGeneratedMesh->mPrimitiveTypes = aiPrimitiveType::aiPrimitiveType_POINT;
     }
@@ -277,8 +275,8 @@ void PLYImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
 }
 
 void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) {
-    ai_assert(NULL != pcElement);
-    ai_assert(NULL != instElement);
+    ai_assert(nullptr != pcElement);
+    ai_assert(nullptr != instElement);
 
     ai_uint aiPositions[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
     PLY::EDataType aiTypes[3] = { EDT_Char, EDT_Char, EDT_Char };
@@ -416,7 +414,7 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
             haveColor = true;
         }
 
-        // assume 1.0 for the alpha channel ifit is not set
+        // assume 1.0 for the alpha channel if it is not set
         if (0xFFFFFFFF == aiColors[3]) {
             cOut.a = 1.0;
         } else {
@@ -481,225 +479,205 @@ void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementIn
 // ------------------------------------------------------------------------------------------------
 // Convert a color component to [0...1]
 ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, PLY::EDataType eType) {
-  switch (eType)
-  {
-  case EDT_Float:
-    return val.fFloat;
-  case EDT_Double:
-    return (ai_real)val.fDouble;
-
-  case EDT_UChar:
-    return (ai_real)val.iUInt / (ai_real)0xFF;
-  case EDT_Char:
-    return (ai_real)(val.iInt + (0xFF / 2)) / (ai_real)0xFF;
-  case EDT_UShort:
-    return (ai_real)val.iUInt / (ai_real)0xFFFF;
-  case EDT_Short:
-    return (ai_real)(val.iInt + (0xFFFF / 2)) / (ai_real)0xFFFF;
-  case EDT_UInt:
-    return (ai_real)val.iUInt / (ai_real)0xFFFF;
-  case EDT_Int:
-    return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f;
-  default:;
-  };
-  return 0.0f;
+    switch (eType) {
+        case EDT_Float:
+            return val.fFloat;
+        case EDT_Double:
+            return (ai_real)val.fDouble;
+        case EDT_UChar:
+            return (ai_real)val.iUInt / (ai_real)0xFF;
+        case EDT_Char:
+            return (ai_real)(val.iInt + (0xFF / 2)) / (ai_real)0xFF;
+        case EDT_UShort:
+            return (ai_real)val.iUInt / (ai_real)0xFFFF;
+        case EDT_Short:
+            return (ai_real)(val.iInt + (0xFFFF / 2)) / (ai_real)0xFFFF;
+        case EDT_UInt:
+            return (ai_real)val.iUInt / (ai_real)0xFFFF;
+        case EDT_Int:
+            return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f;
+        default:
+            break;
+    }
+
+    return 0.0f;
 }
 
 // ------------------------------------------------------------------------------------------------
 // Try to extract proper faces from the PLY DOM
-void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos)
-{
-  ai_assert(NULL != pcElement);
-  ai_assert(NULL != instElement);
-
-  if (mGeneratedMesh == NULL)
-    throw DeadlyImportError("Invalid .ply file: Vertices should be declared before faces");
-
-  bool bOne = false;
-
-  // index of the vertex index list
-  unsigned int iProperty = 0xFFFFFFFF;
-  PLY::EDataType eType = EDT_Char;
-  bool bIsTriStrip = false;
+void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement,
+        unsigned int pos) {
+    ai_assert(nullptr != pcElement);
+    ai_assert(nullptr != instElement);
 
-  // index of the material index property
-  //unsigned int iMaterialIndex = 0xFFFFFFFF;
-  //PLY::EDataType eType2 = EDT_Char;
-
-  // texture coordinates
-  unsigned int iTextureCoord = 0xFFFFFFFF;
-  PLY::EDataType eType3 = EDT_Char;
+    if (mGeneratedMesh == nullptr) {
+        throw DeadlyImportError("Invalid .ply file: Vertices should be declared before faces");
+    }
 
-  // face = unique number of vertex indices
-  if (PLY::EEST_Face == pcElement->eSemantic)
-  {
-    unsigned int _a = 0;
-    for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
-      a != pcElement->alProperties.end(); ++a, ++_a)
-    {
-      if (PLY::EST_VertexIndex == (*a).Semantic)
-      {
-        // must be a dynamic list!
-        if (!(*a).bIsList)
-          continue;
+    bool bOne = false;
+
+    // index of the vertex index list
+    unsigned int iProperty = 0xFFFFFFFF;
+    PLY::EDataType eType = EDT_Char;
+    bool bIsTriStrip = false;
+
+    // index of the material index property
+    //unsigned int iMaterialIndex = 0xFFFFFFFF;
+    //PLY::EDataType eType2 = EDT_Char;
+
+    // texture coordinates
+    unsigned int iTextureCoord = 0xFFFFFFFF;
+    PLY::EDataType eType3 = EDT_Char;
+
+    // face = unique number of vertex indices
+    if (PLY::EEST_Face == pcElement->eSemantic) {
+        unsigned int _a = 0;
+        for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+                a != pcElement->alProperties.end(); ++a, ++_a) {
+            if (PLY::EST_VertexIndex == (*a).Semantic) {
+                // must be a dynamic list!
+                if (!(*a).bIsList) {
+                    continue;
+                }
 
-        iProperty = _a;
-        bOne = true;
-        eType = (*a).eType;
-      }
-      /*else if (PLY::EST_MaterialIndex == (*a).Semantic)
-      {
-      if ((*a).bIsList)
-      continue;
-      iMaterialIndex = _a;
-      bOne = true;
-      eType2 = (*a).eType;
-      }*/
-      else if (PLY::EST_TextureCoordinates == (*a).Semantic)
-      {
-        // must be a dynamic list!
-        if (!(*a).bIsList)
-          continue;
-        iTextureCoord = _a;
-        bOne = true;
-        eType3 = (*a).eType;
-      }
-    }
-  }
-  // triangle strip
-  // TODO: triangle strip and material index support???
-  else if (PLY::EEST_TriStrip == pcElement->eSemantic)
-  {
-    unsigned int _a = 0;
-    for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
-      a != pcElement->alProperties.end(); ++a, ++_a)
-    {
-      // must be a dynamic list!
-      if (!(*a).bIsList)
-        continue;
-      iProperty = _a;
-      bOne = true;
-      bIsTriStrip = true;
-      eType = (*a).eType;
-      break;
+                iProperty = _a;
+                bOne = true;
+                eType = (*a).eType;
+            } else if (PLY::EST_TextureCoordinates == (*a).Semantic) {
+                // must be a dynamic list!
+                if (!(*a).bIsList) {
+                    continue;
+                }
+                iTextureCoord = _a;
+                bOne = true;
+                eType3 = (*a).eType;
+            }
+        }
     }
-  }
-
-  // check whether we have at least one per-face information set
-  if (bOne)
-  {
-    if (mGeneratedMesh->mFaces == NULL)
-    {
-      mGeneratedMesh->mNumFaces = pcElement->NumOccur;
-      mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
+    // triangle strip
+    // TODO: triangle strip and material index support???
+    else if (PLY::EEST_TriStrip == pcElement->eSemantic) {
+        unsigned int _a = 0;
+        for (std::vector<PLY::Property>::const_iterator a = pcElement->alProperties.begin();
+                a != pcElement->alProperties.end(); ++a, ++_a) {
+            // must be a dynamic list!
+            if (!(*a).bIsList) {
+                continue;
+            }
+            iProperty = _a;
+            bOne = true;
+            bIsTriStrip = true;
+            eType = (*a).eType;
+            break;
+        }
     }
 
-    if (!bIsTriStrip)
-    {
-      // parse the list of vertex indices
-      if (0xFFFFFFFF != iProperty)
-      {
-        const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iProperty).avList.size();
-        mGeneratedMesh->mFaces[pos].mNumIndices = iNum;
-        mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[iNum];
-
-        std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
-          GetProperty(instElement->alProperties, iProperty).avList.begin();
-
-        for (unsigned int a = 0; a < iNum; ++a, ++p)
-        {
-          mGeneratedMesh->mFaces[pos].mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p, eType);
+    // check whether we have at least one per-face information set
+    if (bOne) {
+        if (mGeneratedMesh->mFaces == nullptr) {
+            mGeneratedMesh->mNumFaces = pcElement->NumOccur;
+            mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
         }
-      }
 
-      // parse the material index
-      // cannot be handled without processing the whole file first
-      /*if (0xFFFFFFFF != iMaterialIndex)
-      {
-      mGeneratedMesh->mFaces[pos]. = PLY::PropertyInstance::ConvertTo<unsigned int>(
-      GetProperty(instElement->alProperties, iMaterialIndex).avList.front(), eType2);
-      }*/
+        if (!bIsTriStrip) {
+            // parse the list of vertex indices
+            if (0xFFFFFFFF != iProperty) {
+                const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iProperty).avList.size();
+                mGeneratedMesh->mFaces[pos].mNumIndices = iNum;
+                mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[iNum];
 
-      if (0xFFFFFFFF != iTextureCoord)
-      {
-        const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iTextureCoord).avList.size();
+                std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
+                GetProperty(instElement->alProperties, iProperty).avList.begin();
 
-        //should be 6 coords
-        std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
-          GetProperty(instElement->alProperties, iTextureCoord).avList.begin();
+                for (unsigned int a = 0; a < iNum; ++a, ++p) {
+                    mGeneratedMesh->mFaces[pos].mIndices[a] = PLY::PropertyInstance::ConvertTo<unsigned int>(*p, eType);
+                }
+            }
 
-        if ((iNum / 3) == 2) // X Y coord
+        // parse the material index
+        // cannot be handled without processing the whole file first
+        /*if (0xFFFFFFFF != iMaterialIndex)
         {
-          for (unsigned int a = 0; a < iNum; ++a, ++p)
-          {
-            unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2];
-            if (vindex < mGeneratedMesh->mNumVertices)
-            {
-              if (mGeneratedMesh->mTextureCoords[0] == NULL)
-              {
-                mGeneratedMesh->mNumUVComponents[0] = 2;
-                mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
-              }
-
-              if (a % 2 == 0)
-                mGeneratedMesh->mTextureCoords[0][vindex].x = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
-              else
-                mGeneratedMesh->mTextureCoords[0][vindex].y = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
-
-              mGeneratedMesh->mTextureCoords[0][vindex].z = 0;
+            mGeneratedMesh->mFaces[pos]. = PLY::PropertyInstance::ConvertTo<unsigned int>(
+            GetProperty(instElement->alProperties, iMaterialIndex).avList.front(), eType2);
+        }*/
+
+            if (0xFFFFFFFF != iTextureCoord) {
+                const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iTextureCoord).avList.size();
+
+                //should be 6 coords
+                std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator p =
+                GetProperty(instElement->alProperties, iTextureCoord).avList.begin();
+
+                if ((iNum / 3) == 2) // X Y coord
+                {
+                    for (unsigned int a = 0; a < iNum; ++a, ++p) {
+                        unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2];
+                        if (vindex < mGeneratedMesh->mNumVertices) {
+                            if (mGeneratedMesh->mTextureCoords[0] == nullptr ) {
+                                mGeneratedMesh->mNumUVComponents[0] = 2;
+                                mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices];
+                            }
+
+                            if (a % 2 == 0) {
+                                mGeneratedMesh->mTextureCoords[0][vindex].x = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
+                            } else {
+                                mGeneratedMesh->mTextureCoords[0][vindex].y = PLY::PropertyInstance::ConvertTo<ai_real>(*p, eType3);
+                            }
+
+                            mGeneratedMesh->mTextureCoords[0][vindex].z = 0;
+                        }
+                    }
+                }
             }
-          }
-        }
-      }
-    }
-    else // triangle strips
-    {
-      // normally we have only one triangle strip instance where
-      // a value of -1 indicates a restart of the strip
-      bool flip = false;
-      const std::vector<PLY::PropertyInstance::ValueUnion>& quak = GetProperty(instElement->alProperties, iProperty).avList;
-      //pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); //Limits memory consumption
-
-      int aiTable[2] = { -1, -1 };
-      for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a = quak.begin(); a != quak.end(); ++a)  {
-        const int p = PLY::PropertyInstance::ConvertTo<int>(*a, eType);
+        } else { // triangle strips
+            // normally we have only one triangle strip instance where
+            // a value of -1 indicates a restart of the strip
+            bool flip = false;
+            const std::vector<PLY::PropertyInstance::ValueUnion>& quak = GetProperty(instElement->alProperties, iProperty).avList;
+            //pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); //Limits memory consumption
+
+            int aiTable[2] = { -1, -1 };
+            for (std::vector<PLY::PropertyInstance::ValueUnion>::const_iterator a = quak.begin(); a != quak.end(); ++a)  {
+                const int p = PLY::PropertyInstance::ConvertTo<int>(*a, eType);
+
+                if (-1 == p) {
+                    // restart the strip ...
+                    aiTable[0] = aiTable[1] = -1;
+                    flip = false;
+                    continue;
+                }
+                if (-1 == aiTable[0]) {
+                    aiTable[0] = p;
+                    continue;
+                }
+                if (-1 == aiTable[1]) {
+                    aiTable[1] = p;
+                    continue;
+                }
 
-        if (-1 == p)    {
-          // restart the strip ...
-          aiTable[0] = aiTable[1] = -1;
-          flip = false;
-          continue;
-        }
-        if (-1 == aiTable[0]) {
-          aiTable[0] = p;
-          continue;
-        }
-        if (-1 == aiTable[1]) {
-          aiTable[1] = p;
-          continue;
-        }
+                if (mGeneratedMesh->mFaces == nullptr) {
+                    mGeneratedMesh->mNumFaces = pcElement->NumOccur;
+                    mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
+                }
 
-        if (mGeneratedMesh->mFaces == NULL)
-        {
-          mGeneratedMesh->mNumFaces = pcElement->NumOccur;
-          mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces];
-        }
+                mGeneratedMesh->mFaces[pos].mNumIndices = 3;
+                mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[3];
+                mGeneratedMesh->mFaces[pos].mIndices[0] = aiTable[0];
+                mGeneratedMesh->mFaces[pos].mIndices[1] = aiTable[1];
+                mGeneratedMesh->mFaces[pos].mIndices[2] = p;
 
-        mGeneratedMesh->mFaces[pos].mNumIndices = 3;
-        mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[3];
-        mGeneratedMesh->mFaces[pos].mIndices[0] = aiTable[0];
-        mGeneratedMesh->mFaces[pos].mIndices[1] = aiTable[1];
-        mGeneratedMesh->mFaces[pos].mIndices[2] = p;
+                // every second pass swap the indices.
+                flip = !flip;
+                if ( flip ) {
+                    std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]);
+                }
 
-        if ((flip = !flip)) {
-          std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]);
+                aiTable[0] = aiTable[1];
+                aiTable[1] = p;
+            }
         }
-
-        aiTable[0] = aiTable[1];
-        aiTable[1] = p;
-      }
     }
-  }
 }
 
 // ------------------------------------------------------------------------------------------------

+ 19 - 13
code/PlyParser.h

@@ -209,7 +209,7 @@ enum EElementSemantic {
 class Property {
 public:
     //! Default constructor
-    Property()
+    Property() AI_NO_EXCEPT
     : eType (EDT_Int)
     , Semantic()
     , bIsList(false)
@@ -257,7 +257,7 @@ public:
 class Element {
 public:
     //! Default constructor
-    Element()
+    Element() AI_NO_EXCEPT
     : eSemantic (EEST_INVALID)
     , NumOccur(0) {
         // empty
@@ -297,8 +297,9 @@ class PropertyInstance
 public:
 
     //! Default constructor
-    PropertyInstance ()
-    {}
+    PropertyInstance() AI_NO_EXCEPT {
+        // empty
+    }
 
     union ValueUnion
     {
@@ -356,13 +357,13 @@ public:
 // ---------------------------------------------------------------------------------
 /** \brief Class for an element instance in a PLY file
  */
-class ElementInstance
-{
+class ElementInstance {
 public:
-
     //! Default constructor
-    ElementInstance ()
-    {}
+    ElementInstance()  AI_NO_EXCEPT
+    : alProperties() {
+        // empty
+    }
 
     //! List of all parsed properties
     std::vector< PropertyInstance > alProperties;
@@ -386,8 +387,10 @@ class ElementInstanceList
 public:
 
     //! Default constructor
-    ElementInstanceList ()
-    {}
+    ElementInstanceList() AI_NO_EXCEPT
+    : alInstances() {
+        // empty
+    }
 
     //! List of all element instances
     std::vector< ElementInstance > alInstances;
@@ -411,8 +414,11 @@ class DOM
 public:
 
     //! Default constructor
-    DOM()
-    {}
+    DOM() AI_NO_EXCEPT
+    : alElements()
+    , alElementData() {
+
+    }
 
 
     //! Contains all elements of the file format

+ 6 - 3
code/PostStepRegistry.cpp

@@ -164,9 +164,6 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 #if (!defined ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
     out.push_back( new OptimizeGraphProcess());
 #endif
-#if (!defined ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS)
-    out.push_back( new FindDegeneratesProcess());
-#endif
 #ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS
     out.push_back( new ComputeUVMappingProcess());
 #endif
@@ -179,6 +176,12 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 #if (!defined ASSIMP_BUILD_NO_TRIANGULATE_PROCESS)
     out.push_back( new TriangulateProcess());
 #endif
+#if (!defined ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS)
+    //find degenerates should run after triangulation (to sort out small
+    //generated triangles) but before sort by p types (in case there are lines
+    //and points generated and inserted into a mesh)
+    out.push_back( new FindDegeneratesProcess());
+#endif
 #if (!defined ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS)
     out.push_back( new SortByPTypeProcess());
 #endif

+ 21 - 20
code/SMDLoader.h

@@ -62,17 +62,17 @@ struct aiNode;
 // STL headers
 #include <vector>
 
-namespace Assimp    {
-
-namespace SMD   {
+namespace Assimp {
+namespace SMD {
 
 // ---------------------------------------------------------------------------
 /** Data structure for a vertex in a SMD file
 */
-struct Vertex
-{
-    Vertex() : iParentNode(UINT_MAX)
-     {}
+struct Vertex {
+    Vertex() AI_NO_EXCEPT
+    : iParentNode(UINT_MAX) {
+        // empty
+    }
 
     //! Vertex position, normal and texture coordinate
     aiVector3D pos,nor,uv;
@@ -90,10 +90,12 @@ struct Vertex
 // ---------------------------------------------------------------------------
 /** Data structure for a face in a SMD file
 */
-struct Face
-{
-    Face() : iTexture(0x0)
-     {}
+struct Face {
+    Face() AI_NO_EXCEPT
+    : iTexture(0x0)
+    , avVertices{} {
+        // empty
+    }
 
     //! Texture index for the face
     unsigned int iTexture;
@@ -105,11 +107,12 @@ struct Face
 // ---------------------------------------------------------------------------
 /** Data structure for a bone in a SMD file
 */
-struct Bone
-{
+struct Bone {
     //! Default constructor
-    Bone() : iParent(UINT_MAX), bIsUsed(false)
-    {
+    Bone() AI_NO_EXCEPT
+    : iParent(UINT_MAX)
+    , bIsUsed(false) {
+        // empty
     }
 
     //! Destructor
@@ -124,12 +127,10 @@ struct Bone
     uint32_t iParent;
 
     //! Animation of the bone
-    struct Animation
-    {
+    struct Animation {
         //! Public default constructor
-        Animation()
-            : iFirstTimeKey()
-        {
+        Animation() AI_NO_EXCEPT
+        : iFirstTimeKey() {
             asKeys.reserve(20);
         }
 

+ 37 - 15
code/STLLoader.cpp

@@ -90,6 +90,9 @@ static bool IsBinarySTL(const char* buffer, unsigned int fileSize) {
     return expectedBinaryFileSize == fileSize;
 }
 
+static const size_t BufferSize = 500;
+static const char UnicodeBoundary = 127;
+
 // An ascii STL buffer will begin with "solid NAME", where NAME is optional.
 // Note: The "solid NAME" check is necessary, but not sufficient, to determine
 // if the buffer is ASCII; a binary header could also begin with "solid NAME".
@@ -108,10 +111,10 @@ static bool IsAsciiSTL(const char* buffer, unsigned int fileSize) {
     bool isASCII( strncmp( buffer, "solid", 5 ) == 0 );
     if( isASCII ) {
         // A lot of importers are write solid even if the file is binary. So we have to check for ASCII-characters.
-        if( fileSize >= 500 ) {
+        if( fileSize >= BufferSize) {
             isASCII = true;
-            for( unsigned int i = 0; i < 500; i++ ) {
-                if( buffer[ i ] > 127 ) {
+            for( unsigned int i = 0; i < BufferSize; i++ ) {
+                if( buffer[ i ] > UnicodeBoundary) {
                     isASCII = false;
                     break;
                 }
@@ -352,7 +355,7 @@ void STLImporter::LoadASCIIFile( aiNode *root ) {
 
         if (positionBuffer.empty())    {
             pMesh->mNumFaces = 0;
-            throw DeadlyImportError("STL: ASCII file is empty or invalid; no data loaded");
+            ASSIMP_LOG_WARN("STL: mesh is empty or invalid; no data loaded");
         }
         if (positionBuffer.size() % 3 != 0)    {
             pMesh->mNumFaces = 0;
@@ -362,14 +365,23 @@ void STLImporter::LoadASCIIFile( aiNode *root ) {
             pMesh->mNumFaces = 0;
             throw DeadlyImportError("Normal buffer size does not match position buffer size");
         }
-        pMesh->mNumFaces = static_cast<unsigned int>(positionBuffer.size() / 3);
-        pMesh->mNumVertices = static_cast<unsigned int>(positionBuffer.size());
-        pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
-        memcpy(pMesh->mVertices, &positionBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
-        positionBuffer.clear();
-        pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
-        memcpy(pMesh->mNormals, &normalBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
-        normalBuffer.clear();
+
+        // only process positionbuffer when filled, else exception when accessing with index operator
+        // see line 353: only warning is triggered
+        // see line 373(now): access to empty positionbuffer with index operator forced exception
+        if (!positionBuffer.empty()) {
+            pMesh->mNumFaces = static_cast<unsigned int>(positionBuffer.size() / 3);
+            pMesh->mNumVertices = static_cast<unsigned int>(positionBuffer.size());
+            pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
+            memcpy(pMesh->mVertices, &positionBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
+            positionBuffer.clear();
+        }
+        // also only process normalBuffer when filled, else exception when accessing with index operator
+        if (!normalBuffer.empty()) {
+            pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
+            memcpy(pMesh->mNormals, &normalBuffer[0].x, pMesh->mNumVertices * sizeof(aiVector3D));
+            normalBuffer.clear();
+        }
 
         // now copy faces
         addFacesToMesh(pMesh);
@@ -526,11 +538,21 @@ bool STLImporter::LoadBinaryFile()
     // now copy faces
     addFacesToMesh(pMesh);
 
+    aiNode* root = pScene->mRootNode;
+
+    // allocate one node
+    aiNode* node = new aiNode();
+    node->mParent = root;
+
+    root->mNumChildren = 1u;
+    root->mChildren = new aiNode*[root->mNumChildren];
+    root->mChildren[0] = node;
+
     // add all created meshes to the single node
-    pScene->mRootNode->mNumMeshes = pScene->mNumMeshes;
-    pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes];
+    node->mNumMeshes = pScene->mNumMeshes;
+    node->mMeshes = new unsigned int[pScene->mNumMeshes];
     for (unsigned int i = 0; i < pScene->mNumMeshes; i++)
-        pScene->mRootNode->mMeshes[i] = i;
+        node->mMeshes[i] = i;
 
     if (bIsMaterialise && !pMesh->mColors[0])
     {

+ 12 - 12
code/SceneCombiner.cpp

@@ -707,30 +707,30 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator
     // we work with hashes to make the comparisons MUCH faster,
     // at least if we have many bones.
     std::list<BoneWithHash> asBones;
-    BuildUniqueBoneList(asBones, it,end);
+    BuildUniqueBoneList( asBones, it, end );
 
     // now create the output bones
     out->mNumBones = 0;
     out->mBones = new aiBone*[asBones.size()];
 
-    for (std::list<BoneWithHash>::const_iterator it = asBones.begin(),end = asBones.end(); it != end;++it)  {
+    for (std::list<BoneWithHash>::const_iterator boneIt = asBones.begin(),boneEnd = asBones.end(); boneIt != boneEnd; ++boneIt )  {
         // Allocate a bone and setup it's name
         aiBone* pc = out->mBones[out->mNumBones++] = new aiBone();
-        pc->mName = aiString( *((*it).second ));
+        pc->mName = aiString( *( boneIt->second ));
 
-        std::vector< BoneSrcIndex >::const_iterator wend = (*it).pSrcBones.end();
+        std::vector< BoneSrcIndex >::const_iterator wend = boneIt->pSrcBones.end();
 
         // Loop through all bones to be joined for this bone
-        for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)  {
+        for (std::vector< BoneSrcIndex >::const_iterator wmit = boneIt->pSrcBones.begin(); wmit != wend; ++wmit)  {
             pc->mNumWeights += (*wmit).first->mNumWeights;
 
             // NOTE: different offset matrices for bones with equal names
             // are - at the moment - not handled correctly.
-            if (wmit != (*it).pSrcBones.begin() && pc->mOffsetMatrix != (*wmit).first->mOffsetMatrix)   {
+            if (wmit != boneIt->pSrcBones.begin() && pc->mOffsetMatrix != wmit->first->mOffsetMatrix) {
                 ASSIMP_LOG_WARN("Bones with equal names but different offset matrices can't be joined at the moment");
                 continue;
             }
-            pc->mOffsetMatrix = (*wmit).first->mOffsetMatrix;
+            pc->mOffsetMatrix = wmit->first->mOffsetMatrix;
         }
 
         // Allocate the vertex weight array
@@ -738,7 +738,7 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator
 
         // And copy the final weights - adjust the vertex IDs by the
         // face index offset of the corresponding mesh.
-        for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit)  {
+        for (std::vector< BoneSrcIndex >::const_iterator wmit = (*boneIt).pSrcBones.begin(); wmit != wend; ++wmit)  {
             aiBone* pip = (*wmit).first;
             for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw) {
                 const aiVertexWeight& vfi = pip->mWeights[mp];
@@ -849,14 +849,14 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
         // copy vertex colors
         n = 0;
         while ((**begin).HasVertexColors(n))    {
-            aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
-            for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)   {
+            aiColor4D *pVec2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
+            for ( std::vector<aiMesh*>::const_iterator it = begin; it != end; ++it )   {
                 if ((*it)->mColors[n])  {
-                    ::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
+                    ::memcpy( pVec2, (*it)->mColors[ n ], (*it)->mNumVertices * sizeof( aiColor4D ) ) ;
                 } else {
                     ASSIMP_LOG_WARN( "JoinMeshes: VCs expected but input mesh contains no VCs" );
                 }
-                pv2 += (*it)->mNumVertices;
+                pVec2 += (*it)->mNumVertices;
             }
             ++n;
         }

+ 10 - 6
code/ScenePrivate.h

@@ -55,12 +55,8 @@ namespace Assimp {
 class Importer;
 
 struct ScenePrivateData {
-    ScenePrivateData()
-    : mOrigImporter( nullptr )
-    , mPPStepsApplied( 0 )
-    , mIsCopy( false ) {
-        // empty
-    }
+    //  The struct constructor.
+    ScenePrivateData() AI_NO_EXCEPT;
 
     // Importer that originally loaded the scene though the C-API
     // If set, this object is owned by this private data instance.
@@ -77,6 +73,14 @@ struct ScenePrivateData {
     bool mIsCopy;
 };
 
+inline
+ScenePrivateData::ScenePrivateData() AI_NO_EXCEPT
+: mOrigImporter( nullptr )
+, mPPStepsApplied( 0 )
+, mIsCopy( false ) {
+    // empty
+}
+
 // Access private data stored in the scene
 inline
 ScenePrivateData* ScenePriv(aiScene* in) {

+ 1 - 1
code/SpatialSort.cpp

@@ -223,7 +223,7 @@ namespace {
         if( (-42 == (~42 + 1)) && (binValue & 0x80000000))
             return BinFloat(1 << (CHAR_BIT * sizeof(BinFloat) - 1)) - binValue;
         // One's complement?
-        else if( (-42 == ~42) && (binValue & 0x80000000))
+        else if ( (-42 == ~42) && (binValue & 0x80000000))
             return BinFloat(-0) - binValue;
         // Sign-magnitude?
         else if( (-42 == (42 | (-0))) && (binValue & 0x80000000)) // -0 = 1000... binary

+ 1 - 1
code/SplitByBoneCountProcess.cpp

@@ -393,7 +393,7 @@ void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const
             newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end());
         }
 
-        delete pNode->mMeshes;
+        delete [] pNode->mMeshes;
         pNode->mNumMeshes = static_cast<unsigned int>(newMeshList.size());
         pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
         std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);

+ 16 - 17
code/TextureTransform.h

@@ -65,14 +65,14 @@ namespace Assimp    {
 /** Small helper structure representing a shortcut into the material list
  *  to be able to update some values quickly.
 */
-struct TTUpdateInfo
-{
-    TTUpdateInfo() :
-            directShortcut  (NULL)
-        ,   mat             (NULL)
-        ,   semantic        (0)
-        ,   index           (0)
-    {}
+struct TTUpdateInfo {
+    TTUpdateInfo() AI_NO_EXCEPT
+    : directShortcut(nullptr)
+    , mat(nullptr)
+    , semantic(0)
+    , index(0) {
+        // empty
+    }
 
     //! Direct shortcut, if available
     unsigned int* directShortcut;
@@ -88,15 +88,14 @@ struct TTUpdateInfo
 // ---------------------------------------------------------------------------
 /** Helper class representing texture coordinate transformations
 */
-struct STransformVecInfo : public aiUVTransform
-{
-
-    STransformVecInfo()
-        :   uvIndex     (0)
-        ,   mapU        (aiTextureMapMode_Wrap)
-        ,   mapV        (aiTextureMapMode_Wrap)
-        ,   lockedPos   (AI_TT_UV_IDX_LOCK_NONE)
-    {}
+struct STransformVecInfo : public aiUVTransform {
+    STransformVecInfo() AI_NO_EXCEPT
+    : uvIndex(0)
+    , mapU(aiTextureMapMode_Wrap)
+    , mapV(aiTextureMapMode_Wrap)
+    , lockedPos(AI_TT_UV_IDX_LOCK_NONE) {
+        // empty
+    }
 
     //! Source texture coordinate index
     unsigned int uvIndex;

+ 21 - 18
code/TriangulateProcess.cpp

@@ -105,8 +105,10 @@ void TriangulateProcess::Execute( aiScene* pScene)
     bool bHas = false;
     for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
     {
-        if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) {
-            bHas = true;
+        if (pScene->mMeshes[ a ]) {
+            if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) {
+                bHas = true;
+            }
         }
     }
     if ( bHas ) {
@@ -285,7 +287,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
             // We project it onto a plane to get a 2d triangle.
 
             // Collect all vertices of of the polygon.
-            for (tmp = 0; tmp < max; ++tmp) {
+           for (tmp = 0; tmp < max; ++tmp) {
                 temp_verts3d[tmp] = verts[idx[tmp]];
             }
 
@@ -485,21 +487,22 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
         for(aiFace* f = last_face; f != curOut; ) {
             unsigned int* i = f->mIndices;
 
-            //  drop dumb 0-area triangles
-            if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) {
-                ASSIMP_LOG_DEBUG("Dropping triangle with area 0");
-                --curOut;
-
-                delete[] f->mIndices;
-                f->mIndices = NULL;
-
-                for(aiFace* ff = f; ff != curOut; ++ff) {
-                    ff->mNumIndices = (ff+1)->mNumIndices;
-                    ff->mIndices = (ff+1)->mIndices;
-                    (ff+1)->mIndices = NULL;
-                }
-                continue;
-            }
+            //  drop dumb 0-area triangles - deactivated for now:
+            //FindDegenerates post processing step can do the same thing
+            //if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) {
+            //    ASSIMP_LOG_DEBUG("Dropping triangle with area 0");
+            //    --curOut;
+
+            //    delete[] f->mIndices;
+            //    f->mIndices = nullptr;
+
+            //    for(aiFace* ff = f; ff != curOut; ++ff) {
+            //        ff->mNumIndices = (ff+1)->mNumIndices;
+            //        ff->mIndices = (ff+1)->mIndices;
+            //        (ff+1)->mIndices = nullptr;
+            //    }
+            //    continue;
+            //}
 
             i[0] = idx[i[0]];
             i[1] = idx[i[1]];

+ 2 - 2
code/ValidateDataStructure.cpp

@@ -369,7 +369,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
 
     // positions must always be there ...
     if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) {
-        ReportError("The mesh contains no vertices");
+        ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str());
     }
 
     if (pMesh->mNumVertices > AI_MAX_VERTICES) {
@@ -386,7 +386,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh)
 
     // faces, too
     if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags))   {
-        ReportError("Mesh contains no faces");
+        ReportError("Mesh %s contains no faces", pMesh->mName.C_Str());
     }
 
     // now check whether the face indexing layout is correct:

+ 5 - 3
code/Version.cpp

@@ -150,9 +150,11 @@ ASSIMP_API aiScene::~aiScene() {
             delete mMeshes[a];
     delete [] mMeshes;
 
-    if (mNumMaterials && mMaterials)
-        for( unsigned int a = 0; a < mNumMaterials; a++)
-            delete mMaterials[a];
+    if (mNumMaterials && mMaterials) {
+        for (unsigned int a = 0; a < mNumMaterials; ++a ) {
+            delete mMaterials[ a ];
+        }
+    }
     delete [] mMaterials;
 
     if (mNumAnimations && mAnimations)

+ 76 - 42
code/XFileHelper.h

@@ -55,32 +55,33 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/anim.h>
 #include <assimp/Defines.h>
 
-namespace Assimp
-{
-namespace XFile
-{
+namespace Assimp {
+namespace XFile {
 
 /** Helper structure representing a XFile mesh face */
-struct Face
-{
+struct Face {
     std::vector<unsigned int> mIndices;
 };
 
 /** Helper structure representing a texture filename inside a material and its potential source */
-struct TexEntry
-{
+struct TexEntry {
     std::string mName;
     bool mIsNormalMap; // true if the texname was specified in a NormalmapFilename tag
 
-    TexEntry() { mIsNormalMap = false; }
-    TexEntry( const std::string& pName, bool pIsNormalMap = false)
-        : mName( pName), mIsNormalMap( pIsNormalMap)
-    { /* done */ }
+    TexEntry() AI_NO_EXCEPT
+    : mName()
+    , mIsNormalMap(false) {
+        // empty
+    }
+    TexEntry(const std::string& pName, bool pIsNormalMap = false)
+    : mName(pName)
+    , mIsNormalMap(pIsNormalMap) {
+        // empty
+    }
 };
 
 /** Helper structure representing a XFile material */
-struct Material
-{
+struct Material {
     std::string mName;
     bool mIsReference; // if true, mName holds a name by which the actual material can be found in the material list
     aiColor4D mDiffuse;
@@ -88,19 +89,18 @@ struct Material
     aiColor3D mSpecular;
     aiColor3D mEmissive;
     std::vector<TexEntry> mTextures;
-
     size_t sceneIndex; ///< the index under which it was stored in the scene's material list
 
-    Material()
-        : mIsReference(false),
-        mSpecularExponent(),
-        sceneIndex(SIZE_MAX)
-    {}
+    Material() AI_NO_EXCEPT
+    : mIsReference(false)
+    , mSpecularExponent()
+    , sceneIndex(SIZE_MAX) {
+        // empty
+    }
 };
 
 /** Helper structure to represent a bone weight */
-struct BoneWeight
-{
+struct BoneWeight {
     unsigned int mVertex;
     ai_real mWeight;
 };
@@ -114,8 +114,7 @@ struct Bone
 };
 
 /** Helper structure to represent an XFile mesh */
-struct Mesh
-{
+struct Mesh {
     std::string mName;
     std::vector<aiVector3D> mPositions;
     std::vector<Face> mPosFaces;
@@ -131,38 +130,65 @@ struct Mesh
 
     std::vector<Bone> mBones;
 
-    explicit Mesh(const std::string &pName = "") { mName = pName; mNumTextures = 0; mNumColorSets = 0; }
+    explicit Mesh(const std::string &pName = "") AI_NO_EXCEPT
+    : mName( pName )
+    , mPositions()
+    , mPosFaces()
+    , mNormals()
+    , mNormFaces()
+    , mNumTextures(0)
+    , mTexCoords{}
+    , mNumColorSets(0)
+    , mColors{}
+    , mFaceMaterials()
+    , mMaterials()
+    , mBones() {
+        // empty
+    }
 };
 
 /** Helper structure to represent a XFile frame */
-struct Node
-{
+struct Node {
     std::string mName;
     aiMatrix4x4 mTrafoMatrix;
     Node* mParent;
     std::vector<Node*> mChildren;
     std::vector<Mesh*> mMeshes;
 
-    Node() { mParent = NULL; }
-    explicit Node( Node* pParent) { mParent = pParent; }
-    ~Node()
-    {
-        for( unsigned int a = 0; a < mChildren.size(); a++)
+    Node() AI_NO_EXCEPT
+    : mName()
+    , mTrafoMatrix()
+    , mParent(nullptr)
+    , mChildren()
+    , mMeshes() {
+        // empty
+    }
+    explicit Node( Node* pParent)
+    : mName()
+    , mTrafoMatrix()
+    , mParent(pParent)
+    , mChildren()
+    , mMeshes() {
+        // empty
+    }
+
+    ~Node() {
+        for (unsigned int a = 0; a < mChildren.size(); ++a ) {
             delete mChildren[a];
-        for( unsigned int a = 0; a < mMeshes.size(); a++)
+        }
+        for (unsigned int a = 0; a < mMeshes.size(); ++a) {
             delete mMeshes[a];
+        }
     }
 };
 
-struct MatrixKey
-{
+struct MatrixKey {
     double mTime;
     aiMatrix4x4 mMatrix;
 };
 
 /** Helper structure representing a single animated bone in a XFile */
-struct AnimBone
-{
+struct AnimBone {
     std::string mBoneName;
     std::vector<aiVectorKey> mPosKeys;  // either three separate key sequences for position, rotation, scaling
     std::vector<aiQuatKey> mRotKeys;
@@ -194,14 +220,22 @@ struct Scene
     std::vector<Animation*> mAnims;
     unsigned int mAnimTicksPerSecond;
 
-    Scene() { mRootNode = NULL; mAnimTicksPerSecond = 0; }
-    ~Scene()
-    {
+    Scene() AI_NO_EXCEPT
+    : mRootNode(nullptr)
+    , mGlobalMeshes()
+    , mGlobalMaterials()
+    , mAnimTicksPerSecond(0) {
+        // empty
+    }
+    ~Scene() {
         delete mRootNode;
-        for( unsigned int a = 0; a < mGlobalMeshes.size(); a++)
+        mRootNode = nullptr;
+        for (unsigned int a = 0; a < mGlobalMeshes.size(); ++a ) {
             delete mGlobalMeshes[a];
-        for( unsigned int a = 0; a < mAnims.size(); a++)
+        }
+        for (unsigned int a = 0; a < mAnims.size(); ++a ) {
             delete mAnims[a];
+        }
     }
 };
 

+ 6 - 1
code/XFileImporter.cpp

@@ -332,6 +332,11 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec
                 // collect vertex data for indices of this face
                 for( unsigned int d = 0; d < df.mNumIndices; ++d ) {
                     df.mIndices[d] = newIndex;
+                    const unsigned int newIdx( pf.mIndices[ d ] );
+                    if ( newIdx > sourceMesh->mPositions.size() ) {
+                        continue;
+                    }
+
                     orgPoints[newIndex] = pf.mIndices[d];
 
                     // Position
@@ -459,7 +464,7 @@ void XFileImporter::CreateAnimations( aiScene* pScene, const XFile::Scene* pData
             nbone->mNodeName.Set( bone->mBoneName);
             nanim->mChannels[b] = nbone;
 
-            // keyframes are given as combined transformation matrix keys
+            // key-frames are given as combined transformation matrix keys
             if( !bone->mTrafoKeys.empty() )
             {
                 nbone->mNumPositionKeys = (unsigned int)bone->mTrafoKeys.size();

+ 8 - 3
code/XFileParser.cpp

@@ -471,7 +471,10 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh)
         unsigned int numIndices = ReadInt();
         Face& face = pMesh->mPosFaces[a];
         for (unsigned int b = 0; b < numIndices; ++b) {
-            face.mIndices.push_back( ReadInt() );
+            const int idx( ReadInt() );
+            if ( static_cast<unsigned int>( idx ) <= numVertices ) {
+                face.mIndices.push_back( idx );
+            }
         }
         TestForSeparator();
     }
@@ -1293,7 +1296,7 @@ unsigned int XFileParser::ReadBinDWord() {
 // ------------------------------------------------------------------------------------------------
 unsigned int XFileParser::ReadInt()
 {
-    if( mIsBinaryFormat)
+   if( mIsBinaryFormat)
     {
         if( mBinaryNumCount == 0 && mEnd - mP >= 2)
         {
@@ -1305,7 +1308,8 @@ unsigned int XFileParser::ReadInt()
         }
 
         --mBinaryNumCount;
-        if ( mEnd - mP >= 4) {
+        const size_t len( mEnd - mP );
+        if ( len >= 4) {
             return ReadBinDWord();
         } else {
             mP = mEnd;
@@ -1340,6 +1344,7 @@ unsigned int XFileParser::ReadInt()
         }
 
         CheckForSeparator();
+
         return isNegative ? ((unsigned int) -int( number)) : number;
     }
 }

+ 7 - 0
code/glTF2Asset.h

@@ -766,10 +766,17 @@ namespace glTF2
             Ref<Accessor> indices;
 
             Ref<Material> material;
+
+            struct Target {
+                AccessorList position, normal, tangent;
+            };
+            std::vector<Target> targets;
         };
 
         std::vector<Primitive> primitives;
 
+        std::vector<float> weights;
+
         Mesh() {}
 
 		/// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root)

+ 52 - 4
code/glTF2Asset.inl

@@ -931,6 +931,21 @@ namespace {
         else return false;
         return true;
     }
+
+    inline bool GetAttribTargetVector(Mesh::Primitive& p, const int targetIndex, const char* attr, Mesh::AccessorList*& v, int& pos)
+    {
+        if ((pos = Compare(attr, "POSITION"))) {
+            v = &(p.targets[targetIndex].position);
+        }
+        else if ((pos = Compare(attr, "NORMAL"))) {
+            v = &(p.targets[targetIndex].normal);
+        }
+        else if ((pos = Compare(attr, "TANGENT"))) {
+            v = &(p.targets[targetIndex].tangent);
+        }
+        else return false;
+        return true;
+    }
 }
 
 inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
@@ -965,6 +980,26 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
                 }
             }
 
+            if (Value* targetsArray = FindArray(primitive, "targets")) {
+                prim.targets.resize(targetsArray->Size());
+                for (unsigned int i = 0; i < targetsArray->Size(); ++i) {
+                    Value& target = (*targetsArray)[i];
+                    if (!target.IsObject()) continue;
+                    for (Value::MemberIterator it = target.MemberBegin(); it != target.MemberEnd(); ++it) {
+                        if (!it->value.IsUint()) continue;
+                        const char* attr = it->name.GetString();
+                        // Valid attribute semantics include POSITION, NORMAL, TANGENT
+                        int undPos = 0;
+                        Mesh::AccessorList* vec = 0;
+                        if (GetAttribTargetVector(prim, i, attr, vec, undPos)) {
+                            size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0;
+                            if ((*vec).size() <= idx) (*vec).resize(idx + 1);
+                            (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint());
+                        }
+                    }
+                }
+            }
+
             if (Value* indices = FindUInt(primitive, "indices")) {
 				prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint());
             }
@@ -974,6 +1009,16 @@ inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root)
             }
         }
     }
+
+    if (Value* weights = FindArray(pJSON_Object, "weights")) {
+        this->weights.resize(weights->Size());
+        for (unsigned int i = 0; i < weights->Size(); ++i) {
+          Value& weightValue = (*weights)[i];
+          if (weightValue.IsNumber()) {
+            this->weights[i] = weightValue.GetFloat();
+          }
+        }
+    }
 }
 
 inline void Camera::Read(Value& obj, Asset& /*r*/)
@@ -1216,12 +1261,15 @@ inline void Asset::Load(const std::string& pFile, bool isBinary)
 
     // Read the "scene" property, which specifies which scene to load
     // and recursively load everything referenced by it
+    unsigned int sceneIndex = 0;
     if (Value* scene = FindUInt(doc, "scene")) {
-        unsigned int sceneIndex = scene->GetUint();
-
-        Ref<Scene> s = scenes.Retrieve(sceneIndex);
+        sceneIndex = scene->GetUint();
+    }
 
-        this->scene = s;
+    if (Value* scenesArray = FindArray(doc, "scenes")) {
+        if (sceneIndex < scenesArray->Size()) {
+            this->scene = scenes.Retrieve(sceneIndex);
+        }
     }
 
     // Clean up

+ 6 - 23
code/glTF2Exporter.cpp

@@ -94,19 +94,7 @@ glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const ai
     , mIOSystem(pIOSystem)
     , mProperties(pProperties)
 {
-    aiScene* sceneCopy_tmp;
-    SceneCombiner::CopyScene(&sceneCopy_tmp, pScene);
-    std::unique_ptr<aiScene> sceneCopy(sceneCopy_tmp);
-
-    SplitLargeMeshesProcess_Triangle tri_splitter;
-    tri_splitter.SetLimit(0xffff);
-    tri_splitter.Execute(sceneCopy.get());
-
-    SplitLargeMeshesProcess_Vertex vert_splitter;
-    vert_splitter.SetLimit(0xffff);
-    vert_splitter.Execute(sceneCopy.get());
-
-    mScene = sceneCopy.get();
+    mScene = pScene;
 
     mAsset.reset( new Asset( pIOSystem ) );
 
@@ -514,9 +502,9 @@ void glTF2Exporter::ExportMaterials()
             GetMatColor(mat, pbrSG.specularFactor, AI_MATKEY_COLOR_SPECULAR);
 
             if (mat->Get(AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR, pbrSG.glossinessFactor) != AI_SUCCESS) {
-                float shininess;
+				float shininess;
 
-                if (mat->Get(AI_MATKEY_SHININESS, shininess)) {
+				if (mat->Get(AI_MATKEY_SHININESS, shininess) == AI_SUCCESS) {
                     pbrSG.glossinessFactor = shininess / 1000;
                 }
             }
@@ -682,12 +670,7 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref<Mesh>& meshRef, Ref<Buf
 
 void glTF2Exporter::ExportMeshes()
 {
-    // Not for
-    //     using IndicesType = decltype(aiFace::mNumIndices);
-    // But yes for
-    //     using IndicesType = unsigned short;
-    // because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification.
-    typedef unsigned short IndicesType;
+    typedef decltype(aiFace::mNumIndices) IndicesType;
 
     std::string fname = std::string(mFilename);
     std::string bufferIdPrefix = fname.substr(0, fname.rfind(".gltf"));
@@ -779,11 +762,11 @@ void glTF2Exporter::ExportMeshes()
             indices.resize(aim->mNumFaces * nIndicesPerFace);
             for (size_t i = 0; i < aim->mNumFaces; ++i) {
                 for (size_t j = 0; j < nIndicesPerFace; ++j) {
-                    indices[i*nIndicesPerFace + j] = uint16_t(aim->mFaces[i].mIndices[j]);
+                    indices[i*nIndicesPerFace + j] = IndicesType(aim->mFaces[i].mIndices[j]);
                 }
             }
 
-			p.indices = ExportData(*mAsset, meshId, b, unsigned(indices.size()), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT, true);
+			p.indices = ExportData(*mAsset, meshId, b, unsigned(indices.size()), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_INT, true);
 		}
 
         switch (aim->mPrimitiveTypes) {

+ 177 - 31
code/glTF2Importer.cpp

@@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/ai_assert.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/importerdesc.h>
+#include <assimp/CreateAnimMesh.h>
 
 #include <memory>
 
@@ -65,6 +66,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 using namespace Assimp;
 using namespace glTF2;
 
+namespace {
+    // generate bitangents from normals and tangents according to spec
+    struct Tangent {
+        aiVector3D xyz;
+        ai_real w;
+    };
+} // namespace
 
 //
 // glTF2Importer
@@ -109,18 +117,29 @@ bool glTF2Importer::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool
 
     if (pIOHandler) {
         glTF2::Asset asset(pIOHandler);
-        try {
-            asset.Load(pFile, extension == "glb");
-            std::string version = asset.asset.version;
-            return !version.empty() && version[0] == '2';
-        } catch (...) {
-            return false;
-        }
+        asset.Load(pFile, extension == "glb");
+        std::string version = asset.asset.version;
+        return !version.empty() && version[0] == '2';
     }
 
     return false;
 }
 
+static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode)
+{
+    switch (gltfWrapMode) {
+        case SamplerWrap::Mirrored_Repeat:
+            return aiTextureMapMode_Mirror;
+
+        case SamplerWrap::Clamp_To_Edge:
+            return aiTextureMapMode_Clamp;
+
+        case SamplerWrap::UNSET:
+        case SamplerWrap::Repeat:
+        default:
+            return aiTextureMapMode_Wrap;
+    }
+}
 
 //static void CopyValue(const glTF2::vec3& v, aiColor3D& out)
 //{
@@ -198,8 +217,10 @@ inline void SetMaterialTextureProperty(std::vector<int>& embeddedTexIdxs, Asset&
             mat->AddProperty(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot));
             mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot));
 
-            mat->AddProperty(&sampler->wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot));
-            mat->AddProperty(&sampler->wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot));
+            aiTextureMapMode wrapS = ConvertWrappingMode(sampler->wrapS);
+            aiTextureMapMode wrapT = ConvertWrappingMode(sampler->wrapT);
+            mat->AddProperty(&wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot));
+            mat->AddProperty(&wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot));
 
             if (sampler->magFilter != SamplerMagFilter::UNSET) {
                 mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot));
@@ -399,10 +420,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r)
                 // only extract tangents if normals are present
                 if (attr.tangent.size() > 0 && attr.tangent[0]) {
                     // generate bitangents from normals and tangents according to spec
-                    struct Tangent {
-                        aiVector3D xyz;
-                        ai_real w;
-                    } *tangents = nullptr;
+                    Tangent *tangents = nullptr;
 
                     attr.tangent[0]->ExtractData(tangents);
 
@@ -419,6 +437,12 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r)
             }
 
             for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) {
+                if (attr.texcoord[tc]->count != aim->mNumVertices) {
+                    DefaultLogger::get()->warn("Texcoord stream size in mesh \"" + mesh.name +
+                                               "\" does not match the vertex count");
+                    continue;
+                }
+
                 attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]);
                 aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents();
 
@@ -428,11 +452,57 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r)
                 }
             }
 
+            std::vector<Mesh::Primitive::Target>& targets = prim.targets;
+            if (targets.size() > 0) {
+                aim->mNumAnimMeshes = targets.size();
+                aim->mAnimMeshes = new aiAnimMesh*[aim->mNumAnimMeshes];
+                for (size_t i = 0; i < targets.size(); i++) {
+                    aim->mAnimMeshes[i] = aiCreateAnimMesh(aim);
+                    aiAnimMesh& aiAnimMesh = *(aim->mAnimMeshes[i]);
+                    Mesh::Primitive::Target& target = targets[i];
+
+                    if (target.position.size() > 0) {
+                        aiVector3D *positionDiff = nullptr;
+                        target.position[0]->ExtractData(positionDiff);
+                        for(unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
+                            aiAnimMesh.mVertices[vertexId] += positionDiff[vertexId];
+                        }
+                        delete [] positionDiff;
+                    }
+                    if (target.normal.size() > 0) {
+                        aiVector3D *normalDiff = nullptr;
+                        target.normal[0]->ExtractData(normalDiff);
+                        for(unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
+                            aiAnimMesh.mNormals[vertexId] += normalDiff[vertexId];
+                        }
+                        delete [] normalDiff;
+                    }
+                    if (target.tangent.size() > 0) {
+                        Tangent *tangent = nullptr;
+                        attr.tangent[0]->ExtractData(tangent);
 
-            if (prim.indices) {
-                aiFace* faces = 0;
-                unsigned int nFaces = 0;
+                        aiVector3D *tangentDiff = nullptr;
+                        target.tangent[0]->ExtractData(tangentDiff);
 
+                        for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; ++vertexId) {
+                            tangent[vertexId].xyz += tangentDiff[vertexId];
+                            aiAnimMesh.mTangents[vertexId] = tangent[vertexId].xyz;
+                            aiAnimMesh.mBitangents[vertexId] = (aiAnimMesh.mNormals[vertexId] ^ tangent[vertexId].xyz) * tangent[vertexId].w;
+                        }
+                        delete [] tangent;
+                        delete [] tangentDiff;
+                    }
+                    if (mesh.weights.size() > i) {
+                        aiAnimMesh.mWeight = mesh.weights[i];
+                    }
+                }
+            }
+
+
+            aiFace* faces = 0;
+            unsigned int nFaces = 0;
+
+            if (prim.indices) {
                 unsigned int count = prim.indices->count;
 
                 Accessor::Indexer data = prim.indices->GetIndexer();
@@ -482,9 +552,18 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r)
                     case PrimitiveMode_TRIANGLE_STRIP: {
                         nFaces = count - 2;
                         faces = new aiFace[nFaces];
-                        SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
-                        for (unsigned int i = 3; i < count; ++i) {
-                            SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i));
+                        for (unsigned int i = 0; i < nFaces; ++i) {
+                            //The ordering is to ensure that the triangles are all drawn with the same orientation
+                            if ((i + 1) % 2 == 0)
+                            {
+                                //For even n, vertices n + 1, n, and n + 2 define triangle n
+                                SetFace(faces[i], data.GetUInt(i + 1), data.GetUInt(i), data.GetUInt(i + 2));
+                            }
+                            else
+                            {
+                                //For odd n, vertices n, n+1, and n+2 define triangle n
+                                SetFace(faces[i], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
+                            }
                         }
                         break;
                     }
@@ -492,19 +571,92 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r)
                         nFaces = count - 2;
                         faces = new aiFace[nFaces];
                         SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2));
-                        for (unsigned int i = 3; i < count; ++i) {
-                            SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i));
+                        for (unsigned int i = 1; i < nFaces; ++i) {
+                            SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i + 2));
                         }
                         break;
                 }
+            }
+            else { // no indices provided so directly generate from counts
+
+                // use the already determined count as it includes checks 
+                unsigned int count = aim->mNumVertices;
+
+                switch (prim.mode) {
+                case PrimitiveMode_POINTS: {
+                    nFaces = count;
+                    faces = new aiFace[nFaces];
+                    for (unsigned int i = 0; i < count; ++i) {
+                        SetFace(faces[i], i);
+                    }
+                    break;
+                }
+
+                case PrimitiveMode_LINES: {
+                    nFaces = count / 2;
+                    faces = new aiFace[nFaces];
+                    for (unsigned int i = 0; i < count; i += 2) {
+                        SetFace(faces[i / 2], i, i + 1);
+                    }
+                    break;
+                }
 
-                if (faces) {
-                    aim->mFaces = faces;
-                    aim->mNumFaces = nFaces;
-                    ai_assert(CheckValidFacesIndices(faces, nFaces, aim->mNumVertices));
+                case PrimitiveMode_LINE_LOOP:
+                case PrimitiveMode_LINE_STRIP: {
+                    nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
+                    faces = new aiFace[nFaces];
+                    SetFace(faces[0], 0, 1);
+                    for (unsigned int i = 2; i < count; ++i) {
+                        SetFace(faces[i - 1], faces[i - 2].mIndices[1], i);
+                    }
+                    if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
+                        SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
+                    }
+                    break;
+                }
+
+                case PrimitiveMode_TRIANGLES: {
+                    nFaces = count / 3;
+                    faces = new aiFace[nFaces];
+                    for (unsigned int i = 0; i < count; i += 3) {
+                        SetFace(faces[i / 3], i, i + 1, i + 2);
+                    }
+                    break;
+                }
+                case PrimitiveMode_TRIANGLE_STRIP: {
+                    nFaces = count - 2;
+                    faces = new aiFace[nFaces];
+                    for (unsigned int i = 0; i < nFaces; ++i) {
+                        //The ordering is to ensure that the triangles are all drawn with the same orientation
+                        if ((i+1) % 2 == 0)
+                        {
+                            //For even n, vertices n + 1, n, and n + 2 define triangle n
+                            SetFace(faces[i], i+1, i, i+2);
+                        }
+                        else
+                        {
+                            //For odd n, vertices n, n+1, and n+2 define triangle n
+                            SetFace(faces[i], i, i+1, i+2);
+                        }
+                    }
+                    break;
+                }
+                case PrimitiveMode_TRIANGLE_FAN:
+                    nFaces = count - 2;
+                    faces = new aiFace[nFaces];
+                    SetFace(faces[0], 0, 1, 2);
+                    for (unsigned int i = 1; i < nFaces; ++i) {
+                        SetFace(faces[i], faces[0].mIndices[0], faces[i - 1].mIndices[2], i + 2);
+                    }
+                    break;
                 }
             }
 
+            if (faces) {
+                aim->mFaces = faces;
+                aim->mNumFaces = nFaces;
+                ai_assert(CheckValidFacesIndices(faces, nFaces, aim->mNumVertices));
+            }
 
             if (prim.material) {
                 aim->mMaterialIndex = prim.material.GetIndex();
@@ -716,12 +868,6 @@ void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IO
 
     ImportNodes(asset);
 
-    // TODO: it does not split the loaded vertices, should it?
-    //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
-    MakeVerboseFormatProcess process;
-    process.Execute(pScene);
-
-
     if (pScene->mNumMeshes == 0) {
         pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
     }

+ 71 - 12
code/glTFImporter.cpp

@@ -351,10 +351,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
             }
 
 
-            if (prim.indices) {
-				aiFace* faces = 0;
-                unsigned int nFaces = 0;
+            aiFace* faces = 0;
+            unsigned int nFaces = 0;
 
+            if (prim.indices) {
                 unsigned int count = prim.indices->count;
 
                 Accessor::Indexer data = prim.indices->GetIndexer();
@@ -419,14 +419,78 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
                         }
                         break;
                 }
+            }
+            else { // no indices provided so directly generate from counts
+
+                // use the already determined count as it includes checks 
+                unsigned int count = aim->mNumVertices;
+
+                switch (prim.mode) {
+                case PrimitiveMode_POINTS: {
+                    nFaces = count;
+                    faces = new aiFace[nFaces];
+                    for (unsigned int i = 0; i < count; ++i) {
+                        SetFace(faces[i], i);
+                    }
+                    break;
+                }
+
+                case PrimitiveMode_LINES: {
+                    nFaces = count / 2;
+                    faces = new aiFace[nFaces];
+                    for (unsigned int i = 0; i < count; i += 2) {
+                        SetFace(faces[i / 2], i, i + 1);
+                    }
+                    break;
+                }
+
+                case PrimitiveMode_LINE_LOOP:
+                case PrimitiveMode_LINE_STRIP: {
+                    nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0);
+                    faces = new aiFace[nFaces];
+                    SetFace(faces[0], 0, 1);
+                    for (unsigned int i = 2; i < count; ++i) {
+                        SetFace(faces[i - 1], faces[i - 2].mIndices[1], i);
+                    }
+                    if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop
+                        SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]);
+                    }
+                    break;
+                }
 
-                if (faces) {
-                    aim->mFaces = faces;
-                    aim->mNumFaces = nFaces;
-                    ai_assert(CheckValidFacesIndices(faces, nFaces, aim->mNumVertices));
+                case PrimitiveMode_TRIANGLES: {
+                    nFaces = count / 3;
+                    faces = new aiFace[nFaces];
+                    for (unsigned int i = 0; i < count; i += 3) {
+                        SetFace(faces[i / 3], i, i + 1, i + 2);
+                    }
+                    break;
+                }
+                case PrimitiveMode_TRIANGLE_STRIP: {
+                    nFaces = count - 2;
+                    faces = new aiFace[nFaces];
+                    SetFace(faces[0], 0, 1, 2);
+                    for (unsigned int i = 3; i < count; ++i) {
+                        SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], i);
+                    }
+                    break;
+                }
+                case PrimitiveMode_TRIANGLE_FAN:
+                    nFaces = count - 2;
+                    faces = new aiFace[nFaces];
+                    SetFace(faces[0], 0, 1, 2);
+                    for (unsigned int i = 3; i < count; ++i) {
+                        SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], i);
+                    }
+                    break;
                 }
             }
 
+            if (faces) {
+                aim->mFaces = faces;
+                aim->mNumFaces = nFaces;
+                ai_assert(CheckValidFacesIndices(faces, nFaces, aim->mNumVertices));
+            }
 
             if (prim.material) {
                 aim->mMaterialIndex = prim.material.GetIndex();
@@ -676,11 +740,6 @@ void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOS
 
     ImportNodes(asset);
 
-    // TODO: it does not split the loaded vertices, should it?
-    //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT;
-	MakeVerboseFormatProcess process;
-    process.Execute(pScene);
-
 
     if (pScene->mNumMeshes == 0) {
         pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;

+ 1 - 2
contrib/irrXML/irrArray.h

@@ -21,8 +21,7 @@ class array
 {
 
 public:
-
-	array()
+	array() 
 		: data(0), allocated(0), used(0),
 			free_when_destroyed(true), is_sorted(true)
 	{

+ 6 - 0
contrib/openddlparser/code/OpenDDLParser.cpp

@@ -100,9 +100,15 @@ static bool isUnsignedIntegerType( Value::ValueType integerType ) {
 }
 
 static DDLNode *createDDLNode( Text *id, OpenDDLParser *parser ) {
+    // Basic checks
     if( ddl_nullptr == id || ddl_nullptr == parser ) {
         return ddl_nullptr;
     }
+    
+    // If the buffer is empty ( an empty node ) return nullptr
+    if ( ddl_nullptr == id->m_buffer ) {
+        return ddl_nullptr;
+    }
 
     const std::string type( id->m_buffer );
     DDLNode *parent( parser->top() );

+ 4 - 5
include/assimp/BaseImporter.h

@@ -77,19 +77,17 @@ class IOStream;
  * imports the given file. ReadFile is not overridable, it just calls
  * InternReadFile() and catches any ImportErrorException that might occur.
  */
-class ASSIMP_API BaseImporter
-{
+class ASSIMP_API BaseImporter {
     friend class Importer;
 
 public:
 
     /** Constructor to be privately used by #Importer */
-    BaseImporter();
+    BaseImporter() AI_NO_EXCEPT;
 
     /** Destructor, private as well */
     virtual ~BaseImporter();
 
-public:
     // -------------------------------------------------------------------
     /** Returns whether the class can handle the format of the given file.
      *
@@ -244,7 +242,8 @@ public: // static utilities
         const char** tokens,
         unsigned int numTokens,
         unsigned int searchBytes = 200,
-        bool tokensSol = false);
+        bool tokensSol = false,
+        bool noAlphaBeforeTokens = false);
 
     // -------------------------------------------------------------------
     /** @brief Check whether a file has a specific file extension

+ 2 - 3
include/assimp/ByteSwapper.h

@@ -60,9 +60,8 @@ namespace Assimp    {
  * This is required to read big-endian model formats on little-endian machines,
  * and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */
 // --------------------------------------------------------------------------------------
-class ByteSwap
-{
-    ByteSwap() {}
+class ByteSwap {
+    ByteSwap() AI_NO_EXCEPT {}
 
 public:
 

+ 11 - 13
include/assimp/DefaultIOStream.h

@@ -69,7 +69,7 @@ class ASSIMP_API DefaultIOStream : public IOStream
 #endif // __ANDROID__
 
 protected:
-    DefaultIOStream();
+    DefaultIOStream() AI_NO_EXCEPT;
     DefaultIOStream(FILE* pFile, const std::string &strFilename);
 
 public:
@@ -111,27 +111,25 @@ private:
     FILE* mFile;
     //  Filename
     std::string mFilename;
-
     // Cached file size
     mutable size_t mCachedSize;
 };
 
 // ----------------------------------------------------------------------------------
-inline DefaultIOStream::DefaultIOStream () :
-    mFile       (NULL),
-    mFilename   (""),
-    mCachedSize(SIZE_MAX)
-{
+inline
+DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT
+: mFile(nullptr)
+, mFilename("")
+, mCachedSize(SIZE_MAX) {
     // empty
 }
 
 // ----------------------------------------------------------------------------------
-inline DefaultIOStream::DefaultIOStream (FILE* pFile,
-        const std::string &strFilename) :
-    mFile(pFile),
-    mFilename(strFilename),
-    mCachedSize(SIZE_MAX)
-{
+inline
+DefaultIOStream::DefaultIOStream (FILE* pFile, const std::string &strFilename)
+: mFile(pFile)
+, mFilename(strFilename)
+, mCachedSize(SIZE_MAX) {
     // empty
 }
 // ----------------------------------------------------------------------------------

+ 1 - 2
include/assimp/DefaultIOSystem.h

@@ -50,8 +50,7 @@ namespace Assimp    {
 
 // ---------------------------------------------------------------------------
 /** Default implementation of IOSystem using the standard C file functions */
-class ASSIMP_API DefaultIOSystem : public IOSystem
-{
+class ASSIMP_API DefaultIOSystem : public IOSystem {
 public:
     // -------------------------------------------------------------------
     /** Tests for the existence of a file at the given path. */

+ 2 - 2
include/assimp/IOStream.hpp

@@ -71,7 +71,7 @@ class ASSIMP_API IOStream
 {
 protected:
     /** Constructor protected, use IOSystem::Open() to create an instance. */
-    IOStream();
+    IOStream() AI_NO_EXCEPT;
 
 public:
     // -------------------------------------------------------------------
@@ -126,7 +126,7 @@ public:
 
 // ----------------------------------------------------------------------------------
 inline
-IOStream::IOStream() {
+IOStream::IOStream() AI_NO_EXCEPT {
     // empty
 }
 

+ 2 - 5
include/assimp/IOSystem.hpp

@@ -95,7 +95,7 @@ public:
      *  Create an instance of your derived class and assign it to an
      *  #Assimp::Importer instance by calling Importer::SetIOHandler().
      */
-    IOSystem();
+    IOSystem() AI_NO_EXCEPT;
 
     // -------------------------------------------------------------------
     /** @brief Virtual destructor.
@@ -105,9 +105,6 @@ public:
      */
     virtual ~IOSystem();
 
-
-public:
-
     // -------------------------------------------------------------------
     /** @brief For backward compatibility
      *  @see Exists(const char*)
@@ -233,7 +230,7 @@ private:
 
 // ----------------------------------------------------------------------------
 AI_FORCE_INLINE
-IOSystem::IOSystem()
+IOSystem::IOSystem() AI_NO_EXCEPT
 : m_pathStack() {
     // empty
 }

+ 163 - 122
include/assimp/LineSplitter.h

@@ -44,11 +44,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief LineSplitter, a helper class to iterate through all lines
  *    of a file easily. Works with StreamReader.
  */
+#pragma once
 #ifndef INCLUDED_LINE_SPLITTER_H
 #define INCLUDED_LINE_SPLITTER_H
 
 #include <stdexcept>
-
 #include "StreamReader.h"
 #include "ParsingUtils.h"
 
@@ -81,164 +81,205 @@ public:
     /** construct from existing stream reader
     note: trim is *always* assumed true if skyp_empty_lines==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) {
-        cur.reserve(1024);
-        operator++();
-
-        idx = 0;
-    }
-
-    ~LineSplitter() {
-        // empty
-    }
+    LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true);
 
-public:
+    ~LineSplitter();
 
     // -----------------------------------------
     /** pseudo-iterator increment */
-    LineSplitter& operator++() {
-        if(swallow) {
-            swallow = false;
-            return *this;
-        }
-        if (!*this) {
-            throw std::logic_error("End of file, no more lines to be retrieved.");
-        }
-        char s;
-        cur.clear();
-        while(stream.GetRemainingSize() && (s = stream.GetI1(),1)) {
-            if (s == '\n' || s == '\r') {
-                if (skip_empty_lines) {
-                    while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\r' || s == '\n'));
-                    if (stream.GetRemainingSize()) {
-                        stream.IncPtr(-1);
-                    }
-                }
-                else {
-                    // skip both potential line terminators but don't read past this line.
-                    if (stream.GetRemainingSize() && (s == '\r' && stream.GetI1() != '\n')) {
-                        stream.IncPtr(-1);
-                    }
-                    if (trim) {
-                        while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\t'));
-                        if (stream.GetRemainingSize()) {
-                            stream.IncPtr(-1);
-                        }
-                    }
-                }
-                break;
-            }
-            cur += s;
-        }
-        ++idx;
-        return *this;
-    }
+    LineSplitter& operator++();
 
     // -----------------------------------------
-    LineSplitter& operator++(int) {
-        return ++(*this);
-    }
+    LineSplitter& operator++(int);
 
     // -----------------------------------------
     /** get a pointer to the beginning of a particular token */
-    const char* operator[] (size_t idx) const {
-        const char* s = operator->()->c_str();
-
-        SkipSpaces(&s);
-        for(size_t i = 0; i < idx; ++i) {
-
-            for(;!IsSpace(*s); ++s) {
-                if(IsLineEnd(*s)) {
-                    throw std::range_error("Token index out of range, EOL reached");
-                }
-            }
-            SkipSpaces(&s);
-        }
-        return s;
-    }
+    const char* operator[] (size_t idx) const;
 
     // -----------------------------------------
     /** extract the start positions of N tokens from the current line*/
     template <size_t N>
-    void get_tokens(const char* (&tokens)[N]) const {
-        const char* s = operator->()->c_str();
-
-        SkipSpaces(&s);
-        for(size_t i = 0; i < N; ++i) {
-            if(IsLineEnd(*s)) {
-
-                throw std::range_error("Token count out of range, EOL reached");
-
-            }
-            tokens[i] = s;
-
-            for(;*s && !IsSpace(*s); ++s);
-            SkipSpaces(&s);
-        }
-    }
+    void get_tokens(const char* (&tokens)[N]) const;
 
     // -----------------------------------------
     /** member access */
-    const std::string* operator -> () const {
-        return &cur;
-    }
+    const std::string* operator -> () const;
 
-    std::string operator* () const {
-        return cur;
-    }
+    std::string operator* () const;
 
     // -----------------------------------------
     /** boolean context */
-    operator bool() const {
-        return stream.GetRemainingSize()>0;
-    }
+    operator bool() const;
 
     // -----------------------------------------
     /** line indices are zero-based, empty lines are included */
-    operator line_idx() const {
-        return idx;
-    }
+    operator line_idx() const;
 
-    line_idx get_index() const {
-        return idx;
-    }
+    line_idx get_index() const;
 
     // -----------------------------------------
     /** access the underlying stream object */
-    StreamReaderLE& get_stream() {
-        return stream;
-    }
+    StreamReaderLE& get_stream();
 
     // -----------------------------------------
     /** !strcmp((*this)->substr(0,strlen(check)),check) */
-    bool match_start(const char* check) {
-        const size_t len = strlen(check);
-
-        return len <= cur.length() && std::equal(check,check+len,cur.begin());
-    }
-
+    bool match_start(const char* check);
 
     // -----------------------------------------
     /** swallow the next call to ++, return the previous value. */
-    void swallow_next_increment() {
-        swallow = true;
-    }
+    void swallow_next_increment();
 
-private:
-    LineSplitter( const LineSplitter & );
-    LineSplitter &operator = ( const LineSplitter & );
+    LineSplitter( const LineSplitter & ) = delete;
+    LineSplitter(LineSplitter &&) = delete;
+    LineSplitter &operator = ( const LineSplitter & ) = delete;
 
 private:
-    line_idx idx;
-    std::string cur;
-    StreamReaderLE& stream;
-    bool swallow, skip_empty_lines, trim;
+    line_idx mIdx;
+    std::string mCur;
+    StreamReaderLE& mStream;
+    bool mSwallow, mSkip_empty_lines, mTrim;
 };
 
+inline
+LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim )
+: mIdx(0)
+, mCur()
+, mStream(stream)
+, mSwallow()
+, mSkip_empty_lines(skip_empty_lines)
+, mTrim(trim) {
+    mCur.reserve(1024);
+    operator++();
+    mIdx = 0;
+}
+
+inline
+LineSplitter::~LineSplitter() {
+    // empty
+}
+
+inline
+LineSplitter& LineSplitter::operator++() {
+    if (mSwallow) {
+        mSwallow = false;
+        return *this;
+    }
+
+    if (!*this) {
+        throw std::logic_error("End of file, no more lines to be retrieved.");
+    }
+
+    char s;
+    mCur.clear();
+    while (mStream.GetRemainingSize() && (s = mStream.GetI1(), 1)) {
+        if (s == '\n' || s == '\r') {
+            if (mSkip_empty_lines) {
+                while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\r' || s == '\n'));
+                if (mStream.GetRemainingSize()) {
+                    mStream.IncPtr(-1);
+                }
+            } else {
+                // skip both potential line terminators but don't read past this line.
+                if (mStream.GetRemainingSize() && (s == '\r' && mStream.GetI1() != '\n')) {
+                    mStream.IncPtr(-1);
+                }
+                if (mTrim) {
+                    while (mStream.GetRemainingSize() && ((s = mStream.GetI1()) == ' ' || s == '\t'));
+                    if (mStream.GetRemainingSize()) {
+                        mStream.IncPtr(-1);
+                    }
+                }
+            }
+            break;
+        }
+        mCur += s;
+    }
+    ++mIdx;
+
+    return *this;
+}
+
+inline
+LineSplitter &LineSplitter::operator++(int) {
+    return ++(*this);
+}
+
+inline
+const char *LineSplitter::operator[] (size_t idx) const {
+    const char* s = operator->()->c_str();
+
+    SkipSpaces(&s);
+    for (size_t i = 0; i < idx; ++i) {
+
+        for (; !IsSpace(*s); ++s) {
+            if (IsLineEnd(*s)) {
+                throw std::range_error("Token index out of range, EOL reached");
+            }
+        }
+        SkipSpaces(&s);
+    }
+    return s;
+}
+
+template <size_t N>
+inline
+void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
+    const char* s = operator->()->c_str();
+
+    SkipSpaces(&s);
+    for (size_t i = 0; i < N; ++i) {
+        if (IsLineEnd(*s)) {
+            throw std::range_error("Token count out of range, EOL reached");
+        }
+        tokens[i] = s;
+
+        for (; *s && !IsSpace(*s); ++s);
+        SkipSpaces(&s);
+    }
+}
+
+inline
+const std::string* LineSplitter::operator -> () const {
+    return &mCur;
+}
+
+inline
+std::string LineSplitter::operator* () const {
+    return mCur;
+}
+
+inline
+LineSplitter::operator bool() const {
+    return mStream.GetRemainingSize() > 0;
+}
+
+inline
+LineSplitter::operator line_idx() const {
+    return mIdx;
+}
+
+inline
+LineSplitter::line_idx LineSplitter::get_index() const {
+    return mIdx;
+}
+
+inline
+StreamReaderLE &LineSplitter::get_stream() {
+    return mStream;
+}
+
+inline
+bool LineSplitter::match_start(const char* check) {
+    const size_t len = ::strlen(check);
+
+    return len <= mCur.length() && std::equal(check, check + len, mCur.begin());
+}
+
+inline
+void LineSplitter::swallow_next_increment() {
+    mSwallow = true;
 }
+
+} // Namespace Assimp
+
 #endif // INCLUDED_LINE_SPLITTER_H

+ 3 - 3
include/assimp/LogStream.hpp

@@ -65,7 +65,7 @@ class ASSIMP_API LogStream
 {
 protected:
     /** @brief  Default constructor */
-    LogStream();
+    LogStream() AI_NO_EXCEPT;
 
 public:
     /** @brief  Virtual destructor  */
@@ -91,12 +91,12 @@ public:
      *  @return New LogStream instance.  */
     static LogStream* createDefaultStream(aiDefaultLogStream stream,
         const char* name = "AssimpLog.txt",
-        IOSystem* io = NULL);
+        IOSystem* io = nullptr );
 
 }; // !class LogStream
 
 inline
-LogStream::LogStream() {
+LogStream::LogStream() AI_NO_EXCEPT {
     // empty
 }
 

+ 7 - 5
include/assimp/Logger.hpp

@@ -161,7 +161,7 @@ protected:
     /**
      *  Default constructor
      */
-    Logger();
+    Logger() AI_NO_EXCEPT;
 
     /**
      *  Construction with a given log severity
@@ -215,8 +215,9 @@ protected:
 // ----------------------------------------------------------------------------------
 //  Default constructor
 inline
-Logger::Logger() {
-    setLogSeverity(NORMAL);
+Logger::Logger() AI_NO_EXCEPT
+: m_Severity(NORMAL) {
+    // empty
 }
 
 // ----------------------------------------------------------------------------------
@@ -229,8 +230,9 @@ Logger::~Logger() {
 // ----------------------------------------------------------------------------------
 // Construction with given logging severity
 inline
-Logger::Logger(LogSeverity severity) {
-    setLogSeverity(severity);
+Logger::Logger(LogSeverity severity)
+: m_Severity(severity) {
+    // empty
 }
 
 // ----------------------------------------------------------------------------------

部分文件因文件數量過多而無法顯示