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