Coverage Report

Created: 2026-05-23 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/Common/Importer.cpp
Line
Count
Source
1
/*
2
---------------------------------------------------------------------------
3
Open Asset Import Library (assimp)
4
---------------------------------------------------------------------------
5
6
Copyright (c) 2006-2026, assimp team
7
8
All rights reserved.
9
10
Redistribution and use of this software in source and binary forms,
11
with or without modification, are permitted provided that the following
12
conditions are met:
13
14
* Redistributions of source code must retain the above
15
  copyright notice, this list of conditions and the
16
  following disclaimer.
17
18
* Redistributions in binary form must reproduce the above
19
  copyright notice, this list of conditions and the
20
  following disclaimer in the documentation and/or other
21
  materials provided with the distribution.
22
23
* Neither the name of the assimp team, nor the names of its
24
  contributors may be used to endorse or promote products
25
  derived from this software without specific prior
26
  written permission of the assimp team.
27
28
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
---------------------------------------------------------------------------
40
*/
41
42
/** @file  Importer.cpp
43
 *  @brief Implementation of the CPP-API class #Importer
44
 */
45
46
#include <assimp/version.h>
47
#include <assimp/config.h>
48
#include <assimp/importerdesc.h>
49
50
// ------------------------------------------------------------------------------------------------
51
/* Uncomment this line to prevent Assimp from catching unknown exceptions.
52
 *
53
 * Note that any Exception except DeadlyImportError may lead to
54
 * undefined behaviour -> loaders could remain in an unusable state and
55
 * further imports with the same Importer instance could fail/crash/burn ...
56
 */
57
// ------------------------------------------------------------------------------------------------
58
#ifndef ASSIMP_BUILD_DEBUG
59
#   define ASSIMP_CATCH_GLOBAL_EXCEPTIONS
60
#endif
61
62
// ------------------------------------------------------------------------------------------------
63
// Internal headers
64
// ------------------------------------------------------------------------------------------------
65
#include "Common/Importer.h"
66
#include "Common/BaseProcess.h"
67
#include "Common/DefaultProgressHandler.h"
68
#include "PostProcessing/ProcessHelper.h"
69
#include "Common/ScenePreprocessor.h"
70
#include "Common/ScenePrivate.h"
71
72
#include <assimp/BaseImporter.h>
73
#include <assimp/GenericProperty.h>
74
#include <assimp/MemoryIOWrapper.h>
75
#include <assimp/Profiler.h>
76
#include <assimp/TinyFormatter.h>
77
#include <assimp/Exceptional.h>
78
#include <assimp/Profiler.h>
79
#include <assimp/commonMetaData.h>
80
81
#include <exception>
82
#include <set>
83
#include <memory>
84
#include <cctype>
85
86
#include <assimp/DefaultIOStream.h>
87
#include <assimp/DefaultIOSystem.h>
88
89
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
90
#   include "PostProcessing/ValidateDataStructure.h"
91
#endif
92
93
using namespace Assimp::Profiling;
94
using namespace Assimp::Formatter;
95
96
namespace Assimp {
97
    // ImporterRegistry.cpp
98
    void GetImporterInstanceList(std::vector< BaseImporter* >& out);
99
  void DeleteImporterInstanceList(std::vector< BaseImporter* >& out);
100
101
    // PostStepRegistry.cpp
102
    void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
103
}
104
105
using namespace Assimp;
106
using namespace Assimp::Intern;
107
108
// ------------------------------------------------------------------------------------------------
109
// Intern::AllocateFromAssimpHeap serves as abstract base class. It overrides
110
// new and delete (and their array counterparts) of public API classes (e.g. Logger) to
111
// utilize our DLL heap.
112
// See http://www.gotw.ca/publications/mill15.htm
113
// ------------------------------------------------------------------------------------------------
114
327k
void* AllocateFromAssimpHeap::operator new ( size_t num_bytes)  {
115
327k
    return ::operator new(num_bytes);
116
327k
}
117
118
0
void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothrow_t& ) throw()  {
119
0
    try {
120
0
        return AllocateFromAssimpHeap::operator new( num_bytes );
121
0
    }
122
0
    catch( ... )    {
123
0
        return nullptr;
124
0
    }
125
0
}
126
127
327k
void AllocateFromAssimpHeap::operator delete ( void* data)  {
128
327k
    return ::operator delete(data);
129
327k
}
130
131
0
void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes)    {
132
0
    return ::operator new[](num_bytes);
133
0
}
134
135
0
void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() {
136
0
    try {
137
0
        return AllocateFromAssimpHeap::operator new[]( num_bytes );
138
0
    } catch( ... )    {
139
0
        return nullptr;
140
0
    }
141
0
}
142
143
0
void AllocateFromAssimpHeap::operator delete[] ( void* data)    {
144
0
    return ::operator delete[](data);
145
0
}
146
147
// ------------------------------------------------------------------------------------------------
148
// Importer constructor.
149
Importer::Importer()
150
40.6k
 : pimpl( new ImporterPimpl ) {
151
40.6k
    pimpl->mScene = nullptr;
152
40.6k
    pimpl->mErrorString = std::string();
153
154
    // Allocate a default IO handler
155
40.6k
    pimpl->mIOHandler = new DefaultIOSystem;
156
40.6k
    pimpl->mIsDefaultHandler = true;
157
40.6k
    pimpl->bExtraVerbose     = false; // disable extra verbose mode by default
158
159
40.6k
    pimpl->mProgressHandler = new DefaultProgressHandler();
160
40.6k
    pimpl->mIsDefaultProgressHandler = true;
161
162
40.6k
    GetImporterInstanceList(pimpl->mImporter);
163
40.6k
    GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps);
164
165
    // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list.
166
40.6k
    pimpl->mPPShared = new SharedPostProcessInfo();
167
40.6k
    for (std::vector<BaseProcess*>::iterator it =  pimpl->mPostProcessingSteps.begin();
168
1.38M
        it != pimpl->mPostProcessingSteps.end();
169
1.34M
        ++it)   {
170
171
1.34M
        (*it)->SetSharedData(pimpl->mPPShared);
172
1.34M
    }
