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 +}