1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2016, 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 /** @file  Assimp.cpp
42  *  @brief Implementation of the Plain-C API
43  */
44 
45 #include <assimp/cimport.h>
46 #include <assimp/LogStream.hpp>
47 #include <assimp/DefaultLogger.hpp>
48 #include <assimp/Importer.hpp>
49 #include <assimp/importerdesc.h>
50 #include <assimp/scene.h>
51 
52 #include "GenericProperty.h"
53 #include "CInterfaceIOWrapper.h"
54 #include "Importer.h"
55 #include "Exceptional.h"
56 #include "ScenePrivate.h"
57 #include "BaseImporter.h"
58 #include <list>
59 
60 // ------------------------------------------------------------------------------------------------
61 #ifndef ASSIMP_BUILD_SINGLETHREADED
62 #   include <thread>
63 #   include <mutex>
64 #endif
65 // ------------------------------------------------------------------------------------------------
66 using namespace Assimp;
67 
68 namespace Assimp
69 {
70     // underlying structure for aiPropertyStore
71     typedef BatchLoader::PropertyMap PropertyMap;
72 
73     /** Stores the LogStream objects for all active C log streams */
74     struct mpred {
operator ()Assimp::mpred75         bool operator  () (const aiLogStream& s0, const aiLogStream& s1) const  {
76             return s0.callback<s1.callback&&s0.user<s1.user;
77         }
78     };
79     typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap;
80 
81     /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */
82     typedef std::list<Assimp::LogStream*> PredefLogStreamMap;
83 
84     /** Local storage of all active log streams */
85     static LogStreamMap gActiveLogStreams;
86 
87     /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */
88     static PredefLogStreamMap gPredefinedStreams;
89 
90     /** Error message of the last failed import process */
91     static std::string gLastErrorString;
92 
93     /** Verbose logging active or not? */
94     static aiBool gVerboseLogging = false;
95 
96     /** will return all registered importers. */
97     void GetImporterInstanceList(std::vector< BaseImporter* >& out);
98 
99     /** will delete all registered importers. */
100     void DeleteImporterInstanceList(std::vector< BaseImporter* >& out);
101 } // namespace assimp
102 
103 
104 #ifndef ASSIMP_BUILD_SINGLETHREADED
105 /** Global mutex to manage the access to the log-stream map */
106 static std::mutex gLogStreamMutex;
107 #endif
108 
109 
110 // ------------------------------------------------------------------------------------------------
111 // Custom LogStream implementation for the C-API
112 class LogToCallbackRedirector : public LogStream
113 {
114 public:
LogToCallbackRedirector(const aiLogStream & s)115     explicit LogToCallbackRedirector(const aiLogStream& s)
116         : stream (s)    {
117             ai_assert(NULL != s.callback);
118     }
119 
~LogToCallbackRedirector()120     ~LogToCallbackRedirector()  {
121 #ifndef ASSIMP_BUILD_SINGLETHREADED
122         std::lock_guard<std::mutex> lock(gLogStreamMutex);
123 #endif
124         // (HACK) Check whether the 'stream.user' pointer points to a
125         // custom LogStream allocated by #aiGetPredefinedLogStream.
126         // In this case, we need to delete it, too. Of course, this
127         // might cause strange problems, but the chance is quite low.
128 
129         PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(),
130             gPredefinedStreams.end(), (Assimp::LogStream*)stream.user);
131 
132         if (it != gPredefinedStreams.end()) {
133             delete *it;
134             gPredefinedStreams.erase(it);
135         }
136     }
137 
138     /** @copydoc LogStream::write */
write(const char * message)139     void write(const char* message) {
140         stream.callback(message,stream.user);
141     }
142 
143 private:
144     aiLogStream stream;
145 };
146 
147 // ------------------------------------------------------------------------------------------------
ReportSceneNotFoundError()148 void ReportSceneNotFoundError()
149 {
150     DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. "
151         "The C-API does not accept scenes produced by the C++ API and vice versa");
152 
153     assert(false);
154 }
155 
156 // ------------------------------------------------------------------------------------------------
157 // Reads the given file and returns its content.
aiImportFile(const char * pFile,unsigned int pFlags)158 const aiScene* aiImportFile( const char* pFile, unsigned int pFlags)
159 {
160     return aiImportFileEx(pFile,pFlags,NULL);
161 }
162 
163 // ------------------------------------------------------------------------------------------------
aiImportFileEx(const char * pFile,unsigned int pFlags,aiFileIO * pFS)164 const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags,  aiFileIO* pFS)
165 {
166     return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL);
167 }
168 
169 // ------------------------------------------------------------------------------------------------
aiImportFileExWithProperties(const char * pFile,unsigned int pFlags,aiFileIO * pFS,const aiPropertyStore * props)170 const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags,
171     aiFileIO* pFS,
172     const aiPropertyStore* props)
173 {
174     ai_assert(NULL != pFile);
175 
176     const aiScene* scene = NULL;
177     ASSIMP_BEGIN_EXCEPTION_REGION();
178 
179     // create an Importer for this file
180     Assimp::Importer* imp = new Assimp::Importer();
181 
182     // copy properties
183     if(props) {
184         const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
185         ImporterPimpl* pimpl = imp->Pimpl();
186         pimpl->mIntProperties = pp->ints;
187         pimpl->mFloatProperties = pp->floats;
188         pimpl->mStringProperties = pp->strings;
189         pimpl->mMatrixProperties = pp->matrices;
190     }
191     // setup a custom IO system if necessary
192     if (pFS)    {
193         imp->SetIOHandler( new CIOSystemWrapper (pFS) );
194     }
195 
196     // and have it read the file
197     scene = imp->ReadFile( pFile, pFlags);
198 
199     // if succeeded, store the importer in the scene and keep it alive
200     if( scene)  {
201         ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
202         priv->mOrigImporter = imp;
203     }
204     else    {
205         // if failed, extract error code and destroy the import
206         gLastErrorString = imp->GetErrorString();
207         delete imp;
208     }
209 
210     // return imported data. If the import failed the pointer is NULL anyways
211     ASSIMP_END_EXCEPTION_REGION(const aiScene*);
212     return scene;
213 }
214 
215 // ------------------------------------------------------------------------------------------------
aiImportFileFromMemory(const char * pBuffer,unsigned int pLength,unsigned int pFlags,const char * pHint)216 const aiScene* aiImportFileFromMemory(
217     const char* pBuffer,
218     unsigned int pLength,
219     unsigned int pFlags,
220     const char* pHint)
221 {
222     return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL);
223 }
224 
225 // ------------------------------------------------------------------------------------------------
aiImportFileFromMemoryWithProperties(const char * pBuffer,unsigned int pLength,unsigned int pFlags,const char * pHint,const aiPropertyStore * props)226 const aiScene* aiImportFileFromMemoryWithProperties(
227     const char* pBuffer,
228     unsigned int pLength,
229     unsigned int pFlags,
230     const char* pHint,
231     const aiPropertyStore* props)
232 {
233     ai_assert( NULL != pBuffer );
234     ai_assert( 0 != pLength );
235 
236     const aiScene* scene = NULL;
237     ASSIMP_BEGIN_EXCEPTION_REGION();
238 
239     // create an Importer for this file
240     Assimp::Importer* imp = new Assimp::Importer();
241 
242     // copy properties
243     if(props) {
244         const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props);
245         ImporterPimpl* pimpl = imp->Pimpl();
246         pimpl->mIntProperties = pp->ints;
247         pimpl->mFloatProperties = pp->floats;
248         pimpl->mStringProperties = pp->strings;
249         pimpl->mMatrixProperties = pp->matrices;
250     }
251 
252     // and have it read the file from the memory buffer
253     scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint);
254 
255     // if succeeded, store the importer in the scene and keep it alive
256     if( scene)  {
257          ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) );
258          priv->mOrigImporter = imp;
259     }
260     else    {
261         // if failed, extract error code and destroy the import
262         gLastErrorString = imp->GetErrorString();
263         delete imp;
264     }
265     // return imported data. If the import failed the pointer is NULL anyways
266     ASSIMP_END_EXCEPTION_REGION(const aiScene*);
267     return scene;
268 }
269 
270 // ------------------------------------------------------------------------------------------------
271 // Releases all resources associated with the given import process.
aiReleaseImport(const aiScene * pScene)272 void aiReleaseImport( const aiScene* pScene)
273 {
274     if (!pScene) {
275         return;
276     }
277 
278     ASSIMP_BEGIN_EXCEPTION_REGION();
279 
280     // find the importer associated with this data
281     const ScenePrivateData* priv = ScenePriv(pScene);
282     if( !priv || !priv->mOrigImporter)  {
283         delete pScene;
284     }
285     else {
286         // deleting the Importer also deletes the scene
287         // Note: the reason that this is not written as 'delete priv->mOrigImporter'
288         // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339)
289         Importer* importer = priv->mOrigImporter;
290         delete importer;
291     }
292 
293     ASSIMP_END_EXCEPTION_REGION(void);
294 }
295 
296 // ------------------------------------------------------------------------------------------------
aiApplyPostProcessing(const aiScene * pScene,unsigned int pFlags)297 ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene,
298     unsigned int pFlags)
299 {
300     const aiScene* sc = NULL;
301 
302 
303     ASSIMP_BEGIN_EXCEPTION_REGION();
304 
305     // find the importer associated with this data
306     const ScenePrivateData* priv = ScenePriv(pScene);
307     if( !priv || !priv->mOrigImporter)  {
308         ReportSceneNotFoundError();
309         return NULL;
310     }
311 
312     sc = priv->mOrigImporter->ApplyPostProcessing(pFlags);
313 
314     if (!sc) {
315         aiReleaseImport(pScene);
316         return NULL;
317     }
318 
319     ASSIMP_END_EXCEPTION_REGION(const aiScene*);
320     return sc;
321 }
322 
323 // ------------------------------------------------------------------------------------------------
aiApplyCustomizedPostProcessing(const aiScene * scene,BaseProcess * process,bool requestValidation)324 ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing( const aiScene *scene,
325                                                            BaseProcess* process,
326                                                            bool requestValidation ) {
327     const aiScene* sc( NULL );
328 
329     ASSIMP_BEGIN_EXCEPTION_REGION();
330 
331     // find the importer associated with this data
332     const ScenePrivateData* priv = ScenePriv( scene );
333     if ( NULL == priv || NULL == priv->mOrigImporter ) {
334         ReportSceneNotFoundError();
335         return NULL;
336     }
337 
338     sc = priv->mOrigImporter->ApplyCustomizedPostProcessing( process, requestValidation );
339 
340     if ( !sc ) {
341         aiReleaseImport( scene );
342         return NULL;
343     }
344 
345     ASSIMP_END_EXCEPTION_REGION( const aiScene* );
346 
347     return sc;
348 }
349 
350 // ------------------------------------------------------------------------------------------------
CallbackToLogRedirector(const char * msg,char * dt)351 void CallbackToLogRedirector (const char* msg, char* dt)
352 {
353     ai_assert( NULL != msg );
354     ai_assert( NULL != dt );
355     LogStream* s = (LogStream*)dt;
356 
357     s->write(msg);
358 }
359 
360 // ------------------------------------------------------------------------------------------------
aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char * file)361 ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file)
362 {
363     aiLogStream sout;
364 
365     ASSIMP_BEGIN_EXCEPTION_REGION();
366     LogStream* stream = LogStream::createDefaultStream(pStream,file);
367     if (!stream) {
368         sout.callback = NULL;
369         sout.user = NULL;
370     }
371     else {
372         sout.callback = &CallbackToLogRedirector;
373         sout.user = (char*)stream;
374     }
375     gPredefinedStreams.push_back(stream);
376     ASSIMP_END_EXCEPTION_REGION(aiLogStream);
377     return sout;
378 }
379 
380 // ------------------------------------------------------------------------------------------------
aiAttachLogStream(const aiLogStream * stream)381 ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
382 {
383     ASSIMP_BEGIN_EXCEPTION_REGION();
384 
385 #ifndef ASSIMP_BUILD_SINGLETHREADED
386     std::lock_guard<std::mutex> lock(gLogStreamMutex);
387 #endif
388 
389     LogStream* lg = new LogToCallbackRedirector(*stream);
390     gActiveLogStreams[*stream] = lg;
391 
392     if (DefaultLogger::isNullLogger()) {
393         DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
394     }
395     DefaultLogger::get()->attachStream(lg);
396     ASSIMP_END_EXCEPTION_REGION(void);
397 }
398 
399 // ------------------------------------------------------------------------------------------------
aiDetachLogStream(const aiLogStream * stream)400 ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
401 {
402     ASSIMP_BEGIN_EXCEPTION_REGION();
403 
404 #ifndef ASSIMP_BUILD_SINGLETHREADED
405     std::lock_guard<std::mutex> lock(gLogStreamMutex);
406 #endif
407     // find the log-stream associated with this data
408     LogStreamMap::iterator it = gActiveLogStreams.find( *stream);
409     // it should be there... else the user is playing fools with us
410     if( it == gActiveLogStreams.end())  {
411         return AI_FAILURE;
412     }
413     DefaultLogger::get()->detatchStream( it->second );
414     delete it->second;
415 
416     gActiveLogStreams.erase( it);
417 
418     if (gActiveLogStreams.empty()) {
419         DefaultLogger::kill();
420     }
421     ASSIMP_END_EXCEPTION_REGION(aiReturn);
422     return AI_SUCCESS;
423 }
424 
425 // ------------------------------------------------------------------------------------------------
aiDetachAllLogStreams(void)426 ASSIMP_API void aiDetachAllLogStreams(void)
427 {
428     ASSIMP_BEGIN_EXCEPTION_REGION();
429 #ifndef ASSIMP_BUILD_SINGLETHREADED
430     std::lock_guard<std::mutex> lock(gLogStreamMutex);
431 #endif
432     Logger *logger( DefaultLogger::get() );
433     if ( NULL == logger ) {
434         return;
435     }
436 
437     for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
438         logger->detatchStream( it->second );
439         delete it->second;
440     }
441     gActiveLogStreams.clear();
442     DefaultLogger::kill();
443 
444     ASSIMP_END_EXCEPTION_REGION(void);
445 }
446 
447 // ------------------------------------------------------------------------------------------------
aiEnableVerboseLogging(aiBool d)448 ASSIMP_API void aiEnableVerboseLogging(aiBool d)
449 {
450     if (!DefaultLogger::isNullLogger()) {
451         DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL));
452     }
453     gVerboseLogging = d;
454 }
455 
456 // ------------------------------------------------------------------------------------------------
457 // Returns the error text of the last failed import process.
aiGetErrorString()458 const char* aiGetErrorString()
459 {
460     return gLastErrorString.c_str();
461 }
462 
463 // -----------------------------------------------------------------------------------------------
464 // Return the description of a importer given its index
aiGetImportFormatDescription(size_t pIndex)465 const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex)
466 {
467     return Importer().GetImporterInfo(pIndex);
468 }
469 
470 // -----------------------------------------------------------------------------------------------
471 // Return the number of importers
aiGetImportFormatCount(void)472 size_t aiGetImportFormatCount(void)
473 {
474     return Importer().GetImporterCount();
475 }
476 
477 // ------------------------------------------------------------------------------------------------
478 // Returns the error text of the last failed import process.
aiIsExtensionSupported(const char * szExtension)479 aiBool aiIsExtensionSupported(const char* szExtension)
480 {
481     ai_assert(NULL != szExtension);
482     aiBool candoit=AI_FALSE;
483     ASSIMP_BEGIN_EXCEPTION_REGION();
484 
485     // FIXME: no need to create a temporary Importer instance just for that ..
486     Assimp::Importer tmp;
487     candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE;
488 
489     ASSIMP_END_EXCEPTION_REGION(aiBool);
490     return candoit;
491 }
492 
493 // ------------------------------------------------------------------------------------------------
494 // Get a list of all file extensions supported by ASSIMP
aiGetExtensionList(aiString * szOut)495 void aiGetExtensionList(aiString* szOut)
496 {
497     ai_assert(NULL != szOut);
498     ASSIMP_BEGIN_EXCEPTION_REGION();
499 
500     // FIXME: no need to create a temporary Importer instance just for that ..
501     Assimp::Importer tmp;
502     tmp.GetExtensionList(*szOut);
503 
504     ASSIMP_END_EXCEPTION_REGION(void);
505 }
506 
507 // ------------------------------------------------------------------------------------------------
508 // Get the memory requirements for a particular import.
aiGetMemoryRequirements(const C_STRUCT aiScene * pIn,C_STRUCT aiMemoryInfo * in)509 void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn,
510     C_STRUCT aiMemoryInfo* in)
511 {
512     ASSIMP_BEGIN_EXCEPTION_REGION();
513 
514     // find the importer associated with this data
515     const ScenePrivateData* priv = ScenePriv(pIn);
516     if( !priv || !priv->mOrigImporter)  {
517         ReportSceneNotFoundError();
518         return;
519     }
520 
521     return priv->mOrigImporter->GetMemoryRequirements(*in);
522     ASSIMP_END_EXCEPTION_REGION(void);
523 }
524 
525 // ------------------------------------------------------------------------------------------------
aiCreatePropertyStore(void)526 ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void)
527 {
528     return reinterpret_cast<aiPropertyStore*>( new PropertyMap() );
529 }
530 
531 // ------------------------------------------------------------------------------------------------
aiReleasePropertyStore(aiPropertyStore * p)532 ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p)
533 {
534     delete reinterpret_cast<PropertyMap*>(p);
535 }
536 
537 // ------------------------------------------------------------------------------------------------
538 // Importer::SetPropertyInteger
aiSetImportPropertyInteger(aiPropertyStore * p,const char * szName,int value)539 ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value)
540 {
541     ASSIMP_BEGIN_EXCEPTION_REGION();
542     PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
543     SetGenericProperty<int>(pp->ints,szName,value);
544     ASSIMP_END_EXCEPTION_REGION(void);
545 }
546 
547 // ------------------------------------------------------------------------------------------------
548 // Importer::SetPropertyFloat
aiSetImportPropertyFloat(aiPropertyStore * p,const char * szName,float value)549 ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, float value)
550 {
551     ASSIMP_BEGIN_EXCEPTION_REGION();
552     PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
553     SetGenericProperty<float>(pp->floats,szName,value);
554     ASSIMP_END_EXCEPTION_REGION(void);
555 }
556 
557 // ------------------------------------------------------------------------------------------------
558 // Importer::SetPropertyString
aiSetImportPropertyString(aiPropertyStore * p,const char * szName,const C_STRUCT aiString * st)559 ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName,
560     const C_STRUCT aiString* st)
561 {
562     if (!st) {
563         return;
564     }
565     ASSIMP_BEGIN_EXCEPTION_REGION();
566     PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
567     SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()));
568     ASSIMP_END_EXCEPTION_REGION(void);
569 }
570 
571 // ------------------------------------------------------------------------------------------------
572 // Importer::SetPropertyMatrix
aiSetImportPropertyMatrix(aiPropertyStore * p,const char * szName,const C_STRUCT aiMatrix4x4 * mat)573 ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName,
574     const C_STRUCT aiMatrix4x4* mat)
575 {
576     if (!mat) {
577         return;
578     }
579     ASSIMP_BEGIN_EXCEPTION_REGION();
580     PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
581     SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat);
582     ASSIMP_END_EXCEPTION_REGION(void);
583 }
584 
585 // ------------------------------------------------------------------------------------------------
586 // Rotation matrix to quaternion
aiCreateQuaternionFromMatrix(aiQuaternion * quat,const aiMatrix3x3 * mat)587 ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
588 {
589     ai_assert( NULL != quat );
590     ai_assert( NULL != mat );
591     *quat = aiQuaternion(*mat);
592 }
593 
594 // ------------------------------------------------------------------------------------------------
595 // Matrix decomposition
aiDecomposeMatrix(const aiMatrix4x4 * mat,aiVector3D * scaling,aiQuaternion * rotation,aiVector3D * position)596 ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling,
597     aiQuaternion* rotation,
598     aiVector3D* position)
599 {
600     ai_assert( NULL != rotation );
601     ai_assert( NULL != position );
602     ai_assert( NULL != scaling );
603     ai_assert( NULL != mat );
604     mat->Decompose(*scaling,*rotation,*position);
605 }
606 
607 // ------------------------------------------------------------------------------------------------
608 // Matrix transpose
aiTransposeMatrix3(aiMatrix3x3 * mat)609 ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat)
610 {
611     ai_assert(NULL != mat);
612     mat->Transpose();
613 }
614 
615 // ------------------------------------------------------------------------------------------------
aiTransposeMatrix4(aiMatrix4x4 * mat)616 ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat)
617 {
618     ai_assert(NULL != mat);
619     mat->Transpose();
620 }
621 
622 // ------------------------------------------------------------------------------------------------
623 // Vector transformation
aiTransformVecByMatrix3(aiVector3D * vec,const aiMatrix3x3 * mat)624 ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec,
625     const aiMatrix3x3* mat)
626 {
627     ai_assert( NULL != mat );
628     ai_assert( NULL != vec);
629     *vec *= (*mat);
630 }
631 
632 // ------------------------------------------------------------------------------------------------
aiTransformVecByMatrix4(aiVector3D * vec,const aiMatrix4x4 * mat)633 ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec,
634     const aiMatrix4x4* mat)
635 {
636     ai_assert( NULL != mat );
637     ai_assert( NULL != vec );
638 
639     *vec *= (*mat);
640 }
641 
642 // ------------------------------------------------------------------------------------------------
643 // Matrix multiplication
aiMultiplyMatrix4(aiMatrix4x4 * dst,const aiMatrix4x4 * src)644 ASSIMP_API void aiMultiplyMatrix4(
645     aiMatrix4x4* dst,
646     const aiMatrix4x4* src)
647 {
648     ai_assert( NULL != dst );
649     ai_assert( NULL != src );
650     *dst = (*dst) * (*src);
651 }
652 
653 // ------------------------------------------------------------------------------------------------
aiMultiplyMatrix3(aiMatrix3x3 * dst,const aiMatrix3x3 * src)654 ASSIMP_API void aiMultiplyMatrix3(
655     aiMatrix3x3* dst,
656     const aiMatrix3x3* src)
657 {
658     ai_assert( NULL != dst );
659     ai_assert( NULL != src );
660     *dst = (*dst) * (*src);
661 }
662 
663 // ------------------------------------------------------------------------------------------------
664 // Matrix identity
aiIdentityMatrix3(aiMatrix3x3 * mat)665 ASSIMP_API void aiIdentityMatrix3(
666     aiMatrix3x3* mat)
667 {
668     ai_assert(NULL != mat);
669     *mat = aiMatrix3x3();
670 }
671 
672 // ------------------------------------------------------------------------------------------------
aiIdentityMatrix4(aiMatrix4x4 * mat)673 ASSIMP_API void aiIdentityMatrix4(
674     aiMatrix4x4* mat)
675 {
676     ai_assert(NULL != mat);
677     *mat = aiMatrix4x4();
678 }
679 
680 // ------------------------------------------------------------------------------------------------
aiGetImporterDesc(const char * extension)681 ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) {
682     if( NULL == extension ) {
683         return NULL;
684     }
685     const aiImporterDesc *desc( NULL );
686     std::vector< BaseImporter* > out;
687     GetImporterInstanceList( out );
688     for( size_t i = 0; i < out.size(); ++i ) {
689         if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) {
690             desc = out[ i ]->GetInfo();
691             break;
692         }
693     }
694 
695     DeleteImporterInstanceList(out);
696 
697     return desc;
698 }
699 
700 // ------------------------------------------------------------------------------------------------
701