nuclear@0: /* nuclear@0: --------------------------------------------------------------------------- nuclear@0: Open Asset Import Library (assimp) nuclear@0: --------------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the following nuclear@0: conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: --------------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: /** @file Importer.cpp nuclear@0: * @brief Implementation of the CPP-API class #Importer nuclear@0: */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #include "assimp/version.h" nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: /* Uncomment this line to prevent Assimp from catching unknown exceptions. nuclear@0: * nuclear@0: * Note that any Exception except DeadlyImportError may lead to nuclear@0: * undefined behaviour -> loaders could remain in an unusable state and nuclear@0: * further imports with the same Importer instance could fail/crash/burn ... nuclear@0: */ nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: #ifndef ASSIMP_BUILD_DEBUG nuclear@0: # define ASSIMP_CATCH_GLOBAL_EXCEPTIONS nuclear@0: #endif nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Internal headers nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: #include "Importer.h" nuclear@0: #include "BaseProcess.h" nuclear@0: nuclear@0: #include "DefaultIOStream.h" nuclear@0: #include "DefaultIOSystem.h" nuclear@0: #include "DefaultProgressHandler.h" nuclear@0: #include "GenericProperty.h" nuclear@0: #include "ProcessHelper.h" nuclear@0: #include "ScenePreprocessor.h" nuclear@0: #include "MemoryIOWrapper.h" nuclear@0: #include "Profiler.h" nuclear@0: #include "TinyFormatter.h" nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS nuclear@0: # include "ValidateDataStructure.h" nuclear@0: #endif nuclear@0: nuclear@0: using namespace Assimp::Profiling; nuclear@0: using namespace Assimp::Formatter; nuclear@0: nuclear@0: namespace Assimp { nuclear@0: // ImporterRegistry.cpp nuclear@0: void GetImporterInstanceList(std::vector< BaseImporter* >& out); nuclear@0: // PostStepRegistry.cpp nuclear@0: void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out); nuclear@0: } nuclear@0: nuclear@0: using namespace Assimp; nuclear@0: using namespace Assimp::Intern; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Intern::AllocateFromAssimpHeap serves as abstract base class. It overrides nuclear@0: // new and delete (and their array counterparts) of public API classes (e.g. Logger) to nuclear@0: // utilize our DLL heap. nuclear@0: // See http://www.gotw.ca/publications/mill15.htm nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void* AllocateFromAssimpHeap::operator new ( size_t num_bytes) { nuclear@0: return ::operator new(num_bytes); nuclear@0: } nuclear@0: nuclear@0: void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothrow_t& ) throw() { nuclear@0: try { nuclear@0: return AllocateFromAssimpHeap::operator new( num_bytes ); nuclear@0: } nuclear@0: catch( ... ) { nuclear@0: return NULL; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void AllocateFromAssimpHeap::operator delete ( void* data) { nuclear@0: return ::operator delete(data); nuclear@0: } nuclear@0: nuclear@0: void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) { nuclear@0: return ::operator new[](num_bytes); nuclear@0: } nuclear@0: nuclear@0: void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() { nuclear@0: try { nuclear@0: return AllocateFromAssimpHeap::operator new[]( num_bytes ); nuclear@0: } nuclear@0: catch( ... ) { nuclear@0: return NULL; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void AllocateFromAssimpHeap::operator delete[] ( void* data) { nuclear@0: return ::operator delete[](data); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Importer constructor. nuclear@0: Importer::Importer() nuclear@0: { nuclear@0: // allocate the pimpl first nuclear@0: pimpl = new ImporterPimpl(); nuclear@0: nuclear@0: pimpl->mScene = NULL; nuclear@0: pimpl->mErrorString = ""; nuclear@0: nuclear@0: // Allocate a default IO handler nuclear@0: pimpl->mIOHandler = new DefaultIOSystem; nuclear@0: pimpl->mIsDefaultHandler = true; nuclear@0: pimpl->bExtraVerbose = false; // disable extra verbose mode by default nuclear@0: nuclear@0: pimpl->mProgressHandler = new DefaultProgressHandler(); nuclear@0: pimpl->mIsDefaultProgressHandler = true; nuclear@0: nuclear@0: GetImporterInstanceList(pimpl->mImporter); nuclear@0: GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps); nuclear@0: nuclear@0: // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list. nuclear@0: pimpl->mPPShared = new SharedPostProcessInfo(); nuclear@0: for (std::vector::iterator it = pimpl->mPostProcessingSteps.begin(); nuclear@0: it != pimpl->mPostProcessingSteps.end(); nuclear@0: ++it) { nuclear@0: nuclear@0: (*it)->SetSharedData(pimpl->mPPShared); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Destructor of Importer nuclear@0: Importer::~Importer() nuclear@0: { nuclear@0: // Delete all import plugins nuclear@0: for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) nuclear@0: delete pimpl->mImporter[a]; nuclear@0: nuclear@0: // Delete all post-processing plug-ins nuclear@0: for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) nuclear@0: delete pimpl->mPostProcessingSteps[a]; nuclear@0: nuclear@0: // Delete the assigned IO and progress handler nuclear@0: delete pimpl->mIOHandler; nuclear@0: delete pimpl->mProgressHandler; nuclear@0: nuclear@0: // Kill imported scene. Destructors should do that recursivly nuclear@0: delete pimpl->mScene; nuclear@0: nuclear@0: // Delete shared post-processing data nuclear@0: delete pimpl->mPPShared; nuclear@0: nuclear@0: // and finally the pimpl itself nuclear@0: delete pimpl; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Copy constructor - copies the config of another Importer, not the scene nuclear@0: Importer::Importer(const Importer &other) nuclear@0: { nuclear@0: new(this) Importer(); nuclear@0: nuclear@0: pimpl->mIntProperties = other.pimpl->mIntProperties; nuclear@0: pimpl->mFloatProperties = other.pimpl->mFloatProperties; nuclear@0: pimpl->mStringProperties = other.pimpl->mStringProperties; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Register a custom post-processing step nuclear@0: aiReturn Importer::RegisterPPStep(BaseProcess* pImp) nuclear@0: { nuclear@0: ai_assert(NULL != pImp); nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: pimpl->mPostProcessingSteps.push_back(pImp); nuclear@0: DefaultLogger::get()->info("Registering custom post-processing step"); nuclear@0: nuclear@0: ASSIMP_END_EXCEPTION_REGION(aiReturn); nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Register a custom loader plugin nuclear@0: aiReturn Importer::RegisterLoader(BaseImporter* pImp) nuclear@0: { nuclear@0: ai_assert(NULL != pImp); nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: // -------------------------------------------------------------------- nuclear@0: // Check whether we would have two loaders for the same file extension nuclear@0: // This is absolutely OK, but we should warn the developer of the new nuclear@0: // loader that his code will probably never be called if the first nuclear@0: // loader is a bit too lazy in his file checking. nuclear@0: // -------------------------------------------------------------------- nuclear@0: std::set st; nuclear@0: std::string baked; nuclear@0: pImp->GetExtensionList(st); nuclear@0: nuclear@0: for(std::set::const_iterator it = st.begin(); it != st.end(); ++it) { nuclear@0: nuclear@0: #ifdef _DEBUG nuclear@0: if (IsExtensionSupported(*it)) { nuclear@0: DefaultLogger::get()->warn("The file extension " + *it + " is already in use"); nuclear@0: } nuclear@0: #endif nuclear@0: baked += *it; nuclear@0: } nuclear@0: nuclear@0: // add the loader nuclear@0: pimpl->mImporter.push_back(pImp); nuclear@0: DefaultLogger::get()->info("Registering custom importer for these file extensions: " + baked); nuclear@0: ASSIMP_END_EXCEPTION_REGION(aiReturn); nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Unregister a custom loader plugin nuclear@0: aiReturn Importer::UnregisterLoader(BaseImporter* pImp) nuclear@0: { nuclear@0: if(!pImp) { nuclear@0: // unregistering a NULL importer is no problem for us ... really! nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: std::vector::iterator it = std::find(pimpl->mImporter.begin(), nuclear@0: pimpl->mImporter.end(),pImp); nuclear@0: nuclear@0: if (it != pimpl->mImporter.end()) { nuclear@0: pimpl->mImporter.erase(it); nuclear@0: nuclear@0: std::set st; nuclear@0: pImp->GetExtensionList(st); nuclear@0: nuclear@0: DefaultLogger::get()->info("Unregistering custom importer: "); nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: DefaultLogger::get()->warn("Unable to remove custom importer: I can't find you ..."); nuclear@0: ASSIMP_END_EXCEPTION_REGION(aiReturn); nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Unregister a custom loader plugin nuclear@0: aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) nuclear@0: { nuclear@0: if(!pImp) { nuclear@0: // unregistering a NULL ppstep is no problem for us ... really! nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: std::vector::iterator it = std::find(pimpl->mPostProcessingSteps.begin(), nuclear@0: pimpl->mPostProcessingSteps.end(),pImp); nuclear@0: nuclear@0: if (it != pimpl->mPostProcessingSteps.end()) { nuclear@0: pimpl->mPostProcessingSteps.erase(it); nuclear@0: DefaultLogger::get()->info("Unregistering custom post-processing step"); nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: DefaultLogger::get()->warn("Unable to remove custom post-processing step: I can't find you .."); nuclear@0: ASSIMP_END_EXCEPTION_REGION(aiReturn); nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Supplies a custom IO handler to the importer to open and access files. nuclear@0: void Importer::SetIOHandler( IOSystem* pIOHandler) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: // If the new handler is zero, allocate a default IO implementation. nuclear@0: if (!pIOHandler) nuclear@0: { nuclear@0: // Release pointer in the possession of the caller nuclear@0: pimpl->mIOHandler = new DefaultIOSystem(); nuclear@0: pimpl->mIsDefaultHandler = true; nuclear@0: } nuclear@0: // Otherwise register the custom handler nuclear@0: else if (pimpl->mIOHandler != pIOHandler) nuclear@0: { nuclear@0: delete pimpl->mIOHandler; nuclear@0: pimpl->mIOHandler = pIOHandler; nuclear@0: pimpl->mIsDefaultHandler = false; nuclear@0: } nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get the currently set IO handler nuclear@0: IOSystem* Importer::GetIOHandler() const nuclear@0: { nuclear@0: return pimpl->mIOHandler; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Check whether a custom IO handler is currently set nuclear@0: bool Importer::IsDefaultIOHandler() const nuclear@0: { nuclear@0: return pimpl->mIsDefaultHandler; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Supplies a custom progress handler to get regular callbacks during importing nuclear@0: void Importer::SetProgressHandler ( ProgressHandler* pHandler ) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: // If the new handler is zero, allocate a default implementation. nuclear@0: if (!pHandler) nuclear@0: { nuclear@0: // Release pointer in the possession of the caller nuclear@0: pimpl->mProgressHandler = new DefaultProgressHandler(); nuclear@0: pimpl->mIsDefaultProgressHandler = true; nuclear@0: } nuclear@0: // Otherwise register the custom handler nuclear@0: else if (pimpl->mProgressHandler != pHandler) nuclear@0: { nuclear@0: delete pimpl->mProgressHandler; nuclear@0: pimpl->mProgressHandler = pHandler; nuclear@0: pimpl->mIsDefaultProgressHandler = false; nuclear@0: } nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get the currently set progress handler nuclear@0: ProgressHandler* Importer::GetProgressHandler() const nuclear@0: { nuclear@0: return pimpl->mProgressHandler; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Check whether a custom progress handler is currently set nuclear@0: bool Importer::IsDefaultProgressHandler() const nuclear@0: { nuclear@0: return pimpl->mIsDefaultProgressHandler; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Validate post process step flags nuclear@0: bool _ValidateFlags(unsigned int pFlags) nuclear@0: { nuclear@0: if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) { nuclear@0: DefaultLogger::get()->error("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible"); nuclear@0: return false; nuclear@0: } nuclear@0: if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices) { nuclear@0: DefaultLogger::get()->error("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible"); nuclear@0: return false; nuclear@0: } nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Free the current scene nuclear@0: void Importer::FreeScene( ) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: delete pimpl->mScene; nuclear@0: pimpl->mScene = NULL; nuclear@0: nuclear@0: pimpl->mErrorString = ""; nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get the current error string, if any nuclear@0: const char* Importer::GetErrorString() const nuclear@0: { nuclear@0: /* Must remain valid as long as ReadFile() or FreeFile() are not called */ nuclear@0: return pimpl->mErrorString.c_str(); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Enable extra-verbose mode nuclear@0: void Importer::SetExtraVerbose(bool bDo) nuclear@0: { nuclear@0: pimpl->bExtraVerbose = bDo; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get the current scene nuclear@0: const aiScene* Importer::GetScene() const nuclear@0: { nuclear@0: return pimpl->mScene; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Orphan the current scene and return it. nuclear@0: aiScene* Importer::GetOrphanedScene() nuclear@0: { nuclear@0: aiScene* s = pimpl->mScene; nuclear@0: nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: pimpl->mScene = NULL; nuclear@0: nuclear@0: pimpl->mErrorString = ""; /* reset error string */ nuclear@0: ASSIMP_END_EXCEPTION_REGION(aiScene*); nuclear@0: return s; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Validate post-processing flags nuclear@0: bool Importer::ValidateFlags(unsigned int pFlags) const nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: // run basic checks for mutually exclusive flags nuclear@0: if(!_ValidateFlags(pFlags)) { nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: // ValidateDS does not anymore occur in the pp list, it plays an awesome extra role ... nuclear@0: #ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS nuclear@0: if (pFlags & aiProcess_ValidateDataStructure) { nuclear@0: return false; nuclear@0: } nuclear@0: #endif nuclear@0: pFlags &= ~aiProcess_ValidateDataStructure; nuclear@0: nuclear@0: // Now iterate through all bits which are set in the flags and check whether we find at least nuclear@0: // one pp plugin which handles it. nuclear@0: for (unsigned int mask = 1; mask < (1u << (sizeof(unsigned int)*8-1));mask <<= 1) { nuclear@0: nuclear@0: if (pFlags & mask) { nuclear@0: nuclear@0: bool have = false; nuclear@0: for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { nuclear@0: if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) { nuclear@0: nuclear@0: have = true; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: if (!have) { nuclear@0: return false; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: ASSIMP_END_EXCEPTION_REGION(bool); nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, nuclear@0: size_t pLength, nuclear@0: unsigned int pFlags, nuclear@0: const char* pHint /*= ""*/) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: if (!pHint) { nuclear@0: pHint = ""; nuclear@0: } nuclear@0: nuclear@0: if (!pBuffer || !pLength || strlen(pHint) > 100) { nuclear@0: pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: // prevent deletion of the previous IOHandler nuclear@0: IOSystem* io = pimpl->mIOHandler; nuclear@0: pimpl->mIOHandler = NULL; nuclear@0: nuclear@0: SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength)); nuclear@0: nuclear@0: // read the file and recover the previous IOSystem nuclear@0: char fbuff[128]; nuclear@0: sprintf(fbuff,"%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint); nuclear@0: nuclear@0: ReadFile(fbuff,pFlags); nuclear@0: SetIOHandler(io); nuclear@0: nuclear@0: ASSIMP_END_EXCEPTION_REGION(const aiScene*); nuclear@0: return pimpl->mScene; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void WriteLogOpening(const std::string& file) nuclear@0: { nuclear@0: Logger* l = DefaultLogger::get(); nuclear@0: if (!l) { nuclear@0: return; nuclear@0: } nuclear@0: l->info("Load " + file); nuclear@0: nuclear@0: // print a full version dump. This is nice because we don't nuclear@0: // need to ask the authors of incoming bug reports for nuclear@0: // the library version they're using - a log dump is nuclear@0: // sufficient. nuclear@0: const unsigned int flags = aiGetCompileFlags(); nuclear@0: l->debug(format() nuclear@0: << "Assimp " nuclear@0: << aiGetVersionMajor() nuclear@0: << "." nuclear@0: << aiGetVersionMinor() nuclear@0: << "." nuclear@0: << aiGetVersionRevision() nuclear@0: nuclear@0: << " " nuclear@0: #if defined(ASSIMP_BUILD_ARCHITECTURE) nuclear@0: << ASSIMP_BUILD_ARCHITECTURE nuclear@0: #elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__) nuclear@0: << "x86" nuclear@0: #elif defined(_M_X64) || defined(__x86_64__) nuclear@0: << "amd64" nuclear@0: #elif defined(_M_IA64) || defined(__ia64__) nuclear@0: << "itanium" nuclear@0: #elif defined(__ppc__) || defined(__powerpc__) nuclear@0: << "ppc32" nuclear@0: #elif defined(__powerpc64__) nuclear@0: << "ppc64" nuclear@0: #elif defined(__arm__) nuclear@0: << "arm" nuclear@0: #else nuclear@0: << "" nuclear@0: #endif nuclear@0: nuclear@0: << " " nuclear@0: #if defined(ASSIMP_BUILD_COMPILER) nuclear@0: << ASSIMP_BUILD_COMPILER nuclear@0: #elif defined(_MSC_VER) nuclear@0: << "msvc" nuclear@0: #elif defined(__GNUC__) nuclear@0: << "gcc" nuclear@0: #else nuclear@0: << "" nuclear@0: #endif nuclear@0: nuclear@0: #ifndef NDEBUG nuclear@0: << " debug" nuclear@0: #endif nuclear@0: nuclear@0: << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "") nuclear@0: << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "") nuclear@0: << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "") nuclear@0: ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Reads the given file and returns its contents if successful. nuclear@0: const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: const std::string pFile(_pFile); nuclear@0: nuclear@0: // ---------------------------------------------------------------------- nuclear@0: // Put a large try block around everything to catch all std::exception's nuclear@0: // that might be thrown by STL containers or by new(). nuclear@0: // ImportErrorException's are throw by ourselves and caught elsewhere. nuclear@0: //----------------------------------------------------------------------- nuclear@0: nuclear@0: WriteLogOpening(pFile); nuclear@0: nuclear@0: #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS nuclear@0: try nuclear@0: #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS nuclear@0: { nuclear@0: // Check whether this Importer instance has already loaded nuclear@0: // a scene. In this case we need to delete the old one nuclear@0: if (pimpl->mScene) { nuclear@0: nuclear@0: DefaultLogger::get()->debug("(Deleting previous scene)"); nuclear@0: FreeScene(); nuclear@0: } nuclear@0: nuclear@0: // First check if the file is accessable at all nuclear@0: if( !pimpl->mIOHandler->Exists( pFile)) { nuclear@0: nuclear@0: pimpl->mErrorString = "Unable to open file \"" + pFile + "\"."; nuclear@0: DefaultLogger::get()->error(pimpl->mErrorString); nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: boost::scoped_ptr profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); nuclear@0: if (profiler) { nuclear@0: profiler->BeginRegion("total"); nuclear@0: } nuclear@0: nuclear@0: // Find an worker class which can handle the file nuclear@0: BaseImporter* imp = NULL; nuclear@0: for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { nuclear@0: nuclear@0: if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) { nuclear@0: imp = pimpl->mImporter[a]; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (!imp) { nuclear@0: // not so bad yet ... try format auto detection. nuclear@0: const std::string::size_type s = pFile.find_last_of('.'); nuclear@0: if (s != std::string::npos) { nuclear@0: DefaultLogger::get()->info("File extension not known, trying signature-based detection"); nuclear@0: for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { nuclear@0: nuclear@0: if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) { nuclear@0: imp = pimpl->mImporter[a]; nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: // Put a proper error message if no suitable importer was found nuclear@0: if( !imp) { nuclear@0: pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; nuclear@0: DefaultLogger::get()->error(pimpl->mErrorString); nuclear@0: return NULL; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Dispatch the reading to the worker class for this format nuclear@0: DefaultLogger::get()->info("Found a matching importer for this file format"); nuclear@0: pimpl->mProgressHandler->Update(); nuclear@0: nuclear@0: if (profiler) { nuclear@0: profiler->BeginRegion("import"); nuclear@0: } nuclear@0: nuclear@0: pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler); nuclear@0: pimpl->mProgressHandler->Update(); nuclear@0: nuclear@0: if (profiler) { nuclear@0: profiler->EndRegion("import"); nuclear@0: } nuclear@0: nuclear@0: // If successful, apply all active post processing steps to the imported data nuclear@0: if( pimpl->mScene) { nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS nuclear@0: // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called. nuclear@0: if (pFlags & aiProcess_ValidateDataStructure) nuclear@0: { nuclear@0: ValidateDSProcess ds; nuclear@0: ds.ExecuteOnScene (this); nuclear@0: if (!pimpl->mScene) { nuclear@0: return NULL; nuclear@0: } nuclear@0: } nuclear@0: #endif // no validation nuclear@0: nuclear@0: // Preprocess the scene and prepare it for post-processing nuclear@0: if (profiler) { nuclear@0: profiler->BeginRegion("preprocess"); nuclear@0: } nuclear@0: nuclear@0: ScenePreprocessor pre(pimpl->mScene); nuclear@0: pre.ProcessScene(); nuclear@0: nuclear@0: pimpl->mProgressHandler->Update(); nuclear@0: if (profiler) { nuclear@0: profiler->EndRegion("preprocess"); nuclear@0: } nuclear@0: nuclear@0: // Ensure that the validation process won't be called twice nuclear@0: ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure)); nuclear@0: } nuclear@0: // if failed, extract the error string nuclear@0: else if( !pimpl->mScene) { nuclear@0: pimpl->mErrorString = imp->GetErrorText(); nuclear@0: } nuclear@0: nuclear@0: // clear any data allocated by post-process steps nuclear@0: pimpl->mPPShared->Clean(); nuclear@0: nuclear@0: if (profiler) { nuclear@0: profiler->EndRegion("total"); nuclear@0: } nuclear@0: } nuclear@0: #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS nuclear@0: catch (std::exception &e) nuclear@0: { nuclear@0: #if (defined _MSC_VER) && (defined _CPPRTTI) nuclear@0: // if we have RTTI get the full name of the exception that occured nuclear@0: pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what(); nuclear@0: #else nuclear@0: pimpl->mErrorString = std::string("std::exception: ") + e.what(); nuclear@0: #endif nuclear@0: nuclear@0: DefaultLogger::get()->error(pimpl->mErrorString); nuclear@0: delete pimpl->mScene; pimpl->mScene = NULL; nuclear@0: } nuclear@0: #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS nuclear@0: nuclear@0: // either successful or failure - the pointer expresses it anyways nuclear@0: ASSIMP_END_EXCEPTION_REGION(const aiScene*); nuclear@0: return pimpl->mScene; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Apply post-processing to the currently bound scene nuclear@0: const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: // Return immediately if no scene is active nuclear@0: if (!pimpl->mScene) { nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: // If no flags are given, return the current scene with no further action nuclear@0: if (!pFlags) { nuclear@0: return pimpl->mScene; nuclear@0: } nuclear@0: nuclear@0: // In debug builds: run basic flag validation nuclear@0: ai_assert(_ValidateFlags(pFlags)); nuclear@0: DefaultLogger::get()->info("Entering post processing pipeline"); nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS nuclear@0: // The ValidateDS process plays an exceptional role. It isn't contained in the global nuclear@0: // list of post-processing steps, so we need to call it manually. nuclear@0: if (pFlags & aiProcess_ValidateDataStructure) nuclear@0: { nuclear@0: ValidateDSProcess ds; nuclear@0: ds.ExecuteOnScene (this); nuclear@0: if (!pimpl->mScene) { nuclear@0: return NULL; nuclear@0: } nuclear@0: } nuclear@0: #endif // no validation nuclear@0: #ifdef _DEBUG nuclear@0: if (pimpl->bExtraVerbose) nuclear@0: { nuclear@0: #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS nuclear@0: DefaultLogger::get()->error("Verbose Import is not available due to build settings"); nuclear@0: #endif // no validation nuclear@0: pFlags |= aiProcess_ValidateDataStructure; nuclear@0: } nuclear@0: #else nuclear@0: if (pimpl->bExtraVerbose) { nuclear@0: DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting"); nuclear@0: } nuclear@0: #endif // ! DEBUG nuclear@0: nuclear@0: boost::scoped_ptr profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); nuclear@0: for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { nuclear@0: nuclear@0: BaseProcess* process = pimpl->mPostProcessingSteps[a]; nuclear@0: if( process->IsActive( pFlags)) { nuclear@0: nuclear@0: if (profiler) { nuclear@0: profiler->BeginRegion("postprocess"); nuclear@0: } nuclear@0: nuclear@0: process->ExecuteOnScene ( this ); nuclear@0: pimpl->mProgressHandler->Update(); nuclear@0: nuclear@0: if (profiler) { nuclear@0: profiler->EndRegion("postprocess"); nuclear@0: } nuclear@0: } nuclear@0: if( !pimpl->mScene) { nuclear@0: break; nuclear@0: } nuclear@0: #ifdef _DEBUG nuclear@0: nuclear@0: #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS nuclear@0: continue; nuclear@0: #endif // no validation nuclear@0: nuclear@0: // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step nuclear@0: if (pimpl->bExtraVerbose) { nuclear@0: DefaultLogger::get()->debug("Verbose Import: revalidating data structures"); nuclear@0: nuclear@0: ValidateDSProcess ds; nuclear@0: ds.ExecuteOnScene (this); nuclear@0: if( !pimpl->mScene) { nuclear@0: DefaultLogger::get()->error("Verbose Import: failed to revalidate data structures"); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: #endif // ! DEBUG nuclear@0: } nuclear@0: nuclear@0: // update private scene flags nuclear@0: if( pimpl->mScene ) nuclear@0: ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags; nuclear@0: nuclear@0: // clear any data allocated by post-process steps nuclear@0: pimpl->mPPShared->Clean(); nuclear@0: DefaultLogger::get()->info("Leaving post processing pipeline"); nuclear@0: nuclear@0: ASSIMP_END_EXCEPTION_REGION(const aiScene*); nuclear@0: return pimpl->mScene; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Helper function to check whether an extension is supported by ASSIMP nuclear@0: bool Importer::IsExtensionSupported(const char* szExtension) const nuclear@0: { nuclear@0: return NULL != GetImporter(szExtension); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: size_t Importer::GetImporterCount() const nuclear@0: { nuclear@0: return pimpl->mImporter.size(); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: const aiImporterDesc* Importer::GetImporterInfo(size_t index) const nuclear@0: { nuclear@0: if (index >= pimpl->mImporter.size()) { nuclear@0: return NULL; nuclear@0: } nuclear@0: return pimpl->mImporter[index]->GetInfo(); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: BaseImporter* Importer::GetImporter (size_t index) const nuclear@0: { nuclear@0: if (index >= pimpl->mImporter.size()) { nuclear@0: return NULL; nuclear@0: } nuclear@0: return pimpl->mImporter[index]; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Find a loader plugin for a given file extension nuclear@0: BaseImporter* Importer::GetImporter (const char* szExtension) const nuclear@0: { nuclear@0: return GetImporter(GetImporterIndex(szExtension)); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Find a loader plugin for a given file extension nuclear@0: size_t Importer::GetImporterIndex (const char* szExtension) const nuclear@0: { nuclear@0: ai_assert(szExtension); nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: // skip over wildcard and dot characters at string head -- nuclear@0: for(;*szExtension == '*' || *szExtension == '.'; ++szExtension); nuclear@0: nuclear@0: std::string ext(szExtension); nuclear@0: if (ext.empty()) { nuclear@0: return static_cast(-1); nuclear@0: } nuclear@0: std::transform(ext.begin(),ext.end(), ext.begin(), tolower); nuclear@0: nuclear@0: std::set str; nuclear@0: for (std::vector::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { nuclear@0: str.clear(); nuclear@0: nuclear@0: (*i)->GetExtensionList(str); nuclear@0: for (std::set::const_iterator it = str.begin(); it != str.end(); ++it) { nuclear@0: if (ext == *it) { nuclear@0: return std::distance(static_cast< std::vector::const_iterator >(pimpl->mImporter.begin()), i); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: ASSIMP_END_EXCEPTION_REGION(size_t); nuclear@0: return static_cast(-1); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Helper function to build a list of all file extensions supported by ASSIMP nuclear@0: void Importer::GetExtensionList(aiString& szOut) const nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: std::set str; nuclear@0: for (std::vector::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { nuclear@0: (*i)->GetExtensionList(str); nuclear@0: } nuclear@0: nuclear@0: for (std::set::const_iterator it = str.begin();; ) { nuclear@0: szOut.Append("*."); nuclear@0: szOut.Append((*it).c_str()); nuclear@0: nuclear@0: if (++it == str.end()) { nuclear@0: break; nuclear@0: } nuclear@0: szOut.Append(";"); nuclear@0: } nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Set a configuration property nuclear@0: void Importer::SetPropertyInteger(const char* szName, int iValue, nuclear@0: bool* bWasExisting /*= NULL*/) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: SetGenericProperty(pimpl->mIntProperties, szName,iValue,bWasExisting); nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Set a configuration property nuclear@0: void Importer::SetPropertyFloat(const char* szName, float iValue, nuclear@0: bool* bWasExisting /*= NULL*/) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: SetGenericProperty(pimpl->mFloatProperties, szName,iValue,bWasExisting); nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Set a configuration property nuclear@0: void Importer::SetPropertyString(const char* szName, const std::string& value, nuclear@0: bool* bWasExisting /*= NULL*/) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: SetGenericProperty(pimpl->mStringProperties, szName,value,bWasExisting); nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get a configuration property nuclear@0: int Importer::GetPropertyInteger(const char* szName, nuclear@0: int iErrorReturn /*= 0xffffffff*/) const nuclear@0: { nuclear@0: return GetGenericProperty(pimpl->mIntProperties,szName,iErrorReturn); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get a configuration property nuclear@0: float Importer::GetPropertyFloat(const char* szName, nuclear@0: float iErrorReturn /*= 10e10*/) const nuclear@0: { nuclear@0: return GetGenericProperty(pimpl->mFloatProperties,szName,iErrorReturn); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get a configuration property nuclear@0: const std::string& Importer::GetPropertyString(const char* szName, nuclear@0: const std::string& iErrorReturn /*= ""*/) const nuclear@0: { nuclear@0: return GetGenericProperty(pimpl->mStringProperties,szName,iErrorReturn); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get the memory requirements of a single node nuclear@0: inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) nuclear@0: { nuclear@0: iScene += sizeof(aiNode); nuclear@0: iScene += sizeof(unsigned int) * pcNode->mNumMeshes; nuclear@0: iScene += sizeof(void*) * pcNode->mNumChildren; nuclear@0: nuclear@0: for (unsigned int i = 0; i < pcNode->mNumChildren;++i) { nuclear@0: AddNodeWeight(iScene,pcNode->mChildren[i]); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get the memory requirements of the scene nuclear@0: void Importer::GetMemoryRequirements(aiMemoryInfo& in) const nuclear@0: { nuclear@0: in = aiMemoryInfo(); nuclear@0: aiScene* mScene = pimpl->mScene; nuclear@0: nuclear@0: // return if we have no scene loaded nuclear@0: if (!pimpl->mScene) nuclear@0: return; nuclear@0: nuclear@0: nuclear@0: in.total = sizeof(aiScene); nuclear@0: nuclear@0: // add all meshes nuclear@0: for (unsigned int i = 0; i < mScene->mNumMeshes;++i) nuclear@0: { nuclear@0: in.meshes += sizeof(aiMesh); nuclear@0: if (mScene->mMeshes[i]->HasPositions()) { nuclear@0: in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; nuclear@0: } nuclear@0: nuclear@0: if (mScene->mMeshes[i]->HasNormals()) { nuclear@0: in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; nuclear@0: } nuclear@0: nuclear@0: if (mScene->mMeshes[i]->HasTangentsAndBitangents()) { nuclear@0: in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices * 2; nuclear@0: } nuclear@0: nuclear@0: for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) { nuclear@0: if (mScene->mMeshes[i]->HasVertexColors(a)) { nuclear@0: in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices; nuclear@0: } nuclear@0: else break; nuclear@0: } nuclear@0: for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { nuclear@0: if (mScene->mMeshes[i]->HasTextureCoords(a)) { nuclear@0: in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; nuclear@0: } nuclear@0: else break; nuclear@0: } nuclear@0: if (mScene->mMeshes[i]->HasBones()) { nuclear@0: in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones; nuclear@0: for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones;++p) { nuclear@0: in.meshes += sizeof(aiBone); nuclear@0: in.meshes += mScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight); nuclear@0: } nuclear@0: } nuclear@0: in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int))*mScene->mMeshes[i]->mNumFaces; nuclear@0: } nuclear@0: in.total += in.meshes; nuclear@0: nuclear@0: // add all embedded textures nuclear@0: for (unsigned int i = 0; i < mScene->mNumTextures;++i) { nuclear@0: const aiTexture* pc = mScene->mTextures[i]; nuclear@0: in.textures += sizeof(aiTexture); nuclear@0: if (pc->mHeight) { nuclear@0: in.textures += 4 * pc->mHeight * pc->mWidth; nuclear@0: } nuclear@0: else in.textures += pc->mWidth; nuclear@0: } nuclear@0: in.total += in.textures; nuclear@0: nuclear@0: // add all animations nuclear@0: for (unsigned int i = 0; i < mScene->mNumAnimations;++i) { nuclear@0: const aiAnimation* pc = mScene->mAnimations[i]; nuclear@0: in.animations += sizeof(aiAnimation); nuclear@0: nuclear@0: // add all bone anims nuclear@0: for (unsigned int a = 0; a < pc->mNumChannels; ++a) { nuclear@0: const aiNodeAnim* pc2 = pc->mChannels[i]; nuclear@0: in.animations += sizeof(aiNodeAnim); nuclear@0: in.animations += pc2->mNumPositionKeys * sizeof(aiVectorKey); nuclear@0: in.animations += pc2->mNumScalingKeys * sizeof(aiVectorKey); nuclear@0: in.animations += pc2->mNumRotationKeys * sizeof(aiQuatKey); nuclear@0: } nuclear@0: } nuclear@0: in.total += in.animations; nuclear@0: nuclear@0: // add all cameras and all lights nuclear@0: in.total += in.cameras = sizeof(aiCamera) * mScene->mNumCameras; nuclear@0: in.total += in.lights = sizeof(aiLight) * mScene->mNumLights; nuclear@0: nuclear@0: // add all nodes nuclear@0: AddNodeWeight(in.nodes,mScene->mRootNode); nuclear@0: in.total += in.nodes; nuclear@0: nuclear@0: // add all materials nuclear@0: for (unsigned int i = 0; i < mScene->mNumMaterials;++i) { nuclear@0: const aiMaterial* pc = mScene->mMaterials[i]; nuclear@0: in.materials += sizeof(aiMaterial); nuclear@0: in.materials += pc->mNumAllocated * sizeof(void*); nuclear@0: nuclear@0: for (unsigned int a = 0; a < pc->mNumProperties;++a) { nuclear@0: in.materials += pc->mProperties[a]->mDataLength; nuclear@0: } nuclear@0: } nuclear@0: in.total += in.materials; nuclear@0: } nuclear@0: