Browse Source

Updated assimp to commit 1d565b0 with iFire

Signed-off-by: RevoluPowered <[email protected]>
Signed-off-by: K. S. Ernest (iFIre) Lee <[email protected]>
RevoluPowered 6 years ago
parent
commit
243f400ee2
100 changed files with 2034 additions and 2325 deletions
  1. 10 3
      modules/assimp/SCsub
  2. 2 1
      modules/assimp/godot_update_assimp.sh
  3. 1 1
      thirdparty/README.md
  4. 16 0
      thirdparty/assimp/assimp/config.h
  5. 156 0
      thirdparty/assimp/code/CApi/AssimpCExport.cpp
  6. 0 0
      thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp
  7. 0 0
      thirdparty/assimp/code/CApi/CInterfaceIOWrapper.h
  8. 695 0
      thirdparty/assimp/code/Common/Assimp.cpp
  9. 5 1
      thirdparty/assimp/code/Common/BaseImporter.cpp
  10. 1 1
      thirdparty/assimp/code/Common/BaseProcess.cpp
  11. 0 0
      thirdparty/assimp/code/Common/BaseProcess.h
  12. 0 0
      thirdparty/assimp/code/Common/Bitmap.cpp
  13. 0 4
      thirdparty/assimp/code/Common/CreateAnimMesh.cpp
  14. 0 0
      thirdparty/assimp/code/Common/DefaultIOStream.cpp
  15. 0 0
      thirdparty/assimp/code/Common/DefaultIOSystem.cpp
  16. 0 0
      thirdparty/assimp/code/Common/DefaultLogger.cpp
  17. 0 0
      thirdparty/assimp/code/Common/DefaultProgressHandler.h
  18. 19 13
      thirdparty/assimp/code/Common/Exporter.cpp
  19. 0 0
      thirdparty/assimp/code/Common/FileLogStream.h
  20. 0 0
      thirdparty/assimp/code/Common/FileSystemFilter.h
  21. 102 0
      thirdparty/assimp/code/Common/IFF.h
  22. 11 8
      thirdparty/assimp/code/Common/Importer.cpp
  23. 0 0
      thirdparty/assimp/code/Common/Importer.h
  24. 48 48
      thirdparty/assimp/code/Common/ImporterRegistry.cpp
  25. 0 0
      thirdparty/assimp/code/Common/PolyTools.h
  26. 35 28
      thirdparty/assimp/code/Common/PostStepRegistry.cpp
  27. 0 0
      thirdparty/assimp/code/Common/RemoveComments.cpp
  28. 0 0
      thirdparty/assimp/code/Common/SGSpatialSort.cpp
  29. 0 0
      thirdparty/assimp/code/Common/SceneCombiner.cpp
  30. 0 0
      thirdparty/assimp/code/Common/ScenePreprocessor.cpp
  31. 0 0
      thirdparty/assimp/code/Common/ScenePreprocessor.h
  32. 0 0
      thirdparty/assimp/code/Common/ScenePrivate.h
  33. 0 0
      thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp
  34. 0 0
      thirdparty/assimp/code/Common/SpatialSort.cpp
  35. 0 0
      thirdparty/assimp/code/Common/SplitByBoneCountProcess.cpp
  36. 0 0
      thirdparty/assimp/code/Common/SplitByBoneCountProcess.h
  37. 0 0
      thirdparty/assimp/code/Common/StandardShapes.cpp
  38. 0 0
      thirdparty/assimp/code/Common/StdOStreamLogStream.h
  39. 4 3
      thirdparty/assimp/code/Common/Subdivision.cpp
  40. 0 0
      thirdparty/assimp/code/Common/TargetAnimation.cpp
  41. 0 0
      thirdparty/assimp/code/Common/TargetAnimation.h
  42. 1 1
      thirdparty/assimp/code/Common/Version.cpp
  43. 0 0
      thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp
  44. 0 0
      thirdparty/assimp/code/Common/VertexTriangleAdjacency.h
  45. 0 0
      thirdparty/assimp/code/Common/Win32DebugLogStream.h
  46. 196 0
      thirdparty/assimp/code/Common/assbin_chunks.h
  47. 0 0
      thirdparty/assimp/code/Common/scene.cpp
  48. 0 0
      thirdparty/assimp/code/Common/simd.cpp
  49. 0 0
      thirdparty/assimp/code/Common/simd.h
  50. 0 0
      thirdparty/assimp/code/FBX/FBXAnimation.cpp
  51. 6 6
      thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp
  52. 2 2
      thirdparty/assimp/code/FBX/FBXCommon.h
  53. 0 0
      thirdparty/assimp/code/FBX/FBXCompileConfig.h
  54. 184 84
      thirdparty/assimp/code/FBX/FBXConverter.cpp
  55. 29 8
      thirdparty/assimp/code/FBX/FBXConverter.h
  56. 0 0
      thirdparty/assimp/code/FBX/FBXDeformer.cpp
  57. 0 0
      thirdparty/assimp/code/FBX/FBXDocument.cpp
  58. 2 2
      thirdparty/assimp/code/FBX/FBXDocument.h
  59. 0 0
      thirdparty/assimp/code/FBX/FBXDocumentUtil.cpp
  60. 0 0
      thirdparty/assimp/code/FBX/FBXDocumentUtil.h
  61. 7 4
      thirdparty/assimp/code/FBX/FBXExportNode.cpp
  62. 6 6
      thirdparty/assimp/code/FBX/FBXExportNode.h
  63. 141 116
      thirdparty/assimp/code/FBX/FBXExportProperty.cpp
  64. 24 24
      thirdparty/assimp/code/FBX/FBXExportProperty.h
  65. 89 26
      thirdparty/assimp/code/FBX/FBXExporter.cpp
  66. 0 0
      thirdparty/assimp/code/FBX/FBXExporter.h
  67. 25 14
      thirdparty/assimp/code/FBX/FBXImportSettings.h
  68. 8 2
      thirdparty/assimp/code/FBX/FBXImporter.cpp
  69. 0 0
      thirdparty/assimp/code/FBX/FBXImporter.h
  70. 34 10
      thirdparty/assimp/code/FBX/FBXMaterial.cpp
  71. 6 5
      thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp
  72. 0 0
      thirdparty/assimp/code/FBX/FBXMeshGeometry.h
  73. 0 0
      thirdparty/assimp/code/FBX/FBXModel.cpp
  74. 0 0
      thirdparty/assimp/code/FBX/FBXNodeAttribute.cpp
  75. 4 8
      thirdparty/assimp/code/FBX/FBXParser.cpp
  76. 0 0
      thirdparty/assimp/code/FBX/FBXParser.h
  77. 0 0
      thirdparty/assimp/code/FBX/FBXProperties.cpp
  78. 0 0
      thirdparty/assimp/code/FBX/FBXProperties.h
  79. 0 0
      thirdparty/assimp/code/FBX/FBXTokenizer.cpp
  80. 6 6
      thirdparty/assimp/code/FBX/FBXTokenizer.h
  81. 107 28
      thirdparty/assimp/code/FBX/FBXUtil.cpp
  82. 20 3
      thirdparty/assimp/code/FBX/FBXUtil.h
  83. 0 1834
      thirdparty/assimp/code/FIReader.cpp
  84. 0 0
      thirdparty/assimp/code/MMD/MMDCpp14.h
  85. 7 5
      thirdparty/assimp/code/MMD/MMDImporter.cpp
  86. 0 0
      thirdparty/assimp/code/MMD/MMDImporter.h
  87. 0 0
      thirdparty/assimp/code/MMD/MMDPmdParser.h
  88. 5 1
      thirdparty/assimp/code/MMD/MMDPmxParser.cpp
  89. 0 0
      thirdparty/assimp/code/MMD/MMDPmxParser.h
  90. 0 0
      thirdparty/assimp/code/MMD/MMDVmdParser.h
  91. 7 5
      thirdparty/assimp/code/Material/MaterialSystem.cpp
  92. 0 0
      thirdparty/assimp/code/Material/MaterialSystem.h
  93. 0 0
      thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.cpp
  94. 2 2
      thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.h
  95. 0 0
      thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp
  96. 2 1
      thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.h
  97. 0 0
      thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.cpp
  98. 2 1
      thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.h
  99. 0 0
      thirdparty/assimp/code/PostProcessing/DeboneProcess.cpp
  100. 7 10
      thirdparty/assimp/code/PostProcessing/DeboneProcess.h

+ 10 - 3
modules/assimp/SCsub

@@ -9,6 +9,7 @@ env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/include'])
 env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/code/Importer/IFC'])
 env_assimp.Prepend(CPPPATH=['#thirdparty/misc'])
 env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/code'])
+env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/common'])
 env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/contrib/irrXML/'])
 env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/contrib/unzip/'])
 env_assimp.Prepend(CPPPATH=['#thirdparty/assimp/code/Importer/STEPParser'])
@@ -65,11 +66,11 @@ env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_STEP_IMPORTER'])
 env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_IFC_IMPORTER'])
 env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_XGL_IMPORTER'])
 env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_ASSBIN_IMPORTER'])
-env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_GLTF_IMPORTER'])
 env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_C4D_IMPORTER'])
 env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_3MF_IMPORTER'])
 env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_X3D_IMPORTER'])
-
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_GLTF_IMPORTER'])
+env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_NO_GLTF2_IMPORTER'])
 env_assimp.Append(CPPDEFINES=['ASSIMP_BUILD_SINGLETHREADED'])
 
 if(env['platform'] == 'windows'):
@@ -84,7 +85,13 @@ elif(env['platform'] == 'osx'):
     
 env_thirdparty = env_assimp.Clone()
 env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/*.cpp'))
+env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/Common/*.cpp'))
+env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/PostProcessing/*.cpp'))
+env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/Material/*.cpp'))
+env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/FBX/*.cpp'))
+env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/MMD/*.cpp'))
+env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/glTF/*.cpp'))
+env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/glTF2/*.cpp'))
 
 # Godot's own source files
 env_assimp.add_source_files(env.modules_sources, "*.cpp")

+ 2 - 1
modules/assimp/godot_update_assimp.sh

@@ -254,8 +254,9 @@ rm -rf contrib/irrXML
 rm -rf contrib/Open3DGC
 rm -rf contrib/openddlparser
 rm -rf contrib/poly2tri
-rm -rf contrib/rapidjson
+#rm -rf contrib/rapidjson
 rm -rf contrib/unzip
 rm -rf contrib/zip
 rm -rf contrib/stb_image
 rm .travis*
+

+ 1 - 1
thirdparty/README.md

@@ -4,7 +4,7 @@
 ## assimp
 
 - Upstream: http://github.com/assimp/assimp
-- Version: git (d3d98a7ec0c8d38e1952b46dfe53f7e9233dc92d)
+- Version: git (1d565b0aab5a2ee00462f18c5b8a81f6a5454a48)
 - License: BSD-3-Clause
 
 

+ 16 - 0
thirdparty/assimp/assimp/config.h

@@ -646,6 +646,21 @@ enum aiComponent {
 #define AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING \
 	"AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
 
+// ---------------------------------------------------------------------------
+/** @brief  Set wether the FBX importer shall not remove empty bones.
+ *  
+ *  
+ *  Empty bone are often used to define connections for other models.
+ */
+#define AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES \
+    "AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES"
+
+// ---------------------------------------------------------------------------
+/** @brief  Set wether the FBX importer shall convert the unit from cm to m.
+ */
+#define AI_CONFIG_FBX_CONVERT_TO_M \
+    "AI_CONFIG_FBX_CONVERT_TO_M"
+
 // ---------------------------------------------------------------------------
 /** @brief  Set the vertex animation keyframe to be imported
  *
@@ -978,3 +993,4 @@ enum aiComponent {
 /* #cmakedefine ASSIMP_DOUBLE_PRECISION 1 */
 
 #endif // !! AI_CONFIG_H_INC
+

+ 156 - 0
thirdparty/assimp/code/CApi/AssimpCExport.cpp

@@ -0,0 +1,156 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+/** @file AssimpCExport.cpp
+Assimp C export interface. See Exporter.cpp for some notes.
+*/
+
+#ifndef ASSIMP_BUILD_NO_EXPORT
+
+#include "CInterfaceIOWrapper.h"
+#include <assimp/SceneCombiner.h>
+#include "Common/ScenePrivate.h"
+#include <assimp/Exporter.hpp>
+
+using namespace Assimp;
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API size_t aiGetExportFormatCount(void)
+{
+    return Exporter().GetExportFormatCount();
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index)
+{
+    // Note: this is valid as the index always pertains to a built-in exporter,
+    // for which the returned structure is guaranteed to be of static storage duration.
+    Exporter exporter;
+    const aiExportFormatDesc* orig( exporter.GetExportFormatDescription( index ) );
+    if (NULL == orig) {
+        return NULL;
+    }
+
+    aiExportFormatDesc *desc = new aiExportFormatDesc;
+    desc->description = new char[ strlen( orig->description ) + 1 ]();
+    ::strncpy( (char*) desc->description, orig->description, strlen( orig->description ) );
+    desc->fileExtension = new char[ strlen( orig->fileExtension ) + 1 ]();
+    ::strncpy( ( char* ) desc->fileExtension, orig->fileExtension, strlen( orig->fileExtension ) );
+    desc->id = new char[ strlen( orig->id ) + 1 ]();
+    ::strncpy( ( char* ) desc->id, orig->id, strlen( orig->id ) );
+
+    return desc;
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiReleaseExportFormatDescription( const aiExportFormatDesc *desc ) {
+    if (NULL == desc) {
+        return;
+    }
+
+    delete [] desc->description;
+    delete [] desc->fileExtension;
+    delete [] desc->id;
+    delete desc;
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut)
+{
+    if (!pOut || !pIn) {
+        return;
+    }
+
+    SceneCombiner::CopyScene(pOut,pIn,true);
+    ScenePriv(*pOut)->mIsCopy = true;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiFreeScene(const C_STRUCT aiScene* pIn)
+{
+    // note: aiReleaseImport() is also able to delete scene copies, but in addition
+    // it also handles scenes with import metadata.
+    delete pIn;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing )
+{
+    return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing);
+}
+
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, aiFileIO* pIO, unsigned int pPreprocessing )
+{
+    Exporter exp;
+
+    if (pIO) {
+        exp.SetIOHandler(new CIOSystemWrapper(pIO));
+    }
+    return exp.Export(pScene,pFormatId,pFileName,pPreprocessing);
+}
+
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing  )
+{
+    Exporter exp;
+    if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) {
+        return NULL;
+    }
+    const aiExportDataBlob* blob = exp.GetOrphanedBlob();
+    ai_assert(blob);
+
+    return blob;
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API C_STRUCT void aiReleaseExportBlob( const aiExportDataBlob* pData )
+{
+    delete pData;
+}
+
+#endif // !ASSIMP_BUILD_NO_EXPORT

+ 0 - 0
thirdparty/assimp/code/CInterfaceIOWrapper.cpp → thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp


+ 0 - 0
thirdparty/assimp/code/CInterfaceIOWrapper.h → thirdparty/assimp/code/CApi/CInterfaceIOWrapper.h


+ 695 - 0
thirdparty/assimp/code/Common/Assimp.cpp

