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