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