173
40.6k
}
174
175
// ------------------------------------------------------------------------------------------------
176
// Destructor of Importer
177
40.6k
Importer::~Importer() {
178
    // Delete all import plugins
179
40.6k
  DeleteImporterInstanceList(pimpl->mImporter);
180
181
    // Delete all post-processing plug-ins
182
1.38M
    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
183
1.34M
        delete pimpl->mPostProcessingSteps[a];
184
1.34M
    }
185
186
    // Delete the assigned IO and progress handler
187
40.6k
    delete pimpl->mIOHandler;
188
40.6k
    delete pimpl->mProgressHandler;
189
190
    // Kill imported scene. Destructor's should do that recursively
191
40.6k
    delete pimpl->mScene;
192
193
    // Delete shared post-processing data
194
40.6k
    delete pimpl->mPPShared;
195
196
    // and finally the pimpl itself
197
40.6k
    delete pimpl;
198
40.6k
}
199
200
// ------------------------------------------------------------------------------------------------
201
// Register a custom post-processing step
202
0
aiReturn Importer::RegisterPPStep(BaseProcess* pImp) {
203
0
    ai_assert( nullptr != pImp );
204
205
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
206
207
0
        pimpl->mPostProcessingSteps.push_back(pImp);
208
0
        ASSIMP_LOG_INFO("Registering custom post-processing step");
209
210
0
    ASSIMP_END_EXCEPTION_REGION(aiReturn);
211
0
    return AI_SUCCESS;
212
0
}
213
214
// ------------------------------------------------------------------------------------------------
215
// Register a custom loader plugin
216
0
aiReturn Importer::RegisterLoader(BaseImporter* pImp) {
217
0
    ai_assert(nullptr != pImp);
218
219
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
220
221
    // --------------------------------------------------------------------
222
    // Check whether we would have two loaders for the same file extension
223
    // This is absolutely OK, but we should warn the developer of the new
224
    // loader that his code will probably never be called if the first
225
    // loader is a bit too lazy in his file checking.
226
    // --------------------------------------------------------------------
227
0
    std::set<std::string> st;
228
0
    std::string baked;
229
0
    pImp->GetExtensionList(st);
230
231
0
    for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
232
233
0
#ifdef ASSIMP_BUILD_DEBUG
234
0
        if (IsExtensionSupported(*it)) {
235
0
            ASSIMP_LOG_WARN("The file extension ", *it, " is already in use");
236
0
        }
237
0
#endif
238
0
        baked += *it;
239
0
    }
240
241
    // add the loader
242
0
    pimpl->mImporter.push_back(pImp);
243
0
    ASSIMP_LOG_INFO("Registering custom importer for these file extensions: ", baked);
244
0
    ASSIMP_END_EXCEPTION_REGION(aiReturn);
245
246
0
    return AI_SUCCESS;
247
0
}
248
249
// ------------------------------------------------------------------------------------------------
250
// Unregister a custom loader plugin
251
1.89M
aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
252
1.89M
    if(!pImp) {
253
        // unregistering a nullptr importer is no problem for us ... really!
254
0
        return AI_SUCCESS;
255
0
    }
256
257
1.89M
    ASSIMP_BEGIN_EXCEPTION_REGION();
258
1.89M
    std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),
259
1.89M
        pimpl->mImporter.end(),pImp);
260
261
1.89M
    if (it != pimpl->mImporter.end())   {
262
1.89M
        pimpl->mImporter.erase(it);
263
1.89M
        ASSIMP_LOG_INFO("Unregistering custom importer: ");
264
1.89M
        return AI_SUCCESS;
265
1.89M
    }
266
1.89M
    ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ...");
267
0
    ASSIMP_END_EXCEPTION_REGION(aiReturn);
268
269
0
    return AI_FAILURE;
270
1.89M
}
271
272
// ------------------------------------------------------------------------------------------------
273
// Unregister a custom loader plugin
274
0
aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) {
275
0
    if(!pImp) {
276
        // unregistering a nullptr ppstep is no problem for us ... really!
277
0
        return AI_SUCCESS;
278
0
    }
279
280
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
281
0
    std::vector<BaseProcess*>::iterator it = std::find(pimpl->mPostProcessingSteps.begin(),
282
0
        pimpl->mPostProcessingSteps.end(),pImp);
283
284
0
    if (it != pimpl->mPostProcessingSteps.end())    {
285
0
        pimpl->mPostProcessingSteps.erase(it);
286
0
        ASSIMP_LOG_INFO("Unregistering custom post-processing step");
287
0
        return AI_SUCCESS;
288
0
    }
289
0
    ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you ..");
290
0
    ASSIMP_END_EXCEPTION_REGION(aiReturn);
291
292
0
    return AI_FAILURE;
293
0
}
294
295
// ------------------------------------------------------------------------------------------------
296
// Supplies a custom IO handler to the importer to open and access files.
297
81.2k
void Importer::SetIOHandler( IOSystem* pIOHandler) {
298
81.2k
    ai_assert(nullptr != pimpl);
299
300
81.2k
    ASSIMP_BEGIN_EXCEPTION_REGION();
301
    // If the new handler is zero, allocate a default IO implementation.
302
81.2k
    if (!pIOHandler) {
303
        // Release pointer in the possession of the caller
304
0
        pimpl->mIOHandler = new DefaultIOSystem();
305
0
        pimpl->mIsDefaultHandler = true;
306
81.2k
    } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
307
81.2k
        delete pimpl->mIOHandler;
308
81.2k
        pimpl->mIOHandler = pIOHandler;
309
81.2k
        pimpl->mIsDefaultHandler = false;
310
81.2k
    }
311
81.2k
    ASSIMP_END_EXCEPTION_REGION(void);
