Quellcode durchsuchen

Merge branch 'master' into master

Kim Kulling vor 4 Jahren
Ursprung
Commit
223372aaba

+ 5 - 5
code/AssetLib/FBX/FBXConverter.cpp

@@ -1715,14 +1715,14 @@ aiString FBXConverter::GetTexturePath(const Texture *tex) {
         bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
         unsigned int index=0;
 
-        VideoMap::const_iterator it = textures_converted.find(*media);
+        VideoMap::const_iterator it = textures_converted.find(media);
         if (it != textures_converted.end()) {
             index = (*it).second;
             textureReady = true;
         } else {
             if (media->ContentLength() > 0) {
                 index = ConvertVideo(*media);
-                textures_converted[*media] = index;
+                textures_converted[media] = index;
                 textureReady = true;
             }
         }
@@ -2221,12 +2221,12 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial *out_mat, const PropertyTa
             if (media != nullptr && media->ContentLength() > 0) {
                 unsigned int index;
 
-                VideoMap::const_iterator videoIt = textures_converted.find(*media);
+                VideoMap::const_iterator videoIt = textures_converted.find(media);
                 if (videoIt != textures_converted.end()) {
                     index = videoIt->second;
                 } else {
                     index = ConvertVideo(*media);
-                    textures_converted[*media] = index;
+                    textures_converted[media] = index;
                 }
 
                 // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
@@ -3493,7 +3493,7 @@ void FBXConverter::ConvertOrphanedEmbeddedTextures() {
             if (realTexture) {
                 const Video *media = realTexture->Media();
                 unsigned int index = ConvertVideo(*media);
-                textures_converted[*media] = index;
+                textures_converted[media] = index;
             }
         }
     }

+ 1 - 1
code/AssetLib/FBX/FBXConverter.h

@@ -428,7 +428,7 @@ private:
     using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>;
     MaterialMap materials_converted;
 
-    using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
+    using VideoMap = std::fbx_unordered_map<const Video*, unsigned int>;
     VideoMap textures_converted;
 
     using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >;

+ 0 - 35
code/AssetLib/FBX/FBXDocument.h

@@ -638,20 +638,6 @@ public:
         return ptr;
     }
 
-    bool operator==(const Video& other) const
-    {
-        return (
-               type == other.type
-            && relativeFileName == other.relativeFileName
-            && fileName == other.fileName
-        );
-    }
-
-    bool operator<(const Video& other) const
-    {
-        return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName);
-    }
-
 private:
     std::string type;
     std::string relativeFileName;
@@ -1192,25 +1178,4 @@ private:
 } // Namespace FBX
 } // Namespace Assimp
 
-namespace std
-{
-    template <>
-    struct hash<const Assimp::FBX::Video>
-    {
-        std::size_t operator()(const Assimp::FBX::Video& video) const
-        {
-            using std::size_t;
-            using std::hash;
-            using std::string;
-
-            size_t res = 17;
-            res = res * 31 + hash<string>()(video.Name());
-            res = res * 31 + hash<string>()(video.RelativeFilename());
-            res = res * 31 + hash<string>()(video.Type());
-
-            return res;
-        }
-    };
-}
-
 #endif // INCLUDED_AI_FBX_DOCUMENT_H

+ 40 - 8
code/AssetLib/FBX/FBXParser.cpp

@@ -641,7 +641,11 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
         ai_assert(data == end);
-        ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
+        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
         const uint32_t count3 = count / 3;
         out.reserve(count3);
@@ -728,7 +732,11 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
         ai_assert(data == end);
-        ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
+        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
         const uint32_t count4 = count / 4;
         out.reserve(count4);
@@ -807,7 +815,11 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
         ai_assert(data == end);
-        ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
+        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
         const uint32_t count2 = count / 2;
         out.reserve(count2);
