Coverage Report

Created: 2025-11-11 06:59

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-2025, 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
28.3k
void* AllocateFromAssimpHeap::operator new ( size_t num_bytes)  {
115
28.3k
    return ::operator new(num_bytes);
116
28.3k
}
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
28.3k
void AllocateFromAssimpHeap::operator delete ( void* data)  {
128
28.3k
    return ::operator delete(data);
129
28.3k
}
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
891
 : pimpl( new ImporterPimpl ) {
151
891
    pimpl->mScene = nullptr;
152
891
    pimpl->mErrorString = std::string();
153
154
    // Allocate a default IO handler
155
891
    pimpl->mIOHandler = new DefaultIOSystem;
156
891
    pimpl->mIsDefaultHandler = true;
157
891
    pimpl->bExtraVerbose     = false; // disable extra verbose mode by default
158
159
891
    pimpl->mProgressHandler = new DefaultProgressHandler();
160
891
    pimpl->mIsDefaultProgressHandler = true;
161
162
891
    GetImporterInstanceList(pimpl->mImporter);
163
891
    GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps);
164
165
    // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list.
166
891
    pimpl->mPPShared = new SharedPostProcessInfo();
167
891
    for (std::vector<BaseProcess*>::iterator it =  pimpl->mPostProcessingSteps.begin();
168
30.2k
        it != pimpl->mPostProcessingSteps.end();
169
29.4k
        ++it)   {
170
171
29.4k
        (*it)->SetSharedData(pimpl->mPPShared);
172
29.4k
    }
173
891
}
174
175
// ------------------------------------------------------------------------------------------------
176
// Destructor of Importer
177
891
Importer::~Importer() {
178
    // Delete all import plugins
179
891
  DeleteImporterInstanceList(pimpl->mImporter);
180
181
    // Delete all post-processing plug-ins
182
30.2k
    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
183
29.4k
        delete pimpl->mPostProcessingSteps[a];
184
29.4k
    }
185
186
    // Delete the assigned IO and progress handler
187
891
    delete pimpl->mIOHandler;
188
891
    delete pimpl->mProgressHandler;
189
190
    // Kill imported scene. Destructor's should do that recursively
191
891
    delete pimpl->mScene;
192
193
    // Delete shared post-processing data
194
891
    delete pimpl->mPPShared;
195
196
    // and finally the pimpl itself
197
891
    delete pimpl;
198
891
}
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
0
aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
252
0
    if(!pImp) {
253
        // unregistering a nullptr importer is no problem for us ... really!
254
0
        return AI_SUCCESS;
255
0
    }
256
257
0
    ASSIMP_BEGIN_EXCEPTION_REGION();
258
0
    std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),
259
0
        pimpl->mImporter.end(),pImp);
260
261
0
    if (it != pimpl->mImporter.end())   {
262
0
        pimpl->mImporter.erase(it);
263
0
        ASSIMP_LOG_INFO("Unregistering custom importer: ");
264
0
        return AI_SUCCESS;
265
0
    }
266
0
    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
0
}
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
1.78k
void Importer::SetIOHandler( IOSystem* pIOHandler) {
298
1.78k
    ai_assert(nullptr != pimpl);
299
300
1.78k
    ASSIMP_BEGIN_EXCEPTION_REGION();
301
    // If the new handler is zero, allocate a default IO implementation.
302
1.78k
    if (!pIOHandler) {
303
        // Release pointer in the possession of the caller
304
162
        pimpl->mIOHandler = new DefaultIOSystem();
305
162
        pimpl->mIsDefaultHandler = true;
306
1.62k
    } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
307
1.62k
        delete pimpl->mIOHandler;
308
1.62k
        pimpl->mIOHandler = pIOHandler;
309
1.62k
        pimpl->mIsDefaultHandler = false;
310
1.62k
    }
311
1.78k
    ASSIMP_END_EXCEPTION_REGION(void);
