Browse Source

Merge branch 'master' into 3dsMax2021PbrMaterials

Kim Kulling 4 years ago
parent
commit
7dd0596010

+ 9 - 3
CMakeLists.txt

@@ -249,9 +249,15 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
     SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
   ENDIF()
   ENDIF()
   # hide all not-exported symbols
   # hide all not-exported symbols
-  SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
-  SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
-  SET(LIBSTDC++_LIBRARIES -lstdc++)
+  IF(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "mips64" )
+	SET(CMAKE_CXX_FLAGS "-mxgot -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
+	SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
+	SET(LIBSTDC++_LIBRARIES -lstdc++)
+  ELSE()
+	SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}")
+	SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
+	SET(LIBSTDC++_LIBRARIES -lstdc++)
+  ENDIF()
 ELSEIF(MSVC)
 ELSEIF(MSVC)
   # enable multi-core compilation with MSVC
   # enable multi-core compilation with MSVC
   IF( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) # clang-cl
   IF( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) # clang-cl

+ 7 - 4
Readme.md

@@ -16,13 +16,16 @@ A library to import and export various 3d-model-formats including scene-post-pro
 <br>
 <br>
 
 
 APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
 APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
-
-[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/).
-
 Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
 Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
 
 
-This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
+### Latest Doc's ###
+Please check the latest documents at [Asset-Importer-Lib-Doc](https://assimp-docs.readthedocs.io/en/latest/). 
 
 
+### Get involved ###
+This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
+<br>
+You find a bug in the docs? Use [Doc-Repo](https://github.com/assimp/assimp-docs).
+<br>
 Please check our Wiki as well: https://github.com/assimp/assimp/wiki
 Please check our Wiki as well: https://github.com/assimp/assimp/wiki
 
 
 If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb
 If you want to check our Model-Database, use the following repo: https://github.com/assimp/assimp-mdb

+ 9 - 5
code/AssetLib/Assjson/cencode.c

@@ -9,8 +9,10 @@ For details, see http://sourceforge.net/projects/libb64
 
 
 const int CHARS_PER_LINE = 72;
 const int CHARS_PER_LINE = 72;
 
 
+#ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(push)
 #pragma warning(disable : 4244)
 #pragma warning(disable : 4244)
+#endif // _MSC_VER
 
 
 void base64_init_encodestate(base64_encodestate* state_in)
 void base64_init_encodestate(base64_encodestate* state_in)
 {
 {
@@ -33,9 +35,9 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 	char* codechar = code_out;
 	char* codechar = code_out;
 	char result;
 	char result;
 	char fragment;
 	char fragment;
-	
+
 	result = state_in->result;
 	result = state_in->result;
-	
+
 	switch (state_in->step)
 	switch (state_in->step)
 	{
 	{
 		while (1)
 		while (1)
@@ -74,7 +76,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 			*codechar++ = base64_encode_value(result);
 			*codechar++ = base64_encode_value(result);
 			result  = (fragment & 0x03f) >> 0;
 			result  = (fragment & 0x03f) >> 0;
 			*codechar++ = base64_encode_value(result);
 			*codechar++ = base64_encode_value(result);
-			
+
 			++(state_in->stepcount);
 			++(state_in->stepcount);
 			if (state_in->stepcount == CHARS_PER_LINE/4)
 			if (state_in->stepcount == CHARS_PER_LINE/4)
 			{
 			{
@@ -90,7 +92,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
 int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 {
 {
 	char* codechar = code_out;
 	char* codechar = code_out;
-	
+
 	switch (state_in->step)
 	switch (state_in->step)
 	{
 	{
 	case step_B:
 	case step_B:
@@ -106,8 +108,10 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 		break;
 		break;
 	}
 	}
 	*codechar++ = '\n';
 	*codechar++ = '\n';
-	
+
 	return (int)(codechar - code_out);
 	return (int)(codechar - code_out);
 }
 }
 
 
+#ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
+#endif // _MSC_VER

+ 110 - 107
code/AssetLib/FBX/FBXConverter.cpp

@@ -185,6 +185,17 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
     return unique_name;
     return unique_name;
 }
 }
 
 
+/// This struct manages nodes which may or may not end up in the node hierarchy.
+/// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
+struct FBXConverter::PotentialNode
+{
+    PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
+    PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
+    aiNode* operator->() { return mNode; }
+    std::unique_ptr<aiNode> mOwnership;
+    aiNode* mNode;
+};
+
 /// todo: pre-build node hierarchy
 /// todo: pre-build node hierarchy
 /// todo: get bone from stack
 /// todo: get bone from stack
 /// todo: make map of aiBone* to aiNode*
 /// todo: make map of aiBone* to aiNode*
@@ -192,137 +203,129 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
 void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
 void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
     const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
     const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
 
 
-    std::vector<aiNode *> nodes;
+    std::vector<PotentialNode> nodes;
     nodes.reserve(conns.size());
     nodes.reserve(conns.size());
 
 
-    std::vector<aiNode *> nodes_chain;
-    std::vector<aiNode *> post_nodes_chain;
-
-    try {
-        for (const Connection *con : conns) {
-            // ignore object-property links
-            if (con->PropertyName().length()) {
-                // really important we document why this is ignored.
-                FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
-                continue; //?
-            }
-
-            // convert connection source object into Object base class
-            const Object *const object = con->SourceObject();
-            if (nullptr == object) {
-                FBXImporter::LogError("failed to convert source object for Model link");
-                continue;
-            }
+    std::vector<PotentialNode> nodes_chain;
+    std::vector<PotentialNode> post_nodes_chain;
 
 
-            // FBX Model::Cube, Model::Bone001, etc elements
-            // This detects if we can cast the object into this model structure.
-            const Model *const model = dynamic_cast<const Model *>(object);
+    for (const Connection *con : conns) {
+        // ignore object-property links
+        if (con->PropertyName().length()) {
+            // really important we document why this is ignored.
+            FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
+            continue; //?
+        }
 
 
-            if (nullptr != model) {
-                nodes_chain.clear();
-                post_nodes_chain.clear();
+        // convert connection source object into Object base class
+        const Object *const object = con->SourceObject();
+        if (nullptr == object) {
+            FBXImporter::LogError("failed to convert source object for Model link");
+            continue;
+        }
 
 
-                aiMatrix4x4 new_abs_transform = parent->mTransformation;
-                std::string node_name = FixNodeName(model->Name());
-                // 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.
+        // FBX Model::Cube, Model::Bone001, etc elements
+        // This detects if we can cast the object into this model structure.
+        const Model *const model = dynamic_cast<const Model *>(object);
 
 
-                // generate node transforms - this includes pivot data
-                // if need_additional_node is true then you t
-                const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
+        if (nullptr != model) {
+            nodes_chain.clear();
+            post_nodes_chain.clear();
 
 
-                // assert that for the current node we must have at least a single transform
-                ai_assert(nodes_chain.size());
+            aiMatrix4x4 new_abs_transform = parent->mTransformation;
+            std::string node_name = FixNodeName(model->Name());
+            // 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.
 
 
-                if (need_additional_node) {
-                    nodes_chain.push_back(new aiNode(node_name));
-                }
+            // generate node transforms - this includes pivot data
+            // if need_additional_node is true then you t
+            const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
 
 
-                //setup metadata on newest node
-                SetupNodeMetadata(*model, *nodes_chain.back());
+            // assert that for the current node we must have at least a single transform
+            ai_assert(nodes_chain.size());
 
 
-                // link all nodes in a row
-                aiNode *last_parent = parent;
-                for (aiNode *child : nodes_chain) {
-                    ai_assert(child);
+            if (need_additional_node) {
+                nodes_chain.emplace_back(PotentialNode(node_name));
+            }
 
 
-                    if (last_parent != parent) {
-                        last_parent->mNumChildren = 1;
-                        last_parent->mChildren = new aiNode *[1];
-                        last_parent->mChildren[0] = child;
-                    }
+            //setup metadata on newest node
+            SetupNodeMetadata(*model, *nodes_chain.back().mNode);
 
 
-                    child->mParent = last_parent;
-                    last_parent = child;
+            // link all nodes in a row
+            aiNode *last_parent = parent;
+            for (PotentialNode& child : nodes_chain) {
+                ai_assert(child.mNode);
 
 
-                    new_abs_transform *= child->mTransformation;
+                if (last_parent != parent) {
+                    last_parent->mNumChildren = 1;
+                    last_parent->mChildren = new aiNode *[1];
+                    last_parent->mChildren[0] = child.mOwnership.release();
                 }
                 }
 
 
-                // attach geometry
-                ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform);
+                child->mParent = last_parent;
+                last_parent = child.mNode;
 
 
-                // check if there will be any child nodes
-                const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
+                new_abs_transform *= child->mTransformation;
+            }
 
 
-                // if so, link the geometric transform inverse nodes
-                // before we attach any child nodes
-                if (child_conns.size()) {
-                    for (aiNode *postnode : post_nodes_chain) {
-                        ai_assert(postnode);
+            // attach geometry
+            ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform);
 
 
-                        if (last_parent != parent) {
-                            last_parent->mNumChildren = 1;
-                            last_parent->mChildren = new aiNode *[1];
-                            last_parent->mChildren[0] = postnode;
-                        }
+            // check if there will be any child nodes
+            const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
 
 
-                        postnode->mParent = last_parent;
-                        last_parent = postnode;
+            // if so, link the geometric transform inverse nodes
+            // before we attach any child nodes
+            if (child_conns.size()) {
+                for (PotentialNode& postnode : post_nodes_chain) {
+                    ai_assert(postnode.mNode);
 
 
-                        new_abs_transform *= postnode->mTransformation;
+                    if (last_parent != parent) {
+                        last_parent->mNumChildren = 1;
+                        last_parent->mChildren = new aiNode *[1];
+                        last_parent->mChildren[0] = postnode.mOwnership.release();
                     }
                     }
-                } else {
-                    // free the nodes we allocated as we don't need them
-                    Util::delete_fun<aiNode> deleter;
-                    std::for_each(
-                            post_nodes_chain.begin(),
-                            post_nodes_chain.end(),
-                            deleter);
-                }
 
 
-                // recursion call - child nodes
-                ConvertNodes(model->ID(), last_parent, root_node);
+                    postnode->mParent = last_parent;
+                    last_parent = postnode.mNode;
 
 
-                if (doc.Settings().readLights) {
-                    ConvertLights(*model, node_name);
+                    new_abs_transform *= postnode->mTransformation;
                 }
                 }
+            } else {
+                // free the nodes we allocated as we don't need them
+                post_nodes_chain.clear();
+            }
 
 
-                if (doc.Settings().readCameras) {
-                    ConvertCameras(*model, node_name);
-                }
+            // recursion call - child nodes
+            ConvertNodes(model->ID(), last_parent, root_node);
 
 
-                nodes.push_back(nodes_chain.front());
-                nodes_chain.clear();
+            if (doc.Settings().readLights) {
+                ConvertLights(*model, node_name);
             }
             }
-        }
 
 
-        if (nodes.size()) {
-            parent->mChildren = new aiNode *[nodes.size()]();
-            parent->mNumChildren = static_cast<unsigned int>(nodes.size());
+            if (doc.Settings().readCameras) {
+                ConvertCameras(*model, node_name);
+            }
 
 
-            std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren);
-        } else {
-            parent->mNumChildren = 0;
-            parent->mChildren = nullptr;
+            nodes.push_back(std::move(nodes_chain.front()));
+            nodes_chain.clear();
         }
         }
+    }
 
 
-    } catch (std::exception &) {
-        Util::delete_fun<aiNode> deleter;
-        std::for_each(nodes.begin(), nodes.end(), deleter);
-        std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter);
-        std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter);
+    if (nodes.size()) {
+        parent->mChildren = new aiNode *[nodes.size()]();
+        parent->mNumChildren = static_cast<unsigned int>(nodes.size());
+
+        for (unsigned int i = 0; i < nodes.size(); ++i)
+        {
+            parent->mChildren[i] = nodes[i].mOwnership.release();
+        }
+        nodes.clear();
+    } else {
+        parent->mNumChildren = 0;
+        parent->mChildren = nullptr;
     }
     }
 }
 }
 
 
@@ -681,8 +684,8 @@ std::string FBXConverter::NameTransformationChainNode(const std::string &name, T
     return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
     return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
 }
 }
 
 
-bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<aiNode *> &output_nodes,
-        std::vector<aiNode *> &post_output_nodes) {
+bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<PotentialNode> &output_nodes,
+        std::vector<PotentialNode> &post_output_nodes) {
     const PropertyTable &props = model.Props();
     const PropertyTable &props = model.Props();
     const Model::RotOrder rot = model.RotationOrder();
     const Model::RotOrder rot = model.RotationOrder();
 
 
@@ -828,7 +831,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
                 chain[i] = chain[i].Inverse();
                 chain[i] = chain[i].Inverse();
             }
             }
 
 
-            aiNode *nd = new aiNode();
+            PotentialNode nd;
             nd->mName.Set(NameTransformationChainNode(name, comp));
             nd->mName.Set(NameTransformationChainNode(name, comp));
             nd->mTransformation = chain[i];
             nd->mTransformation = chain[i];
 
 
@@ -836,9 +839,9 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
             if (comp == TransformationComp_GeometricScalingInverse ||
             if (comp == TransformationComp_GeometricScalingInverse ||
                     comp == TransformationComp_GeometricRotationInverse ||
                     comp == TransformationComp_GeometricRotationInverse ||
                     comp == TransformationComp_GeometricTranslationInverse) {
                     comp == TransformationComp_GeometricTranslationInverse) {
-                post_output_nodes.push_back(nd);
+                post_output_nodes.emplace_back(std::move(nd));
             } else {
             } else {
-                output_nodes.push_back(nd);
+                output_nodes.emplace_back(std::move(nd));
             }
             }
         }
         }
 
 
@@ -847,8 +850,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
     }
     }
 
 
     // else, we can just multiply the matrices together
     // else, we can just multiply the matrices together
-    aiNode *nd = new aiNode();
-    output_nodes.push_back(nd);
+    PotentialNode nd;
 
 
     // name passed to the method is already unique
     // name passed to the method is already unique
     nd->mName.Set(name);
     nd->mName.Set(name);
@@ -857,6 +859,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
     for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) {
     for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) {
       nd->mTransformation = nd->mTransformation * chain[i];
       nd->mTransformation = nd->mTransformation * chain[i];
     }
     }
+    output_nodes.push_back(std::move(nd));
     return false;
     return false;
 }
 }
   
   

+ 3 - 2
code/AssetLib/FBX/FBXConverter.h

@@ -171,9 +171,10 @@ private:
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     /**
     /**
-    *  note: memory for output_nodes will be managed by the caller
+    *  note: memory for output_nodes is managed by the caller, via the PotentialNode struct.
     */
     */
-    bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes);
+    struct PotentialNode;
+    bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<PotentialNode>& output_nodes, std::vector<PotentialNode>& post_output_nodes);
 
 
     // ------------------------------------------------------------------------------------------------
     // ------------------------------------------------------------------------------------------------
     void SetupNodeMetadata(const Model& model, aiNode& nd);
     void SetupNodeMetadata(const Model& model, aiNode& nd);

+ 3 - 1
code/AssetLib/glTF/glTFCommon.cpp

@@ -49,7 +49,9 @@ using namespace glTFCommon::Util;
 namespace Util {
 namespace Util {
 
 
 size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out) {
 size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out) {
-    ai_assert(inLength % 4 == 0);
+    if (inLength % 4 != 0) {
+        throw DeadlyImportError("Invalid base64 encoded data: \"", std::string(in, std::min(size_t(32), inLength)), "\", length:", inLength);
+    }
 
 
     if (inLength < 4) {
     if (inLength < 4) {
         out = 0;
         out = 0;

+ 4 - 1
code/AssetLib/glTF/glTFCommon.h

@@ -249,7 +249,10 @@ inline char EncodeCharBase64(uint8_t b) {
 }
 }
 
 
 inline uint8_t DecodeCharBase64(char c) {
 inline uint8_t DecodeCharBase64(char c) {
-    return DATA<true>::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs?
+    if (c & 0x80) {
+        throw DeadlyImportError("Invalid base64 char value: ", size_t(c));
+    }
+    return DATA<true>::tableDecodeBase64[size_t(c & 0x7F)]; // TODO faster with lookup table or ifs?
 }
 }
 
 
 size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out);
 size_t DecodeBase64(const char *in, size_t inLength, uint8_t *&out);

+ 8 - 0
code/AssetLib/glTF2/glTF2Asset.h

@@ -1124,6 +1124,14 @@ private:
     IOStream *OpenFile(std::string path, const char *mode, bool absolute = false);
     IOStream *OpenFile(std::string path, const char *mode, bool absolute = false);
 };
 };
 
 
+inline std::string getContextForErrorMessages(const std::string &id, const std::string &name) {
+    std::string context = id;
+    if (!name.empty()) {
+        context += " (\"" + name + "\")";
+    }
+    return context;
+}
+
 } // namespace glTF2
 } // namespace glTF2
 
 
 // Include the implementation of the methods
 // Include the implementation of the methods

+ 11 - 14
code/AssetLib/glTF2/glTF2Asset.inl

@@ -273,17 +273,21 @@ Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
     }
     }
 
 
     if (!mDict->IsArray()) {
     if (!mDict->IsArray()) {
-        throw DeadlyImportError("GLTF: Field is not an array \"", mDictId, "\"");
+        throw DeadlyImportError("GLTF: Field \"", mDictId, "\"  is not an array");
+    }
+
+    if (i >= mDict->Size()) {
+        throw DeadlyImportError("GLTF: Array index ", i, " is out of bounds (", mDict->Size(), ") for \"", mDictId, "\"");
     }
     }
 
 
     Value &obj = (*mDict)[i];
     Value &obj = (*mDict)[i];
 
 
     if (!obj.IsObject()) {
     if (!obj.IsObject()) {
-        throw DeadlyImportError("GLTF: Object at index \"", to_string(i), "\" is not a JSON object");
+        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" is not a JSON object");
     }
     }
 
 
     if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
     if (mRecursiveReferenceCheck.find(i) != mRecursiveReferenceCheck.end()) {
-        throw DeadlyImportError("GLTF: Object at index \"", to_string(i), "\" has recursive reference to itself");
+        throw DeadlyImportError("GLTF: Object at index ", i, " in array \"", mDictId, "\" has recursive reference to itself");
     }
     }
     mRecursiveReferenceCheck.insert(i);
     mRecursiveReferenceCheck.insert(i);
 
 
@@ -741,14 +745,6 @@ inline void CopyData(size_t count,
     }
     }
 }
 }
 
 
-inline std::string getContextForErrorMessages(const std::string& id, const std::string& name) {
-    std::string context = id;
-    if (!name.empty()) {
-        context += " (\"" + name + "\")";
-    }
-    return context;
-}
-
 } // namespace
 } // namespace
 
 
 template <class T>
 template <class T>
@@ -766,11 +762,12 @@ void Accessor::ExtractData(T *&outData) {
     const size_t targetElemSize = sizeof(T);
     const size_t targetElemSize = sizeof(T);
 
 
     if (elemSize > targetElemSize) {
     if (elemSize > targetElemSize) {
-        throw DeadlyImportError("GLTF: elemSize > targetElemSize");
+        throw DeadlyImportError("GLTF: elemSize ", elemSize, " > targetElemSize ", targetElemSize, " in ", getContextForErrorMessages(id, name));
     }
     }
 
 
-    if (count*stride > (bufferView ? bufferView->byteLength : sparse->data.size())) {
-        throw DeadlyImportError("GLTF: count*stride out of range");
+    const size_t maxSize = (bufferView ? bufferView->byteLength : sparse->data.size());
+    if (count*stride > maxSize) {
+        throw DeadlyImportError("GLTF: count*stride ", (count * stride), " > maxSize ", maxSize, " in ", getContextForErrorMessages(id, name));
     }
     }
 
 
     outData = new T[count];
     outData = new T[count];

+ 1 - 1
code/AssetLib/glTF2/glTF2Exporter.cpp

@@ -1126,7 +1126,7 @@ void glTF2Exporter::MergeMeshes()
                         unsigned int meshIndex = meshRef.GetIndex();
                         unsigned int meshIndex = meshRef.GetIndex();
 
 
                         if (meshIndex == removedIndex) {
                         if (meshIndex == removedIndex) {
-                            node->meshes.erase(curNode->meshes.begin() + mm);
+                            curNode->meshes.erase(curNode->meshes.begin() + mm);
                         } else if (meshIndex > removedIndex) {
                         } else if (meshIndex > removedIndex) {
                             Ref<Mesh> newMeshRef = mAsset->meshes.Get(meshIndex - 1);
                             Ref<Mesh> newMeshRef = mAsset->meshes.Get(meshIndex - 1);
 
 

+ 4 - 1
code/AssetLib/glTF2/glTF2Importer.cpp

@@ -918,7 +918,10 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
 
 
     if (!node.meshes.empty()) {
     if (!node.meshes.empty()) {
         // GLTF files contain at most 1 mesh per node.
         // GLTF files contain at most 1 mesh per node.
-        assert(node.meshes.size() == 1);
+        if (node.meshes.size() > 1)
+        {
+            throw DeadlyImportError("GLTF: Invalid input, found ", node.meshes.size(), " meshes in ", getContextForErrorMessages(node.id, node.name), ", but only 1 mesh per node allowed.");
+        }
         int mesh_idx = node.meshes[0].GetIndex();
         int mesh_idx = node.meshes[0].GetIndex();
         int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx];
         int count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx];
 
 

+ 4 - 1
code/CMakeLists.txt

@@ -1033,7 +1033,10 @@ ELSE()
   INCLUDE_DIRECTORIES( "../contrib" )
   INCLUDE_DIRECTORIES( "../contrib" )
   INCLUDE_DIRECTORIES( "../contrib/pugixml/src" )
   INCLUDE_DIRECTORIES( "../contrib/pugixml/src" )
   ADD_DEFINITIONS( -DRAPIDJSON_HAS_STDSTRING=1 )
   ADD_DEFINITIONS( -DRAPIDJSON_HAS_STDSTRING=1 )
-  ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS )
+  option( ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR "Suppress rapidjson warning on MSVC (NOTE: breaks android build)" ON )
+  if(ASSIMP_RAPIDJSON_NO_MEMBER_ITERATOR)
+    ADD_DEFINITIONS( -DRAPIDJSON_NOMEMBERITERATORCLASS )
+  endif()
 ENDIF()
 ENDIF()
 
 
 # VC2010 fixes
 # VC2010 fixes

+ 39 - 0
code/PostProcessing/SplitByBoneCountProcess.cpp

@@ -408,6 +408,45 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
             }
             }
         }
         }
 
 
+        // ... and copy all the morph targets for all the vertices which made it into the new submesh
+        if (pMesh->mNumAnimMeshes > 0) {
+            newMesh->mNumAnimMeshes = pMesh->mNumAnimMeshes;
+            newMesh->mAnimMeshes = new aiAnimMesh*[newMesh->mNumAnimMeshes];
+            
+            for (unsigned int morphIdx = 0; morphIdx < newMesh->mNumAnimMeshes; ++morphIdx) {
+                aiAnimMesh* origTarget = pMesh->mAnimMeshes[morphIdx];
+                aiAnimMesh* newTarget = new aiAnimMesh;
+                newTarget->mName = origTarget->mName;
+                newTarget->mWeight = origTarget->mWeight;
+                newTarget->mNumVertices = numSubMeshVertices;
+                newTarget->mVertices = new aiVector3D[numSubMeshVertices];
+                newMesh->mAnimMeshes[morphIdx] = newTarget;
+                
+                if (origTarget->HasNormals()) {
+                    newTarget->mNormals = new aiVector3D[numSubMeshVertices];
+                }
+                
+                if (origTarget->HasTangentsAndBitangents()) {
+                    newTarget->mTangents = new aiVector3D[numSubMeshVertices];
+                    newTarget->mBitangents = new aiVector3D[numSubMeshVertices];
+                }
+                
+                for( unsigned int vi = 0; vi < numSubMeshVertices; ++vi) {
+                    // find the source vertex for it in the source mesh
+                    unsigned int previousIndex = previousVertexIndices[vi];
+                    newTarget->mVertices[vi] = origTarget->mVertices[previousIndex];
+
+                    if (newTarget->HasNormals()) {
+                        newTarget->mNormals[vi] = origTarget->mNormals[previousIndex];
+                    }
+                    if (newTarget->HasTangentsAndBitangents()) {
+                        newTarget->mTangents[vi] = origTarget->mTangents[previousIndex];
+                        newTarget->mBitangents[vi] = origTarget->mBitangents[previousIndex];
+                    }
+                }
+            }
+        }
+
         // I have the strange feeling that this will break apart at some point in time...
         // I have the strange feeling that this will break apart at some point in time...
     }
     }
 }
 }

