170 lines
6.1 KiB
C++
170 lines
6.1 KiB
C++
/*
|
|
Open Asset Import Library (ASSIMP)
|
|
----------------------------------------------------------------------
|
|
|
|
Copyright (c) 2006-2008, ASSIMP Development Team
|
|
All rights reserved.
|
|
|
|
Redistribution and use of this software in source and binary forms,
|
|
with or without modification, are permitted provided that the
|
|
following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above
|
|
copyright notice, this list of conditions and the
|
|
following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above
|
|
copyright notice, this list of conditions and the
|
|
following disclaimer in the documentation and/or other
|
|
materials provided with the distribution.
|
|
|
|
* Neither the name of the ASSIMP team, nor the names of its
|
|
contributors may be used to endorse or promote products
|
|
derived from this software without specific prior
|
|
written permission of the ASSIMP Development Team.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
----------------------------------------------------------------------
|
|
*/
|
|
|
|
/** Implementation of the LimitBoneWeightsProcess post processing step */
|
|
|
|
#include <vector>
|
|
#include <assert.h>
|
|
|
|
#include "LimitBoneWeightsProcess.h"
|
|
|
|
#include "../include/aiPostProcess.h"
|
|
#include "../include/aiMesh.h"
|
|
#include "../include/aiScene.h"
|
|
#include "../include/DefaultLogger.h"
|
|
|
|
using namespace Assimp;
|
|
|
|
|
|
/*static*/ unsigned int LimitBoneWeightsProcess::mMaxWeights = AI_LMW_MAX_WEIGHTS;
|
|
|
|
extern "C" {
|
|
// ------------------------------------------------------------------------------------------------
|
|
aiReturn aiSetBoneWeightLimit(unsigned int pLimit)
|
|
{
|
|
if (0 == pLimit)
|
|
{
|
|
LimitBoneWeightsProcess::mMaxWeights = 0xFFFFFFFF;
|
|
return AI_FAILURE;
|
|
}
|
|
|
|
LimitBoneWeightsProcess::mMaxWeights = pLimit;
|
|
DefaultLogger::get()->debug("aiSetBoneWeightLimit() - bone weight limit was changed");
|
|
return AI_SUCCESS;
|
|
}
|
|
};
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Constructor to be privately used by Importer
|
|
LimitBoneWeightsProcess::LimitBoneWeightsProcess()
|
|
{
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Destructor, private as well
|
|
LimitBoneWeightsProcess::~LimitBoneWeightsProcess()
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Executes the post processing step on the given imported data.
|
|
void LimitBoneWeightsProcess::Execute( aiScene* pScene)
|
|
{
|
|
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
|
ProcessMesh( pScene->mMeshes[a]);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------
|
|
// Unites identical vertices in the given mesh
|
|
void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
|
|
{
|
|
if( !pMesh->HasBones())
|
|
return;
|
|
|
|
// collect all bone weights per vertex
|
|
typedef std::vector< std::vector< Weight > > WeightsPerVertex;
|
|
WeightsPerVertex vertexWeights( pMesh->mNumVertices);
|
|
|
|
// 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].push_back( Weight( a, w.mWeight));
|
|
}
|
|
}
|
|
|
|
// 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());
|
|
|
|
// now kill everything beyond the maximum count
|
|
vit->erase( vit->begin() + mMaxWeights, vit->end());
|
|
|
|
// and renormalize the weights
|
|
float sum = 0.0f;
|
|
for( std::vector<Weight>::const_iterator it = vit->begin(); it != vit->end(); ++it)
|
|
sum += it->mWeight;
|
|
for( std::vector<Weight>::iterator it = vit->begin(); it != vit->end(); ++it)
|
|
it->mWeight /= sum;
|
|
}
|
|
|
|
// 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<Weight>& vw = vertexWeights[a];
|
|
for( std::vector<Weight>::const_iterator it = vw.begin(); it != vw.end(); ++it)
|
|
boneWeights[it->mBone].push_back( aiVertexWeight( a, it->mWeight));
|
|
}
|
|
|
|
// and finally copy the vertex weight list over to the mesh's bones
|
|
for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
|
{
|
|
const std::vector<aiVertexWeight>& bw = boneWeights[a];
|
|
aiBone* bone = pMesh->mBones[a];
|
|
// ignore the bone if no vertex weights were removed there
|
|
if( bw.size() == bone->mNumWeights)
|
|
continue;
|
|
|
|
// copy the weight list. should always be less weights than before, so we don't need a new allocation
|
|
assert( bw.size() < bone->mNumWeights);
|
|
bone->mNumWeights = (unsigned int) bw.size();
|
|
memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
|
|
}
|
|
}
|