1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2021, 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 // ------------------------------------------------------------------------------------------------
operator new(size_t num_bytes)114 void* AllocateFromAssimpHeap::operator new ( size_t num_bytes) {
115 return ::operator new(num_bytes);
116 }
117
operator new(size_t num_bytes,const std::nothrow_t &)118 void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothrow_t& ) throw() {
119 try {
120 return AllocateFromAssimpHeap::operator new( num_bytes );
121 }
122 catch( ... ) {
123 return nullptr;
124 }
125 }
126
operator delete(void * data)127 void AllocateFromAssimpHeap::operator delete ( void* data) {
128 return ::operator delete(data);
129 }
130
operator new[](size_t num_bytes)131 void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) {
132 return ::operator new[](num_bytes);
133 }
134
operator new[](size_t num_bytes,const std::nothrow_t &)135 void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() {
136 try {
137 return AllocateFromAssimpHeap::operator new[]( num_bytes );
138 } catch( ... ) {
139 return nullptr;
140 }
141 }
142
operator delete[](void * data)143 void AllocateFromAssimpHeap::operator delete[] ( void* data) {
144 return ::operator delete[](data);
145 }
146
147 // ------------------------------------------------------------------------------------------------
148 // Importer constructor.
Importer()149 Importer::Importer()
150 : pimpl( new ImporterPimpl ) {
151 pimpl->mScene = nullptr;
152 pimpl->mErrorString = std::string();
153
154 // Allocate a default IO handler
155 pimpl->mIOHandler = new DefaultIOSystem;
156 pimpl->mIsDefaultHandler = true;
157 pimpl->bExtraVerbose = false; // disable extra verbose mode by default
158
159 pimpl->mProgressHandler = new DefaultProgressHandler();
160 pimpl->mIsDefaultProgressHandler = true;
161
162 GetImporterInstanceList(pimpl->mImporter);
163 GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps);
164
165 // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list.
166 pimpl->mPPShared = new SharedPostProcessInfo();
167 for (std::vector<BaseProcess*>::iterator it = pimpl->mPostProcessingSteps.begin();
168 it != pimpl->mPostProcessingSteps.end();
169 ++it) {
170
171 (*it)->SetSharedData(pimpl->mPPShared);
172 }
173 }
174
175 // ------------------------------------------------------------------------------------------------
176 // Destructor of Importer
~Importer()177 Importer::~Importer() {
178 // Delete all import plugins
179 DeleteImporterInstanceList(pimpl->mImporter);
180
181 // Delete all post-processing plug-ins
182 for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
183 delete pimpl->mPostProcessingSteps[a];
184 }
185
186 // Delete the assigned IO and progress handler
187 delete pimpl->mIOHandler;
188 delete pimpl->mProgressHandler;
189
190 // Kill imported scene. Destructor's should do that recursively
191 delete pimpl->mScene;
192
193 // Delete shared post-processing data
194 delete pimpl->mPPShared;
195
196 // and finally the pimpl itself
197 delete pimpl;
198 }
199
200 // ------------------------------------------------------------------------------------------------
201 // Register a custom post-processing step
RegisterPPStep(BaseProcess * pImp)202 aiReturn Importer::RegisterPPStep(BaseProcess* pImp) {
203 ai_assert( nullptr != pImp );
204
205 ASSIMP_BEGIN_EXCEPTION_REGION();
206
207 pimpl->mPostProcessingSteps.push_back(pImp);
208 ASSIMP_LOG_INFO("Registering custom post-processing step");
209
210 ASSIMP_END_EXCEPTION_REGION(aiReturn);
211 return AI_SUCCESS;
212 }
213
214 // ------------------------------------------------------------------------------------------------
215 // Register a custom loader plugin
RegisterLoader(BaseImporter * pImp)216 aiReturn Importer::RegisterLoader(BaseImporter* pImp) {
217 ai_assert(nullptr != pImp);
218
219 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 std::set<std::string> st;
228 std::string baked;
229 pImp->GetExtensionList(st);
230
231 for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
232
233 #ifdef ASSIMP_BUILD_DEBUG
234 if (IsExtensionSupported(*it)) {
235 ASSIMP_LOG_WARN("The file extension ", *it, " is already in use");
236 }
237 #endif
238 baked += *it;
239 }
240
241 // add the loader
242 pimpl->mImporter.push_back(pImp);
243 ASSIMP_LOG_INFO("Registering custom importer for these file extensions: ", baked);
244 ASSIMP_END_EXCEPTION_REGION(aiReturn);
245
246 return AI_SUCCESS;
247 }
248
249 // ------------------------------------------------------------------------------------------------
250 // Unregister a custom loader plugin
UnregisterLoader(BaseImporter * pImp)251 aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
252 if(!pImp) {
253 // unregistering a nullptr importer is no problem for us ... really!
254 return AI_SUCCESS;
255 }
256
257 ASSIMP_BEGIN_EXCEPTION_REGION();
258 std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),
259 pimpl->mImporter.end(),pImp);
260
261 if (it != pimpl->mImporter.end()) {
262 pimpl->mImporter.erase(it);
263 ASSIMP_LOG_INFO("Unregistering custom importer: ");
264 return AI_SUCCESS;
265 }
266 ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ...");
267 ASSIMP_END_EXCEPTION_REGION(aiReturn);
268
269 return AI_FAILURE;
270 }
271
272 // ------------------------------------------------------------------------------------------------
273 // Unregister a custom loader plugin
UnregisterPPStep(BaseProcess * pImp)274 aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) {
275 if(!pImp) {
276 // unregistering a nullptr ppstep is no problem for us ... really!
277 return AI_SUCCESS;
278 }
279
280 ASSIMP_BEGIN_EXCEPTION_REGION();
281 std::vector<BaseProcess*>::iterator it = std::find(pimpl->mPostProcessingSteps.begin(),
282 pimpl->mPostProcessingSteps.end(),pImp);
283
284 if (it != pimpl->mPostProcessingSteps.end()) {
285 pimpl->mPostProcessingSteps.erase(it);
286 ASSIMP_LOG_INFO("Unregistering custom post-processing step");
287 return AI_SUCCESS;
288 }
289 ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you ..");
290 ASSIMP_END_EXCEPTION_REGION(aiReturn);
291
292 return AI_FAILURE;
293 }
294
295 // ------------------------------------------------------------------------------------------------
296 // Supplies a custom IO handler to the importer to open and access files.
SetIOHandler(IOSystem * pIOHandler)297 void Importer::SetIOHandler( IOSystem* pIOHandler) {
298 ai_assert(nullptr != pimpl);
299
300 ASSIMP_BEGIN_EXCEPTION_REGION();
301 // If the new handler is zero, allocate a default IO implementation.
302 if (!pIOHandler) {
303 // Release pointer in the possession of the caller
304 pimpl->mIOHandler = new DefaultIOSystem();
305 pimpl->mIsDefaultHandler = true;
306 } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
307 delete pimpl->mIOHandler;
308 pimpl->mIOHandler = pIOHandler;
309 pimpl->mIsDefaultHandler = false;
310 }
311 ASSIMP_END_EXCEPTION_REGION(void);
312 }
313
314 // ------------------------------------------------------------------------------------------------
315 // Get the currently set IO handler
GetIOHandler() const316 IOSystem* Importer::GetIOHandler() const {
317 ai_assert(nullptr != pimpl);
318
319 return pimpl->mIOHandler;
320 }
321
322 // ------------------------------------------------------------------------------------------------
323 // Check whether a custom IO handler is currently set
IsDefaultIOHandler() const324 bool Importer::IsDefaultIOHandler() const {
325 ai_assert(nullptr != pimpl);
326
327 return pimpl->mIsDefaultHandler;
328 }
329
330 // ------------------------------------------------------------------------------------------------
331 // Supplies a custom progress handler to get regular callbacks during importing
SetProgressHandler(ProgressHandler * pHandler)332 void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
333 ai_assert(nullptr != pimpl);
334
335 ASSIMP_BEGIN_EXCEPTION_REGION();
336
337 // If the new handler is zero, allocate a default implementation.
338 if (!pHandler) {
339 // Release pointer in the possession of the caller
340 pimpl->mProgressHandler = new DefaultProgressHandler();
341 pimpl->mIsDefaultProgressHandler = true;
342 } else if (pimpl->mProgressHandler != pHandler) { // Otherwise register the custom handler
343 delete pimpl->mProgressHandler;
344 pimpl->mProgressHandler = pHandler;
345 pimpl->mIsDefaultProgressHandler = false;
346 }
347 ASSIMP_END_EXCEPTION_REGION(void);
348 }
349
350 // ------------------------------------------------------------------------------------------------
351 // Get the currently set progress handler
GetProgressHandler() const352 ProgressHandler* Importer::GetProgressHandler() const {
353 ai_assert(nullptr != pimpl);
354
355 return pimpl->mProgressHandler;
356 }
357
358 // ------------------------------------------------------------------------------------------------
359 // Check whether a custom progress handler is currently set
IsDefaultProgressHandler() const360 bool Importer::IsDefaultProgressHandler() const {
361 ai_assert(nullptr != pimpl);
362
363 return pimpl->mIsDefaultProgressHandler;
364 }
365
366 // ------------------------------------------------------------------------------------------------
367 // Validate post process step flags
_ValidateFlags(unsigned int pFlags)368 bool _ValidateFlags(unsigned int pFlags) {
369 if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) {
370 ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
371 return false;
372 }
373 if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices) {
374 ASSIMP_LOG_ERROR("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible");
375 return false;
376 }
377 return true;
378 }
379
380 // ------------------------------------------------------------------------------------------------
381 // Free the current scene
FreeScene()382 void Importer::FreeScene( ) {
383 ai_assert(nullptr != pimpl);
384
385 ASSIMP_BEGIN_EXCEPTION_REGION();
386
387 delete pimpl->mScene;
388 pimpl->mScene = nullptr;
389
390 pimpl->mErrorString = std::string();
391 pimpl->mException = std::exception_ptr();
392 ASSIMP_END_EXCEPTION_REGION(void);
393 }
394
395 // ------------------------------------------------------------------------------------------------
396 // Get the current error string, if any
GetErrorString() const397 const char* Importer::GetErrorString() const {
398 ai_assert(nullptr != pimpl);
399
400 // Must remain valid as long as ReadFile() or FreeFile() are not called
401 return pimpl->mErrorString.c_str();
402 }
403
GetException() const404 const std::exception_ptr& Importer::GetException() const {
405 ai_assert(nullptr != pimpl);
406
407 // Must remain valid as long as ReadFile() or FreeFile() are not called
408 return pimpl->mException;
409 }
410
411 // ------------------------------------------------------------------------------------------------
412 // Enable extra-verbose mode
SetExtraVerbose(bool bDo)413 void Importer::SetExtraVerbose(bool bDo) {
414 ai_assert(nullptr != pimpl);
415
416 pimpl->bExtraVerbose = bDo;
417 }
418
419 // ------------------------------------------------------------------------------------------------
420 // Get the current scene
GetScene() const421 const aiScene* Importer::GetScene() const {
422 ai_assert(nullptr != pimpl);
423
424 return pimpl->mScene;
425 }
426
427 // ------------------------------------------------------------------------------------------------
428 // Orphan the current scene and return it.
GetOrphanedScene()429 aiScene* Importer::GetOrphanedScene() {
430 ai_assert(nullptr != pimpl);
431
432 aiScene* s = pimpl->mScene;
433
434 ASSIMP_BEGIN_EXCEPTION_REGION();
435 pimpl->mScene = nullptr;
436
437 pimpl->mErrorString = std::string();
438 pimpl->mException = std::exception_ptr();
439 ASSIMP_END_EXCEPTION_REGION(aiScene*);
440
441 return s;
442 }
443
444 // ------------------------------------------------------------------------------------------------
445 // Validate post-processing flags
ValidateFlags(unsigned int pFlags) const446 bool Importer::ValidateFlags(unsigned int pFlags) const {
447 ASSIMP_BEGIN_EXCEPTION_REGION();
448 // run basic checks for mutually exclusive flags
449 if(!_ValidateFlags(pFlags)) {
450 return false;
451 }
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 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 for (unsigned int mask = 1; mask < (1u << (sizeof(unsigned int)*8-1));mask <<= 1) {
464
465 if (pFlags & mask) {
466
467 bool have = false;
468 for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
469 if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) {
470
471 have = true;
472 break;
473 }
474 }
475 if (!have) {
476 return false;
477 }
478 }
479 }
480 ASSIMP_END_EXCEPTION_REGION(bool);
481 return true;
482 }
483
484 // ------------------------------------------------------------------------------------------------
ReadFileFromMemory(const void * pBuffer,size_t pLength,unsigned int pFlags,const char * pHint)485 const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
486 size_t pLength,
487 unsigned int pFlags,
488 const char* pHint /*= ""*/) {
489 ai_assert(nullptr != pimpl);
490
491 ASSIMP_BEGIN_EXCEPTION_REGION();
492 if (!pHint) {
493 pHint = "";
494 }
495
496 if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
497 pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
498 return nullptr;
499 }
500
501 // prevent deletion of the previous IOHandler
502 IOSystem* io = pimpl->mIOHandler;
503 pimpl->mIOHandler = nullptr;
504
505 SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
506
507 // read the file and recover the previous IOSystem
508 static const size_t BufSize(Importer::MaxLenHint + 28);
509 char fbuff[BufSize];
510 ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
511
512 ReadFile(fbuff,pFlags);
513 SetIOHandler(io);
514
515 ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
516 return pimpl->mScene;
517 }
518
519 // ------------------------------------------------------------------------------------------------
WriteLogOpening(const std::string & file)520 void WriteLogOpening(const std::string& file) {
521
522 ASSIMP_LOG_INFO("Load ", file);
523
524 // print a full version dump. This is nice because we don't
525 // need to ask the authors of incoming bug reports for
526 // the library version they're using - a log dump is
527 // sufficient.
528 const unsigned int flags = aiGetCompileFlags();
529 std::stringstream stream;
530 stream << "Assimp " << aiGetVersionMajor() << "." << aiGetVersionMinor() << "." << aiGetVersionRevision() << " "
531 #if defined(ASSIMP_BUILD_ARCHITECTURE)
532 << ASSIMP_BUILD_ARCHITECTURE
533 #elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__)
534 << "x86"
535 #elif defined(_M_X64) || defined(__x86_64__)
536 << "amd64"
537 #elif defined(_M_IA64) || defined(__ia64__)
538 << "itanium"
539 #elif defined(__ppc__) || defined(__powerpc__)
540 << "ppc32"
541 #elif defined(__powerpc64__)
542 << "ppc64"
543 #elif defined(__arm__)
544 << "arm"
545 #else
546 << "<unknown architecture>"
547 #endif
548 << " "
549 #if defined(ASSIMP_BUILD_COMPILER)
550 << (ASSIMP_BUILD_COMPILER)
551 #elif defined(_MSC_VER)
552 << "msvc"
553 #elif defined(__GNUC__)
554 << "gcc"
555 #elif defined(__clang__)
556 << "clang"
557 #elif defined(__EMSCRIPTEN__)
558 << "emscripten"
559 #elif defined(__MINGW32__)
560 << "MinGW-w64 32bit"
561 #elif defined(__MINGW64__)
562 << "MinGW-w64 64bit"
563 #else
564 << "<unknown compiler>"
565 #endif
566
567 #ifdef ASSIMP_BUILD_DEBUG
568 << " debug"
569 #endif
570
571 << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "")
572 << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "")
573 << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "")
574 << (flags & ASSIMP_CFLAGS_DOUBLE_SUPPORT ? " double : " : "single : ");
575
576 ASSIMP_LOG_DEBUG(stream.str());
577 }
578
579 // ------------------------------------------------------------------------------------------------
580 // Reads the given file and returns its contents if successful.
ReadFile(const char * _pFile,unsigned int pFlags)581 const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
582 ai_assert(nullptr != pimpl);
583
584 ASSIMP_BEGIN_EXCEPTION_REGION();
585 const std::string pFile(_pFile);
586
587 // ----------------------------------------------------------------------
588 // Put a large try block around everything to catch all std::exception's
589 // that might be thrown by STL containers or by new().
590 // ImportErrorException's are throw by ourselves and caught elsewhere.
591 //-----------------------------------------------------------------------
592
593 WriteLogOpening(pFile);
594
595 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
596 try
597 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
598 {
599 // Check whether this Importer instance has already loaded
600 // a scene. In this case we need to delete the old one
601 if (pimpl->mScene) {
602
603 ASSIMP_LOG_DEBUG("(Deleting previous scene)");
604 FreeScene();
605 }
606
607 // First check if the file is accessible at all
608 if( !pimpl->mIOHandler->Exists( pFile)) {
609
610 pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
611 ASSIMP_LOG_ERROR(pimpl->mErrorString);
612 return nullptr;
613 }
614
615 std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
616 if (profiler) {
617 profiler->BeginRegion("total");
618 }
619
620 // Find an worker class which can handle the file
621 BaseImporter* imp = nullptr;
622 SetPropertyInteger("importerIndex", -1);
623 for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
624
625 if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
626 imp = pimpl->mImporter[a];
627 SetPropertyInteger("importerIndex", a);
628 break;
629 }
630 }
631
632 if (!imp) {
633 // not so bad yet ... try format auto detection.
634 const std::string::size_type s = pFile.find_last_of('.');
635 if (s != std::string::npos) {
636 ASSIMP_LOG_INFO("File extension not known, trying signature-based detection");
637 for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
638 if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
639 imp = pimpl->mImporter[a];
640 SetPropertyInteger("importerIndex", a);
641 break;
642 }
643 }
644 }
645 // Put a proper error message if no suitable importer was found
646 if( !imp) {
647 pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
648 ASSIMP_LOG_ERROR(pimpl->mErrorString);
649 return nullptr;
650 }
651 }
652
653 // Get file size for progress handler
654 IOStream * fileIO = pimpl->mIOHandler->Open( pFile );
655 uint32_t fileSize = 0;
656 if (fileIO)
657 {
658 fileSize = static_cast<uint32_t>(fileIO->FileSize());
659 pimpl->mIOHandler->Close( fileIO );
660 }
661
662 // Dispatch the reading to the worker class for this format
663 const aiImporterDesc *desc( imp->GetInfo() );
664 std::string ext( "unknown" );
665 if ( nullptr != desc ) {
666 ext = desc->mName;
667 }
668 ASSIMP_LOG_INFO("Found a matching importer for this file format: ", ext, "." );
669 pimpl->mProgressHandler->UpdateFileRead( 0, fileSize );
670
671 if (profiler) {
672 profiler->BeginRegion("import");
673 }
674
675 pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
676 pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize );
677
678 if (profiler) {
679 profiler->EndRegion("import");
680 }
681
682 SetPropertyString("sourceFilePath", pFile);
683
684 // If successful, apply all active post processing steps to the imported data
685 if( pimpl->mScene) {
686 if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
687 if (!pimpl->mScene->mMetaData) {
688 pimpl->mScene->mMetaData = new aiMetadata;
689 }
690 pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext));
691 }
692
693 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
694 // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
695 if (pFlags & aiProcess_ValidateDataStructure) {
696 ValidateDSProcess ds;
697 ds.ExecuteOnScene (this);
698 if (!pimpl->mScene) {
699 return nullptr;
700 }
701 }
702 #endif // no validation
703
704 // Preprocess the scene and prepare it for post-processing
705 if (profiler) {
706 profiler->BeginRegion("preprocess");
707 }
708
709 ScenePreprocessor pre(pimpl->mScene);
710 pre.ProcessScene();
711
712 if (profiler) {
713 profiler->EndRegion("preprocess");
714 }
715
716 // Ensure that the validation process won't be called twice
717 ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
718 }
719 // if failed, extract the error string
720 else if( !pimpl->mScene) {
721 pimpl->mErrorString = imp->GetErrorText();
722 pimpl->mException = imp->GetException();
723 }
724
725 // clear any data allocated by post-process steps
726 pimpl->mPPShared->Clean();
727
728 if (profiler) {
729 profiler->EndRegion("total");
730 }
731 }
732 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
733 catch (std::exception &e) {
734 #if (defined _MSC_VER) && (defined _CPPRTTI)
735 // if we have RTTI get the full name of the exception that occurred
736 pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
737 #else
738 pimpl->mErrorString = std::string("std::exception: ") + e.what();
739 #endif
740
741 ASSIMP_LOG_ERROR(pimpl->mErrorString);
742 delete pimpl->mScene; pimpl->mScene = nullptr;
743 }
744 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
745
746 // either successful or failure - the pointer expresses it anyways
747 ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString, pimpl->mException);
748
749 return pimpl->mScene;
750 }
751
752
753 // ------------------------------------------------------------------------------------------------
754 // Apply post-processing to the currently bound scene
ApplyPostProcessing(unsigned int pFlags)755 const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
756 ai_assert(nullptr != pimpl);
757
758 ASSIMP_BEGIN_EXCEPTION_REGION();
759 // Return immediately if no scene is active
760 if (!pimpl->mScene) {
761 return nullptr;
762 }
763
764 // If no flags are given, return the current scene with no further action
765 if (!pFlags) {
766 return pimpl->mScene;
767 }
768
769 // In debug builds: run basic flag validation
770 ai_assert(_ValidateFlags(pFlags));
771 ASSIMP_LOG_INFO("Entering post processing pipeline");
772
773 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
774 // The ValidateDS process plays an exceptional role. It isn't contained in the global
775 // list of post-processing steps, so we need to call it manually.
776 if (pFlags & aiProcess_ValidateDataStructure) {
777 ValidateDSProcess ds;
778 ds.ExecuteOnScene (this);
779 if (!pimpl->mScene) {
780 return nullptr;
781 }
782 }
783 #endif // no validation
784 #ifdef ASSIMP_BUILD_DEBUG
785 if (pimpl->bExtraVerbose)
786 {
787 #ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
788 ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
789 #endif // no validation
790 pFlags |= aiProcess_ValidateDataStructure;
791 }
792 #else
793 if (pimpl->bExtraVerbose) {
794 ASSIMP_LOG_WARN("Not a debug build, ignoring extra verbose setting");
795 }
796 #endif // ! DEBUG
797
798 std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
799 for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
800 BaseProcess* process = pimpl->mPostProcessingSteps[a];
801 pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
802 if( process->IsActive( pFlags)) {
803 if (profiler) {
804 profiler->BeginRegion("postprocess");
805 }
806
807 process->ExecuteOnScene ( this );
808
809 if (profiler) {
810 profiler->EndRegion("postprocess");
811 }
812 }
813 if( !pimpl->mScene) {
814 break;
815 }
816 #ifdef ASSIMP_BUILD_DEBUG
817
818 #ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
819 continue;
820 #endif // no validation
821
822 // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
823 if (pimpl->bExtraVerbose) {
824 ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures");
825
826 ValidateDSProcess ds;
827 ds.ExecuteOnScene (this);
828 if( !pimpl->mScene) {
829 ASSIMP_LOG_ERROR("Verbose Import: failed to re-validate data structures");
830 break;
831 }
832 }
833 #endif // ! DEBUG
834 }
835 pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()),
836 static_cast<int>(pimpl->mPostProcessingSteps.size()) );
837
838 // update private scene flags
839 if( pimpl->mScene ) {
840 ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
841 }
842
843 // clear any data allocated by post-process steps
844 pimpl->mPPShared->Clean();
845 ASSIMP_LOG_INFO("Leaving post processing pipeline");
846
847 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
848
849 return pimpl->mScene;
850 }
851
852 // ------------------------------------------------------------------------------------------------
ApplyCustomizedPostProcessing(BaseProcess * rootProcess,bool requestValidation)853 const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) {
854 ai_assert(nullptr != pimpl);
855
856 ASSIMP_BEGIN_EXCEPTION_REGION();
857
858 // Return immediately if no scene is active
859 if ( nullptr == pimpl->mScene ) {
860 return nullptr;
861 }
862
863 // If no flags are given, return the current scene with no further action
864 if (nullptr == rootProcess) {
865 return pimpl->mScene;
866 }
867
868 // In debug builds: run basic flag validation
869 ASSIMP_LOG_INFO( "Entering customized post processing pipeline" );
870
871 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
872 // The ValidateDS process plays an exceptional role. It isn't contained in the global
873 // list of post-processing steps, so we need to call it manually.
874 if ( requestValidation )
875 {
876 ValidateDSProcess ds;
877 ds.ExecuteOnScene( this );
878 if ( !pimpl->mScene ) {
879 return nullptr;
880 }
881 }
882 #endif // no validation
883 #ifdef ASSIMP_BUILD_DEBUG
884 if ( pimpl->bExtraVerbose )
885 {
886 #ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
887 ASSIMP_LOG_ERROR( "Verbose Import is not available due to build settings" );
888 #endif // no validation
889 }
890 #else
891 if ( pimpl->bExtraVerbose ) {
892 ASSIMP_LOG_WARN( "Not a debug build, ignoring extra verbose setting" );
893 }
894 #endif // ! DEBUG
895
896 std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME, 0) ? new Profiler() : nullptr);
897
898 if ( profiler ) {
899 profiler->BeginRegion( "postprocess" );
900 }
901
902 rootProcess->ExecuteOnScene( this );
903
904 if ( profiler ) {
905 profiler->EndRegion( "postprocess" );
906 }
907
908 // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
909 if ( pimpl->bExtraVerbose || requestValidation ) {
910 ASSIMP_LOG_DEBUG( "Verbose Import: revalidating data structures" );
911
912 ValidateDSProcess ds;
913 ds.ExecuteOnScene( this );
914 if ( !pimpl->mScene ) {
915 ASSIMP_LOG_ERROR( "Verbose Import: failed to revalidate data structures" );
916 }
917 }
918
919 // clear any data allocated by post-process steps
920 pimpl->mPPShared->Clean();
921 ASSIMP_LOG_INFO( "Leaving customized post processing pipeline" );
922
923 ASSIMP_END_EXCEPTION_REGION( const aiScene* );
924
925 return pimpl->mScene;
926 }
927
928 // ------------------------------------------------------------------------------------------------
929 // Helper function to check whether an extension is supported by ASSIMP
IsExtensionSupported(const char * szExtension) const930 bool Importer::IsExtensionSupported(const char* szExtension) const {
931 return nullptr != GetImporter(szExtension);
932 }
933
934 // ------------------------------------------------------------------------------------------------
GetImporterCount() const935 size_t Importer::GetImporterCount() const {
936 ai_assert(nullptr != pimpl);
937
938 return pimpl->mImporter.size();
939 }
940
941 // ------------------------------------------------------------------------------------------------
GetImporterInfo(size_t index) const942 const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
943 ai_assert(nullptr != pimpl);
944
945 if (index >= pimpl->mImporter.size()) {
946 return nullptr;
947 }
948 return pimpl->mImporter[index]->GetInfo();
949 }
950
951
952 // ------------------------------------------------------------------------------------------------
GetImporter(size_t index) const953 BaseImporter* Importer::GetImporter (size_t index) const {
954 ai_assert(nullptr != pimpl);
955
956 if (index >= pimpl->mImporter.size()) {
957 return nullptr;
958 }
959 return pimpl->mImporter[index];
960 }
961
962 // ------------------------------------------------------------------------------------------------
963 // Find a loader plugin for a given file extension
GetImporter(const char * szExtension) const964 BaseImporter* Importer::GetImporter (const char* szExtension) const {
965 ai_assert(nullptr != pimpl);
966
967 return GetImporter(GetImporterIndex(szExtension));
968 }
969
970 // ------------------------------------------------------------------------------------------------
971 // Find a loader plugin for a given file extension
GetImporterIndex(const char * szExtension) const972 size_t Importer::GetImporterIndex (const char* szExtension) const {
973 ai_assert(nullptr != pimpl);
974 ai_assert(nullptr != szExtension);
975
976 ASSIMP_BEGIN_EXCEPTION_REGION();
977
978 // skip over wild-card and dot characters at string head --
979 for ( ; *szExtension == '*' || *szExtension == '.'; ++szExtension );
980
981 std::string ext(szExtension);
982 if (ext.empty()) {
983 return static_cast<size_t>(-1);
984 }
985 ext = ai_tolower(ext);
986 std::set<std::string> str;
987 for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) {
988 str.clear();
989
990 (*i)->GetExtensionList(str);
991 for (std::set<std::string>::const_iterator it = str.begin(); it != str.end(); ++it) {
992 if (ext == *it) {
993 return std::distance(static_cast< std::vector<BaseImporter*>::const_iterator >(pimpl->mImporter.begin()), i);
994 }
995 }
996 }
997 ASSIMP_END_EXCEPTION_REGION(size_t);
998 return static_cast<size_t>(-1);
999 }
1000
1001 // ------------------------------------------------------------------------------------------------
1002 // Helper function to build a list of all file extensions supported by ASSIMP
GetExtensionList(aiString & szOut) const1003 void Importer::GetExtensionList(aiString& szOut) const {
1004 ai_assert(nullptr != pimpl);
1005
1006 ASSIMP_BEGIN_EXCEPTION_REGION();
1007 std::set<std::string> str;
1008 for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) {
1009 (*i)->GetExtensionList(str);
1010 }
1011
1012 // List can be empty
1013 if( !str.empty() ) {
1014 for (std::set<std::string>::const_iterator it = str.begin();; ) {
1015 szOut.Append("*.");
1016 szOut.Append((*it).c_str());
1017
1018 if (++it == str.end()) {
1019 break;
1020 }
1021 szOut.Append(";");
1022 }
1023 }
1024 ASSIMP_END_EXCEPTION_REGION(void);
1025 }
1026
1027 // ------------------------------------------------------------------------------------------------
1028 // Set a configuration property
SetPropertyInteger(const char * szName,int iValue)1029 bool Importer::SetPropertyInteger(const char* szName, int iValue) {
1030 ai_assert(nullptr != pimpl);
1031
1032 bool existing;
1033 ASSIMP_BEGIN_EXCEPTION_REGION();
1034 existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
1035 ASSIMP_END_EXCEPTION_REGION(bool);
1036 return existing;
1037 }
1038
1039 // ------------------------------------------------------------------------------------------------
1040 // Set a configuration property
SetPropertyFloat(const char * szName,ai_real iValue)1041 bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
1042 ai_assert(nullptr != pimpl);
1043
1044 bool existing;
1045 ASSIMP_BEGIN_EXCEPTION_REGION();
1046 existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
1047 ASSIMP_END_EXCEPTION_REGION(bool);
1048 return existing;
1049 }
1050
1051 // ------------------------------------------------------------------------------------------------
1052 // Set a configuration property
SetPropertyString(const char * szName,const std::string & value)1053 bool Importer::SetPropertyString(const char* szName, const std::string& value) {
1054 ai_assert(nullptr != pimpl);
1055
1056 bool existing;
1057 ASSIMP_BEGIN_EXCEPTION_REGION();
1058 existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
1059 ASSIMP_END_EXCEPTION_REGION(bool);
1060 return existing;
1061 }
1062
1063 // ------------------------------------------------------------------------------------------------
1064 // Set a configuration property
SetPropertyMatrix(const char * szName,const aiMatrix4x4 & value)1065 bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
1066 ai_assert(nullptr != pimpl);
1067
1068 bool existing;
1069 ASSIMP_BEGIN_EXCEPTION_REGION();
1070 existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value);
1071 ASSIMP_END_EXCEPTION_REGION(bool);
1072 return existing;
1073 }
1074
1075 // ------------------------------------------------------------------------------------------------
1076 // Set a configuration property
SetPropertyPointer(const char * szName,void * value)1077 bool Importer::SetPropertyPointer(const char* szName, void* value) {
1078 ai_assert(nullptr != pimpl);
1079
1080 bool existing;
1081 ASSIMP_BEGIN_EXCEPTION_REGION();
1082 existing = SetGenericProperty<void*>(pimpl->mPointerProperties, szName,value);
1083 ASSIMP_END_EXCEPTION_REGION(bool);
1084 return existing;
1085 }
1086
1087 // ------------------------------------------------------------------------------------------------
1088 // Get a configuration property
GetPropertyInteger(const char * szName,int iErrorReturn) const1089 int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
1090 ai_assert(nullptr != pimpl);
1091
1092 return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
1093 }
1094
1095 // ------------------------------------------------------------------------------------------------
1096 // Get a configuration property
GetPropertyFloat(const char * szName,ai_real iErrorReturn) const1097 ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
1098 ai_assert(nullptr != pimpl);
1099
1100 return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
1101 }
1102
1103 // ------------------------------------------------------------------------------------------------
1104 // Get a configuration property
GetPropertyString(const char * szName,const std::string & iErrorReturn) const1105 std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
1106 ai_assert(nullptr != pimpl);
1107
1108 return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
1109 }
1110
1111 // ------------------------------------------------------------------------------------------------
1112 // Get a configuration property
GetPropertyMatrix(const char * szName,const aiMatrix4x4 & iErrorReturn) const1113 aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
1114 ai_assert(nullptr != pimpl);
1115
1116 return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
1117 }
1118
1119 // ------------------------------------------------------------------------------------------------
1120 // Get a configuration property
GetPropertyPointer(const char * szName,void * iErrorReturn) const1121 void* Importer::GetPropertyPointer(const char* szName, void* iErrorReturn /*= nullptr*/) const {
1122 ai_assert(nullptr != pimpl);
1123
1124 return GetGenericProperty<void*>(pimpl->mPointerProperties,szName,iErrorReturn);
1125 }
1126
1127 // ------------------------------------------------------------------------------------------------
1128 // Get the memory requirements of a single node
1129 inline
AddNodeWeight(unsigned int & iScene,const aiNode * pcNode)1130 void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) {
1131 if ( nullptr == pcNode ) {
1132 return;
1133 }
1134 iScene += sizeof(aiNode);
1135 iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
1136 iScene += sizeof(void*) * pcNode->mNumChildren;
1137
1138 for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
1139 AddNodeWeight(iScene,pcNode->mChildren[i]);
1140 }
1141 }
1142
1143 // ------------------------------------------------------------------------------------------------
1144 // Get the memory requirements of the scene
GetMemoryRequirements(aiMemoryInfo & in) const1145 void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
1146 ai_assert(nullptr != pimpl);
1147
1148 in = aiMemoryInfo();
1149 aiScene* mScene = pimpl->mScene;
1150
1151 // return if we have no scene loaded
1152 if (!mScene)
1153 return;
1154
1155 in.total = sizeof(aiScene);
1156
1157 // add all meshes
1158 for (unsigned int i = 0; i < mScene->mNumMeshes;++i) {
1159 in.meshes += sizeof(aiMesh);
1160 if (mScene->mMeshes[i]->HasPositions()) {
1161 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
1162 }
1163
1164 if (mScene->mMeshes[i]->HasNormals()) {
1165 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
1166 }
1167
1168 if (mScene->mMeshes[i]->HasTangentsAndBitangents()) {
1169 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices * 2;
1170 }
1171
1172 for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) {
1173 if (mScene->mMeshes[i]->HasVertexColors(a)) {
1174 in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
1175 } else {
1176 break;
1177 }
1178 }
1179 for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
1180 if (mScene->mMeshes[i]->HasTextureCoords(a)) {
1181 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
1182 } else {
1183 break;
1184 }
1185 }
1186 if (mScene->mMeshes[i]->HasBones()) {
1187 in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
1188 for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones;++p) {
1189 in.meshes += sizeof(aiBone);
1190 in.meshes += mScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight);
1191 }
1192 }
1193 in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int))*mScene->mMeshes[i]->mNumFaces;
1194 }
1195 in.total += in.meshes;
1196
1197 // add all embedded textures
1198 for (unsigned int i = 0; i < mScene->mNumTextures;++i) {
1199 const aiTexture* pc = mScene->mTextures[i];
1200 in.textures += sizeof(aiTexture);
1201 if (pc->mHeight) {
1202 in.textures += 4 * pc->mHeight * pc->mWidth;
1203 } else {
1204 in.textures += pc->mWidth;
1205 }
1206 }
1207 in.total += in.textures;
1208
1209 // add all animations
1210 for (unsigned int i = 0; i < mScene->mNumAnimations;++i) {
1211 const aiAnimation* pc = mScene->mAnimations[i];
1212 in.animations += sizeof(aiAnimation);
1213
1214 // add all bone anims
1215 for (unsigned int a = 0; a < pc->mNumChannels; ++a) {
1216 const aiNodeAnim* pc2 = pc->mChannels[a];
1217 in.animations += sizeof(aiNodeAnim);
1218 in.animations += pc2->mNumPositionKeys * sizeof(aiVectorKey);
1219 in.animations += pc2->mNumScalingKeys * sizeof(aiVectorKey);
1220 in.animations += pc2->mNumRotationKeys * sizeof(aiQuatKey);
1221 }
1222 }
1223 in.total += in.animations;
1224
1225 // add all cameras and all lights
1226 in.total += in.cameras = sizeof(aiCamera) * mScene->mNumCameras;
1227 in.total += in.lights = sizeof(aiLight) * mScene->mNumLights;
1228
1229 // add all nodes
1230 AddNodeWeight(in.nodes,mScene->mRootNode);
1231 in.total += in.nodes;
1232
1233 // add all materials
1234 for (unsigned int i = 0; i < mScene->mNumMaterials;++i) {
1235 const aiMaterial* pc = mScene->mMaterials[i];
1236 in.materials += sizeof(aiMaterial);
1237 in.materials += pc->mNumAllocated * sizeof(void*);
1238
1239 for (unsigned int a = 0; a < pc->mNumProperties;++a) {
1240 in.materials += pc->mProperties[a]->mDataLength;
1241 }
1242 }
1243
1244 in.total += in.materials;
1245 }
1246