@@ -0,0 +1,695 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2019, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+/** @file  Assimp.cpp
+ *  @brief Implementation of the Plain-C API
+ */
+
+#include <assimp/cimport.h>
+#include <assimp/LogStream.hpp>
+#include <assimp/DefaultLogger.hpp>
+#include <assimp/Importer.hpp>
+#include <assimp/importerdesc.h>
+#include <assimp/scene.h>
+#include <assimp/GenericProperty.h>
+#include <assimp/Exceptional.h>
+#include <assimp/BaseImporter.h>
+
+#include "CApi/CInterfaceIOWrapper.h"
+#include "Importer.h"
+#include "ScenePrivate.h"
+
+#include <list>
+
+// ------------------------------------------------------------------------------------------------
+#ifndef ASSIMP_BUILD_SINGLETHREADED
+#   include <thread>
+#   include <mutex>
+#endif
+// ------------------------------------------------------------------------------------------------
+using namespace Assimp;
+
+namespace Assimp {
+    // underlying structure for aiPropertyStore
+    typedef BatchLoader::PropertyMap PropertyMap;
+
+    /** Stores the LogStream objects for all active C log streams */
+    struct mpred {
+        bool operator  () (const aiLogStream& s0, const aiLogStream& s1) const  {
+            return s0.callback<s1.callback&&s0.user<s1.user;
+        }
+    };
+    typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
+
+    /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
+    typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
+
+    /** Local storage of all active log streams */
+    static LogStreamMap gActiveLogStreams;
+
+    /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
+    static PredefLogStreamMap gPredefinedStreams;
+
+    /** Error message of the last failed import process */
+    static std::string gLastErrorString;
+
+    /** Verbose logging active or not? */
+    static aiBool gVerboseLogging = false;
+
+    /** will return all registered importers. */
+    void GetImporterInstanceList(std::vector< BaseImporter* >& out);
+
+    /** will delete all registered importers. */
+    void DeleteImporterInstanceList(std::vector< BaseImporter* >& out);
+} // namespace assimp
+
+
+#ifndef ASSIMP_BUILD_SINGLETHREADED
+/** Global mutex to manage the access to the log-stream map */
+static std::mutex gLogStreamMutex;
+#endif
+
+// ------------------------------------------------------------------------------------------------
+// Custom LogStream implementation for the C-API
+class LogToCallbackRedirector : public LogStream {
+public:
+    explicit LogToCallbackRedirector(const aiLogStream& s)
+    : stream (s)    {
+        ai_assert(NULL != s.callback);
+    }
+
+    ~LogToCallbackRedirector()  {
+#ifndef ASSIMP_BUILD_SINGLETHREADED
+        std::lock_guard<std::mutex> lock(gLogStreamMutex);
+#endif
+        // (HACK) Check whether the 'stream.user' pointer points to a
+        // custom LogStream allocated by #aiGetPredefinedLogStream.
+        // In this case, we need to delete it, too. Of course, this
+        // might cause strange problems, but the chance is quite low.
+
+        PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
+            gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
+
+        if (it != gPredefinedStreams.end()) {
+            delete *it;
+            gPredefinedStreams.erase(it);
+        }
+    }
+
+    /** @copydoc LogStream::write */
+    void write(const char* message) {
+        stream.callback(message,stream.user);
+    }
+
+private:
+    aiLogStream stream;
+};
+
+// ------------------------------------------------------------------------------------------------
+void ReportSceneNotFoundError() {
+    ASSIMP_LOG_ERROR("Unable to find the Assimp::Importer for this aiScene. "
+        "The C-API does not accept scenes produced by the C++ API and vice versa");
+
+    ai_assert(false);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Reads the given file and returns its content.
+const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) {
+    return aiImportFileEx(pFile,pFlags,NULL);
+}
+
+// ------------------------------------------------------------------------------------------------
+const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,  aiFileIO* pFS) {
+    return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
+}
+
+// ------------------------------------------------------------------------------------------------
+const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, 
+        aiFileIO* pFS, const aiPropertyStore* props) {
+    ai_assert(NULL != pFile);
+
+    const aiScene* scene = NULL;
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // create an Importer for this file
+    Assimp::Importer* imp = new Assimp::Importer();
+
+    // copy properties
+    if(props) {
+        const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
+        ImporterPimpl* pimpl = imp->Pimpl();
+        pimpl->mIntProperties = pp->ints;
+        pimpl->mFloatProperties = pp->floats;
+        pimpl->mStringProperties = pp->strings;
+        pimpl->mMatrixProperties = pp->matrices;
+    }
+    // setup a custom IO system if necessary
+    if (pFS) {
+        imp->SetIOHandler( new CIOSystemWrapper (pFS) );
+    }
+
+    // and have it read the file
+    scene = imp->ReadFile( pFile, pFlags);
+
+    // if succeeded, store the importer in the scene and keep it alive
+    if( scene)  {
+        ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
+        priv->mOrigImporter = imp;
+    } else {
+        // if failed, extract error code and destroy the import
+        gLastErrorString = imp->GetErrorString();
+        delete imp;
+    }
+
+    // return imported data. If the import failed the pointer is NULL anyways
+    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    
+    return scene;
+}
+
+// ------------------------------------------------------------------------------------------------
+const aiScene* aiImportFileFromMemory(
+    const char* pBuffer,
+    unsigned int pLength,
+    unsigned int pFlags,
+    const char* pHint)
+{
+    return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
+}
+
+// ------------------------------------------------------------------------------------------------
+const aiScene* aiImportFileFromMemoryWithProperties(
+    const char* pBuffer,
+    unsigned int pLength,
+    unsigned int pFlags,
+    const char* pHint,
+    const aiPropertyStore* props)
+{
+    ai_assert( NULL != pBuffer );
+    ai_assert( 0 != pLength );
+
+    const aiScene* scene = NULL;
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // create an Importer for this file
+    Assimp::Importer* imp = new Assimp::Importer();
+
+    // copy properties
+    if(props) {
+        const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
+        ImporterPimpl* pimpl = imp->Pimpl();
+        pimpl->mIntProperties = pp->ints;
+        pimpl->mFloatProperties = pp->floats;
+        pimpl->mStringProperties = pp->strings;
+        pimpl->mMatrixProperties = pp->matrices;
+    }
+
+    // and have it read the file from the memory buffer
+    scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
+
+    // if succeeded, store the importer in the scene and keep it alive
+    if( scene)  {
+         ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
+         priv->mOrigImporter = imp;
+    }
+    else    {
+        // if failed, extract error code and destroy the import
+        gLastErrorString = imp->GetErrorString();
+        delete imp;
+    }
+    // return imported data. If the import failed the pointer is NULL anyways
+    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    return scene;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Releases all resources associated with the given import process.
+void aiReleaseImport( const aiScene* pScene)
+{
+    if (!pScene) {
+        return;
+    }
+
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // find the importer associated with this data
+    const ScenePrivateData* priv = ScenePriv(pScene);
+    if( !priv || !priv->mOrigImporter)  {
+        delete pScene;
+    }
+    else {
+        // deleting the Importer also deletes the scene
+        // Note: the reason that this is not written as 'delete priv->mOrigImporter'
+        // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
+        Importer* importer = priv->mOrigImporter;
+        delete importer;
+    }
+
+    ASSIMP_END_EXCEPTION_REGION(void);
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene,
+    unsigned int pFlags)
+{
+    const aiScene* sc = NULL;
+
+
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // find the importer associated with this data
+    const ScenePrivateData* priv = ScenePriv(pScene);
+    if( !priv || !priv->mOrigImporter)  {
+        ReportSceneNotFoundError();
+        return NULL;
+    }
+
+    sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
+
+    if (!sc) {
+        aiReleaseImport(pScene);
+        return NULL;
+    }
+
+    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
+    return sc;
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing( const aiScene *scene,
+                                                           BaseProcess* process,
+                                                           bool requestValidation ) {
+    const aiScene* sc( NULL );
+
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // find the importer associated with this data
+    const ScenePrivateData* priv = ScenePriv( scene );
+    if ( NULL == priv || NULL == priv->mOrigImporter ) {
+        ReportSceneNotFoundError();
+        return NULL;
+    }
+
+    sc = priv->mOrigImporter->ApplyCustomizedPostProcessing( process, requestValidation );
+
+    if ( !sc ) {
+        aiReleaseImport( scene );
+        return NULL;
+    }
+
+    ASSIMP_END_EXCEPTION_REGION( const aiScene* );
+
+    return sc;
+}
+
+// ------------------------------------------------------------------------------------------------
+void CallbackToLogRedirector (const char* msg, char* dt)
+{
+    ai_assert( NULL != msg );
+    ai_assert( NULL != dt );
+    LogStream* s = (LogStream*)dt;
+
+    s->write(msg);
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file)
+{
+    aiLogStream sout;
+
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    LogStream* stream = LogStream::createDefaultStream(pStream,file);
+    if (!stream) {
+        sout.callback = NULL;
+        sout.user = NULL;
+    }
+    else {
+        sout.callback = &CallbackToLogRedirector;
+        sout.user = (char*)stream;
+    }
+    gPredefinedStreams.push_back(stream);
+    ASSIMP_END_EXCEPTION_REGION(aiLogStream);
+    return sout;
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
+{
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+#ifndef ASSIMP_BUILD_SINGLETHREADED
+    std::lock_guard<std::mutex> lock(gLogStreamMutex);
+#endif
+
+    LogStream* lg = new LogToCallbackRedirector(*stream);
+    gActiveLogStreams[*stream] = lg;
+
+    if (DefaultLogger::isNullLogger()) {
+        DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
+    }
+    DefaultLogger::get()->attachStream(lg);
+    ASSIMP_END_EXCEPTION_REGION(void);
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
+{
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+#ifndef ASSIMP_BUILD_SINGLETHREADED
+    std::lock_guard<std::mutex> lock(gLogStreamMutex);
+#endif
+    // find the log-stream associated with this data
+    LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
+    // it should be there... else the user is playing fools with us
+    if( it == gActiveLogStreams.end())  {
+        return AI_FAILURE;
+    }
+    DefaultLogger::get()->detatchStream( it->second );
+    delete it->second;
+
+    gActiveLogStreams.erase( it);
+
+    if (gActiveLogStreams.empty()) {
+        DefaultLogger::kill();
+    }
+    ASSIMP_END_EXCEPTION_REGION(aiReturn);
+    return AI_SUCCESS;
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiDetachAllLogStreams(void)
+{
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+#ifndef ASSIMP_BUILD_SINGLETHREADED
+    std::lock_guard<std::mutex> lock(gLogStreamMutex);
+#endif
+    Logger *logger( DefaultLogger::get() );
+    if ( NULL == logger ) {
+        return;
+    }
+
+    for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
+        logger->detatchStream( it->second );
+        delete it->second;
+    }
+    gActiveLogStreams.clear();
+    DefaultLogger::kill();
+
+    ASSIMP_END_EXCEPTION_REGION(void);
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiEnableVerboseLogging(aiBool d)
+{
+    if (!DefaultLogger::isNullLogger()) {
+        DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
+    }
+    gVerboseLogging = d;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Returns the error text of the last failed import process.
+const char* aiGetErrorString()
+{
+    return gLastErrorString.c_str();
+}
+
+// -----------------------------------------------------------------------------------------------
+// Return the description of a importer given its index
+const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex)
+{
+    return Importer().GetImporterInfo(pIndex);
+}
+
+// -----------------------------------------------------------------------------------------------
+// Return the number of importers
+size_t aiGetImportFormatCount(void)
+{
+    return Importer().GetImporterCount();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Returns the error text of the last failed import process.
+aiBool aiIsExtensionSupported(const char* szExtension)
+{
+    ai_assert(NULL != szExtension);
+    aiBool candoit=AI_FALSE;
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // FIXME: no need to create a temporary Importer instance just for that ..
+    Assimp::Importer tmp;
+    candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
+
+    ASSIMP_END_EXCEPTION_REGION(aiBool);
+    return candoit;
+}
+
+// ------------------------------------------------------------------------------------------------
+// Get a list of all file extensions supported by ASSIMP
+void aiGetExtensionList(aiString* szOut)
+{
+    ai_assert(NULL != szOut);
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // FIXME: no need to create a temporary Importer instance just for that ..
+    Assimp::Importer tmp;
+    tmp.GetExtensionList(*szOut);
+
+    ASSIMP_END_EXCEPTION_REGION(void);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Get the memory requirements for a particular import.
+void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
+    C_STRUCT aiMemoryInfo* in)
+{
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+
+    // find the importer associated with this data
+    const ScenePrivateData* priv = ScenePriv(pIn);
+    if( !priv || !priv->mOrigImporter)  {
+        ReportSceneNotFoundError();
+        return;
+    }
+
+    return priv->mOrigImporter->GetMemoryRequirements(*in);
+    ASSIMP_END_EXCEPTION_REGION(void);
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void)
+{
+    return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p)
+{
+    delete reinterpret_cast<PropertyMap*>(p);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Importer::SetPropertyInteger
+ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value)
+{
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+    SetGenericProperty<int>(pp->ints,szName,value);
+    ASSIMP_END_EXCEPTION_REGION(void);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Importer::SetPropertyFloat
+ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, ai_real value)
+{
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+    SetGenericProperty<ai_real>(pp->floats,szName,value);
+    ASSIMP_END_EXCEPTION_REGION(void);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Importer::SetPropertyString
+ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName,
+    const C_STRUCT aiString* st)
+{
+    if (!st) {
+        return;
+    }
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+    SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()));
+    ASSIMP_END_EXCEPTION_REGION(void);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Importer::SetPropertyMatrix
+ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName,
+    const C_STRUCT aiMatrix4x4* mat)
+{
+    if (!mat) {
+        return;
+    }
+    ASSIMP_BEGIN_EXCEPTION_REGION();
+    PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+    SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat);
+    ASSIMP_END_EXCEPTION_REGION(void);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Rotation matrix to quaternion
+ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
+{
+    ai_assert( NULL != quat );
+    ai_assert( NULL != mat );
+    *quat = aiQuaternion(*mat);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Matrix decomposition
+ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling,
+    aiQuaternion* rotation,
+    aiVector3D* position)
+{
+    ai_assert( NULL != rotation );
+    ai_assert( NULL != position );
+    ai_assert( NULL != scaling );
+    ai_assert( NULL != mat );
+    mat->Decompose(*scaling,*rotation,*position);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Matrix transpose
+ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat)
+{
+    ai_assert(NULL != mat);
+    mat->Transpose();
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat)
+{
+    ai_assert(NULL != mat);
+    mat->Transpose();
+}
+
+// ------------------------------------------------------------------------------------------------
+// Vector transformation
+ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec,
+    const aiMatrix3x3* mat)
+{
+    ai_assert( NULL != mat );
+    ai_assert( NULL != vec);
+    *vec *= (*mat);
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec,
+    const aiMatrix4x4* mat)
+{
+    ai_assert( NULL != mat );
+    ai_assert( NULL != vec );
+
+    *vec *= (*mat);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Matrix multiplication
+ASSIMP_API void aiMultiplyMatrix4(
+    aiMatrix4x4* dst,
+    const aiMatrix4x4* src)
+{
+    ai_assert( NULL != dst );
+    ai_assert( NULL != src );
+    *dst = (*dst) * (*src);
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiMultiplyMatrix3(
+    aiMatrix3x3* dst,
+    const aiMatrix3x3* src)
+{
+    ai_assert( NULL != dst );
+    ai_assert( NULL != src );
+    *dst = (*dst) * (*src);
+}
+
+// ------------------------------------------------------------------------------------------------
+// Matrix identity
+ASSIMP_API void aiIdentityMatrix3(
+    aiMatrix3x3* mat)
+{
+    ai_assert(NULL != mat);
+    *mat = aiMatrix3x3();
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API void aiIdentityMatrix4(
+    aiMatrix4x4* mat)
+{
+    ai_assert(NULL != mat);
+    *mat = aiMatrix4x4();
+}
+
+// ------------------------------------------------------------------------------------------------
+ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) {
+    if( NULL == extension ) {
+        return NULL;
+    }
+    const aiImporterDesc *desc( NULL );
+    std::vector< BaseImporter* > out;
+    GetImporterInstanceList( out );
+    for( size_t i = 0; i < out.size(); ++i ) {
+        if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) {
+            desc = out[ i ]->GetInfo();
+            break;
+        }
+    }
+
+    DeleteImporterInstanceList(out);
+
+    return desc;
+}
+
+// ------------------------------------------------------------------------------------------------

+ 5 - 1
thirdparty/assimp/code/BaseImporter.cpp → thirdparty/assimp/code/Common/BaseImporter.cpp

@@ -320,7 +320,11 @@ std::string BaseImporter::GetExtension( const std::string& file ) {
     return false;
 }
 
-#include "../contrib/utf8cpp/source/utf8.h"
+#ifdef ASSIMP_USE_HUNTER
+#  include <utf8/utf8.h>
+#else
+#  include "../contrib/utf8cpp/source/utf8.h"
+#endif
 
 // ------------------------------------------------------------------------------------------------
 // Convert to UTF8 data

+ 1 - 1
thirdparty/assimp/code/BaseProcess.cpp → thirdparty/assimp/code/Common/BaseProcess.cpp

@@ -89,7 +89,7 @@ void BaseProcess::ExecuteOnScene( Importer* pImp)
 
         // and kill the partially imported data
         delete pImp->Pimpl()->mScene;
-        pImp->Pimpl()->mScene = NULL;
+        pImp->Pimpl()->mScene = nullptr;
     }
 }
 

+ 0 - 0
thirdparty/assimp/code/BaseProcess.h → thirdparty/assimp/code/Common/BaseProcess.h


+ 0 - 0
thirdparty/assimp/code/Bitmap.cpp → thirdparty/assimp/code/Common/Bitmap.cpp


+ 0 - 4
thirdparty/assimp/code/CreateAnimMesh.cpp → thirdparty/assimp/code/Common/CreateAnimMesh.cpp

@@ -47,10 +47,6 @@ namespace Assimp    {
 aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
 {
     aiAnimMesh *animesh = new aiAnimMesh;
-    animesh->mVertices = NULL;
-    animesh->mNormals = NULL;
-    animesh->mTangents = NULL;
-    animesh->mBitangents = NULL;
     animesh->mNumVertices = mesh->mNumVertices;
     if (mesh->mVertices) {
         animesh->mVertices = new aiVector3D[animesh->mNumVertices];

+ 0 - 0
thirdparty/assimp/code/DefaultIOStream.cpp → thirdparty/assimp/code/Common/DefaultIOStream.cpp


+ 0 - 0
thirdparty/assimp/code/DefaultIOSystem.cpp → thirdparty/assimp/code/Common/DefaultIOSystem.cpp


+ 0 - 0
thirdparty/assimp/code/DefaultLogger.cpp → thirdparty/assimp/code/Common/DefaultLogger.cpp


+ 0 - 0
thirdparty/assimp/code/DefaultProgressHandler.h → thirdparty/assimp/code/Common/DefaultProgressHandler.h


+ 19 - 13
thirdparty/assimp/code/Exporter.cpp → thirdparty/assimp/code/Common/Exporter.cpp

@@ -61,15 +61,16 @@ Here we implement only the C++ interface (Assimp::Exporter).
 #include <assimp/mesh.h>
 #include <assimp/postprocess.h>
 #include <assimp/scene.h>
-
-#include "DefaultProgressHandler.h"
-#include "BaseProcess.h"
-#include "JoinVerticesProcess.h"
-#include "MakeVerboseFormat.h"
-#include "ConvertToLHProcess.h"
-#include "PretransformVertices.h"
 #include <assimp/Exceptional.h>
-#include "ScenePrivate.h"
+
+#include "Common/DefaultProgressHandler.h"
+#include "Common/BaseProcess.h"
+#include "Common/ScenePrivate.h"
+#include "PostProcessing/CalcTangentsProcess.h"
+#include "PostProcessing/MakeVerboseFormat.h"
+#include "PostProcessing/JoinVerticesProcess.h"
+#include "PostProcessing/ConvertToLHProcess.h"
+#include "PostProcessing/PretransformVertices.h"
 
 #include <memory>
 
@@ -101,6 +102,7 @@ void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperti
 void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
 void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
+void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
 
 // ------------------------------------------------------------------------------------------------
 // global array of all export formats which Assimp supports in its current build
@@ -161,11 +163,11 @@ Exporter::ExportFormatEntry gExporters[] =
 #endif
 
 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
-    Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0 ),
+    Exporter::ExportFormatEntry( "assbin", "Assimp Binary File", "assbin" , &ExportSceneAssbin, 0 ),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
-    Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0 ),
+    Exporter::ExportFormatEntry( "assxml", "Assimp XML Document", "assxml" , &ExportSceneAssxml, 0 ),
 #endif
 
 #ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
@@ -178,7 +180,11 @@ Exporter::ExportFormatEntry gExporters[] =
 #endif
 
 #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
-    Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 )
+    Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ),
+#endif
+
+#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
+    Exporter::ExportFormatEntry( "assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0)
 #endif
 };
 
@@ -288,7 +294,7 @@ void Exporter::SetProgressHandler(ProgressHandler* pHandler) {
 
 // ------------------------------------------------------------------------------------------------
 const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId,
-                                                unsigned int, const ExportProperties* /*pProperties*/ ) {
+                                                unsigned int pPreprocessing, const ExportProperties* pProperties) {
     if (pimpl->blob) {
         delete pimpl->blob;
         pimpl->blob = nullptr;
@@ -298,7 +304,7 @@ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const cha
     BlobIOSystem* blobio = new BlobIOSystem();
     pimpl->mIOSystem = std::shared_ptr<IOSystem>( blobio );
 
-    if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName())) {
+    if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName(), pPreprocessing, pProperties)) {
         pimpl->mIOSystem = old;
         return nullptr;
     }

+ 0 - 0
thirdparty/assimp/code/FileLogStream.h → thirdparty/assimp/code/Common/FileLogStream.h


+ 0 - 0
thirdparty/assimp/code/FileSystemFilter.h → thirdparty/assimp/code/Common/FileSystemFilter.h


+ 102 - 0
thirdparty/assimp/code/Common/IFF.h

@@ -0,0 +1,102 @@
+// Definitions for the Interchange File Format (IFF)
+// Alexander Gessler, 2006
+// Adapted to Assimp August 2008
+
+#ifndef AI_IFF_H_INCLUDED
+#define AI_IFF_H_INCLUDED
+
+#include <assimp/ByteSwapper.h>
+
+namespace Assimp    {
+namespace IFF       {
+
+/////////////////////////////////////////////////////////////////////////////////
+//! Describes an IFF chunk header
+/////////////////////////////////////////////////////////////////////////////////
+struct ChunkHeader
+{
+    //! Type of the chunk header - FourCC
+    uint32_t type;
+
+    //! Length of the chunk data, in bytes
+    uint32_t length;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////////
+//! Describes an IFF sub chunk header
+/////////////////////////////////////////////////////////////////////////////////
+struct SubChunkHeader
+{
+    //! Type of the chunk header - FourCC
+    uint32_t type;
+
+    //! Length of the chunk data, in bytes
+    uint16_t length;
+};
+
+
+#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \
+    ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d)))
+
+
+#define AI_IFF_FOURCC_FORM AI_IFF_FOURCC('F','O','R','M')
+
+
+/////////////////////////////////////////////////////////////////////////////////
+//! Load a chunk header
+//! @param outFile Pointer to the file data - points to the chunk data afterwards
+//! @return Copy of the chunk header
+/////////////////////////////////////////////////////////////////////////////////
+inline ChunkHeader LoadChunk(uint8_t*& outFile)
+{
+    ChunkHeader head;
+    ::memcpy(&head.type, outFile, 4);
+    outFile += 4;
+    ::memcpy(&head.length, outFile, 4);
+    outFile += 4;
+    AI_LSWAP4(head.length);
+    AI_LSWAP4(head.type);
+    return head;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//! Load a sub chunk header
+//! @param outFile Pointer to the file data - points to the chunk data afterwards
+//! @return Copy of the sub chunk header
+/////////////////////////////////////////////////////////////////////////////////
+inline SubChunkHeader LoadSubChunk(uint8_t*& outFile)
+{
+    SubChunkHeader head;
+    ::memcpy(&head.type, outFile, 4);
+    outFile += 4;
+    ::memcpy(&head.length, outFile, 2);
+    outFile += 2;
+    AI_LSWAP2(head.length);
+    AI_LSWAP4(head.type);
+    return head;
+}
+
+/////////////////////////////////////////////////////////////////////////////////
+//! Read the file header and return the type of the file and its size
+//! @param outFile Pointer to the file data. The buffer must at
+//!   least be 12 bytes large.
+//! @param fileType Receives the type of the file
+//! @return 0 if everything was OK, otherwise an error message
+/////////////////////////////////////////////////////////////////////////////////
+inline const char* ReadHeader(uint8_t* outFile, uint32_t& fileType)
+{
+    ChunkHeader head = LoadChunk(outFile);
+    if(AI_IFF_FOURCC_FORM != head.type)
+    {
+        return "The file is not an IFF file: FORM chunk is missing";
+    }
+    ::memcpy(&fileType, outFile, 4);
+    AI_LSWAP4(fileType);
+    return 0;
+}
+
+
+}}
+
+#endif // !! AI_IFF_H_INCLUDED

+ 11 - 8
thirdparty/assimp/code/Importer.cpp → thirdparty/assimp/code/Common/Importer.cpp

@@ -64,15 +64,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 // ------------------------------------------------------------------------------------------------
 // Internal headers
 // ------------------------------------------------------------------------------------------------
-#include "Importer.h"
-#include <assimp/BaseImporter.h>
-#include "BaseProcess.h"
+#include "Common/Importer.h"
+#include "Common/BaseProcess.h"
+#include "Common/DefaultProgressHandler.h"
+#include "PostProcessing/ProcessHelper.h"
+#include "Common/ScenePreprocessor.h"
+#include "Common/ScenePrivate.h"
 
-#include "DefaultProgressHandler.h"
+#include <assimp/BaseImporter.h>
 #include <assimp/GenericProperty.h>
-#include "ProcessHelper.h"
-#include "ScenePreprocessor.h"
-#include "ScenePrivate.h"
 #include <assimp/MemoryIOWrapper.h>
 #include <assimp/Profiler.h>
 #include <assimp/TinyFormatter.h>
@@ -86,7 +86,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/DefaultIOSystem.h>
 
 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
-#   include "ValidateDataStructure.h"
+#   include "PostProcessing/ValidateDataStructure.h"
 #endif
 
 using namespace Assimp::Profiling;
@@ -590,10 +590,12 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
 
         // Find an worker class which can handle the file
         BaseImporter* imp = NULL;
+        SetPropertyInteger("importerIndex", -1);
         for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
 
             if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
                 imp = pimpl->mImporter[a];
+                SetPropertyInteger("importerIndex", a);
                 break;
             }
         }
@@ -606,6 +608,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
                 for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
                     if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
                         imp = pimpl->mImporter[a];
+                        SetPropertyInteger("importerIndex", a);
                         break;
                     }
                 }

+ 0 - 0
thirdparty/assimp/code/Importer.h → thirdparty/assimp/code/Common/Importer.h


+ 48 - 48
thirdparty/assimp/code/ImporterRegistry.cpp → thirdparty/assimp/code/Common/ImporterRegistry.cpp

@@ -56,146 +56,146 @@ corresponding preprocessor flag to selectively disable formats.
 // (include_new_importers_here)
 // ------------------------------------------------------------------------------------------------
 #ifndef ASSIMP_BUILD_NO_X_IMPORTER
-#   include "XFileImporter.h"
+#   include "X/XFileImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER
-#   include "AMFImporter.hpp"
+#   include "AMF/AMFImporter.hpp"
 #endif
 #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
-#   include "3DSLoader.h"
+#   include "3DS/3DSLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_MD3_IMPORTER
-#   include "MD3Loader.h"
+#   include "MD3/MD3Loader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_MDL_IMPORTER
-#   include "MDLLoader.h"
+#   include "MDL/MDLLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_MD2_IMPORTER
-#   include "MD2Loader.h"
+#   include "MD2/MD2Loader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_PLY_IMPORTER
-#   include "PlyLoader.h"
+#   include "Ply/PlyLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER
-#   include "ASELoader.h"
+#   include "ASE/ASELoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER
-#   include "ObjFileImporter.h"
+#   include "Obj/ObjFileImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_HMP_IMPORTER
-#   include "HMPLoader.h"
+#   include "HMP/HMPLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_SMD_IMPORTER
-#   include "SMDLoader.h"
+#   include "SMD/SMDLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_MDC_IMPORTER
-#   include "MDCLoader.h"
+#   include "MDC/MDCLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_MD5_IMPORTER
-#   include "MD5Loader.h"
+#   include "MD5/MD5Loader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_STL_IMPORTER
-#   include "STLLoader.h"
+#   include "STL/STLLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
-#   include "LWOLoader.h"
+#   include "LWO/LWOLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_DXF_IMPORTER
-#   include "DXFLoader.h"
+#   include "DXF/DXFLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_NFF_IMPORTER
-#   include "NFFLoader.h"
+#   include "NFF/NFFLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_RAW_IMPORTER
-#   include "RawLoader.h"
+#   include "Raw/RawLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_SIB_IMPORTER
-#   include "SIBImporter.h"
+#   include "SIB/SIBImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_OFF_IMPORTER
-#   include "OFFLoader.h"
+#   include "OFF/OFFLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_AC_IMPORTER
-#   include "ACLoader.h"
+#   include "AC/ACLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_BVH_IMPORTER
-#   include "BVHLoader.h"
+#   include "BVH/BVHLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER
-#   include "IRRMeshLoader.h"
+#   include "Irr/IRRMeshLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_IRR_IMPORTER
-#   include "IRRLoader.h"
+#   include "Irr/IRRLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_Q3D_IMPORTER
-#   include "Q3DLoader.h"
+#   include "Q3D/Q3DLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_B3D_IMPORTER
-#   include "B3DImporter.h"
+#   include "B3D/B3DImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
-#   include "ColladaLoader.h"
+#   include "Collada/ColladaLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_TERRAGEN_IMPORTER
-#   include "TerragenLoader.h"
+#   include "Terragen/TerragenLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_CSM_IMPORTER
-#   include "CSMLoader.h"
+#   include "CSM/CSMLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_3D_IMPORTER
-#   include "UnrealLoader.h"
+#   include "Unreal/UnrealLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_LWS_IMPORTER
-#   include "LWSLoader.h"
+#   include "LWS/LWSLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
-#   include "OgreImporter.h"
+#   include "Ogre/OgreImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER
-#   include "OpenGEXImporter.h"
+#   include "OpenGEX/OpenGEXImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER
-#   include "MS3DLoader.h"
+#   include "MS3D/MS3DLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_COB_IMPORTER
-#   include "COBLoader.h"
+#   include "COB/COBLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
-#   include "BlenderLoader.h"
+#   include "Blender/BlenderLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
-#   include "Q3BSPFileImporter.h"
+#   include "Q3BSP/Q3BSPFileImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_NDO_IMPORTER
-#   include "NDOLoader.h"
+#   include "NDO/NDOLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER
 #   include "Importer/IFC/IFCLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_XGL_IMPORTER
-#   include "XGLLoader.h"
+#   include "XGL/XGLLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
-#   include "FBXImporter.h"
+#   include "FBX/FBXImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER
-#   include "AssbinLoader.h"
+#   include "Assbin/AssbinLoader.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER
-#   include "glTFImporter.h"
-#   include "glTF2Importer.h"
+#   include "glTF/glTFImporter.h"
+#   include "glTF2/glTF2Importer.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_C4D_IMPORTER
-#   include "C4DImporter.h"
+#   include "C4D/C4DImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_3MF_IMPORTER
-#   include "D3MFImporter.h"
+#   include "3MF/D3MFImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
-#   include "X3DImporter.hpp"
+#   include "X3D/X3DImporter.hpp"
 #endif
 #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
-#   include "MMDImporter.h"
+#   include "MMD/MMDImporter.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
 #   include "Importer/StepFile/StepFileImporter.h"
@@ -364,7 +364,7 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
 void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){
 	for(size_t i= 0; i<deleteList.size();++i){
 		delete deleteList[i];
-		deleteList[i]=NULL;
+		deleteList[i]=nullptr;
 	}//for
 }
 

+ 0 - 0
thirdparty/assimp/code/PolyTools.h → thirdparty/assimp/code/Common/PolyTools.h


+ 35 - 28
thirdparty/assimp/code/PostStepRegistry.cpp → thirdparty/assimp/code/Common/PostStepRegistry.cpp

@@ -48,89 +48,93 @@ directly (unless you are adding new steps), instead use the
 corresponding preprocessor flag to selectively disable steps.
 */
 
-#include "ProcessHelper.h"
+#include "PostProcessing/ProcessHelper.h"
 
 #ifndef ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS
-#   include "CalcTangentsProcess.h"
+#   include "PostProcessing/CalcTangentsProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS
-#   include "JoinVerticesProcess.h"
+#   include "PostProcessing/JoinVerticesProcess.h"
 #endif
 #if !(defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS && defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS && defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
-#   include "ConvertToLHProcess.h"
+#   include "PostProcessing/ConvertToLHProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS
-#   include "TriangulateProcess.h"
+#   include "PostProcessing/TriangulateProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_DROPFACENORMALS_PROCESS
-#   include "DropFaceNormalsProcess.h"
+#   include "PostProcessing/DropFaceNormalsProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS
-#   include "GenFaceNormalsProcess.h"
+#   include "PostProcessing/GenFaceNormalsProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS
-#   include "GenVertexNormalsProcess.h"
+#   include "PostProcessing/GenVertexNormalsProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_REMOVEVC_PROCESS
-#   include "RemoveVCProcess.h"
+#   include "PostProcessing/RemoveVCProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS
-#   include "SplitLargeMeshes.h"
+#   include "PostProcessing/SplitLargeMeshes.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS
-#   include "PretransformVertices.h"
+#   include "PostProcessing/PretransformVertices.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS
-#   include "LimitBoneWeightsProcess.h"
+#   include "PostProcessing/LimitBoneWeightsProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
-#   include "ValidateDataStructure.h"
+#   include "PostProcessing/ValidateDataStructure.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS
-#   include "ImproveCacheLocality.h"
+#   include "PostProcessing/ImproveCacheLocality.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS
-#   include "FixNormalsStep.h"
+#   include "PostProcessing/FixNormalsStep.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS
-#   include "RemoveRedundantMaterials.h"
+#   include "PostProcessing/RemoveRedundantMaterials.h"
 #endif
 #if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS)
