Browse Source

Merge branch 'master' into fbxExceptionSafety

Kim Kulling 4 years ago
parent
commit
fe78310486

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

@@ -863,6 +863,7 @@ struct Sampler : public Object {
 };
 };
 
 
 struct Scene : public Object {
 struct Scene : public Object {
+    std::string name;
     std::vector<Ref<Node>> nodes;
     std::vector<Ref<Node>> nodes;
 
 
     Scene() {}
     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) {
 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")) {
     if (Value *array = FindArray(obj, "nodes")) {
         for (unsigned int i = 0; i < array->Size(); ++i) {
         for (unsigned int i = 0; i < array->Size(); ++i) {
             if (!(*array)[i].IsUint()) continue;
             if (!(*array)[i].IsUint()) continue;

+ 3 - 0
code/AssetLib/glTF2/glTF2Importer.cpp

@@ -1386,6 +1386,9 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
     // read the asset file
     // read the asset file
     glTF2::Asset asset(pIOHandler);
     glTF2::Asset asset(pIOHandler);
     asset.Load(pFile, GetExtension(pFile) == "glb");
     asset.Load(pFile, GetExtension(pFile) == "glb");
+    if (asset.scene) {
+        pScene->mName = asset.scene->name;
+    }
 
 
     //
     //
     // Copy the data out
     // Copy the data out

+ 39 - 43
code/PostProcessing/FindDegenerates.cpp

@@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
 
 
 Copyright (c) 2006-2020, assimp team
 Copyright (c) 2006-2020, assimp team
 
 
-
-
 All rights reserved.
 All rights reserved.
 
 
 Redistribution and use of this software in source and binary forms,
 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.
  *  @brief Implementation of the FindDegenerates post-process step.
 */
 */
 
 
-
-
-// internal headers
 #include "ProcessHelper.h"
 #include "ProcessHelper.h"
 #include "FindDegenerates.h"
 #include "FindDegenerates.h"
+
 #include <assimp/Exceptional.h>
 #include <assimp/Exceptional.h>
 
 
+#include <unordered_map>
+
 using namespace Assimp;
 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
 // Constructor to be privately used by Importer
-FindDegeneratesProcess::FindDegeneratesProcess()
-: mConfigRemoveDegenerates( false )
-, mConfigCheckAreaOfTriangle( false ){
+FindDegeneratesProcess::FindDegeneratesProcess() :
+        mConfigRemoveDegenerates( false ),
+        mConfigCheckAreaOfTriangle( false ){
     // empty
     // empty
 }
 }
 
 
@@ -91,50 +87,50 @@ void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
 // Executes the post processing step on the given imported data.
 // Executes the post processing step on the given imported data.
 void FindDegeneratesProcess::Execute( aiScene* pScene) {
 void FindDegeneratesProcess::Execute( aiScene* pScene) {
     ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
     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])) {
         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) {
     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
     //recurse to all children
     for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
     for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
-        updateSceneGraph(pNode->mChildren[i], index);
+        updateSceneGraph(pNode->mChildren[i], meshMap);
     }
     }
 }
 }
 
 

+ 5 - 2
include/assimp/scene.h

@@ -335,12 +335,15 @@ struct aiScene
     /**
     /**
      *  @brief  The global metadata assigned to the scene itself.
      *  @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.
      *  can be used to store format-specific metadata as well.
      */
      */
     C_STRUCT aiMetadata* mMetaData;
     C_STRUCT aiMetadata* mMetaData;
 
 
+    /** The name of the scene itself.
+     */
+    C_STRUCT aiString mName;
 
 
 #ifdef __cplusplus
 #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 "UnitTestPCH.h"
 
 
+#include "../../include/assimp/scene.h"
 #include "PostProcessing/FindDegenerates.h"
 #include "PostProcessing/FindDegenerates.h"
 
 
+#include <memory>
+
 using namespace std;
 using namespace std;
 using namespace Assimp;
 using namespace Assimp;
 
 
@@ -147,3 +150,59 @@ TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) {
 
 
     EXPECT_EQ(mMesh->mNumUVComponents[1] - 100, mMesh->mNumFaces);
     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);    
+}