Coverage Report

Created: 2026-01-07 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/Material/MaterialSystem.cpp
Line
Count
Source
1
/*
2
Open Asset Import Library (assimp)
3
----------------------------------------------------------------------
4
5
Copyright (c) 2006-2025, 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  MaterialSystem.cpp
43
 *  @brief Implementation of the material system of the library
44
 */
45
46
#include "MaterialSystem.h"
47
#include <assimp/Hash.h>
48
#include <assimp/ParsingUtils.h>
49
#include <assimp/fast_atof.h>
50
#include <assimp/material.h>
51
#include <assimp/types.h>
52
#include <assimp/DefaultLogger.hpp>
53
#include <memory>
54
55
using namespace Assimp;
56
57
// ------------------------------------------------------------------------------------------------
58
// Get a specific property from a material
59
aiReturn aiGetMaterialProperty(const aiMaterial *pMat,
60
        const char *pKey,
61
        unsigned int type,
62
        unsigned int index,
63
1.65k
        const aiMaterialProperty **pPropOut) {
64
1.65k
    ai_assert(pMat != nullptr);
65
1.65k
    ai_assert(pKey != nullptr);
66
1.65k
    ai_assert(pPropOut != nullptr);
67
68
    /*  Just search for a property with exactly this name ..
69
     *  could be improved by hashing, but it's possibly
70
     *  no worth the effort (we're bound to C structures,
71
     *  thus std::map or derivates are not applicable. */
72
8.83k
    for (unsigned int i = 0; i < pMat->mNumProperties; ++i) {
73
8.59k
        aiMaterialProperty *prop = pMat->mProperties[i];
74
75
8.59k
        if (prop /* just for safety ... */
76
8.59k
                && 0 == strncmp(prop->mKey.data, pKey, strlen(pKey)) && (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wild-card, but this is undocumented :-) */
77
1.42k
                && (UINT_MAX == index || prop->mIndex == index)) {
78
1.42k
            *pPropOut = pMat->mProperties[i];
79
1.42k
            return AI_SUCCESS;
80
1.42k
        }
81
8.59k
    }
82
237
    *pPropOut = nullptr;
83
237
    return AI_FAILURE;
84
1.65k
}
85
86
namespace
87
{
88
89
// ------------------------------------------------------------------------------------------------
90
// Implementation of functions "aiGetMaterialFloatArray" and "aiGetMaterialFloatFloatArray".
91
template <class TReal>
92
aiReturn GetMaterialFloatArray(const aiMaterial *pMat,
93
        const char *pKey,
94
        unsigned int type,
95
        unsigned int index,
96
        TReal *pOut,
97
979
        unsigned int *pMax) {
98
979
    ai_assert(pOut != nullptr);
99
979
    ai_assert(pMat != nullptr);
100
101
979
    const aiMaterialProperty *prop;
102
979
    aiGetMaterialProperty(pMat, pKey, type, index, (const aiMaterialProperty **)&prop);
103
979
    if (nullptr == prop) {
104
218
        return AI_FAILURE;
105
218
    }
106
107
    // data is given in floats, convert to TReal
108
761
    unsigned int iWrite = 0;
109
761
    if (aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) {
110
761
        iWrite = prop->mDataLength / sizeof(float);
111
761
        if (pMax) {
112
247
            iWrite = std::min(*pMax, iWrite);
113
247
            ;
114
247
        }
115
116
2.04k
        for (unsigned int a = 0; a < iWrite; ++a) {
117
1.28k
            pOut[a] = static_cast<TReal>(reinterpret_cast<float *>(prop->mData)[a]);
118
1.28k
        }
119
120
761
        if (pMax) {
121
247
            *pMax = iWrite;
122
247
        }
123
761
    }
124
    // data is given in doubles, convert to TReal
125
0
    else if (aiPTI_Double == prop->mType) {
126
0
        iWrite = prop->mDataLength / sizeof(double);
127
0
        if (pMax) {
128
0
            iWrite = std::min(*pMax, iWrite);
129
0
            ;
130
0
        }
131
0
        for (unsigned int a = 0; a < iWrite; ++a) {
132
0
            pOut[a] = static_cast<TReal>(reinterpret_cast<double *>(prop->mData)[a]);
133
0
        }
134
0
        if (pMax) {
135
0
            *pMax = iWrite;
136
0
        }
137
0
    }
138
    // data is given in ints, convert to TReal
139
0
    else if (aiPTI_Integer == prop->mType) {
140
0
        iWrite = prop->mDataLength / sizeof(int32_t);
141
0
        if (pMax) {
142
0
            iWrite = std::min(*pMax, iWrite);
143
0
            ;
144
0
        }
145
0
        for (unsigned int a = 0; a < iWrite; ++a) {
146
0
            pOut[a] = static_cast<TReal>(reinterpret_cast<int32_t *>(prop->mData)[a]);
147
0
        }
148
0
        if (pMax) {
149
0
            *pMax = iWrite;
150
0
        }
151
0
    }
152
    // a string ... read floats separated by spaces
153
0
    else {
154
0
        if (pMax) {
155
0
            iWrite = *pMax;
156
0
        }
157
        // strings are zero-terminated with a 32 bit length prefix, so this is safe
158
0
        const char *cur = prop->mData + 4;
159
0
        ai_assert(prop->mDataLength >= 5);
160
0
        ai_assert(!prop->mData[prop->mDataLength - 1]);
161
0
        for (unsigned int a = 0;; ++a) {
162
0
            cur = fast_atoreal_move(cur, pOut[a]);
163
0
            if (a == iWrite - 1) {
164
0
                break;
165
0
            }
166
0
            if (!IsSpace(*cur)) {
167
0
                ASSIMP_LOG_ERROR("Material property", pKey,
168
0
                                 " is a string; failed to parse a float array out of it.");
169
0
                return AI_FAILURE;
170
0
            }
171
0
        }
172
173
0
        if (pMax) {
174
0
            *pMax = iWrite;
175
0
        }
176
0
    }
177
761
    return AI_SUCCESS;
178
761
}
179
180
// ------------------------------------------------------------------------------------------------
181
// Get an array of float typed float values from the material.
182
aiReturn aiGetMaterialFloatFloatArray(const aiMaterial *pMat,
183
        const char *pKey,
184
        unsigned int type,
185
        unsigned int index,
186
        float *pOut,
187
360
        unsigned int *pMax) {
188
360
    return ::GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
189
360
}
190
191
} // namespace
192
193
// ------------------------------------------------------------------------------------------------
194
// Get an array of floating-point values from the material.
195
aiReturn aiGetMaterialFloatArray(const aiMaterial *pMat,
196
        const char *pKey,
197
        unsigned int type,
198
        unsigned int index,
199
        ai_real *pOut,
200
619
        unsigned int *pMax) {
201
619
    return ::GetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax);