-#   include "EmbedTexturesProcess.h"
+#   include "PostProcessing/EmbedTexturesProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS
-#   include "FindInvalidDataProcess.h"
+#   include "PostProcessing/FindInvalidDataProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS
-#   include "FindDegenerates.h"
+#   include "PostProcessing/FindDegenerates.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS
-#   include "SortByPTypeProcess.h"
+#   include "PostProcessing/SortByPTypeProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS
-#   include "ComputeUVMappingProcess.h"
+#   include "PostProcessing/ComputeUVMappingProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS
-#   include "TextureTransform.h"
+#   include "PostProcessing/TextureTransform.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS
-#   include "FindInstancesProcess.h"
+#   include "PostProcessing/FindInstancesProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS
-#   include "OptimizeMeshes.h"
+#   include "PostProcessing/OptimizeMeshes.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS
-#   include "OptimizeGraph.h"
+#   include "PostProcessing/OptimizeGraph.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS
-#   include "SplitByBoneCountProcess.h"
+#   include "Common/SplitByBoneCountProcess.h"
 #endif
 #ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS
-#   include "DeboneProcess.h"
+#   include "PostProcessing/DeboneProcess.h"
 #endif
 #if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
-#   include "ScaleProcess.h"
+#   include "PostProcessing/ScaleProcess.h"
 #endif
+#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
+#   include "PostProcessing/GenBoundingBoxesProcess.h"
+#endif
+
 
 namespace Assimp {
 
@@ -246,6 +250,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 #if (!defined ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS)
     out.push_back( new ImproveCacheLocalityProcess());
 #endif
+#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
+    out.push_back(new GenBoundingBoxesProcess);
+#endif
 }
 
 }

+ 0 - 0
thirdparty/assimp/code/RemoveComments.cpp → thirdparty/assimp/code/Common/RemoveComments.cpp


+ 0 - 0
thirdparty/assimp/code/SGSpatialSort.cpp → thirdparty/assimp/code/Common/SGSpatialSort.cpp


+ 0 - 0
thirdparty/assimp/code/SceneCombiner.cpp → thirdparty/assimp/code/Common/SceneCombiner.cpp


+ 0 - 0
thirdparty/assimp/code/ScenePreprocessor.cpp → thirdparty/assimp/code/Common/ScenePreprocessor.cpp


+ 0 - 0
thirdparty/assimp/code/ScenePreprocessor.h → thirdparty/assimp/code/Common/ScenePreprocessor.h


+ 0 - 0
thirdparty/assimp/code/ScenePrivate.h → thirdparty/assimp/code/Common/ScenePrivate.h


+ 0 - 0
thirdparty/assimp/code/SkeletonMeshBuilder.cpp → thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp


+ 0 - 0
thirdparty/assimp/code/SpatialSort.cpp → thirdparty/assimp/code/Common/SpatialSort.cpp


+ 0 - 0
thirdparty/assimp/code/SplitByBoneCountProcess.cpp → thirdparty/assimp/code/Common/SplitByBoneCountProcess.cpp


+ 0 - 0
thirdparty/assimp/code/SplitByBoneCountProcess.h → thirdparty/assimp/code/Common/SplitByBoneCountProcess.h


+ 0 - 0
thirdparty/assimp/code/StandardShapes.cpp → thirdparty/assimp/code/Common/StandardShapes.cpp


+ 0 - 0
thirdparty/assimp/code/StdOStreamLogStream.h → thirdparty/assimp/code/Common/StdOStreamLogStream.h


+ 4 - 3
thirdparty/assimp/code/Subdivision.cpp → thirdparty/assimp/code/Common/Subdivision.cpp

@@ -43,9 +43,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Subdivision.h>
 #include <assimp/SceneCombiner.h>
 #include <assimp/SpatialSort.h>
-#include "ProcessHelper.h"
 #include <assimp/Vertex.h>
 #include <assimp/ai_assert.h>
+
+#include "PostProcessing/ProcessHelper.h"
+
 #include <stdio.h>
 
 using namespace Assimp;
@@ -56,8 +58,7 @@ void mydummy() {}
  *  implementation is basing on recursive refinement. Directly evaluating the result is also
  *  possible and much quicker, but it depends on lengthy matrix lookup tables. */
 // ------------------------------------------------------------------------------------------------
-class CatmullClarkSubdivider : public Subdivider
-{
+class CatmullClarkSubdivider : public Subdivider {
 public:
     void Subdivide (aiMesh* mesh, aiMesh*& out, unsigned int num, bool discard_input);
     void Subdivide (aiMesh** smesh, size_t nmesh,

+ 0 - 0
thirdparty/assimp/code/TargetAnimation.cpp → thirdparty/assimp/code/Common/TargetAnimation.cpp


+ 0 - 0
thirdparty/assimp/code/TargetAnimation.h → thirdparty/assimp/code/Common/TargetAnimation.h


+ 1 - 1
thirdparty/assimp/code/Version.cpp → thirdparty/assimp/code/Common/Version.cpp

@@ -134,7 +134,7 @@ ASSIMP_API aiScene::aiScene()
 , mCameras(nullptr)
 , mMetaData(nullptr)
 , mPrivate(new Assimp::ScenePrivateData()) {
-    // empty
+	// empty
 }
 
 // ------------------------------------------------------------------------------------------------

+ 0 - 0
thirdparty/assimp/code/VertexTriangleAdjacency.cpp → thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp


+ 0 - 0
thirdparty/assimp/code/VertexTriangleAdjacency.h → thirdparty/assimp/code/Common/VertexTriangleAdjacency.h


+ 0 - 0
thirdparty/assimp/code/Win32DebugLogStream.h → thirdparty/assimp/code/Common/Win32DebugLogStream.h


+ 196 - 0
thirdparty/assimp/code/Common/assbin_chunks.h

@@ -0,0 +1,196 @@
+#ifndef INCLUDED_ASSBIN_CHUNKS_H
+#define INCLUDED_ASSBIN_CHUNKS_H
+
+#define ASSBIN_VERSION_MAJOR 1
+#define ASSBIN_VERSION_MINOR 0
+
+/**
+@page assfile .ASS File formats
+
+@section over Overview
+Assimp provides its own interchange format, which is intended to applications which need
+to serialize 3D-models and to reload them quickly. Assimp's file formats are designed to
+be read by Assimp itself. They encode additional information needed by Assimp to optimize
+its postprocessing pipeline. If you once apply specific steps to a scene, then save it
+and reread it from an ASS format using the same post processing settings, they won't
+be executed again.
+
+The format comes in two flavours: XML and binary - both of them hold a complete dump of
+the 'aiScene' data structure returned by the APIs. The focus for the binary format
+(<tt>.assbin</tt>) is fast loading. Optional deflate compression helps reduce file size. The XML
+flavour, <tt>.assxml</tt> or simply .xml, is just a plain-to-xml conversion of aiScene.
+
+ASSBIN is Assimp's binary interchange format. assimp_cmd (<tt>&lt;root&gt;/tools/assimp_cmd</tt>) is able to
+write it and the core library provides a loader for it.
+
+@section assxml XML File format
+
+The format is pretty much self-explanatory due to its similarity to the in-memory aiScene structure.
+With few exceptions, C structures are wrapped in XML elements.
+
+The DTD for ASSXML can be found in <tt>&lt;root&gt;/doc/AssXML_Scheme.xml</tt>. Or have   look
+at the output files generated by assimp_cmd.
+
+@section assbin Binary file format
+
+The ASSBIN file format is composed of chunks to represent the hierarchical aiScene data structure.
+This makes the format extensible and allows backward-compatibility with future data structure
+versions. The <tt>&lt;root&gt;/code/assbin_chunks.h</tt> header contains some magic constants
+for use by stand-alone ASSBIN loaders. Also, Assimp's own file writer can be found
+in <tt>&lt;root&gt;/tools/assimp_cmd/WriteDumb.cpp</tt> (yes, the 'b' is no typo ...).
+
+@verbatim
+
+-------------------------------------------------------------------------------
+1. File structure:
+-------------------------------------------------------------------------------
+
+----------------------
+| Header (512 bytes) |
+----------------------
+| Variable chunks    |
+----------------------
+
+-------------------------------------------------------------------------------
+2. Definitions:
+-------------------------------------------------------------------------------
+
+integer is four bytes wide, stored in little-endian byte order.
+short   is two bytes wide, stored in little-endian byte order.
+byte    is a single byte.
+string  is an integer n followed by n UTF-8 characters, not terminated by zero
+float   is an IEEE 754 single-precision floating-point value
+double  is an IEEE 754 double-precision floating-point value
+t[n]    is an array of n elements of type t
+
+-------------------------------------------------------------------------------
+2. Header:
+-------------------------------------------------------------------------------
+
+byte[44]    Magic identification string for ASSBIN files.
+                'ASSIMP.binary'
+
+integer     Major version of the Assimp library which wrote the file
+integer     Minor version of the Assimp library which wrote the file
+                match these against ASSBIN_VERSION_MAJOR and ASSBIN_VERSION_MINOR
+
+integer     SVN revision of the Assimp library (intended for our internal
+            debugging - if you write Ass files from your own APPs, set this value to 0.
+integer     Assimp compile flags
+
+short       0 for normal files, 1 for shortened dumps for regression tests
+                these should have the file extension assbin.regress
+
+short       1 if the data after the header is compressed with the DEFLATE algorithm,
+            0 for uncompressed files.
+                   For compressed files, the first integer after the header is
+                   always the uncompressed data size
+
+byte[256]   Zero-terminated source file name, UTF-8
+byte[128]   Zero-terminated command line parameters passed to assimp_cmd, UTF-8
+
+byte[64]    Reserved for future use
+---> Total length: 512 bytes
+
+-------------------------------------------------------------------------------
+3. Chunks:
+-------------------------------------------------------------------------------
+
+integer     Magic chunk ID (ASSBIN_CHUNK_XXX)
+integer     Chunk data length, in bytes
+                (unknown chunks are possible, a good reader skips over them)
+                (chunk-data-length does not include the first two integers)
+
+byte[n]     chunk-data-length bytes of data, depending on the chunk type
+
+Chunks can contain nested chunks. Nested chunks are ALWAYS at the end of the chunk,
+their size is included in chunk-data-length.
+
+The chunk layout for all ASSIMP data structures is derived from their C declarations.
+The general 'rule' to get from Assimp headers to the serialized layout is:
+
+   1. POD members (i.e. aiMesh::mPrimitiveTypes, aiMesh::mNumVertices),
+        in order of declaration.
+
+   2. Array-members (aiMesh::mFaces, aiMesh::mVertices, aiBone::mWeights),
+        in order of declaration.
+
+   2. Object array members (i.e aiMesh::mBones, aiScene::mMeshes) are stored in
+      subchunks directly following the data written in 1.) and 2.)
+
+
+    Of course, there are some exceptions to this general order:
+
+[[aiScene]]
+
+   - The root node holding the scene structure is naturally stored in
+     a ASSBIN_CHUNK_AINODE subchunk following 1.) and 2.) (which is
+     empty for aiScene).
+
+[[aiMesh]]
+
+   - mTextureCoords and mNumUVComponents are serialized as follows:
+
+   [number of used uv channels times]
+       integer mNumUVComponents[n]
+       float mTextureCoords[n][3]
+
+       -> more than AI_MAX_TEXCOORD_CHANNELS can be stored. This allows Assimp
+       builds with different settings for AI_MAX_TEXCOORD_CHANNELS to exchange
+       data.
+       -> the on-disk format always uses 3 floats to write UV coordinates.
+       If mNumUVComponents[0] is 1, the corresponding mTextureCoords array
+       consists of 3 floats.
+
+   - The array member block of aiMesh is prefixed with an integer that specifies
+     the kinds of vertex components actually present in the mesh. This is a
+     bitwise combination of the ASSBIN_MESH_HAS_xxx constants.
+
+[[aiFace]]
+
+   - mNumIndices is stored as short
+   - mIndices are written as short, if aiMesh::mNumVertices<65536
+
+[[aiNode]]
+
+   - mParent is omitted
+
+[[aiLight]]
+
+   - mAttenuationXXX not written if aiLight::mType == aiLightSource_DIRECTIONAL
+   - mAngleXXX not written if aiLight::mType != aiLightSource_SPOT
+
+[[aiMaterial]]
+
+   - mNumAllocated is omitted, for obvious reasons :-)
+
+
+ @endverbatim*/
+
+
+#define ASSBIN_HEADER_LENGTH 512
+
+// these are the magic chunk identifiers for the binary ASS file format
+#define ASSBIN_CHUNK_AICAMERA                   0x1234
+#define ASSBIN_CHUNK_AILIGHT                    0x1235
+#define ASSBIN_CHUNK_AITEXTURE                  0x1236
+#define ASSBIN_CHUNK_AIMESH                     0x1237
+#define ASSBIN_CHUNK_AINODEANIM                 0x1238
+#define ASSBIN_CHUNK_AISCENE                    0x1239
+#define ASSBIN_CHUNK_AIBONE                     0x123a
+#define ASSBIN_CHUNK_AIANIMATION                0x123b
+#define ASSBIN_CHUNK_AINODE                     0x123c
+#define ASSBIN_CHUNK_AIMATERIAL                 0x123d
+#define ASSBIN_CHUNK_AIMATERIALPROPERTY         0x123e
+
+#define ASSBIN_MESH_HAS_POSITIONS                   0x1
+#define ASSBIN_MESH_HAS_NORMALS                     0x2
+#define ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS     0x4
+#define ASSBIN_MESH_HAS_TEXCOORD_BASE               0x100
+#define ASSBIN_MESH_HAS_COLOR_BASE                  0x10000
+
+#define ASSBIN_MESH_HAS_TEXCOORD(n) (ASSBIN_MESH_HAS_TEXCOORD_BASE << n)
+#define ASSBIN_MESH_HAS_COLOR(n)    (ASSBIN_MESH_HAS_COLOR_BASE << n)
+
+
+#endif // INCLUDED_ASSBIN_CHUNKS_H

+ 0 - 0
thirdparty/assimp/code/scene.cpp → thirdparty/assimp/code/Common/scene.cpp


+ 0 - 0
thirdparty/assimp/code/simd.cpp → thirdparty/assimp/code/Common/simd.cpp


+ 0 - 0
thirdparty/assimp/code/simd.h → thirdparty/assimp/code/Common/simd.h


+ 0 - 0
thirdparty/assimp/code/FBXAnimation.cpp → thirdparty/assimp/code/FBX/FBXAnimation.cpp


+ 6 - 6
thirdparty/assimp/code/FBXBinaryTokenizer.cpp → thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp

@@ -98,7 +98,7 @@ namespace FBX {
 //	return (flags & to_check) != 0;
 //}
 // ------------------------------------------------------------------------------------------------
-Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int offset)
+Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset)
     :
     #ifdef DEBUG
     contents(sbegin, static_cast<size_t>(send-sbegin)),
@@ -122,18 +122,18 @@ namespace {
 
 // ------------------------------------------------------------------------------------------------
 // signal tokenization error, this is always unrecoverable. Throws DeadlyImportError.
-AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset) AI_WONT_RETURN_SUFFIX;
-AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset)
+AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX;
+AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset)
 {
     throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset));
 }
 
 
 // ------------------------------------------------------------------------------------------------
