Browse Source

Merge pull request #3040 from Nimer-88/split_by_bone_count_infinite_loop

Fix for #3037 [FATAL] SplitByBoneCountProcess::SplitMesh goes into infinite loop
Kim Kulling 5 years ago
parent
commit
772774495c
1 changed files with 40 additions and 0 deletions
  1. 40 0
      code/Common/SplitByBoneCountProcess.cpp

+ 40 - 0
code/Common/SplitByBoneCountProcess.cpp

@@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include <limits>
 #include <limits>
 #include <assimp/TinyFormatter.h>
 #include <assimp/TinyFormatter.h>
+#include <assimp/Exceptional.h>
 
 
 using namespace Assimp;
 using namespace Assimp;
 using namespace Assimp::Formatter;
 using namespace Assimp::Formatter;
@@ -94,7 +95,10 @@ void SplitByBoneCountProcess::Execute( aiScene* pScene)
     bool isNecessary = false;
     bool isNecessary = false;
     for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
     for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
         if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount )
         if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount )
+        {
             isNecessary = true;
             isNecessary = true;
+            break;
+        }
 
 
     if( !isNecessary )
     if( !isNecessary )
     {
     {
@@ -155,7 +159,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
 {
 {
     // skip if not necessary
     // skip if not necessary
     if( pMesh->mNumBones <= mMaxBoneCount )
     if( pMesh->mNumBones <= mMaxBoneCount )
+    {
         return;
         return;
+    }
 
 
     // necessary optimisation: build a list of all affecting bones for each vertex
     // necessary optimisation: build a list of all affecting bones for each vertex
     // TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays
     // TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays
@@ -165,7 +171,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
     {
     {
         const aiBone* bone = pMesh->mBones[a];
         const aiBone* bone = pMesh->mBones[a];
         for( unsigned int b = 0; b < bone->mNumWeights; ++b)
         for( unsigned int b = 0; b < bone->mNumWeights; ++b)
+        {
             vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight));
             vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight));
+        }
     }
     }
 
 
     unsigned int numFacesHandled = 0;
     unsigned int numFacesHandled = 0;
@@ -189,7 +197,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         {
         {
             // skip if the face is already stored in a submesh
             // skip if the face is already stored in a submesh
             if( isFaceHandled[a] )
             if( isFaceHandled[a] )
+            {
                 continue;
                 continue;
+            }
 
 
             const aiFace& face = pMesh->mFaces[a];
             const aiFace& face = pMesh->mFaces[a];
             // check every vertex if its bones would still fit into the current submesh
             // check every vertex if its bones would still fit into the current submesh
@@ -201,17 +211,27 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
                     unsigned int boneIndex = vb[c].first;
                     unsigned int boneIndex = vb[c].first;
                     // if the bone is already used in this submesh, it's ok
                     // if the bone is already used in this submesh, it's ok
                     if( isBoneUsed[boneIndex] )
                     if( isBoneUsed[boneIndex] )
+                    {
                         continue;
                         continue;
+                    }
 
 
                     // if it's not used, yet, we would need to add it. Store its bone index
                     // if it's not used, yet, we would need to add it. Store its bone index
                     if( std::find( newBonesAtCurrentFace.begin(), newBonesAtCurrentFace.end(), boneIndex) == newBonesAtCurrentFace.end() )
                     if( std::find( newBonesAtCurrentFace.begin(), newBonesAtCurrentFace.end(), boneIndex) == newBonesAtCurrentFace.end() )
+                    {
                         newBonesAtCurrentFace.push_back( boneIndex);
                         newBonesAtCurrentFace.push_back( boneIndex);
+                    }
                 }
                 }
             }
             }
 
 
+            if (newBonesAtCurrentFace.size() > mMaxBoneCount)
+            {
+                throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!");
+            }
             // leave out the face if the new bones required for this face don't fit the bone count limit anymore
             // leave out the face if the new bones required for this face don't fit the bone count limit anymore
             if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount )
             if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount )
+            {
                 continue;
                 continue;
+            }
 
 
             // mark all new bones as necessary
             // mark all new bones as necessary
             while( !newBonesAtCurrentFace.empty() )
             while( !newBonesAtCurrentFace.empty() )