202
619
}
203
204
// ------------------------------------------------------------------------------------------------
205
// Get an array if integers from the material
206
aiReturn aiGetMaterialIntegerArray(const aiMaterial *pMat,
207
        const char *pKey,
208
        unsigned int type,
209
        unsigned int index,
210
        int *pOut,
211
442
        unsigned int *pMax) {
212
442
    ai_assert(pOut != nullptr);
213
442
    ai_assert(pMat != nullptr);
214
215
442
    const aiMaterialProperty *prop;
216
442
    aiGetMaterialProperty(pMat, pKey, type, index, (const aiMaterialProperty **)&prop);
217
442
    if (!prop) {
218
19
        return AI_FAILURE;
219
19
    }
220
221
    // data is given in ints, simply copy it
222
423
    unsigned int iWrite = 0;
223
423
    if (aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) {
224
423
        iWrite = std::max(static_cast<unsigned int>(prop->mDataLength / sizeof(int32_t)), 1u);
225
423
        if (pMax) {
226
0
            iWrite = std::min(*pMax, iWrite);
227
0
        }
228
423
        if (1 == prop->mDataLength) {
229
            // bool type, 1 byte
230
0
            *pOut = static_cast<int>(*prop->mData);
231
423
        } else {
232
846
            for (unsigned int a = 0; a < iWrite; ++a) {
233
423
                pOut[a] = static_cast<int>(reinterpret_cast<int32_t *>(prop->mData)[a]);
234
423
            }
235
423
        }
236
423
        if (pMax) {
237
0
            *pMax = iWrite;
238
0
        }
239
423
    }
240
    // data is given in floats convert to int
241
0
    else if (aiPTI_Float == prop->mType) {
242
0
        iWrite = prop->mDataLength / sizeof(float);
243
0
        if (pMax) {
244
0
            iWrite = std::min(*pMax, iWrite);
245
0
            ;
246
0
        }
247
0
        for (unsigned int a = 0; a < iWrite; ++a) {
248
0
            pOut[a] = static_cast<int>(reinterpret_cast<float *>(prop->mData)[a]);
249
0
        }
250
0
        if (pMax) {
251
0
            *pMax = iWrite;
252
0
        }
253
0
    }
254
    // it is a string ... no way to read something out of this
255
0
    else {
256
0
        if (pMax) {
257
0
            iWrite = *pMax;
258
0
        }
259
        // strings are zero-terminated with a 32 bit length prefix, so this is safe
260
0
        const char *cur = prop->mData + 4;
261
0
        ai_assert(prop->mDataLength >= 5);
262
0
        ai_assert(!prop->mData[prop->mDataLength - 1]);
263
0
        for (unsigned int a = 0;; ++a) {
264
0
            pOut[a] = strtol10(cur, &cur);
265
0
            if (a == iWrite - 1) {
266
0
                break;
267
0
            }
268
0
            if (!IsSpace(*cur)) {
269
0
                ASSIMP_LOG_ERROR("Material property", pKey,
270
0
                                 " is a string; failed to parse an integer array out of it.");
271
0
                return AI_FAILURE;
272
0
            }
273
0
        }
274
275
0
        if (pMax) {
276
0
            *pMax = iWrite;
277
0
        }
278
0
    }
279
423
    return AI_SUCCESS;
280
423
}
281
282
// ------------------------------------------------------------------------------------------------
283
// Get a color (3 or 4 floats) from the material
284
aiReturn aiGetMaterialColor(const aiMaterial *pMat,
285
        const char *pKey,
286
        unsigned int type,
287
        unsigned int index,
288
360
        aiColor4D *pOut) {
289
360
    unsigned int iMax = 4;
290
360
    const aiReturn eRet = aiGetMaterialFloatFloatArray(pMat, pKey, type, index, (float *)pOut, &iMax);
291
292
    // if no alpha channel is defined: set it to 1.0
293
360
    if (3 == iMax) {
294
215
        pOut->a = 1.0;
295
215
    }
296
297
360
    return eRet;
298
360
}
299
300
// ------------------------------------------------------------------------------------------------
301
// Get a aiUVTransform (5 floats) from the material
302
aiReturn aiGetMaterialUVTransform(const aiMaterial *pMat,
303
        const char *pKey,
304
        unsigned int type,
305
        unsigned int index,
306
0
        aiUVTransform *pOut) {
307
0
    unsigned int iMax = 5;
308
0
    return aiGetMaterialFloatArray(pMat, pKey, type, index, (ai_real *)pOut, &iMax);
309
0
}
310
311
// ------------------------------------------------------------------------------------------------
312
// Get a string from the material
313
aiReturn aiGetMaterialString(const aiMaterial *pMat,
314
        const char *pKey,
315
        unsigned int type,
316
        unsigned int index,
317
238
        aiString *pOut) {
318
238
    ai_assert(pOut != nullptr);
319
320
238
    const aiMaterialProperty *prop;
321
238
    aiGetMaterialProperty(pMat, pKey, type, index, (const aiMaterialProperty **)&prop);
322
238
    if (!prop) {
323
0
        return AI_FAILURE;
324
0
    }
325
326
238
    if (aiPTI_String == prop->mType) {
327
238
        ai_assert(prop->mDataLength >= 5);
328
329
        // The string is stored as 32 but length prefix followed by zero-terminated UTF8 data
330
238
        pOut->length = static_cast<unsigned int>(*reinterpret_cast<uint32_t *>(prop->mData));
331
332
238
        ai_assert(pOut->length + 1 + 4 == prop->mDataLength);
333
238
        ai_assert(!prop->mData[prop->mDataLength - 1]);
334
238
        memcpy(pOut->data, prop->mData + 4, pOut->length + 1);
335
238
    } else {
336
        // TODO - implement lexical cast as well
337
0
        ASSIMP_LOG_ERROR("Material property", pKey, " was found, but is no string");
338
0
        return AI_FAILURE;
339
0
    }
340
238
    return AI_SUCCESS;
341
238
}
342
343
// ------------------------------------------------------------------------------------------------
344
// Get a c-like string fron an aiString
345
0
const char *aiGetStringC_Str(const aiString *str) {
346
0
  return str->data;
347
0
}
348
349
// ------------------------------------------------------------------------------------------------
350
// Get the number of textures on a particular texture stack
351
3.06k
unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial *pMat, C_ENUM aiTextureType type) {
352
3.06k
    ai_assert(pMat != nullptr);
353
354
    // Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again)
355
3.06k
    unsigned int max = 0;
356
31.1k
    for (unsigned int i = 0; i < pMat->mNumProperties; ++i) {
357
28.0k
        aiMaterialProperty *prop = pMat->mProperties[i];
358
359
28.0k
        if (prop /* just a sanity check ... */
360
28.0k
                && 0 == strcmp(prop->mKey.data, _AI_MATKEY_TEXTURE_BASE) && static_cast<aiTextureType>(prop->mSemantic) == type) {
361
362
4
            max = std::max(max, prop->mIndex + 1);
363
4
        }
364
28.0k
    }
365
3.06k
    return max;
366
3.06k
}
367
368
// ------------------------------------------------------------------------------------------------
369
aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial *mat,
370
        aiTextureType type,