@@ -879,7 +891,11 @@ void ParseVectorDataArray(std::vector<int>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
         ai_assert(data == end);
-        ai_assert(buff.size() == count * 4);
+        uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
         out.reserve(count);
 
@@ -937,7 +953,11 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
         ai_assert(data == end);
-        ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
+        uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
         if (type == 'd') {
             const double* d = reinterpret_cast<const double*>(&buff[0]);
@@ -998,7 +1018,11 @@ void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
         ai_assert(data == end);
-        ai_assert(buff.size() == count * 4);
+        uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
         out.reserve(count);
 
@@ -1063,7 +1087,11 @@ void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
         ai_assert(data == end);
-        ai_assert(buff.size() == count * 8);
+        uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
         out.reserve(count);
 
@@ -1121,7 +1149,11 @@ void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el)
         ReadBinaryDataArray(type, count, data, end, buff, el);
 
         ai_assert(data == end);
-        ai_assert(buff.size() == count * 8);
+        uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
+        ai_assert(buff.size() == dataToRead);
+        if (dataToRead > buff.size()) {
+            ParseError("Invalid read size (binary)",&el);
+        }
 
         out.reserve(count);
 

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

@@ -863,6 +863,7 @@ struct Sampler : public Object {
 };
 
 struct Scene : public Object {
+    std::string name;
     std::vector<Ref<Node>> nodes;
 
     Scene() {}

+ 5 - 0
code/AssetLib/glTF2/glTF2Asset.inl

@@ -1400,6 +1400,11 @@ inline void Node::Read(Value &obj, Asset &r) {
 }
 
 inline void Scene::Read(Value &obj, Asset &r) {
+    if (Value *scene_name = FindString(obj, "name")) {
+        if (scene_name->IsString()) {
+            this->name = scene_name->GetString();
+        }
+    }
     if (Value *array = FindArray(obj, "nodes")) {
         for (unsigned int i = 0; i < array->Size(); ++i) {
             if (!(*array)[i].IsUint()) continue;

+ 29 - 12
code/AssetLib/glTF2/glTF2Importer.cpp

@@ -453,11 +453,16 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
                 aim->mNumAnimMeshes = (unsigned int)targets.size();
                 aim->mAnimMeshes = new aiAnimMesh *[aim->mNumAnimMeshes];
                 for (size_t i = 0; i < targets.size(); i++) {
-                    aim->mAnimMeshes[i] = aiCreateAnimMesh(aim);
+                    bool needPositions = targets[i].position.size() > 0;
+                    bool needNormals = targets[i].normal.size() > 0;
+                    bool needTangents = targets[i].tangent.size() > 0;
+                    // GLTF morph does not support colors and texCoords
+                    aim->mAnimMeshes[i] = aiCreateAnimMesh(aim,
+                            needPositions, needNormals, needTangents, false, false);
                     aiAnimMesh &aiAnimMesh = *(aim->mAnimMeshes[i]);
                     Mesh::Primitive::Target &target = targets[i];
 
-                    if (target.position.size() > 0) {
+                    if (needPositions) {
                         aiVector3D *positionDiff = nullptr;
                         target.position[0]->ExtractData(positionDiff);
                         for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
@@ -465,7 +470,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
                         }
                         delete[] positionDiff;
                     }
-                    if (target.normal.size() > 0) {
+                    if (needNormals) {
                         aiVector3D *normalDiff = nullptr;
                         target.normal[0]->ExtractData(normalDiff);
                         for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
@@ -473,7 +478,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
                         }
                         delete[] normalDiff;
                     }
-                    if (target.tangent.size() > 0) {
+                    if (needTangents) {
                         Tangent *tangent = nullptr;
                         attr.tangent[0]->ExtractData(tangent);
 
@@ -1069,9 +1074,11 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler
         samplers.translation->output->ExtractData(values);
         anim->mNumPositionKeys = static_cast<uint32_t>(samplers.translation->input->count);
         anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
+        unsigned int ii = (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
         for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
             anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
-            anim->mPositionKeys[i].mValue = values[i];
+            anim->mPositionKeys[i].mValue = values[ii];
+            ii += (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1;
         }
         delete[] times;
         delete[] values;
@@ -1091,12 +1098,14 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler
         samplers.rotation->output->ExtractData(values);
         anim->mNumRotationKeys = static_cast<uint32_t>(samplers.rotation->input->count);
         anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
+        unsigned int ii = (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
         for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
             anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
-            anim->mRotationKeys[i].mValue.x = values[i].w;
-            anim->mRotationKeys[i].mValue.y = values[i].x;
-            anim->mRotationKeys[i].mValue.z = values[i].y;
-            anim->mRotationKeys[i].mValue.w = values[i].z;
+            anim->mRotationKeys[i].mValue.x = values[ii].w;
+            anim->mRotationKeys[i].mValue.y = values[ii].x;
+            anim->mRotationKeys[i].mValue.z = values[ii].y;
+            anim->mRotationKeys[i].mValue.w = values[ii].z;
+            ii += (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1;
         }
         delete[] times;
         delete[] values;
@@ -1117,9 +1126,11 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler
         samplers.scale->output->ExtractData(values);
         anim->mNumScalingKeys = static_cast<uint32_t>(samplers.scale->input->count);
         anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
+        unsigned int ii = (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
         for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) {
             anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
-            anim->mScalingKeys[i].mValue = values[i];
+            anim->mScalingKeys[i].mValue = values[ii];
+            ii += (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1;
         }
         delete[] times;
         delete[] values;
@@ -1148,11 +1159,14 @@ aiMeshMorphAnim *CreateMeshMorphAnim(glTF2::Asset&, Node &node, AnimationSampler
         samplers.weight->output->ExtractData(values);
         anim->mNumKeys = static_cast<uint32_t>(samplers.weight->input->count);
 
-        const unsigned int numMorphs = (unsigned int)samplers.weight->output->count / anim->mNumKeys;
+        // for Interpolation_CUBICSPLINE can have more outputs
+        const unsigned int weightStride = (unsigned int)samplers.weight->output->count / anim->mNumKeys;
+        const unsigned int numMorphs = (samplers.weight->interpolation == Interpolation_CUBICSPLINE) ? weightStride - 2 : weightStride;
 
         anim->mKeys = new aiMeshMorphKey[anim->mNumKeys];
-        unsigned int k = 0u;
+        unsigned int ii = (samplers.weight->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
         for (unsigned int i = 0u; i < anim->mNumKeys; ++i) {
+            unsigned int k = weightStride * i + ii;
             anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
             anim->mKeys[i].mNumValuesAndWeights = numMorphs;
             anim->mKeys[i].mValues = new unsigned int[numMorphs];
@@ -1386,6 +1400,9 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
     // read the asset file
     glTF2::Asset asset(pIOHandler);
     asset.Load(pFile, GetExtension(pFile) == "glb");
+    if (asset.scene) {
+        pScene->mName = asset.scene->name;
+    }
 
     //
     // Copy the data out

+ 21 - 17
code/Common/CreateAnimMesh.cpp

@@ -44,42 +44,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 namespace Assimp    {
 
-aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
+aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh, bool needPositions, bool needNormals, bool needTangents, bool needColors, bool needTexCoords)
 {
     aiAnimMesh *animesh = new aiAnimMesh;
     animesh->mNumVertices = mesh->mNumVertices;
-    if (mesh->mVertices) {
+    if (needPositions && mesh->mVertices) {
         animesh->mVertices = new aiVector3D[animesh->mNumVertices];
         std::memcpy(animesh->mVertices, mesh->mVertices, mesh->mNumVertices * sizeof(aiVector3D));
     }
-    if (mesh->mNormals) {
+    if (needNormals && mesh->mNormals) {
         animesh->mNormals = new aiVector3D[animesh->mNumVertices];
         std::memcpy(animesh->mNormals, mesh->mNormals, mesh->mNumVertices * sizeof(aiVector3D));
     }
-    if (mesh->mTangents) {
+    if (needTangents && mesh->mTangents) {
         animesh->mTangents = new aiVector3D[animesh->mNumVertices];
         std::memcpy(animesh->mTangents, mesh->mTangents, mesh->mNumVertices * sizeof(aiVector3D));
     }
-    if (mesh->mBitangents) {
+    if (needTangents && mesh->mBitangents) {
         animesh->mBitangents = new aiVector3D[animesh->mNumVertices];
         std::memcpy(animesh->mBitangents, mesh->mBitangents, mesh->mNumVertices * sizeof(aiVector3D));
     }
 
-    for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
-        if (mesh->mColors[i]) {
-            animesh->mColors[i] = new aiColor4D[animesh->mNumVertices];
-            std::memcpy(animesh->mColors[i], mesh->mColors[i], mesh->mNumVertices * sizeof(aiColor4D));
-        } else {
-            animesh->mColors[i] = nullptr;
+    if (needColors) {
+        for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
+            if (mesh->mColors[i]) {
+                animesh->mColors[i] = new aiColor4D[animesh->mNumVertices];
+                std::memcpy(animesh->mColors[i], mesh->mColors[i], mesh->mNumVertices * sizeof(aiColor4D));
+            } else {
+                animesh->mColors[i] = nullptr;
+            }
         }
     }
 
-    for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
-        if (mesh->mTextureCoords[i]) {
-            animesh->mTextureCoords[i] = new aiVector3D[animesh->mNumVertices];
-            std::memcpy(animesh->mTextureCoords[i], mesh->mTextureCoords[i], mesh->mNumVertices * sizeof(aiVector3D));
-        } else {
-            animesh->mTextureCoords[i] = nullptr;
+    if (needTexCoords) {
+        for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+            if (mesh->mTextureCoords[i]) {
+                animesh->mTextureCoords[i] = new aiVector3D[animesh->mNumVertices];
+                std::memcpy(animesh->mTextureCoords[i], mesh->mTextureCoords[i], mesh->mNumVertices * sizeof(aiVector3D));
+            } else {
+                animesh->mTextureCoords[i] = nullptr;
+            }
         }
     }
     return animesh;

+ 39 - 43
code/PostProcessing/FindDegenerates.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 Copyright (c) 2006-2020, assimp team
 
-
-
 All rights reserved.
 
 Redistribution and use of this software in source and binary forms,
@@ -45,25 +43,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Implementation of the FindDegenerates post-process step.
 */
 
-
-
-// internal headers
 #include "ProcessHelper.h"
 #include "FindDegenerates.h"
+
 #include <assimp/Exceptional.h>
 
+#include <unordered_map>
+
 using namespace Assimp;
 
-//remove mesh at position 'index' from the scene
-static void removeMesh(aiScene* pScene, unsigned const index);
-//correct node indices to meshes and remove references to deleted mesh
-static void updateSceneGraph(aiNode* pNode, unsigned const index);
+// Correct node indices to meshes and remove references to deleted mesh
+static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap);
 
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
-FindDegeneratesProcess::FindDegeneratesProcess()
-: mConfigRemoveDegenerates( false )
-, mConfigCheckAreaOfTriangle( false ){
+FindDegeneratesProcess::FindDegeneratesProcess() :
+        mConfigRemoveDegenerates( false ),
+        mConfigCheckAreaOfTriangle( false ){
     // empty
 }
 
@@ -91,50 +87,50 @@ void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
 // Executes the post processing step on the given imported data.
 void FindDegeneratesProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
-    for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
-    {
-        //Do not process point cloud, ExecuteOnMesh works only with faces data
+    if ( nullptr == pScene) {
+        return;
+    }
+    
+    std::unordered_map<unsigned int, unsigned int> meshMap;
+    meshMap.reserve(pScene->mNumMeshes);
+
+    const unsigned int originalNumMeshes = pScene->mNumMeshes;
+    unsigned int targetIndex = 0;
+    for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
+        // Do not process point cloud, ExecuteOnMesh works only with faces data
         if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
-            removeMesh(pScene, i);
-            --i; //the current i is removed, do not skip the next one
+            delete pScene->mMeshes[i];
+            // Not strictly required, but clean:
+            pScene->mMeshes[i] = nullptr;
+        } else {
+            meshMap[i] = targetIndex;
+            pScene->mMeshes[targetIndex] = pScene->mMeshes[i];
+            ++targetIndex;
         }
     }
-    ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
-}
+    pScene->mNumMeshes = targetIndex;
 
-static void removeMesh(aiScene* pScene, unsigned const index) {
-    //we start at index and copy the pointers one position forward
-    //save the mesh pointer to delete it later
-    auto delete_me = pScene->mMeshes[index];
-    for (unsigned i = index; i < pScene->mNumMeshes - 1; ++i) {
-        pScene->mMeshes[i] = pScene->mMeshes[i+1];
+    if (meshMap.size() < originalNumMeshes) {
+        updateSceneGraph(pScene->mRootNode, meshMap);
     }
-    pScene->mMeshes[pScene->mNumMeshes - 1] = nullptr;
-    --(pScene->mNumMeshes);
-    delete delete_me;
 
-    //removing a mesh also requires updating all references to it in the scene graph
-    updateSceneGraph(pScene->mRootNode, index);
+    ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
 }
 
-static void updateSceneGraph(aiNode* pNode, unsigned const index) {
+static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap) {
+    unsigned int targetIndex = 0;
     for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
-        if (pNode->mMeshes[i] > index) {
-            --(pNode->mMeshes[i]);
-            continue;
-        }
-        if (pNode->mMeshes[i] == index) {
-            for (unsigned j = i; j < pNode->mNumMeshes -1; ++j) {
-                pNode->mMeshes[j] = pNode->mMeshes[j+1];
-            }
-            --(pNode->mNumMeshes);
-            --i;
-            continue;
+        const unsigned int sourceMeshIndex = pNode->mMeshes[i];
+        auto it = meshMap.find(sourceMeshIndex);
+        if (it != meshMap.end()) {
+            pNode->mMeshes[targetIndex] = it->second;
+            ++targetIndex;
         }
     }
+    pNode->mNumMeshes = targetIndex;
     //recurse to all children
     for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
-        updateSceneGraph(pNode->mChildren[i], index);
+        updateSceneGraph(pNode->mChildren[i], meshMap);
     }
 }
 

+ 12 - 2
include/assimp/CreateAnimMesh.h

@@ -57,10 +57,20 @@ namespace Assimp {
 
 /**
  *  Create aiAnimMesh from aiMesh.
- *  @param  mesh    The input mesh to create an animated mesh from.
+ *  @param  mesh            The input mesh to create an animated mesh from.
+ *  @param  needPositions   If true, positions will be copied from.
+ *  @param  needNormals     If true, normals will be copied from.
+ *  @param  needTangents    If true, tangents and bitangents will be copied from.
+ *  @param  needColors      If true, colors will be copied from.
+ *  @param  needTexCoords   If true, texCoords will be copied from.
  *  @return The new created animated mesh.
  */
-ASSIMP_API aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh);
+ASSIMP_API aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh,
+                                        bool needPositions = true,
+                                        bool needNormals = true,
+                                        bool needTangents = true,
+                                        bool needColors = true,
+                                        bool needTexCoords = true);
 
 } // end of namespace Assimp
 

+ 5 - 2
include/assimp/scene.h

@@ -335,12 +335,15 @@ struct aiScene
     /**
      *  @brief  The global metadata assigned to the scene itself.
      *
-     *  This data contains global metadata which belongs to the scene like 
-     *  unit-conversions, versions, vendors or other model-specific data. This 
+     *  This data contains global metadata which belongs to the scene like
+     *  unit-conversions, versions, vendors or other model-specific data. This
      *  can be used to store format-specific metadata as well.
      */
     C_STRUCT aiMetadata* mMetaData;
 
+    /** The name of the scene itself.
+     */
+    C_STRUCT aiString mName;
 
 #ifdef __cplusplus
 

+ 59 - 0
test/unit/utFindDegenerates.cpp

@@ -40,8 +40,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 #include "UnitTestPCH.h"
 
+#include "../../include/assimp/scene.h"
 #include "PostProcessing/FindDegenerates.h"
 
+#include <memory>
+
 using namespace std;
 using namespace Assimp;
 
@@ -147,3 +150,59 @@ TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) {
 
     EXPECT_EQ(mMesh->mNumUVComponents[1] - 100, mMesh->mNumFaces);
 }
+
+namespace
+{
+    std::unique_ptr<aiMesh> getDegenerateMesh()
+    {
+        std::unique_ptr<aiMesh> mesh(new aiMesh);
+        mesh->mNumVertices = 2;
+        mesh->mVertices = new aiVector3D[2];
+        mesh->mVertices[0] = aiVector3D{ 0.0f, 0.0f, 0.0f };
+        mesh->mVertices[1] = aiVector3D{ 1.0f, 0.0f, 0.0f };
+        mesh->mNumFaces = 1;
+        mesh->mFaces = new aiFace[1];
+        mesh->mFaces[0].mNumIndices = 3;
+        mesh->mFaces[0].mIndices = new unsigned int[3];
+        mesh->mFaces[0].mIndices[0] = 0;
+        mesh->mFaces[0].mIndices[1] = 1;
+        mesh->mFaces[0].mIndices[2] = 0;
+        return mesh;
+    }
+}
+
+TEST_F(FindDegeneratesProcessTest, meshRemoval) {
+    mProcess->EnableAreaCheck(true);
+    mProcess->EnableInstantRemoval(true);
+    mProcess->ExecuteOnMesh(mMesh);
+
+    std::unique_ptr<aiScene> scene(new aiScene);
+    scene->mNumMeshes = 5;
+    scene->mMeshes = new aiMesh*[5];
+
+    /// Use the mesh which doesn't get completely stripped of faces from the main test.
+    aiMesh* meshWhichSurvives = mMesh;
+    mMesh = nullptr;
+
+    scene->mMeshes[0] = getDegenerateMesh().release();
+    scene->mMeshes[1] = getDegenerateMesh().release();
+    scene->mMeshes[2] = meshWhichSurvives;
+    scene->mMeshes[3] = getDegenerateMesh().release();
+    scene->mMeshes[4] = getDegenerateMesh().release();
+
+    scene->mRootNode = new aiNode;
+    scene->mRootNode->mNumMeshes = 5;
+    scene->mRootNode->mMeshes = new unsigned int[5];
+    scene->mRootNode->mMeshes[0] = 0;
+    scene->mRootNode->mMeshes[1] = 1;
+    scene->mRootNode->mMeshes[2] = 2;
+    scene->mRootNode->mMeshes[3] = 3;
+    scene->mRootNode->mMeshes[4] = 4;
+
+    mProcess->Execute(scene.get());    
+
+    EXPECT_EQ(scene->mNumMeshes, 1);
+    EXPECT_EQ(scene->mMeshes[0], meshWhichSurvives);
+    EXPECT_EQ(scene->mRootNode->mNumMeshes, 1);
+    EXPECT_EQ(scene->mRootNode->mMeshes[0], 0);    
+}