Coverage Report

Created: 2026-05-23 06: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
7.19k
SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() {
52
7.19k
    LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES;
53
7.19k
}
54
55
// ------------------------------------------------------------------------------------------------
56
// Returns whether the processing step is present in the given flag field.
57
1.59k
bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const {
58
1.59k
    return (pFlags & aiProcess_SplitLargeMeshes) != 0;
59
1.59k
}
60
61
// ------------------------------------------------------------------------------------------------
62
// Executes the post processing step on the given imported data.
63
1.59k
void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) {
64
1.59k
    if (0xffffffff == this->LIMIT || nullptr == pScene ) {
65
0
        return;
66
0
    }
67
68
1.59k
    ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle begin");
69
1.59k
    std::vector<std::pair<aiMesh*, unsigned int> > avList;
70
71
3.87k
    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
72
2.27k
        this->SplitMesh(a, pScene->mMeshes[a],avList);
73
2.27k
    }
74
75
1.59k
    if (avList.size() == pScene->mNumMeshes) {
76
1.59k
        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do");
77
1.59k
    }
78
79
    // it seems something has been split. rebuild the mesh list
80
1.59k
    delete[] pScene->mMeshes;
81
1.59k
    pScene->mNumMeshes = (unsigned int)avList.size();
82
1.59k
    pScene->mMeshes = new aiMesh*[avList.size()];
83
84
3.87k
    for (unsigned int i = 0; i < avList.size();++i) {
85
2.27k
        pScene->mMeshes[i] = avList[i].first;
86
2.27k
    }
87
88
    // now we need to update all nodes
89
1.59k
    this->UpdateNode(pScene->mRootNode,avList);
90
1.59k
    ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split");
91
1.59k
}
92
93
// ------------------------------------------------------------------------------------------------
94
// Setup properties
95
1.59k
void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) {
96
    // get the current value of the split property
97
1.59k
    this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES);
98
1.59k
}
99
100
// ------------------------------------------------------------------------------------------------
101
// Update a node after some meshes have been split
102
7.64k
void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, const std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
103
7.64k
    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
7.64k
    std::vector<unsigned int> aiEntries;
110
7.64k
    aiEntries.reserve(pcNode->mNumMeshes + 1);
111
10.6k
    for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) {
112
10.4k
        for (unsigned int a = 0; a < avList.size();++a) {
113
7.49k
            if (avList[a].second == pcNode->mMeshes[i]) {
114
2.96k
                aiEntries.push_back(a);
115
2.96k
            }
116
7.49k
        }
117
2.96k
    }
118
119
    // now build the new list
120
7.64k
    delete[] pcNode->mMeshes;
121
7.64k
    pcNode->mNumMeshes = (unsigned int)aiEntries.size();
122
7.64k
    pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
123
124
10.6k
    for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) {
125
2.96k
        pcNode->mMeshes[b] = aiEntries[b];
126
2.96k
    }
127
128
    // recursively update all other nodes
129
13.6k
    for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
130
6.05k
        UpdateNode ( pcNode->mChildren[i], avList );
131
6.05k
    }
132
7.64k
}
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
2.27k
        std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
140
2.27k
    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
2.27k
    } else {
321
2.27k
        avList.emplace_back(pMesh,a);
322
2.27k
    }
323
2.27k
}
324
325
// ------------------------------------------------------------------------------------------------
326
7.19k
SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() {
327
7.19k
    LIMIT = AI_SLM_DEFAULT_MAX_VERTICES;
328
7.19k
}
329
330
// ------------------------------------------------------------------------------------------------
331
// Returns whether the processing step is present in the given flag field.
332
1.59k
bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const {
333
1.59k
    return (pFlags & aiProcess_SplitLargeMeshes) != 0;
334
1.59k
}
335
336
// ------------------------------------------------------------------------------------------------
337
// Executes the post processing step on the given imported data.
338
1.59k
void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) {
339
1.59k
    if (0xffffffff == this->LIMIT || nullptr == pScene ) {
340
0
        return;
341
0
    }
342
343
1.59k
    ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex begin");
344
345
1.59k
    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
3.05k
    for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
350
1.87k
        if ( pScene->mMeshes[a]->mPrimitiveTypes == aiPrimitiveType_POINT ) {
351
413
            return;
352
413
        }
353
1.87k
    }
354
355
2.62k
    for( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
356
1.44k
        this->SplitMesh(a, pScene->mMeshes[a], avList);
357
1.44k
    }
358
359
1.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
1.17k
    } else {
373
1.17k
        ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex finished. There was nothing to do");
374
1.17k
    }
375
1.17k
}
376
377
// ------------------------------------------------------------------------------------------------
378
// Setup properties
379
1.59k
void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) {
380
1.59k
    this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES);
381
1.59k
}
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
1.44k
        std::vector<std::pair<aiMesh*, unsigned int> >& avList) {
389
1.44k
    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
1.44k
    avList.emplace_back(pMesh,a);
615
1.44k
}