371
        unsigned int index,
372
        C_STRUCT aiString *path,
373
        aiTextureMapping *_mapping /*= nullptr*/,
374
        unsigned int *uvindex /*= nullptr*/,
375
        ai_real *blend /*= nullptr*/,
376
        aiTextureOp *op /*= nullptr*/,
377
        aiTextureMapMode *mapmode /*= nullptr*/,
378
        unsigned int *flags /*= nullptr*/
379
3
) {
380
3
    ai_assert(nullptr != mat);
381
3
    ai_assert(nullptr != path);
382
383
    // Get the path to the texture
384
3
    if (AI_SUCCESS != aiGetMaterialString(mat, AI_MATKEY_TEXTURE(type, index), path)) {
385
0
        return AI_FAILURE;
386
0
    }
387
388
    // Determine mapping type
389
3
    int mapping_ = static_cast<int>(aiTextureMapping_UV);
390
3
    aiGetMaterialInteger(mat, AI_MATKEY_MAPPING(type, index), &mapping_);
391
3
    aiTextureMapping mapping = static_cast<aiTextureMapping>(mapping_);
392
3
    if (_mapping)
393
0
        *_mapping = mapping;
394
395
    // Get UV index
396
3
    if (aiTextureMapping_UV == mapping && uvindex) {
397
0
        aiGetMaterialInteger(mat, AI_MATKEY_UVWSRC(type, index), (int *)uvindex);
398
0
    }
399
    // Get blend factor
400
3
    if (blend) {
401
0
        aiGetMaterialFloat(mat, AI_MATKEY_TEXBLEND(type, index), blend);
402
0
    }
403
    // Get texture operation
404
3
    if (op) {
405
0
        aiGetMaterialInteger(mat, AI_MATKEY_TEXOP(type, index), (int *)op);
406
0
    }
407
    // Get texture mapping modes
408
3
    if (mapmode) {
409
0
        aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_U(type, index), (int *)&mapmode[0]);
410
0
        aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_V(type, index), (int *)&mapmode[1]);
