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