-uint32_t Offset(const char* begin, const char* cursor) {
+size_t Offset(const char* begin, const char* cursor) {
     ai_assert(begin <= cursor);
 
-    return static_cast<unsigned int>(cursor - begin);
+    return cursor - begin;
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -424,7 +424,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor,
 
 // ------------------------------------------------------------------------------------------------
 // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent
-void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int length)
+void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
 {
     ai_assert(input);
 

+ 2 - 2
thirdparty/assimp/code/FBXCommon.h → thirdparty/assimp/code/FBX/FBXCommon.h

@@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
 
-
+namespace Assimp {
 namespace FBX
 {
     const std::string NULL_RECORD = { // 13 null bytes
@@ -80,7 +80,7 @@ namespace FBX
         TransformInheritance_MAX // end-of-enum sentinel
     };
 }
-
+}
 #endif // ASSIMP_BUILD_NO_FBX_EXPORTER
 
 #endif // AI_FBXCOMMON_H_INC

+ 0 - 0
thirdparty/assimp/code/FBXCompileConfig.h → thirdparty/assimp/code/FBX/FBXCompileConfig.h


+ 184 - 84
thirdparty/assimp/code/FBXConverter.cpp → thirdparty/assimp/code/FBX/FBXConverter.cpp

@@ -67,6 +67,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <sstream>
 #include <iomanip>
 
+
 namespace Assimp {
     namespace FBX {
 
@@ -76,20 +77,21 @@ namespace Assimp {
 
 #define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000L
 
-        FBXConverter::FBXConverter(aiScene* out, const Document& doc)
-            : defaultMaterialIndex()
-            , lights()
-            , cameras()
-            , textures()
-            , materials_converted()
-            , textures_converted()
-            , meshes_converted()
-            , node_anim_chain_bits()
-            , mNodeNameInstances()
-            , mNodeNames()
-            , anim_fps()
-            , out(out)
-            , doc(doc) {
+        FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit )
+        : defaultMaterialIndex()
+        , lights()
+        , cameras()
+        , textures()
+        , materials_converted()
+        , textures_converted()
+        , meshes_converted()
+        , node_anim_chain_bits()
+        , mNodeNames()
+        , anim_fps()
+        , out(out)
+        , doc(doc)
+        , mRemoveEmptyBones( removeEmptyBones )
+        , mCurrentUnit(FbxUnit::cm) {
             // animations need to be converted first since this will
             // populate the node_anim_chain_bits map, which is needed
             // to determine which nodes need to be generated.
@@ -117,6 +119,7 @@ namespace Assimp {
 
             ConvertGlobalSettings();
             TransferDataToScene();
+            ConvertToUnitScale(unit);
 
             // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE
             // to make sure the scene passes assimp's validation. FBX files
@@ -138,12 +141,46 @@ namespace Assimp {
 
         void FBXConverter::ConvertRootNode() {
             out->mRootNode = new aiNode();
-            out->mRootNode->mName.Set("RootNode");
+            std::string unique_name;
+            GetUniqueName("RootNode", unique_name);
+            out->mRootNode->mName.Set(unique_name);
 
             // root has ID 0
             ConvertNodes(0L, *out->mRootNode);
         }
 
+        static std::string getAncestorBaseName(const aiNode* node)
+        {
+            const char* nodeName = nullptr;
+            size_t length = 0;
+            while (node && (!nodeName || length == 0))
+            {
+                nodeName = node->mName.C_Str();
+                length = node->mName.length;
+                node = node->mParent;
+            }
+
+            if (!nodeName || length == 0)
+            {
+                return {};
+            }
+            // could be std::string_view if c++17 available
+            return std::string(nodeName, length);
+        }
+
+        // Make unique name
+        std::string FBXConverter::MakeUniqueNodeName(const Model* const model, const aiNode& parent)
+        {
+            std::string original_name = FixNodeName(model->Name());
+            if (original_name.empty())
+            {
+                original_name = getAncestorBaseName(&parent);
+            }
+            std::string unique_name;
+            GetUniqueName(original_name, unique_name);
+            return unique_name;
+        }
+
         void FBXConverter::ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform) {
             const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
 
@@ -175,35 +212,18 @@ namespace Assimp {
 
                         aiMatrix4x4 new_abs_transform = parent_transform;
 
+                        std::string unique_name = MakeUniqueNodeName(model, parent);
+
                         // even though there is only a single input node, the design of
                         // assimp (or rather: the complicated transformation chain that
                         // is employed by fbx) means that we may need multiple aiNode's
                         // to represent a fbx node's transformation.
-                        GenerateTransformationNodeChain(*model, nodes_chain, post_nodes_chain);
+                        const bool need_additional_node = GenerateTransformationNodeChain(*model, unique_name, nodes_chain, post_nodes_chain);
 
                         ai_assert(nodes_chain.size());
 
-                        std::string original_name = FixNodeName(model->Name());
-
-                        // check if any of the nodes in the chain has the name the fbx node
-                        // is supposed to have. If there is none, add another node to
-                        // preserve the name - people might have scripts etc. that rely
-                        // on specific node names.
-                        aiNode* name_carrier = NULL;
-                        for (aiNode* prenode : nodes_chain) {
-                            if (!strcmp(prenode->mName.C_Str(), original_name.c_str())) {
-                                name_carrier = prenode;
-                                break;
-                            }
-                        }
-
-                        if (!name_carrier) {
-                            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();
+                        if (need_additional_node) {
+                            nodes_chain.push_back(new aiNode(unique_name));
                         }
 
                         //setup metadata on newest node
@@ -265,11 +285,11 @@ namespace Assimp {
                         ConvertNodes(model->ID(), *last_parent, new_abs_transform);
 
                         if (doc.Settings().readLights) {
-                            ConvertLights(*model, original_name);
+                            ConvertLights(*model, unique_name);
                         }
 
                         if (doc.Settings().readCameras) {
-                            ConvertCameras(*model, original_name);
+                            ConvertCameras(*model, unique_name);
                         }
 
                         nodes.push_back(nodes_chain.front());
@@ -387,6 +407,7 @@ namespace Assimp {
                 break;
             default:
                 ai_assert(false);
+                break;
             }
         }
 
@@ -399,11 +420,6 @@ namespace Assimp {
 
             out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
 
-            //cameras are defined along positive x direction
-            /*out_camera->mPosition = cam.Position();
-            out_camera->mLookAt = (cam.InterestPosition() - out_camera->mPosition).Normalize();
-            out_camera->mUp = cam.UpVector();*/
-
             out_camera->mPosition = aiVector3D(0.0f);
             out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f);
             out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f);
@@ -421,21 +437,16 @@ namespace Assimp {
         void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName)
         {
             uniqueName = name;
-            int i = 0;
-            auto it = mNodeNameInstances.find(name); // duplicate node name instance count
-            if (it != mNodeNameInstances.end())
+            auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count
+            unsigned int& i = it_pair.first->second;
+            while (!it_pair.second)
             {
-                i = it->second;
-                while (mNodeNames.find(uniqueName) != mNodeNames.end())
-                {
-                    i++;
-                    std::stringstream ext;
-                    ext << name << std::setfill('0') << std::setw(3) << i;
-                    uniqueName = ext.str();
-                }
+                i++;
+                std::ostringstream ext;
+                ext << name << std::setfill('0') << std::setw(3) << i;
+                uniqueName = ext.str();
+                it_pair = mNodeNames.insert({ uniqueName, 0 });
             }
-            mNodeNameInstances[name] = i;
-            mNodeNames.insert(uniqueName);
         }
 
         const char* FBXConverter::NameTransformationComp(TransformationComp comp) {
@@ -651,8 +662,7 @@ namespace Assimp {
                     if ((v - all_ones).SquareLength() > zero_epsilon) {
                         return true;
                     }
-                }
-                else if (ok) {
+                } else if (ok) {
                     if (v.SquareLength() > zero_epsilon) {
                         return true;
                     }
@@ -667,7 +677,7 @@ namespace Assimp {
             return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
         }
 
-        void FBXConverter::GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes,
+        bool FBXConverter::GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes,
             std::vector<aiNode*>& post_output_nodes) {
             const PropertyTable& props = model.Props();
             const Model::RotOrder rot = model.RotationOrder();
@@ -782,8 +792,6 @@ namespace Assimp {
             // not be guaranteed.
             ai_assert(NeedsComplexTransformationChain(model) == is_complex);
 
-            std::string name = FixNodeName(model.Name());
-
             // now, if we have more than just Translation, Scaling and Rotation,
             // we need to generate a full node chain to accommodate for assimp's
             // lack to express pivots and offsets.
@@ -825,20 +833,20 @@ namespace Assimp {
                 }
 
                 ai_assert(output_nodes.size());
-                return;
+                return true;
             }
 
             // else, we can just multiply the matrices together
             aiNode* nd = new aiNode();
             output_nodes.push_back(nd);
-            std::string uniqueName;
-            GetUniqueName(name, uniqueName);
 
-            nd->mName.Set(uniqueName);
+            // name passed to the method is already unique
+            nd->mName.Set(name);
 
             for (const auto &transform : chain) {
                 nd->mTransformation = nd->mTransformation * transform;
             }
+            return false;
         }
 
         void FBXConverter::SetupNodeMetadata(const Model& model, aiNode& nd)
@@ -977,7 +985,9 @@ namespace Assimp {
             unsigned int epcount = 0;
             for (unsigned i = 0; i < indices.size(); i++)
             {
-                if (indices[i] < 0) epcount++;
+                if (indices[i] < 0) {
+                    epcount++;
+                }
             }
             unsigned int pcount = static_cast<unsigned int>( indices.size() );
             unsigned int scount = out_mesh->mNumFaces = pcount - epcount;
@@ -1237,10 +1247,10 @@ namespace Assimp {
             ai_assert(count_faces);
             ai_assert(count_vertices);
 
-            // mapping from output indices to DOM indexing, needed to resolve weights
+            // mapping from output indices to DOM indexing, needed to resolve weights or blendshapes
             std::vector<unsigned int> reverseMapping;
-
-            if (process_weights) {
+            std::map<unsigned int, unsigned int> translateIndexMap;
+            if (process_weights || mesh.GetBlendShapes().size() > 0) {
                 reverseMapping.resize(count_vertices);
             }
 
@@ -1347,6 +1357,7 @@ namespace Assimp {
 
                     if (reverseMapping.size()) {
                         reverseMapping[cursor] = in_cursor;
+                        translateIndexMap[in_cursor] = cursor;
                     }
 
                     out_mesh->mVertices[cursor] = vertices[in_cursor];
@@ -1378,6 +1389,50 @@ namespace Assimp {
                 ConvertWeights(out_mesh, model, mesh, node_global_transform, index, &reverseMapping);
             }
 
+            std::vector<aiAnimMesh*> animMeshes;
+            for (const BlendShape* blendShape : mesh.GetBlendShapes()) {
+                for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) {
+                    const std::vector<const ShapeGeometry*>& shapeGeometries = blendShapeChannel->GetShapeGeometries();
+                    for (size_t i = 0; i < shapeGeometries.size(); i++) {
+                        aiAnimMesh* animMesh = aiCreateAnimMesh(out_mesh);
+                        const ShapeGeometry* shapeGeometry = shapeGeometries.at(i);
+                        const std::vector<aiVector3D>& vertices = shapeGeometry->GetVertices();
+                        const std::vector<aiVector3D>& normals = shapeGeometry->GetNormals();
+                        const std::vector<unsigned int>& indices = shapeGeometry->GetIndices();
+                        animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name()));
+                        for (size_t j = 0; j < indices.size(); j++) {
+                            unsigned int index = indices.at(j);
+                            aiVector3D vertex = vertices.at(j);
+                            aiVector3D normal = normals.at(j);
+                            unsigned int count = 0;
+                            const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count);
+                            for (unsigned int k = 0; k < count; k++) {
+                                unsigned int outIndex = outIndices[k];
+                                if (translateIndexMap.find(outIndex) == translateIndexMap.end())
+                                    continue;
+                                unsigned int index = translateIndexMap[outIndex];
+                                animMesh->mVertices[index] += vertex;
+                                if (animMesh->mNormals != nullptr) {
+                                    animMesh->mNormals[index] += normal;
+                                    animMesh->mNormals[index].NormalizeSafe();
+                                }
+                            }
+                        }
+                        animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f;
+                        animMeshes.push_back(animMesh);
+                    }
+                }
+            }
+
+            const size_t numAnimMeshes = animMeshes.size();
+            if (numAnimMeshes > 0) {
+                out_mesh->mNumAnimMeshes = static_cast<unsigned int>(numAnimMeshes);
+                out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes];
+                for (size_t i = 0; i < numAnimMeshes; i++) {
+                    out_mesh->mAnimMeshes[i] = animMeshes.at(i);
+                }
+            }
+
             return static_cast<unsigned int>(meshes.size() - 1);
         }
 
@@ -1407,7 +1462,7 @@ namespace Assimp {
 
                     const WeightIndexArray& indices = cluster->GetIndices();
 
-                    if (indices.empty()) {
+                    if (indices.empty() && mRemoveEmptyBones ) {
                         continue;
                     }
 
@@ -1439,13 +1494,11 @@ namespace Assimp {
 
                                 if (index_out_indices.back() == no_index_sentinel) {
                                     index_out_indices.back() = out_indices.size();
-
                                 }
 
                                 if (no_mat_check) {
                                     out_indices.push_back(out_idx[i]);
-                                }
-                                else {
+                                } else {
                                     // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn)
                                     const std::vector<unsigned int>::iterator it = std::lower_bound(
                                         outputVertStartIndices->begin(),
@@ -1461,11 +1514,11 @@ namespace Assimp {
                             }
                         }
                     }
-
+                    
                     // if we found at least one, generate the output bones
                     // XXX this could be heavily simplified by collecting the bone
                     // data in a single step.
-                    if (ok) {
+                    if (ok && mRemoveEmptyBones) {
                         ConvertCluster(bones, model, *cluster, out_indices, index_out_indices,
                             count_out_indices, node_global_transform);
                     }
@@ -1596,6 +1649,13 @@ namespace Assimp {
                 out_mat->AddProperty(&str, AI_MATKEY_NAME);
             }
 
+            // Set the shading mode as best we can: The FBX specification only mentions Lambert and Phong, and only Phong is mentioned in Assimp's aiShadingMode enum.
+            if (material.GetShadingModel() == "phong")
+            {
+                aiShadingMode shadingMode = aiShadingMode_Phong;
+                out_mat->AddProperty<aiShadingMode>(&shadingMode, 1, AI_MATKEY_SHADING_MODEL);               
+            }
+
             // shading stuff and colors
             SetShadingPropertiesCommon(out_mat, props);
             SetShadingPropertiesRaw( out_mat, props, material.Textures(), mesh );
@@ -1621,7 +1681,7 @@ namespace Assimp {
             out_tex->pcData = reinterpret_cast<aiTexel*>(const_cast<Video&>(video).RelinquishContent());
 
             // try to extract a hint from the file extension
-            const std::string& filename = video.FileName().empty() ? video.RelativeFilename() : video.FileName();
+            const std::string& filename = video.RelativeFilename().empty() ? video.FileName() : video.RelativeFilename();
             std::string ext = BaseImporter::GetExtension(filename);
 
             if (ext == "jpeg") {
@@ -1632,7 +1692,7 @@ namespace Assimp {
                 memcpy(out_tex->achFormatHint, ext.c_str(), ext.size());
             }
 
-            out_tex->mFilename.Set(video.FileName().c_str());
+            out_tex->mFilename.Set(filename.c_str());
 
             return static_cast<unsigned int>(textures.size() - 1);
         }
@@ -1678,9 +1738,8 @@ namespace Assimp {
         }
 
         void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
-            const std::string& propName,
-            aiTextureType target, const MeshGeometry* const mesh)
-        {
+                const std::string& propName,
+                aiTextureType target, const MeshGeometry* const mesh) {
             TextureMap::const_iterator it = textures.find(propName);
             if (it == textures.end()) {
                 return;
@@ -3407,8 +3466,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
 
             na->mNumScalingKeys = static_cast<unsigned int>(keys.size());
             na->mScalingKeys = new aiVectorKey[keys.size()];
-            if (keys.size() > 0)
+            if (keys.size() > 0) {
                 InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime);
+            }
         }
 
         void FBXConverter::ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes,
@@ -3472,6 +3532,46 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
             out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate());
         }
 
+        void FBXConverter::ConvertToUnitScale( FbxUnit unit ) {
+            if (mCurrentUnit == unit) {
+                return;
+            }
+
+            ai_real scale = 1.0;
+            if (mCurrentUnit == FbxUnit::cm) {
+                if (unit == FbxUnit::m) {
+                    scale = (ai_real)0.01;
+                } else if (unit == FbxUnit::km) {
+                    scale = (ai_real)0.00001;
+                }
+            } else if (mCurrentUnit == FbxUnit::m) {
+                if (unit == FbxUnit::cm) {
+                    scale = (ai_real)100.0;
+                } else if (unit == FbxUnit::km) {
+                    scale = (ai_real)0.001;
+                }
+            } else if (mCurrentUnit == FbxUnit::km) {
+                if (unit == FbxUnit::cm) {
+                    scale = (ai_real)100000.0;
+                } else if (unit == FbxUnit::m) {
+                    scale = (ai_real)1000.0;
+                }
+            }
+            
+            for (auto mesh : meshes) {
+                if (nullptr == mesh) {
+                    continue;
+                }
+
+                if (mesh->HasPositions()) {
+                    for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
+                        aiVector3D &pos = mesh->mVertices[i];
+                        pos *= scale;
+                    }
+                }
+            }
+        }
+
         void FBXConverter::TransferDataToScene()
         {
             ai_assert(!out->mMeshes);
@@ -3525,9 +3625,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
         }
 
         // ------------------------------------------------------------------------------------------------
-        void ConvertToAssimpScene(aiScene* out, const Document& doc)
+        void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit)
         {
-            FBXConverter converter(out, doc);
+            FBXConverter converter(out, doc, removeEmptyBones, unit);
         }
 
     } // !FBX

+ 29 - 8
thirdparty/assimp/code/FBXConverter.h → thirdparty/assimp/code/FBX/FBXConverter.h

@@ -52,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "FBXUtil.h"
 #include "FBXProperties.h"
 #include "FBXImporter.h"
+
 #include <assimp/anim.h>
 #include <assimp/material.h>
 #include <assimp/light.h>
@@ -76,12 +77,22 @@ namespace FBX {
 
 class Document;
 
+enum class FbxUnit {
+    cm = 0,
+    m,
+    km,
+    NumUnits,
+
+    Undefined
+};
+
 /** 
  *  Convert a FBX #Document to #aiScene
  *  @param out Empty scene to be populated
- *  @param doc Parsed FBX document 
+ *  @param doc Parsed FBX document
+ *  @param removeEmptyBones Will remove bones, which do not have any references to vertices.
  */
-void ConvertToAssimpScene(aiScene* out, const Document& doc);
+void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit);
 
 /** Dummy class to encapsulate the conversion process */
 class FBXConverter {
@@ -112,7 +123,7 @@ public:
     };
 
 public:
-    FBXConverter(aiScene* out, const Document& doc);
+    FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit);
     ~FBXConverter();
 
 private:
@@ -144,6 +155,11 @@ private:
     // while these would be allowed, they are a potential trouble spot so better not use them).
     const char* NameTransformationComp(TransformationComp comp);
 
+    // ------------------------------------------------------------------------------------------------
+    // Returns an unique name for a node or traverses up a hierarchy until a non-empty name is found and
+    // then makes this name unique
+    std::string MakeUniqueNodeName(const Model* const model, const aiNode& parent);
+
     // ------------------------------------------------------------------------------------------------
     // note: this returns the REAL fbx property names
     const char* NameTransformationCompProperty(TransformationComp comp);
@@ -167,7 +183,7 @@ private:
     /**
     *  note: memory for output_nodes will be managed by the caller
     */
-    void GenerateTransformationNodeChain(const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
+    bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
 
     // ------------------------------------------------------------------------------------------------
     void SetupNodeMetadata(const Model& model, aiNode& nd);
@@ -414,6 +430,10 @@ private:
 
     void ConvertGlobalSettings();
 
+    // ------------------------------------------------------------------------------------------------
+    //  Will perform the conversion from a given unit to the requested unit.
+    void ConvertToUnitScale(FbxUnit unit);
+
     // ------------------------------------------------------------------------------------------------
     // copy generated meshes, animations, lights, cameras and textures to the output scene
     void TransferDataToScene();
@@ -443,16 +463,17 @@ private:
     NodeAnimBitMap node_anim_chain_bits;
 
     // number of nodes with the same name
-    using NodeAnimNameMap = std::unordered_map<std::string, unsigned int>;
-    NodeAnimNameMap mNodeNameInstances;
-
-    using NodeNameCache = std::unordered_set<std::string>;
+    using NodeNameCache = std::unordered_map<std::string, unsigned int>;
     NodeNameCache mNodeNames;
 
     double anim_fps;
 
     aiScene* const out;
     const FBX::Document& doc;
+
+    bool mRemoveEmptyBones;
+
+    FbxUnit mCurrentUnit;
 };
 
 }

+ 0 - 0
thirdparty/assimp/code/FBXDeformer.cpp → thirdparty/assimp/code/FBX/FBXDeformer.cpp


+ 0 - 0
thirdparty/assimp/code/FBXDocument.cpp → thirdparty/assimp/code/FBX/FBXDocument.cpp


+ 2 - 2
thirdparty/assimp/code/FBXDocument.h → thirdparty/assimp/code/FBX/FBXDocument.h

@@ -627,7 +627,7 @@ public:
         return content;
     }
 
-    uint32_t ContentLength() const {
+    uint64_t ContentLength() const {
         return contentLength;
     }
 
@@ -643,7 +643,7 @@ private:
     std::string fileName;
     std::shared_ptr<const PropertyTable> props;
 
-    uint32_t contentLength;
+    uint64_t contentLength;
     uint8_t* content;
 };
 

+ 0 - 0
thirdparty/assimp/code/FBXDocumentUtil.cpp → thirdparty/assimp/code/FBX/FBXDocumentUtil.cpp


+ 0 - 0
thirdparty/assimp/code/FBXDocumentUtil.h → thirdparty/assimp/code/FBX/FBXDocumentUtil.h


+ 7 - 4
thirdparty/assimp/code/FBXExportNode.cpp → thirdparty/assimp/code/FBX/FBXExportNode.cpp

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <sstream> // ostringstream
 #include <memory> // shared_ptr
 
+namespace Assimp {
 // AddP70<type> helpers... there's no usable pattern here,
 // so all are defined as separate functions.
 // Even "animatable" properties are often completely different
@@ -252,7 +253,8 @@ void FBX::Node::DumpChildren(
     } else {
         std::ostringstream ss;
         DumpChildrenAscii(ss, indent);
-        s.PutString(ss.str());
+        if (ss.tellp() > 0)
+            s.PutString(ss.str());
     }
 }
 
@@ -266,7 +268,8 @@ void FBX::Node::End(
     } else {
         std::ostringstream ss;
         EndAscii(ss, indent, has_children);
-        s.PutString(ss.str());
+        if (ss.tellp() > 0)
+            s.PutString(ss.str());
     }
 }
 
@@ -367,7 +370,7 @@ void FBX::Node::EndBinary(
     bool has_children
 ) {
     // if there were children, add a null record
-    if (has_children) { s.PutString(FBX::NULL_RECORD); }
+    if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD); }
 
     // now go back and write initial pos
     this->end_pos = s.Tell();
@@ -563,6 +566,6 @@ void FBX::Node::WritePropertyNode(
         FBX::Node::WritePropertyNodeAscii(name, v, s, indent);
     }
 }
-
+}
 #endif // ASSIMP_BUILD_NO_FBX_EXPORTER
 #endif // ASSIMP_BUILD_NO_EXPORT

+ 6 - 6
thirdparty/assimp/code/FBXExportNode.h → thirdparty/assimp/code/FBX/FBXExportNode.h

@@ -54,16 +54,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <string>
 #include <vector>
 
+namespace Assimp {
 namespace FBX {
     class Node;
 }
 
-class FBX::Node
-{
-public: // public data members
+class FBX::Node {
+public: 
     // TODO: accessors
     std::string name; // node name
-    std::vector<FBX::Property> properties; // node properties
+    std::vector<FBX::FBXExportProperty> properties; // node properties
     std::vector<FBX::Node> children; // child nodes
 
     // some nodes always pretend they have children...
@@ -214,7 +214,7 @@ public: // static member functions
         Assimp::StreamWriterLE& s,
         bool binary, int indent
     ) {
-        FBX::Property p(value);
+        FBX::FBXExportProperty p(value);
         FBX::Node node(name, p);
         node.Dump(s, binary, indent);
     }
@@ -264,7 +264,7 @@ private: // static helper functions
     );
 
 };
-
+}
 
 #endif // ASSIMP_BUILD_NO_FBX_EXPORTER
 

+ 141 - 116
thirdparty/assimp/code/FBXExportProperty.cpp → thirdparty/assimp/code/FBX/FBXExportProperty.cpp

@@ -52,187 +52,210 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <locale>
 #include <sstream> // ostringstream
 