312
1.78k
}
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
4.89k
ProgressHandler* Importer::GetProgressHandler() const {
353
4.89k
    ai_assert(nullptr != pimpl);
354
355
4.89k
    return pimpl->mProgressHandler;
356
4.89k
}
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
267
bool _ValidateFlags(unsigned int pFlags) {
369
267
    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
267
    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
267
    return true;
378
267
}
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
428
aiScene* Importer::GetOrphanedScene() {
430
428
    ai_assert(nullptr != pimpl);
431
432
428
    aiScene* s = pimpl->mScene;
433
434
428
    ASSIMP_BEGIN_EXCEPTION_REGION();
435
428
    pimpl->mScene = nullptr;
436
437
428
    pimpl->mErrorString = std::string();
438
428
    pimpl->mException = std::exception_ptr();
439
428
    ASSIMP_END_EXCEPTION_REGION(aiScene*);
440
441
0
    return s;
442
428
}
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
729
const aiScene* Importer::ReadFileFromMemory(const void* pBuffer, size_t pLength, unsigned int pFlags, const char* pHint ) {
486
729
    ai_assert(nullptr != pimpl);
487
488
729
    IOSystem* io = pimpl->mIOHandler;
489
729
    try {
490
729
        if (pHint == nullptr) {
491
729
            pHint = "";
492
729
        }
493
729
        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
729
        pimpl->mIOHandler = nullptr;
499
500
729
        SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
501
502
        // read the file and recover the previous IOSystem
503
729
        static const size_t BufSize(Importer::MaxLenHint + 28);
504
729
        char fbuff[BufSize];
505
729
        ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
506
507
729
        ReadFile(fbuff,pFlags);
508
729
        SetIOHandler(io);
509
729
    } 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
729
    return pimpl->mScene;
523
729
}
524
525
// ------------------------------------------------------------------------------------------------
526
1.15k
void WriteLogOpening(const std::string& file) {
527
528
1.15k
    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
1.15k
    const unsigned int flags = aiGetCompileFlags();
535
1.15k
    std::stringstream stream;
536
1.15k
    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
1.15k
           << " "
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
1.15k
#ifdef ASSIMP_BUILD_DEBUG
574
1.15k
           << " debug"
575
1.15k
#endif
576
577
1.15k
           << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "")
578
1.15k
           << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "")
579
1.15k
           << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "")
580
1.15k
           << (flags & ASSIMP_CFLAGS_DOUBLE_SUPPORT ? " double : " : "single : ");
581
582
1.15k
    ASSIMP_LOG_DEBUG(stream.str());
583
1.15k
}
584
585
// ------------------------------------------------------------------------------------------------
586
// Reads the given file and returns its contents if successful.
587
1.15k
const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
588
1.15k
    ai_assert(nullptr != pimpl);
589
590
1.15k
    ASSIMP_BEGIN_EXCEPTION_REGION();
591
1.15k
    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
1.15k
    WriteLogOpening(pFile);
600
601
#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
602
    try
603
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
604
1.15k
    {
605
        // Check whether this Importer instance has already loaded
606
        // a scene. In this case we need to delete the old one
607
1.15k
        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
1.15k
        if( !pimpl->mIOHandler->Exists( pFile)) {
615
616
280
            pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
617
280
            ASSIMP_LOG_ERROR(pimpl->mErrorString);
618
280
            return nullptr;
619
280
        }
620
621
877
        std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
622
877
        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
877
        SetPropertyInteger("importerIndex", -1);
629
877
        struct ImporterAndIndex {
630
877
            BaseImporter * importer;
631
877
            unsigned int   index;
632
877
        };
633
877
        std::vector<ImporterAndIndex> possibleImporters;
634
42.9k
        for (unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
635
636
            // Every importer has a list of supported extensions.
637
42.0k
            std::set<std::string> extensions;
638
42.0k
            pimpl->mImporter[a]->GetExtensionList(extensions);
639
640
42.0k
            if (BaseImporter::HasExtension(pFile, extensions)) {
641
47
                ImporterAndIndex candidate = { pimpl->mImporter[a], a };
642
47
                possibleImporters.push_back(candidate);
643
47
            }
644
42.0k
        }
645
646
        // If just one importer supports this extension, pick it and close the case.
647
877
        BaseImporter* imp = nullptr;
648
877
        if (1 == possibleImporters.size()) {
649
47
            imp = possibleImporters[0].importer;
650
47
            SetPropertyInteger("importerIndex", possibleImporters[0].index);
651
47
        }
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
830
        else {
655
830
            for (std::vector<ImporterAndIndex>::const_iterator it = possibleImporters.begin(); it < possibleImporters.end(); ++it) {
656
0
                BaseImporter & importer = *it->importer;
657
658
0
                ASSIMP_LOG_INFO("Found a possible importer: " + std::string(importer.GetInfo()->mName) + "; trying signature-based detection");
659
0
                if (importer.CanRead( pFile, pimpl->mIOHandler, true)) {
660
0
                    imp = &importer;
661
0
                    SetPropertyInteger("importerIndex", it->index);
662
0
                    break;
663
0
                }
664
665
0
            }
666
667
830
        }
668
669
877
        if (!imp)   {
670
            // not so bad yet ... try format auto detection.
671
830
            ASSIMP_LOG_INFO("File extension not known, trying signature-based detection");
672
17.4k
            for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
673
17.3k
                if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
674
718
                    imp = pimpl->mImporter[a];
675
718
                    SetPropertyInteger("importerIndex", a);
676
718
                    break;
677
718
                }
678
17.3k
            }
