vrshoot
view libs/assimp/Assimp.cpp @ 1:e7ca128b8713
looks nice :)
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 02 Feb 2014 00:35:22 +0200 |
parents | |
children |
line source
1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
6 Copyright (c) 2006-2012, assimp team
8 All rights reserved.
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41 /** @file Assimp.cpp
42 * @brief Implementation of the Plain-C API
43 */
45 #include "AssimpPCH.h"
46 #include "assimp/cimport.h"
48 #include "GenericProperty.h"
49 #include "CInterfaceIOWrapper.h"
50 #include "Importer.h"
52 // ------------------------------------------------------------------------------------------------
53 #ifdef AI_C_THREADSAFE
54 # include <boost/thread/thread.hpp>
55 # include <boost/thread/mutex.hpp>
56 #endif
57 // ------------------------------------------------------------------------------------------------
58 using namespace Assimp;
60 namespace Assimp
61 {
62 // underlying structure for aiPropertyStore
63 typedef BatchLoader::PropertyMap PropertyMap;
65 /** Stores the LogStream objects for all active C log streams */
66 struct mpred {
67 bool operator () (const aiLogStream& s0, const aiLogStream& s1) const {
68 return s0.callback<s1.callback&&s0.user<s1.user;
69 }
70 };
71 typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
73 /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
74 typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
76 /** Local storage of all active log streams */
77 static LogStreamMap gActiveLogStreams;
79 /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
80 static PredefLogStreamMap gPredefinedStreams;
82 /** Error message of the last failed import process */
83 static std::string gLastErrorString;
85 /** Verbose logging active or not? */
86 static aiBool gVerboseLogging = false;
87 }
90 #ifdef AI_C_THREADSAFE
91 /** Global mutex to manage the access to the logstream map */
92 static boost::mutex gLogStreamMutex;
93 #endif
96 // ------------------------------------------------------------------------------------------------
97 // Custom LogStream implementation for the C-API
98 class LogToCallbackRedirector : public LogStream
99 {
100 public:
101 LogToCallbackRedirector(const aiLogStream& s)
102 : stream (s) {
103 ai_assert(NULL != s.callback);
104 }
106 ~LogToCallbackRedirector() {
107 #ifdef AI_C_THREADSAFE
108 boost::mutex::scoped_lock lock(gLogStreamMutex);
109 #endif
110 // (HACK) Check whether the 'stream.user' pointer points to a
111 // custom LogStream allocated by #aiGetPredefinedLogStream.
112 // In this case, we need to delete it, too. Of course, this
113 // might cause strange problems, but the chance is quite low.
115 PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
116 gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
118 if (it != gPredefinedStreams.end()) {
119 delete *it;
120 gPredefinedStreams.erase(it);
121 }
122 }
124 /** @copydoc LogStream::write */
125 void write(const char* message) {
126 stream.callback(message,stream.user);
127 }
129 private:
130 aiLogStream stream;
131 };
133 // ------------------------------------------------------------------------------------------------
134 void ReportSceneNotFoundError()
135 {
136 DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
137 "The C-API does not accept scenes produced by the C++ API and vice versa");
139 assert(false);
140 }
142 // ------------------------------------------------------------------------------------------------
143 // Reads the given file and returns its content.
144 const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
145 {
146 return aiImportFileEx(pFile,pFlags,NULL);
147 }
149 // ------------------------------------------------------------------------------------------------
150 const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS)
151 {
152 return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
153 }
155 // ------------------------------------------------------------------------------------------------
156 const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags,
157 aiFileIO* pFS,
158 const aiPropertyStore* props)
159 {
160 ai_assert(NULL != pFile);
162 const aiScene* scene = NULL;
163 ASSIMP_BEGIN_EXCEPTION_REGION();
165 // create an Importer for this file
166 Assimp::Importer* imp = new Assimp::Importer();
168 // copy properties
169 if(props) {
170 const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
171 ImporterPimpl* pimpl = imp->Pimpl();
172 pimpl->mIntProperties = pp->ints;
173 pimpl->mFloatProperties = pp->floats;
174 pimpl->mStringProperties = pp->strings;
175 }
176 // setup a custom IO system if necessary
177 if (pFS) {
178 imp->SetIOHandler( new CIOSystemWrapper (pFS) );
179 }
181 // and have it read the file
182 scene = imp->ReadFile( pFile, pFlags);
184 // if succeeded, store the importer in the scene and keep it alive
185 if( scene) {
186 ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
187 priv->mOrigImporter = imp;
188 }
189 else {
190 // if failed, extract error code and destroy the import
191 gLastErrorString = imp->GetErrorString();
192 delete imp;
193 }
195 // return imported data. If the import failed the pointer is NULL anyways
196 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
197 return scene;
198 }
200 // ------------------------------------------------------------------------------------------------
201 const aiScene* aiImportFileFromMemory(
202 const char* pBuffer,
203 unsigned int pLength,
204 unsigned int pFlags,
205 const char* pHint)
206 {
207 return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
208 }
210 // ------------------------------------------------------------------------------------------------
211 const aiScene* aiImportFileFromMemoryWithProperties(
212 const char* pBuffer,
213 unsigned int pLength,
214 unsigned int pFlags,
215 const char* pHint,
216 const aiPropertyStore* props)
217 {
218 ai_assert(NULL != pBuffer && 0 != pLength);
220 const aiScene* scene = NULL;
221 ASSIMP_BEGIN_EXCEPTION_REGION();
223 // create an Importer for this file
224 Assimp::Importer* imp = new Assimp::Importer();
226 // copy properties
227 if(props) {
228 const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
229 ImporterPimpl* pimpl = imp->Pimpl();
230 pimpl->mIntProperties = pp->ints;
231 pimpl->mFloatProperties = pp->floats;
232 pimpl->mStringProperties = pp->strings;
233 }
235 // and have it read the file from the memory buffer
236 scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
238 // if succeeded, store the importer in the scene and keep it alive
239 if( scene) {
240 ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
241 priv->mOrigImporter = imp;
242 }
243 else {
244 // if failed, extract error code and destroy the import
245 gLastErrorString = imp->GetErrorString();
246 delete imp;
247 }
248 // return imported data. If the import failed the pointer is NULL anyways
249 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
250 return scene;
251 }
253 // ------------------------------------------------------------------------------------------------
254 // Releases all resources associated with the given import process.
255 void aiReleaseImport( const aiScene* pScene)
256 {
257 if (!pScene) {
258 return;
259 }
261 ASSIMP_BEGIN_EXCEPTION_REGION();
263 // find the importer associated with this data
264 const ScenePrivateData* priv = ScenePriv(pScene);
265 if( !priv || !priv->mOrigImporter) {
266 delete pScene;
267 }
268 else {
269 // deleting the Importer also deletes the scene
270 // Note: the reason that this is not written as 'delete priv->mOrigImporter'
271 // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
272 Importer* importer = priv->mOrigImporter;
273 delete importer;
274 }
276 ASSIMP_END_EXCEPTION_REGION(void);
277 }
279 // ------------------------------------------------------------------------------------------------
280 ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene,
281 unsigned int pFlags)
282 {
283 const aiScene* sc = NULL;
286 ASSIMP_BEGIN_EXCEPTION_REGION();
288 // find the importer associated with this data
289 const ScenePrivateData* priv = ScenePriv(pScene);
290 if( !priv || !priv->mOrigImporter) {
291 ReportSceneNotFoundError();
292 return NULL;
293 }
295 sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
297 if (!sc) {
298 aiReleaseImport(pScene);
299 return NULL;
300 }
302 ASSIMP_END_EXCEPTION_REGION(const aiScene*);
303 return sc;
304 }
306 // ------------------------------------------------------------------------------------------------
307 void CallbackToLogRedirector (const char* msg, char* dt)
308 {
309 ai_assert(NULL != msg && NULL != dt);
310 LogStream* s = (LogStream*)dt;
312 s->write(msg);
313 }
315 // ------------------------------------------------------------------------------------------------
316 ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file)
317 {
318 aiLogStream sout;
320 ASSIMP_BEGIN_EXCEPTION_REGION();
321 LogStream* stream = LogStream::createDefaultStream(pStream,file);
322 if (!stream) {
323 sout.callback = NULL;
324 sout.user = NULL;
325 }
326 else {
327 sout.callback = &CallbackToLogRedirector;
328 sout.user = (char*)stream;
329 }
330 gPredefinedStreams.push_back(stream);
331 ASSIMP_END_EXCEPTION_REGION(aiLogStream);
332 return sout;
333 }
335 // ------------------------------------------------------------------------------------------------
336 ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
337 {
338 ASSIMP_BEGIN_EXCEPTION_REGION();
340 #ifdef AI_C_THREADSAFE
341 boost::mutex::scoped_lock lock(gLogStreamMutex);
342 #endif
344 LogStream* lg = new LogToCallbackRedirector(*stream);
345 gActiveLogStreams[*stream] = lg;
347 if (DefaultLogger::isNullLogger()) {
348 DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
349 }
350 DefaultLogger::get()->attachStream(lg);
351 ASSIMP_END_EXCEPTION_REGION(void);
352 }
354 // ------------------------------------------------------------------------------------------------
355 ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
356 {
357 ASSIMP_BEGIN_EXCEPTION_REGION();
359 #ifdef AI_C_THREADSAFE
360 boost::mutex::scoped_lock lock(gLogStreamMutex);
361 #endif
362 // find the logstream associated with this data
363 LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
364 // it should be there... else the user is playing fools with us
365 if( it == gActiveLogStreams.end()) {
366 return AI_FAILURE;
367 }
368 DefaultLogger::get()->detatchStream( it->second );
369 delete it->second;
371 gActiveLogStreams.erase( it);
373 if (gActiveLogStreams.empty()) {
374 DefaultLogger::kill();
375 }
376 ASSIMP_END_EXCEPTION_REGION(aiReturn);
377 return AI_SUCCESS;
378 }
380 // ------------------------------------------------------------------------------------------------
381 ASSIMP_API void aiDetachAllLogStreams(void)
382 {
383 ASSIMP_BEGIN_EXCEPTION_REGION();
384 #ifdef AI_C_THREADSAFE
385 boost::mutex::scoped_lock lock(gLogStreamMutex);
386 #endif
387 for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
388 DefaultLogger::get()->detatchStream( it->second );
389 delete it->second;
390 }
391 gActiveLogStreams.clear();
392 DefaultLogger::kill();
393 ASSIMP_END_EXCEPTION_REGION(void);
394 }
396 // ------------------------------------------------------------------------------------------------
397 ASSIMP_API void aiEnableVerboseLogging(aiBool d)
398 {
399 if (!DefaultLogger::isNullLogger()) {
400 DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
401 }
402 gVerboseLogging = d;
403 }
405 // ------------------------------------------------------------------------------------------------
406 // Returns the error text of the last failed import process.
407 const char* aiGetErrorString()
408 {
409 return gLastErrorString.c_str();
410 }
412 // ------------------------------------------------------------------------------------------------
413 // Returns the error text of the last failed import process.
414 aiBool aiIsExtensionSupported(const char* szExtension)
415 {
416 ai_assert(NULL != szExtension);
417 aiBool candoit=AI_FALSE;
418 ASSIMP_BEGIN_EXCEPTION_REGION();
420 // FIXME: no need to create a temporary Importer instance just for that ..
421 Assimp::Importer tmp;
422 candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
424 ASSIMP_END_EXCEPTION_REGION(aiBool);
425 return candoit;
426 }
428 // ------------------------------------------------------------------------------------------------
429 // Get a list of all file extensions supported by ASSIMP
430 void aiGetExtensionList(aiString* szOut)
431 {
432 ai_assert(NULL != szOut);
433 ASSIMP_BEGIN_EXCEPTION_REGION();
435 // FIXME: no need to create a temporary Importer instance just for that ..
436 Assimp::Importer tmp;
437 tmp.GetExtensionList(*szOut);
439 ASSIMP_END_EXCEPTION_REGION(void);
440 }
442 // ------------------------------------------------------------------------------------------------
443 // Get the memory requirements for a particular import.
444 void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
445 C_STRUCT aiMemoryInfo* in)
446 {
447 ASSIMP_BEGIN_EXCEPTION_REGION();
449 // find the importer associated with this data
450 const ScenePrivateData* priv = ScenePriv(pIn);
451 if( !priv || !priv->mOrigImporter) {
452 ReportSceneNotFoundError();
453 return;
454 }
456 return priv->mOrigImporter->GetMemoryRequirements(*in);
457 ASSIMP_END_EXCEPTION_REGION(void);
458 }
460 // ------------------------------------------------------------------------------------------------
461 ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void)
462 {
463 return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
464 }
467 // ------------------------------------------------------------------------------------------------
468 ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p)
469 {
470 delete reinterpret_cast<PropertyMap*>(p);
471 }
473 // ------------------------------------------------------------------------------------------------
474 // Importer::SetPropertyInteger
475 ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value)
476 {
477 ASSIMP_BEGIN_EXCEPTION_REGION();
478 PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
479 SetGenericProperty<int>(pp->ints,szName,value,NULL);
480 ASSIMP_END_EXCEPTION_REGION(void);
481 }
483 // ------------------------------------------------------------------------------------------------
484 // Importer::SetPropertyFloat
485 ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, float value)
486 {
487 ASSIMP_BEGIN_EXCEPTION_REGION();
488 PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
489 SetGenericProperty<float>(pp->floats,szName,value,NULL);
490 ASSIMP_END_EXCEPTION_REGION(void);
491 }
493 // ------------------------------------------------------------------------------------------------
494 // Importer::SetPropertyString
495 ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName,
496 const C_STRUCT aiString* st)
497 {
498 if (!st) {
499 return;
500 }
501 ASSIMP_BEGIN_EXCEPTION_REGION();
502 PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
503 SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()),NULL);
504 ASSIMP_END_EXCEPTION_REGION(void);
505 }
507 // ------------------------------------------------------------------------------------------------
508 // Rotation matrix to quaternion
509 ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
510 {
511 ai_assert(NULL != quat && NULL != mat);
512 *quat = aiQuaternion(*mat);
513 }
515 // ------------------------------------------------------------------------------------------------
516 // Matrix decomposition
517 ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling,
518 aiQuaternion* rotation,
519 aiVector3D* position)
520 {
521 ai_assert(NULL != rotation && NULL != position && NULL != scaling && NULL != mat);
522 mat->Decompose(*scaling,*rotation,*position);
523 }
525 // ------------------------------------------------------------------------------------------------
526 // Matrix transpose
527 ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat)
528 {
529 ai_assert(NULL != mat);
530 mat->Transpose();
531 }
533 // ------------------------------------------------------------------------------------------------
534 ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat)
535 {
536 ai_assert(NULL != mat);
537 mat->Transpose();
538 }
540 // ------------------------------------------------------------------------------------------------
541 // Vector transformation
542 ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec,
543 const aiMatrix3x3* mat)
544 {
545 ai_assert(NULL != mat && NULL != vec);
546 *vec *= (*mat);
547 }
549 // ------------------------------------------------------------------------------------------------
550 ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec,
551 const aiMatrix4x4* mat)
552 {
553 ai_assert(NULL != mat && NULL != vec);
554 *vec *= (*mat);
555 }
557 // ------------------------------------------------------------------------------------------------
558 // Matrix multiplication
559 ASSIMP_API void aiMultiplyMatrix4(
560 aiMatrix4x4* dst,
561 const aiMatrix4x4* src)
562 {
563 ai_assert(NULL != dst && NULL != src);
564 *dst = (*dst) * (*src);
565 }
567 // ------------------------------------------------------------------------------------------------
568 ASSIMP_API void aiMultiplyMatrix3(
569 aiMatrix3x3* dst,
570 const aiMatrix3x3* src)
571 {
572 ai_assert(NULL != dst && NULL != src);
573 *dst = (*dst) * (*src);
574 }
576 // ------------------------------------------------------------------------------------------------
577 // Matrix identity
578 ASSIMP_API void aiIdentityMatrix3(
579 aiMatrix3x3* mat)
580 {
581 ai_assert(NULL != mat);
582 *mat = aiMatrix3x3();
583 }
585 // ------------------------------------------------------------------------------------------------
586 ASSIMP_API void aiIdentityMatrix4(
587 aiMatrix4x4* mat)
588 {
589 ai_assert(NULL != mat);
590 *mat = aiMatrix4x4();
591 }