Coverage Report

Created: 2026-04-29 07:04

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