+namespace Assimp {
+namespace FBX {
 
 // constructors for single element properties
 
-FBX::Property::Property(bool v)
-    : type('C'), data(1)
-{
-    data = {uint8_t(v)};
+FBXExportProperty::FBXExportProperty(bool v)
+: type('C')
+, data(1) {
+    data = {
+        uint8_t(v)
+    };
 }
 
-FBX::Property::Property(int16_t v) : type('Y'), data(2)
-{
+FBXExportProperty::FBXExportProperty(int16_t v)
+: type('Y')
+, data(2) {
     uint8_t* d = data.data();
     (reinterpret_cast<int16_t*>(d))[0] = v;
 }
 
-FBX::Property::Property(int32_t v) : type('I'), data(4)
-{
+FBXExportProperty::FBXExportProperty(int32_t v)
+: type('I')
+, data(4) {
     uint8_t* d = data.data();
     (reinterpret_cast<int32_t*>(d))[0] = v;
 }
 
-FBX::Property::Property(float v) : type('F'), data(4)
-{
+FBXExportProperty::FBXExportProperty(float v)
+: type('F')
+, data(4) {
     uint8_t* d = data.data();
     (reinterpret_cast<float*>(d))[0] = v;
 }
 
-FBX::Property::Property(double v) : type('D'), data(8)
-{
+FBXExportProperty::FBXExportProperty(double v)
+: type('D')
+, data(8) {
     uint8_t* d = data.data();
     (reinterpret_cast<double*>(d))[0] = v;
 }
 
-FBX::Property::Property(int64_t v) : type('L'), data(8)
-{
+FBXExportProperty::FBXExportProperty(int64_t v)
+: type('L')
+, data(8) {
     uint8_t* d = data.data();
     (reinterpret_cast<int64_t*>(d))[0] = v;
 }
 
-
 // constructors for array-type properties
 
-FBX::Property::Property(const char* c, bool raw)
-    : Property(std::string(c), raw)
-{}
+FBXExportProperty::FBXExportProperty(const char* c, bool raw)
+: FBXExportProperty(std::string(c), raw) {
+    // empty
+}
 
 // strings can either be saved as "raw" (R) data, or "string" (S) data
-FBX::Property::Property(const std::string& s, bool raw)
-    : type(raw ? 'R' : 'S'), data(s.size())
-{
+FBXExportProperty::FBXExportProperty(const std::string& s, bool raw)
+: type(raw ? 'R' : 'S')
+, data(s.size()) {
     for (size_t i = 0; i < s.size(); ++i) {
         data[i] = uint8_t(s[i]);
     }
 }
 
-FBX::Property::Property(const std::vector<uint8_t>& r)
-    : type('R'), data(r)
-{}
+FBXExportProperty::FBXExportProperty(const std::vector<uint8_t>& r)
+: type('R')
+, data(r) {
+    // empty
+}
 
-FBX::Property::Property(const std::vector<int32_t>& va)
-    : type('i'), data(4*va.size())
-{
+FBXExportProperty::FBXExportProperty(const std::vector<int32_t>& va)
+: type('i')
+, data(4 * va.size() ) {
     int32_t* d = reinterpret_cast<int32_t*>(data.data());
-    for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
+    for (size_t i = 0; i < va.size(); ++i) {
+        d[i] = va[i];
+    }
 }
 
-FBX::Property::Property(const std::vector<int64_t>& va)
-    : type('l'), data(8*va.size())
-{
+FBXExportProperty::FBXExportProperty(const std::vector<int64_t>& va)
+: type('l')
+, data(8 * va.size()) {
     int64_t* d = reinterpret_cast<int64_t*>(data.data());
-    for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
+    for (size_t i = 0; i < va.size(); ++i) {
+        d[i] = va[i];
+    }
 }
 
-FBX::Property::Property(const std::vector<float>& va)
-    : type('f'), data(4*va.size())
-{
+FBXExportProperty::FBXExportProperty(const std::vector<float>& va)
+: type('f')
+, data(4 * va.size()) {
     float* d = reinterpret_cast<float*>(data.data());
-    for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
+    for (size_t i = 0; i < va.size(); ++i) {
+        d[i] = va[i];
+    }
 }
 
-FBX::Property::Property(const std::vector<double>& va)
-    : type('d'), data(8*va.size())
-{
+FBXExportProperty::FBXExportProperty(const std::vector<double>& va)
+: type('d')
+, data(8 * va.size()) {
     double* d = reinterpret_cast<double*>(data.data());
-    for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; }
+    for (size_t i = 0; i < va.size(); ++i) {
+        d[i] = va[i];
+    }
 }
 
-FBX::Property::Property(const aiMatrix4x4& vm)
-    : type('d'), data(8*16)
-{
+FBXExportProperty::FBXExportProperty(const aiMatrix4x4& vm)
+: type('d')
+, data(8 * 16) {
     double* d = reinterpret_cast<double*>(data.data());
     for (unsigned int c = 0; c < 4; ++c) {
         for (unsigned int r = 0; r < 4; ++r) {
-            d[4*c+r] = vm[r][c];
+            d[4 * c + r] = vm[r][c];
         }
     }
 }
 
 // public member functions
 
-size_t FBX::Property::size()
-{
+size_t FBXExportProperty::size() {
     switch (type) {
-    case 'C': case 'Y': case 'I': case 'F': case 'D': case 'L':
-        return data.size() + 1;
-    case 'S': case 'R':
-        return data.size() + 5;
-    case 'i': case 'd':
-        return data.size() + 13;
-    default:
-        throw DeadlyExportError("Requested size on property of unknown type");
+        case 'C':
+        case 'Y':
+        case 'I':
+        case 'F':
+        case 'D':
+        case 'L':
+            return data.size() + 1;
+        case 'S':
+        case 'R':
+            return data.size() + 5;
+        case 'i':
+        case 'd':
+            return data.size() + 13;
+        default:
+            throw DeadlyExportError("Requested size on property of unknown type");
     }
 }
 
-void FBX::Property::DumpBinary(Assimp::StreamWriterLE &s)
-{
+void FBXExportProperty::DumpBinary(Assimp::StreamWriterLE& s) {
     s.PutU1(type);
     uint8_t* d = data.data();
     size_t N;
     switch (type) {
-    case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return;
-    case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return;
-    case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return;
-    case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return;
-    case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return;
-    case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return;
-    case 'S':
-    case 'R':
-        s.PutU4(uint32_t(data.size()));
-        for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
-        return;
-    case 'i':
-        N = data.size() / 4;
-        s.PutU4(uint32_t(N)); // number of elements
-        s.PutU4(0); // no encoding (1 would be zip-compressed)
-        // TODO: compress if large?
-        s.PutU4(uint32_t(data.size())); // data size
-        for (size_t i = 0; i < N; ++i) {
-            s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
-        }
-        return;
-    case 'l':
-        N = data.size() / 8;
-        s.PutU4(uint32_t(N)); // number of elements
-        s.PutU4(0); // no encoding (1 would be zip-compressed)
-        // TODO: compress if large?
-        s.PutU4(uint32_t(data.size())); // data size
-        for (size_t i = 0; i < N; ++i) {
-            s.PutI8((reinterpret_cast<int64_t*>(d))[i]);
-        }
-        return;
-    case 'f':
-        N = data.size() / 4;
-        s.PutU4(uint32_t(N)); // number of elements
-        s.PutU4(0); // no encoding (1 would be zip-compressed)
-        // TODO: compress if large?
-        s.PutU4(uint32_t(data.size())); // data size
-        for (size_t i = 0; i < N; ++i) {
-            s.PutF4((reinterpret_cast<float*>(d))[i]);
-        }
-        return;
-    case 'd':
-        N = data.size() / 8;
-        s.PutU4(uint32_t(N)); // number of elements
-        s.PutU4(0); // no encoding (1 would be zip-compressed)
-        // TODO: compress if large?
-        s.PutU4(uint32_t(data.size())); // data size
-        for (size_t i = 0; i < N; ++i) {
-            s.PutF8((reinterpret_cast<double*>(d))[i]);
-        }
-        return;
-    default:
-        std::ostringstream err;
-        err << "Tried to dump property with invalid type '";
-        err << type << "'!";
-        throw DeadlyExportError(err.str());
+        case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return;
+        case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return;
+        case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return;
+        case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return;
+        case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return;
+        case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return;
+        case 'S':
+        case 'R':
+            s.PutU4(uint32_t(data.size()));
+            for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
+            return;
+        case 'i':
+            N = data.size() / 4;
+            s.PutU4(uint32_t(N)); // number of elements
+            s.PutU4(0); // no encoding (1 would be zip-compressed)
+            // TODO: compress if large?
+            s.PutU4(uint32_t(data.size())); // data size
+            for (size_t i = 0; i < N; ++i) {
+                s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
+            }
+            return;
+        case 'l':
+            N = data.size() / 8;
+            s.PutU4(uint32_t(N)); // number of elements
+            s.PutU4(0); // no encoding (1 would be zip-compressed)
+            // TODO: compress if large?
+            s.PutU4(uint32_t(data.size())); // data size
+            for (size_t i = 0; i < N; ++i) {
+                s.PutI8((reinterpret_cast<int64_t*>(d))[i]);
+            }
+            return;
+        case 'f':
+            N = data.size() / 4;
+            s.PutU4(uint32_t(N)); // number of elements
+            s.PutU4(0); // no encoding (1 would be zip-compressed)
+            // TODO: compress if large?
+            s.PutU4(uint32_t(data.size())); // data size
+            for (size_t i = 0; i < N; ++i) {
+                s.PutF4((reinterpret_cast<float*>(d))[i]);
+            }
+            return;
+        case 'd':
+            N = data.size() / 8;
+            s.PutU4(uint32_t(N)); // number of elements
+            s.PutU4(0); // no encoding (1 would be zip-compressed)
+            // TODO: compress if large?
+            s.PutU4(uint32_t(data.size())); // data size
+            for (size_t i = 0; i < N; ++i) {
+                s.PutF8((reinterpret_cast<double*>(d))[i]);
+            }
+            return;
+        default:
+            std::ostringstream err;
+            err << "Tried to dump property with invalid type '";
+            err << type << "'!";
+            throw DeadlyExportError(err.str());
     }
 }
 
-void FBX::Property::DumpAscii(Assimp::StreamWriterLE &outstream, int indent)
-{
+void FBXExportProperty::DumpAscii(Assimp::StreamWriterLE& outstream, int indent) {
     std::ostringstream ss;
     ss.imbue(std::locale::classic());
     ss.precision(15); // this seems to match official FBX SDK exports
@@ -240,8 +263,7 @@ void FBX::Property::DumpAscii(Assimp::StreamWriterLE &outstream, int indent)
     outstream.PutString(ss.str());
 }
 
-void FBX::Property::DumpAscii(std::ostream& s, int indent)
-{
+void FBXExportProperty::DumpAscii(std::ostream& s, int indent) {
     // no writing type... or anything. just shove it into the stream.
     uint8_t* d = data.data();
     size_t N;
@@ -360,5 +382,8 @@ void FBX::Property::DumpAscii(std::ostream& s, int indent)
     }
 }
 
+} // Namespace FBX
+} // Namespace Assimp
+
 #endif // ASSIMP_BUILD_NO_FBX_EXPORTER
 #endif // ASSIMP_BUILD_NO_EXPORT

+ 24 - 24
thirdparty/assimp/code/FBXExportProperty.h → thirdparty/assimp/code/FBX/FBXExportProperty.h

@@ -47,7 +47,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
 
-
 #include <assimp/types.h> // aiMatrix4x4
 #include <assimp/StreamWriter.h> // StreamWriterLE
 
@@ -56,11 +55,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <ostream>
 #include <type_traits> // is_void
 
+namespace Assimp {
 namespace FBX {
-    class Property;
-}
 
-/** FBX::Property
+/** @brief FBX::Property
  *
  *  Holds a value of any of FBX's recognized types,
  *  each represented by a particular one-character code.
@@ -78,35 +76,34 @@ namespace FBX {
  *  S : string (array of 1-byte char)
  *  R : raw data (array of bytes)
  */
-class FBX::Property
-{
+class FBXExportProperty {
 public:
     // constructors for basic types.
     // all explicit to avoid accidental typecasting
-    explicit Property(bool v);
+    explicit FBXExportProperty(bool v);
     // TODO: determine if there is actually a byte type,
     // or if this always means <bool>. 'C' seems to imply <char>,
     // so possibly the above was intended to represent both.
-    explicit Property(int16_t v);
-    explicit Property(int32_t v);
-    explicit Property(float v);
-    explicit Property(double v);
-    explicit Property(int64_t v);
+    explicit FBXExportProperty(int16_t v);
+    explicit FBXExportProperty(int32_t v);
+    explicit FBXExportProperty(float v);
+    explicit FBXExportProperty(double v);
+    explicit FBXExportProperty(int64_t v);
     // strings can either be stored as 'R' (raw) or 'S' (string) type
-    explicit Property(const char* c, bool raw=false);
-    explicit Property(const std::string& s, bool raw=false);
-    explicit Property(const std::vector<uint8_t>& r);
-    explicit Property(const std::vector<int32_t>& va);
-    explicit Property(const std::vector<int64_t>& va);
-    explicit Property(const std::vector<double>& va);
-    explicit Property(const std::vector<float>& va);
-    explicit Property(const aiMatrix4x4& vm);
+    explicit FBXExportProperty(const char* c, bool raw = false);
+    explicit FBXExportProperty(const std::string& s, bool raw = false);
+    explicit FBXExportProperty(const std::vector<uint8_t>& r);
+    explicit FBXExportProperty(const std::vector<int32_t>& va);
+    explicit FBXExportProperty(const std::vector<int64_t>& va);
+    explicit FBXExportProperty(const std::vector<double>& va);
+    explicit FBXExportProperty(const std::vector<float>& va);
+    explicit FBXExportProperty(const aiMatrix4x4& vm);
 
     // this will catch any type not defined above,
     // so that we don't accidentally convert something we don't want.
     // for example (const char*) --> (bool)... seriously wtf C++
     template <class T>
-    explicit Property(T v) : type('X') {
+    explicit FBXExportProperty(T v) : type('X') {
         static_assert(std::is_void<T>::value, "TRIED TO CREATE FBX PROPERTY WITH UNSUPPORTED TYPE, CHECK YOUR PROPERTY INSTANTIATION");
     } // note: no line wrap so it appears verbatim on the compiler error
 
@@ -114,9 +111,9 @@ public:
     size_t size();
 
     // write this property node as binary data to the given stream
-    void DumpBinary(Assimp::StreamWriterLE &s);
-    void DumpAscii(Assimp::StreamWriterLE &s, int indent=0);
-    void DumpAscii(std::ostream &s, int indent=0);
+    void DumpBinary(Assimp::StreamWriterLE& s);
+    void DumpAscii(Assimp::StreamWriterLE& s, int indent = 0);
+    void DumpAscii(std::ostream& s, int indent = 0);
     // note: make sure the ostream is in classic "C" locale
 
 private:
@@ -124,6 +121,9 @@ private:
     std::vector<uint8_t> data;
 };
 
+} // Namespace FBX
+} // Namespace Assimp
+
 #endif // ASSIMP_BUILD_NO_FBX_EXPORTER
 
 #endif // AI_FBXEXPORTPROPERTY_H_INC

+ 89 - 26
thirdparty/assimp/code/FBXExporter.cpp → thirdparty/assimp/code/FBX/FBXExporter.cpp

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "FBXExportNode.h"
 #include "FBXExportProperty.h"
 #include "FBXCommon.h"
+#include "FBXUtil.h"
 
 #include <assimp/version.h> // aiGetVersion
 #include <assimp/IOSystem.hpp>
@@ -73,7 +74,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 const ai_real DEG = ai_real( 57.29577951308232087679815481 ); // degrees per radian
 
+using namespace Assimp;
+using namespace Assimp::FBX;
+
 // some constants that we'll use for writing metadata
+namespace Assimp {
 namespace FBX {
     const std::string EXPORT_VERSION_STR = "7.4.0";
     const uint32_t EXPORT_VERSION_INT = 7400; // 7.4 == 2014/2015
@@ -92,11 +97,6 @@ namespace FBX {
         ";------------------------------------------------------------------";
 }
 
-using namespace Assimp;
-using namespace FBX;
-
-namespace Assimp {
-
     // ---------------------------------------------------------------------
     // Worker function for exporting a scene to binary FBX.
     // Prototyped and registered in Exporter.cpp
@@ -121,6 +121,7 @@ namespace Assimp {
         IOSystem* pIOSystem,
         const aiScene* pScene,
         const ExportProperties* pProperties
+
     ){
         // initialize the exporter
         FBXExporter exporter(pScene, pProperties);
@@ -1218,6 +1219,16 @@ void FBXExporter::WriteObjects ()
         layer.AddChild(le);
         layer.Dump(outstream, binary, indent);
 
+        for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr)
+        {
+            FBX::Node layerExtra("Layer", int32_t(1));
+            layerExtra.AddChild("Version", int32_t(100));
+            FBX::Node leExtra("LayerElement");
+            leExtra.AddChild("Type", "LayerElementUV");
+            leExtra.AddChild("TypedIndex", int32_t(lr));
+            layerExtra.AddChild(leExtra);
+            layerExtra.Dump(outstream, binary, indent);
+        }
         // finish the node record
         indent = 1;
         n.End(outstream, binary, indent, true);
@@ -1393,10 +1404,6 @@ void FBXExporter::WriteObjects ()
 
     // FbxVideo - stores images used by textures.
     for (const auto &it : uid_by_image) {
-        if (it.first.compare(0, 1, "*") == 0) {
-            // TODO: embedded textures
-            continue;
-        }
         FBX::Node n("Video");
         const int64_t& uid = it.second;
         const std::string name = ""; // TODO: ... name???
@@ -1406,7 +1413,33 @@ void FBXExporter::WriteObjects ()
         // TODO: get full path... relative path... etc... ugh...
         // for now just use the same path for everything,
         // and hopefully one of them will work out.
-        const std::string& path = it.first;
+        std::string path = it.first;
+        // try get embedded texture
+        const aiTexture* embedded_texture = mScene->GetEmbeddedTexture(it.first.c_str());
+        if (embedded_texture != nullptr) {
+            // change the path (use original filename, if available. If name is empty, concatenate texture index with file extension)
+            std::stringstream newPath;
+            if (embedded_texture->mFilename.length > 0) {
+                newPath << embedded_texture->mFilename.C_Str();
+            } else if (embedded_texture->achFormatHint[0]) {
+                int texture_index = std::stoi(path.substr(1, path.size() - 1));
+                newPath << texture_index << "." << embedded_texture->achFormatHint;
+            }
+            path = newPath.str();
+            // embed the texture
+            size_t texture_size = static_cast<size_t>(embedded_texture->mWidth * std::max(embedded_texture->mHeight, 1u));
+            if (binary) {
+                // embed texture as binary data
+                std::vector<uint8_t> tex_data;
+                tex_data.resize(texture_size);
+                memcpy(&tex_data[0], (char*)embedded_texture->pcData, texture_size);
+                n.AddChild("Content", tex_data);
+            } else {
+                // embed texture in base64 encoding
+                std::string encoded_texture = FBX::Util::EncodeBase64((char*)embedded_texture->pcData, texture_size);
+                n.AddChild("Content", encoded_texture);
+            }
+        }
         p.AddP70("Path", "KString", "XRefUrl", "", path);
         n.AddChild(p);
         n.AddChild("UseMipMap", int32_t(0));
@@ -1419,17 +1452,17 @@ void FBXExporter::WriteObjects ()
     // referenced by material_index/texture_type pairs.
     std::map<std::pair<size_t,size_t>,int64_t> texture_uids;
     const std::map<aiTextureType,std::string> prop_name_by_tt = {
-        {aiTextureType_DIFFUSE, "DiffuseColor"},
-        {aiTextureType_SPECULAR, "SpecularColor"},
-        {aiTextureType_AMBIENT, "AmbientColor"},
-        {aiTextureType_EMISSIVE, "EmissiveColor"},
-        {aiTextureType_HEIGHT, "Bump"},
-        {aiTextureType_NORMALS, "NormalMap"},
-        {aiTextureType_SHININESS, "ShininessExponent"},
-        {aiTextureType_OPACITY, "TransparentColor"},
+        {aiTextureType_DIFFUSE,      "DiffuseColor"},
+        {aiTextureType_SPECULAR,     "SpecularColor"},
+        {aiTextureType_AMBIENT,      "AmbientColor"},
+        {aiTextureType_EMISSIVE,     "EmissiveColor"},
+        {aiTextureType_HEIGHT,       "Bump"},
+        {aiTextureType_NORMALS,      "NormalMap"},
+        {aiTextureType_SHININESS,    "ShininessExponent"},
+        {aiTextureType_OPACITY,      "TransparentColor"},
         {aiTextureType_DISPLACEMENT, "DisplacementColor"},
         //{aiTextureType_LIGHTMAP, "???"},
-        {aiTextureType_REFLECTION, "ReflectionColor"}
+        {aiTextureType_REFLECTION,   "ReflectionColor"}
         //{aiTextureType_UNKNOWN, ""}
     };
     for (size_t i = 0; i < mScene->mNumMaterials; ++i) {
@@ -1575,19 +1608,41 @@ void FBXExporter::WriteObjects ()
     // one sticky point is that the number of vertices may not match,
     // because assimp splits vertices by normal, uv, etc.
 
+    // functor for aiNode sorting
+    struct SortNodeByName
+    {
+        bool operator()(const aiNode *lhs, const aiNode *rhs) const
+        {
+            return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0;
+        }
+    };
+
     // first we should mark the skeleton for each mesh.
     // the skeleton must include not only the aiBones,
     // but also all their parent nodes.
     // anything that affects the position of any bone node must be included.
-    std::vector<std::set<const aiNode*>> skeleton_by_mesh(mScene->mNumMeshes);
+    // Use SorNodeByName to make sure the exported result will be the same across all systems
+    // Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent
+    std::vector<std::set<const aiNode*, SortNodeByName>> skeleton_by_mesh(mScene->mNumMeshes);
     // at the same time we can build a list of all the skeleton nodes,
     // which will be used later to mark them as type "limbNode".
     std::unordered_set<const aiNode*> limbnodes;
+    
+    //actual bone nodes in fbx, without parenting-up
+    std::unordered_set<std::string> setAllBoneNamesInScene;
+    for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m)
+    {
+        aiMesh* pMesh = mScene->mMeshes[m];
+        for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
+            setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data);
+    }
+    aiMatrix4x4 mxTransIdentity;
+    
     // and a map of nodes by bone name, as finding them is annoying.
     std::map<std::string,aiNode*> node_by_bone;
     for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
         const aiMesh* m = mScene->mMeshes[mi];
-        std::set<const aiNode*> skeleton;
+        std::set<const aiNode*, SortNodeByName> skeleton;
         for (size_t bi =0; bi < m->mNumBones; ++bi) {
             const aiBone* b = m->mBones[bi];
             const std::string name(b->mName.C_Str());
@@ -1626,6 +1681,11 @@ void FBXExporter::WriteObjects ()
                 if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) {
                     continue;
                 }
+                //not a bone in scene && no effect in transform
+                if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end()
+                   && parent->mTransformation == mxTransIdentity) {
+                        continue;
+                }
                 // otherwise check if this is the root of the skeleton
                 bool end = false;
                 // is the mesh part of this node?
@@ -1728,7 +1788,7 @@ void FBXExporter::WriteObjects ()
         aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
 
         // now make a subdeformer for each bone in the skeleton
-        const std::set<const aiNode*> &skeleton = skeleton_by_mesh[mi];
+        const std::set<const aiNode*, SortNodeByName> skeleton= skeleton_by_mesh[mi];
         for (const aiNode* bone_node : skeleton) {
             // if there's a bone for this node, find it
             const aiBone* b = nullptr;
@@ -1790,7 +1850,10 @@ void FBXExporter::WriteObjects ()
 
             // this should be the same as the bone's mOffsetMatrix.
             // if it's not the same, the skeleton isn't in the bind pose.
-            const float epsilon = 1e-4f; // some error is to be expected
+            float epsilon = 1e-4f; // some error is to be expected
+            float epsilon_custom = mProperties->GetPropertyFloat("BINDPOSE_EPSILON", -1);
+            if(epsilon_custom > 0)
+                epsilon = epsilon_custom;
             bool bone_xform_okay = true;
             if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
                 not_in_bind_pose.insert(b);
@@ -2237,8 +2300,8 @@ void FBXExporter::WriteModelNode(
 
     // not sure what these are for,
     // but they seem to be omnipresent
-    m.AddChild("Shading", Property(true));
-    m.AddChild("Culling", Property("CullingOff"));
+    m.AddChild("Shading", FBXExportProperty(true));
+    m.AddChild("Culling", FBXExportProperty("CullingOff"));
 
     m.Dump(outstream, binary, 1);
 }
@@ -2351,7 +2414,7 @@ void FBXExporter::WriteModelNodes(
         na.AddProperties(
             node_attribute_uid, FBX::SEPARATOR + "NodeAttribute", "LimbNode"
         );
-        na.AddChild("TypeFlags", Property("Skeleton"));
+        na.AddChild("TypeFlags", FBXExportProperty("Skeleton"));
         na.Dump(outstream, binary, 1);
         // and connect them
         connections.emplace_back("C", "OO", node_attribute_uid, node_uid);

+ 0 - 0
thirdparty/assimp/code/FBXExporter.h → thirdparty/assimp/code/FBX/FBXExporter.h


+ 25 - 14
thirdparty/assimp/code/FBXImportSettings.h → thirdparty/assimp/code/FBX/FBXImportSettings.h

@@ -53,19 +53,22 @@ namespace FBX {
 struct ImportSettings
 {
     ImportSettings()
-        : strictMode(true)
-        , readAllLayers(true)
-        , readAllMaterials(false)
-        , readMaterials(true)
-        , readTextures(true)
-        , readCameras(true)
-        , readLights(true)
-        , readAnimations(true)
-        , readWeights(true)
-        , preservePivots(true)
-        , optimizeEmptyAnimationCurves(true)
-        , useLegacyEmbeddedTextureNaming(false)
-    {}
+    : strictMode(true)
+    , readAllLayers(true)
+    , readAllMaterials(false)
+    , readMaterials(true)
+    , readTextures(true)
+    , readCameras(true)
+    , readLights(true)
+    , readAnimations(true)
+    , readWeights(true)
+    , preservePivots(true)
+    , optimizeEmptyAnimationCurves(true)
+    , useLegacyEmbeddedTextureNaming(false)
+    , removeEmptyBones( true )
+    , convertToMeters( false ) {
+        // empty
+    }
 
 
     /** enable strict mode:
@@ -141,8 +144,16 @@ struct ImportSettings
     bool optimizeEmptyAnimationCurves;
 
     /** use legacy naming for embedded textures eg: (*0, *1, *2)
-    **/
+    */
     bool useLegacyEmbeddedTextureNaming;
+
+    /** Empty bones shall be removed
+    */
+    bool removeEmptyBones;
+
+    /** Set to true to perform a conversion from cm to meter after the import
+    */
+    bool convertToMeters;
 };
 
 

+ 8 - 2
thirdparty/assimp/code/FBXImporter.cpp → thirdparty/assimp/code/FBX/FBXImporter.cpp

@@ -140,6 +140,8 @@ void FBXImporter::SetupProperties(const Importer* pImp)
     settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
     settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
     settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
+    settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
+    settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -170,7 +172,7 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
         bool is_binary = false;
         if (!strncmp(begin,"Kaydara FBX Binary",18)) {
             is_binary = true;
-            TokenizeBinary(tokens,begin,static_cast<unsigned int>(contents.size()));
+            TokenizeBinary(tokens,begin,contents.size());
         }
         else {
             Tokenize(tokens,begin);
@@ -183,8 +185,12 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
         // take the raw parse-tree and convert it to a FBX DOM
         Document doc(parser,settings);
 
+        FbxUnit unit(FbxUnit::cm);
+        if (settings.convertToMeters) {
+            unit = FbxUnit::m;
+        }
         // convert the FBX DOM to aiScene
-        ConvertToAssimpScene(pScene,doc);
+        ConvertToAssimpScene(pScene,doc, settings.removeEmptyBones, unit);
 
         std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
     }

+ 0 - 0
thirdparty/assimp/code/FBXImporter.h → thirdparty/assimp/code/FBX/FBXImporter.h


+ 34 - 10
thirdparty/assimp/code/FBXMaterial.cpp → thirdparty/assimp/code/FBX/FBXMaterial.cpp

@@ -316,7 +316,7 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std
         relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0));
     }
 
-    if(Content) {
+    if(Content && !Content->Tokens().empty()) {
         //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
         try {
             const Token& token = GetRequiredToken(*Content, 0);
@@ -326,16 +326,40 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std
                     DOMError("embedded content is not surrounded by quotation marks", &element);
                 }
                 else {
-                    const char* encodedData = data + 1;
-                    size_t encodedDataLen = static_cast<size_t>(token.end() - token.begin());
-                    // search for last quotation mark
-                    while (encodedDataLen > 1 && encodedData[encodedDataLen] != '"')
-                        encodedDataLen--;
-                    if (encodedDataLen % 4 != 0) {
-                        DOMError("embedded content is invalid, needs to be in base64", &element);
+                    size_t targetLength = 0;
+                    auto numTokens = Content->Tokens().size();
+                    // First time compute size (it could be large like 64Gb and it is good to allocate it once)
+                    for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx)
+                    {
+                        const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
+                        size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
+                        const char* base64data = dataToken.begin() + 1;
+                        const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength);
+                        if (outLength == 0)
+                        {
+                            DOMError("Corrupted embedded content found", &element);
+                        }
+                        targetLength += outLength;
                     }
-                    else {
-                        contentLength = Util::DecodeBase64(encodedData, encodedDataLen, content);
+                    if (targetLength == 0)
+                    {
+                        DOMError("Corrupted embedded content found", &element);
+                    }
+                    content = new uint8_t[targetLength];
+                    contentLength = static_cast<uint64_t>(targetLength);
+                    size_t dst_offset = 0;
+                    for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx)
+                    {
+                        const Token& dataToken = GetRequiredToken(*Content, tokenIdx);
+                        size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes
+                        const char* base64data = dataToken.begin() + 1;
+                        dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset);
+                    }
+                    if (targetLength != dst_offset)
+                    {
+                        delete[] content;
+                        contentLength = 0;
+                        DOMError("Corrupted embedded content found", &element);
                     }
                 }
             }

+ 6 - 5
thirdparty/assimp/code/FBXMeshGeometry.cpp → thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp

@@ -568,15 +568,15 @@ void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, cons
 }
 
 // ------------------------------------------------------------------------------------------------
-static const std::string TangentIndexToken = "TangentIndex";
-static const std::string TangentsIndexToken = "TangentsIndex";
+static const char *TangentIndexToken = "TangentIndex";
+static const char *TangentsIndexToken = "TangentsIndex";
 
 void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source,
     const std::string& MappingInformationType,
     const std::string& ReferenceInformationType)
 {
     const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent";
-    const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken.c_str() : TangentIndexToken.c_str();
+    const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken;
     ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType,
         str,
         strIdx,
@@ -630,10 +630,11 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
             materials_out.clear();
         }
 
-        m_materials.assign(m_vertices.size(),materials_out[0]);
+        materials_out.resize(m_vertices.size());
+        std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0));
     }
     else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
-        m_materials.resize(face_count);
+        materials_out.resize(face_count);
 
         if(materials_out.size() != face_count) {
             FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ")

+ 0 - 0
thirdparty/assimp/code/FBXMeshGeometry.h → thirdparty/assimp/code/FBX/FBXMeshGeometry.h


+ 0 - 0
thirdparty/assimp/code/FBXModel.cpp → thirdparty/assimp/code/FBX/FBXModel.cpp


+ 0 - 0
thirdparty/assimp/code/FBXNodeAttribute.cpp → thirdparty/assimp/code/FBX/FBXNodeAttribute.cpp


+ 4 - 8
thirdparty/assimp/code/FBXParser.cpp → thirdparty/assimp/code/FBX/FBXParser.cpp

@@ -117,7 +117,7 @@ namespace FBX {
 Element::Element(const Token& key_token, Parser& parser)
 : key_token(key_token)
 {
-    TokenPtr n = NULL;
+    TokenPtr n = nullptr;
     do {
         n = parser.AdvanceToNextToken();
         if(!n) {
@@ -643,9 +643,9 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
         if (type == 'd') {
             const double* d = reinterpret_cast<const double*>(&buff[0]);
             for (unsigned int i = 0; i < count3; ++i, d += 3) {
-                out.push_back(aiVector3D(static_cast<float>(d[0]),
-                    static_cast<float>(d[1]),
-                    static_cast<float>(d[2])));
+                out.push_back(aiVector3D(static_cast<ai_real>(d[0]),
+                    static_cast<ai_real>(d[1]),
+                    static_cast<ai_real>(d[2])));
             }
             // for debugging
             /*for ( size_t i = 0; i < out.size(); i++ ) {
@@ -963,7 +963,6 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
     }
 }
 
-
 // ------------------------------------------------------------------------------------------------
 // read an array of uints
 void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
@@ -1280,7 +1279,6 @@ float ParseTokenAsFloat(const Token& t)
     return i;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 // wrapper around ParseTokenAsInt() with ParseError handling
 int ParseTokenAsInt(const Token& t)
@@ -1293,8 +1291,6 @@ int ParseTokenAsInt(const Token& t)
     return i;
 }
 
-
-
 // ------------------------------------------------------------------------------------------------
 // wrapper around ParseTokenAsInt64() with ParseError handling
 int64_t ParseTokenAsInt64(const Token& t)

+ 0 - 0
thirdparty/assimp/code/FBXParser.h → thirdparty/assimp/code/FBX/FBXParser.h


+ 0 - 0
thirdparty/assimp/code/FBXProperties.cpp → thirdparty/assimp/code/FBX/FBXProperties.cpp


+ 0 - 0
thirdparty/assimp/code/FBXProperties.h → thirdparty/assimp/code/FBX/FBXProperties.h


+ 0 - 0
thirdparty/assimp/code/FBXTokenizer.cpp → thirdparty/assimp/code/FBX/FBXTokenizer.cpp


+ 6 - 6
thirdparty/assimp/code/FBXTokenizer.h → thirdparty/assimp/code/FBX/FBXTokenizer.h

@@ -93,7 +93,7 @@ public:
     Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column);
 
     /** construct a binary token */
-    Token(const char* sbegin, const char* send, TokenType type, unsigned int offset);
+    Token(const char* sbegin, const char* send, TokenType type, size_t offset);
 
     ~Token();
 
@@ -118,14 +118,14 @@ public:
         return type;
     }
 
-    unsigned int Offset() const {
+    size_t Offset() const {
         ai_assert(IsBinary());
         return offset;
     }
 
     unsigned int Line() const {
         ai_assert(!IsBinary());
-        return line;
+        return static_cast<unsigned int>(line);
     }
 
     unsigned int Column() const {
@@ -147,8 +147,8 @@ private:
     const TokenType type;
 
     union {
-        const unsigned int line;
-        unsigned int offset;
+        size_t line;
+        size_t offset;
     };
     const unsigned int column;
 };
@@ -178,7 +178,7 @@ void Tokenize(TokenList& output_tokens, const char* input);
  * @param input_buffer Binary input buffer to be processed.
  * @param length Length of input buffer, in bytes. There is no 0-terminal.
  * @throw DeadlyImportError if something goes wrong */
-void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int length);
+void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length);
 
 
 } // ! FBX

+ 107 - 28
thirdparty/assimp/code/FBXUtil.cpp → thirdparty/assimp/code/FBX/FBXUtil.cpp

@@ -86,7 +86,7 @@ const char* TokenTypeString(TokenType t)
 
 
 // ------------------------------------------------------------------------------------------------
-std::string AddOffset(const std::string& prefix, const std::string& text, unsigned int offset)
+std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset)
 {
     return static_cast<std::string>( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) );
 }
@@ -114,47 +114,126 @@ std::string AddTokenText(const std::string& prefix, const std::string& text, con
         text) );
 }
 
+// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
 static const uint8_t base64DecodeTable[128] = {
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0, 63,
-    52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,  0, 64,  0,  0,
-    0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
-    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,
-    0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
-    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,  0,  0,  0,  0,  0
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+    255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255,
+    255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
+    255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255
 };
 
 uint8_t DecodeBase64(char ch)
 {
-    return base64DecodeTable[size_t(ch)];
+    const auto idx = static_cast<uint8_t>(ch);
+    if (idx > 127)
+        return 255;
+    return base64DecodeTable[idx];
 }
 
-size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out)
+size_t ComputeDecodedSizeBase64(const char* in, size_t inLength)
 {
-    if (inLength < 4) {
-        out = 0;
+    if (inLength < 2)
+    {
+        return 0;
+    }
+    const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '=');
+    const size_t full_length = (inLength * 3) >> 2; // div by 4
+    if (full_length < equals)
+    {
+        return 0;
+    }
+    return full_length - equals;
+}
+
+size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength)
+{
+    if (maxOutLength == 0 || inLength < 2) {
         return 0;
     }
+    const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '=');
+    size_t dst_offset = 0;
+    int val = 0, valb = -8;
+    for (size_t src_offset = 0; src_offset < realLength; ++src_offset)
+    {
+        const uint8_t table_value = Util::DecodeBase64(in[src_offset]);
+        if (table_value == 255)
+        {
+            return 0;
+        }
+        val = (val << 6) + table_value;
+        valb += 6;
+        if (valb >= 0)
+        {
+            out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF);
+            valb -= 8;
+            val &= 0xFFF;
+        }
+    }
+    return dst_offset;
+}
 
-    const size_t outLength = (inLength * 3) / 4;
-    out = new uint8_t[outLength];
-    memset(out, 0, outLength);
+static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+char EncodeBase64(char byte)
+{
+    return to_base64_string[(size_t)byte];
+}
 
-    size_t i = 0;
-    size_t j = 0;
-    for (i = 0; i < inLength - 4; i += 4)
+/** Encodes a block of 4 bytes to base64 encoding
+*
+*  @param bytes Bytes to encode.
+*  @param out_string String to write encoded values to.
+*  @param string_pos Position in out_string.*/
+void EncodeByteBlock(const char* bytes, std::string& out_string, size_t string_pos)
+{
+    char b0 = (bytes[0] & 0xFC) >> 2;
+    char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4);
+    char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6);
+    char b3 = (bytes[2] & 0x3F);
+
+    out_string[string_pos + 0] = EncodeBase64(b0);
+    out_string[string_pos + 1] = EncodeBase64(b1);
+    out_string[string_pos + 2] = EncodeBase64(b2);
+    out_string[string_pos + 3] = EncodeBase64(b3);
+}
+
+std::string EncodeBase64(const char* data, size_t length)
+{
+    // calculate extra bytes needed to get a multiple of 3
+    size_t extraBytes = 3 - length % 3;
+
+    // number of base64 bytes
+    size_t encodedBytes = 4 * (length + extraBytes) / 3;
+
+    std::string encoded_string(encodedBytes, '=');
+
+    // read blocks of 3 bytes
+    for (size_t ib3 = 0; ib3 < length / 3; ib3++)
     {
-        uint8_t b0 = Util::DecodeBase64(in[i]);
-        uint8_t b1 = Util::DecodeBase64(in[i + 1]);
-        uint8_t b2 = Util::DecodeBase64(in[i + 2]);
-        uint8_t b3 = Util::DecodeBase64(in[i + 3]);
-
-        out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4));
-        out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2));
-        out[j++] = (uint8_t)((b2 << 6) | b3);
+        const size_t iByte = ib3 * 3;
+        const size_t iEncodedByte = ib3 * 4;
+        const char* currData = &data[iByte];
+
+        EncodeByteBlock(currData, encoded_string, iEncodedByte);
+    }
+
+    // if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed)
+    if (extraBytes > 0)
+    {
+        char finalBytes[4] = { 0,0,0,0 };
+        memcpy(&finalBytes[0], &data[length - length % 3], length % 3);
+
+        const size_t iEncodedByte = encodedBytes - 4;
+        EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte);
+
+        // add '=' at the end
+        for (size_t i = 0; i < 4 * extraBytes / 3; i++)
+            encoded_string[encodedBytes - i - 1] = '=';
     }
