diff --git a/code/PostProcessing/LimitBoneWeightsProcess.cpp b/code/PostProcessing/LimitBoneWeightsProcess.cpp index 012897391..09ccc51b3 100644 --- a/code/PostProcessing/LimitBoneWeightsProcess.cpp +++ b/code/PostProcessing/LimitBoneWeightsProcess.cpp @@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "LimitBoneWeightsProcess.h" +#include #include #include #include @@ -52,150 +53,140 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; - // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer LimitBoneWeightsProcess::LimitBoneWeightsProcess() { - mMaxWeights = AI_LMW_MAX_WEIGHTS; + mMaxWeights = AI_LMW_MAX_WEIGHTS; } // ------------------------------------------------------------------------------------------------ // Destructor, private as well LimitBoneWeightsProcess::~LimitBoneWeightsProcess() { - // nothing to do here + // nothing to do here } // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_LimitBoneWeights) != 0; + return (pFlags & aiProcess_LimitBoneWeights) != 0; } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void LimitBoneWeightsProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin"); - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a ) { - ProcessMesh(pScene->mMeshes[a]); - } +void LimitBoneWeightsProcess::Execute( aiScene* pScene) +{ + ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin"); - ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end"); + for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) { + ProcessMesh(pScene->mMeshes[m]); + } + + ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end"); } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) { - // get the current value of the property - this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS); + // get the current value of the property + this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS); } // ------------------------------------------------------------------------------------------------ // Unites identical vertices in the given mesh -void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh) +void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) { - if( !pMesh->HasBones()) - return; + if (!pMesh->HasBones()) + return; - // collect all bone weights per vertex - typedef std::vector< std::vector< Weight > > WeightsPerVertex; - WeightsPerVertex vertexWeights( pMesh->mNumVertices); + // collect all bone weights per vertex + typedef SmallVector VertexWeightArray; + typedef std::vector WeightsPerVertex; + WeightsPerVertex vertexWeights(pMesh->mNumVertices); + size_t maxVertexWeights = 0; - // collect all weights per vertex - for( unsigned int a = 0; a < pMesh->mNumBones; a++) - { - const aiBone* bone = pMesh->mBones[a]; - for( unsigned int b = 0; b < bone->mNumWeights; b++) - { - const aiVertexWeight& w = bone->mWeights[b]; - vertexWeights[w.mVertexId].emplace_back( a, w.mWeight); - } - } + for (unsigned int b = 0; b < pMesh->mNumBones; ++b) + { + const aiBone* bone = pMesh->mBones[b]; + for (unsigned int w = 0; w < bone->mNumWeights; ++w) + { + const aiVertexWeight& vw = bone->mWeights[w]; + vertexWeights[vw.mVertexId].push_back(Weight(b, vw.mWeight)); + maxVertexWeights = std::max(maxVertexWeights, vertexWeights[vw.mVertexId].size()); + } + } - unsigned int removed = 0, old_bones = pMesh->mNumBones; + if (maxVertexWeights <= mMaxWeights) + return; - // now cut the weight count if it exceeds the maximum - bool bChanged = false; - for( WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) - { - if( vit->size() <= mMaxWeights) - continue; + unsigned int removed = 0, old_bones = pMesh->mNumBones; - bChanged = true; + // now cut the weight count if it exceeds the maximum + for (WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) + { + if (vit->size() <= mMaxWeights) + continue; - // more than the defined maximum -> first sort by weight in descending order. That's - // why we defined the < operator in such a weird way. - std::sort( vit->begin(), vit->end()); + // more than the defined maximum -> first sort by weight in descending order. That's + // why we defined the < operator in such a weird way. + std::sort(vit->begin(), vit->end()); - // now kill everything beyond the maximum count - unsigned int m = static_cast(vit->size()); - vit->erase( vit->begin() + mMaxWeights, vit->end()); - removed += static_cast(m-vit->size()); + // now kill everything beyond the maximum count + unsigned int m = static_cast(vit->size()); + vit->resize(mMaxWeights); + removed += static_cast(m - vit->size()); - // and renormalize the weights - float sum = 0.0f; - for( std::vector::const_iterator it = vit->begin(); it != vit->end(); ++it ) { - sum += it->mWeight; - } - if( 0.0f != sum ) { - const float invSum = 1.0f / sum; - for( std::vector::iterator it = vit->begin(); it != vit->end(); ++it ) { - it->mWeight *= invSum; - } - } - } + // and renormalize the weights + float sum = 0.0f; + for(const Weight* it = vit->begin(); it != vit->end(); ++it) { + sum += it->mWeight; + } + if (0.0f != sum) { + const float invSum = 1.0f / sum; + for(Weight* it = vit->begin(); it != vit->end(); ++it) { + it->mWeight *= invSum; + } + } + } - if (bChanged) { - // rebuild the vertex weight array for all bones - typedef std::vector< std::vector< aiVertexWeight > > WeightsPerBone; - WeightsPerBone boneWeights( pMesh->mNumBones); - for( unsigned int a = 0; a < vertexWeights.size(); a++) - { - const std::vector& vw = vertexWeights[a]; - for( std::vector::const_iterator it = vw.begin(); it != vw.end(); ++it) - boneWeights[it->mBone].emplace_back( a, it->mWeight); - } + // clear weight count for all bone + for (unsigned int a = 0; a < pMesh->mNumBones; ++a) + { + pMesh->mBones[a]->mNumWeights = 0; + } - // and finally copy the vertex weight list over to the mesh's bones - std::vector abNoNeed(pMesh->mNumBones,false); - bChanged = false; + // rebuild the vertex weight array for all bones + for (unsigned int a = 0; a < vertexWeights.size(); ++a) + { + const VertexWeightArray& vw = vertexWeights[a]; + for (const Weight* it = vw.begin(); it != vw.end(); ++it) + { + aiBone* bone = pMesh->mBones[it->mBone]; + bone->mWeights[bone->mNumWeights++] = aiVertexWeight(a, it->mWeight); + } + } - for( unsigned int a = 0; a < pMesh->mNumBones; a++) - { - const std::vector& bw = boneWeights[a]; - aiBone* bone = pMesh->mBones[a]; + // remove empty bones + unsigned int writeBone = 0; - if ( bw.empty() ) - { - abNoNeed[a] = bChanged = true; - continue; - } + for (unsigned int readBone = 0; readBone< pMesh->mNumBones; ++readBone) + { + aiBone* bone = pMesh->mBones[readBone]; + if (bone->mNumWeights > 0) + { + pMesh->mBones[writeBone++] = bone; + } + else + { + delete bone; + } + } + pMesh->mNumBones = writeBone; - // copy the weight list. should always be less weights than before, so we don't need a new allocation - ai_assert( bw.size() <= bone->mNumWeights); - bone->mNumWeights = static_cast( bw.size() ); - ::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight)); - } - - if (bChanged) { - // the number of new bones is smaller than before, so we can reuse the old array - aiBone** ppcCur = pMesh->mBones;aiBone** ppcSrc = ppcCur; - - for (std::vector::const_iterator iter = abNoNeed.begin();iter != abNoNeed.end() ;++iter) { - if (*iter) { - delete *ppcSrc; - --pMesh->mNumBones; - } - else *ppcCur++ = *ppcSrc; - ++ppcSrc; - } - } - - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones ); - } - } + if (!DefaultLogger::isNullLogger()) { + ASSIMP_LOG_INFO_F("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones); + } }