vrshoot
view libs/assimp/Importer.cpp @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
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:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
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.
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.
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 */
42 /** @file Importer.cpp
43 * @brief Implementation of the CPP-API class #Importer
44 */
46 #include "AssimpPCH.h"
47 #include "assimp/version.h"
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
61 // ------------------------------------------------------------------------------------------------
62 // Internal headers
63 // ------------------------------------------------------------------------------------------------
64 #include "Importer.h"
65 #include "BaseProcess.h"
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"
77 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
78 # include "ValidateDataStructure.h"
79 #endif
81 using namespace Assimp::Profiling;
82 using namespace Assimp::Formatter;
84 namespace Assimp {
85 // ImporterRegistry.cpp
86 void GetImporterInstanceList(std::vector< BaseImporter* >& out);
87 // PostStepRegistry.cpp
88 void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
89 }
91 using namespace Assimp;
92 using namespace Assimp::Intern;
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 // ------------------------------------------------------------------------------------------------
100 void* AllocateFromAssimpHeap::operator new ( size_t num_bytes) {
101 return ::operator new(num_bytes);
102 }
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 }
113 void AllocateFromAssimpHeap::operator delete ( void* data) {
114 return ::operator delete(data);
115 }
117 void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) {
118 return ::operator new[](num_bytes);
119 }
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 }
130 void AllocateFromAssimpHeap::operator delete[] ( void* data) {
131 return ::operator delete[](data);
132 }
134 // ------------------------------------------------------------------------------------------------
135 // Importer constructor.
136 Importer::Importer()
137 {
138 // allocate the pimpl first
139 pimpl = new ImporterPimpl();
141 pimpl->mScene = NULL;
142 pimpl->mErrorString = "";
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
149 pimpl->mProgressHandler = new DefaultProgressHandler();
150 pimpl->mIsDefaultProgressHandler = true;
152 GetImporterInstanceList(pimpl->mImporter);
153 GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps);
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) {
161 (*it)->SetSharedData(pimpl->mPPShared);
162 }
163 }
165 // ------------------------------------------------------------------------------------------------
166 // Destructor of 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];
173 // Delete all post-processing plug-ins
174 for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)
175 delete pimpl->mPostProcessingSteps[a];
177 // Delete the assigned IO and progress handler
178 delete pimpl->mIOHandler;
179 delete pimpl->mProgressHandler;
181 // Kill imported scene. Destructors should do that recursivly
182 delete pimpl->mScene;
184 // Delete shared post-processing data
185 delete pimpl->mPPShared;
187 // and finally the pimpl itself
188 delete pimpl;
189 }
191 // ------------------------------------------------------------------------------------------------
192 // Copy constructor - copies the config of another Importer, not the scene
193 Importer::Importer(const Importer &other)
194 {
195 new(this) Importer();
197 pimpl->mIntProperties = other.pimpl->mIntProperties;
198 pimpl->mFloatProperties = other.pimpl->mFloatProperties;
199 pimpl->mStringProperties = other.pimpl->mStringProperties;
200 }
202 // ------------------------------------------------------------------------------------------------
203 // Register a custom post-processing step
204 aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
205 {
206 ai_assert(NULL != pImp);
207 ASSIMP_BEGIN_EXCEPTION_REGION();
209 pimpl->mPostProcessingSteps.push_back(pImp);
210 DefaultLogger::get()->info("Registering custom post-processing step");
212 ASSIMP_END_EXCEPTION_REGION(aiReturn);
213 return AI_SUCCESS;
214 }
216 // ------------------------------------------------------------------------------------------------
217 // Register a custom loader plugin
218 aiReturn Importer::RegisterLoader(BaseImporter* pImp)
219 {
220 ai_assert(NULL != pImp);
221 ASSIMP_BEGIN_EXCEPTION_REGION();
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);
233 for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
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 }
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 }
250 // ------------------------------------------------------------------------------------------------
251 // Unregister a custom loader plugin
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 }
259 ASSIMP_BEGIN_EXCEPTION_REGION();
260 std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(),
261 pimpl->mImporter.end(),pImp);
263 if (it != pimpl->mImporter.end()) {
264 pimpl->mImporter.erase(it);
266 std::set<std::string> st;
267 pImp->GetExtensionList(st);
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 }
277 // ------------------------------------------------------------------------------------------------
278 // Unregister a custom loader plugin
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 }
286 ASSIMP_BEGIN_EXCEPTION_REGION();
287 std::vector<BaseProcess*>::iterator it = std::find(pimpl->mPostProcessingSteps.begin(),
288 pimpl->mPostProcessingSteps.end(),pImp);
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 }
300 // ------------------------------------------------------------------------------------------------
301 // Supplies a custom IO handler to the importer to open and access files.
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 }
322 // ------------------------------------------------------------------------------------------------
323 // Get the currently set IO handler
324 IOSystem* Importer::GetIOHandler() const
325 {
326 return pimpl->mIOHandler;
327 }
329 // ------------------------------------------------------------------------------------------------
330 // Check whether a custom IO handler is currently set
331 bool Importer::IsDefaultIOHandler() const
332 {
333 return pimpl->mIsDefaultHandler;
334 }
336 // ------------------------------------------------------------------------------------------------
337 // Supplies a custom progress handler to get regular callbacks during importing
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 }
358 // ------------------------------------------------------------------------------------------------
359 // Get the currently set progress handler
360 ProgressHandler* Importer::GetProgressHandler() const
361 {
362 return pimpl->mProgressHandler;
363 }
365 // ------------------------------------------------------------------------------------------------
366 // Check whether a custom progress handler is currently set
367 bool Importer::IsDefaultProgressHandler() const
368 {
369 return pimpl->mIsDefaultProgressHandler;
370 }
372 // ------------------------------------------------------------------------------------------------
373 // Validate post process step flags
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 }
387 // ------------------------------------------------------------------------------------------------
388 // Free the current scene
389 void Importer::FreeScene( )
390 {
391 ASSIMP_BEGIN_EXCEPTION_REGION();
392 delete pimpl->mScene;
393 pimpl->mScene = NULL;
395 pimpl->mErrorString = "";
396 ASSIMP_END_EXCEPTION_REGION(void);
397 }
399 // ------------------------------------------------------------------------------------------------
400 // Get the current error string, if any
401 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 }
407 // ------------------------------------------------------------------------------------------------
408 // Enable extra-verbose mode
409 void Importer::SetExtraVerbose(bool bDo)
410 {
411 pimpl->bExtraVerbose = bDo;
412 }
414 // ------------------------------------------------------------------------------------------------
415 // Get the current scene
416 const aiScene* Importer::GetScene() const
417 {
418 return pimpl->mScene;
419 }
421 // ------------------------------------------------------------------------------------------------
422 // Orphan the current scene and return it.
423 aiScene* Importer::GetOrphanedScene()
424 {
425 aiScene* s = pimpl->mScene;
427 ASSIMP_BEGIN_EXCEPTION_REGION();
428 pimpl->mScene = NULL;
430 pimpl->mErrorString = ""; /* reset error string */
431 ASSIMP_END_EXCEPTION_REGION(aiScene*);
432 return s;
433 }
435 // ------------------------------------------------------------------------------------------------
436 // Validate post-processing flags
437 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 }
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;
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) {
457 if (pFlags & mask) {
459 bool have = false;
460 for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
461 if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) {
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 }
476 // ------------------------------------------------------------------------------------------------
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 }
487 if (!pBuffer || !pLength || strlen(pHint) > 100) {
488 pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
489 return NULL;
490 }
492 // prevent deletion of the previous IOHandler
493 IOSystem* io = pimpl->mIOHandler;
494 pimpl->mIOHandler = NULL;
496 SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength));
498 // read the file and recover the previous IOSystem
499 char fbuff[128];
500 sprintf(fbuff,"%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint);
502 ReadFile(fbuff,pFlags);
503 SetIOHandler(io);
505 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
506 return pimpl->mScene;
507 }
509 // ------------------------------------------------------------------------------------------------
510 void WriteLogOpening(const std::string& file)
511 {
512 Logger* l = DefaultLogger::get();
513 if (!l) {
514 return;
515 }
516 l->info("Load " + file);
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()
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
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
561 #ifndef NDEBUG
562 << " debug"
563 #endif
565 << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "")
566 << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "")
567 << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "")
568 );
569 }
571 // ------------------------------------------------------------------------------------------------
572 // Reads the given file and returns its contents if successful.
573 const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
574 {
575 ASSIMP_BEGIN_EXCEPTION_REGION();
576 const std::string pFile(_pFile);
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 //-----------------------------------------------------------------------
584 WriteLogOpening(pFile);
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) {
594 DefaultLogger::get()->debug("(Deleting previous scene)");
595 FreeScene();
596 }
598 // First check if the file is accessable at all
599 if( !pimpl->mIOHandler->Exists( pFile)) {
601 pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
602 DefaultLogger::get()->error(pimpl->mErrorString);
603 return NULL;
604 }
606 boost::scoped_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
607 if (profiler) {
608 profiler->BeginRegion("total");
609 }
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++) {
615 if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) {
616 imp = pimpl->mImporter[a];
617 break;
618 }
619 }
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++) {
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 }
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();
646 if (profiler) {
647 profiler->BeginRegion("import");
648 }
650 pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler);
651 pimpl->mProgressHandler->Update();
653 if (profiler) {
654 profiler->EndRegion("import");
655 }
657 // If successful, apply all active post processing steps to the imported data
658 if( pimpl->mScene) {
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
672 // Preprocess the scene and prepare it for post-processing
673 if (profiler) {
674 profiler->BeginRegion("preprocess");
675 }
677 ScenePreprocessor pre(pimpl->mScene);
678 pre.ProcessScene();
680 pimpl->mProgressHandler->Update();
681 if (profiler) {
682 profiler->EndRegion("preprocess");
683 }
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 }
693 // clear any data allocated by post-process steps
694 pimpl->mPPShared->Clean();
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
710 DefaultLogger::get()->error(pimpl->mErrorString);
711 delete pimpl->mScene; pimpl->mScene = NULL;
712 }
713 #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
715 // either successful or failure - the pointer expresses it anyways
716 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
717 return pimpl->mScene;
718 }
721 // ------------------------------------------------------------------------------------------------
722 // Apply post-processing to the currently bound scene
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 }
731 // If no flags are given, return the current scene with no further action
732 if (!pFlags) {
733 return pimpl->mScene;
734 }
736 // In debug builds: run basic flag validation
737 ai_assert(_ValidateFlags(pFlags));
738 DefaultLogger::get()->info("Entering post processing pipeline");
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
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++) {
769 BaseProcess* process = pimpl->mPostProcessingSteps[a];
770 if( process->IsActive( pFlags)) {
772 if (profiler) {
773 profiler->BeginRegion("postprocess");
774 }
776 process->ExecuteOnScene ( this );
777 pimpl->mProgressHandler->Update();
779 if (profiler) {
780 profiler->EndRegion("postprocess");
781 }
782 }
783 if( !pimpl->mScene) {
784 break;
785 }
786 #ifdef _DEBUG
788 #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
789 continue;
790 #endif // no validation
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");
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 }
806 // update private scene flags
807 if( pimpl->mScene )
808 ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
810 // clear any data allocated by post-process steps
811 pimpl->mPPShared->Clean();
812 DefaultLogger::get()->info("Leaving post processing pipeline");
814 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
815 return pimpl->mScene;
816 }
818 // ------------------------------------------------------------------------------------------------
819 // Helper function to check whether an extension is supported by ASSIMP
820 bool Importer::IsExtensionSupported(const char* szExtension) const
821 {
822 return NULL != GetImporter(szExtension);
823 }
825 // ------------------------------------------------------------------------------------------------
826 size_t Importer::GetImporterCount() const
827 {
828 return pimpl->mImporter.size();
829 }
831 // ------------------------------------------------------------------------------------------------
832 const aiImporterDesc* Importer::GetImporterInfo(size_t index) const
833 {
834 if (index >= pimpl->mImporter.size()) {
835 return NULL;
836 }
837 return pimpl->mImporter[index]->GetInfo();
838 }
841 // ------------------------------------------------------------------------------------------------
842 BaseImporter* Importer::GetImporter (size_t index) const
843 {
844 if (index >= pimpl->mImporter.size()) {
845 return NULL;
846 }
847 return pimpl->mImporter[index];
848 }
850 // ------------------------------------------------------------------------------------------------
851 // Find a loader plugin for a given file extension
852 BaseImporter* Importer::GetImporter (const char* szExtension) const
853 {
854 return GetImporter(GetImporterIndex(szExtension));
855 }
857 // ------------------------------------------------------------------------------------------------
858 // Find a loader plugin for a given file extension
859 size_t Importer::GetImporterIndex (const char* szExtension) const
860 {
861 ai_assert(szExtension);
862 ASSIMP_BEGIN_EXCEPTION_REGION();
864 // skip over wildcard and dot characters at string head --
865 for(;*szExtension == '*' || *szExtension == '.'; ++szExtension);
867 std::string ext(szExtension);
868 if (ext.empty()) {
869 return static_cast<size_t>(-1);
870 }
871 std::transform(ext.begin(),ext.end(), ext.begin(), tolower);
873 std::set<std::string> str;
874 for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) {
875 str.clear();
877 (*i)->GetExtensionList(str);
878 for (std::set<std::string>::const_iterator it = str.begin(); it != str.end(); ++it) {
879 if (ext == *it) {
880 return std::distance(static_cast< std::vector<BaseImporter*>::const_iterator >(pimpl->mImporter.begin()), i);
881 }
882 }
883 }
884 ASSIMP_END_EXCEPTION_REGION(size_t);
885 return static_cast<size_t>(-1);
886 }
888 // ------------------------------------------------------------------------------------------------
889 // Helper function to build a list of all file extensions supported by ASSIMP
890 void Importer::GetExtensionList(aiString& szOut) const
891 {
892 ASSIMP_BEGIN_EXCEPTION_REGION();
893 std::set<std::string> str;
894 for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) {
895 (*i)->GetExtensionList(str);
896 }
898 for (std::set<std::string>::const_iterator it = str.begin();; ) {
899 szOut.Append("*.");
900 szOut.Append((*it).c_str());
902 if (++it == str.end()) {
903 break;
904 }
905 szOut.Append(";");
906 }
907 ASSIMP_END_EXCEPTION_REGION(void);
908 }
910 // ------------------------------------------------------------------------------------------------
911 // Set a configuration property
912 void Importer::SetPropertyInteger(const char* szName, int iValue,
913 bool* bWasExisting /*= NULL*/)
914 {
915 ASSIMP_BEGIN_EXCEPTION_REGION();
916 SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue,bWasExisting);
917 ASSIMP_END_EXCEPTION_REGION(void);
918 }
920 // ------------------------------------------------------------------------------------------------
921 // Set a configuration property
922 void Importer::SetPropertyFloat(const char* szName, float iValue,
923 bool* bWasExisting /*= NULL*/)
924 {
925 ASSIMP_BEGIN_EXCEPTION_REGION();
926 SetGenericProperty<float>(pimpl->mFloatProperties, szName,iValue,bWasExisting);
927 ASSIMP_END_EXCEPTION_REGION(void);
928 }
930 // ------------------------------------------------------------------------------------------------
931 // Set a configuration property
932 void Importer::SetPropertyString(const char* szName, const std::string& value,
933 bool* bWasExisting /*= NULL*/)
934 {
935 ASSIMP_BEGIN_EXCEPTION_REGION();
936 SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value,bWasExisting);
937 ASSIMP_END_EXCEPTION_REGION(void);
938 }
940 // ------------------------------------------------------------------------------------------------
941 // Get a configuration property
942 int Importer::GetPropertyInteger(const char* szName,
943 int iErrorReturn /*= 0xffffffff*/) const
944 {
945 return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
946 }
948 // ------------------------------------------------------------------------------------------------
949 // Get a configuration property
950 float Importer::GetPropertyFloat(const char* szName,
951 float iErrorReturn /*= 10e10*/) const
952 {
953 return GetGenericProperty<float>(pimpl->mFloatProperties,szName,iErrorReturn);
954 }
956 // ------------------------------------------------------------------------------------------------
957 // Get a configuration property
958 const std::string& Importer::GetPropertyString(const char* szName,
959 const std::string& iErrorReturn /*= ""*/) const
960 {
961 return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
962 }
964 // ------------------------------------------------------------------------------------------------
965 // Get the memory requirements of a single node
966 inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
967 {
968 iScene += sizeof(aiNode);
969 iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
970 iScene += sizeof(void*) * pcNode->mNumChildren;
972 for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
973 AddNodeWeight(iScene,pcNode->mChildren[i]);
974 }
975 }
977 // ------------------------------------------------------------------------------------------------
978 // Get the memory requirements of the scene
979 void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
980 {
981 in = aiMemoryInfo();
982 aiScene* mScene = pimpl->mScene;
984 // return if we have no scene loaded
985 if (!pimpl->mScene)
986 return;
989 in.total = sizeof(aiScene);
991 // add all meshes
992 for (unsigned int i = 0; i < mScene->mNumMeshes;++i)
993 {
994 in.meshes += sizeof(aiMesh);
995 if (mScene->mMeshes[i]->HasPositions()) {
996 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
997 }
999 if (mScene->mMeshes[i]->HasNormals()) {
1000 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
1001 }
1003 if (mScene->mMeshes[i]->HasTangentsAndBitangents()) {
1004 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices * 2;
1005 }
1007 for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) {
1008 if (mScene->mMeshes[i]->HasVertexColors(a)) {
1009 in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
1010 }
1011 else break;
1012 }
1013 for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
1014 if (mScene->mMeshes[i]->HasTextureCoords(a)) {
1015 in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
1016 }
1017 else break;
1018 }
1019 if (mScene->mMeshes[i]->HasBones()) {
1020 in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
1021 for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones;++p) {
1022 in.meshes += sizeof(aiBone);
1023 in.meshes += mScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight);
1024 }
1025 }
1026 in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int))*mScene->mMeshes[i]->mNumFaces;
1027 }
1028 in.total += in.meshes;
1030 // add all embedded textures
1031 for (unsigned int i = 0; i < mScene->mNumTextures;++i) {
1032 const aiTexture* pc = mScene->mTextures[i];
1033 in.textures += sizeof(aiTexture);
1034 if (pc->mHeight) {
1035 in.textures += 4 * pc->mHeight * pc->mWidth;
1036 }
1037 else in.textures += pc->mWidth;
1038 }
1039 in.total += in.textures;
1041 // add all animations
1042 for (unsigned int i = 0; i < mScene->mNumAnimations;++i) {
1043 const aiAnimation* pc = mScene->mAnimations[i];
1044 in.animations += sizeof(aiAnimation);
1046 // add all bone anims
1047 for (unsigned int a = 0; a < pc->mNumChannels; ++a) {
1048 const aiNodeAnim* pc2 = pc->mChannels[i];
1049 in.animations += sizeof(aiNodeAnim);
1050 in.animations += pc2->mNumPositionKeys * sizeof(aiVectorKey);
1051 in.animations += pc2->mNumScalingKeys * sizeof(aiVectorKey);
1052 in.animations += pc2->mNumRotationKeys * sizeof(aiQuatKey);
1053 }
1054 }
1055 in.total += in.animations;
1057 // add all cameras and all lights
1058 in.total += in.cameras = sizeof(aiCamera) * mScene->mNumCameras;
1059 in.total += in.lights = sizeof(aiLight) * mScene->mNumLights;
1061 // add all nodes
1062 AddNodeWeight(in.nodes,mScene->mRootNode);
1063 in.total += in.nodes;
1065 // add all materials
1066 for (unsigned int i = 0; i < mScene->mNumMaterials;++i) {
1067 const aiMaterial* pc = mScene->mMaterials[i];
1068 in.materials += sizeof(aiMaterial);
1069 in.materials += pc->mNumAllocated * sizeof(void*);
1071 for (unsigned int a = 0; a < pc->mNumProperties;++a) {
1072 in.materials += pc->mProperties[a]->mDataLength;
1073 }
1074 }
1075 in.total += in.materials;
1076 }