vrshoot

annotate 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
rev   line source
nuclear@0 1 /*
nuclear@0 2 Open Asset Import Library (assimp)
nuclear@0 3 ----------------------------------------------------------------------
nuclear@0 4
nuclear@0 5 Copyright (c) 2006-2012, assimp team
nuclear@0 6 All rights reserved.
nuclear@0 7
nuclear@0 8 Redistribution and use of this software in source and binary forms,
nuclear@0 9 with or without modification, are permitted provided that the
nuclear@0 10 following conditions are met:
nuclear@0 11
nuclear@0 12 * Redistributions of source code must retain the above
nuclear@0 13 copyright notice, this list of conditions and the
nuclear@0 14 following disclaimer.
nuclear@0 15
nuclear@0 16 * Redistributions in binary form must reproduce the above
nuclear@0 17 copyright notice, this list of conditions and the
nuclear@0 18 following disclaimer in the documentation and/or other
nuclear@0 19 materials provided with the distribution.
nuclear@0 20
nuclear@0 21 * Neither the name of the assimp team, nor the names of its
nuclear@0 22 contributors may be used to endorse or promote products
nuclear@0 23 derived from this software without specific prior
nuclear@0 24 written permission of the assimp team.
nuclear@0 25
nuclear@0 26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 37
nuclear@0 38 ----------------------------------------------------------------------
nuclear@0 39 */
nuclear@0 40
nuclear@0 41
nuclear@0 42 /** @file Implementation of the SplitLargeMeshes postprocessing step
nuclear@0 43 */
nuclear@0 44
nuclear@0 45 #include "AssimpPCH.h"
nuclear@0 46
nuclear@0 47 // internal headers of the post-processing framework
nuclear@0 48 #include "SplitLargeMeshes.h"
nuclear@0 49 #include "ProcessHelper.h"
nuclear@0 50
nuclear@0 51 using namespace Assimp;
nuclear@0 52
nuclear@0 53
nuclear@0 54 // ------------------------------------------------------------------------------------------------
nuclear@0 55 SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle()
nuclear@0 56 {
nuclear@0 57 LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
nuclear@0 58 }
nuclear@0 59
nuclear@0 60 // ------------------------------------------------------------------------------------------------
nuclear@0 61 SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle()
nuclear@0 62 {
nuclear@0 63 // nothing to do here
nuclear@0 64 }
nuclear@0 65
nuclear@0 66 // ------------------------------------------------------------------------------------------------
nuclear@0 67 // Returns whether the processing step is present in the given flag field.
nuclear@0 68 bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const
nuclear@0 69 {
nuclear@0 70 return (pFlags & aiProcess_SplitLargeMeshes) != 0;
nuclear@0 71 }
nuclear@0 72
nuclear@0 73 // ------------------------------------------------------------------------------------------------
nuclear@0 74 // Executes the post processing step on the given imported data.
nuclear@0 75 void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene)
nuclear@0 76 {
nuclear@0 77 if (0xffffffff == this->LIMIT)return;
nuclear@0 78
nuclear@0 79 DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle begin");
nuclear@0 80 std::vector<std::pair<aiMesh*, unsigned int> > avList;
nuclear@0 81
nuclear@0 82 for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
nuclear@0 83 this->SplitMesh(a, pScene->mMeshes[a],avList);
nuclear@0 84
nuclear@0 85 if (avList.size() != pScene->mNumMeshes)
nuclear@0 86 {
nuclear@0 87 // it seems something has been split. rebuild the mesh list
nuclear@0 88 delete[] pScene->mMeshes;
nuclear@0 89 pScene->mNumMeshes = (unsigned int)avList.size();
nuclear@0 90 pScene->mMeshes = new aiMesh*[avList.size()];
nuclear@0 91
nuclear@0 92 for (unsigned int i = 0; i < avList.size();++i)
nuclear@0 93 pScene->mMeshes[i] = avList[i].first;
nuclear@0 94
nuclear@0 95 // now we need to update all nodes
nuclear@0 96 this->UpdateNode(pScene->mRootNode,avList);
nuclear@0 97 DefaultLogger::get()->info("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
nuclear@0 98 }
nuclear@0 99 else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
nuclear@0 100 return;
nuclear@0 101 }
nuclear@0 102
nuclear@0 103 // ------------------------------------------------------------------------------------------------
nuclear@0 104 // Setup properties
nuclear@0 105 void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp)
nuclear@0 106 {
nuclear@0 107 // get the current value of the split property
nuclear@0 108 this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
nuclear@0 109 }
nuclear@0 110
nuclear@0 111 // ------------------------------------------------------------------------------------------------
nuclear@0 112 // Update a node after some meshes have been split
nuclear@0 113 void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode,
nuclear@0 114 const std::vector<std::pair<aiMesh*, unsigned int> >& avList)
nuclear@0 115 {
nuclear@0 116 // for every index in out list build a new entry
nuclear@0 117 std::vector<unsigned int> aiEntries;
nuclear@0 118 aiEntries.reserve(pcNode->mNumMeshes + 1);
nuclear@0 119 for (unsigned int i = 0; i < pcNode->mNumMeshes;++i)
nuclear@0 120 {
nuclear@0 121 for (unsigned int a = 0; a < avList.size();++a)
nuclear@0 122 {
nuclear@0 123 if (avList[a].second == pcNode->mMeshes[i])
nuclear@0 124 {
nuclear@0 125 aiEntries.push_back(a);
nuclear@0 126 }
nuclear@0 127 }
nuclear@0 128 }
nuclear@0 129
nuclear@0 130 // now build the new list
nuclear@0 131 delete pcNode->mMeshes;
nuclear@0 132 pcNode->mNumMeshes = (unsigned int)aiEntries.size();
nuclear@0 133 pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
nuclear@0 134
nuclear@0 135 for (unsigned int b = 0; b < pcNode->mNumMeshes;++b)
nuclear@0 136 pcNode->mMeshes[b] = aiEntries[b];
nuclear@0 137
nuclear@0 138 // recusively update all other nodes
nuclear@0 139 for (unsigned int i = 0; i < pcNode->mNumChildren;++i)
nuclear@0 140 {
nuclear@0 141 UpdateNode ( pcNode->mChildren[i], avList );
nuclear@0 142 }
nuclear@0 143 return;
nuclear@0 144 }
nuclear@0 145
nuclear@0 146 // ------------------------------------------------------------------------------------------------
nuclear@0 147 // Executes the post processing step on the given imported data.
nuclear@0 148 void SplitLargeMeshesProcess_Triangle::SplitMesh(
nuclear@0 149 unsigned int a,
nuclear@0 150 aiMesh* pMesh,
nuclear@0 151 std::vector<std::pair<aiMesh*, unsigned int> >& avList)
nuclear@0 152 {
nuclear@0 153 if (pMesh->mNumFaces > SplitLargeMeshesProcess_Triangle::LIMIT)
nuclear@0 154 {
nuclear@0 155 DefaultLogger::get()->info("Mesh exceeds the triangle limit. It will be split ...");
nuclear@0 156
nuclear@0 157 // we need to split this mesh into sub meshes
nuclear@0 158 // determine the size of a submesh
nuclear@0 159 const unsigned int iSubMeshes = (pMesh->mNumFaces / LIMIT) + 1;
nuclear@0 160
nuclear@0 161 const unsigned int iOutFaceNum = pMesh->mNumFaces / iSubMeshes;
nuclear@0 162 const unsigned int iOutVertexNum = iOutFaceNum * 3;
nuclear@0 163
nuclear@0 164 // now generate all submeshes
nuclear@0 165 for (unsigned int i = 0; i < iSubMeshes;++i)
nuclear@0 166 {
nuclear@0 167 aiMesh* pcMesh = new aiMesh;
nuclear@0 168 pcMesh->mNumFaces = iOutFaceNum;
nuclear@0 169 pcMesh->mMaterialIndex = pMesh->mMaterialIndex;
nuclear@0 170
nuclear@0 171 // the name carries the adjacency information between the meshes
nuclear@0 172 pcMesh->mName = pMesh->mName;
nuclear@0 173
nuclear@0 174 if (i == iSubMeshes-1)
nuclear@0 175 {
nuclear@0 176 pcMesh->mNumFaces = iOutFaceNum + (
nuclear@0 177 pMesh->mNumFaces - iOutFaceNum * iSubMeshes);
nuclear@0 178 }
nuclear@0 179 // copy the list of faces
nuclear@0 180 pcMesh->mFaces = new aiFace[pcMesh->mNumFaces];
nuclear@0 181
nuclear@0 182 const unsigned int iBase = iOutFaceNum * i;
nuclear@0 183
nuclear@0 184 // get the total number of indices
nuclear@0 185 unsigned int iCnt = 0;
nuclear@0 186 for (unsigned int p = iBase; p < pcMesh->mNumFaces + iBase;++p)
nuclear@0 187 {
nuclear@0 188 iCnt += pMesh->mFaces[p].mNumIndices;
nuclear@0 189 }
nuclear@0 190 pcMesh->mNumVertices = iCnt;
nuclear@0 191
nuclear@0 192 // allocate storage
nuclear@0 193 if (pMesh->mVertices != NULL)
nuclear@0 194 pcMesh->mVertices = new aiVector3D[iCnt];
nuclear@0 195
nuclear@0 196 if (pMesh->HasNormals())
nuclear@0 197 pcMesh->mNormals = new aiVector3D[iCnt];
nuclear@0 198
nuclear@0 199 if (pMesh->HasTangentsAndBitangents())
nuclear@0 200 {
nuclear@0 201 pcMesh->mTangents = new aiVector3D[iCnt];
nuclear@0 202 pcMesh->mBitangents = new aiVector3D[iCnt];
nuclear@0 203 }
nuclear@0 204
nuclear@0 205 // texture coordinates
nuclear@0 206 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
nuclear@0 207 {
nuclear@0 208 pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
nuclear@0 209 if (pMesh->HasTextureCoords( c))
nuclear@0 210 {
nuclear@0 211 pcMesh->mTextureCoords[c] = new aiVector3D[iCnt];
nuclear@0 212 }
nuclear@0 213 }
nuclear@0 214
nuclear@0 215 // vertex colors
nuclear@0 216 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
nuclear@0 217 {
nuclear@0 218 if (pMesh->HasVertexColors( c))
nuclear@0 219 {
nuclear@0 220 pcMesh->mColors[c] = new aiColor4D[iCnt];
nuclear@0 221 }
nuclear@0 222 }
nuclear@0 223
nuclear@0 224 if (pMesh->HasBones())
nuclear@0 225 {
nuclear@0 226 // assume the number of bones won't change in most cases
nuclear@0 227 pcMesh->mBones = new aiBone*[pMesh->mNumBones];
nuclear@0 228
nuclear@0 229 // iterate through all bones of the mesh and find those which
nuclear@0 230 // need to be copied to the split mesh
nuclear@0 231 std::vector<aiVertexWeight> avTempWeights;
nuclear@0 232 for (unsigned int p = 0; p < pcMesh->mNumBones;++p)
nuclear@0 233 {
nuclear@0 234 aiBone* const bone = pcMesh->mBones[p];
nuclear@0 235 avTempWeights.clear();
nuclear@0 236 avTempWeights.reserve(bone->mNumWeights / iSubMeshes);
nuclear@0 237
nuclear@0 238 for (unsigned int q = 0; q < bone->mNumWeights;++q)
nuclear@0 239 {
nuclear@0 240 aiVertexWeight& weight = bone->mWeights[q];
nuclear@0 241 if(weight.mVertexId >= iBase && weight.mVertexId < iBase + iOutVertexNum)
nuclear@0 242 {
nuclear@0 243 avTempWeights.push_back(weight);
nuclear@0 244 weight = avTempWeights.back();
nuclear@0 245 weight.mVertexId -= iBase;
nuclear@0 246 }
nuclear@0 247 }
nuclear@0 248
nuclear@0 249 if (!avTempWeights.empty())
nuclear@0 250 {
nuclear@0 251 // we'll need this bone. Copy it ...
nuclear@0 252 aiBone* pc = new aiBone();
nuclear@0 253 pcMesh->mBones[pcMesh->mNumBones++] = pc;
nuclear@0 254 pc->mName = aiString(bone->mName);
nuclear@0 255 pc->mNumWeights = (unsigned int)avTempWeights.size();
nuclear@0 256 pc->mOffsetMatrix = bone->mOffsetMatrix;
nuclear@0 257
nuclear@0 258 // no need to reallocate the array for the last submesh.
nuclear@0 259 // Here we can reuse the (large) source array, although
nuclear@0 260 // we'll waste some memory
nuclear@0 261 if (iSubMeshes-1 == i)
nuclear@0 262 {
nuclear@0 263 pc->mWeights = bone->mWeights;
nuclear@0 264 bone->mWeights = NULL;
nuclear@0 265 }
nuclear@0 266 else pc->mWeights = new aiVertexWeight[pc->mNumWeights];
nuclear@0 267
nuclear@0 268 // copy the weights
nuclear@0 269 ::memcpy(pc->mWeights,&avTempWeights[0],sizeof(aiVertexWeight)*pc->mNumWeights);
nuclear@0 270 }
nuclear@0 271 }
nuclear@0 272 }
nuclear@0 273
nuclear@0 274 // (we will also need to copy the array of indices)
nuclear@0 275 unsigned int iCurrent = 0;
nuclear@0 276 for (unsigned int p = 0; p < pcMesh->mNumFaces;++p)
nuclear@0 277 {
nuclear@0 278 pcMesh->mFaces[p].mNumIndices = 3;
nuclear@0 279 // allocate a new array
nuclear@0 280 const unsigned int iTemp = p + iBase;
nuclear@0 281 const unsigned int iNumIndices = pMesh->mFaces[iTemp].mNumIndices;
nuclear@0 282
nuclear@0 283 // setup face type and number of indices
nuclear@0 284 pcMesh->mFaces[p].mNumIndices = iNumIndices;
nuclear@0 285 unsigned int* pi = pMesh->mFaces[iTemp].mIndices;
nuclear@0 286 unsigned int* piOut = pcMesh->mFaces[p].mIndices = new unsigned int[iNumIndices];
nuclear@0 287
nuclear@0 288 // need to update the output primitive types
nuclear@0 289 switch (iNumIndices)
nuclear@0 290 {
nuclear@0 291 case 1:
nuclear@0 292 pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
nuclear@0 293 break;
nuclear@0 294 case 2:
nuclear@0 295 pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
nuclear@0 296 break;
nuclear@0 297 case 3:
nuclear@0 298 pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
nuclear@0 299 break;
nuclear@0 300 default:
nuclear@0 301 pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
nuclear@0 302 }
nuclear@0 303
nuclear@0 304 // and copy the contents of the old array, offset by current base
nuclear@0 305 for (unsigned int v = 0; v < iNumIndices;++v)
nuclear@0 306 {
nuclear@0 307 unsigned int iIndex = pi[v];
nuclear@0 308 unsigned int iIndexOut = iCurrent++;
nuclear@0 309 piOut[v] = iIndexOut;
nuclear@0 310
nuclear@0 311 // copy positions
nuclear@0 312 if (pMesh->mVertices != NULL)
nuclear@0 313 pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex];
nuclear@0 314
nuclear@0 315 // copy normals
nuclear@0 316 if (pMesh->HasNormals())
nuclear@0 317 pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex];
nuclear@0 318
nuclear@0 319 // copy tangents/bitangents
nuclear@0 320 if (pMesh->HasTangentsAndBitangents())
nuclear@0 321 {
nuclear@0 322 pcMesh->mTangents[iIndexOut] = pMesh->mTangents[iIndex];
nuclear@0 323 pcMesh->mBitangents[iIndexOut] = pMesh->mBitangents[iIndex];
nuclear@0 324 }
nuclear@0 325
nuclear@0 326 // texture coordinates
nuclear@0 327 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
nuclear@0 328 {
nuclear@0 329 if (pMesh->HasTextureCoords( c))
nuclear@0 330 pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex];
nuclear@0 331 }
nuclear@0 332 // vertex colors
nuclear@0 333 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
nuclear@0 334 {
nuclear@0 335 if (pMesh->HasVertexColors( c))
nuclear@0 336 pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex];
nuclear@0 337 }
nuclear@0 338 }
nuclear@0 339 }
nuclear@0 340
nuclear@0 341 // add the newly created mesh to the list
nuclear@0 342 avList.push_back(std::pair<aiMesh*, unsigned int>(pcMesh,a));
nuclear@0 343 }
nuclear@0 344
nuclear@0 345 // now delete the old mesh data
nuclear@0 346 delete pMesh;
nuclear@0 347 }
nuclear@0 348 else avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a));
nuclear@0 349 return;
nuclear@0 350 }
nuclear@0 351
nuclear@0 352 // ------------------------------------------------------------------------------------------------
nuclear@0 353 SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex()
nuclear@0 354 {
nuclear@0 355 LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
nuclear@0 356 }
nuclear@0 357
nuclear@0 358 // ------------------------------------------------------------------------------------------------
nuclear@0 359 SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex()
nuclear@0 360 {
nuclear@0 361 // nothing to do here
nuclear@0 362 }
nuclear@0 363
nuclear@0 364 // ------------------------------------------------------------------------------------------------
nuclear@0 365 // Returns whether the processing step is present in the given flag field.
nuclear@0 366 bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const
nuclear@0 367 {
nuclear@0 368 return (pFlags & aiProcess_SplitLargeMeshes) != 0;
nuclear@0 369 }
nuclear@0 370
nuclear@0 371 // ------------------------------------------------------------------------------------------------
nuclear@0 372 // Executes the post processing step on the given imported data.
nuclear@0 373 void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene)
nuclear@0 374 {
nuclear@0 375 std::vector<std::pair<aiMesh*, unsigned int> > avList;
nuclear@0 376
nuclear@0 377 if (0xffffffff == this->LIMIT)return;
nuclear@0 378
nuclear@0 379 DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex begin");
nuclear@0 380 for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
nuclear@0 381 this->SplitMesh(a, pScene->mMeshes[a],avList);
nuclear@0 382
nuclear@0 383 if (avList.size() != pScene->mNumMeshes)
nuclear@0 384 {
nuclear@0 385 // it seems something has been split. rebuild the mesh list
nuclear@0 386 delete[] pScene->mMeshes;
nuclear@0 387 pScene->mNumMeshes = (unsigned int)avList.size();
nuclear@0 388 pScene->mMeshes = new aiMesh*[avList.size()];
nuclear@0 389
nuclear@0 390 for (unsigned int i = 0; i < avList.size();++i)
nuclear@0 391 pScene->mMeshes[i] = avList[i].first;
nuclear@0 392
nuclear@0 393 // now we need to update all nodes
nuclear@0 394 SplitLargeMeshesProcess_Triangle::UpdateNode(pScene->mRootNode,avList);
nuclear@0 395 DefaultLogger::get()->info("SplitLargeMeshesProcess_Vertex finished. Meshes have been split");
nuclear@0 396 }
nuclear@0 397 else DefaultLogger::get()->debug("SplitLargeMeshesProcess_Vertex finished. There was nothing to do");
nuclear@0 398 return;
nuclear@0 399 }
nuclear@0 400
nuclear@0 401 // ------------------------------------------------------------------------------------------------
nuclear@0 402 // Setup properties
nuclear@0 403 void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp)
nuclear@0 404 {
nuclear@0 405 this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
nuclear@0 406 }
nuclear@0 407
nuclear@0 408 // ------------------------------------------------------------------------------------------------
nuclear@0 409 // Executes the post processing step on the given imported data.
nuclear@0 410 void SplitLargeMeshesProcess_Vertex::SplitMesh(
nuclear@0 411 unsigned int a,
nuclear@0 412 aiMesh* pMesh,
nuclear@0 413 std::vector<std::pair<aiMesh*, unsigned int> >& avList)
nuclear@0 414 {
nuclear@0 415 if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT)
nuclear@0 416 {
nuclear@0 417 typedef std::vector< std::pair<unsigned int,float> > VertexWeightTable;
nuclear@0 418
nuclear@0 419 // build a per-vertex weight list if necessary
nuclear@0 420 VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(pMesh);
nuclear@0 421
nuclear@0 422 // we need to split this mesh into sub meshes
nuclear@0 423 // determine the estimated size of a submesh
nuclear@0 424 // (this could be too large. Max waste is a single digit percentage)
nuclear@0 425 const unsigned int iSubMeshes = (pMesh->mNumVertices / SplitLargeMeshesProcess_Vertex::LIMIT) + 1;
nuclear@0 426 //const unsigned int iOutVertexNum2 = pMesh->mNumVertices /iSubMeshes;
nuclear@0 427
nuclear@0 428 // create a std::vector<unsigned int> to indicate which vertices
nuclear@0 429 // have already been copied
nuclear@0 430 std::vector<unsigned int> avWasCopied;
nuclear@0 431 avWasCopied.resize(pMesh->mNumVertices,0xFFFFFFFF);
nuclear@0 432
nuclear@0 433 // try to find a good estimate for the number of output faces
nuclear@0 434 // per mesh. Add 12.5% as buffer
nuclear@0 435 unsigned int iEstimatedSize = pMesh->mNumFaces / iSubMeshes;
nuclear@0 436 iEstimatedSize += iEstimatedSize >> 3;
nuclear@0 437
nuclear@0 438 // now generate all submeshes
nuclear@0 439 unsigned int iBase = 0;
nuclear@0 440 while (true)
nuclear@0 441 {
nuclear@0 442 const unsigned int iOutVertexNum = SplitLargeMeshesProcess_Vertex::LIMIT;
nuclear@0 443
nuclear@0 444 aiMesh* pcMesh = new aiMesh;
nuclear@0 445 pcMesh->mNumVertices = 0;
nuclear@0 446 pcMesh->mMaterialIndex = pMesh->mMaterialIndex;
nuclear@0 447
nuclear@0 448 // the name carries the adjacency information between the meshes
nuclear@0 449 pcMesh->mName = pMesh->mName;
nuclear@0 450
nuclear@0 451 typedef std::vector<aiVertexWeight> BoneWeightList;
nuclear@0 452 if (pMesh->HasBones())
nuclear@0 453 {
nuclear@0 454 pcMesh->mBones = new aiBone*[pMesh->mNumBones];
nuclear@0 455 ::memset(pcMesh->mBones,0,sizeof(void*)*pMesh->mNumBones);
nuclear@0 456 }
nuclear@0 457
nuclear@0 458 // clear the temporary helper array
nuclear@0 459 if (iBase)
nuclear@0 460 {
nuclear@0 461 // we can't use memset here we unsigned int needn' be 32 bits
nuclear@0 462 for (std::vector<unsigned int>::iterator
nuclear@0 463 iter = avWasCopied.begin(),end = avWasCopied.end();
nuclear@0 464 iter != end;++iter)
nuclear@0 465 {
nuclear@0 466 (*iter) = 0xffffffff;
nuclear@0 467 }
nuclear@0 468 }
nuclear@0 469
nuclear@0 470 // output vectors
nuclear@0 471 std::vector<aiFace> vFaces;
nuclear@0 472
nuclear@0 473 // reserve enough storage for most cases
nuclear@0 474 if (pMesh->HasPositions())
nuclear@0 475 {
nuclear@0 476 pcMesh->mVertices = new aiVector3D[iOutVertexNum];
nuclear@0 477 }
nuclear@0 478 if (pMesh->HasNormals())
nuclear@0 479 {
nuclear@0 480 pcMesh->mNormals = new aiVector3D[iOutVertexNum];
nuclear@0 481 }
nuclear@0 482 if (pMesh->HasTangentsAndBitangents())
nuclear@0 483 {
nuclear@0 484 pcMesh->mTangents = new aiVector3D[iOutVertexNum];
nuclear@0 485 pcMesh->mBitangents = new aiVector3D[iOutVertexNum];
nuclear@0 486 }
nuclear@0 487 for (unsigned int c = 0; pMesh->HasVertexColors(c);++c)
nuclear@0 488 {
nuclear@0 489 pcMesh->mColors[c] = new aiColor4D[iOutVertexNum];
nuclear@0 490 }
nuclear@0 491 for (unsigned int c = 0; pMesh->HasTextureCoords(c);++c)
nuclear@0 492 {
nuclear@0 493 pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c];
nuclear@0 494 pcMesh->mTextureCoords[c] = new aiVector3D[iOutVertexNum];
nuclear@0 495 }
nuclear@0 496 vFaces.reserve(iEstimatedSize);
nuclear@0 497
nuclear@0 498 // (we will also need to copy the array of indices)
nuclear@0 499 while (iBase < pMesh->mNumFaces)
nuclear@0 500 {
nuclear@0 501 // allocate a new array
nuclear@0 502 const unsigned int iNumIndices = pMesh->mFaces[iBase].mNumIndices;
nuclear@0 503
nuclear@0 504 // doesn't catch degenerates but is quite fast
nuclear@0 505 unsigned int iNeed = 0;
nuclear@0 506 for (unsigned int v = 0; v < iNumIndices;++v)
nuclear@0 507 {
nuclear@0 508 unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
nuclear@0 509
nuclear@0 510 // check whether we do already have this vertex
nuclear@0 511 if (0xFFFFFFFF == avWasCopied[iIndex])
nuclear@0 512 {
nuclear@0 513 iNeed++;
nuclear@0 514 }
nuclear@0 515 }
nuclear@0 516 if (pcMesh->mNumVertices + iNeed > iOutVertexNum)
nuclear@0 517 {
nuclear@0 518 // don't use this face
nuclear@0 519 break;
nuclear@0 520 }
nuclear@0 521
nuclear@0 522 vFaces.push_back(aiFace());
nuclear@0 523 aiFace& rFace = vFaces.back();
nuclear@0 524
nuclear@0 525 // setup face type and number of indices
nuclear@0 526 rFace.mNumIndices = iNumIndices;
nuclear@0 527 rFace.mIndices = new unsigned int[iNumIndices];
nuclear@0 528
nuclear@0 529 // need to update the output primitive types
nuclear@0 530 switch (rFace.mNumIndices)
nuclear@0 531 {
nuclear@0 532 case 1:
nuclear@0 533 pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
nuclear@0 534 break;
nuclear@0 535 case 2:
nuclear@0 536 pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
nuclear@0 537 break;
nuclear@0 538 case 3:
nuclear@0 539 pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
nuclear@0 540 break;
nuclear@0 541 default:
nuclear@0 542 pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
nuclear@0 543 }
nuclear@0 544
nuclear@0 545 // and copy the contents of the old array, offset by current base
nuclear@0 546 for (unsigned int v = 0; v < iNumIndices;++v)
nuclear@0 547 {
nuclear@0 548 unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v];
nuclear@0 549
nuclear@0 550 // check whether we do already have this vertex
nuclear@0 551 if (0xFFFFFFFF != avWasCopied[iIndex])
nuclear@0 552 {
nuclear@0 553 rFace.mIndices[v] = avWasCopied[iIndex];
nuclear@0 554 continue;
nuclear@0 555 }
nuclear@0 556
nuclear@0 557 // copy positions
nuclear@0 558 pcMesh->mVertices[pcMesh->mNumVertices] = (pMesh->mVertices[iIndex]);
nuclear@0 559
nuclear@0 560 // copy normals
nuclear@0 561 if (pMesh->HasNormals())
nuclear@0 562 {
nuclear@0 563 pcMesh->mNormals[pcMesh->mNumVertices] = (pMesh->mNormals[iIndex]);
nuclear@0 564 }
nuclear@0 565
nuclear@0 566 // copy tangents/bitangents
nuclear@0 567 if (pMesh->HasTangentsAndBitangents())
nuclear@0 568 {
nuclear@0 569 pcMesh->mTangents[pcMesh->mNumVertices] = (pMesh->mTangents[iIndex]);
nuclear@0 570 pcMesh->mBitangents[pcMesh->mNumVertices] = (pMesh->mBitangents[iIndex]);
nuclear@0 571 }
nuclear@0 572
nuclear@0 573 // texture coordinates
nuclear@0 574 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c)
nuclear@0 575 {
nuclear@0 576 if (pMesh->HasTextureCoords( c))
nuclear@0 577 {
nuclear@0 578 pcMesh->mTextureCoords[c][pcMesh->mNumVertices] = pMesh->mTextureCoords[c][iIndex];
nuclear@0 579 }
nuclear@0 580 }
nuclear@0 581 // vertex colors
nuclear@0 582 for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c)
nuclear@0 583 {
nuclear@0 584 if (pMesh->HasVertexColors( c))
nuclear@0 585 {
nuclear@0 586 pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex];
nuclear@0 587 }
nuclear@0 588 }
nuclear@0 589 // check whether we have bone weights assigned to this vertex
nuclear@0 590 rFace.mIndices[v] = pcMesh->mNumVertices;
nuclear@0 591 if (avPerVertexWeights)
nuclear@0 592 {
nuclear@0 593 VertexWeightTable& table = avPerVertexWeights[ pcMesh->mNumVertices ];
nuclear@0 594 if( !table.empty() )
nuclear@0 595 {
nuclear@0 596 for (VertexWeightTable::const_iterator
nuclear@0 597 iter = table.begin();
nuclear@0 598 iter != table.end();++iter)
nuclear@0 599 {
nuclear@0 600 // allocate the bone weight array if necessary
nuclear@0 601 BoneWeightList* pcWeightList = (BoneWeightList*)pcMesh->mBones[(*iter).first];
nuclear@0 602 if (!pcWeightList)
nuclear@0 603 {
nuclear@0 604 pcMesh->mBones[(*iter).first] = (aiBone*)(pcWeightList = new BoneWeightList());
nuclear@0 605 }
nuclear@0 606 pcWeightList->push_back(aiVertexWeight(pcMesh->mNumVertices,(*iter).second));
nuclear@0 607 }
nuclear@0 608 }
nuclear@0 609 }
nuclear@0 610
nuclear@0 611 avWasCopied[iIndex] = pcMesh->mNumVertices;
nuclear@0 612 pcMesh->mNumVertices++;
nuclear@0 613 }
nuclear@0 614 iBase++;
nuclear@0 615 if(pcMesh->mNumVertices == iOutVertexNum)
nuclear@0 616 {
nuclear@0 617 // break here. The face is only added if it was complete
nuclear@0 618 break;
nuclear@0 619 }
nuclear@0 620 }
nuclear@0 621
nuclear@0 622 // check which bones we'll need to create for this submesh
nuclear@0 623 if (pMesh->HasBones())
nuclear@0 624 {
nuclear@0 625 aiBone** ppCurrent = pcMesh->mBones;
nuclear@0 626 for (unsigned int k = 0; k < pMesh->mNumBones;++k)
nuclear@0 627 {
nuclear@0 628 // check whether the bone is existing
nuclear@0 629 BoneWeightList* pcWeightList;
nuclear@0 630 if ((pcWeightList = (BoneWeightList*)pcMesh->mBones[k]))
nuclear@0 631 {
nuclear@0 632 aiBone* pcOldBone = pMesh->mBones[k];
nuclear@0 633 aiBone* pcOut;
nuclear@0 634 *ppCurrent++ = pcOut = new aiBone();
nuclear@0 635 pcOut->mName = aiString(pcOldBone->mName);
nuclear@0 636 pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix;
nuclear@0 637 pcOut->mNumWeights = (unsigned int)pcWeightList->size();
nuclear@0 638 pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights];
nuclear@0 639
nuclear@0 640 // copy the vertex weights
nuclear@0 641 ::memcpy(pcOut->mWeights,&pcWeightList->operator[](0),
nuclear@0 642 pcOut->mNumWeights * sizeof(aiVertexWeight));
nuclear@0 643
nuclear@0 644 // delete the temporary bone weight list
nuclear@0 645 delete pcWeightList;
nuclear@0 646 pcMesh->mNumBones++;
nuclear@0 647 }
nuclear@0 648 }
nuclear@0 649 }
nuclear@0 650
nuclear@0 651 // copy the face list to the mesh
nuclear@0 652 pcMesh->mFaces = new aiFace[vFaces.size()];
nuclear@0 653 pcMesh->mNumFaces = (unsigned int)vFaces.size();
nuclear@0 654
nuclear@0 655 for (unsigned int p = 0; p < pcMesh->mNumFaces;++p)
nuclear@0 656 pcMesh->mFaces[p] = vFaces[p];
nuclear@0 657
nuclear@0 658 // add the newly created mesh to the list
nuclear@0 659 avList.push_back(std::pair<aiMesh*, unsigned int>(pcMesh,a));
nuclear@0 660
nuclear@0 661 if (iBase == pMesh->mNumFaces)
nuclear@0 662 {
nuclear@0 663 // have all faces ... finish the outer loop, too
nuclear@0 664 break;
nuclear@0 665 }
nuclear@0 666 }
nuclear@0 667
nuclear@0 668 // delete the per-vertex weight list again
nuclear@0 669 delete[] avPerVertexWeights;
nuclear@0 670
nuclear@0 671 // now delete the old mesh data
nuclear@0 672 delete pMesh;
nuclear@0 673 return;
nuclear@0 674 }
nuclear@0 675 avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a));
nuclear@0 676 return;
nuclear@0 677 }