vrshoot
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/assimp/Importer.cpp Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,1077 @@ 1.4 +/* 1.5 +--------------------------------------------------------------------------- 1.6 +Open Asset Import Library (assimp) 1.7 +--------------------------------------------------------------------------- 1.8 + 1.9 +Copyright (c) 2006-2012, assimp team 1.10 + 1.11 +All rights reserved. 1.12 + 1.13 +Redistribution and use of this software in source and binary forms, 1.14 +with or without modification, are permitted provided that the following 1.15 +conditions are met: 1.16 + 1.17 +* Redistributions of source code must retain the above 1.18 + copyright notice, this list of conditions and the 1.19 + following disclaimer. 1.20 + 1.21 +* Redistributions in binary form must reproduce the above 1.22 + copyright notice, this list of conditions and the 1.23 + following disclaimer in the documentation and/or other 1.24 + materials provided with the distribution. 1.25 + 1.26 +* Neither the name of the assimp team, nor the names of its 1.27 + contributors may be used to endorse or promote products 1.28 + derived from this software without specific prior 1.29 + written permission of the assimp team. 1.30 + 1.31 +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.32 +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.33 +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.34 +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.35 +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.36 +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.37 +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.38 +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.39 +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.40 +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.41 +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.42 +--------------------------------------------------------------------------- 1.43 +*/ 1.44 + 1.45 +/** @file Importer.cpp 1.46 + * @brief Implementation of the CPP-API class #Importer 1.47 + */ 1.48 + 1.49 +#include "AssimpPCH.h" 1.50 +#include "assimp/version.h" 1.51 + 1.52 +// ------------------------------------------------------------------------------------------------ 1.53 +/* Uncomment this line to prevent Assimp from catching unknown exceptions. 1.54 + * 1.55 + * Note that any Exception except DeadlyImportError may lead to 1.56 + * undefined behaviour -> loaders could remain in an unusable state and 1.57 + * further imports with the same Importer instance could fail/crash/burn ... 1.58 + */ 1.59 +// ------------------------------------------------------------------------------------------------ 1.60 +#ifndef ASSIMP_BUILD_DEBUG 1.61 +# define ASSIMP_CATCH_GLOBAL_EXCEPTIONS 1.62 +#endif 1.63 + 1.64 +// ------------------------------------------------------------------------------------------------ 1.65 +// Internal headers 1.66 +// ------------------------------------------------------------------------------------------------ 1.67 +#include "Importer.h" 1.68 +#include "BaseProcess.h" 1.69 + 1.70 +#include "DefaultIOStream.h" 1.71 +#include "DefaultIOSystem.h" 1.72 +#include "DefaultProgressHandler.h" 1.73 +#include "GenericProperty.h" 1.74 +#include "ProcessHelper.h" 1.75 +#include "ScenePreprocessor.h" 1.76 +#include "MemoryIOWrapper.h" 1.77 +#include "Profiler.h" 1.78 +#include "TinyFormatter.h" 1.79 + 1.80 +#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS 1.81 +# include "ValidateDataStructure.h" 1.82 +#endif 1.83 + 1.84 +using namespace Assimp::Profiling; 1.85 +using namespace Assimp::Formatter; 1.86 + 1.87 +namespace Assimp { 1.88 + // ImporterRegistry.cpp 1.89 + void GetImporterInstanceList(std::vector< BaseImporter* >& out); 1.90 + // PostStepRegistry.cpp 1.91 + void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out); 1.92 +} 1.93 + 1.94 +using namespace Assimp; 1.95 +using namespace Assimp::Intern; 1.96 + 1.97 +// ------------------------------------------------------------------------------------------------ 1.98 +// Intern::AllocateFromAssimpHeap serves as abstract base class. It overrides 1.99 +// new and delete (and their array counterparts) of public API classes (e.g. Logger) to 1.100 +// utilize our DLL heap. 1.101 +// See http://www.gotw.ca/publications/mill15.htm 1.102 +// ------------------------------------------------------------------------------------------------ 1.103 +void* AllocateFromAssimpHeap::operator new ( size_t num_bytes) { 1.104 + return ::operator new(num_bytes); 1.105 +} 1.106 + 1.107 +void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothrow_t& ) throw() { 1.108 + try { 1.109 + return AllocateFromAssimpHeap::operator new( num_bytes ); 1.110 + } 1.111 + catch( ... ) { 1.112 + return NULL; 1.113 + } 1.114 +} 1.115 + 1.116 +void AllocateFromAssimpHeap::operator delete ( void* data) { 1.117 + return ::operator delete(data); 1.118 +} 1.119 + 1.120 +void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) { 1.121 + return ::operator new[](num_bytes); 1.122 +} 1.123 + 1.124 +void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() { 1.125 + try { 1.126 + return AllocateFromAssimpHeap::operator new[]( num_bytes ); 1.127 + } 1.128 + catch( ... ) { 1.129 + return NULL; 1.130 + } 1.131 +} 1.132 + 1.133 +void AllocateFromAssimpHeap::operator delete[] ( void* data) { 1.134 + return ::operator delete[](data); 1.135 +} 1.136 + 1.137 +// ------------------------------------------------------------------------------------------------ 1.138 +// Importer constructor. 1.139 +Importer::Importer() 1.140 +{ 1.141 + // allocate the pimpl first 1.142 + pimpl = new ImporterPimpl(); 1.143 + 1.144 + pimpl->mScene = NULL; 1.145 + pimpl->mErrorString = ""; 1.146 + 1.147 + // Allocate a default IO handler 1.148 + pimpl->mIOHandler = new DefaultIOSystem; 1.149 + pimpl->mIsDefaultHandler = true; 1.150 + pimpl->bExtraVerbose = false; // disable extra verbose mode by default 1.151 + 1.152 + pimpl->mProgressHandler = new DefaultProgressHandler(); 1.153 + pimpl->mIsDefaultProgressHandler = true; 1.154 + 1.155 + GetImporterInstanceList(pimpl->mImporter); 1.156 + GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps); 1.157 + 1.158 + // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list. 1.159 + pimpl->mPPShared = new SharedPostProcessInfo(); 1.160 + for (std::vector<BaseProcess*>::iterator it = pimpl->mPostProcessingSteps.begin(); 1.161 + it != pimpl->mPostProcessingSteps.end(); 1.162 + ++it) { 1.163 + 1.164 + (*it)->SetSharedData(pimpl->mPPShared); 1.165 + } 1.166 +} 1.167 + 1.168 +// ------------------------------------------------------------------------------------------------ 1.169 +// Destructor of Importer 1.170 +Importer::~Importer() 1.171 +{ 1.172 + // Delete all import plugins 1.173 + for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) 1.174 + delete pimpl->mImporter[a]; 1.175 + 1.176 + // Delete all post-processing plug-ins 1.177 + for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) 1.178 + delete pimpl->mPostProcessingSteps[a]; 1.179 + 1.180 + // Delete the assigned IO and progress handler 1.181 + delete pimpl->mIOHandler; 1.182 + delete pimpl->mProgressHandler; 1.183 + 1.184 + // Kill imported scene. Destructors should do that recursivly 1.185 + delete pimpl->mScene; 1.186 + 1.187 + // Delete shared post-processing data 1.188 + delete pimpl->mPPShared; 1.189 + 1.190 + // and finally the pimpl itself 1.191 + delete pimpl; 1.192 +} 1.193 + 1.194 +// ------------------------------------------------------------------------------------------------ 1.195 +// Copy constructor - copies the config of another Importer, not the scene 1.196 +Importer::Importer(const Importer &other) 1.197 +{ 1.198 + new(this) Importer(); 1.199 + 1.200 + pimpl->mIntProperties = other.pimpl->mIntProperties; 1.201 + pimpl->mFloatProperties = other.pimpl->mFloatProperties; 1.202 + pimpl->mStringProperties = other.pimpl->mStringProperties; 1.203 +} 1.204 + 1.205 +// ------------------------------------------------------------------------------------------------ 1.206 +// Register a custom post-processing step 1.207 +aiReturn Importer::RegisterPPStep(BaseProcess* pImp) 1.208 +{ 1.209 + ai_assert(NULL != pImp); 1.210 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.211 + 1.212 + pimpl->mPostProcessingSteps.push_back(pImp); 1.213 + DefaultLogger::get()->info("Registering custom post-processing step"); 1.214 + 1.215 + ASSIMP_END_EXCEPTION_REGION(aiReturn); 1.216 + return AI_SUCCESS; 1.217 +} 1.218 + 1.219 +// ------------------------------------------------------------------------------------------------ 1.220 +// Register a custom loader plugin 1.221 +aiReturn Importer::RegisterLoader(BaseImporter* pImp) 1.222 +{ 1.223 + ai_assert(NULL != pImp); 1.224 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.225 + 1.226 + // -------------------------------------------------------------------- 1.227 + // Check whether we would have two loaders for the same file extension 1.228 + // This is absolutely OK, but we should warn the developer of the new 1.229 + // loader that his code will probably never be called if the first 1.230 + // loader is a bit too lazy in his file checking. 1.231 + // -------------------------------------------------------------------- 1.232 + std::set<std::string> st; 1.233 + std::string baked; 1.234 + pImp->GetExtensionList(st); 1.235 + 1.236 + for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) { 1.237 + 1.238 +#ifdef _DEBUG 1.239 + if (IsExtensionSupported(*it)) { 1.240 + DefaultLogger::get()->warn("The file extension " + *it + " is already in use"); 1.241 + } 1.242 +#endif 1.243 + baked += *it; 1.244 + } 1.245 + 1.246 + // add the loader 1.247 + pimpl->mImporter.push_back(pImp); 1.248 + DefaultLogger::get()->info("Registering custom importer for these file extensions: " + baked); 1.249 + ASSIMP_END_EXCEPTION_REGION(aiReturn); 1.250 + return AI_SUCCESS; 1.251 +} 1.252 + 1.253 +// ------------------------------------------------------------------------------------------------ 1.254 +// Unregister a custom loader plugin 1.255 +aiReturn Importer::UnregisterLoader(BaseImporter* pImp) 1.256 +{ 1.257 + if(!pImp) { 1.258 + // unregistering a NULL importer is no problem for us ... really! 1.259 + return AI_SUCCESS; 1.260 + } 1.261 + 1.262 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.263 + std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(), 1.264 + pimpl->mImporter.end(),pImp); 1.265 + 1.266 + if (it != pimpl->mImporter.end()) { 1.267 + pimpl->mImporter.erase(it); 1.268 + 1.269 + std::set<std::string> st; 1.270 + pImp->GetExtensionList(st); 1.271 + 1.272 + DefaultLogger::get()->info("Unregistering custom importer: "); 1.273 + return AI_SUCCESS; 1.274 + } 1.275 + DefaultLogger::get()->warn("Unable to remove custom importer: I can't find you ..."); 1.276 + ASSIMP_END_EXCEPTION_REGION(aiReturn); 1.277 + return AI_FAILURE; 1.278 +} 1.279 + 1.280 +// ------------------------------------------------------------------------------------------------ 1.281 +// Unregister a custom loader plugin 1.282 +aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) 1.283 +{ 1.284 + if(!pImp) { 1.285 + // unregistering a NULL ppstep is no problem for us ... really! 1.286 + return AI_SUCCESS; 1.287 + } 1.288 + 1.289 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.290 + std::vector<BaseProcess*>::iterator it = std::find(pimpl->mPostProcessingSteps.begin(), 1.291 + pimpl->mPostProcessingSteps.end(),pImp); 1.292 + 1.293 + if (it != pimpl->mPostProcessingSteps.end()) { 1.294 + pimpl->mPostProcessingSteps.erase(it); 1.295 + DefaultLogger::get()->info("Unregistering custom post-processing step"); 1.296 + return AI_SUCCESS; 1.297 + } 1.298 + DefaultLogger::get()->warn("Unable to remove custom post-processing step: I can't find you .."); 1.299 + ASSIMP_END_EXCEPTION_REGION(aiReturn); 1.300 + return AI_FAILURE; 1.301 +} 1.302 + 1.303 +// ------------------------------------------------------------------------------------------------ 1.304 +// Supplies a custom IO handler to the importer to open and access files. 1.305 +void Importer::SetIOHandler( IOSystem* pIOHandler) 1.306 +{ 1.307 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.308 + // If the new handler is zero, allocate a default IO implementation. 1.309 + if (!pIOHandler) 1.310 + { 1.311 + // Release pointer in the possession of the caller 1.312 + pimpl->mIOHandler = new DefaultIOSystem(); 1.313 + pimpl->mIsDefaultHandler = true; 1.314 + } 1.315 + // Otherwise register the custom handler 1.316 + else if (pimpl->mIOHandler != pIOHandler) 1.317 + { 1.318 + delete pimpl->mIOHandler; 1.319 + pimpl->mIOHandler = pIOHandler; 1.320 + pimpl->mIsDefaultHandler = false; 1.321 + } 1.322 + ASSIMP_END_EXCEPTION_REGION(void); 1.323 +} 1.324 + 1.325 +// ------------------------------------------------------------------------------------------------ 1.326 +// Get the currently set IO handler 1.327 +IOSystem* Importer::GetIOHandler() const 1.328 +{ 1.329 + return pimpl->mIOHandler; 1.330 +} 1.331 + 1.332 +// ------------------------------------------------------------------------------------------------ 1.333 +// Check whether a custom IO handler is currently set 1.334 +bool Importer::IsDefaultIOHandler() const 1.335 +{ 1.336 + return pimpl->mIsDefaultHandler; 1.337 +} 1.338 + 1.339 +// ------------------------------------------------------------------------------------------------ 1.340 +// Supplies a custom progress handler to get regular callbacks during importing 1.341 +void Importer::SetProgressHandler ( ProgressHandler* pHandler ) 1.342 +{ 1.343 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.344 + // If the new handler is zero, allocate a default implementation. 1.345 + if (!pHandler) 1.346 + { 1.347 + // Release pointer in the possession of the caller 1.348 + pimpl->mProgressHandler = new DefaultProgressHandler(); 1.349 + pimpl->mIsDefaultProgressHandler = true; 1.350 + } 1.351 + // Otherwise register the custom handler 1.352 + else if (pimpl->mProgressHandler != pHandler) 1.353 + { 1.354 + delete pimpl->mProgressHandler; 1.355 + pimpl->mProgressHandler = pHandler; 1.356 + pimpl->mIsDefaultProgressHandler = false; 1.357 + } 1.358 + ASSIMP_END_EXCEPTION_REGION(void); 1.359 +} 1.360 + 1.361 +// ------------------------------------------------------------------------------------------------ 1.362 +// Get the currently set progress handler 1.363 +ProgressHandler* Importer::GetProgressHandler() const 1.364 +{ 1.365 + return pimpl->mProgressHandler; 1.366 +} 1.367 + 1.368 +// ------------------------------------------------------------------------------------------------ 1.369 +// Check whether a custom progress handler is currently set 1.370 +bool Importer::IsDefaultProgressHandler() const 1.371 +{ 1.372 + return pimpl->mIsDefaultProgressHandler; 1.373 +} 1.374 + 1.375 +// ------------------------------------------------------------------------------------------------ 1.376 +// Validate post process step flags 1.377 +bool _ValidateFlags(unsigned int pFlags) 1.378 +{ 1.379 + if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) { 1.380 + DefaultLogger::get()->error("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible"); 1.381 + return false; 1.382 + } 1.383 + if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices) { 1.384 + DefaultLogger::get()->error("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible"); 1.385 + return false; 1.386 + } 1.387 + return true; 1.388 +} 1.389 + 1.390 +// ------------------------------------------------------------------------------------------------ 1.391 +// Free the current scene 1.392 +void Importer::FreeScene( ) 1.393 +{ 1.394 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.395 + delete pimpl->mScene; 1.396 + pimpl->mScene = NULL; 1.397 + 1.398 + pimpl->mErrorString = ""; 1.399 + ASSIMP_END_EXCEPTION_REGION(void); 1.400 +} 1.401 + 1.402 +// ------------------------------------------------------------------------------------------------ 1.403 +// Get the current error string, if any 1.404 +const char* Importer::GetErrorString() const 1.405 +{ 1.406 + /* Must remain valid as long as ReadFile() or FreeFile() are not called */ 1.407 + return pimpl->mErrorString.c_str(); 1.408 +} 1.409 + 1.410 +// ------------------------------------------------------------------------------------------------ 1.411 +// Enable extra-verbose mode 1.412 +void Importer::SetExtraVerbose(bool bDo) 1.413 +{ 1.414 + pimpl->bExtraVerbose = bDo; 1.415 +} 1.416 + 1.417 +// ------------------------------------------------------------------------------------------------ 1.418 +// Get the current scene 1.419 +const aiScene* Importer::GetScene() const 1.420 +{ 1.421 + return pimpl->mScene; 1.422 +} 1.423 + 1.424 +// ------------------------------------------------------------------------------------------------ 1.425 +// Orphan the current scene and return it. 1.426 +aiScene* Importer::GetOrphanedScene() 1.427 +{ 1.428 + aiScene* s = pimpl->mScene; 1.429 + 1.430 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.431 + pimpl->mScene = NULL; 1.432 + 1.433 + pimpl->mErrorString = ""; /* reset error string */ 1.434 + ASSIMP_END_EXCEPTION_REGION(aiScene*); 1.435 + return s; 1.436 +} 1.437 + 1.438 +// ------------------------------------------------------------------------------------------------ 1.439 +// Validate post-processing flags 1.440 +bool Importer::ValidateFlags(unsigned int pFlags) const 1.441 +{ 1.442 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.443 + // run basic checks for mutually exclusive flags 1.444 + if(!_ValidateFlags(pFlags)) { 1.445 + return false; 1.446 + } 1.447 + 1.448 + // ValidateDS does not anymore occur in the pp list, it plays an awesome extra role ... 1.449 +#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS 1.450 + if (pFlags & aiProcess_ValidateDataStructure) { 1.451 + return false; 1.452 + } 1.453 +#endif 1.454 + pFlags &= ~aiProcess_ValidateDataStructure; 1.455 + 1.456 + // Now iterate through all bits which are set in the flags and check whether we find at least 1.457 + // one pp plugin which handles it. 1.458 + for (unsigned int mask = 1; mask < (1u << (sizeof(unsigned int)*8-1));mask <<= 1) { 1.459 + 1.460 + if (pFlags & mask) { 1.461 + 1.462 + bool have = false; 1.463 + for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { 1.464 + if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) { 1.465 + 1.466 + have = true; 1.467 + break; 1.468 + } 1.469 + } 1.470 + if (!have) { 1.471 + return false; 1.472 + } 1.473 + } 1.474 + } 1.475 + ASSIMP_END_EXCEPTION_REGION(bool); 1.476 + return true; 1.477 +} 1.478 + 1.479 +// ------------------------------------------------------------------------------------------------ 1.480 +const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, 1.481 + size_t pLength, 1.482 + unsigned int pFlags, 1.483 + const char* pHint /*= ""*/) 1.484 +{ 1.485 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.486 + if (!pHint) { 1.487 + pHint = ""; 1.488 + } 1.489 + 1.490 + if (!pBuffer || !pLength || strlen(pHint) > 100) { 1.491 + pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; 1.492 + return NULL; 1.493 + } 1.494 + 1.495 + // prevent deletion of the previous IOHandler 1.496 + IOSystem* io = pimpl->mIOHandler; 1.497 + pimpl->mIOHandler = NULL; 1.498 + 1.499 + SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength)); 1.500 + 1.501 + // read the file and recover the previous IOSystem 1.502 + char fbuff[128]; 1.503 + sprintf(fbuff,"%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint); 1.504 + 1.505 + ReadFile(fbuff,pFlags); 1.506 + SetIOHandler(io); 1.507 + 1.508 + ASSIMP_END_EXCEPTION_REGION(const aiScene*); 1.509 + return pimpl->mScene; 1.510 +} 1.511 + 1.512 +// ------------------------------------------------------------------------------------------------ 1.513 +void WriteLogOpening(const std::string& file) 1.514 +{ 1.515 + Logger* l = DefaultLogger::get(); 1.516 + if (!l) { 1.517 + return; 1.518 + } 1.519 + l->info("Load " + file); 1.520 + 1.521 + // print a full version dump. This is nice because we don't 1.522 + // need to ask the authors of incoming bug reports for 1.523 + // the library version they're using - a log dump is 1.524 + // sufficient. 1.525 + const unsigned int flags = aiGetCompileFlags(); 1.526 + l->debug(format() 1.527 + << "Assimp " 1.528 + << aiGetVersionMajor() 1.529 + << "." 1.530 + << aiGetVersionMinor() 1.531 + << "." 1.532 + << aiGetVersionRevision() 1.533 + 1.534 + << " " 1.535 +#if defined(ASSIMP_BUILD_ARCHITECTURE) 1.536 + << ASSIMP_BUILD_ARCHITECTURE 1.537 +#elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__) 1.538 + << "x86" 1.539 +#elif defined(_M_X64) || defined(__x86_64__) 1.540 + << "amd64" 1.541 +#elif defined(_M_IA64) || defined(__ia64__) 1.542 + << "itanium" 1.543 +#elif defined(__ppc__) || defined(__powerpc__) 1.544 + << "ppc32" 1.545 +#elif defined(__powerpc64__) 1.546 + << "ppc64" 1.547 +#elif defined(__arm__) 1.548 + << "arm" 1.549 +#else 1.550 + << "<unknown architecture>" 1.551 +#endif 1.552 + 1.553 + << " " 1.554 +#if defined(ASSIMP_BUILD_COMPILER) 1.555 + << ASSIMP_BUILD_COMPILER 1.556 +#elif defined(_MSC_VER) 1.557 + << "msvc" 1.558 +#elif defined(__GNUC__) 1.559 + << "gcc" 1.560 +#else 1.561 + << "<unknown compiler>" 1.562 +#endif 1.563 + 1.564 +#ifndef NDEBUG 1.565 + << " debug" 1.566 +#endif 1.567 + 1.568 + << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "") 1.569 + << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "") 1.570 + << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "") 1.571 + ); 1.572 +} 1.573 + 1.574 +// ------------------------------------------------------------------------------------------------ 1.575 +// Reads the given file and returns its contents if successful. 1.576 +const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) 1.577 +{ 1.578 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.579 + const std::string pFile(_pFile); 1.580 + 1.581 + // ---------------------------------------------------------------------- 1.582 + // Put a large try block around everything to catch all std::exception's 1.583 + // that might be thrown by STL containers or by new(). 1.584 + // ImportErrorException's are throw by ourselves and caught elsewhere. 1.585 + //----------------------------------------------------------------------- 1.586 + 1.587 + WriteLogOpening(pFile); 1.588 + 1.589 +#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS 1.590 + try 1.591 +#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS 1.592 + { 1.593 + // Check whether this Importer instance has already loaded 1.594 + // a scene. In this case we need to delete the old one 1.595 + if (pimpl->mScene) { 1.596 + 1.597 + DefaultLogger::get()->debug("(Deleting previous scene)"); 1.598 + FreeScene(); 1.599 + } 1.600 + 1.601 + // First check if the file is accessable at all 1.602 + if( !pimpl->mIOHandler->Exists( pFile)) { 1.603 + 1.604 + pimpl->mErrorString = "Unable to open file \"" + pFile + "\"."; 1.605 + DefaultLogger::get()->error(pimpl->mErrorString); 1.606 + return NULL; 1.607 + } 1.608 + 1.609 + boost::scoped_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); 1.610 + if (profiler) { 1.611 + profiler->BeginRegion("total"); 1.612 + } 1.613 + 1.614 + // Find an worker class which can handle the file 1.615 + BaseImporter* imp = NULL; 1.616 + for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { 1.617 + 1.618 + if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) { 1.619 + imp = pimpl->mImporter[a]; 1.620 + break; 1.621 + } 1.622 + } 1.623 + 1.624 + if (!imp) { 1.625 + // not so bad yet ... try format auto detection. 1.626 + const std::string::size_type s = pFile.find_last_of('.'); 1.627 + if (s != std::string::npos) { 1.628 + DefaultLogger::get()->info("File extension not known, trying signature-based detection"); 1.629 + for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { 1.630 + 1.631 + if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) { 1.632 + imp = pimpl->mImporter[a]; 1.633 + break; 1.634 + } 1.635 + } 1.636 + } 1.637 + // Put a proper error message if no suitable importer was found 1.638 + if( !imp) { 1.639 + pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; 1.640 + DefaultLogger::get()->error(pimpl->mErrorString); 1.641 + return NULL; 1.642 + } 1.643 + } 1.644 + 1.645 + // Dispatch the reading to the worker class for this format 1.646 + DefaultLogger::get()->info("Found a matching importer for this file format"); 1.647 + pimpl->mProgressHandler->Update(); 1.648 + 1.649 + if (profiler) { 1.650 + profiler->BeginRegion("import"); 1.651 + } 1.652 + 1.653 + pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler); 1.654 + pimpl->mProgressHandler->Update(); 1.655 + 1.656 + if (profiler) { 1.657 + profiler->EndRegion("import"); 1.658 + } 1.659 + 1.660 + // If successful, apply all active post processing steps to the imported data 1.661 + if( pimpl->mScene) { 1.662 + 1.663 +#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS 1.664 + // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called. 1.665 + if (pFlags & aiProcess_ValidateDataStructure) 1.666 + { 1.667 + ValidateDSProcess ds; 1.668 + ds.ExecuteOnScene (this); 1.669 + if (!pimpl->mScene) { 1.670 + return NULL; 1.671 + } 1.672 + } 1.673 +#endif // no validation 1.674 + 1.675 + // Preprocess the scene and prepare it for post-processing 1.676 + if (profiler) { 1.677 + profiler->BeginRegion("preprocess"); 1.678 + } 1.679 + 1.680 + ScenePreprocessor pre(pimpl->mScene); 1.681 + pre.ProcessScene(); 1.682 + 1.683 + pimpl->mProgressHandler->Update(); 1.684 + if (profiler) { 1.685 + profiler->EndRegion("preprocess"); 1.686 + } 1.687 + 1.688 + // Ensure that the validation process won't be called twice 1.689 + ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure)); 1.690 + } 1.691 + // if failed, extract the error string 1.692 + else if( !pimpl->mScene) { 1.693 + pimpl->mErrorString = imp->GetErrorText(); 1.694 + } 1.695 + 1.696 + // clear any data allocated by post-process steps 1.697 + pimpl->mPPShared->Clean(); 1.698 + 1.699 + if (profiler) { 1.700 + profiler->EndRegion("total"); 1.701 + } 1.702 + } 1.703 +#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS 1.704 + catch (std::exception &e) 1.705 + { 1.706 +#if (defined _MSC_VER) && (defined _CPPRTTI) 1.707 + // if we have RTTI get the full name of the exception that occured 1.708 + pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what(); 1.709 +#else 1.710 + pimpl->mErrorString = std::string("std::exception: ") + e.what(); 1.711 +#endif 1.712 + 1.713 + DefaultLogger::get()->error(pimpl->mErrorString); 1.714 + delete pimpl->mScene; pimpl->mScene = NULL; 1.715 + } 1.716 +#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS 1.717 + 1.718 + // either successful or failure - the pointer expresses it anyways 1.719 + ASSIMP_END_EXCEPTION_REGION(const aiScene*); 1.720 + return pimpl->mScene; 1.721 +} 1.722 + 1.723 + 1.724 +// ------------------------------------------------------------------------------------------------ 1.725 +// Apply post-processing to the currently bound scene 1.726 +const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) 1.727 +{ 1.728 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.729 + // Return immediately if no scene is active 1.730 + if (!pimpl->mScene) { 1.731 + return NULL; 1.732 + } 1.733 + 1.734 + // If no flags are given, return the current scene with no further action 1.735 + if (!pFlags) { 1.736 + return pimpl->mScene; 1.737 + } 1.738 + 1.739 + // In debug builds: run basic flag validation 1.740 + ai_assert(_ValidateFlags(pFlags)); 1.741 + DefaultLogger::get()->info("Entering post processing pipeline"); 1.742 + 1.743 +#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS 1.744 + // The ValidateDS process plays an exceptional role. It isn't contained in the global 1.745 + // list of post-processing steps, so we need to call it manually. 1.746 + if (pFlags & aiProcess_ValidateDataStructure) 1.747 + { 1.748 + ValidateDSProcess ds; 1.749 + ds.ExecuteOnScene (this); 1.750 + if (!pimpl->mScene) { 1.751 + return NULL; 1.752 + } 1.753 + } 1.754 +#endif // no validation 1.755 +#ifdef _DEBUG 1.756 + if (pimpl->bExtraVerbose) 1.757 + { 1.758 +#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS 1.759 + DefaultLogger::get()->error("Verbose Import is not available due to build settings"); 1.760 +#endif // no validation 1.761 + pFlags |= aiProcess_ValidateDataStructure; 1.762 + } 1.763 +#else 1.764 + if (pimpl->bExtraVerbose) { 1.765 + DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting"); 1.766 + } 1.767 +#endif // ! DEBUG 1.768 + 1.769 + boost::scoped_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); 1.770 + for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { 1.771 + 1.772 + BaseProcess* process = pimpl->mPostProcessingSteps[a]; 1.773 + if( process->IsActive( pFlags)) { 1.774 + 1.775 + if (profiler) { 1.776 + profiler->BeginRegion("postprocess"); 1.777 + } 1.778 + 1.779 + process->ExecuteOnScene ( this ); 1.780 + pimpl->mProgressHandler->Update(); 1.781 + 1.782 + if (profiler) { 1.783 + profiler->EndRegion("postprocess"); 1.784 + } 1.785 + } 1.786 + if( !pimpl->mScene) { 1.787 + break; 1.788 + } 1.789 +#ifdef _DEBUG 1.790 + 1.791 +#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS 1.792 + continue; 1.793 +#endif // no validation 1.794 + 1.795 + // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step 1.796 + if (pimpl->bExtraVerbose) { 1.797 + DefaultLogger::get()->debug("Verbose Import: revalidating data structures"); 1.798 + 1.799 + ValidateDSProcess ds; 1.800 + ds.ExecuteOnScene (this); 1.801 + if( !pimpl->mScene) { 1.802 + DefaultLogger::get()->error("Verbose Import: failed to revalidate data structures"); 1.803 + break; 1.804 + } 1.805 + } 1.806 +#endif // ! DEBUG 1.807 + } 1.808 + 1.809 + // update private scene flags 1.810 + if( pimpl->mScene ) 1.811 + ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags; 1.812 + 1.813 + // clear any data allocated by post-process steps 1.814 + pimpl->mPPShared->Clean(); 1.815 + DefaultLogger::get()->info("Leaving post processing pipeline"); 1.816 + 1.817 + ASSIMP_END_EXCEPTION_REGION(const aiScene*); 1.818 + return pimpl->mScene; 1.819 +} 1.820 + 1.821 +// ------------------------------------------------------------------------------------------------ 1.822 +// Helper function to check whether an extension is supported by ASSIMP 1.823 +bool Importer::IsExtensionSupported(const char* szExtension) const 1.824 +{ 1.825 + return NULL != GetImporter(szExtension); 1.826 +} 1.827 + 1.828 +// ------------------------------------------------------------------------------------------------ 1.829 +size_t Importer::GetImporterCount() const 1.830 +{ 1.831 + return pimpl->mImporter.size(); 1.832 +} 1.833 + 1.834 +// ------------------------------------------------------------------------------------------------ 1.835 +const aiImporterDesc* Importer::GetImporterInfo(size_t index) const 1.836 +{ 1.837 + if (index >= pimpl->mImporter.size()) { 1.838 + return NULL; 1.839 + } 1.840 + return pimpl->mImporter[index]->GetInfo(); 1.841 +} 1.842 + 1.843 + 1.844 +// ------------------------------------------------------------------------------------------------ 1.845 +BaseImporter* Importer::GetImporter (size_t index) const 1.846 +{ 1.847 + if (index >= pimpl->mImporter.size()) { 1.848 + return NULL; 1.849 + } 1.850 + return pimpl->mImporter[index]; 1.851 +} 1.852 + 1.853 +// ------------------------------------------------------------------------------------------------ 1.854 +// Find a loader plugin for a given file extension 1.855 +BaseImporter* Importer::GetImporter (const char* szExtension) const 1.856 +{ 1.857 + return GetImporter(GetImporterIndex(szExtension)); 1.858 +} 1.859 + 1.860 +// ------------------------------------------------------------------------------------------------ 1.861 +// Find a loader plugin for a given file extension 1.862 +size_t Importer::GetImporterIndex (const char* szExtension) const 1.863 +{ 1.864 + ai_assert(szExtension); 1.865 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.866 + 1.867 + // skip over wildcard and dot characters at string head -- 1.868 + for(;*szExtension == '*' || *szExtension == '.'; ++szExtension); 1.869 + 1.870 + std::string ext(szExtension); 1.871 + if (ext.empty()) { 1.872 + return static_cast<size_t>(-1); 1.873 + } 1.874 + std::transform(ext.begin(),ext.end(), ext.begin(), tolower); 1.875 + 1.876 + std::set<std::string> str; 1.877 + for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { 1.878 + str.clear(); 1.879 + 1.880 + (*i)->GetExtensionList(str); 1.881 + for (std::set<std::string>::const_iterator it = str.begin(); it != str.end(); ++it) { 1.882 + if (ext == *it) { 1.883 + return std::distance(static_cast< std::vector<BaseImporter*>::const_iterator >(pimpl->mImporter.begin()), i); 1.884 + } 1.885 + } 1.886 + } 1.887 + ASSIMP_END_EXCEPTION_REGION(size_t); 1.888 + return static_cast<size_t>(-1); 1.889 +} 1.890 + 1.891 +// ------------------------------------------------------------------------------------------------ 1.892 +// Helper function to build a list of all file extensions supported by ASSIMP 1.893 +void Importer::GetExtensionList(aiString& szOut) const 1.894 +{ 1.895 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.896 + std::set<std::string> str; 1.897 + for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { 1.898 + (*i)->GetExtensionList(str); 1.899 + } 1.900 + 1.901 + for (std::set<std::string>::const_iterator it = str.begin();; ) { 1.902 + szOut.Append("*."); 1.903 + szOut.Append((*it).c_str()); 1.904 + 1.905 + if (++it == str.end()) { 1.906 + break; 1.907 + } 1.908 + szOut.Append(";"); 1.909 + } 1.910 + ASSIMP_END_EXCEPTION_REGION(void); 1.911 +} 1.912 + 1.913 +// ------------------------------------------------------------------------------------------------ 1.914 +// Set a configuration property 1.915 +void Importer::SetPropertyInteger(const char* szName, int iValue, 1.916 + bool* bWasExisting /*= NULL*/) 1.917 +{ 1.918 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.919 + SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue,bWasExisting); 1.920 + ASSIMP_END_EXCEPTION_REGION(void); 1.921 +} 1.922 + 1.923 +// ------------------------------------------------------------------------------------------------ 1.924 +// Set a configuration property 1.925 +void Importer::SetPropertyFloat(const char* szName, float iValue, 1.926 + bool* bWasExisting /*= NULL*/) 1.927 +{ 1.928 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.929 + SetGenericProperty<float>(pimpl->mFloatProperties, szName,iValue,bWasExisting); 1.930 + ASSIMP_END_EXCEPTION_REGION(void); 1.931 +} 1.932 + 1.933 +// ------------------------------------------------------------------------------------------------ 1.934 +// Set a configuration property 1.935 +void Importer::SetPropertyString(const char* szName, const std::string& value, 1.936 + bool* bWasExisting /*= NULL*/) 1.937 +{ 1.938 + ASSIMP_BEGIN_EXCEPTION_REGION(); 1.939 + SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value,bWasExisting); 1.940 + ASSIMP_END_EXCEPTION_REGION(void); 1.941 +} 1.942 + 1.943 +// ------------------------------------------------------------------------------------------------ 1.944 +// Get a configuration property 1.945 +int Importer::GetPropertyInteger(const char* szName, 1.946 + int iErrorReturn /*= 0xffffffff*/) const 1.947 +{ 1.948 + return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn); 1.949 +} 1.950 + 1.951 +// ------------------------------------------------------------------------------------------------ 1.952 +// Get a configuration property 1.953 +float Importer::GetPropertyFloat(const char* szName, 1.954 + float iErrorReturn /*= 10e10*/) const 1.955 +{ 1.956 + return GetGenericProperty<float>(pimpl->mFloatProperties,szName,iErrorReturn); 1.957 +} 1.958 + 1.959 +// ------------------------------------------------------------------------------------------------ 1.960 +// Get a configuration property 1.961 +const std::string& Importer::GetPropertyString(const char* szName, 1.962 + const std::string& iErrorReturn /*= ""*/) const 1.963 +{ 1.964 + return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn); 1.965 +} 1.966 + 1.967 +// ------------------------------------------------------------------------------------------------ 1.968 +// Get the memory requirements of a single node 1.969 +inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) 1.970 +{ 1.971 + iScene += sizeof(aiNode); 1.972 + iScene += sizeof(unsigned int) * pcNode->mNumMeshes; 1.973 + iScene += sizeof(void*) * pcNode->mNumChildren; 1.974 + 1.975 + for (unsigned int i = 0; i < pcNode->mNumChildren;++i) { 1.976 + AddNodeWeight(iScene,pcNode->mChildren[i]); 1.977 + } 1.978 +} 1.979 + 1.980 +// ------------------------------------------------------------------------------------------------ 1.981 +// Get the memory requirements of the scene 1.982 +void Importer::GetMemoryRequirements(aiMemoryInfo& in) const 1.983 +{ 1.984 + in = aiMemoryInfo(); 1.985 + aiScene* mScene = pimpl->mScene; 1.986 + 1.987 + // return if we have no scene loaded 1.988 + if (!pimpl->mScene) 1.989 + return; 1.990 + 1.991 + 1.992 + in.total = sizeof(aiScene); 1.993 + 1.994 + // add all meshes 1.995 + for (unsigned int i = 0; i < mScene->mNumMeshes;++i) 1.996 + { 1.997 + in.meshes += sizeof(aiMesh); 1.998 + if (mScene->mMeshes[i]->HasPositions()) { 1.999 + in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; 1.1000 + } 1.1001 + 1.1002 + if (mScene->mMeshes[i]->HasNormals()) { 1.1003 + in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; 1.1004 + } 1.1005 + 1.1006 + if (mScene->mMeshes[i]->HasTangentsAndBitangents()) { 1.1007 + in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices * 2; 1.1008 + } 1.1009 + 1.1010 + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) { 1.1011 + if (mScene->mMeshes[i]->HasVertexColors(a)) { 1.1012 + in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices; 1.1013 + } 1.1014 + else break; 1.1015 + } 1.1016 + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { 1.1017 + if (mScene->mMeshes[i]->HasTextureCoords(a)) { 1.1018 + in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; 1.1019 + } 1.1020 + else break; 1.1021 + } 1.1022 + if (mScene->mMeshes[i]->HasBones()) { 1.1023 + in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones; 1.1024 + for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones;++p) { 1.1025 + in.meshes += sizeof(aiBone); 1.1026 + in.meshes += mScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight); 1.1027 + } 1.1028 + } 1.1029 + in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int))*mScene->mMeshes[i]->mNumFaces; 1.1030 + } 1.1031 + in.total += in.meshes; 1.1032 + 1.1033 + // add all embedded textures 1.1034 + for (unsigned int i = 0; i < mScene->mNumTextures;++i) { 1.1035 + const aiTexture* pc = mScene->mTextures[i]; 1.1036 + in.textures += sizeof(aiTexture); 1.1037 + if (pc->mHeight) { 1.1038 + in.textures += 4 * pc->mHeight * pc->mWidth; 1.1039 + } 1.1040 + else in.textures += pc->mWidth; 1.1041 + } 1.1042 + in.total += in.textures; 1.1043 + 1.1044 + // add all animations 1.1045 + for (unsigned int i = 0; i < mScene->mNumAnimations;++i) { 1.1046 + const aiAnimation* pc = mScene->mAnimations[i]; 1.1047 + in.animations += sizeof(aiAnimation); 1.1048 + 1.1049 + // add all bone anims 1.1050 + for (unsigned int a = 0; a < pc->mNumChannels; ++a) { 1.1051 + const aiNodeAnim* pc2 = pc->mChannels[i]; 1.1052 + in.animations += sizeof(aiNodeAnim); 1.1053 + in.animations += pc2->mNumPositionKeys * sizeof(aiVectorKey); 1.1054 + in.animations += pc2->mNumScalingKeys * sizeof(aiVectorKey); 1.1055 + in.animations += pc2->mNumRotationKeys * sizeof(aiQuatKey); 1.1056 + } 1.1057 + } 1.1058 + in.total += in.animations; 1.1059 + 1.1060 + // add all cameras and all lights 1.1061 + in.total += in.cameras = sizeof(aiCamera) * mScene->mNumCameras; 1.1062 + in.total += in.lights = sizeof(aiLight) * mScene->mNumLights; 1.1063 + 1.1064 + // add all nodes 1.1065 + AddNodeWeight(in.nodes,mScene->mRootNode); 1.1066 + in.total += in.nodes; 1.1067 + 1.1068 + // add all materials 1.1069 + for (unsigned int i = 0; i < mScene->mNumMaterials;++i) { 1.1070 + const aiMaterial* pc = mScene->mMaterials[i]; 1.1071 + in.materials += sizeof(aiMaterial); 1.1072 + in.materials += pc->mNumAllocated * sizeof(void*); 1.1073 + 1.1074 + for (unsigned int a = 0; a < pc->mNumProperties;++a) { 1.1075 + in.materials += pc->mProperties[a]->mDataLength; 1.1076 + } 1.1077 + } 1.1078 + in.total += in.materials; 1.1079 +} 1.1080 +