Quellcode durchsuchen

Merge branch 'master' into 3dsMax2021PbrMaterials

Kim Kulling vor 4 Jahren
Ursprung
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)
   ENDIF()
   # 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)
   # enable multi-core compilation with MSVC
   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>
 
 APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS.
-
-[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/).
-
 Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more.
 
-This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases).
+### 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
 
 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;
 
+#ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable : 4244)
+#endif // _MSC_VER
 
 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 result;
 	char fragment;
-	
+
 	result = state_in->result;
-	
+
 	switch (state_in->step)
 	{
 		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);
 			result  = (fragment & 0x03f) >> 0;
 			*codechar++ = base64_encode_value(result);
-			
+
 			++(state_in->stepcount);
 			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)
 {
 	char* codechar = code_out;
-	
+
 	switch (state_in->step)
 	{
 	case step_B:
@@ -106,8 +108,10 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
 		break;
 	}
 	*codechar++ = '\n';
-	
+
 	return (int)(codechar - code_out);
 }
 
+#ifdef _MSC_VER
 #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;
 }
 
+/// 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: get bone from stack
 /// 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) {
     const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
 
-    std::vector<aiNode *> nodes;
+    std::vector<PotentialNode> nodes;
     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);
 }
 
-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 Model::RotOrder rot = model.RotationOrder();
 
@@ -828,7 +831,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
                 chain[i] = chain[i].Inverse();
             }
 
-            aiNode *nd = new aiNode();
+            PotentialNode nd;
             nd->mName.Set(NameTransformationChainNode(name, comp));
             nd->mTransformation = chain[i];
 
@@ -836,9 +839,9 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
             if (comp == TransformationComp_GeometricScalingInverse ||
                     comp == TransformationComp_GeometricRotationInverse ||
                     comp == TransformationComp_GeometricTranslationInverse) {
-                post_output_nodes.push_back(nd);
+                post_output_nodes.emplace_back(std::move(nd));
             } 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
-    aiNode *nd = new aiNode();
-    output_nodes.push_back(nd);
+    PotentialNode nd;
 
     // name passed to the method is already unique
     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++) {
       nd->mTransformation = nd->mTransformation * chain[i];
     }
+    output_nodes.push_back(std::move(nd));
     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);

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

@@ -49,7 +49,9 @@ using namespace glTFCommon::Util;
 namespace Util {
 
 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) {
         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) {
-    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);

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

@@ -1124,6 +1124,14 @@ private:
     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
 
 // 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()) {
-        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];
 
     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()) {
-        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);
 
@@ -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
 
 template <class T>
@@ -766,11 +762,12 @@ void Accessor::ExtractData(T *&outData) {
     const size_t targetElemSize = sizeof(T);
 
     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];

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

@@ -1126,7 +1126,7 @@ void glTF2Exporter::MergeMeshes()
                         unsigned int meshIndex = meshRef.GetIndex();
 
                         if (meshIndex == removedIndex) {
-                            node->meshes.erase(curNode->meshes.begin() + mm);
+                            curNode->meshes.erase(curNode->meshes.begin() + mm);
                         } else if (meshIndex > removedIndex) {
                             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()) {
         // 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 count = meshOffsets[mesh_idx + 1] - meshOffsets[mesh_idx];
 

+ 4 - 1
code/CMakeLists.txt

@@ -1033,7 +1033,10 @@ ELSE()
   INCLUDE_DIRECTORIES( "../contrib" )
   INCLUDE_DIRECTORIES( "../contrib/pugixml/src" )
   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()
 
 # 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...
     }
 }

+ 4 - 4
contrib/Open3DGC/o3dgcSC3DMCDecoder.inl

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

+ 4 - 4
contrib/Open3DGC/o3dgcSC3DMCEncoder.inl

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

+ 2 - 0
contrib/Open3DGC/o3dgcTimer.h

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

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

@@ -18,8 +18,10 @@
 /* Win32, DOS, MSVC, MSVS */
 #include <direct.h>
 
+#ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable : 4706)
+#endif // _MSC_VER
 
 #define MKDIR(DIRNAME) _mkdir(DIRNAME)
 #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL)
@@ -968,4 +970,6 @@ out:
   return status;
 }
 
+#ifdef _MSC_VER
 #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
 #endif
 
-#ifdef _WIN32
+#ifdef _MSC_VER
 #pragma warning(disable : 4351)
-#endif // _WIN32
+#endif // _MSC_VER
 
 #include <assimp/aabb.h>
 #include <assimp/types.h>
@@ -458,8 +458,8 @@ struct aiAnimMesh {
      */
     unsigned int mNumVertices;
 
-    /** 
-     * Weight of the AnimMesh. 
+    /**
+     * Weight of the AnimMesh.
      */
     float mWeight;
 
@@ -713,8 +713,8 @@ struct aiMesh {
      *  Note! Currently only works with Collada loader.*/
     C_STRUCT aiAnimMesh **mAnimMeshes;
 
-    /** 
-     *  Method of morphing when animeshes are specified. 
+    /**
+     *  Method of morphing when animeshes are specified.
      */
     unsigned int mMethod;
 

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

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

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

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

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

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

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

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