vrshoot

diff libs/assimp/SplitLargeMeshes.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/SplitLargeMeshes.cpp	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,677 @@
     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 +
    1.45 +/** @file Implementation of the SplitLargeMeshes postprocessing step
    1.46 +*/
    1.47 +
    1.48 +#include "AssimpPCH.h"
    1.49 +
    1.50 +// internal headers of the post-processing framework
    1.51 +#include "SplitLargeMeshes.h"
    1.52 +#include "ProcessHelper.h"
    1.53 +
    1.54 +using namespace Assimp;
    1.55 +
    1.56 +
    1.57 +// ------------------------------------------------------------------------------------------------
    1.58 +SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle()
    1.59 +{
    1.60 +	LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
    1.61 +}
    1.62 +
    1.63 +// ------------------------------------------------------------------------------------------------
    1.64 +SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle()
    1.65 +{
    1.66 +	// nothing to do here
    1.67 +}
    1.68 +
    1.69 +// ------------------------------------------------------------------------------------------------
    1.70 +// Returns whether the processing step is present in the given flag field.
    1.71 +bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const
    1.72 +{
    1.73 +	return (pFlags & aiProcess_SplitLargeMeshes) != 0;
    1.74 +}
    1.75 +
    1.76 +// ------------------------------------------------------------------------------------------------
    1.77 +// Executes the post processing step on the given imported data.
    1.78 +void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene)
    1.79 +{
    1.80 +	if (0xffffffff == this->LIMIT)return;
    1.81 +
    1.82 +	DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle begin");
    1.83 +	std::vector<std::pair<aiMesh*, unsigned int> > avList;
    1.84 +
    1.85 +	for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
    1.86 +		this->SplitMesh(a, pScene->mMeshes[a],avList);
    1.87 +
    1.88 +	if (avList.size() != pScene->mNumMeshes)
    1.89 +	{
    1.90 +		// it seems something has been split. rebuild the mesh list
    1.91 +		delete[] pScene->mMeshes;
    1.92 +		pScene->mNumMeshes = (unsigned int)avList.size();
    1.93 +		pScene->mMeshes = new aiMesh*[avList.size()];
    1.94 +
    1.95 +		for (unsigned int i = 0; i < avList.size();++i)
    1.96 +			pScene->mMeshes[i] = avList[i].first;
    1.97 +
    1.98 +		// now we need to update all nodes
    1.99 +		this->UpdateNode(pScene->mRootNode,avList);
   1.100 +		DefaultLogger::get()->info("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
   1.101 +	}
   1.102 +	else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
   1.103 +	return;
   1.104 +}
   1.105 +
   1.106 +// ------------------------------------------------------------------------------------------------
   1.107 +// Setup properties
   1.108 +void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
   1.109 +{
   1.110 +    // get the current value of the split property
   1.111 +	this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
   1.112 +}
   1.113 +
   1.114 +// ------------------------------------------------------------------------------------------------
   1.115 +// Update a node after some meshes have been split
   1.116 +void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode,
   1.117 +	const std::vector<std::pair<aiMesh*, unsigned int> >& avList)
   1.118 +{
   1.119 +	// for every index in out list build a new entry
   1.120 +	std::vector<unsigned int> aiEntries;
   1.121 +	aiEntries.reserve(pcNode->mNumMeshes + 1);
   1.122 +	for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
   1.123 +	{
   1.124 +		for (unsigned int a = 0; a < avList.size();++a)
   1.125 +		{
   1.126 +			if (avList[a].second == pcNode->mMeshes[i])
   1.127 +			{
   1.128 +				aiEntries.push_back(a);
   1.129 +			}
   1.130 +		}
   1.131 +	}
   1.132 +
   1.133 +	// now build the new list
   1.134 +	delete pcNode->mMeshes;
   1.135 +	pcNode->mNumMeshes = (unsigned int)aiEntries.size();
   1.136 +	pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
   1.137 +
   1.138 +	for (unsigned int b = 0; b < pcNode->mNumMeshes;++b)
   1.139 +		pcNode->mMeshes[b] = aiEntries[b];
   1.140 +
   1.141 +	// recusively update all other nodes
   1.142 +	for (unsigned int i = 0; i < pcNode->mNumChildren;++i)
   1.143 +	{
   1.144 +		UpdateNode ( pcNode->mChildren[i], avList );
   1.145 +	}
   1.146 +	return;
   1.147 +}
   1.148 +
   1.149 +// ------------------------------------------------------------------------------------------------
   1.150 +// Executes the post processing step on the given imported data.
   1.151 +void SplitLargeMeshesProcess_Triangle::SplitMesh(
   1.152 +	unsigned int a,
   1.153 +	aiMesh* pMesh,
   1.154 +	std::vector<std::pair<aiMesh*, unsigned int> >& avList)
   1.155 +{
   1.156 +	if (pMesh->mNumFaces > SplitLargeMeshesProcess_Triangle::LIMIT)
   1.157 +	{
   1.158 +		DefaultLogger::get()->info("Mesh exceeds the triangle limit. It will be split ...");
   1.159 +
   1.160 +		// we need to split this mesh into sub meshes
   1.161 +		// determine the size of a submesh
   1.162 +		const unsigned int iSubMeshes = (pMesh->mNumFaces / LIMIT) + 1;
   1.163 +
   1.164 +		const unsigned int iOutFaceNum = pMesh->mNumFaces / iSubMeshes;
   1.165 +		const unsigned int iOutVertexNum = iOutFaceNum * 3;
   1.166 +
   1.167 +		// now generate all submeshes
   1.168 +		for (unsigned int i = 0; i < iSubMeshes;++i)
   1.169 +		{
   1.170 +			aiMesh* pcMesh			= new aiMesh;			
   1.171 +			pcMesh->mNumFaces		= iOutFaceNum;
   1.172 +			pcMesh->mMaterialIndex	= pMesh->mMaterialIndex;
   1.173 +
   1.174 +			// the name carries the adjacency information between the meshes
   1.175 +			pcMesh->mName = pMesh->mName;
   1.176 +
   1.177 +			if (i == iSubMeshes-1)
   1.178 +			{
   1.179 +				pcMesh->mNumFaces = iOutFaceNum + (
   1.180 +					pMesh->mNumFaces - iOutFaceNum * iSubMeshes);
   1.181 +			}
   1.182 +			// copy the list of faces
   1.183 +			pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
   1.184 +
   1.185 +			const unsigned int iBase = iOutFaceNum * i;
   1.186 +
   1.187 +			// get the total number of indices
   1.188 +			unsigned int iCnt = 0;
   1.189 +			for (unsigned int p = iBase; p < pcMesh->mNumFaces + iBase;++p)
   1.190 +			{
   1.191 +				iCnt += pMesh->mFaces[p].mNumIndices;
   1.192 +			}
   1.193 +			pcMesh->mNumVertices = iCnt;
   1.194 +
   1.195 +			// allocate storage
   1.196 +			if (pMesh->mVertices != NULL)
   1.197 +				pcMesh->mVertices = new aiVector3D[iCnt];
   1.198 +
   1.199 +			if (pMesh->HasNormals())
   1.200 +				pcMesh->mNormals = new aiVector3D[iCnt];
   1.201 +
   1.202 +			if (pMesh->HasTangentsAndBitangents())
   1.203 +			{
   1.204 +				pcMesh->mTangents = new aiVector3D[iCnt];
   1.205 +				pcMesh->mBitangents = new aiVector3D[iCnt];
   1.206 +			}
   1.207 +
   1.208 +			// texture coordinates
   1.209 +			for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
   1.210 +			{
   1.211 +				pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
   1.212 +				if (pMesh->HasTextureCoords( c))
   1.213 +				{
   1.214 +					pcMesh->mTextureCoords[c] = new aiVector3D[iCnt];
   1.215 +				}
   1.216 +			}
   1.217 +
   1.218 +			// vertex colors
   1.219 +			for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
   1.220 +			{
   1.221 +				if (pMesh->HasVertexColors( c))
   1.222 +				{
   1.223 +					pcMesh->mColors[c] = new aiColor4D[iCnt];
   1.224 +				}
   1.225 +			}
   1.226 +
   1.227 +			if (pMesh->HasBones())
   1.228 +			{
   1.229 +				// assume the number of bones won't change in most cases
   1.230 +				pcMesh->mBones = new aiBone*[pMesh->mNumBones];
   1.231 +
   1.232 +				// iterate through all bones of the mesh and find those which
   1.233 +				// need to be copied to the split mesh
   1.234 +				std::vector<aiVertexWeight> avTempWeights;
   1.235 +				for (unsigned int p = 0; p < pcMesh->mNumBones;++p)
   1.236 +				{
   1.237 +					aiBone* const bone = pcMesh->mBones[p];
   1.238 +					avTempWeights.clear();
   1.239 +					avTempWeights.reserve(bone->mNumWeights / iSubMeshes);
   1.240 +
   1.241 +					for (unsigned int q = 0; q < bone->mNumWeights;++q)
   1.242 +					{
   1.243 +						aiVertexWeight& weight = bone->mWeights[q];
   1.244 +						if(weight.mVertexId >= iBase && weight.mVertexId < iBase + iOutVertexNum)
   1.245 +						{
   1.246 +							avTempWeights.push_back(weight);
   1.247 +							weight = avTempWeights.back();
   1.248 +							weight.mVertexId -= iBase;
   1.249 +						}
   1.250 +					}
   1.251 +
   1.252 +					if (!avTempWeights.empty())
   1.253 +					{
   1.254 +						// we'll need this bone. Copy it ...
   1.255 +						aiBone* pc = new aiBone();
   1.256 +						pcMesh->mBones[pcMesh->mNumBones++] = pc;
   1.257 +						pc->mName = aiString(bone->mName);
   1.258 +						pc->mNumWeights = (unsigned int)avTempWeights.size();
   1.259 +						pc->mOffsetMatrix = bone->mOffsetMatrix;
   1.260 +
   1.261 +						// no need to reallocate the array for the last submesh.
   1.262 +						// Here we can reuse the (large) source array, although
   1.263 +						// we'll waste some memory
   1.264 +						if (iSubMeshes-1 == i)
   1.265 +						{
   1.266 +							pc->mWeights = bone->mWeights;
   1.267 +							bone->mWeights = NULL;
   1.268 +						}
   1.269 +						else pc->mWeights = new aiVertexWeight[pc->mNumWeights];
   1.270 +
   1.271 +						// copy the weights
   1.272 +						::memcpy(pc->mWeights,&avTempWeights[0],sizeof(aiVertexWeight)*pc->mNumWeights);
   1.273 +					}
   1.274 +				}
   1.275 +			}
   1.276 +
   1.277 +			// (we will also need to copy the array of indices)
   1.278 +			unsigned int iCurrent = 0;
   1.279 +			for (unsigned int p = 0; p < pcMesh->mNumFaces;++p)
   1.280 +			{
   1.281 +				pcMesh->mFaces[p].mNumIndices = 3;
   1.282 +				// allocate a new array
   1.283 +				const unsigned int iTemp = p + iBase;
   1.284 +				const unsigned int iNumIndices = pMesh->mFaces[iTemp].mNumIndices;
   1.285 +
   1.286 +				// setup face type and number of indices
   1.287 +				pcMesh->mFaces[p].mNumIndices = iNumIndices;
   1.288 +				unsigned int* pi = pMesh->mFaces[iTemp].mIndices;
   1.289 +				unsigned int* piOut = pcMesh->mFaces[p].mIndices = new unsigned int[iNumIndices];
   1.290 +
   1.291 +				// need to update the output primitive types
   1.292 +				switch (iNumIndices)
   1.293 +				{
   1.294 +				case 1:
   1.295 +					pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
   1.296 +					break;
   1.297 +				case 2:
   1.298 +					pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
   1.299 +					break;
   1.300 +				case 3:
   1.301 +					pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
   1.302 +					break;
   1.303 +				default:
   1.304 +					pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
   1.305 +				}
   1.306 +
   1.307 +				// and copy the contents of the old array, offset by current base
   1.308 +				for (unsigned int v = 0; v < iNumIndices;++v)
   1.309 +				{
   1.310 +					unsigned int iIndex = pi[v];
   1.311 +					unsigned int iIndexOut = iCurrent++;
   1.312 +					piOut[v] = iIndexOut;
   1.313 +
   1.314 +					// copy positions
   1.315 +					if (pMesh->mVertices != NULL)
   1.316 +						pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex];
   1.317 +
   1.318 +					// copy normals
   1.319 +					if (pMesh->HasNormals())
   1.320 +						pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex];
   1.321 +
   1.322 +					// copy tangents/bitangents
   1.323 +					if (pMesh->HasTangentsAndBitangents())
   1.324 +					{
   1.325 +						pcMesh->mTangents[iIndexOut] = pMesh->mTangents[iIndex];
   1.326 +						pcMesh->mBitangents[iIndexOut] = pMesh->mBitangents[iIndex];
   1.327 +					}
   1.328 +
   1.329 +					// texture coordinates
   1.330 +					for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
   1.331 +					{
   1.332 +						if (pMesh->HasTextureCoords( c))
   1.333 +							pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex];
   1.334 +					}
   1.335 +					// vertex colors 
   1.336 +					for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
   1.337 +					{
   1.338 +						if (pMesh->HasVertexColors( c))
   1.339 +							pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex];
   1.340 +					}
   1.341 +				}
   1.342 +			}
   1.343 +
   1.344 +			// add the newly created mesh to the list
   1.345 +			avList.push_back(std::pair<aiMesh*, unsigned int>(pcMesh,a));
   1.346 +		}
   1.347 +
   1.348 +		// now delete the old mesh data
   1.349 +		delete pMesh;
   1.350 +	}
   1.351 +	else avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a));
   1.352 +	return;
   1.353 +}
   1.354 +
   1.355 +// ------------------------------------------------------------------------------------------------
   1.356 +SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex()
   1.357 +{
   1.358 +	LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
   1.359 +}
   1.360 +
   1.361 +// ------------------------------------------------------------------------------------------------
   1.362 +SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex()
   1.363 +{
   1.364 +	// nothing to do here
   1.365 +}
   1.366 +
   1.367 +// ------------------------------------------------------------------------------------------------
   1.368 +// Returns whether the processing step is present in the given flag field.
   1.369 +bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const
   1.370 +{
   1.371 +	return (pFlags & aiProcess_SplitLargeMeshes) != 0;
   1.372 +}
   1.373 +
   1.374 +// ------------------------------------------------------------------------------------------------
   1.375 +// Executes the post processing step on the given imported data.
   1.376 +void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene)
   1.377 +{
   1.378 +	std::vector<std::pair<aiMesh*, unsigned int> > avList;
   1.379 +
   1.380 +  	if (0xffffffff == this->LIMIT)return;
   1.381 +
   1.382 +	DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex begin");
   1.383 +	for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
   1.384 +		this->SplitMesh(a, pScene->mMeshes[a],avList);
   1.385 +
   1.386 +	if (avList.size() != pScene->mNumMeshes)
   1.387 +	{
   1.388 +		// it seems something has been split. rebuild the mesh list
   1.389 +		delete[] pScene->mMeshes;
   1.390 +		pScene->mNumMeshes = (unsigned int)avList.size();
   1.391 +		pScene->mMeshes = new aiMesh*[avList.size()];
   1.392 +
   1.393 +		for (unsigned int i = 0; i < avList.size();++i)
   1.394 +			pScene->mMeshes[i] = avList[i].first;
   1.395 +
   1.396 +		// now we need to update all nodes
   1.397 +		SplitLargeMeshesProcess_Triangle::UpdateNode(pScene->mRootNode,avList);
   1.398 +		DefaultLogger::get()->info("SplitLargeMeshesProcess_Vertex finished. Meshes have been split");
   1.399 +	}
   1.400 +	else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex finished. There was nothing to do");
   1.401 +	return;
   1.402 +}
   1.403 +
   1.404 +// ------------------------------------------------------------------------------------------------
   1.405 +// Setup properties
   1.406 +void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp)
   1.407 +{
   1.408 +	this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
   1.409 +}
   1.410 +
   1.411 +// ------------------------------------------------------------------------------------------------
   1.412 +// Executes the post processing step on the given imported data.
   1.413 +void SplitLargeMeshesProcess_Vertex::SplitMesh(
   1.414 +	unsigned int a,
   1.415 +	aiMesh* pMesh,
   1.416 +	std::vector<std::pair<aiMesh*, unsigned int> >& avList)
   1.417 +{
   1.418 +	if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT)
   1.419 +	{
   1.420 +		typedef std::vector< std::pair<unsigned int,float> > VertexWeightTable;
   1.421 +
   1.422 +		// build a per-vertex weight list if necessary
   1.423 +		VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(pMesh);
   1.424 +
   1.425 +		// we need to split this mesh into sub meshes
   1.426 +		// determine the estimated size of a submesh
   1.427 +		// (this could be too large. Max waste is a single digit percentage)
   1.428 +		const unsigned int iSubMeshes = (pMesh->mNumVertices / SplitLargeMeshesProcess_Vertex::LIMIT) + 1;
   1.429 +		//const unsigned int iOutVertexNum2 = pMesh->mNumVertices /iSubMeshes;
   1.430 +
   1.431 +		// create a std::vector<unsigned int> to indicate which vertices
   1.432 +		// have already been copied
   1.433 +		std::vector<unsigned int> avWasCopied;
   1.434 +		avWasCopied.resize(pMesh->mNumVertices,0xFFFFFFFF);
   1.435 +
   1.436 +		// try to find a good estimate for the number of output faces
   1.437 +		// per mesh. Add 12.5% as buffer
   1.438 +		unsigned int iEstimatedSize = pMesh->mNumFaces / iSubMeshes;
   1.439 +		iEstimatedSize += iEstimatedSize >> 3;
   1.440 +
   1.441 +		// now generate all submeshes
   1.442 +		unsigned int iBase = 0;
   1.443 +		while (true)
   1.444 +		{
   1.445 +			const unsigned int iOutVertexNum = SplitLargeMeshesProcess_Vertex::LIMIT;
   1.446 +
   1.447 +			aiMesh* pcMesh			= new aiMesh;			
   1.448 +			pcMesh->mNumVertices	= 0;
   1.449 +			pcMesh->mMaterialIndex	= pMesh->mMaterialIndex;
   1.450 +
   1.451 +			// the name carries the adjacency information between the meshes
   1.452 +			pcMesh->mName = pMesh->mName;
   1.453 +
   1.454 +			typedef std::vector<aiVertexWeight> BoneWeightList;
   1.455 +			if (pMesh->HasBones())
   1.456 +			{
   1.457 +				pcMesh->mBones = new aiBone*[pMesh->mNumBones];
   1.458 +				::memset(pcMesh->mBones,0,sizeof(void*)*pMesh->mNumBones);
   1.459 +			}
   1.460 +
   1.461 +			// clear the temporary helper array
   1.462 +			if (iBase)
   1.463 +			{
   1.464 +				// we can't use memset here we unsigned int needn' be 32 bits
   1.465 +				for (std::vector<unsigned int>::iterator
   1.466 +					iter = avWasCopied.begin(),end = avWasCopied.end();
   1.467 +					iter != end;++iter)
   1.468 +				{
   1.469 +					(*iter) = 0xffffffff;
   1.470 +				}
   1.471 +			}
   1.472 +
   1.473 +			// output vectors
   1.474 +			std::vector<aiFace> vFaces;
   1.475 +
   1.476 +			// reserve enough storage for most cases
   1.477 +			if (pMesh->HasPositions())
   1.478 +			{
   1.479 +				pcMesh->mVertices = new aiVector3D[iOutVertexNum];
   1.480 +			}
   1.481 +			if (pMesh->HasNormals())
   1.482 +			{
   1.483 +				pcMesh->mNormals = new aiVector3D[iOutVertexNum];
   1.484 +			}
   1.485 +			if (pMesh->HasTangentsAndBitangents())
   1.486 +			{
   1.487 +				pcMesh->mTangents = new aiVector3D[iOutVertexNum];
   1.488 +				pcMesh->mBitangents = new aiVector3D[iOutVertexNum];
   1.489 +			}
   1.490 +			for (unsigned int c = 0; pMesh->HasVertexColors(c);++c)
   1.491 +			{
   1.492 +				pcMesh->mColors[c] = new aiColor4D[iOutVertexNum];
   1.493 +			}
   1.494 +			for (unsigned int c = 0; pMesh->HasTextureCoords(c);++c)
   1.495 +			{
   1.496 +				pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
   1.497 +				pcMesh->mTextureCoords[c] = new aiVector3D[iOutVertexNum];
   1.498 +			}
   1.499 +			vFaces.reserve(iEstimatedSize);
   1.500 +
   1.501 +			// (we will also need to copy the array of indices)
   1.502 +			while (iBase < pMesh->mNumFaces)
   1.503 +			{
   1.504 +				// allocate a new array
   1.505 +				const unsigned int iNumIndices = pMesh->mFaces[iBase].mNumIndices;
   1.506 +
   1.507 +				// doesn't catch degenerates but is quite fast
   1.508 +				unsigned int iNeed = 0;
   1.509 +				for (unsigned int v = 0; v < iNumIndices;++v)
   1.510 +				{
   1.511 +					unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
   1.512 +
   1.513 +					// check whether we do already have this vertex
   1.514 +					if (0xFFFFFFFF == avWasCopied[iIndex])
   1.515 +					{
   1.516 +						iNeed++; 
   1.517 +					}
   1.518 +				}
   1.519 +				if (pcMesh->mNumVertices + iNeed > iOutVertexNum)
   1.520 +				{
   1.521 +					// don't use this face
   1.522 +					break;
   1.523 +				}
   1.524 +
   1.525 +				vFaces.push_back(aiFace());
   1.526 +				aiFace& rFace = vFaces.back();
   1.527 +
   1.528 +				// setup face type and number of indices
   1.529 +				rFace.mNumIndices = iNumIndices;
   1.530 +				rFace.mIndices = new unsigned int[iNumIndices];
   1.531 +
   1.532 +				// need to update the output primitive types
   1.533 +				switch (rFace.mNumIndices)
   1.534 +				{
   1.535 +				case 1:
   1.536 +					pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
   1.537 +					break;
   1.538 +				case 2:
   1.539 +					pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
   1.540 +					break;
   1.541 +				case 3:
   1.542 +					pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
   1.543 +					break;
   1.544 +				default:
   1.545 +					pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
   1.546 +				}
   1.547 +
   1.548 +				// and copy the contents of the old array, offset by current base
   1.549 +				for (unsigned int v = 0; v < iNumIndices;++v)
   1.550 +				{
   1.551 +					unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
   1.552 +
   1.553 +					// check whether we do already have this vertex
   1.554 +					if (0xFFFFFFFF != avWasCopied[iIndex])
   1.555 +					{
   1.556 +						rFace.mIndices[v] = avWasCopied[iIndex];
   1.557 +						continue;
   1.558 +					}
   1.559 +
   1.560 +					// copy positions
   1.561 +					pcMesh->mVertices[pcMesh->mNumVertices] = (pMesh->mVertices[iIndex]);
   1.562 +
   1.563 +					// copy normals
   1.564 +					if (pMesh->HasNormals())
   1.565 +					{
   1.566 +						pcMesh->mNormals[pcMesh->mNumVertices] = (pMesh->mNormals[iIndex]);
   1.567 +					}
   1.568 +
   1.569 +					// copy tangents/bitangents
   1.570 +					if (pMesh->HasTangentsAndBitangents())
   1.571 +					{
   1.572 +						pcMesh->mTangents[pcMesh->mNumVertices] = (pMesh->mTangents[iIndex]);
   1.573 +						pcMesh->mBitangents[pcMesh->mNumVertices] = (pMesh->mBitangents[iIndex]);
   1.574 +					}
   1.575 +
   1.576 +					// texture coordinates
   1.577 +					for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
   1.578 +					{
   1.579 +						if (pMesh->HasTextureCoords( c))
   1.580 +						{
   1.581 +							pcMesh->mTextureCoords[c][pcMesh->mNumVertices] = pMesh->mTextureCoords[c][iIndex];
   1.582 +						}
   1.583 +					}
   1.584 +					// vertex colors 
   1.585 +					for (unsigned int c = 0;  c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
   1.586 +					{
   1.587 +						if (pMesh->HasVertexColors( c))
   1.588 +						{
   1.589 +							pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex];
   1.590 +						}
   1.591 +					}
   1.592 +					// check whether we have bone weights assigned to this vertex
   1.593 +					rFace.mIndices[v] = pcMesh->mNumVertices;
   1.594 +					if (avPerVertexWeights)
   1.595 +					{
   1.596 +						VertexWeightTable& table = avPerVertexWeights[ pcMesh->mNumVertices ];
   1.597 +						if( !table.empty() )
   1.598 +						{
   1.599 +							for (VertexWeightTable::const_iterator
   1.600 +								iter =  table.begin();
   1.601 +								iter != table.end();++iter)
   1.602 +							{
   1.603 +								// allocate the bone weight array if necessary
   1.604 +								BoneWeightList* pcWeightList = (BoneWeightList*)pcMesh->mBones[(*iter).first];
   1.605 +								if (!pcWeightList)
   1.606 +								{
   1.607 +									pcMesh->mBones[(*iter).first] = (aiBone*)(pcWeightList = new BoneWeightList());
   1.608 +								}
   1.609 +								pcWeightList->push_back(aiVertexWeight(pcMesh->mNumVertices,(*iter).second));
   1.610 +							}
   1.611 +						}
   1.612 +					}
   1.613 +
   1.614 +					avWasCopied[iIndex] = pcMesh->mNumVertices;
   1.615 +					pcMesh->mNumVertices++;
   1.616 +				}
   1.617 +				iBase++;
   1.618 +				if(pcMesh->mNumVertices == iOutVertexNum)
   1.619 +				{
   1.620 +					// break here. The face is only added if it was complete
   1.621 +					break;
   1.622 +				}
   1.623 +			}
   1.624 +
   1.625 +			// check which bones we'll need to create for this submesh
   1.626 +			if (pMesh->HasBones())
   1.627 +			{
   1.628 +				aiBone** ppCurrent = pcMesh->mBones;
   1.629 +				for (unsigned int k = 0; k < pMesh->mNumBones;++k)
   1.630 +				{
   1.631 +					// check whether the bone is existing
   1.632 +					BoneWeightList* pcWeightList;
   1.633 +					if ((pcWeightList = (BoneWeightList*)pcMesh->mBones[k]))
   1.634 +					{
   1.635 +						aiBone* pcOldBone = pMesh->mBones[k];
   1.636 +						aiBone* pcOut;
   1.637 +						*ppCurrent++ = pcOut = new aiBone();
   1.638 +						pcOut->mName = aiString(pcOldBone->mName);
   1.639 +						pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix;
   1.640 +						pcOut->mNumWeights = (unsigned int)pcWeightList->size();
   1.641 +						pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights];
   1.642 +
   1.643 +						// copy the vertex weights
   1.644 +						::memcpy(pcOut->mWeights,&pcWeightList->operator[](0),
   1.645 +							pcOut->mNumWeights * sizeof(aiVertexWeight));
   1.646 +
   1.647 +						// delete the temporary bone weight list
   1.648 +						delete pcWeightList;
   1.649 +						pcMesh->mNumBones++;
   1.650 +					}
   1.651 +				}
   1.652 +			}
   1.653 +
   1.654 +			// copy the face list to the mesh
   1.655 +			pcMesh->mFaces = new aiFace[vFaces.size()];
   1.656 +			pcMesh->mNumFaces = (unsigned int)vFaces.size();
   1.657 +
   1.658 +			for (unsigned int p = 0; p < pcMesh->mNumFaces;++p)
   1.659 +				pcMesh->mFaces[p] = vFaces[p];
   1.660 +
   1.661 +			// add the newly created mesh to the list
   1.662 +			avList.push_back(std::pair<aiMesh*, unsigned int>(pcMesh,a));
   1.663 +
   1.664 +			if (iBase == pMesh->mNumFaces)
   1.665 +			{
   1.666 +				// have all faces ... finish the outer loop, too
   1.667 +				break;
   1.668 +			}
   1.669 +		}
   1.670 +
   1.671 +		// delete the per-vertex weight list again
   1.672 +		delete[] avPerVertexWeights;
   1.673 +
   1.674 +		// now delete the old mesh data
   1.675 +		delete pMesh;
   1.676 +		return;
   1.677 +	}
   1.678 +	avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a));
   1.679 +	return;
   1.680 +}