+ 4 - 4
contrib/Open3DGC/o3dgcSC3DMCDecoder.inl

@@ -27,10 +27,10 @@ THE SOFTWARE.
 #include "o3dgcArithmeticCodec.h"
 #include "o3dgcArithmeticCodec.h"
 #include "o3dgcTimer.h"
 #include "o3dgcTimer.h"
 
 
-#ifdef _WIN32
+#ifdef _MSC_VER
 #    pragma warning(push)
 #    pragma warning(push)
 #    pragma warning( disable : 4456)
 #    pragma warning( disable : 4456)
-#endif // _WIN32
+#endif // _MSC_VER
 
 
 //#define DEBUG_VERBOSE
 //#define DEBUG_VERBOSE
 
 
@@ -852,9 +852,9 @@ namespace o3dgc
     }
     }
 } // namespace o3dgc
 } // namespace o3dgc
 
 
-#ifdef _WIN32
+#ifdef _MSC_VER
 #    pragma warning( pop )
 #    pragma warning( pop )
-#endif // _WIN32
+#endif // _MSC_VER
 
 
 #endif // O3DGC_SC3DMC_DECODER_INL
 #endif // O3DGC_SC3DMC_DECODER_INL
 
 

+ 4 - 4
contrib/Open3DGC/o3dgcSC3DMCEncoder.inl

@@ -32,10 +32,10 @@ THE SOFTWARE.
 
 
 //#define DEBUG_VERBOSE
 //#define DEBUG_VERBOSE
 
 
-#ifdef _WIN32
+#ifdef _MSC_VER
 #    pragma warning(push)
 #    pragma warning(push)
 #    pragma warning(disable : 4456)
 #    pragma warning(disable : 4456)
-#endif // _WIN32
+#endif // _MSC_VER
 
 
 namespace o3dgc
 namespace o3dgc
 {
 {
@@ -927,9 +927,9 @@ namespace o3dgc
     }
     }
 } // namespace o3dgc
 } // namespace o3dgc
 
 
-#ifdef _WIN32
+#ifdef _MSC_VER
 #    pragma warning(pop)
 #    pragma warning(pop)
-#endif // _WIN32
+#endif // _MSC_VER
 
 
 #endif // O3DGC_SC3DMC_ENCODER_INL
 #endif // O3DGC_SC3DMC_ENCODER_INL
 
 

+ 2 - 0
contrib/Open3DGC/o3dgcTimer.h

@@ -28,7 +28,9 @@ THE SOFTWARE.
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 /* Thank you, Microsoft, for file WinDef.h with min/max redefinition. */
 /* Thank you, Microsoft, for file WinDef.h with min/max redefinition. */
+#ifndef NOMINMAX
 #define NOMINMAX
 #define NOMINMAX
+#endif
 #include <windows.h>
 #include <windows.h>
 #elif __APPLE__
 #elif __APPLE__
 #include <mach/clock.h>
 #include <mach/clock.h>

+ 4 - 0
contrib/zip/src/zip.c

@@ -18,8 +18,10 @@
 /* Win32, DOS, MSVC, MSVS */
 /* Win32, DOS, MSVC, MSVS */
 #include <direct.h>
 #include <direct.h>
 
 
+#ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(push)
 #pragma warning(disable : 4706)
 #pragma warning(disable : 4706)
+#endif // _MSC_VER
 
 
 #define MKDIR(DIRNAME) _mkdir(DIRNAME)
 #define MKDIR(DIRNAME) _mkdir(DIRNAME)
 #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL)
 #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL)
@@ -968,4 +970,6 @@ out:
   return status;
   return status;
 }
 }
 
 
+#ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
+#endif // _MSC_VER

+ 6 - 6
include/assimp/mesh.h

@@ -52,9 +52,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #pragma GCC system_header
 #pragma GCC system_header
 #endif
 #endif
 
 