679
            // Put a proper error message if no suitable importer was found
680
830
            if( !imp)   {
681
79
                pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
682
79
                ASSIMP_LOG_ERROR(pimpl->mErrorString);
683
79
                return nullptr;
684
79
            }
685
830
        }
686
687
        // Get file size for progress handler
688
798
        IOStream * fileIO = pimpl->mIOHandler->Open( pFile );
689
798
        uint32_t fileSize = 0;
690
798
        if (fileIO)
691
765
        {
692
765
            fileSize = static_cast<uint32_t>(fileIO->FileSize());
693
765
            pimpl->mIOHandler->Close( fileIO );
694
765
        }
695
696
        // Dispatch the reading to the worker class for this format
697
798
        const aiImporterDesc *desc( imp->GetInfo() );
698
798
        std::string ext( "unknown" );
699
798
        if ( nullptr != desc ) {
700
765
            ext = desc->mName;
701
765
        }
702
798
        ASSIMP_LOG_INFO("Found a matching importer for this file format: ", ext, "." );
703
798
        pimpl->mProgressHandler->UpdateFileRead( 0, fileSize );
704
705
798
        if (profiler) {
706
0
            profiler->BeginRegion("import");
707
0
        }
708
709
798
        pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
710
798
        pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize );
711
712
798
        if (profiler) {
713
0
            profiler->EndRegion("import");
714
0
        }
715
716
798
        SetPropertyString("sourceFilePath", pFile);
717
718
        // If successful, apply all active post processing steps to the imported data
719
798
        if( pimpl->mScene)  {
720
471
            if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
721
471
                if (!pimpl->mScene->mMetaData) {
722
471
                    pimpl->mScene->mMetaData = new aiMetadata;
723
471
                }
724
471
                pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext));
725
471
            }
726
727
471
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
728
            // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
729
471
            if (pFlags & aiProcess_ValidateDataStructure) {
730
449
                ValidateDSProcess ds;
731
449
                ds.ExecuteOnScene (this);
732
449
                if (!pimpl->mScene) {
733
182
                    return nullptr;
734
182
                }
735
449
            }
736
289
#endif // ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
737
738
            // Preprocess the scene and prepare it for post-processing
739
289
            if (profiler) {
740
0
                profiler->BeginRegion("preprocess");
741
0
            }
742
743
289
            ScenePreprocessor pre(pimpl->mScene);
744
289
            pre.ProcessScene();
745
746
289
            if (profiler) {
747
0
                profiler->EndRegion("preprocess");
748
0
            }
749
750
            // Ensure that the validation process won't be called twice
751
289
            ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
752
289
        }
753
        // if failed, extract the error string
754
327
        else if( !pimpl->mScene) {
755
294
            pimpl->mErrorString = imp->GetErrorText();
756
294
            pimpl->mException = imp->GetException();
757
294
        }
758
759
        // clear any data allocated by post-process steps
760
616
        pimpl->mPPShared->Clean();
761
762
616
        if (profiler) {
763
0
            profiler->EndRegion("total");
764
0
        }
765
616
    }
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
616
    ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
783
784
583
    return pimpl->mScene;
785
1.15k
}
786
787
788
// ------------------------------------------------------------------------------------------------
789
// Apply post-processing to the currently bound scene
790
289
const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
791
289
    ai_assert(nullptr != pimpl);
792
793
289
    ASSIMP_BEGIN_EXCEPTION_REGION();
794
    // Return immediately if no scene is active
795
289
    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
289
    if (!pFlags) {
801
22
        return pimpl->mScene;
802
22
    }
803
804
    // In debug builds: run basic flag validation
805
289
    ai_assert(_ValidateFlags(pFlags));
806
267
    ASSIMP_LOG_INFO("Entering post processing pipeline");
807
808
267
#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
267
    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
267
#endif // no validation
819
267
#ifdef ASSIMP_BUILD_DEBUG
820
267
    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
267
    std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