312
81.2k
}
313
314
// ------------------------------------------------------------------------------------------------
315
// Get the currently set IO handler
316
0
IOSystem* Importer::GetIOHandler() const {
317
0
    ai_assert(nullptr != pimpl);
318
319
0
    return pimpl->mIOHandler;
320
0
}
321
322
// ------------------------------------------------------------------------------------------------
323
// Check whether a custom IO handler is currently set
324
0
bool Importer::IsDefaultIOHandler() const {
325
0
    ai_assert(nullptr != pimpl);
326
327
0
    return pimpl->mIsDefaultHandler;
328
0
}
329
330
// ------------------------------------------------------------------------------------------------
331
// Supplies a custom progress handler to get regular callbacks during importing
332
0
void Importer::SetProgressHandler(ProgressHandler* pHandler) {
333
0
    ai_assert(nullptr != pimpl);
334
335
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
336
337
    // If the new handler is zero, allocate a default implementation.
338
0
    if (!pHandler) {
339
        // Release pointer in the possession of the caller
340
0
        pimpl->mProgressHandler = new DefaultProgressHandler();
341
0
        pimpl->mIsDefaultProgressHandler = true;
342
0
    } else if (pimpl->mProgressHandler != pHandler) { // Otherwise register the custom handler
343
0
        delete pimpl->mProgressHandler;
344
0
        pimpl->mProgressHandler = pHandler;
345
0
        pimpl->mIsDefaultProgressHandler = false;
346
0
    }
347
0
    ASSIMP_END_EXCEPTION_REGION(void);
348
0
}
349
350
// ------------------------------------------------------------------------------------------------
351
// Get the currently set progress handler
352
219k
ProgressHandler* Importer::GetProgressHandler() const {
353
219k
    ai_assert(nullptr != pimpl);
354
355
219k
    return pimpl->mProgressHandler;
356
219k
}
357
358
// ------------------------------------------------------------------------------------------------
359
// Check whether a custom progress handler is currently set
360
0
bool Importer::IsDefaultProgressHandler() const {
361
0
    ai_assert(nullptr != pimpl);
362
363
0
    return pimpl->mIsDefaultProgressHandler;
364
0
}
365
366
// ------------------------------------------------------------------------------------------------
367
// Validate post process step flags
368
11.5k
bool _ValidateFlags(unsigned int pFlags) {
369
11.5k
    if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals)   {
370
0
        ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
371
0
        return false;
372
0
    }
373
11.5k
    if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices)    {
374
0
        ASSIMP_LOG_ERROR("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible");
375
0
        return false;
376
0
    }
377
11.5k
    return true;
378
11.5k
}
379
380
// ------------------------------------------------------------------------------------------------
381
// Free the current scene
382
0
void Importer::FreeScene( ) {
383
0
    ai_assert(nullptr != pimpl);
384
385
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
386
387
0
    delete pimpl->mScene;
388
0
    pimpl->mScene = nullptr;
389
390
0
    pimpl->mErrorString = std::string();
391
0
    pimpl->mException = std::exception_ptr();
392
0
    ASSIMP_END_EXCEPTION_REGION(void);
393
0
}
394
395
// ------------------------------------------------------------------------------------------------
396
// Get the current error string, if any
397
0
const char* Importer::GetErrorString() const {
398
0
    ai_assert(nullptr != pimpl);
399
400
    // Must remain valid as long as ReadFile() or FreeFile() are not called
401
0
    return pimpl->mErrorString.c_str();
402
0
}
403
404
0
const std::exception_ptr& Importer::GetException() const {
405
0
    ai_assert(nullptr != pimpl);
406
407
    // Must remain valid as long as ReadFile() or FreeFile() are not called
408
0
    return pimpl->mException;
409
0
}
410
411
// ------------------------------------------------------------------------------------------------
412
// Enable extra-verbose mode
413
0
void Importer::SetExtraVerbose(bool bDo) {
414
0
    ai_assert(nullptr != pimpl);
415
416
0
    pimpl->bExtraVerbose = bDo;
417
0
}
418
419
// ------------------------------------------------------------------------------------------------
420
// Get the current scene
421
0
const aiScene* Importer::GetScene() const {
422
0
    ai_assert(nullptr != pimpl);
423
424
0
    return pimpl->mScene;
425
0
}
426
427
// ------------------------------------------------------------------------------------------------
428
// Orphan the current scene and return it.
429
0
aiScene* Importer::GetOrphanedScene() {
430
0
    ai_assert(nullptr != pimpl);
431
432
0
    aiScene* s = pimpl->mScene;
433
434
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
435
0
    pimpl->mScene = nullptr;
436
437
0
    pimpl->mErrorString = std::string();
438
0
    pimpl->mException = std::exception_ptr();
439
0
    ASSIMP_END_EXCEPTION_REGION(aiScene*);
440
441
0
    return s;
442
0
}
443
444
// ------------------------------------------------------------------------------------------------
445
// Validate post-processing flags
446
0
bool Importer::ValidateFlags(unsigned int pFlags) const {
447
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
448
    // run basic checks for mutually exclusive flags
449
0
    if(!_ValidateFlags(pFlags)) {
450
0
        return false;
451
0
    }
452
453
    // ValidateDS does not anymore occur in the pp list, it plays an awesome extra role ...
454
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
455
    if (pFlags & aiProcess_ValidateDataStructure) {
456
        return false;
457
    }
458
#endif
459
0
    pFlags &= ~aiProcess_ValidateDataStructure;
460
461
    // Now iterate through all bits which are set in the flags and check whether we find at least
462
    // one pp plugin which handles it.
463
0
    for (unsigned int mask = 1; mask < (1u << (sizeof(unsigned int)*8-1));mask <<= 1) {
464
465
0
        if (pFlags & mask) {
466
467
0
            bool have = false;
468
0
            for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)   {
469
0
                if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) {
470
471
0
                    have = true;
472
0
                    break;
473
0
                }
474
0
            }
475
0
            if (!have) {
476
0
                return false;
477
0
            }
478
0
        }
479
0
    }
480
0
    ASSIMP_END_EXCEPTION_REGION(bool);
481
0
    return true;