-#ifdef _WIN32
+#ifdef _MSC_VER
 #pragma warning(disable : 4351)
 #pragma warning(disable : 4351)
-#endif // _WIN32
+#endif // _MSC_VER
 
 
 #include <assimp/aabb.h>
 #include <assimp/aabb.h>
 #include <assimp/types.h>
 #include <assimp/types.h>
@@ -458,8 +458,8 @@ struct aiAnimMesh {
      */
      */
     unsigned int mNumVertices;
     unsigned int mNumVertices;
 
 
-    /** 
-     * Weight of the AnimMesh. 
+    /**
+     * Weight of the AnimMesh.
      */
      */
     float mWeight;
     float mWeight;
 
 
@@ -713,8 +713,8 @@ struct aiMesh {
      *  Note! Currently only works with Collada loader.*/
      *  Note! Currently only works with Collada loader.*/
     C_STRUCT aiAnimMesh **mAnimMeshes;
     C_STRUCT aiAnimMesh **mAnimMeshes;
 
 
-    /** 
-     *  Method of morphing when animeshes are specified. 
+    /**
+     *  Method of morphing when animeshes are specified.
      */
      */
     unsigned int mMethod;
     unsigned int mMethod;
 
 

+ 6 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp

@@ -31,10 +31,16 @@
 #include <dxgiformat.h>
 #include <dxgiformat.h>
 #include <assert.h>
 #include <assert.h>
 
 
+#ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(push)
 #pragma warning(disable : 4005)
 #pragma warning(disable : 4005)
+#endif // _MSC_VER
+
 #include <wincodec.h>
 #include <wincodec.h>
+
+#ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
+#endif // _MSC_VER
 
 
 #include <memory>
 #include <memory>
 
 

+ 6 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h

@@ -31,10 +31,16 @@
 
 
 #include <d3d11.h>
 #include <d3d11.h>
 
 
+#ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(push)
 #pragma warning(disable : 4005)
 #pragma warning(disable : 4005)
+#endif // _MSC_VER
+
 #include <stdint.h>
 #include <stdint.h>
+
+#ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
+#endif // _MSC_VER
 
 
 HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice,
 HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice,
 	_In_opt_ ID3D11DeviceContext* d3dContext,
 	_In_opt_ ID3D11DeviceContext* d3dContext,

+ 2 - 0
samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp

@@ -25,10 +25,12 @@
 #include "UTFConverter.h"
 #include "UTFConverter.h"
 #include "SafeRelease.hpp"
 #include "SafeRelease.hpp"
 
 
+#ifdef _MSC_VER
 #pragma comment (lib, "d3d11.lib")
 #pragma comment (lib, "d3d11.lib")
 #pragma comment (lib, "Dxgi.lib")
 #pragma comment (lib, "Dxgi.lib")
 #pragma comment(lib,"d3dcompiler.lib")
 #pragma comment(lib,"d3dcompiler.lib")
 #pragma comment (lib, "dxguid.lib")
 #pragma comment (lib, "dxguid.lib")
+#endif // _MSC_VER
 
 
 using namespace DirectX;
 using namespace DirectX;
 using namespace AssimpSamples::SharedCode;
 using namespace AssimpSamples::SharedCode;

+ 6 - 0
samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp

@@ -18,10 +18,16 @@
 #include <GL/gl.h>
 #include <GL/gl.h>
 #include <GL/glu.h>
 #include <GL/glu.h>
 
 
+#ifdef _MSC_VER
 #pragma warning(disable: 4100) // Disable warning 'unreferenced formal parameter'
 #pragma warning(disable: 4100) // Disable warning 'unreferenced formal parameter'
+#endif // _MSC_VER
+
 #define STB_IMAGE_IMPLEMENTATION
 #define STB_IMAGE_IMPLEMENTATION
 #include "contrib/stb_image/stb_image.h"
 #include "contrib/stb_image/stb_image.h"
+
+#ifdef _MSC_VER
 #pragma warning(default: 4100) // Enable warning 'unreferenced formal parameter'
 #pragma warning(default: 4100) // Enable warning 'unreferenced formal parameter'
+#endif // _MSC_VER
 
 
 #include <fstream>
 #include <fstream>