834
8.48k
    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)   {
835
8.25k
        BaseProcess* process = pimpl->mPostProcessingSteps[a];
836
8.25k
        pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
837
8.25k
        if( process->IsActive( pFlags)) {
838
3.68k
            if (profiler) {
839
0
                profiler->BeginRegion("postprocess");
840
0
            }
841
842
3.68k
            process->ExecuteOnScene ( this );
843
844
3.68k
            if (profiler) {
845
0
                profiler->EndRegion("postprocess");
846
0
            }
847
3.68k
        }
848
8.25k
        if( !pimpl->mScene) {
849
34
            break;
850
34
        }
851
8.21k
#ifdef ASSIMP_BUILD_DEBUG
852
8.21k
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
853
        // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
854
8.21k
        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
8.21k
#endif  // no validation
865
8.21k
#endif // ! DEBUG
866
8.21k
    }
867
267
    pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()),
868
267
        static_cast<int>(pimpl->mPostProcessingSteps.size()) );
869
870
    // update private scene flags
871
267
    if( pimpl->mScene ) {
872
233
      ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
873
233
    }
874
875
    // clear any data allocated by post-process steps
876
267
    pimpl->mPPShared->Clean();
877
267
    ASSIMP_LOG_INFO("Leaving post processing pipeline");
878
879
267
    ASSIMP_END_EXCEPTION_REGION(const aiScene*);
880
881
267
    return pimpl->mScene;
882
289
}
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
0
size_t Importer::GetImporterCount() const {
970
0
    ai_assert(nullptr != pimpl);
971
972
0
    return pimpl->mImporter.size();
973
0
}
974
975
// ------------------------------------------------------------------------------------------------
976
0
const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
977
0
    ai_assert(nullptr != pimpl);
978
979
0
    if (index >= pimpl->mImporter.size()) {
980
0
        return nullptr;
981
0
    }
982
0
    return pimpl->mImporter[index]->GetInfo();
983
0
}
984
985
986
// ------------------------------------------------------------------------------------------------
987
0
BaseImporter* Importer::GetImporter (size_t index) const {
988
0
    ai_assert(nullptr != pimpl);
989
990
0
    if (index >= pimpl->mImporter.size()) {
991
0
        return nullptr;
992
0
    }
993
0
    return pimpl->mImporter[index];
994
0
}
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
1.64k
bool Importer::SetPropertyInteger(const char* szName, int iValue) {
1064
1.64k
    ai_assert(nullptr != pimpl);
1065
1066
1.64k
    bool existing;
1067
1.64k
    ASSIMP_BEGIN_EXCEPTION_REGION();
1068
1.64k
        existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
1069
1.64k
    ASSIMP_END_EXCEPTION_REGION(bool);
1070
1.64k
    return existing;
1071
1.64k
}
1072
1073
// ------------------------------------------------------------------------------------------------
1074
// Set a configuration property
1075
471
bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
1076
471
    ai_assert(nullptr != pimpl);
1077
1078
471
    bool existing;
1079
471
    ASSIMP_BEGIN_EXCEPTION_REGION();
1080
471
        existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
1081
471
    ASSIMP_END_EXCEPTION_REGION(bool);
1082
471
    return existing;
1083
471
}
1084
1085
// ------------------------------------------------------------------------------------------------
1086
// Set a configuration property
1087
765
bool Importer::SetPropertyString(const char* szName, const std::string& value) {
1088
765
    ai_assert(nullptr != pimpl);
1089
1090
765
    bool existing;
1091
765
    ASSIMP_BEGIN_EXCEPTION_REGION();
1092
765
        existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
1093
765
    ASSIMP_END_EXCEPTION_REGION(bool);
1094
765
    return existing;
1095
765
}
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
4.96k
int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
1124
4.96k
    ai_assert(nullptr != pimpl);
1125
1126
4.96k
    return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
1127
4.96k
}
1128
1129
// ------------------------------------------------------------------------------------------------
1130
// Get a configuration property
1131
728
ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
1132
728
    ai_assert(nullptr != pimpl);
1133
1134
728
    return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
1135
728
}
1136
1137
// ------------------------------------------------------------------------------------------------
1138
// Get a configuration property
1139
310
std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
1140
310
    ai_assert(nullptr != pimpl);
1141
1142
310
    return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
1143
310
}
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
0
void* Importer::GetPropertyPointer(const char* szName, void* iErrorReturn /*= nullptr*/) const {
1156
0
    ai_assert(nullptr != pimpl);
1157
1158
0
    return GetGenericProperty<void*>(pimpl->mPointerProperties,szName,iErrorReturn);
1159
0
}
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
}