482
0
}
483
484
// ------------------------------------------------------------------------------------------------
485
40.6k
const aiScene* Importer::ReadFileFromMemory(const void* pBuffer, size_t pLength, unsigned int pFlags, const char* pHint ) {
486
40.6k
    ai_assert(nullptr != pimpl);
487
488
40.6k
    IOSystem* io = pimpl->mIOHandler;
489
40.6k
    try {
490
40.6k
        if (pHint == nullptr) {
491
0
            pHint = "";
492
0
        }
493
40.6k
        if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
494
0
            pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
495
0
            return nullptr;
496
0
        }
497
        // prevent deletion of the previous IOHandler
498
40.6k
        pimpl->mIOHandler = nullptr;
499
500
40.6k
        SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
501
502
        // read the file and recover the previous IOSystem
503
40.6k
        static const size_t BufSize(Importer::MaxLenHint + 28);
504
40.6k
        char fbuff[BufSize];
505
40.6k
        ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
506
507
40.6k
        ReadFile(fbuff,pFlags);
508
40.6k
        SetIOHandler(io);
509
40.6k
    } catch(const DeadlyImportError &e) {
510
0
        pimpl->mErrorString = e.what();
511
0
        pimpl->mException = std::current_exception();
512
0
        SetIOHandler(io);
513
0
        return ExceptionSwallower<const aiScene*>()();                                                                                                    \
514
0
    } catch(...) {
515
0
        pimpl->mErrorString = "Unknown exception";
516
0
        pimpl->mException = std::current_exception();
517
0
        SetIOHandler(io);
518
0
        return ExceptionSwallower<const aiScene*>()();                                                                                                    \
519
0
520
0
    }
521
522
40.6k
    return pimpl->mScene;
523
40.6k
}
524
525
// ------------------------------------------------------------------------------------------------
526
40.6k
void WriteLogOpening(const std::string& file) {
527
528
40.6k
    ASSIMP_LOG_INFO("Load ", file);
529
530
    // print a full version dump. This is nice because we don't
531
    // need to ask the authors of incoming bug reports for
532
    // the library version they're using - a log dump is
533
    // sufficient.
534
40.6k
    const unsigned int flags = aiGetCompileFlags();
535
40.6k
    std::stringstream stream;
536
40.6k
    stream << "Assimp " << aiGetVersionMajor() << "." << aiGetVersionMinor() << "." << aiGetVersionRevision() << " "
537
#if defined(ASSIMP_BUILD_ARCHITECTURE)
538
           << ASSIMP_BUILD_ARCHITECTURE
539
#elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__)
540
           << "x86"
541
#elif defined(_M_X64) || defined(__x86_64__)
542
           << "amd64"
543
#elif defined(_M_IA64) || defined(__ia64__)
544
           << "itanium"
545
#elif defined(__ppc__) || defined(__powerpc__)
546
           << "ppc32"
547
#elif defined(__powerpc64__)
548
           << "ppc64"
549
#elif defined(__arm__)
550
           << "arm"
551
#else
552
           << "<unknown architecture>"
553
#endif
554
40.6k
           << " "
555
#if defined(ASSIMP_BUILD_COMPILER)
556
           << (ASSIMP_BUILD_COMPILER)
557
#elif defined(_MSC_VER)
558
           << "msvc"
559
#elif defined(__GNUC__)
560
           << "gcc"
561
#elif defined(__clang__)
562
           << "clang"
563
#elif defined(__EMSCRIPTEN__)
564
           << "emscripten"
565
#elif defined(__MINGW32__)
566
           << "MinGW-w64 32bit"
567
#elif defined(__MINGW64__)
568
           << "MinGW-w64 64bit"
569
#else
570
           << "<unknown compiler>"
571
#endif
572
573
40.6k
#ifdef ASSIMP_BUILD_DEBUG
574
40.6k
           << " debug"
575
40.6k
#endif
576
577
40.6k
           << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "")
578
40.6k
           << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "")
579
40.6k
           << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "")
580
40.6k
           << (flags & ASSIMP_CFLAGS_DOUBLE_SUPPORT ? " double : " : "single : ");
581
582
40.6k
    ASSIMP_LOG_DEBUG(stream.str());
583
40.6k
}
584
585
// ------------------------------------------------------------------------------------------------
586
// Reads the given file and returns its contents if successful.
587
40.6k
const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
588
40.6k
    ai_assert(nullptr != pimpl);
589
590
40.6k
    ASSIMP_BEGIN_EXCEPTION_REGION();
591
40.6k
    const std::string pFile(_pFile);
592
593
    // ----------------------------------------------------------------------
594
    // Put a large try block around everything to catch all std::exception's
595
    // that might be thrown by STL containers or by new().
596
    // ImportErrorException's are throw by ourselves and caught elsewhere.
597
    //-----------------------------------------------------------------------
598
599
40.6k
    WriteLogOpening(pFile);
600
601
#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
602
    try
603
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
604
40.6k
    {
605
        // Check whether this Importer instance has already loaded
606
        // a scene. In this case we need to delete the old one
607
40.6k
        if (pimpl->mScene)  {
608
609
0
            ASSIMP_LOG_DEBUG("(Deleting previous scene)");
610
0
            FreeScene();
611
0
        }
612
613
        // First check if the file is accessible at all
614
40.6k
        if( !pimpl->mIOHandler->Exists( pFile)) {
615
616
0
            pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
617
0
            ASSIMP_LOG_ERROR(pimpl->mErrorString);
618
0
            return nullptr;
619
0
        }
620
621
40.6k
        std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
622
40.6k
        if (profiler) {
623
0
            profiler->BeginRegion("total");
624
0
        }
625
626
        // Find an worker class which can handle the file extension.
627
        // Multiple importers may be able to handle the same extension (.xml!); gather them all.
628
40.6k
        SetPropertyInteger("importerIndex", -1);
629
40.6k
        struct ImporterAndIndex {
630
40.6k
            BaseImporter * importer;
631
40.6k
            unsigned int   index;
632
40.6k
        };
633
40.6k
        std::vector<ImporterAndIndex> possibleImporters;
634
91.9k
        for (unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
635
636
            // Every importer has a list of supported extensions.
637
51.2k
            std::set<std::string> extensions;
638
51.2k
            pimpl->mImporter[a]->GetExtensionList(extensions);
639
640
51.2k
            if (BaseImporter::HasExtension(pFile, extensions)) {
641
51.2k
                ImporterAndIndex candidate = { pimpl->mImporter[a], a };
642
51.2k
                possibleImporters.push_back(candidate);
643
51.2k
            }
644
51.2k
        }
645
646
        // If just one importer supports this extension, pick it and close the case.
647
40.6k
        BaseImporter* imp = nullptr;
648
40.6k
        if (1 == possibleImporters.size()) {
649
29.9k
            imp = possibleImporters[0].importer;
650
29.9k
            SetPropertyInteger("importerIndex", possibleImporters[0].index);
651
29.9k
        }
652
        // If multiple importers claim this file extension, ask them to look at the actual file data to decide.
653
        // This can happen e.g. with XML (COLLADA vs. Irrlicht).
654
10.6k
        else {
655
24.8k
            for (std::vector<ImporterAndIndex>::const_iterator it = possibleImporters.begin(); it < possibleImporters.end(); ++it) {
656
20.8k
                BaseImporter & importer = *it->importer;
657
658
20.8k
                ASSIMP_LOG_INFO("Found a possible importer: " + std::string(importer.GetInfo()->mName) + "; trying signature-based detection");
659
20.8k
                if (importer.CanRead( pFile, pimpl->mIOHandler, true)) {
660
6.68k
                    imp = &importer;
661
6.68k
                    SetPropertyInteger("importerIndex", it->index);
662
6.68k
                    break;
663
6.68k
                }
664
665
20.8k
            }
666
667
10.6k
        }
668
669
40.6k
        if (!imp)   {
670
            // not so bad yet ... try format auto detection.
671
3.99k
            ASSIMP_LOG_INFO("File extension not known, trying signature-based detection");
672
11.9k
            for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
673
7.99k
                if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
674
0
                    imp = pimpl->mImporter[a];
675
0
                    SetPropertyInteger("importerIndex", a);
676
0
                    break;
677
0
                }
678
7.99k
            }