411
0
    }
412
    // Get texture flags
413
3
    if (flags) {
414
0
        aiGetMaterialInteger(mat, AI_MATKEY_TEXFLAGS(type, index), (int *)flags);
415
0
    }
416
417
3
    return AI_SUCCESS;
418
3
}
419
420
static const unsigned int DefaultNumAllocated = 5;
421
422
// ------------------------------------------------------------------------------------------------
423
// Construction. Actually the one and only way to get an aiMaterial instance
424
aiMaterial::aiMaterial() :
425
1.15k
        mProperties(nullptr), mNumProperties(0), mNumAllocated(DefaultNumAllocated) {
426
    // Allocate 5 entries by default
427
1.15k
    mProperties = new aiMaterialProperty *[DefaultNumAllocated];
428
1.15k
}
429
430
// ------------------------------------------------------------------------------------------------
431
1.15k
aiMaterial::~aiMaterial() {
432
1.15k
    Clear();
433
434
1.15k
    delete[] mProperties;
435
1.15k
}
436
437
// ------------------------------------------------------------------------------------------------
438
0
aiString aiMaterial::GetName() const {
439
0
    aiString name;
440
0
    Get(AI_MATKEY_NAME, name);
441
442
0
    return name;
443
0
}
444
445
// ------------------------------------------------------------------------------------------------
446
1.20k
void aiMaterial::Clear() {
447
13.1k
    for (unsigned int i = 0; i < mNumProperties; ++i) {
448
        // delete this entry
449
11.9k
        delete mProperties[i];
450
11.9k
        AI_DEBUG_INVALIDATE_PTR(mProperties[i]);
451
11.9k
    }
452
1.20k
    mNumProperties = 0;
453
454
    // The array remains allocated, we just invalidated its contents
455
1.20k
}
456
457
// ------------------------------------------------------------------------------------------------
458
0
aiReturn aiMaterial::RemoveProperty(const char *pKey, unsigned int type, unsigned int index) {
459
0
    ai_assert(nullptr != pKey);
460
461
0
    for (unsigned int i = 0; i < mNumProperties; ++i) {
462
0
        aiMaterialProperty *prop = mProperties[i];
463
464
0
        if (prop && !strcmp(prop->mKey.data, pKey) &&
465
0
                prop->mSemantic == type && prop->mIndex == index) {
466
            // Delete this entry
467
0
            delete mProperties[i];
468
469
            // collapse the array behind --.
470
0
            --mNumProperties;
471
0
            for (unsigned int a = i; a < mNumProperties; ++a) {
472
0
                mProperties[a] = mProperties[a + 1];
473
0
            }
474
0
            return AI_SUCCESS;
475
0
        }
476
0
    }
477
478
0
    return AI_FAILURE;
479
0
}
480
481
// ------------------------------------------------------------------------------------------------
482
aiReturn aiMaterial::AddBinaryProperty(const void *pInput,
483
        unsigned int pSizeInBytes,
484
        const char *pKey,
485
        unsigned int type,
486
        unsigned int index,
487
11.5k
        aiPropertyTypeInfo pType) {
488
11.5k
    ai_assert(pInput != nullptr);
489
11.5k
    ai_assert(pKey != nullptr);
490
11.5k
    ai_assert(0 != pSizeInBytes);
491
492
11.5k
    if (0 == pSizeInBytes) {
493
0
        return AI_FAILURE;
494
0
    }
495
496
    // first search the list whether there is already an entry with this key
497
11.5k
    unsigned int iOutIndex(UINT_MAX);
498
68.4k
    for (unsigned int i = 0; i < mNumProperties; ++i) {
499
56.9k
        aiMaterialProperty *prop(mProperties[i]);
500
501
56.9k
        if (prop /* just for safety */ && !strcmp(prop->mKey.data, pKey) &&
502
24
                prop->mSemantic == type && prop->mIndex == index) {
503
504
2
            delete mProperties[i];
505
2
            iOutIndex = i;
506
2
        }
507
56.9k
    }
508
509
    // Allocate a new material property
510
11.5k
    std::unique_ptr<aiMaterialProperty> pcNew(new aiMaterialProperty());
511
512
    // .. and fill it
513
11.5k
    pcNew->mType = pType;
514
11.5k
    pcNew->mSemantic = type;
515
11.5k
    pcNew->mIndex = index;
516
517
11.5k
    pcNew->mDataLength = pSizeInBytes;
518
11.5k
    pcNew->mData = new char[pSizeInBytes];
519
11.5k
    memcpy(pcNew->mData, pInput, pSizeInBytes);
520
521
11.5k
    pcNew->mKey.length = static_cast<ai_uint32>(::strlen(pKey));
522
11.5k
    ai_assert(AI_MAXLEN > pcNew->mKey.length);
523
11.5k
    strcpy(pcNew->mKey.data, pKey);
524
525
11.5k
    if (UINT_MAX != iOutIndex) {
526
2
        mProperties[iOutIndex] = pcNew.release();
527
2
        return AI_SUCCESS;
528
2
    }
529
530
    // resize the array ... double the storage allocated
531
11.5k
    if (mNumProperties == mNumAllocated) {
532
1.58k
        const unsigned int iOld = mNumAllocated;
533
1.58k
        mNumAllocated *= 2;
534
535
1.58k
        aiMaterialProperty **ppTemp;
536
1.58k
        try {
537
1.58k
            ppTemp = new aiMaterialProperty *[mNumAllocated];
538
1.58k
        } catch (std::bad_alloc &) {
539
0
            return AI_OUTOFMEMORY;
540
0
        }
541
542
        // just copy all items over; then replace the old array
543
1.58k
        memcpy(ppTemp, mProperties, iOld * sizeof(void *));
544
545
1.58k
        delete[] mProperties;
546
1.58k
        mProperties = ppTemp;
547
1.58k
    }
548
    // push back ...
549
11.5k
    mProperties[mNumProperties++] = pcNew.release();
550
551
11.5k
    return AI_SUCCESS;
552
11.5k
}
553
554
// ------------------------------------------------------------------------------------------------
555
aiReturn aiMaterial::AddProperty(const aiString *pInput,
556
        const char *pKey,
557
        unsigned int type,
558
1.60k
        unsigned int index) {
559
1.60k
    ai_assert(sizeof(ai_uint32) == 4);
560
1.60k
    return AddBinaryProperty(pInput,
561
1.60k
            static_cast<unsigned int>(pInput->length + 1 + 4),
562
1.60k
            pKey,
563
1.60k
            type,
564
1.60k
            index,
565
1.60k
            aiPTI_String);
566
1.60k
}
567
568
// ------------------------------------------------------------------------------------------------
569
249
uint32_t Assimp::ComputeMaterialHash(const aiMaterial *mat, bool includeMatName /*= false*/) {
570
249
    uint32_t hash = 1503; // magic start value, chosen to be my birthday :-)
571
2.73k
    for (unsigned int i = 0; i < mat->mNumProperties; ++i) {
572
2.48k
        aiMaterialProperty *prop;
573
574
        // Exclude all properties whose first character is '?' from the hash
575
        // See doc for aiMaterialProperty.
576
2.48k
        prop = mat->mProperties[i];
577
2.48k
        if (nullptr != prop && (includeMatName || prop->mKey.data[0] != '?')) {
578
579
2.23k
            hash = SuperFastHash(prop->mKey.data, (unsigned int)prop->mKey.length, hash);
580
2.23k
            hash = SuperFastHash(prop->mData, prop->mDataLength, hash);
581
582
            // Combine the semantic and the index with the hash
583
2.23k
            hash = SuperFastHash((const char *)&prop->mSemantic, sizeof(unsigned int), hash);
584
2.23k
            hash = SuperFastHash((const char *)&prop->mIndex, sizeof(unsigned int), hash);
585
2.23k
        }
586
2.48k
    }
587
249
    return hash;
588
249
}
589
590
// ------------------------------------------------------------------------------------------------
591
void aiMaterial::CopyPropertyList(aiMaterial *const pcDest,
592
0
        const aiMaterial *pcSrc) {
593
0
    ai_assert(nullptr != pcDest);
594
0
    ai_assert(nullptr != pcSrc);
595
0
    ai_assert(pcDest->mNumProperties <= pcDest->mNumAllocated);
596
0
    ai_assert(pcSrc->mNumProperties <= pcSrc->mNumAllocated);
597
598
0
    const unsigned int iOldNum = pcDest->mNumProperties;
599
0
    pcDest->mNumAllocated += pcSrc->mNumAllocated;
600
0
    pcDest->mNumProperties += pcSrc->mNumProperties;
601
602
0
    const unsigned int numAllocated = pcDest->mNumAllocated;
603
0
    aiMaterialProperty **pcOld = pcDest->mProperties;
604
0
    pcDest->mProperties = new aiMaterialProperty *[numAllocated];
605
606
0
    ai_assert(!iOldNum || pcOld);
607
0
    ai_assert(iOldNum < numAllocated);
608
609
0
    if (iOldNum && pcOld) {
610
0
        for (unsigned int i = 0; i < iOldNum; ++i) {
611
0
            pcDest->mProperties[i] = pcOld[i];
612
0
        }
613
0
    }
614
615
0
    if (pcOld) {
616
0
        delete[] pcOld;
617
0
    }
618
619
0
    for (unsigned int i = iOldNum; i < pcDest->mNumProperties; ++i) {
620
0
        aiMaterialProperty *propSrc = pcSrc->mProperties[i];
621
622
        // search whether we have already a property with this name -> if yes, overwrite it
623
0
        aiMaterialProperty *prop;
624
0
        for (unsigned int q = 0; q < iOldNum; ++q) {
625
0
            prop = pcDest->mProperties[q];
626
0
            if (prop /* just for safety */ && prop->mKey == propSrc->mKey && prop->mSemantic == propSrc->mSemantic && prop->mIndex == propSrc->mIndex) {
627
0
                delete prop;
628
629
                // collapse the whole array ...
630
0
                memmove(&pcDest->mProperties[q], &pcDest->mProperties[q + 1], i - q);
631
0
                i--;
632
0
                pcDest->mNumProperties--;
633
0
            }
634
0
        }
635
636
        // Allocate the output property and copy the source property
637
0
        prop = pcDest->mProperties[i] = new aiMaterialProperty();
638
0
        prop->mKey = propSrc->mKey;
639
0
        prop->mDataLength = propSrc->mDataLength;
640
0
        prop->mType = propSrc->mType;
641
0
        prop->mSemantic = propSrc->mSemantic;
642
0
        prop->mIndex = propSrc->mIndex;
643
644
0
        prop->mData = new char[propSrc->mDataLength];
645
0
        memcpy(prop->mData, propSrc->mData, prop->mDataLength);
646
0
    }
647
0
}