vrshoot

diff libs/assimp/DeboneProcess.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libs/assimp/DeboneProcess.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,464 @@
     1.4 +									 /*
     1.5 +Open Asset Import Library (assimp)
     1.6 +----------------------------------------------------------------------
     1.7 +
     1.8 +Copyright (c) 2006-2012, assimp team
     1.9 +All rights reserved.
    1.10 +
    1.11 +Redistribution and use of this software in source and binary forms, 
    1.12 +with or without modification, are permitted provided that the 
    1.13 +following conditions are met:
    1.14 +
    1.15 +* Redistributions of source code must retain the above
    1.16 +  copyright notice, this list of conditions and the
    1.17 +  following disclaimer.
    1.18 +
    1.19 +* Redistributions in binary form must reproduce the above
    1.20 +  copyright notice, this list of conditions and the
    1.21 +  following disclaimer in the documentation and/or other
    1.22 +  materials provided with the distribution.
    1.23 +
    1.24 +* Neither the name of the assimp team, nor the names of its
    1.25 +  contributors may be used to endorse or promote products
    1.26 +  derived from this software without specific prior
    1.27 +  written permission of the assimp team.
    1.28 +
    1.29 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    1.30 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    1.31 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.32 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    1.33 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.34 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    1.35 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.36 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
    1.37 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    1.38 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    1.39 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.40 +
    1.41 +----------------------------------------------------------------------
    1.42 +*/
    1.43 +
    1.44 +/// @file DeboneProcess.cpp
    1.45 +/** Implementation of the DeboneProcess post processing step */
    1.46 +
    1.47 +#include "AssimpPCH.h"
    1.48 +
    1.49 +// internal headers of the post-processing framework
    1.50 +#include "ProcessHelper.h"
    1.51 +#include "DeboneProcess.h"
    1.52 +
    1.53 +
    1.54 +using namespace Assimp;
    1.55 +
    1.56 +// ------------------------------------------------------------------------------------------------
    1.57 +// Constructor to be privately used by Importer
    1.58 +DeboneProcess::DeboneProcess()
    1.59 +{
    1.60 +	mNumBones = 0;
    1.61 +	mNumBonesCanDoWithout = 0;
    1.62 +
    1.63 +	mThreshold = AI_DEBONE_THRESHOLD;
    1.64 +	mAllOrNone = false;
    1.65 +}
    1.66 +
    1.67 +// ------------------------------------------------------------------------------------------------
    1.68 +// Destructor, private as well
    1.69 +DeboneProcess::~DeboneProcess()
    1.70 +{
    1.71 +	// nothing to do here
    1.72 +}
    1.73 +
    1.74 +// ------------------------------------------------------------------------------------------------
    1.75 +// Returns whether the processing step is present in the given flag field.
    1.76 +bool DeboneProcess::IsActive( unsigned int pFlags) const
    1.77 +{
    1.78 +	return (pFlags & aiProcess_Debone) != 0;
    1.79 +}
    1.80 +
    1.81 +// ------------------------------------------------------------------------------------------------
    1.82 +// Executes the post processing step on the given imported data.
    1.83 +void DeboneProcess::SetupProperties(const Importer* pImp)
    1.84 +{	
    1.85 +	// get the current value of the property
    1.86 +	mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false;
    1.87 +	mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD);
    1.88 +}
    1.89 +
    1.90 +// ------------------------------------------------------------------------------------------------
    1.91 +// Executes the post processing step on the given imported data.
    1.92 +void DeboneProcess::Execute( aiScene* pScene)
    1.93 +{
    1.94 +	DefaultLogger::get()->debug("DeboneProcess begin");
    1.95 +
    1.96 +	if(!pScene->mNumMeshes) {
    1.97 +		return;
    1.98 +	}
    1.99 +
   1.100 +	std::vector<bool> splitList(pScene->mNumMeshes); 
   1.101 +	for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
   1.102 +		splitList[a] = ConsiderMesh( pScene->mMeshes[a] );
   1.103 +	}
   1.104 +
   1.105 +	int numSplits = 0; 
   1.106 +
   1.107 +	if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones))	{
   1.108 +		for(unsigned int a = 0; a < pScene->mNumMeshes; a++)	{
   1.109 +			if(splitList[a]) {
   1.110 +				numSplits++;
   1.111 +			}
   1.112 +		}
   1.113 +	}
   1.114 +
   1.115 +	if(numSplits)	{
   1.116 +		// we need to do something. Let's go.
   1.117 +		mSubMeshIndices.clear();
   1.118 +		mSubMeshIndices.resize(pScene->mNumMeshes);
   1.119 +
   1.120 +		// build a new array of meshes for the scene
   1.121 +		std::vector<aiMesh*> meshes;
   1.122 +
   1.123 +		for(unsigned int a=0;a<pScene->mNumMeshes;a++)
   1.124 +		{
   1.125 +			aiMesh* srcMesh = pScene->mMeshes[a];
   1.126 +
   1.127 +			std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes;
   1.128 +
   1.129 +			if(splitList[a]) { 
   1.130 +				SplitMesh(srcMesh,newMeshes);
   1.131 +			}
   1.132 +
   1.133 +			// mesh was split
   1.134 +			if(!newMeshes.empty())	{				
   1.135 +				unsigned int out = 0, in = srcMesh->mNumBones;				
   1.136 +
   1.137 +				// store new meshes and indices of the new meshes
   1.138 +				for(unsigned int b=0;b<newMeshes.size();b++)	{						
   1.139 +					const aiString *find = newMeshes[b].second?&newMeshes[b].second->mName:0;
   1.140 +
   1.141 +					aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0;
   1.142 +					std::pair<unsigned int,aiNode*> push_pair(meshes.size(),theNode);
   1.143 +
   1.144 +					mSubMeshIndices[a].push_back(push_pair);
   1.145 +					meshes.push_back(newMeshes[b].first);
   1.146 +
   1.147 +					out+=newMeshes[b].first->mNumBones;
   1.148 +				}
   1.149 +						   
   1.150 +				if(!DefaultLogger::isNullLogger()) {
   1.151 +					char buffer[1024];
   1.152 +					::sprintf(buffer,"Removed %i bones. Input bones: %i. Output bones: %i",in-out,in,out);
   1.153 +					DefaultLogger::get()->info(buffer);
   1.154 +				}
   1.155 +
   1.156 +				// and destroy the source mesh. It should be completely contained inside the new submeshes
   1.157 +				delete srcMesh;
   1.158 +			}
   1.159 +			else	{
   1.160 +				// Mesh is kept unchanged - store it's new place in the mesh array
   1.161 +				mSubMeshIndices[a].push_back(std::pair<unsigned int,aiNode*>(meshes.size(),(aiNode*)0));
   1.162 +				meshes.push_back(srcMesh);
   1.163 +			}
   1.164 +		}	
   1.165 +			
   1.166 +		// rebuild the scene's mesh array
   1.167 +		pScene->mNumMeshes = meshes.size();
   1.168 +		delete [] pScene->mMeshes;
   1.169 +		pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
   1.170 +		std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
   1.171 +
   1.172 +		// recurse through all nodes and translate the node's mesh indices to fit the new mesh array
   1.173 +		UpdateNode( pScene->mRootNode);
   1.174 +	}
   1.175 +
   1.176 +	DefaultLogger::get()->debug("DeboneProcess end");
   1.177 +}
   1.178 +
   1.179 +// ------------------------------------------------------------------------------------------------
   1.180 +// Counts bones total/removable in a given mesh.
   1.181 +bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
   1.182 +{
   1.183 +	if(!pMesh->HasBones()) {
   1.184 +		return false;
   1.185 +	}
   1.186 +
   1.187 +	bool split = false;
   1.188 +
   1.189 +	//interstitial faces not permitted
   1.190 +	bool isInterstitialRequired = false;
   1.191 +
   1.192 +	std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
   1.193 +	std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
   1.194 +
   1.195 +	const unsigned int cUnowned = UINT_MAX;
   1.196 +	const unsigned int cCoowned = UINT_MAX-1;
   1.197 +
   1.198 +	for(unsigned int i=0;i<pMesh->mNumBones;i++)	{
   1.199 +		for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++)	{
   1.200 +			float w = pMesh->mBones[i]->mWeights[j].mWeight;
   1.201 +
   1.202 +			if(w==0.0f) {
   1.203 +				continue;
   1.204 +			}
   1.205 +
   1.206 +			unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
   1.207 +			if(w>=mThreshold)	{
   1.208 +
   1.209 +				if(vertexBones[vid]!=cUnowned)	{
   1.210 +					if(vertexBones[vid]==i) //double entry
   1.211 +					{
   1.212 +						DefaultLogger::get()->warn("Encountered double entry in bone weights");					
   1.213 +					}
   1.214 +					else //TODO: track attraction in order to break tie
   1.215 +					{
   1.216 +						vertexBones[vid] = cCoowned;
   1.217 +					}
   1.218 +				}
   1.219 +				else vertexBones[vid] = i;			
   1.220 +			}
   1.221 +
   1.222 +			if(!isBoneNecessary[i]) {
   1.223 +				isBoneNecessary[i] = w<mThreshold;
   1.224 +			}
   1.225 +		}
   1.226 +
   1.227 +		if(!isBoneNecessary[i])  {
   1.228 +			isInterstitialRequired = true;
   1.229 +		}
   1.230 +	}
   1.231 +
   1.232 +	if(isInterstitialRequired) {
   1.233 +		for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
   1.234 +			unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
   1.235 +
   1.236 +			for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
   1.237 +				unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
   1.238 +
   1.239 +				if(v!=w)	{
   1.240 +					if(v<pMesh->mNumBones) isBoneNecessary[v] = true; 
   1.241 +					if(w<pMesh->mNumBones) isBoneNecessary[w] = true; 
   1.242 +				}
   1.243 +			}
   1.244 +		}
   1.245 +	}
   1.246 +
   1.247 +	for(unsigned int i=0;i<pMesh->mNumBones;i++)	{
   1.248 +		if(!isBoneNecessary[i])	{
   1.249 +			mNumBonesCanDoWithout++; 
   1.250 +			split = true;
   1.251 +		}
   1.252 +		
   1.253 +		mNumBones++;
   1.254 +	}
   1.255 +	return split;
   1.256 +}
   1.257 +
   1.258 +// ------------------------------------------------------------------------------------------------
   1.259 +// Splits the given mesh by bone count.
   1.260 +void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const
   1.261 +{
   1.262 +	// same deal here as ConsiderMesh basically
   1.263 +
   1.264 +	std::vector<bool> isBoneNecessary(pMesh->mNumBones,false);
   1.265 +	std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX);
   1.266 +
   1.267 +	const unsigned int cUnowned = UINT_MAX;
   1.268 +	const unsigned int cCoowned = UINT_MAX-1;
   1.269 +
   1.270 +	for(unsigned int i=0;i<pMesh->mNumBones;i++)	{
   1.271 +		for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++)	{
   1.272 +			float w = pMesh->mBones[i]->mWeights[j].mWeight;
   1.273 +
   1.274 +			if(w==0.0f) {
   1.275 +				continue;
   1.276 +			}
   1.277 +
   1.278 +			unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId;
   1.279 +
   1.280 +			if(w>=mThreshold) {
   1.281 +				if(vertexBones[vid]!=cUnowned)  {
   1.282 +					if(vertexBones[vid]==i) //double entry
   1.283 +					{
   1.284 +						//DefaultLogger::get()->warn("Encountered double entry in bone weights");					
   1.285 +					}
   1.286 +					else //TODO: track attraction in order to break tie
   1.287 +					{
   1.288 +						vertexBones[vid] = cCoowned;
   1.289 +					}
   1.290 +				}
   1.291 +				else vertexBones[vid] = i;			
   1.292 +			}
   1.293 +
   1.294 +			if(!isBoneNecessary[i]) {
   1.295 +				isBoneNecessary[i] = w<mThreshold;
   1.296 +			}
   1.297 +		}
   1.298 +	}
   1.299 +
   1.300 +	unsigned int nFacesUnowned = 0;
   1.301 +
   1.302 +	std::vector<unsigned int> faceBones(pMesh->mNumFaces,UINT_MAX);
   1.303 +	std::vector<unsigned int> facesPerBone(pMesh->mNumBones,0);
   1.304 +
   1.305 +	for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
   1.306 +		unsigned int nInterstitial = 1;
   1.307 +
   1.308 +		unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]];
   1.309 +
   1.310 +		for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) {
   1.311 +			unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]];
   1.312 +
   1.313 +			if(v!=w)	{
   1.314 +				if(v<pMesh->mNumBones) isBoneNecessary[v] = true; 
   1.315 +				if(w<pMesh->mNumBones) isBoneNecessary[w] = true; 
   1.316 +			}
   1.317 +			else nInterstitial++;
   1.318 +		}
   1.319 +
   1.320 +		if(v<pMesh->mNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices)	{				
   1.321 +			faceBones[i] = v; //primitive belongs to bone #v
   1.322 +			facesPerBone[v]++;
   1.323 +		}
   1.324 +		else nFacesUnowned++; 
   1.325 +	}
   1.326 +
   1.327 +	// invalidate any "cojoined" faces
   1.328 +	for(unsigned int i=0;i<pMesh->mNumFaces;i++) {
   1.329 +		if(faceBones[i]<pMesh->mNumBones&&isBoneNecessary[faceBones[i]]) 
   1.330 +		{
   1.331 +			ai_assert(facesPerBone[faceBones[i]]>0);
   1.332 +			facesPerBone[faceBones[i]]--; 
   1.333 +			
   1.334 +			nFacesUnowned++; 
   1.335 +			faceBones[i] = cUnowned; 
   1.336 +		}
   1.337 +	}
   1.338 +
   1.339 +	if(nFacesUnowned) {	 	
   1.340 +		std::vector<unsigned int> subFaces;
   1.341 +
   1.342 +		for(unsigned int i=0;i<pMesh->mNumFaces;i++)	{
   1.343 +			if(faceBones[i]==cUnowned) {
   1.344 +				subFaces.push_back(i);
   1.345 +			}
   1.346 +		}
   1.347 +
   1.348 +		aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0);
   1.349 +		std::pair<aiMesh*,const aiBone*> push_pair(baseMesh,(const aiBone*)0);
   1.350 +
   1.351 +		poNewMeshes.push_back(push_pair);
   1.352 +	}
   1.353 +
   1.354 +	for(unsigned int i=0;i<pMesh->mNumBones;i++) {			
   1.355 +
   1.356 +		if(!isBoneNecessary[i]&&facesPerBone[i]>0)	{				
   1.357 +			std::vector<unsigned int> subFaces;
   1.358 +
   1.359 +			for(unsigned int j=0;j<pMesh->mNumFaces;j++)	{
   1.360 +				if(faceBones[j]==i) {
   1.361 +					subFaces.push_back(j);
   1.362 +				}
   1.363 +			}
   1.364 +
   1.365 +			unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES;
   1.366 +			aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f);
   1.367 +
   1.368 +			//Lifted from PretransformVertices.cpp
   1.369 +			ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix);
   1.370 +			std::pair<aiMesh*,const aiBone*> push_pair(subMesh,pMesh->mBones[i]);
   1.371 +
   1.372 +			poNewMeshes.push_back(push_pair);		
   1.373 +		}
   1.374 +	}
   1.375 +}
   1.376 +
   1.377 +// ------------------------------------------------------------------------------------------------
   1.378 +// Recursively updates the node's mesh list to account for the changed mesh list
   1.379 +void DeboneProcess::UpdateNode(aiNode* pNode) const
   1.380 +{
   1.381 +	// rebuild the node's mesh index list
   1.382 +	
   1.383 +	std::vector<unsigned int> newMeshList;
   1.384 +
   1.385 +	// this will require two passes
   1.386 +
   1.387 +	unsigned int m = pNode->mNumMeshes, n = mSubMeshIndices.size();
   1.388 +	
   1.389 +	// first pass, look for meshes which have not moved
   1.390 +
   1.391 +	for(unsigned int a=0;a<m;a++)	{
   1.392 +
   1.393 +		unsigned int srcIndex = pNode->mMeshes[a];
   1.394 +		const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex];
   1.395 +		unsigned int nSubmeshes = subMeshes.size();
   1.396 +
   1.397 +		for(unsigned int b=0;b<nSubmeshes;b++) {
   1.398 +			if(!subMeshes[b].second) {
   1.399 +				newMeshList.push_back(subMeshes[b].first);
   1.400 +			}
   1.401 +		}
   1.402 +	}
   1.403 +
   1.404 +	// second pass, collect deboned meshes 
   1.405 +
   1.406 +	for(unsigned int a=0;a<n;a++)
   1.407 +	{
   1.408 +		const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a];
   1.409 +		unsigned int nSubmeshes = subMeshes.size();
   1.410 +
   1.411 +		for(unsigned int b=0;b<nSubmeshes;b++) {
   1.412 +			if(subMeshes[b].second == pNode)	{
   1.413 +				newMeshList.push_back(subMeshes[b].first);
   1.414 +			}
   1.415 +		}
   1.416 +	}
   1.417 +
   1.418 +	if( pNode->mNumMeshes > 0 )	{
   1.419 +		delete [] pNode->mMeshes; pNode->mMeshes = NULL;
   1.420 +	}
   1.421 +
   1.422 +	pNode->mNumMeshes = newMeshList.size();
   1.423 +
   1.424 +	if(pNode->mNumMeshes)	{
   1.425 +		pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
   1.426 +		std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
   1.427 +	}
   1.428 +
   1.429 +	// do that also recursively for all children
   1.430 +	for( unsigned int a = 0; a < pNode->mNumChildren; ++a )	{
   1.431 +		UpdateNode( pNode->mChildren[a]);
   1.432 +	}
   1.433 +}
   1.434 +
   1.435 +// ------------------------------------------------------------------------------------------------
   1.436 +// Apply the node transformation to a mesh
   1.437 +void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const
   1.438 +{
   1.439 +	// Check whether we need to transform the coordinates at all
   1.440 +	if (!mat.IsIdentity()) {
   1.441 +		
   1.442 +		if (mesh->HasPositions()) {
   1.443 +			for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
   1.444 +				mesh->mVertices[i] = mat * mesh->mVertices[i];
   1.445 +			}
   1.446 +		}
   1.447 +		if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) {
   1.448 +			aiMatrix4x4 mWorldIT = mat;
   1.449 +			mWorldIT.Inverse().Transpose();
   1.450 +
   1.451 +			// TODO: implement Inverse() for aiMatrix3x3
   1.452 +			aiMatrix3x3 m = aiMatrix3x3(mWorldIT);
   1.453 +
   1.454 +			if (mesh->HasNormals()) {
   1.455 +				for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
   1.456 +					mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize();
   1.457 +				}
   1.458 +			}
   1.459 +			if (mesh->HasTangentsAndBitangents()) {
   1.460 +				for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
   1.461 +					mesh->mTangents[i]   = (m * mesh->mTangents[i]).Normalize();
   1.462 +					mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize();
   1.463 +				}
   1.464 +			}
   1.465 +		}
   1.466 +	}
   1.467 +}