679
            // Put a proper error message if no suitable importer was found
680
3.99k
            if( !imp)   {
681
3.99k
                pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
682
3.99k
                ASSIMP_LOG_ERROR(pimpl->mErrorString);
683
3.99k
                return nullptr;
684
3.99k
            }
685
3.99k
        }
686
687
        // Get file size for progress handler
688
36.6k
        IOStream * fileIO = pimpl->mIOHandler->Open( pFile );
689
36.6k
        uint32_t fileSize = 0;
690
36.6k
        if (fileIO)
691
36.6k
        {
692
36.6k
            fileSize = static_cast<uint32_t>(fileIO->FileSize());
693
36.6k
            pimpl->mIOHandler->Close( fileIO );
694
36.6k
        }
695
696
        // Dispatch the reading to the worker class for this format
697
36.6k
        const aiImporterDesc *desc( imp->GetInfo() );
698
36.6k
        std::string ext( "unknown" );
699
36.6k
        if ( nullptr != desc ) {
700
36.6k
            ext = desc->mName;
701
36.6k
        }
702
36.6k
        ASSIMP_LOG_INFO("Found a matching importer for this file format: ", ext, "." );
703
36.6k
        pimpl->mProgressHandler->UpdateFileRead( 0, fileSize );
704
705
36.6k
        if (profiler) {
706
0
            profiler->BeginRegion("import");
707
0
        }
708
709
36.6k
        pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
710
36.6k
        pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize );
711
712
36.6k
        if (profiler) {
713
0
            profiler->EndRegion("import");
714
0
        }
715
716
36.6k
        SetPropertyString("sourceFilePath", pFile);
717
718
        // If successful, apply all active post processing steps to the imported data
719
36.6k
        if( pimpl->mScene)  {
720
20.6k
            if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
721
20.6k
                if (!pimpl->mScene->mMetaData) {
722
15.0k
                    pimpl->mScene->mMetaData = new aiMetadata;
723
15.0k
                }
724
20.6k
                pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext));
725
20.6k
            }
726
727
20.6k
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
728
            // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
729
20.6k
            if (pFlags & aiProcess_ValidateDataStructure) {
730
20.6k
                ValidateDSProcess ds;
731
20.6k
                ds.ExecuteOnScene (this);
732
20.6k
                if (!pimpl->mScene) {
733
9.04k
                    return nullptr;
734
9.04k
                }
735
20.6k
            }
736
11.5k
#endif // ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
737
738
            // Preprocess the scene and prepare it for post-processing
739
11.5k
            if (profiler) {
740
0
                profiler->BeginRegion("preprocess");
741
0
            }
742
743
11.5k
            ScenePreprocessor pre(pimpl->mScene);
744
11.5k
            pre.ProcessScene();
745
746
11.5k
            if (profiler) {
747
0
                profiler->EndRegion("preprocess");
748
0
            }
749
750
            // Ensure that the validation process won't be called twice
751
11.5k
            ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
752
11.5k
        }
753
        // if failed, extract the error string
754
15.9k
        else if( !pimpl->mScene) {
755
15.9k
            pimpl->mErrorString = imp->GetErrorText();
756
15.9k
            pimpl->mException = imp->GetException();
757
15.9k
        }
758
759
        // clear any data allocated by post-process steps
760
27.5k
        pimpl->mPPShared->Clean();
761
762
27.5k
        if (profiler) {
763
0
            profiler->EndRegion("total");
764
0
        }
765
27.5k
    }
766
#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
767
    catch (std::exception &e) {
768
#if (defined _MSC_VER) &&   (defined _CPPRTTI)
769
        // if we have RTTI get the full name of the exception that occurred
770
        pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
771
#else
772
        pimpl->mErrorString = std::string("std::exception: ") + e.what();
773
#endif
774
        pimpl->mException = std::current_exception();
775
776
        ASSIMP_LOG_ERROR(pimpl->mErrorString);
777
        delete pimpl->mScene; pimpl->mScene = nullptr;
778
    }
779
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
780
781
    // either successful or failure - the pointer expresses it anyways
782
27.5k
    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
783
784
27.5k
    return pimpl->mScene;
785
40.6k
}
786
787
788
// ------------------------------------------------------------------------------------------------
789
// Apply post-processing to the currently bound scene
790
11.5k
const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
791
11.5k
    ai_assert(nullptr != pimpl);
792
793
11.5k
    ASSIMP_BEGIN_EXCEPTION_REGION();
794
    // Return immediately if no scene is active
795
11.5k
    if (!pimpl->mScene) {
796
0
        return nullptr;
797
0
    }
798
799
    // If no flags are given, return the current scene with no further action
800
11.5k
    if (!pFlags) {
801
0
        return pimpl->mScene;
802
0
    }
803
804
    // In debug builds: run basic flag validation
805
11.5k
    ai_assert(_ValidateFlags(pFlags));