@@ -219,7 +239,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
                 unsigned int newIndex = newBonesAtCurrentFace.back();
                 unsigned int newIndex = newBonesAtCurrentFace.back();
                 newBonesAtCurrentFace.pop_back(); // this also avoids the deallocation which comes with a clear()
                 newBonesAtCurrentFace.pop_back(); // this also avoids the deallocation which comes with a clear()
                 if( isBoneUsed[newIndex] )
                 if( isBoneUsed[newIndex] )
+                {
                     continue;
                     continue;
+                }
 
 
                 isBoneUsed[newIndex] = true;
                 isBoneUsed[newIndex] = true;
                 numBones++;
                 numBones++;
@@ -237,7 +259,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         // create a new mesh to hold this subset of the source mesh
         // create a new mesh to hold this subset of the source mesh
         aiMesh* newMesh = new aiMesh;
         aiMesh* newMesh = new aiMesh;
         if( pMesh->mName.length > 0 )
         if( pMesh->mName.length > 0 )
+        {
             newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size());
             newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size());
+        }
         newMesh->mMaterialIndex = pMesh->mMaterialIndex;
         newMesh->mMaterialIndex = pMesh->mMaterialIndex;
         newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes;
         newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes;
         poNewMeshes.push_back( newMesh);
         poNewMeshes.push_back( newMesh);
@@ -247,7 +271,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
         newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
         newMesh->mVertices = new aiVector3D[newMesh->mNumVertices];
         newMesh->mVertices = new aiVector3D[newMesh->mNumVertices];
         if( pMesh->HasNormals() )
         if( pMesh->HasNormals() )
+        {
             newMesh->mNormals = new aiVector3D[newMesh->mNumVertices];
             newMesh->mNormals = new aiVector3D[newMesh->mNumVertices];
+        }
         if( pMesh->HasTangentsAndBitangents() )
         if( pMesh->HasTangentsAndBitangents() )
         {
         {
             newMesh->mTangents = new aiVector3D[newMesh->mNumVertices];
             newMesh->mTangents = new aiVector3D[newMesh->mNumVertices];
@@ -256,13 +282,17 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
         for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
         {
         {
             if( pMesh->HasTextureCoords( a) )
             if( pMesh->HasTextureCoords( a) )
+            {
                 newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices];
                 newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices];
+            }
             newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
             newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
         }
         }
         for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
         for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
         {
         {
             if( pMesh->HasVertexColors( a) )
             if( pMesh->HasVertexColors( a) )
+            {
                 newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices];
                 newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices];
+            }
         }
         }
 
 
         // and copy over the data, generating faces with linear indices along the way
         // and copy over the data, generating faces with linear indices along the way
@@ -285,7 +315,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
 
 
                 newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
                 newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
                 if( pMesh->HasNormals() )
                 if( pMesh->HasNormals() )
+                {
                     newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
                     newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
+                }
                 if( pMesh->HasTangentsAndBitangents() )
                 if( pMesh->HasTangentsAndBitangents() )
                 {
                 {
                     newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
                     newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
@@ -294,12 +326,16 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
                 for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c )
                 for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c )
                 {
                 {
                     if( pMesh->HasTextureCoords( c) )
                     if( pMesh->HasTextureCoords( c) )
+                    {
                         newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
                         newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
+                    }
                 }
                 }
                 for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c )
                 for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c )
                 {
                 {
                     if( pMesh->HasVertexColors( c) )
                     if( pMesh->HasVertexColors( c) )
+                    {
                         newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
                         newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
+                    }
                 }
                 }
 
 
                 nvi++;
                 nvi++;
@@ -316,7 +352,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
         for( unsigned int a = 0; a < pMesh->mNumBones; ++a )
         for( unsigned int a = 0; a < pMesh->mNumBones; ++a )
         {
         {
             if( !isBoneUsed[a] )
             if( !isBoneUsed[a] )
+            {
                 continue;
                 continue;
+            }
 
 
             // create the new bone
             // create the new bone
             const aiBone* srcBone = pMesh->mBones[a];
             const aiBone* srcBone = pMesh->mBones[a];
@@ -340,7 +378,9 @@ void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh
             {
             {
                 unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
                 unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
                 if( newBoneIndex != std::numeric_limits<unsigned int>::max() )
                 if( newBoneIndex != std::numeric_limits<unsigned int>::max() )
+                {
                     newMesh->mBones[newBoneIndex]->mNumWeights++;
                     newMesh->mBones[newBoneIndex]->mNumWeights++;
+                }
             }
             }
         }
         }