1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2012, 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 "AssimpPCH.h"
47 #include "../include/assimp/version.h"
48 
49 // ------------------------------------------------------------------------------------------------
50 /* Uncomment this line to prevent Assimp from catching unknown exceptions.
51  *
52  * Note that any Exception except DeadlyImportError may lead to
53  * undefined behaviour -> loaders could remain in an unusable state and
54  * further imports with the same Importer instance could fail/crash/burn ...
55  */
56 // ------------------------------------------------------------------------------------------------
57 #ifndef ASSIMP_BUILD_DEBUG
58 #	define ASSIMP_CATCH_GLOBAL_EXCEPTIONS
59 #endif
60 
61 // ------------------------------------------------------------------------------------------------
62 // Internal headers
63 // ------------------------------------------------------------------------------------------------
64 #include "Importer.h"
65 #include "BaseProcess.h"
66 
67 #include "DefaultIOStream.h"
68 #include "DefaultIOSystem.h"
69 #include "DefaultProgressHandler.h"
70 #include "GenericProperty.h"
71 #include "ProcessHelper.h"
72 #include "ScenePreprocessor.h"
73 #include "MemoryIOWrapper.h"
74 #include "Profiler.h"
75 #include "TinyFormatter.h"
76 
77 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
78 #	include "ValidateDataStructure.h"
79 #endif
80 
81 using namespace Assimp::Profiling;
82 using namespace Assimp::Formatter;
83 
84 namespace Assimp {
85 	// ImporterRegistry.cpp
86 	void GetImporterInstanceList(std::vector< BaseImporter* >& out);
87 	// PostStepRegistry.cpp
88 	void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
89 }
90 
91 using namespace Assimp;
92 using namespace Assimp::Intern;
93 
94 // ------------------------------------------------------------------------------------------------
95 // Intern::AllocateFromAssimpHeap serves as abstract base class. It overrides
96 // new and delete (and their array counterparts) of public API classes (e.g. Logger) to
97 // utilize our DLL heap.
98 // See http://www.gotw.ca/publications/mill15.htm
99 // ------------------------------------------------------------------------------------------------
operator new(size_t num_bytes)100 void* AllocateFromAssimpHeap::operator new ( size_t num_bytes)	{
101 	return ::operator new(num_bytes);
102 }
103 
operator new(size_t num_bytes,const std::nothrow_t &)104 void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothrow_t& ) throw()	{
105 	try	{
106 		return AllocateFromAssimpHeap::operator new( num_bytes );
107 	}
108 	catch( ... )	{
109 		return NULL;
110 	}
111 }
112 
operator delete(void * data)113 void AllocateFromAssimpHeap::operator delete ( void* data)	{
114 	return ::operator delete(data);
115 }
116 
operator new[](size_t num_bytes)117 void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes)	{
118 	return ::operator new[](num_bytes);
119 }
120 
operator new[](size_t num_bytes,const std::nothrow_t &)121 void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() {
122 	try	{
123 		return AllocateFromAssimpHeap::operator new[]( num_bytes );
124 	}
125 	catch( ... )	{
126 		return NULL;
127 	}
128 }
129 
operator delete[](void * data)130 void AllocateFromAssimpHeap::operator delete[] ( void* data)	{
131 	return ::operator delete[](data);
132 }
133 
134 // ------------------------------------------------------------------------------------------------
135 // Importer constructor.
Importer()136 Importer::Importer()
137 {
138 	// allocate the pimpl first
139 	pimpl = new ImporterPimpl();
140 
141 	pimpl->mScene = NULL;
142 	pimpl->mErrorString = "";
143 
144 	// Allocate a default IO handler
145 	pimpl->mIOHandler = new DefaultIOSystem;
146 	pimpl->mIsDefaultHandler = true;
147 	pimpl->bExtraVerbose     = false; // disable extra verbose mode by default
148 
149 	pimpl->mProgressHandler = new DefaultProgressHandler();
150 	pimpl->mIsDefaultProgressHandler = true;
151 
152 	GetImporterInstanceList(pimpl->mImporter);
153 	GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps);
154 
155 	// Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list.
156 	pimpl->mPPShared = new SharedPostProcessInfo();
157 	for (std::vector<BaseProcess*>::iterator it =  pimpl->mPostProcessingSteps.begin();
158 		it != pimpl->mPostProcessingSteps.end();
159 		++it)	{
160 
161 		(*it)->SetSharedData(pimpl->mPPShared);
162 	}
163 }
164 
165 // ------------------------------------------------------------------------------------------------
166 // Destructor of Importer
~Importer()167 Importer::~Importer()
168 {
169 	// Delete all import plugins
170 	for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)
171 		delete pimpl->mImporter[a];
172 
173 	// Delete all post-processing plug-ins
174 	for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)
175 		delete pimpl->mPostProcessingSteps[a];
176 
177 	// Delete the assigned IO and progress handler
178 	delete pimpl->mIOHandler;
179 	delete pimpl->mProgressHandler;
180 
181 	// Kill imported scene. Destructors should do that recursivly
182 	delete pimpl->mScene;
183 
184 	// Delete shared post-processing data
185 	delete pimpl->mPPShared;
186 
187 	// and finally the pimpl itself
188 	delete pimpl;
189 }
190 
191 // ------------------------------------------------------------------------------------------------
192 // Copy constructor - copies the config of another Importer, not the scene
Importer(const Importer & other)193 Importer::Importer(const Importer &other)
194 {
195 	new(this) Importer();
196 
197 	pimpl->mIntProperties    = other.pimpl->mIntProperties;
198 	pimpl->mFloatProperties  = other.pimpl->mFloatProperties;
199 	pimpl->mStringProperties = other.pimpl->mStringProperties;
200 }
201 
202 // ------------------------------------------------------------------------------------------------
203 // Register a custom post-processing step
RegisterPPStep(BaseProcess * pImp)204 aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
205 {
206 	ai_assert(NULL != pImp);
207 	ASSIMP_BEGIN_EXCEPTION_REGION();
208 
209 		pimpl->mPostProcessingSteps.push_back(pImp);
210 		DefaultLogger::get()->info("Registering custom post-processing step");
211 
212 	ASSIMP_END_EXCEPTION_REGION(aiReturn);
213 	return AI_SUCCESS;
214 }
215 
216 // ------------------------------------------------------------------------------------------------
217 // Register a custom loader plugin
RegisterLoader(BaseImporter * pImp)218 aiReturn Importer::RegisterLoader(BaseImporter* pImp)
219 {
220 	ai_assert(NULL != pImp);
221 	ASSIMP_BEGIN_EXCEPTION_REGION();
222 
223 	// --------------------------------------------------------------------
224 	// Check whether we would have two loaders for the same file extension
225 	// This is absolutely OK, but we should warn the developer of the new
226 	// loader that his code will probably never be called if the first
227 	// loader is a bit too lazy in his file checking.
228 	// --------------------------------------------------------------------
229 	std::set<std::string> st;
230 	std::string baked;
231 	pImp->GetExtensionList(st);
232 
233 	for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
234 
235 #ifdef _DEBUG
236 		if (IsExtensionSupported(*it)) {
237 			DefaultLogger::get()->warn("The file extension " + *it + " is already in use");
238 		}
239 #endif
240 		baked += *it;
241 	}
242 
243 	// add the loader
244 	pimpl->mImporter.push_back(pImp);
245 	DefaultLogger::get()->info("Registering custom importer for these file extensions: " + baked);
246 	ASSIMP_END_EXCEPTION_REGION(aiReturn);
247 	return AI_SUCCESS;
248 }
249 
250 // ------------------------------------------------------------------------------------------------
251 // Unregister a custom loader plugin
UnregisterLoader(BaseImporter * pImp)252 aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
253 {
254 	if(!pImp) {
255 		// unregistering a NULL importer is no problem for us ... really!
256 		return AI_SUCCESS;
257 	}
258 
259 	ASSIMP_BEGIN_EXCEPTION_REGION();
260 	std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),
261 		pimpl->mImporter.end(),pImp);
262 
263 	if (it != pimpl->mImporter.end())	{
264 		pimpl->mImporter.erase(it);
265 
266 		std::set<std::string> st;
267 		pImp->GetExtensionList(st);
268 
269 		DefaultLogger::get()->info("Unregistering custom importer: ");
270 		return AI_SUCCESS;
271 	}
272 	DefaultLogger::get()->warn("Unable to remove custom importer: I can't find you ...");
273 	ASSIMP_END_EXCEPTION_REGION(aiReturn);
274 	return AI_FAILURE;
275 }
276 
277 // ------------------------------------------------------------------------------------------------
278 // Unregister a custom loader plugin
UnregisterPPStep(BaseProcess * pImp)279 aiReturn Importer::UnregisterPPStep(BaseProcess* pImp)
280 {
281 	if(!pImp) {
282 		// unregistering a NULL ppstep is no problem for us ... really!
283 		return AI_SUCCESS;
284 	}
285 
286 	ASSIMP_BEGIN_EXCEPTION_REGION();
287 	std::vector<BaseProcess*>::iterator it = std::find(pimpl->mPostProcessingSteps.begin(),
288 		pimpl->mPostProcessingSteps.end(),pImp);
289 
290 	if (it != pimpl->mPostProcessingSteps.end())	{
291 		pimpl->mPostProcessingSteps.erase(it);
292 		DefaultLogger::get()->info("Unregistering custom post-processing step");
293 		return AI_SUCCESS;
294 	}
295 	DefaultLogger::get()->warn("Unable to remove custom post-processing step: I can't find you ..");
296 	ASSIMP_END_EXCEPTION_REGION(aiReturn);
297 	return AI_FAILURE;
298 }
299 
300 // ------------------------------------------------------------------------------------------------
301 // Supplies a custom IO handler to the importer to open and access files.
SetIOHandler(IOSystem * pIOHandler)302 void Importer::SetIOHandler( IOSystem* pIOHandler)
303 {
304 	ASSIMP_BEGIN_EXCEPTION_REGION();
305 	// If the new handler is zero, allocate a default IO implementation.
306 	if (!pIOHandler)
307 	{
308 		// Release pointer in the possession of the caller
309 		pimpl->mIOHandler = new DefaultIOSystem();
310 		pimpl->mIsDefaultHandler = true;
311 	}
312 	// Otherwise register the custom handler
313 	else if (pimpl->mIOHandler != pIOHandler)
314 	{
315 		delete pimpl->mIOHandler;
316 		pimpl->mIOHandler = pIOHandler;
317 		pimpl->mIsDefaultHandler = false;
318 	}
319 	ASSIMP_END_EXCEPTION_REGION(void);
320 }
321 
322 // ------------------------------------------------------------------------------------------------
323 // Get the currently set IO handler
GetIOHandler() const324 IOSystem* Importer::GetIOHandler() const
325 {
326 	return pimpl->mIOHandler;
327 }
328 
329 // ------------------------------------------------------------------------------------------------
330 // Check whether a custom IO handler is currently set
IsDefaultIOHandler() const331 bool Importer::IsDefaultIOHandler() const
332 {
333 	return pimpl->mIsDefaultHandler;
334 }
335 
336 // ------------------------------------------------------------------------------------------------
337 // Supplies a custom progress handler to get regular callbacks during importing
SetProgressHandler(ProgressHandler * pHandler)338 void Importer::SetProgressHandler ( ProgressHandler* pHandler )
339 {
340 	ASSIMP_BEGIN_EXCEPTION_REGION();
341 	// If the new handler is zero, allocate a default implementation.
342 	if (!pHandler)
343 	{
344 		// Release pointer in the possession of the caller
345 		pimpl->mProgressHandler = new DefaultProgressHandler();
346 		pimpl->mIsDefaultProgressHandler = true;
347 	}
348 	// Otherwise register the custom handler
349 	else if (pimpl->mProgressHandler != pHandler)
350 	{
351 		delete pimpl->mProgressHandler;
352 		pimpl->mProgressHandler = pHandler;
353 		pimpl->mIsDefaultProgressHandler = false;
354 	}
355 	ASSIMP_END_EXCEPTION_REGION(void);
356 }
357 
358 // ------------------------------------------------------------------------------------------------
359 // Get the currently set progress handler
GetProgressHandler() const360 ProgressHandler* Importer::GetProgressHandler() const
361 {
362 	return pimpl->mProgressHandler;
363 }
364 
365 // ------------------------------------------------------------------------------------------------
366 // Check whether a custom progress handler is currently set
IsDefaultProgressHandler() const367 bool Importer::IsDefaultProgressHandler() const
368 {
369 	return pimpl->mIsDefaultProgressHandler;
370 }
371 
372 // ------------------------------------------------------------------------------------------------
373 // Validate post process step flags
_ValidateFlags(unsigned int pFlags)374 bool _ValidateFlags(unsigned int pFlags)
375 {
376 	if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals)	{
377 		DefaultLogger::get()->error("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
378 		return false;
379 	}
380 	if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices)	{
381 		DefaultLogger::get()->error("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible");
382 		return false;
383 	}
384 	return true;
385 }
386 
387 // ------------------------------------------------------------------------------------------------
388 // Free the current scene
FreeScene()389 void Importer::FreeScene( )
390 {
391 	ASSIMP_BEGIN_EXCEPTION_REGION();
392 	delete pimpl->mScene;
393 	pimpl->mScene = NULL;
394 
395 	pimpl->mErrorString = "";
396 	ASSIMP_END_EXCEPTION_REGION(void);
397 }
398 
399 // ------------------------------------------------------------------------------------------------
400 // Get the current error string, if any
GetErrorString() const401 const char* Importer::GetErrorString() const
402 {
403 	 /* Must remain valid as long as ReadFile() or FreeFile() are not called */
404 	return pimpl->mErrorString.c_str();
405 }
406 
407 // ------------------------------------------------------------------------------------------------
408 // Enable extra-verbose mode
SetExtraVerbose(bool bDo)409 void Importer::SetExtraVerbose(bool bDo)
410 {
411 	pimpl->bExtraVerbose = bDo;
412 }
413 
414 // ------------------------------------------------------------------------------------------------
415 // Get the current scene
GetScene() const416 const aiScene* Importer::GetScene() const
417 {
418 	return pimpl->mScene;
419 }
420 
421 // ------------------------------------------------------------------------------------------------
422 // Orphan the current scene and return it.
GetOrphanedScene()423 aiScene* Importer::GetOrphanedScene()
424 {
425 	aiScene* s = pimpl->mScene;
426 
427 	ASSIMP_BEGIN_EXCEPTION_REGION();
428 	pimpl->mScene = NULL;
429 
430 	pimpl->mErrorString = ""; /* reset error string */
431 	ASSIMP_END_EXCEPTION_REGION(aiScene*);
432 	return s;
433 }
434 
435 // ------------------------------------------------------------------------------------------------
436 // Validate post-processing flags
ValidateFlags(unsigned int pFlags) const437 bool Importer::ValidateFlags(unsigned int pFlags) const
438 {
439 	ASSIMP_BEGIN_EXCEPTION_REGION();
440 	// run basic checks for mutually exclusive flags
441 	if(!_ValidateFlags(pFlags)) {
442 		return false;
443 	}
444 
445 	// ValidateDS does not anymore occur in the pp list, it plays an awesome extra role ...
446 #ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
447 	if (pFlags & aiProcess_ValidateDataStructure) {
448 		return false;
449 	}
450 #endif
451 	pFlags &= ~aiProcess_ValidateDataStructure;
452 
453 	// Now iterate through all bits which are set in the flags and check whether we find at least
454 	// one pp plugin which handles it.
455 	for (unsigned int mask = 1; mask < (1u << (sizeof(unsigned int)*8-1));mask <<= 1) {
456 
457 		if (pFlags & mask) {
458 
459 			bool have = false;
460 			for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)	{
461 				if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) {
462 
463 					have = true;
464 					break;
465 				}
466 			}
467 			if (!have) {
468 				return false;
469 			}
470 		}
471 	}
472 	ASSIMP_END_EXCEPTION_REGION(bool);
473 	return true;
474 }
475 
476 // ------------------------------------------------------------------------------------------------
ReadFileFromMemory(const void * pBuffer,size_t pLength,unsigned int pFlags,const char * pHint)477 const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
478 	size_t pLength,
479 	unsigned int pFlags,
480 	const char* pHint /*= ""*/)
481 {
482 	ASSIMP_BEGIN_EXCEPTION_REGION();
483 	if (!pHint) {
484 		pHint = "";
485 	}
486 
487 	if (!pBuffer || !pLength || strlen(pHint) > 100) {
488 		pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
489 		return NULL;
490 	}
491 
492 	// prevent deletion of the previous IOHandler
493 	IOSystem* io = pimpl->mIOHandler;
494 	pimpl->mIOHandler = NULL;
495 
496 	SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength));
497 
498 	// read the file and recover the previous IOSystem
499 	char fbuff[128];
500 	sprintf(fbuff,"%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
501 
502 	ReadFile(fbuff,pFlags);
503 	SetIOHandler(io);
504 
505 	ASSIMP_END_EXCEPTION_REGION(const aiScene*);
506 	return pimpl->mScene;
507 }
508 
509 // ------------------------------------------------------------------------------------------------
WriteLogOpening(const std::string & file)510 void WriteLogOpening(const std::string& file)
511 {
512 	Logger* l = DefaultLogger::get();
513 	if (!l) {
514 		return;
515 	}
516 	l->info("Load " + file);
517 
518 	// print a full version dump. This is nice because we don't
519 	// need to ask the authors of incoming bug reports for
520 	// the library version they're using - a log dump is
521 	// sufficient.
522 	const unsigned int flags = aiGetCompileFlags();
523 	l->debug(format()
524 		<< "Assimp "
525 		<< aiGetVersionMajor()
526 		<< "."
527 		<< aiGetVersionMinor()
528 		<< "."
529 		<< aiGetVersionRevision()
530 
531 		<< " "
532 #if defined(ASSIMP_BUILD_ARCHITECTURE)
533 		<< ASSIMP_BUILD_ARCHITECTURE
534 #elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__)
535 		<< "x86"
536 #elif defined(_M_X64) || defined(__x86_64__)
537 		<< "amd64"
538 #elif defined(_M_IA64) || defined(__ia64__)
539 		<< "itanium"
540 #elif defined(__ppc__) || defined(__powerpc__)
541 		<< "ppc32"
542 #elif defined(__powerpc64__)
543 		<< "ppc64"
544 #elif defined(__arm__)
545 		<< "arm"
546 #else
547 	<< "<unknown architecture>"
548 #endif
549 
550 		<< " "
551 #if defined(ASSIMP_BUILD_COMPILER)
552 		<< ASSIMP_BUILD_COMPILER
553 #elif defined(_MSC_VER)
554 		<< "msvc"
555 #elif defined(__GNUC__)
556 		<< "gcc"
557 #else
558 		<< "<unknown compiler>"
559 #endif
560 
561 #ifndef NDEBUG
562 		<< " debug"
563 #endif
564 
565 		<< (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "")
566 		<< (flags & ASSIMP_CFLAGS_SHARED  ? " shared" : "")
567 		<< (flags & ASSIMP_CFLAGS_SINGLETHREADED  ? " singlethreaded" : "")
568 		);
569 }
570 
571 // ------------------------------------------------------------------------------------------------
572 // Reads the given file and returns its contents if successful.
ReadFile(const char * _pFile,unsigned int pFlags)573 const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
574 {
575 	ASSIMP_BEGIN_EXCEPTION_REGION();
576 	const std::string pFile(_pFile);
577 
578 	// ----------------------------------------------------------------------
579 	// Put a large try block around everything to catch all std::exception's
580 	// that might be thrown by STL containers or by new().
581 	// ImportErrorException's are throw by ourselves and caught elsewhere.
582 	//-----------------------------------------------------------------------
583 
584 	WriteLogOpening(pFile);
585 
586 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
587 	try
588 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
589 	{
590 		// Check whether this Importer instance has already loaded
591 		// a scene. In this case we need to delete the old one
592 		if (pimpl->mScene)	{
593 
594 			DefaultLogger::get()->debug("(Deleting previous scene)");
595 			FreeScene();
596 		}
597 
598 		// First check if the file is accessable at all
599 		if( !pimpl->mIOHandler->Exists( pFile))	{
600 
601 			pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
602 			DefaultLogger::get()->error(pimpl->mErrorString);
603 			return NULL;
604 		}
605 
606 		boost::scoped_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
607 		if (profiler) {
608 			profiler->BeginRegion("total");
609 		}
610 
611 		// Find an worker class which can handle the file
612 		BaseImporter* imp = NULL;
613 		for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)	{
614 
615 			if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
616 				imp = pimpl->mImporter[a];
617 				break;
618 			}
619 		}
620 
621 		if (!imp)	{
622 			// not so bad yet ... try format auto detection.
623 			const std::string::size_type s = pFile.find_last_of('.');
624 			if (s != std::string::npos) {
625 				DefaultLogger::get()->info("File extension not known, trying signature-based detection");
626 				for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)	{
627 
628 					if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
629 						imp = pimpl->mImporter[a];
630 						break;
631 					}
632 				}
633 			}
634 			// Put a proper error message if no suitable importer was found
635 			if( !imp)	{
636 				pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
637 				DefaultLogger::get()->error(pimpl->mErrorString);
638 				return NULL;
639 			}
640 		}
641 
642 		// Dispatch the reading to the worker class for this format
643 		DefaultLogger::get()->info("Found a matching importer for this file format");
644 		pimpl->mProgressHandler->Update();
645 
646 		if (profiler) {
647 			profiler->BeginRegion("import");
648 		}
649 
650 		pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
651 		pimpl->mProgressHandler->Update();
652 
653 		if (profiler) {
654 			profiler->EndRegion("import");
655 		}
656 
657 		// If successful, apply all active post processing steps to the imported data
658 		if( pimpl->mScene)	{
659 
660 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
661 			// The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
662 			if (pFlags & aiProcess_ValidateDataStructure)
663 			{
664 				ValidateDSProcess ds;
665 				ds.ExecuteOnScene (this);
666 				if (!pimpl->mScene) {
667 					return NULL;
668 				}
669 			}
670 #endif // no validation
671 
672 			// Preprocess the scene and prepare it for post-processing
673 			if (profiler) {
674 				profiler->BeginRegion("preprocess");
675 			}
676 
677 			ScenePreprocessor pre(pimpl->mScene);
678 			pre.ProcessScene();
679 
680 			pimpl->mProgressHandler->Update();
681 			if (profiler) {
682 				profiler->EndRegion("preprocess");
683 			}
684 
685 			// Ensure that the validation process won't be called twice
686 			ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure));
687 		}
688 		// if failed, extract the error string
689 		else if( !pimpl->mScene) {
690 			pimpl->mErrorString = imp->GetErrorText();
691 		}
692 
693 		// clear any data allocated by post-process steps
694 		pimpl->mPPShared->Clean();
695 
696 		if (profiler) {
697 			profiler->EndRegion("total");
698 		}
699 	}
700 #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
701 	catch (std::exception &e)
702 	{
703 #if (defined _MSC_VER) &&	(defined _CPPRTTI)
704 		// if we have RTTI get the full name of the exception that occured
705 		pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
706 #else
707 		pimpl->mErrorString = std::string("std::exception: ") + e.what();
708 #endif
709 
710 		DefaultLogger::get()->error(pimpl->mErrorString);
711 		delete pimpl->mScene; pimpl->mScene = NULL;
712 	}
713 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
714 
715 	// either successful or failure - the pointer expresses it anyways
716 	ASSIMP_END_EXCEPTION_REGION(const aiScene*);
717 	return pimpl->mScene;
718 }
719 
720 
721 // ------------------------------------------------------------------------------------------------
722 // Apply post-processing to the currently bound scene
ApplyPostProcessing(unsigned int pFlags)723 const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
724 {
725 	ASSIMP_BEGIN_EXCEPTION_REGION();
726 	// Return immediately if no scene is active
727 	if (!pimpl->mScene) {
728 		return NULL;
729 	}
730 
731 	// If no flags are given, return the current scene with no further action
732 	if (!pFlags) {
733 		return pimpl->mScene;
734 	}
735 
736 	// In debug builds: run basic flag validation
737 	ai_assert(_ValidateFlags(pFlags));
738 	DefaultLogger::get()->info("Entering post processing pipeline");
739 
740 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
741 	// The ValidateDS process plays an exceptional role. It isn't contained in the global
742 	// list of post-processing steps, so we need to call it manually.
743 	if (pFlags & aiProcess_ValidateDataStructure)
744 	{
745 		ValidateDSProcess ds;
746 		ds.ExecuteOnScene (this);
747 		if (!pimpl->mScene) {
748 			return NULL;
749 		}
750 	}
751 #endif // no validation
752 #ifdef _DEBUG
753 	if (pimpl->bExtraVerbose)
754 	{
755 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
756 		DefaultLogger::get()->error("Verbose Import is not available due to build settings");
757 #endif  // no validation
758 		pFlags |= aiProcess_ValidateDataStructure;
759 	}
760 #else
761 	if (pimpl->bExtraVerbose) {
762 		DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting");
763 	}
764 #endif // ! DEBUG
765 
766 	boost::scoped_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
767 	for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)	{
768 
769 		BaseProcess* process = pimpl->mPostProcessingSteps[a];
770 		if( process->IsActive( pFlags))	{
771 
772 			if (profiler) {
773 				profiler->BeginRegion("postprocess");
774 			}
775 
776 			process->ExecuteOnScene	( this );
777 			pimpl->mProgressHandler->Update();
778 
779 			if (profiler) {
780 				profiler->EndRegion("postprocess");
781 			}
782 		}
783 		if( !pimpl->mScene) {
784 			break;
785 		}
786 #ifdef _DEBUG
787 
788 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
789 		continue;
790 #endif  // no validation
791 
792 		// If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
793 		if (pimpl->bExtraVerbose)	{
794 			DefaultLogger::get()->debug("Verbose Import: revalidating data structures");
795 
796 			ValidateDSProcess ds;
797 			ds.ExecuteOnScene (this);
798 			if( !pimpl->mScene)	{
799 				DefaultLogger::get()->error("Verbose Import: failed to revalidate data structures");
800 				break;
801 			}
802 		}
803 #endif // ! DEBUG
804 	}
805 
806 	// update private scene flags
807 	ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
808 
809 	// clear any data allocated by post-process steps
810 	pimpl->mPPShared->Clean();
811 	DefaultLogger::get()->info("Leaving post processing pipeline");
812 
813 	ASSIMP_END_EXCEPTION_REGION(const aiScene*);
814 	return pimpl->mScene;
815 }
816 
817 // ------------------------------------------------------------------------------------------------
818 // Helper function to check whether an extension is supported by ASSIMP
IsExtensionSupported(const char * szExtension) const819 bool Importer::IsExtensionSupported(const char* szExtension) const
820 {
821 	return NULL != FindLoader(szExtension);
822 }
823 
824 // ------------------------------------------------------------------------------------------------
825 // Find a loader plugin for a given file extension
FindLoader(const char * szExtension) const826 BaseImporter* Importer::FindLoader (const char* szExtension) const
827 {
828 	ai_assert(szExtension);
829 	ASSIMP_BEGIN_EXCEPTION_REGION();
830 
831 	// skip over wildcard and dot characters at string head --
832 	for(;*szExtension == '*' || *szExtension == '.'; ++szExtension);
833 
834 	std::string ext(szExtension);
835 	if (ext.empty()) {
836 		return NULL;
837 	}
838 	std::transform(ext.begin(),ext.end(), ext.begin(), tolower);
839 
840 	std::set<std::string> str;
841 	for (std::vector<BaseImporter*>::const_iterator i =  pimpl->mImporter.begin();i != pimpl->mImporter.end();++i)	{
842 		str.clear();
843 
844 		(*i)->GetExtensionList(str);
845 		for (std::set<std::string>::const_iterator it = str.begin(); it != str.end(); ++it) {
846 			if (ext == *it) {
847 				return (*i);
848 			}
849 		}
850 	}
851 	ASSIMP_END_EXCEPTION_REGION(BaseImporter*);
852 	return NULL;
853 }
854 
855 // ------------------------------------------------------------------------------------------------
856 // Helper function to build a list of all file extensions supported by ASSIMP
GetExtensionList(aiString & szOut) const857 void Importer::GetExtensionList(aiString& szOut) const
858 {
859 	ASSIMP_BEGIN_EXCEPTION_REGION();
860 	std::set<std::string> str;
861 	for (std::vector<BaseImporter*>::const_iterator i =  pimpl->mImporter.begin();i != pimpl->mImporter.end();++i)	{
862 		(*i)->GetExtensionList(str);
863 	}
864 
865 	for (std::set<std::string>::const_iterator it = str.begin();; ) {
866 		szOut.Append("*.");
867 		szOut.Append((*it).c_str());
868 
869 		if (++it == str.end()) {
870 			break;
871 		}
872 		szOut.Append(";");
873 	}
874 	ASSIMP_END_EXCEPTION_REGION(void);
875 }
876 
877 // ------------------------------------------------------------------------------------------------
878 // Set a configuration property
SetPropertyInteger(const char * szName,int iValue,bool * bWasExisting)879 void Importer::SetPropertyInteger(const char* szName, int iValue,
880 	bool* bWasExisting /*= NULL*/)
881 {
882 	ASSIMP_BEGIN_EXCEPTION_REGION();
883 		SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue,bWasExisting);
884 	ASSIMP_END_EXCEPTION_REGION(void);
885 }
886 
887 // ------------------------------------------------------------------------------------------------
888 // Set a configuration property
SetPropertyFloat(const char * szName,float iValue,bool * bWasExisting)889 void Importer::SetPropertyFloat(const char* szName, float iValue,
890 	bool* bWasExisting /*= NULL*/)
891 {
892 	ASSIMP_BEGIN_EXCEPTION_REGION();
893 		SetGenericProperty<float>(pimpl->mFloatProperties, szName,iValue,bWasExisting);
894 	ASSIMP_END_EXCEPTION_REGION(void);
895 }
896 
897 // ------------------------------------------------------------------------------------------------
898 // Set a configuration property
SetPropertyString(const char * szName,const std::string & value,bool * bWasExisting)899 void Importer::SetPropertyString(const char* szName, const std::string& value,
900 	bool* bWasExisting /*= NULL*/)
901 {
902 	ASSIMP_BEGIN_EXCEPTION_REGION();
903 		SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value,bWasExisting);
904 	ASSIMP_END_EXCEPTION_REGION(void);
905 }
906 
907 // ------------------------------------------------------------------------------------------------
908 // Get a configuration property
GetPropertyInteger(const char * szName,int iErrorReturn) const909 int Importer::GetPropertyInteger(const char* szName,
910 	int iErrorReturn /*= 0xffffffff*/) const
911 {
912 	return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
913 }
914 
915 // ------------------------------------------------------------------------------------------------
916 // Get a configuration property
GetPropertyFloat(const char * szName,float iErrorReturn) const917 float Importer::GetPropertyFloat(const char* szName,
918 	float iErrorReturn /*= 10e10*/) const
919 {
920 	return GetGenericProperty<float>(pimpl->mFloatProperties,szName,iErrorReturn);
921 }
922 
923 // ------------------------------------------------------------------------------------------------
924 // Get a configuration property
GetPropertyString(const char * szName,const std::string & iErrorReturn) const925 const std::string& Importer::GetPropertyString(const char* szName,
926 	const std::string& iErrorReturn /*= ""*/) const
927 {
928 	return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
929 }
930 
931 // ------------------------------------------------------------------------------------------------
932 // Get the memory requirements of a single node
AddNodeWeight(unsigned int & iScene,const aiNode * pcNode)933 inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
934 {
935 	iScene += sizeof(aiNode);
936 	iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
937 	iScene += sizeof(void*) * pcNode->mNumChildren;
938 
939 	for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
940 		AddNodeWeight(iScene,pcNode->mChildren[i]);
941 	}
942 }
943 
944 // ------------------------------------------------------------------------------------------------
945 // Get the memory requirements of the scene
GetMemoryRequirements(aiMemoryInfo & in) const946 void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
947 {
948 	in = aiMemoryInfo();
949 	aiScene* mScene = pimpl->mScene;
950 
951 	// return if we have no scene loaded
952 	if (!pimpl->mScene)
953 		return;
954 
955 
956 	in.total = sizeof(aiScene);
957 
958 	// add all meshes
959 	for (unsigned int i = 0; i < mScene->mNumMeshes;++i)
960 	{
961 		in.meshes += sizeof(aiMesh);
962 		if (mScene->mMeshes[i]->HasPositions()) {
963 			in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
964 		}
965 
966 		if (mScene->mMeshes[i]->HasNormals()) {
967 			in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
968 		}
969 
970 		if (mScene->mMeshes[i]->HasTangentsAndBitangents()) {
971 			in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices * 2;
972 		}
973 
974 		for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) {
975 			if (mScene->mMeshes[i]->HasVertexColors(a)) {
976 				in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
977 			}
978 			else break;
979 		}
980 		for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
981 			if (mScene->mMeshes[i]->HasTextureCoords(a)) {
982 				in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
983 			}
984 			else break;
985 		}
986 		if (mScene->mMeshes[i]->HasBones()) {
987 			in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
988 			for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones;++p) {
989 				in.meshes += sizeof(aiBone);
990 				in.meshes += mScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight);
991 			}
992 		}
993 		in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int))*mScene->mMeshes[i]->mNumFaces;
994 	}
995     in.total += in.meshes;
996 
997 	// add all embedded textures
998 	for (unsigned int i = 0; i < mScene->mNumTextures;++i) {
999 		const aiTexture* pc = mScene->mTextures[i];
1000 		in.textures += sizeof(aiTexture);
1001 		if (pc->mHeight) {
1002 			in.textures += 4 * pc->mHeight * pc->mWidth;
1003 		}
1004 		else in.textures += pc->mWidth;
1005 	}
1006 	in.total += in.textures;
1007 
1008 	// add all animations
1009 	for (unsigned int i = 0; i < mScene->mNumAnimations;++i) {
1010 		const aiAnimation* pc = mScene->mAnimations[i];
1011 		in.animations += sizeof(aiAnimation);
1012 
1013 		// add all bone anims
1014 		for (unsigned int a = 0; a < pc->mNumChannels; ++a) {
1015 			const aiNodeAnim* pc2 = pc->mChannels[i];
1016 			in.animations += sizeof(aiNodeAnim);
1017 			in.animations += pc2->mNumPositionKeys * sizeof(aiVectorKey);
1018 			in.animations += pc2->mNumScalingKeys * sizeof(aiVectorKey);
1019 			in.animations += pc2->mNumRotationKeys * sizeof(aiQuatKey);
1020 		}
1021 	}
1022 	in.total += in.animations;
1023 
1024 	// add all cameras and all lights
1025 	in.total += in.cameras = sizeof(aiCamera) *  mScene->mNumCameras;
1026 	in.total += in.lights  = sizeof(aiLight)  *  mScene->mNumLights;
1027 
1028 	// add all nodes
1029 	AddNodeWeight(in.nodes,mScene->mRootNode);
1030 	in.total += in.nodes;
1031 
1032 	// add all materials
1033 	for (unsigned int i = 0; i < mScene->mNumMaterials;++i) {
1034 		const aiMaterial* pc = mScene->mMaterials[i];
1035 		in.materials += sizeof(aiMaterial);
1036 		in.materials += pc->mNumAllocated * sizeof(void*);
1037 
1038 		for (unsigned int a = 0; a < pc->mNumProperties;++a) {
1039 			in.materials += pc->mProperties[a]->mDataLength;
1040 		}
1041 	}
1042 	in.total += in.materials;
1043 }
1044 
1045