806
11.5k
    ASSIMP_LOG_INFO("Entering post processing pipeline");
807
808
11.5k
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
809
    // The ValidateDS process plays an exceptional role. It isn't contained in the global
810
    // list of post-processing steps, so we need to call it manually.
811
11.5k
    if (pFlags & aiProcess_ValidateDataStructure) {
812
0
        ValidateDSProcess ds;
813
0
        ds.ExecuteOnScene (this);
814
0
        if (!pimpl->mScene) {
815
0
            return nullptr;
816
0
        }
817
0
    }
818
11.5k
#endif // no validation
819
11.5k
#ifdef ASSIMP_BUILD_DEBUG
820
11.5k
    if (pimpl->bExtraVerbose)
821
0
    {
822
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
823
        ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
824
#endif  // no validation
825
0
        pFlags |= aiProcess_ValidateDataStructure;
826
0
    }
827
#else
828
    if (pimpl->bExtraVerbose) {
829
        ASSIMP_LOG_WARN("Not a debug build, ignoring extra verbose setting");
830
    }
831
#endif // ! DEBUG
832
833
11.5k
    std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
834
371k
    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)   {
835
361k
        BaseProcess* process = pimpl->mPostProcessingSteps[a];
836
361k
        pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
837
361k
        if( process->IsActive( pFlags)) {
838
162k
            if (profiler) {
839
0
                profiler->BeginRegion("postprocess");
840
0
            }
841
842
162k
            process->ExecuteOnScene ( this );
843
844
162k
            if (profiler) {
845
0
                profiler->EndRegion("postprocess");
846
0
            }
847
162k
        }
848
361k
        if( !pimpl->mScene) {
849
1.30k
            break;
850
1.30k
        }
851
360k
#ifdef ASSIMP_BUILD_DEBUG
852
360k
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
853
        // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
854
360k
        if (pimpl->bExtraVerbose)   {
855
0
            ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures");
856
857
0
            ValidateDSProcess ds;
858
0
            ds.ExecuteOnScene (this);
859
0
            if( !pimpl->mScene) {
860
0
                ASSIMP_LOG_ERROR("Verbose Import: failed to re-validate data structures");
861
0
                break;
862
0
            }
863
0
        }
864
360k
#endif  // no validation
865
360k
#endif // ! DEBUG
866
360k
    }
867
11.5k
    pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()),
868
11.5k
        static_cast<int>(pimpl->mPostProcessingSteps.size()) );
869
870
    // update private scene flags
871
11.5k
    if( pimpl->mScene ) {
872
10.2k
      ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
873
10.2k
    }
874
875
    // clear any data allocated by post-process steps
876
11.5k
    pimpl->mPPShared->Clean();
877
11.5k
    ASSIMP_LOG_INFO("Leaving post processing pipeline");
878
879
11.5k
    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
880
881
11.5k
    return pimpl->mScene;
882
11.5k
}
883
884
// ------------------------------------------------------------------------------------------------
885
0
const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) {
886
0
    ai_assert(nullptr != pimpl);
887
888
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
889
890
    // Return immediately if no scene is active
891
0
    if ( nullptr == pimpl->mScene ) {
892
0
        return nullptr;
893
0
    }
894
895
    // If no flags are given, return the current scene with no further action
896
0
    if (nullptr == rootProcess) {
897
0
        return pimpl->mScene;
898
0
    }
899
900
    // In debug builds: run basic flag validation
901
0
    ASSIMP_LOG_INFO( "Entering customized post processing pipeline" );
902
903
0
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
904
    // The ValidateDS process plays an exceptional role. It isn't contained in the global
905
    // list of post-processing steps, so we need to call it manually.
906
0
    if ( requestValidation )
907
0
    {
908
0
        ValidateDSProcess ds;
909
0
        ds.ExecuteOnScene( this );
910
0
        if ( !pimpl->mScene ) {
911
0
            return nullptr;
912
0
        }
913
0
    }
914
0
#endif // no validation
915
0
#ifdef ASSIMP_BUILD_DEBUG
916
0
    if ( pimpl->bExtraVerbose )
917
0
    {
918
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
919
        ASSIMP_LOG_ERROR( "Verbose Import is not available due to build settings" );
920
#endif  // no validation
921
0
    }
922
#else
923
    if ( pimpl->bExtraVerbose ) {
924
        ASSIMP_LOG_WARN( "Not a debug build, ignoring extra verbose setting" );
925
    }
926
#endif // ! DEBUG
927
928
0
    std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
929
930
0
    if ( profiler ) {
931
0
        profiler->BeginRegion( "postprocess" );
932
0
    }
933
934
0
    rootProcess->ExecuteOnScene( this );
935
936
0
    if ( profiler ) {
937
0
        profiler->EndRegion( "postprocess" );
938
0
    }
939
940
0
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
941
    // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
942
0
    if ( pimpl->bExtraVerbose || requestValidation  ) {
943
0
        ASSIMP_LOG_DEBUG( "Verbose Import: revalidating data structures" );
944
945
0
        ValidateDSProcess ds;
946
0
        ds.ExecuteOnScene( this );
947
0
        if ( !pimpl->mScene ) {
948
0
            ASSIMP_LOG_ERROR( "Verbose Import: failed to revalidate data structures" );
949
0
        }
950
0
    }
951
0
#endif // no validation
952
953
    // clear any data allocated by post-process steps
954
0
    pimpl->mPPShared->Clean();
955
0
    ASSIMP_LOG_INFO( "Leaving customized post processing pipeline" );
956
957
0
    ASSIMP_END_EXCEPTION_REGION( const aiScene* );
958
959
0
    return pimpl->mScene;
960
0
}
961
962
// ------------------------------------------------------------------------------------------------
963
// Helper function to check whether an extension is supported by ASSIMP
964
0
bool Importer::IsExtensionSupported(const char* szExtension) const {
965
0
    return nullptr != GetImporter(szExtension);
966
0
}
967
968
// ------------------------------------------------------------------------------------------------
969
40.6k
size_t Importer::GetImporterCount() const {
970
40.6k
    ai_assert(nullptr != pimpl);
971
972
40.6k
    return pimpl->mImporter.size();
973
40.6k
}
974
975
// ------------------------------------------------------------------------------------------------
976
1.94M
const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
977
1.94M
    ai_assert(nullptr != pimpl);