-    return outLength;
+    return encoded_string;
 }
 
 } // !Util

+ 20 - 3
thirdparty/assimp/code/FBXUtil.h → thirdparty/assimp/code/FBX/FBXUtil.h

@@ -78,7 +78,7 @@ const char* TokenTypeString(TokenType t);
  *  @param line Line index, 1-based
  *  @param column Column index, 1-based
  *  @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/
-std::string AddOffset(const std::string& prefix, const std::string& text, unsigned int offset);
+std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset);
 
 
 /** Format log/error messages using a given line location in the source file.
@@ -105,13 +105,30 @@ std::string AddTokenText(const std::string& prefix, const std::string& text, con
 *  @return decoded byte value*/
 uint8_t DecodeBase64(char ch);
 
+/** Compute decoded size of a Base64-encoded string
+*
+*  @param in Characters to decode.
+*  @param inLength Number of characters to decode.
+*  @return size of the decoded data (number of bytes)*/
+size_t ComputeDecodedSizeBase64(const char* in, size_t inLength);
+
 /** Decode a Base64-encoded string
 *
 *  @param in Characters to decode.
 *  @param inLength Number of characters to decode.
-*  @param out Reference to pointer where we will store the decoded data.
+*  @param out Pointer where we will store the decoded data.
+*  @param maxOutLength Size of output buffer.
 *  @return size of the decoded data (number of bytes)*/
-size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
+size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength);
+
+char EncodeBase64(char byte);
+
+/** Encode bytes in base64-encoding
+*
+*  @param data Binary data to encode.
+*  @param inLength Number of bytes to encode.
+*  @return base64-encoded string*/
+std::string EncodeBase64(const char* data, size_t length);
 
 }
 }

+ 0 - 1834
thirdparty/assimp/code/FIReader.cpp

