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