978
979
1.94M
    if (index >= pimpl->mImporter.size()) {
980
0
        return nullptr;
981
0
    }
982
1.94M
    return pimpl->mImporter[index]->GetInfo();
983
1.94M
}
984
985
986
// ------------------------------------------------------------------------------------------------
987
1.94M
BaseImporter* Importer::GetImporter (size_t index) const {
988
1.94M
    ai_assert(nullptr != pimpl);
989
990
1.94M
    if (index >= pimpl->mImporter.size()) {
991
0
        return nullptr;
992
0
    }
993
1.94M
    return pimpl->mImporter[index];
994
1.94M
}
995
996
// ------------------------------------------------------------------------------------------------
997
// Find a loader plugin for a given file extension
998
0
BaseImporter* Importer::GetImporter (const char* szExtension) const {
999
0
    ai_assert(nullptr != pimpl);
1000
1001
0
    return GetImporter(GetImporterIndex(szExtension));
1002
0
}
1003
1004
// ------------------------------------------------------------------------------------------------
1005
// Find a loader plugin for a given file extension
1006
0
size_t Importer::GetImporterIndex (const char* szExtension) const {
1007
0
    ai_assert(nullptr != pimpl);
1008
0
    ai_assert(nullptr != szExtension);
1009
1010
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
1011
1012
    // skip over wild-card and dot characters at string head --
1013
0
    for ( ; *szExtension == '*' || *szExtension == '.'; ++szExtension );
1014
1015
0
    std::string ext(szExtension);
1016
0
    if (ext.empty()) {
1017
0
        return static_cast<size_t>(-1);
1018
0
    }
1019
0
    ext = ai_tolower(ext);
1020
0
    std::set<std::string> str;
1021
0
    for (std::vector<BaseImporter*>::const_iterator i =  pimpl->mImporter.begin();i != pimpl->mImporter.end();++i)  {
1022
0
        str.clear();
1023
1024
0
        (*i)->GetExtensionList(str);
1025
0
        for (std::set<std::string>::const_iterator it = str.begin(); it != str.end(); ++it) {
1026
0
            if (ext == *it) {
1027
0
                return std::distance(static_cast< std::vector<BaseImporter*>::const_iterator >(pimpl->mImporter.begin()), i);
1028
0
            }
1029
0
        }
1030
0
    }
1031
0
    ASSIMP_END_EXCEPTION_REGION(size_t);
1032
0
    return static_cast<size_t>(-1);
1033
0
}
1034
1035
// ------------------------------------------------------------------------------------------------
1036
// Helper function to build a list of all file extensions supported by ASSIMP
1037
0
void Importer::GetExtensionList(aiString& szOut) const {
1038
0
    ai_assert(nullptr != pimpl);
1039
1040
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
1041
0
    std::set<std::string> str;
1042
0
    for (std::vector<BaseImporter*>::const_iterator i =  pimpl->mImporter.begin();i != pimpl->mImporter.end();++i)  {
1043
0
        (*i)->GetExtensionList(str);
1044
0
    }
1045
1046
  // List can be empty
1047
0
  if( !str.empty() ) {
1048
0
    for (std::set<std::string>::const_iterator it = str.begin();; ) {
1049
0
      szOut.Append("*.");
1050
0
      szOut.Append((*it).c_str());
1051
1052
0
      if (++it == str.end()) {
1053
0
        break;
1054
0
      }
1055
0
      szOut.Append(";");
1056
0
    }
1057
0
  }
1058
0
    ASSIMP_END_EXCEPTION_REGION(void);
1059
0
}
1060
1061
// ------------------------------------------------------------------------------------------------
1062
// Set a configuration property
1063
77.2k
bool Importer::SetPropertyInteger(const char* szName, int iValue) {
1064
77.2k
    ai_assert(nullptr != pimpl);
1065
1066
77.2k
    bool existing;
1067
77.2k
    ASSIMP_BEGIN_EXCEPTION_REGION();
1068
77.2k
        existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
1069
77.2k
    ASSIMP_END_EXCEPTION_REGION(bool);
1070
77.2k
    return existing;
1071
77.2k
}
1072
1073
// ------------------------------------------------------------------------------------------------
1074
// Set a configuration property
1075
20.6k
bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
1076
20.6k
    ai_assert(nullptr != pimpl);
1077
1078
20.6k
    bool existing;
1079
20.6k
    ASSIMP_BEGIN_EXCEPTION_REGION();
1080
20.6k
        existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
1081
20.6k
    ASSIMP_END_EXCEPTION_REGION(bool);
1082
20.6k
    return existing;
1083
20.6k
}
1084
1085
// ------------------------------------------------------------------------------------------------
1086
// Set a configuration property
1087
36.6k
bool Importer::SetPropertyString(const char* szName, const std::string& value) {
1088
36.6k
    ai_assert(nullptr != pimpl);
1089
1090
36.6k
    bool existing;
1091
36.6k
    ASSIMP_BEGIN_EXCEPTION_REGION();
1092
36.6k
        existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
1093
36.6k
    ASSIMP_END_EXCEPTION_REGION(bool);
1094
36.6k
    return existing;
1095
36.6k
}
1096
1097
// ------------------------------------------------------------------------------------------------
1098
// Set a configuration property
1099
0
bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
1100
0
    ai_assert(nullptr != pimpl);
1101
1102
0
    bool existing;
1103
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
1104
0
        existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value);
1105
0
    ASSIMP_END_EXCEPTION_REGION(bool);
1106
0
    return existing;
1107
0
}
1108
1109
// ------------------------------------------------------------------------------------------------
1110
// Set a configuration property
1111
0
bool Importer::SetPropertyPointer(const char* szName, void* value) {
1112
0
    ai_assert(nullptr != pimpl);
1113
1114
0
    bool existing;
1115
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
1116
0
        existing = SetGenericProperty<void*>(pimpl->mPointerProperties, szName,value);
1117
0
    ASSIMP_END_EXCEPTION_REGION(bool);
1118
0
    return existing;
1119
0
}
1120
1121
// ------------------------------------------------------------------------------------------------
1122
// Get a configuration property
1123
231k
int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
1124
231k
    ai_assert(nullptr != pimpl);
1125
1126
231k
    return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
1127
231k
}
1128
1129
// ------------------------------------------------------------------------------------------------
1130
// Get a configuration property
1131
32.0k
ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
1132
32.0k
    ai_assert(nullptr != pimpl);
1133
1134
32.0k
    return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
1135
32.0k
}
1136
1137
// ------------------------------------------------------------------------------------------------
1138
// Get a configuration property
1139
11.5k
std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
1140
11.5k
    ai_assert(nullptr != pimpl);
1141
1142
11.5k
    return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
1143
11.5k
}
1144
1145
// ------------------------------------------------------------------------------------------------
1146
// Get a configuration property
1147
0
aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
1148
0
    ai_assert(nullptr != pimpl);
1149
1150
0
    return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
1151
0
}
1152
1153
// ------------------------------------------------------------------------------------------------
1154
// Get a configuration property
1155
6.20k
void* Importer::GetPropertyPointer(const char* szName, void* iErrorReturn /*= nullptr*/) const {
1156
6.20k
    ai_assert(nullptr != pimpl);
1157
1158
6.20k
    return GetGenericProperty<void*>(pimpl->mPointerProperties,szName,iErrorReturn);
1159
6.20k
}
1160
1161
// ------------------------------------------------------------------------------------------------
1162
// Get the memory requirements of a single node
1163
inline
1164
0
void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) {
1165
0
    if ( nullptr == pcNode ) {
1166
0
        return;
1167
0
    }
1168
0
    iScene += sizeof(aiNode);
1169
0
    iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
1170
0
    iScene += sizeof(void*) * pcNode->mNumChildren;
1171
1172
0
    for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
1173
0
        AddNodeWeight(iScene,pcNode->mChildren[i]);
1174
0
    }
1175
0
}
1176
1177
// ------------------------------------------------------------------------------------------------
1178
// Get the memory requirements of the scene
1179
0
void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
1180
0
    ai_assert(nullptr != pimpl);
1181
1182
0
    in = aiMemoryInfo();
1183
0
    aiScene* mScene = pimpl->mScene;
1184
1185
    // return if we have no scene loaded
1186
0
    if (!mScene)
1187
0
        return;
1188
1189
0
    in.total = sizeof(aiScene);
1190
1191
    // add all meshes
1192
0
    for (unsigned int i = 0; i < mScene->mNumMeshes;++i) {
1193
0
        in.meshes += sizeof(aiMesh);
1194
0
        if (mScene->mMeshes[i]->HasPositions()) {
1195
0
            in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
1196
0
        }
1197
1198
0
        if (mScene->mMeshes[i]->HasNormals()) {
1199
0
            in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
1200
0
        }
1201
1202
0
        if (mScene->mMeshes[i]->HasTangentsAndBitangents()) {
1203
0
            in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices * 2;
1204
0
        }
1205
1206
0
        for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) {
1207
0
            if (mScene->mMeshes[i]->HasVertexColors(a)) {
1208
0
                in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
1209
0
            } else {
1210
0
                break;
1211
0
            }
1212
0
        }
1213
0
        for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
1214
0
            if (mScene->mMeshes[i]->HasTextureCoords(a)) {
1215
0
                in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
1216
0
            } else {
1217
0
                break;
1218
0
            }
1219
0
        }
1220
0
        if (mScene->mMeshes[i]->HasBones()) {
1221
0
            in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
1222
0
            for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones;++p) {
1223
0
                in.meshes += sizeof(aiBone);
1224
0
                in.meshes += mScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight);
1225
0
            }
1226
0
        }
1227
0
        in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int))*mScene->mMeshes[i]->mNumFaces;
1228
0
    }
1229
0
    in.total += in.meshes;
1230
1231
    // add all embedded textures
1232
0
    for (unsigned int i = 0; i < mScene->mNumTextures;++i) {
1233
0
        const aiTexture* pc = mScene->mTextures[i];
1234
0
        in.textures += sizeof(aiTexture);
1235
0
        if (pc->mHeight) {
1236
0
            in.textures += 4 * pc->mHeight * pc->mWidth;
1237
0
        } else {
1238
0
            in.textures += pc->mWidth;
1239
0
        }
1240
0
    }
1241
0
    in.total += in.textures;
1242
1243
    // add all animations
1244
0
    for (unsigned int i = 0; i < mScene->mNumAnimations;++i) {
1245
0
        const aiAnimation* pc = mScene->mAnimations[i];
1246
0
        in.animations += sizeof(aiAnimation);
1247
1248
        // add all bone anims
1249
0
        for (unsigned int a = 0; a < pc->mNumChannels; ++a) {
1250
0
            const aiNodeAnim* pc2 = pc->mChannels[a];
1251
0
            in.animations += sizeof(aiNodeAnim);
1252
0
            in.animations += pc2->mNumPositionKeys * sizeof(aiVectorKey);
1253
0
            in.animations += pc2->mNumScalingKeys * sizeof(aiVectorKey);
1254
0
            in.animations += pc2->mNumRotationKeys * sizeof(aiQuatKey);
1255
0
        }
1256
0
    }
1257
0
    in.total += in.animations;
1258
1259
    // add all cameras and all lights
1260
0
    in.total += in.cameras = sizeof(aiCamera) *  mScene->mNumCameras;
1261
0
    in.total += in.lights  = sizeof(aiLight)  *  mScene->mNumLights;
1262
1263
    // add all nodes
1264
0
    AddNodeWeight(in.nodes,mScene->mRootNode);
1265
0
    in.total += in.nodes;
1266
1267
    // add all materials
1268
0
    for (unsigned int i = 0; i < mScene->mNumMaterials;++i) {
1269
0
        const aiMaterial* pc = mScene->mMaterials[i];
1270
0
        in.materials += sizeof(aiMaterial);
1271
0
        in.materials += pc->mNumAllocated * sizeof(void*);
1272
1273
0
        for (unsigned int a = 0; a < pc->mNumProperties;++a) {
1274
0
            in.materials += pc->mProperties[a]->mDataLength;
1275
0
        }
1276
0
    }
1277
1278
0
    in.total += in.materials;
1279
0
}