@@ -1,1834 +0,0 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2019, assimp team
-
-
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms,
-with or without modification, are permitted provided that the
-following conditions are met:
-
-* Redistributions of source code must retain the above
-copyright notice, this list of conditions and the
-following disclaimer.
-
-* Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the
-following disclaimer in the documentation and/or other
-materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
-contributors may be used to endorse or promote products
-derived from this software without specific prior
-written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-/// \file   FIReader.cpp
-/// \brief  Reader for Fast Infoset encoded binary XML files.
-/// \date   2017
-/// \author Patrick Daehne
-
-#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER
-
-#include "FIReader.hpp"
-#include <assimp/StringUtils.h>
-
-// Workaround for issue #1361
-// https://github.com/assimp/assimp/issues/1361
-#ifdef __ANDROID__
-#  define _GLIBCXX_USE_C99 1
-#endif
-
-#include <assimp/Exceptional.h>
-#include <assimp/IOStream.hpp>
-#include <assimp/types.h>
-#include <assimp/MemoryIOWrapper.h>
-#include <assimp/irrXMLWrapper.h>
-#include "../contrib/utf8cpp/source/utf8.h"
-#include <assimp/fast_atof.h>
-#include <stack>
-#include <map>
-#include <iostream>
-#include <sstream>
-#include <iomanip>
-
-namespace Assimp {
-
-static const std::string parseErrorMessage = "Fast Infoset parse error";
-
-static const char *xmlDeclarations[] = {
-    "<?xml encoding='finf'?>",
-    "<?xml encoding='finf' standalone='yes'?>",
-    "<?xml encoding='finf' standalone='no'?>",
-    "<?xml version='1.0' encoding='finf'?>",
-    "<?xml version='1.0' encoding='finf' standalone='yes'?>",
-    "<?xml version='1.0' encoding='finf' standalone='no'?>",
-    "<?xml version='1.1' encoding='finf'?>",
-    "<?xml version='1.1' encoding='finf' standalone='yes'?>",
-    "<?xml version='1.1' encoding='finf' standalone='no'?>"
-};
-
-static size_t parseMagic(const uint8_t *data, const uint8_t *dataEnd) {
-    if (dataEnd - data < 4) {
-        return 0;
-    }
-    uint32_t magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
-    switch (magic) {
-    case 0xe0000001:
-        return 4;
-    case 0x3c3f786d: // "<?xm"
-        {
-            size_t xmlDeclarationsLength = sizeof(xmlDeclarations) / sizeof(xmlDeclarations[0]);
-            for (size_t i = 0; i < xmlDeclarationsLength; ++i) {
-                auto xmlDeclaration = xmlDeclarations[i];
-                ptrdiff_t xmlDeclarationLength = strlen(xmlDeclaration);
-                if ((dataEnd - data >= xmlDeclarationLength) && (memcmp(xmlDeclaration, data, xmlDeclarationLength) == 0)) {
-                    data += xmlDeclarationLength;
-                    if (dataEnd - data < 4) {
-                        return 0;
-                    }
-                    magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
-                    return magic == 0xe0000001 ? xmlDeclarationLength + 4 : 0;
-                }
-            }
-            return 0;
-        }
-    default:
-        return 0;
-    }
-}
-
-static std::string parseUTF8String(const uint8_t *data, size_t len) {
-    return std::string((char*)data, len);
-}
-
-static std::string parseUTF16String(const uint8_t *data, size_t len) {
-    if (len & 1) {
-        throw DeadlyImportError(parseErrorMessage);
-    }
-    size_t numShorts = len / 2;
-    std::vector<short> utf16;
-    utf16.reserve(numShorts);
-    for (size_t i = 0; i < numShorts; ++i) {
-        short v = (data[0] << 8) | data[1];
-        utf16.push_back(v);
-        data += 2;
-    }
-    std::string result;
-    utf8::utf16to8(utf16.begin(), utf16.end(), back_inserter(result));
-    return result;
-}
-
-struct FIStringValueImpl: public FIStringValue {
-    inline FIStringValueImpl(std::string &&value_) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ { return value; }
-};
-
-std::shared_ptr<FIStringValue> FIStringValue::create(std::string &&value) {
-    return std::make_shared<FIStringValueImpl>(std::move(value));
-}
-
-struct FIHexValueImpl: public FIHexValue {
-    mutable std::string strValue;
-    mutable bool strValueValid;
-    inline FIHexValueImpl(std::vector<uint8_t> &&value_):  strValueValid(false) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ {
-        if (!strValueValid) {
-            strValueValid = true;
-            std::ostringstream os;
-            os << std::hex << std::uppercase << std::setfill('0');
-            std::for_each(value.begin(), value.end(), [&](uint8_t c) { os << std::setw(2) << static_cast<int>(c); });
-            strValue = os.str();
-        }
-        return strValue;
-    };
-};
-
-std::shared_ptr<FIHexValue> FIHexValue::create(std::vector<uint8_t> &&value) {
-    return std::make_shared<FIHexValueImpl>(std::move(value));
-}
-
-struct FIBase64ValueImpl: public FIBase64Value {
-    mutable std::string strValue;
-    mutable bool strValueValid;
-    inline FIBase64ValueImpl(std::vector<uint8_t> &&value_): strValueValid(false) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ {
-        if (!strValueValid) {
-            strValueValid = true;
-            std::ostringstream os;
-            uint8_t c1 = 0, c2;
-            int imod3 = 0;
-            std::vector<uint8_t>::size_type valueSize = value.size();
-            for (std::vector<uint8_t>::size_type i = 0; i < valueSize; ++i) {
-                c2 = value[i];
-                switch (imod3) {
-                case 0:
-                    os << basis_64[c2 >> 2];
-                    imod3 = 1;
-                    break;
-                case 1:
-                    os << basis_64[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)];
-                    imod3 = 2;
-                    break;
-                case 2:
-                    os << basis_64[((c1 & 0x0f) << 2) | ((c2 & 0xc0) >> 6)] << basis_64[c2 & 0x3f];
-                    imod3 = 0;
-                    break;
-                }
-                c1 = c2;
-            }
-            switch (imod3) {
-            case 1:
-                os << basis_64[(c1 & 0x03) << 4] << "==";
-                break;
-            case 2:
-                os << basis_64[(c1 & 0x0f) << 2] << '=';
-                break;
-            }
-            strValue = os.str();
-        }
-        return strValue;
-    };
-    static const char basis_64[];
-};
-
-const char FIBase64ValueImpl::basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-std::shared_ptr<FIBase64Value> FIBase64Value::create(std::vector<uint8_t> &&value) {
-    return std::make_shared<FIBase64ValueImpl>(std::move(value));
-}
-
-struct FIShortValueImpl: public FIShortValue {
-    mutable std::string strValue;
-    mutable bool strValueValid;
-    inline FIShortValueImpl(std::vector<int16_t> &&value_): strValueValid(false) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ {
-        if (!strValueValid) {
-            strValueValid = true;
-            std::ostringstream os;
-            int n = 0;
-            std::for_each(value.begin(), value.end(), [&](int16_t s) { if (++n > 1) os << ' '; os << s; });
-            strValue = os.str();
-        }
-        return strValue;
-    }
-};
-
-std::shared_ptr<FIShortValue> FIShortValue::create(std::vector<int16_t> &&value) {
-    return std::make_shared<FIShortValueImpl>(std::move(value));
-}
-
-struct FIIntValueImpl: public FIIntValue {
-    mutable std::string strValue;
-    mutable bool strValueValid;
-    inline FIIntValueImpl(std::vector<int32_t> &&value_): strValueValid(false) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ {
-        if (!strValueValid) {
-            strValueValid = true;
-            std::ostringstream os;
-            int n = 0;
-            std::for_each(value.begin(), value.end(), [&](int32_t i) { if (++n > 1) os << ' '; os << i; });
-            strValue = os.str();
-        }
-        return strValue;
-    };
-};
-
-std::shared_ptr<FIIntValue> FIIntValue::create(std::vector<int32_t> &&value) {
-    return std::make_shared<FIIntValueImpl>(std::move(value));
-}
-
-struct FILongValueImpl: public FILongValue {
-    mutable std::string strValue;
-    mutable bool strValueValid;
-    inline FILongValueImpl(std::vector<int64_t> &&value_): strValueValid(false) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ {
-        if (!strValueValid) {
-            strValueValid = true;
-            std::ostringstream os;
-            int n = 0;
-            std::for_each(value.begin(), value.end(), [&](int64_t l) { if (++n > 1) os << ' '; os << l; });
-            strValue = os.str();
-        }
-        return strValue;
-    };
-};
-
-std::shared_ptr<FILongValue> FILongValue::create(std::vector<int64_t> &&value) {
-    return std::make_shared<FILongValueImpl>(std::move(value));
-}
-
-struct FIBoolValueImpl: public FIBoolValue {
-    mutable std::string strValue;
-    mutable bool strValueValid;
-    inline FIBoolValueImpl(std::vector<bool> &&value_): strValueValid(false) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ {
-        if (!strValueValid) {
-            strValueValid = true;
-            std::ostringstream os;
-            os << std::boolalpha;
-            int n = 0;
-            std::for_each(value.begin(), value.end(), [&](bool b) { if (++n > 1) os << ' '; os << b; });
-            strValue = os.str();
-        }
-        return strValue;
-    };
-};
-
-std::shared_ptr<FIBoolValue> FIBoolValue::create(std::vector<bool> &&value) {
-    return std::make_shared<FIBoolValueImpl>(std::move(value));
-}
-
-struct FIFloatValueImpl: public FIFloatValue {
-    mutable std::string strValue;
-    mutable bool strValueValid;
-    inline FIFloatValueImpl(std::vector<float> &&value_): strValueValid(false) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ {
-        if (!strValueValid) {
-            strValueValid = true;
-            std::ostringstream os;
-            int n = 0;
-            std::for_each(value.begin(), value.end(), [&](float f) { if (++n > 1) os << ' '; os << f; });
-            strValue = os.str();
-        }
-        return strValue;
-    }
-};
-
-std::shared_ptr<FIFloatValue> FIFloatValue::create(std::vector<float> &&value) {
-    return std::make_shared<FIFloatValueImpl>(std::move(value));
-}
-
-struct FIDoubleValueImpl: public FIDoubleValue {
-    mutable std::string strValue;
-    mutable bool strValueValid;
-    inline FIDoubleValueImpl(std::vector<double> &&value_): strValueValid(false) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ {
-        if (!strValueValid) {
-            strValueValid = true;
-            std::ostringstream os;
-            int n = 0;
-            std::for_each(value.begin(), value.end(), [&](double d) { if (++n > 1) os << ' '; os << d; });
-            strValue = os.str();
-        }
-        return strValue;
-    }
-};
-
-std::shared_ptr<FIDoubleValue> FIDoubleValue::create(std::vector<double> &&value) {
-    return std::make_shared<FIDoubleValueImpl>(std::move(value));
-}
-
-struct FIUUIDValueImpl: public FIUUIDValue {
-    mutable std::string strValue;
-    mutable bool strValueValid;
-    inline FIUUIDValueImpl(std::vector<uint8_t> &&value_): strValueValid(false) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ {
-        if (!strValueValid) {
-            strValueValid = true;
-            std::ostringstream os;
-            os << std::hex << std::uppercase << std::setfill('0');
-            std::vector<uint8_t>::size_type valueSize = value.size();
-            for (std::vector<uint8_t>::size_type i = 0; i < valueSize; ++i) {
-                switch (i & 15) {
-                case 0:
-                    if (i > 0) {
-                        os << ' ';
-                    }
-                    os << std::setw(2) << static_cast<int>(value[i]);
-                    break;
-                case 4:
-                case 6:
-                case 8:
-                case 10:
-                    os << '-';
-                    // intentionally fall through!
-                case 1:
-                case 2:
-                case 3:
-                case 5:
-                case 7:
-                case 9:
-                case 11:
-                case 12:
-                case 13:
-                case 14:
-                case 15:
-                    os << std::setw(2) << static_cast<int>(value[i]);
-                    break;
-                }
-            }
-            strValue = os.str();
-        }
-        return strValue;
-    };
-};
-
-std::shared_ptr<FIUUIDValue> FIUUIDValue::create(std::vector<uint8_t> &&value) {
-    return std::make_shared<FIUUIDValueImpl>(std::move(value));
-}
-
-struct FICDATAValueImpl: public FICDATAValue {
-    inline FICDATAValueImpl(std::string &&value_) { value = std::move(value_); }
-    virtual const std::string &toString() const /*override*/ { return value; }
-};
-
-std::shared_ptr<FICDATAValue> FICDATAValue::create(std::string &&value) {
-    return std::make_shared<FICDATAValueImpl>(std::move(value));
-}
-
-struct FIHexDecoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        return FIHexValue::create(std::vector<uint8_t>(data, data + len));
-    }
-};
-
-struct FIBase64Decoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        return FIBase64Value::create(std::vector<uint8_t>(data, data + len));
-    }
-};
-
-struct FIShortDecoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        if (len & 1) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        std::vector<int16_t> value;
-        size_t numShorts = len / 2;
-        value.reserve(numShorts);
-        for (size_t i = 0; i < numShorts; ++i) {
-            int16_t v = (data[0] << 8) | data[1];
-            value.push_back(v);
-            data += 2;
-        }
-        return FIShortValue::create(std::move(value));
-    }
-};
-
-struct FIIntDecoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        if (len & 3) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        std::vector<int32_t> value;
-        size_t numInts = len / 4;
-        value.reserve(numInts);
-        for (size_t i = 0; i < numInts; ++i) {
-            int32_t v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
-            value.push_back(v);
-            data += 4;
-        }
-        return FIIntValue::create(std::move(value));
-    }
-};
-
-struct FILongDecoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        if (len & 7) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        std::vector<int64_t> value;
-        size_t numLongs = len / 8;
-        value.reserve(numLongs);
-        for (size_t i = 0; i < numLongs; ++i) {
-            int64_t b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7];
-            int64_t v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
-            value.push_back(v);
-            data += 8;
-        }
-        return FILongValue::create(std::move(value));
-    }
-};
-
-struct FIBoolDecoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        if (len < 1) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        std::vector<bool> value;
-        uint8_t b = *data++;
-        size_t unusedBits = b >> 4;
-        size_t numBools = (len * 8) - 4 - unusedBits;
-        value.reserve(numBools);
-        uint8_t mask = 1 << 3;
-        for (size_t i = 0; i < numBools; ++i) {
-            if (!mask) {
-                mask = 1 << 7;
-                b = *data++;
-            }
-            value.push_back((b & mask) != 0);
-        }
-        return FIBoolValue::create(std::move(value));
-    }
-};
-
-struct FIFloatDecoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        if (len & 3) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        std::vector<float> value;
-        size_t numFloats = len / 4;
-        value.reserve(numFloats);
-        for (size_t i = 0; i < numFloats; ++i) {
-            int v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
-            float f;
-            memcpy(&f, &v, 4);
-            value.push_back(f);
-            data += 4;
-        }
-        return FIFloatValue::create(std::move(value));
-    }
-};
-
-struct FIDoubleDecoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        if (len & 7) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        std::vector<double> value;
-        size_t numDoubles = len / 8;
-        value.reserve(numDoubles);
-        for (size_t i = 0; i < numDoubles; ++i) {
-            long long b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7];
-            long long v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
-            double f;
-            memcpy(&f, &v, 8);
-            value.push_back(f);
-            data += 8;
-        }
-        return FIDoubleValue::create(std::move(value));
-    }
-};
-
-struct FIUUIDDecoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        if (len & 15) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        return FIUUIDValue::create(std::vector<uint8_t>(data, data + len));
-    }
-};
-
-struct FICDATADecoder: public FIDecoder {
-    virtual std::shared_ptr<const FIValue> decode(const uint8_t *data, size_t len) /*override*/ {
-        return FICDATAValue::create(parseUTF8String(data, len));
-    }
-};
-
-class CFIReaderImpl: public FIReader {
-public:
-
-    CFIReaderImpl(std::unique_ptr<uint8_t[]> data_, size_t size):
-    data(std::move(data_)), dataP(data.get()), dataEnd(data.get() + size), currentNodeType(irr::io::EXN_NONE),
-    emptyElement(false), headerPending(true), terminatorPending(false)
-    {}
-
-    virtual ~CFIReaderImpl() {}
-
-    virtual bool read() /*override*/ {
-        if (headerPending) {
-            headerPending = false;
-            parseHeader();
-        }
-        if (terminatorPending) {
-            terminatorPending = false;
-            if (elementStack.empty()) {
-                return false;
-            }
-            else {
-                nodeName = elementStack.top();
-                elementStack.pop();
-                currentNodeType = nodeName.empty() ? irr::io::EXN_UNKNOWN : irr::io::EXN_ELEMENT_END;
-                return true;
-            }
-        }
-        if (dataP >= dataEnd) {
-            return false;
-        }
-        uint8_t b = *dataP;
-        if (b < 0x80) { // Element (C.2.11.2, C.3.7.2)
-            // C.3
-            parseElement();
-            return true;
-        }
-        else if (b < 0xc0) { // Characters (C.3.7.5)
-            // C.7
-            auto chars = parseNonIdentifyingStringOrIndex3(vocabulary.charactersTable);
-            nodeName = chars->toString();
-            currentNodeType = irr::io::EXN_TEXT;
-            return true;
-        }
-        else if (b < 0xe0) {
-            if ((b & 0xfc) == 0xc4) { // DTD (C.2.11.5)
-                // C.9
-                ++dataP;
-                if (b & 0x02) {
-                    /*const std::string &systemID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
-                }
-                if (b & 0x01) {
-                    /*const std::string &publicID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
-                }
-                elementStack.push(EmptyString);
-                currentNodeType = irr::io::EXN_UNKNOWN;
-                return true;
-            }
-            else if ((b & 0xfc) == 0xc8) { // Unexpanded entity reference (C.3.7.4)
-                // C.6
-                ++dataP;
-                /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
-                if (b & 0x02) {
-                    /*const std::string &systemID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
-                }
-                if (b & 0x01) {
-                    /*const std::string &publicID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
-                }
-                currentNodeType = irr::io::EXN_UNKNOWN;
-                return true;
-            }
-        }
-        else if (b < 0xf0) {
-            if (b == 0xe1) { // Processing instruction (C.2.11.3, C.3.7.3)
-                // C.5
-                ++dataP;
-                /*const std::string &target =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
-                if (dataEnd - dataP < 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                /*std::shared_ptr<const FIValue> data =*/ parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable);
-                currentNodeType = irr::io::EXN_UNKNOWN;
-                return true;
-            }
-            else if (b == 0xe2) { // Comment (C.2.11.4, C.3.7.6)
-                // C.8
-                ++dataP;
-                if (dataEnd - dataP < 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                std::shared_ptr<const FIValue> comment = parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable);
-                nodeName = comment->toString();
-                currentNodeType = irr::io::EXN_COMMENT;
-                return true;
-            }
-        }
-        else { // Terminator (C.2.12, C.3.8)
-            ++dataP;
-            if (b == 0xff) {
-                terminatorPending = true;
-            }
-            if (elementStack.empty()) {
-                return false;
-            }
-            else {
-                nodeName = elementStack.top();
-                elementStack.pop();
-                currentNodeType = nodeName.empty() ? irr::io::EXN_UNKNOWN : irr::io::EXN_ELEMENT_END;
-                return true;
-            }
-        }
-        throw DeadlyImportError(parseErrorMessage);
-    }
-
-    virtual irr::io::EXML_NODE getNodeType() const /*override*/ {
-        return currentNodeType;
-    }
-
-    virtual int getAttributeCount() const /*override*/ {
-        return static_cast<int>(attributes.size());
-    }
-
-    virtual const char* getAttributeName(int idx) const /*override*/ {
-        if (idx < 0 || idx >= (int)attributes.size()) {
-            return nullptr;
-        }
-        return attributes[idx].name.c_str();
-    }
-
-    virtual const char* getAttributeValue(int idx) const /*override*/ {
-        if (idx < 0 || idx >= (int)attributes.size()) {
-            return nullptr;
-        }
-        return attributes[idx].value->toString().c_str();
-    }
-
-    virtual const char* getAttributeValue(const char* name) const /*override*/ {
-        const Attribute* attr = getAttributeByName(name);
-        if (!attr) {
-            return nullptr;
-        }
-        return attr->value->toString().c_str();
-    }
-
-    virtual const char* getAttributeValueSafe(const char* name) const /*override*/ {
-        const Attribute* attr = getAttributeByName(name);
-        if (!attr) {
-            return EmptyString.c_str();
-        }
-        return attr->value->toString().c_str();
-    }
-
-    virtual int getAttributeValueAsInt(const char* name) const /*override*/ {
-        const Attribute* attr = getAttributeByName(name);
-        if (!attr) {
-            return 0;
-        }
-        std::shared_ptr<const FIIntValue> intValue = std::dynamic_pointer_cast<const FIIntValue>(attr->value);
-        if (intValue) {
-            return intValue->value.size() == 1 ? intValue->value.front() : 0;
-        }
-        return atoi(attr->value->toString().c_str());
-    }
-
-    virtual int getAttributeValueAsInt(int idx) const /*override*/ {
-        if (idx < 0 || idx >= (int)attributes.size()) {
-            return 0;
-        }
-        std::shared_ptr<const FIIntValue> intValue = std::dynamic_pointer_cast<const FIIntValue>(attributes[idx].value);
-        if (intValue) {
-            return intValue->value.size() == 1 ? intValue->value.front() : 0;
-        }
-        return atoi(attributes[idx].value->toString().c_str());
-    }
-
-    virtual float getAttributeValueAsFloat(const char* name) const /*override*/ {
-        const Attribute* attr = getAttributeByName(name);
-        if (!attr) {
-            return 0;
-        }
-        std::shared_ptr<const FIFloatValue> floatValue = std::dynamic_pointer_cast<const FIFloatValue>(attr->value);
-        if (floatValue) {
-            return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
-        }
-
-        return fast_atof(attr->value->toString().c_str());
-    }
-
-    virtual float getAttributeValueAsFloat(int idx) const /*override*/ {
-        if (idx < 0 || idx >= (int)attributes.size()) {
-            return 0;
-        }
-        std::shared_ptr<const FIFloatValue> floatValue = std::dynamic_pointer_cast<const FIFloatValue>(attributes[idx].value);
-        if (floatValue) {
-            return floatValue->value.size() == 1 ? floatValue->value.front() : 0;
-        }
-        return fast_atof(attributes[idx].value->toString().c_str());
-    }
-
-    virtual const char* getNodeName() const /*override*/ {
-        return nodeName.c_str();
-    }
-
-    virtual const char* getNodeData() const /*override*/ {
-        return nodeName.c_str();
-    }
-
-    virtual bool isEmptyElement() const /*override*/ {
-        return emptyElement;
-    }
-
-    virtual irr::io::ETEXT_FORMAT getSourceFormat() const /*override*/ {
-        return irr::io::ETF_UTF8;
-    }
-
-    virtual irr::io::ETEXT_FORMAT getParserFormat() const /*override*/ {
-        return irr::io::ETF_UTF8;
-    }
-
-    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int idx) const /*override*/ {
-        if (idx < 0 || idx >= (int)attributes.size()) {
-            return nullptr;
-        }
-        return attributes[idx].value;
-    }
-
-    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char* name) const /*override*/ {
-        const Attribute* attr = getAttributeByName(name);
-        if (!attr) {
-            return nullptr;
-        }
-        return attr->value;
-    }
-
-    virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr<FIDecoder> decoder) /*override*/ {
-        decoderMap[algorithmUri] = std::move(decoder);
-    }
-
-    virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) /*override*/ {
-        vocabularyMap[vocabularyUri] = vocabulary;
-    }
-
-private:
-
-    struct QName {
-        std::string prefix;
-        std::string uri;
-        std::string name;
-        inline QName() {}
-        inline QName(const FIQName &qname): prefix(qname.prefix ? qname.prefix : ""), uri(qname.uri ? qname.uri : ""), name(qname.name) {}
-    };
-
-    struct Attribute {
-        QName qname;
-        std::string name;
-        std::shared_ptr<const FIValue> value;
-    };
-
-    struct Vocabulary {
-        std::vector<std::string> restrictedAlphabetTable;
-        std::vector<std::string> encodingAlgorithmTable;
-        std::vector<std::string> prefixTable;
-        std::vector<std::string> namespaceNameTable;
-        std::vector<std::string> localNameTable;
-        std::vector<std::string> otherNCNameTable;
-        std::vector<std::string> otherURITable;
-        std::vector<std::shared_ptr<const FIValue>> attributeValueTable;
-        std::vector<std::shared_ptr<const FIValue>> charactersTable;
-        std::vector<std::shared_ptr<const FIValue>> otherStringTable;
-        std::vector<QName> elementNameTable;
-        std::vector<QName> attributeNameTable;
-        Vocabulary() {
-            prefixTable.push_back("xml");
-            namespaceNameTable.push_back("http://www.w3.org/XML/1998/namespace");
-        }
-    };
-
-    const Attribute* getAttributeByName(const char* name) const {
-        if (!name) {
-            return 0;
-        }
-        std::string n = name;
-        for (int i=0; i<(int)attributes.size(); ++i) {
-            if (attributes[i].name == n) {
-                return &attributes[i];
-            }
-        }
-        return 0;
-    }
-
-    size_t parseInt2() { // C.25
-        uint8_t b = *dataP++;
-        if (!(b & 0x40)) { // x0...... (C.25.2)
-            return b & 0x3f;
-        }
-        else if ((b & 0x60) == 0x40) { // x10..... ........ (C.25.3)
-            if (dataEnd - dataP > 0) {
-                return (((b & 0x1f) << 8) | *dataP++) + 0x40;
-            }
-        }
-        else if ((b & 0x70) == 0x60) { // x110.... ........ ........ (C.25.4)
-            if (dataEnd - dataP > 1) {
-                size_t result = (((b & 0x0f) << 16) | (dataP[0] << 8) | dataP[1]) + 0x2040;
-                dataP += 2;
-                return result;
-            }
-        }
-        throw DeadlyImportError(parseErrorMessage);
-    }
-
-    size_t parseInt3() { // C.27
-        uint8_t b = *dataP++;
-        if (!(b & 0x20)) { // xx0..... (C.27.2)
-            return b & 0x1f;
-        }
-        else if ((b & 0x38) == 0x20) { // xx100... ........ (C.27.3)
-            if (dataEnd - dataP > 0) {
-                return (((b & 0x07) << 8) | *dataP++) + 0x20;
-            }
-        }
-        else if ((b & 0x38) == 0x28) { // xx101... ........ ........ (C.27.4)
-            if (dataEnd - dataP > 1) {
-                size_t result = (((b & 0x07) << 16) | (dataP[0] << 8) | dataP[1]) + 0x820;
-                dataP += 2;
-                return result;
-            }
-        }
-        else if ((b & 0x3f) == 0x30) { // xx110000 0000.... ........ ........ (C.27.5)
-            if ((dataEnd - dataP > 2) && !(dataP[0] & 0xf0)) {
-                size_t result = (((dataP[0] & 0x0f) << 16) | (dataP[1] << 8) | dataP[2]) + 0x80820;
-                dataP += 3;
-                return result;
-            }
-        }
-        throw DeadlyImportError(parseErrorMessage);
-    }
-
-    size_t parseInt4() { // C.28
-        uint8_t b = *dataP++;
-        if (!(b & 0x10)) { // xxx0.... (C.28.2)
-            return b & 0x0f;
-        }
-        else if ((b & 0x1c) == 0x10) { // xxx100.. ........ (C.28.3)
-            if (dataEnd - dataP > 0) {
-                return (((b & 0x03) << 8) | *dataP++) + 0x10;
-            }
-        }
-        else if ((b & 0x1c) == 0x14) { // xxx101.. ........ ........ (C.28.4)
-            if (dataEnd - dataP > 1) {
-                size_t result = (((b & 0x03) << 16) | (dataP[0] << 8) | dataP[1]) + 0x410;
-                dataP += 2;
-                return result;
-            }
-        }
-        else if ((b & 0x1f) == 0x18) { // xxx11000 0000.... ........ ........ (C.28.5)
-            if ((dataEnd - dataP > 2) && !(dataP[0] & 0xf0)) {
-                size_t result = (((dataP[0] & 0x0f) << 16) | (dataP[1] << 8) | dataP[2]) + 0x40410;
-                dataP += 3;
-                return result;
-            }
-        }
-        throw DeadlyImportError(parseErrorMessage);
-    }
-
-    size_t parseSequenceLen() { // C.21
-        if (dataEnd - dataP > 0) {
-            uint8_t b = *dataP++;
-            if (b < 0x80) { // 0....... (C.21.2)
-                return b;
-            }
-            else if ((b & 0xf0) == 0x80) { // 1000.... ........ ........ (C.21.3)
-                if (dataEnd - dataP > 1) {
-                    size_t result = (((b & 0x0f) << 16) | (dataP[0] << 8) | dataP[1]) + 0x80;
-                    dataP += 2;
-                    return result;
-                }
-            }
-        }
-        throw DeadlyImportError(parseErrorMessage);
-    }
-
-    std::string parseNonEmptyOctetString2() { // C.22
-        // Parse the length of the string
-        uint8_t b = *dataP++ & 0x7f;
-        size_t len;
-        if (!(b & 0x40)) { // x0...... (C.22.3.1)
-            len = b + 1;
-        }
-        else if (b == 0x40) { // x1000000 ........ (C.22.3.2)
-            if (dataEnd - dataP < 1) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            len = *dataP++ + 0x41;
-        }
-        else if (b == 0x60) { // x1100000 ........ ........ ........ ........ (C.22.3.3)
-            if (dataEnd - dataP < 4) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            len = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x141;
-            dataP += 4;
-        }
-        else {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-
-        // Parse the string (C.22.4)
-        if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        std::string s = parseUTF8String(dataP, len);
-        dataP += len;
-
-        return s;
-    }
-
-    size_t parseNonEmptyOctetString5Length() { // C.23
-        // Parse the length of the string
-        size_t b = *dataP++ & 0x0f;
-        if (!(b & 0x08)) { // xxxx0... (C.23.3.1)
-            return b + 1;
-        }
-        else if (b == 0x08) { // xxxx1000 ........ (C.23.3.2)
-            if (dataEnd - dataP > 0) {
-                return *dataP++ + 0x09;
-            }
-        }
-        else if (b == 0x0c) { // xxxx1100 ........ ........ ........ ........ (C.23.3.3)
-            if (dataEnd - dataP > 3) {
-                size_t result = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x109;
-                dataP += 4;
-                return result;
-            }
-        }
-        throw DeadlyImportError(parseErrorMessage);
-    }
-
-    size_t parseNonEmptyOctetString7Length() { // C.24
-        // Parse the length of the string
-        size_t b = *dataP++ & 0x03;
-        if (!(b & 0x02)) { // xxxxxx0. (C.24.3.1)
-            return b + 1;
-        }
-        else if (b == 0x02) { // xxxxxx10 ........ (C.24.3.2)
-            if (dataEnd - dataP > 0) {
-                return *dataP++ + 0x3;
-            }
-        }
-        else if (b == 0x03) { // xxxxxx11 ........ ........ ........ ........ (C.24.3.3)
-            if (dataEnd - dataP > 3) {
-                size_t result = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x103;
-                dataP += 4;
-                return result;
-            }
-        }
-        throw DeadlyImportError(parseErrorMessage);
-    }
-
-    std::shared_ptr<const FIValue> parseEncodedData(size_t index, size_t len) {
-        if (index < 32) {
-            FIDecoder *decoder = defaultDecoder[index];
-            if (!decoder) {
-                throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index));
-            }
-            return decoder->decode(dataP, len);
-        }
-        else {
-            if (index - 32 >= vocabulary.encodingAlgorithmTable.size()) {
-                throw DeadlyImportError("Invalid encoding algorithm index " + to_string(index));
-            }
-            std::string uri = vocabulary.encodingAlgorithmTable[index - 32];
-            auto it = decoderMap.find(uri);
-            if (it == decoderMap.end()) {
-                throw DeadlyImportError("Unsupported encoding algorithm " + uri);
-            }
-            else {
-                return it->second->decode(dataP, len);
-            }
-        }
-    }
-
-    std::shared_ptr<const FIValue> parseRestrictedAlphabet(size_t index, size_t len) {
-        std::string alphabet;
-        if (index < 16) {
-            switch (index) {
-            case 0: // numeric
-                alphabet = "0123456789-+.e ";
-                break;
-            case 1: // date and time
-                alphabet = "0123456789-:TZ ";
-                break;
-            default:
-                throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index));
-            }
-        }
-        else {
-            if (index - 16 >= vocabulary.restrictedAlphabetTable.size()) {
-                throw DeadlyImportError("Invalid restricted alphabet index " + to_string(index));
-            }
-            alphabet = vocabulary.restrictedAlphabetTable[index - 16];
-        }
-        std::vector<uint32_t> alphabetUTF32;
-        utf8::utf8to32(alphabet.begin(), alphabet.end(), back_inserter(alphabetUTF32));
-        std::string::size_type alphabetLength = alphabetUTF32.size();
-        if (alphabetLength < 2) {
-            throw DeadlyImportError("Invalid restricted alphabet length " + to_string(alphabetLength));
-        }
-        std::string::size_type bitsPerCharacter = 1;
-        while ((1ull << bitsPerCharacter) <= alphabetLength) {
-            ++bitsPerCharacter;
-        }
-        size_t bitsAvail = 0;
-        uint8_t mask = (1 << bitsPerCharacter) - 1;
-        uint32_t bits = 0;
-        std::string s;
-        for (size_t i = 0; i < len; ++i) {
-            bits = (bits << 8) | dataP[i];
-            bitsAvail += 8;
-            while (bitsAvail >= bitsPerCharacter) {
-                bitsAvail -= bitsPerCharacter;
-                size_t charIndex = (bits >> bitsAvail) & mask;
-                if (charIndex < alphabetLength) {
-                    s.push_back(alphabetUTF32[charIndex]);
-                }
-                else if (charIndex != mask) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-            }
-        }
-        return FIStringValue::create(std::move(s));
-    }
-
-    std::shared_ptr<const FIValue> parseEncodedCharacterString3() { // C.19
-        std::shared_ptr<const FIValue> result;
-        size_t len;
-        uint8_t b = *dataP;
-        if (b & 0x20) {
-            ++dataP;
-            if (dataEnd - dataP < 1) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            size_t index = ((b & 0x0f) << 4) | ((*dataP & 0xf0) >> 4); // C.29
-            len = parseNonEmptyOctetString5Length();
-            if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            if (b & 0x10) {
-                // encoding algorithm (C.19.3.4)
-                result = parseEncodedData(index, len);
-            }
-            else {
-                // Restricted alphabet (C.19.3.3)
-                result = parseRestrictedAlphabet(index, len);
-            }
-        }
-        else {
-            len = parseNonEmptyOctetString5Length();
-            if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            if (b & 0x10) {
-                // UTF-16 (C.19.3.2)
-                if (len & 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                result = FIStringValue::create(parseUTF16String(dataP, len));
-            }
-            else {
-                // UTF-8 (C.19.3.1)
-                result = FIStringValue::create(parseUTF8String(dataP, len));
-            }
-        }
-        dataP += len;
-        return result;
-    }
-
-    std::shared_ptr<const FIValue> parseEncodedCharacterString5() { // C.20
-        std::shared_ptr<const FIValue> result;
-        size_t len;
-        uint8_t b = *dataP;
-        if (b & 0x08) {
-            ++dataP;
-            if (dataEnd - dataP < 1) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            size_t index = ((b & 0x03) << 6) | ((*dataP & 0xfc) >> 2); /* C.29 */
-            len = parseNonEmptyOctetString7Length();
-            if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            if (b & 0x04) {
-                // encoding algorithm (C.20.3.4)
-                result = parseEncodedData(index, len);
-            }
-            else {
-                // Restricted alphabet (C.20.3.3)
-                result = parseRestrictedAlphabet(index, len);
-            }
-        }
-        else {
-            len = parseNonEmptyOctetString7Length();
-            if (dataEnd - dataP < static_cast<ptrdiff_t>(len)) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            if (b & 0x04) {
-                // UTF-16 (C.20.3.2)
-                if (len & 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                result = FIStringValue::create(parseUTF16String(dataP, len));
-            }
-            else {
-                // UTF-8 (C.20.3.1)
-                result = FIStringValue::create(parseUTF8String(dataP, len));
-            }
-        }
-        dataP += len;
-        return result;
-    }
-
-    const std::string &parseIdentifyingStringOrIndex(std::vector<std::string> &stringTable) { // C.13
-        if (dataEnd - dataP < 1) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        uint8_t b = *dataP;
-        if (b & 0x80) {
-            // We have an index (C.13.4)
-            size_t index = parseInt2();
-            if (index >= stringTable.size()) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            return stringTable[index];
-        }
-        else {
-            // We have a string (C.13.3)
-            stringTable.push_back(parseNonEmptyOctetString2());
-            return stringTable.back();
-        }
-    }
-
-    QName parseNameSurrogate() { // C.16
-        if (dataEnd - dataP < 1) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        uint8_t b = *dataP++;
-        if (b & 0xfc) { // Padding '000000' C.2.5.5
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        QName result;
-        size_t index;
-        if (b & 0x02) { // prefix (C.16.3)
-            if ((dataEnd - dataP < 1) || (*dataP & 0x80)) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            index = parseInt2();
-            if (index >= vocabulary.prefixTable.size()) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            result.prefix = vocabulary.prefixTable[index];
-        }
-        if (b & 0x01) { // namespace-name (C.16.4)
-            if ((dataEnd - dataP < 1) || (*dataP & 0x80)) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            index = parseInt2();
-            if (index >= vocabulary.namespaceNameTable.size()) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            result.uri = vocabulary.namespaceNameTable[index];
-        }
-        // local-name
-        if ((dataEnd - dataP < 1) || (*dataP & 0x80)) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        index = parseInt2();
-        if (index >= vocabulary.localNameTable.size()) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        result.name = vocabulary.localNameTable[index];
-        return result;
-    }
-
-    const QName &parseQualifiedNameOrIndex2(std::vector<QName> &qNameTable) { // C.17
-        uint8_t b = *dataP;
-        if ((b & 0x7c) == 0x78) { // x11110..
-            // We have a literal (C.17.3)
-            ++dataP;
-            QName result;
-            // prefix (C.17.3.1)
-            result.prefix = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string();
-            // namespace-name (C.17.3.1)
-            result.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string();
-            // local-name
-            result.name = parseIdentifyingStringOrIndex(vocabulary.localNameTable);
-            qNameTable.push_back(result);
-            return qNameTable.back();
-        }
-        else {
-            // We have an index (C.17.4)
-            size_t index = parseInt2();
-            if (index >= qNameTable.size()) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            return qNameTable[index];
-        }
-    }
-
-    const QName &parseQualifiedNameOrIndex3(std::vector<QName> &qNameTable) { // C.18
-        uint8_t b = *dataP;
-        if ((b & 0x3c) == 0x3c) { // xx1111..
-            // We have a literal (C.18.3)
-            ++dataP;
-            QName result;
-            // prefix (C.18.3.1)
-            result.prefix = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string();
-            // namespace-name (C.18.3.1)
-            result.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string();
-            // local-name
-            result.name = parseIdentifyingStringOrIndex(vocabulary.localNameTable);
-            qNameTable.push_back(result);
-            return qNameTable.back();
-        }
-        else {
-            // We have an index (C.18.4)
-            size_t index = parseInt3();
-            if (index >= qNameTable.size()) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            return qNameTable[index];
-        }
-    }
-
-    std::shared_ptr<const FIValue> parseNonIdentifyingStringOrIndex1(std::vector<std::shared_ptr<const FIValue>> &valueTable) { // C.14
-        uint8_t b = *dataP;
-        if (b == 0xff) { // C.26.2
-            // empty string
-            ++dataP;
-            return EmptyFIString;
-        }
-        else if (b & 0x80) { // C.14.4
-            // We have an index
-            size_t index = parseInt2();
-            if (index >= valueTable.size()) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            return valueTable[index];
-        }
-        else { // C.14.3
-            // We have a literal
-            std::shared_ptr<const FIValue> result = parseEncodedCharacterString3();
-            if (b & 0x40) { // C.14.3.1
-                valueTable.push_back(result);
-            }
-            return result;
-        }
-    }
-
-    std::shared_ptr<const FIValue> parseNonIdentifyingStringOrIndex3(std::vector<std::shared_ptr<const FIValue>> &valueTable) { // C.15
-        uint8_t b = *dataP;
-        if (b & 0x20) { // C.15.4
-            // We have an index
-            size_t index = parseInt4();
-            if (index >= valueTable.size()) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            return valueTable[index];
-        }
-        else { // C.15.3
-            // We have a literal
-            std::shared_ptr<const FIValue> result = parseEncodedCharacterString5();
-            if (b & 0x10) { // C.15.3.1
-                valueTable.push_back(result);
-            }
-            return result;
-        }
-    }
-
-    void parseElement() {
-        // C.3
-
-        attributes.clear();
-
-        uint8_t b = *dataP;
-        bool hasAttributes = (b & 0x40) != 0; // C.3.3
-        if ((b & 0x3f) == 0x38) { // C.3.4.1
-            // Parse namespaces
-            ++dataP;
-            for (;;) {
-                if (dataEnd - dataP < 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                b = *dataP++;
-                if (b == 0xf0) { // C.3.4.3
-                    break;
-                }
-                if ((b & 0xfc) != 0xcc) { // C.3.4.2
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                // C.12
-                Attribute attr;
-                attr.qname.prefix = "xmlns";
-                attr.qname.name = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string();
-                attr.qname.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string();
-                attr.name = attr.qname.name.empty() ? "xmlns" : "xmlns:" + attr.qname.name;
-                attr.value = FIStringValue::create(std::string(attr.qname.uri));
-                attributes.push_back(attr);
-            }
-            if ((dataEnd - dataP < 1) || (*dataP & 0xc0)) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-        }
-
-        // Parse Element name (C.3.5)
-        const QName &elemName = parseQualifiedNameOrIndex3(vocabulary.elementNameTable);
-        nodeName = elemName.prefix.empty() ? elemName.name : elemName.prefix + ':' + elemName.name;
-
-        if (hasAttributes) {
-            for (;;) {
-                if (dataEnd - dataP < 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                b = *dataP;
-                if (b < 0x80) { // C.3.6.1
-                    // C.4
-                    Attribute attr;
-                    attr.qname = parseQualifiedNameOrIndex2(vocabulary.attributeNameTable);
-                    attr.name = attr.qname.prefix.empty() ? attr.qname.name : attr.qname.prefix + ':' + attr.qname.name;
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    attr.value = parseNonIdentifyingStringOrIndex1(vocabulary.attributeValueTable);
-                    attributes.push_back(attr);
-                }
-                else {
-                    if ((b & 0xf0) != 0xf0) { // C.3.6.2
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    emptyElement = b == 0xff; // C.3.6.2, C.3.8
-                    ++dataP;
-                    break;
-                }
-            }
-        }
-        else {
-            if (dataEnd - dataP < 1) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            b = *dataP;
-            switch (b) {
-            case 0xff:
-                terminatorPending = true;
-                // Intentionally fall through
-            case 0xf0:
-                emptyElement = true;
-                ++dataP;
-                break;
-            default:
-                emptyElement = false;
-            }
-        }
-        if (!emptyElement) {
-            elementStack.push(nodeName);
-        }
-
-        currentNodeType = irr::io::EXN_ELEMENT;
-    }
-
-    void parseHeader() {
-        // Parse header (C.1.3)
-        size_t magicSize = parseMagic(dataP, dataEnd);
-        if (!magicSize) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        dataP += magicSize;
-        // C.2.3
-        if (dataEnd - dataP < 1) {
-            throw DeadlyImportError(parseErrorMessage);
-        }
-        uint8_t b = *dataP++;
-        if (b & 0x40) {
-            // Parse additional data (C.2.4)
-            size_t len = parseSequenceLen();
-            for (size_t i = 0; i < len; ++i) {
-                if (dataEnd - dataP < 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                /*std::string id =*/ parseNonEmptyOctetString2();
-                if (dataEnd - dataP < 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                /*std::string data =*/ parseNonEmptyOctetString2();
-            }
-        }
-        if (b & 0x20) {
-            // Parse initial vocabulary (C.2.5)
-            if (dataEnd - dataP < 2) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            uint16_t b1 = (dataP[0] << 8) | dataP[1];
-            dataP += 2;
-            if (b1 & 0x1000) {
-                // External vocabulary (C.2.5.2)
-                if (dataEnd - dataP < 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                std::string uri = parseNonEmptyOctetString2();
-                auto it = vocabularyMap.find(uri);
-                if (it == vocabularyMap.end()) {
-                    throw DeadlyImportError("Unknown vocabulary " + uri);
-                }
-                const FIVocabulary *externalVocabulary = it->second;
-                if (externalVocabulary->restrictedAlphabetTable) {
-                    std::copy(externalVocabulary->restrictedAlphabetTable, externalVocabulary->restrictedAlphabetTable + externalVocabulary->restrictedAlphabetTableSize, std::back_inserter(vocabulary.restrictedAlphabetTable));
-                }
-                if (externalVocabulary->encodingAlgorithmTable) {
-                    std::copy(externalVocabulary->encodingAlgorithmTable, externalVocabulary->encodingAlgorithmTable + externalVocabulary->encodingAlgorithmTableSize, std::back_inserter(vocabulary.encodingAlgorithmTable));
-                }
-                if (externalVocabulary->prefixTable) {
-                    std::copy(externalVocabulary->prefixTable, externalVocabulary->prefixTable + externalVocabulary->prefixTableSize, std::back_inserter(vocabulary.prefixTable));
-                }
-                if (externalVocabulary->namespaceNameTable) {
-                    std::copy(externalVocabulary->namespaceNameTable, externalVocabulary->namespaceNameTable + externalVocabulary->namespaceNameTableSize, std::back_inserter(vocabulary.namespaceNameTable));
-                }
-                if (externalVocabulary->localNameTable) {
-                    std::copy(externalVocabulary->localNameTable, externalVocabulary->localNameTable + externalVocabulary->localNameTableSize, std::back_inserter(vocabulary.localNameTable));
-                }
-                if (externalVocabulary->otherNCNameTable) {
-                    std::copy(externalVocabulary->otherNCNameTable, externalVocabulary->otherNCNameTable + externalVocabulary->otherNCNameTableSize, std::back_inserter(vocabulary.otherNCNameTable));
-                }
-                if (externalVocabulary->otherURITable) {
-                    std::copy(externalVocabulary->otherURITable, externalVocabulary->otherURITable + externalVocabulary->otherURITableSize, std::back_inserter(vocabulary.otherURITable));
-                }
-                if (externalVocabulary->attributeValueTable) {
-                    std::copy(externalVocabulary->attributeValueTable, externalVocabulary->attributeValueTable + externalVocabulary->attributeValueTableSize, std::back_inserter(vocabulary.attributeValueTable));
-                }
-                if (externalVocabulary->charactersTable) {
-                    std::copy(externalVocabulary->charactersTable, externalVocabulary->charactersTable + externalVocabulary->charactersTableSize, std::back_inserter(vocabulary.charactersTable));
-                }
-                if (externalVocabulary->otherStringTable) {
-                    std::copy(externalVocabulary->otherStringTable, externalVocabulary->otherStringTable + externalVocabulary->otherStringTableSize, std::back_inserter(vocabulary.otherStringTable));
-                }
-                if (externalVocabulary->elementNameTable) {
-                    std::copy(externalVocabulary->elementNameTable, externalVocabulary->elementNameTable + externalVocabulary->elementNameTableSize, std::back_inserter(vocabulary.elementNameTable));
-                }
-                if (externalVocabulary->attributeNameTable) {
-                    std::copy(externalVocabulary->attributeNameTable, externalVocabulary->attributeNameTable + externalVocabulary->attributeNameTableSize, std::back_inserter(vocabulary.attributeNameTable));
-                }
-            }
-            if (b1 & 0x0800) {
-                // Parse restricted alphabets (C.2.5.3)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.restrictedAlphabetTable.push_back(parseNonEmptyOctetString2());
-                }
-            }
-            if (b1 & 0x0400) {
-                // Parse encoding algorithms (C.2.5.3)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.encodingAlgorithmTable.push_back(parseNonEmptyOctetString2());
-                }
-            }
-            if (b1 & 0x0200) {
-                // Parse prefixes (C.2.5.3)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.prefixTable.push_back(parseNonEmptyOctetString2());
-                }
-            }
-            if (b1 & 0x0100) {
-                // Parse namespace names (C.2.5.3)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.namespaceNameTable.push_back(parseNonEmptyOctetString2());
-                }
-            }
-            if (b1 & 0x0080) {
-                // Parse local names (C.2.5.3)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.localNameTable.push_back(parseNonEmptyOctetString2());
-                }
-            }
-            if (b1 & 0x0040) {
-                // Parse other ncnames (C.2.5.3)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.otherNCNameTable.push_back(parseNonEmptyOctetString2());
-                }
-            }
-            if (b1 & 0x0020) {
-                // Parse other uris (C.2.5.3)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.otherURITable.push_back(parseNonEmptyOctetString2());
-                }
-            }
-            if (b1 & 0x0010) {
-                // Parse attribute values (C.2.5.4)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.attributeValueTable.push_back(parseEncodedCharacterString3());
-                }
-            }
-            if (b1 & 0x0008) {
-                // Parse content character chunks (C.2.5.4)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.charactersTable.push_back(parseEncodedCharacterString3());
-                }
-            }
-            if (b1 & 0x0004) {
-                // Parse other strings (C.2.5.4)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    if (dataEnd - dataP < 1) {
-                        throw DeadlyImportError(parseErrorMessage);
-                    }
-                    vocabulary.otherStringTable.push_back(parseEncodedCharacterString3());
-                }
-            }
-            if (b1 & 0x0002) {
-                // Parse element name surrogates (C.2.5.5)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    vocabulary.elementNameTable.push_back(parseNameSurrogate());
-                }
-            }
-            if (b1 & 0x0001) {
-                // Parse attribute name surrogates (C.2.5.5)
-                for (size_t len = parseSequenceLen(); len > 0; --len) {
-                    vocabulary.attributeNameTable.push_back(parseNameSurrogate());
-                }
-            }
-        }
-        if (b & 0x10) {
-            // Parse notations (C.2.6)
-            for (;;) {
-                if (dataEnd - dataP < 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                uint8_t b1 = *dataP++;
-                if (b1 == 0xf0) {
-                    break;
-                }
-                if ((b1 & 0xfc) != 0xc0) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                /* C.11 */
-                /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
-                if (b1 & 0x02) {
-                    /*const std::string &systemId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
-                }
-                if (b1 & 0x01) {
-                    /*const std::string &publicId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
-                }
-            }
-        }
-        if (b & 0x08) {
-            // Parse unparsed entities (C.2.7)
-            for (;;) {
-                if (dataEnd - dataP < 1) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                uint8_t b1 = *dataP++;
-                if (b1 == 0xf0) {
-                    break;
-                }
-                if ((b1 & 0xfe) != 0xd0) {
-                    throw DeadlyImportError(parseErrorMessage);
-                }
-                /* C.10 */
-                /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
-                /*const std::string &systemId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
-                if (b1 & 0x01) {
-                    /*const std::string &publicId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable);
-                }
-                /*const std::string &notationName =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable);
-            }
-        }
-        if (b & 0x04) {
-            // Parse character encoding scheme (C.2.8)
-            if (dataEnd - dataP < 1) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            /*std::string characterEncodingScheme =*/ parseNonEmptyOctetString2();
-        }
-        if (b & 0x02) {
-            // Parse standalone flag (C.2.9)
-            if (dataEnd - dataP < 1) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            uint8_t b1 = *dataP++;
-            if (b1 & 0xfe) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            //bool standalone = b1 & 0x01;
-        }
-        if (b & 0x01) {
-            // Parse version (C.2.10)
-            if (dataEnd - dataP < 1) {
-                throw DeadlyImportError(parseErrorMessage);
-            }
-            /*std::shared_ptr<const FIValue> version =*/ parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable);
-        }
-    }
-
-    std::unique_ptr<uint8_t[]> data;
-    uint8_t *dataP, *dataEnd;
-    irr::io::EXML_NODE currentNodeType;
-    bool emptyElement;
-    bool headerPending;
-    bool terminatorPending;
-    Vocabulary vocabulary;
-    std::vector<Attribute> attributes;
-    std::stack<std::string> elementStack;
-    std::string nodeName;
-    std::map<std::string, std::unique_ptr<FIDecoder>> decoderMap;
-    std::map<std::string, const FIVocabulary*> vocabularyMap;
-
-    static const std::string EmptyString;
-    static std::shared_ptr<const FIValue> EmptyFIString;
-
-    static FIHexDecoder hexDecoder;
-    static FIBase64Decoder base64Decoder;
-    static FIShortDecoder shortDecoder;
-    static FIIntDecoder intDecoder;
-    static FILongDecoder longDecoder;
-    static FIBoolDecoder boolDecoder;
-    static FIFloatDecoder floatDecoder;
-    static FIDoubleDecoder doubleDecoder;
-    static FIUUIDDecoder uuidDecoder;
-    static FICDATADecoder cdataDecoder;
-    static FIDecoder *defaultDecoder[32];
-};
-
-const std::string CFIReaderImpl::EmptyString;
-std::shared_ptr<const FIValue> CFIReaderImpl::EmptyFIString = FIStringValue::create(std::string());
-
-FIHexDecoder CFIReaderImpl::hexDecoder;
-FIBase64Decoder CFIReaderImpl::base64Decoder;
-FIShortDecoder CFIReaderImpl::shortDecoder;
-FIIntDecoder CFIReaderImpl::intDecoder;
-FILongDecoder CFIReaderImpl::longDecoder;
-FIBoolDecoder CFIReaderImpl::boolDecoder;
-FIFloatDecoder CFIReaderImpl::floatDecoder;
-FIDoubleDecoder CFIReaderImpl::doubleDecoder;
-FIUUIDDecoder CFIReaderImpl::uuidDecoder;
-FICDATADecoder CFIReaderImpl::cdataDecoder;
-
-FIDecoder *CFIReaderImpl::defaultDecoder[32] = {
-    &hexDecoder,
-    &base64Decoder,
-    &shortDecoder,
-    &intDecoder,
-    &longDecoder,
-    &boolDecoder,
-    &floatDecoder,
-    &doubleDecoder,
-    &uuidDecoder,
-    &cdataDecoder
-};
-
-class CXMLReaderImpl : public FIReader
-{
-public:
-
-    //! Constructor
-    CXMLReaderImpl(std::unique_ptr<irr::io::IIrrXMLReader<char, irr::io::IXMLBase>> reader_)
-    : reader(std::move(reader_))
-    {}
-
-    virtual ~CXMLReaderImpl() {}
-
-    virtual bool read() /*override*/ {
-        return reader->read();
-    }
-
-    virtual irr::io::EXML_NODE getNodeType() const /*override*/ {
-        return reader->getNodeType();
-    }
-
-    virtual int getAttributeCount() const /*override*/ {
-        return reader->getAttributeCount();
-    }
-
-    virtual const char* getAttributeName(int idx) const /*override*/ {
-        return reader->getAttributeName(idx);
-    }
-
-    virtual const char* getAttributeValue(int idx) const /*override*/ {
-        return reader->getAttributeValue(idx);
-    }
-
-    virtual const char* getAttributeValue(const char* name) const /*override*/ {
-        return reader->getAttributeValue(name);
-    }
-
-    virtual const char* getAttributeValueSafe(const char* name) const /*override*/ {
-        return reader->getAttributeValueSafe(name);
-    }
-
-    virtual int getAttributeValueAsInt(const char* name) const /*override*/ {
-        return reader->getAttributeValueAsInt(name);
-    }
-
-    virtual int getAttributeValueAsInt(int idx) const /*override*/ {
-        return reader->getAttributeValueAsInt(idx);
-    }
-
-    virtual float getAttributeValueAsFloat(const char* name) const /*override*/ {
-        return reader->getAttributeValueAsFloat(name);
-    }
-
-    virtual float getAttributeValueAsFloat(int idx) const /*override*/ {
-        return reader->getAttributeValueAsFloat(idx);
-    }
-
-    virtual const char* getNodeName() const /*override*/ {
-        return reader->getNodeName();
-    }
-
-    virtual const char* getNodeData() const /*override*/ {
-        return reader->getNodeData();
-    }
-
-    virtual bool isEmptyElement() const /*override*/ {
-        return reader->isEmptyElement();
-    }
-
-    virtual irr::io::ETEXT_FORMAT getSourceFormat() const /*override*/ {
-        return reader->getSourceFormat();
-    }
-
-    virtual irr::io::ETEXT_FORMAT getParserFormat() const /*override*/ {
-        return reader->getParserFormat();
-    }
-
-    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(int /*idx*/) const /*override*/ {
-        return nullptr;
-    }
-
-    virtual std::shared_ptr<const FIValue> getAttributeEncodedValue(const char* /*name*/) const /*override*/ {
-        return nullptr;
-    }
-
-    virtual void registerDecoder(const std::string & /*algorithmUri*/, std::unique_ptr<FIDecoder> /*decoder*/) /*override*/ {}
-
-
-    virtual void registerVocabulary(const std::string &/*vocabularyUri*/, const FIVocabulary * /*vocabulary*/) /*override*/ {}
-
-private:
-
-    std::unique_ptr<irr::io::IIrrXMLReader<char, irr::io::IXMLBase>> reader;
-};
-
-static std::unique_ptr<uint8_t[]> readFile(IOStream *stream, size_t &size, bool &isFI) {
-    size = stream->FileSize();
-    std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(new uint8_t[size]);
-    if (stream->Read(data.get(), size, 1) != 1) {
-        size = 0;
-        data.reset();
-    }
-    isFI = parseMagic(data.get(), data.get() + size) > 0;
-    return data;
-}
-
-std::unique_ptr<FIReader> FIReader::create(IOStream *stream)
-{
-    size_t size;
-    bool isFI;
-    auto data = readFile(stream, size, isFI);
-    if (isFI) {
-        return std::unique_ptr<FIReader>(new CFIReaderImpl(std::move(data), size));
-    }
-    else {
-        auto memios = std::unique_ptr<MemoryIOStream>(new MemoryIOStream(data.release(), size, true));
-        auto callback = std::unique_ptr<CIrrXML_IOStreamReader>(new CIrrXML_IOStreamReader(memios.get()));
-        return std::unique_ptr<FIReader>(new CXMLReaderImpl(std::unique_ptr<irr::io::IIrrXMLReader<char, irr::io::IXMLBase>>(createIrrXMLReader(callback.get()))));
-    }
-}
-
-}// namespace Assimp
-
-#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER

+ 0 - 0
thirdparty/assimp/code/MMDCpp14.h → thirdparty/assimp/code/MMD/MMDCpp14.h


+ 7 - 5
thirdparty/assimp/code/MMDImporter.cpp → thirdparty/assimp/code/MMD/MMDImporter.cpp

@@ -41,15 +41,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
 
-#include "MMDImporter.h"
-#include "MMDPmdParser.h"
-#include "MMDPmxParser.h"
-#include "MMDVmdParser.h"
-#include "ConvertToLHProcess.h"
+#include "MMD/MMDImporter.h"
+#include "MMD/MMDPmdParser.h"
+#include "MMD/MMDPmxParser.h"
+#include "MMD/MMDVmdParser.h"
+#include "PostProcessing/ConvertToLHProcess.h"
+
 #include <assimp/DefaultIOSystem.h>
 #include <assimp/Importer.hpp>
 #include <assimp/ai_assert.h>
 #include <assimp/scene.h>
+
 #include <fstream>
 #include <iomanip>
 #include <memory>

+ 0 - 0
thirdparty/assimp/code/MMDImporter.h → thirdparty/assimp/code/MMD/MMDImporter.h


+ 0 - 0
thirdparty/assimp/code/MMDPmdParser.h → thirdparty/assimp/code/MMD/MMDPmdParser.h


+ 5 - 1
thirdparty/assimp/code/MMDPmxParser.cpp → thirdparty/assimp/code/MMD/MMDPmxParser.cpp

@@ -42,7 +42,11 @@ 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"
+#ifdef ASSIMP_USE_HUNTER
+#  include <utf8/utf8.h>
+#else
+#  include "../contrib/utf8cpp/source/utf8.h"
+#endif
 #include <assimp/Exceptional.h>
 
 namespace pmx

+ 0 - 0
thirdparty/assimp/code/MMDPmxParser.h → thirdparty/assimp/code/MMD/MMDPmxParser.h


+ 0 - 0
thirdparty/assimp/code/MMDVmdParser.h → thirdparty/assimp/code/MMD/MMDVmdParser.h


+ 7 - 5
thirdparty/assimp/code/MaterialSystem.cpp → thirdparty/assimp/code/Material/MaterialSystem.cpp

@@ -96,12 +96,12 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
     ai_real* pOut,
     unsigned int* pMax)
 {
-    ai_assert( pOut != NULL );
-    ai_assert( pMat != NULL );
+    ai_assert( pOut != nullptr );
+    ai_assert( pMat != nullptr );
 
     const aiMaterialProperty* prop;
     aiGetMaterialProperty(pMat,pKey,type,index, (const aiMaterialProperty**) &prop);
-    if (!prop) {
+    if ( nullptr == prop) {
         return AI_FAILURE;
     }
 
@@ -112,9 +112,11 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat,
         if (pMax) {
             iWrite = std::min(*pMax,iWrite); ;
         }
-        for (unsigned int a = 0; a < iWrite;++a)    {
-            pOut[a] = static_cast<ai_real> ( reinterpret_cast<float*>(prop->mData)[a] );
+
+        for (unsigned int a = 0; a < iWrite; ++a) {
+            pOut[ a ] = static_cast<ai_real> ( reinterpret_cast<float*>(prop->mData)[a] );
         }
+
         if (pMax) {
             *pMax = iWrite;
         }

+ 0 - 0
thirdparty/assimp/code/MaterialSystem.h → thirdparty/assimp/code/Material/MaterialSystem.h


+ 0 - 0
thirdparty/assimp/code/CalcTangentsProcess.cpp → thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.cpp


+ 2 - 2
thirdparty/assimp/code/CalcTangentsProcess.h → thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.h

@@ -42,11 +42,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 /** @file Defines a post processing step to calculate tangents and
-    bitangents on all imported meshes.*/
+    bi-tangents on all imported meshes.*/
 #ifndef AI_CALCTANGENTSPROCESS_H_INC
 #define AI_CALCTANGENTSPROCESS_H_INC
 
-#include "BaseProcess.h"
+#include "Common/BaseProcess.h"
 
 struct aiMesh;
 

+ 0 - 0
thirdparty/assimp/code/ComputeUVMappingProcess.cpp → thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp


+ 2 - 1
thirdparty/assimp/code/ComputeUVMappingProcess.h → thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.h

@@ -45,7 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_COMPUTEUVMAPPING_H_INC
 #define AI_COMPUTEUVMAPPING_H_INC
 
-#include "BaseProcess.h"
+#include "Common/BaseProcess.h"
+
 #include <assimp/mesh.h>
 #include <assimp/material.h>
 #include <assimp/types.h>

+ 0 - 0
thirdparty/assimp/code/ConvertToLHProcess.cpp → thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.cpp


+ 2 - 1
thirdparty/assimp/code/ConvertToLHProcess.h → thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.h

@@ -52,7 +52,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define AI_CONVERTTOLHPROCESS_H_INC
 
 #include <assimp/types.h>
-#include "BaseProcess.h"
+
+#include "Common/BaseProcess.h"
 
 struct aiMesh;
 struct aiNodeAnim;

+ 0 - 0
thirdparty/assimp/code/DeboneProcess.cpp → thirdparty/assimp/code/PostProcessing/DeboneProcess.cpp


+ 7 - 10
thirdparty/assimp/code/DeboneProcess.h → thirdparty/assimp/code/PostProcessing/DeboneProcess.h

@@ -44,17 +44,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef AI_DEBONEPROCESS_H_INC
 #define AI_DEBONEPROCESS_H_INC
 
-#include <vector>
-#include <utility>
-#include "BaseProcess.h"
+#include "Common/BaseProcess.h"
 
 #include <assimp/mesh.h>
 #include <assimp/scene.h>
 
+#include <vector>
+#include <utility>
+
+#// Forward declarations
 class DeboneTest;
 
-namespace Assimp
-{
+namespace Assimp {
 
 #if (!defined AI_DEBONE_THRESHOLD)
 #   define AI_DEBONE_THRESHOLD  1.0f
@@ -66,14 +67,11 @@ namespace Assimp
 * the bone are split from the mesh. The split off (new) mesh is boneless. At any
 * point in time, bones without affect upon a given mesh are to be removed.
 */
-class DeboneProcess : public BaseProcess
-{
+class DeboneProcess : public BaseProcess {
 public:
-
     DeboneProcess();
     ~DeboneProcess();
 
-public:
     // -------------------------------------------------------------------
     /** Returns whether the processing step is present in the given flag.
     * @param pFlags The processing flags the importer was called with.
@@ -91,7 +89,6 @@ public:
     void SetupProperties(const Importer* pImp);
 
 protected:
-
     // -------------------------------------------------------------------
     /** Executes the post processing step on the given imported data.
     * At the moment a process is not supposed to fail.

Some files were not shown because too many files changed in this diff