nuclear@0: /* nuclear@0: --------------------------------------------------------------------------- nuclear@0: Open Asset Import Library (assimp) nuclear@0: --------------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the following nuclear@0: conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: --------------------------------------------------------------------------- nuclear@0: */ nuclear@0: /** @file Assimp.cpp nuclear@0: * @brief Implementation of the Plain-C API nuclear@0: */ nuclear@0: nuclear@0: #include "AssimpPCH.h" nuclear@0: #include "assimp/cimport.h" nuclear@0: nuclear@0: #include "GenericProperty.h" nuclear@0: #include "CInterfaceIOWrapper.h" nuclear@0: #include "Importer.h" nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: #ifdef AI_C_THREADSAFE nuclear@0: # include nuclear@0: # include nuclear@0: #endif nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: using namespace Assimp; nuclear@0: nuclear@0: namespace Assimp nuclear@0: { nuclear@0: // underlying structure for aiPropertyStore nuclear@0: typedef BatchLoader::PropertyMap PropertyMap; nuclear@0: nuclear@0: /** Stores the LogStream objects for all active C log streams */ nuclear@0: struct mpred { nuclear@0: bool operator () (const aiLogStream& s0, const aiLogStream& s1) const { nuclear@0: return s0.callback LogStreamMap; nuclear@0: nuclear@0: /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */ nuclear@0: typedef std::list PredefLogStreamMap; nuclear@0: nuclear@0: /** Local storage of all active log streams */ nuclear@0: static LogStreamMap gActiveLogStreams; nuclear@0: nuclear@0: /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */ nuclear@0: static PredefLogStreamMap gPredefinedStreams; nuclear@0: nuclear@0: /** Error message of the last failed import process */ nuclear@0: static std::string gLastErrorString; nuclear@0: nuclear@0: /** Verbose logging active or not? */ nuclear@0: static aiBool gVerboseLogging = false; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: #ifdef AI_C_THREADSAFE nuclear@0: /** Global mutex to manage the access to the logstream map */ nuclear@0: static boost::mutex gLogStreamMutex; nuclear@0: #endif nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Custom LogStream implementation for the C-API nuclear@0: class LogToCallbackRedirector : public LogStream nuclear@0: { nuclear@0: public: nuclear@0: LogToCallbackRedirector(const aiLogStream& s) nuclear@0: : stream (s) { nuclear@0: ai_assert(NULL != s.callback); nuclear@0: } nuclear@0: nuclear@0: ~LogToCallbackRedirector() { nuclear@0: #ifdef AI_C_THREADSAFE nuclear@0: boost::mutex::scoped_lock lock(gLogStreamMutex); nuclear@0: #endif nuclear@0: // (HACK) Check whether the 'stream.user' pointer points to a nuclear@0: // custom LogStream allocated by #aiGetPredefinedLogStream. nuclear@0: // In this case, we need to delete it, too. Of course, this nuclear@0: // might cause strange problems, but the chance is quite low. nuclear@0: nuclear@0: PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(), nuclear@0: gPredefinedStreams.end(), (Assimp::LogStream*)stream.user); nuclear@0: nuclear@0: if (it != gPredefinedStreams.end()) { nuclear@0: delete *it; nuclear@0: gPredefinedStreams.erase(it); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: /** @copydoc LogStream::write */ nuclear@0: void write(const char* message) { nuclear@0: stream.callback(message,stream.user); nuclear@0: } nuclear@0: nuclear@0: private: nuclear@0: aiLogStream stream; nuclear@0: }; nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void ReportSceneNotFoundError() nuclear@0: { nuclear@0: DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. " nuclear@0: "The C-API does not accept scenes produced by the C++ API and vice versa"); nuclear@0: nuclear@0: assert(false); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Reads the given file and returns its content. nuclear@0: const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) nuclear@0: { nuclear@0: return aiImportFileEx(pFile,pFlags,NULL); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS) nuclear@0: { nuclear@0: return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, nuclear@0: aiFileIO* pFS, nuclear@0: const aiPropertyStore* props) nuclear@0: { nuclear@0: ai_assert(NULL != pFile); nuclear@0: nuclear@0: const aiScene* scene = NULL; nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: // create an Importer for this file nuclear@0: Assimp::Importer* imp = new Assimp::Importer(); nuclear@0: nuclear@0: // copy properties nuclear@0: if(props) { nuclear@0: const PropertyMap* pp = reinterpret_cast(props); nuclear@0: ImporterPimpl* pimpl = imp->Pimpl(); nuclear@0: pimpl->mIntProperties = pp->ints; nuclear@0: pimpl->mFloatProperties = pp->floats; nuclear@0: pimpl->mStringProperties = pp->strings; nuclear@0: } nuclear@0: // setup a custom IO system if necessary nuclear@0: if (pFS) { nuclear@0: imp->SetIOHandler( new CIOSystemWrapper (pFS) ); nuclear@0: } nuclear@0: nuclear@0: // and have it read the file nuclear@0: scene = imp->ReadFile( pFile, pFlags); nuclear@0: nuclear@0: // if succeeded, store the importer in the scene and keep it alive nuclear@0: if( scene) { nuclear@0: ScenePrivateData* priv = const_cast( ScenePriv(scene) ); nuclear@0: priv->mOrigImporter = imp; nuclear@0: } nuclear@0: else { nuclear@0: // if failed, extract error code and destroy the import nuclear@0: gLastErrorString = imp->GetErrorString(); nuclear@0: delete imp; nuclear@0: } nuclear@0: nuclear@0: // return imported data. If the import failed the pointer is NULL anyways nuclear@0: ASSIMP_END_EXCEPTION_REGION(const aiScene*); nuclear@0: return scene; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: const aiScene* aiImportFileFromMemory( nuclear@0: const char* pBuffer, nuclear@0: unsigned int pLength, nuclear@0: unsigned int pFlags, nuclear@0: const char* pHint) nuclear@0: { nuclear@0: return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: const aiScene* aiImportFileFromMemoryWithProperties( nuclear@0: const char* pBuffer, nuclear@0: unsigned int pLength, nuclear@0: unsigned int pFlags, nuclear@0: const char* pHint, nuclear@0: const aiPropertyStore* props) nuclear@0: { nuclear@0: ai_assert(NULL != pBuffer && 0 != pLength); nuclear@0: nuclear@0: const aiScene* scene = NULL; nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: // create an Importer for this file nuclear@0: Assimp::Importer* imp = new Assimp::Importer(); nuclear@0: nuclear@0: // copy properties nuclear@0: if(props) { nuclear@0: const PropertyMap* pp = reinterpret_cast(props); nuclear@0: ImporterPimpl* pimpl = imp->Pimpl(); nuclear@0: pimpl->mIntProperties = pp->ints; nuclear@0: pimpl->mFloatProperties = pp->floats; nuclear@0: pimpl->mStringProperties = pp->strings; nuclear@0: } nuclear@0: nuclear@0: // and have it read the file from the memory buffer nuclear@0: scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint); nuclear@0: nuclear@0: // if succeeded, store the importer in the scene and keep it alive nuclear@0: if( scene) { nuclear@0: ScenePrivateData* priv = const_cast( ScenePriv(scene) ); nuclear@0: priv->mOrigImporter = imp; nuclear@0: } nuclear@0: else { nuclear@0: // if failed, extract error code and destroy the import nuclear@0: gLastErrorString = imp->GetErrorString(); nuclear@0: delete imp; nuclear@0: } nuclear@0: // return imported data. If the import failed the pointer is NULL anyways nuclear@0: ASSIMP_END_EXCEPTION_REGION(const aiScene*); nuclear@0: return scene; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Releases all resources associated with the given import process. nuclear@0: void aiReleaseImport( const aiScene* pScene) nuclear@0: { nuclear@0: if (!pScene) { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: // find the importer associated with this data nuclear@0: const ScenePrivateData* priv = ScenePriv(pScene); nuclear@0: if( !priv || !priv->mOrigImporter) { nuclear@0: delete pScene; nuclear@0: } nuclear@0: else { nuclear@0: // deleting the Importer also deletes the scene nuclear@0: // Note: the reason that this is not written as 'delete priv->mOrigImporter' nuclear@0: // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339) nuclear@0: Importer* importer = priv->mOrigImporter; nuclear@0: delete importer; nuclear@0: } nuclear@0: nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene, nuclear@0: unsigned int pFlags) nuclear@0: { nuclear@0: const aiScene* sc = NULL; nuclear@0: nuclear@0: nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: // find the importer associated with this data nuclear@0: const ScenePrivateData* priv = ScenePriv(pScene); nuclear@0: if( !priv || !priv->mOrigImporter) { nuclear@0: ReportSceneNotFoundError(); nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: sc = priv->mOrigImporter->ApplyPostProcessing(pFlags); nuclear@0: nuclear@0: if (!sc) { nuclear@0: aiReleaseImport(pScene); nuclear@0: return NULL; nuclear@0: } nuclear@0: nuclear@0: ASSIMP_END_EXCEPTION_REGION(const aiScene*); nuclear@0: return sc; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void CallbackToLogRedirector (const char* msg, char* dt) nuclear@0: { nuclear@0: ai_assert(NULL != msg && NULL != dt); nuclear@0: LogStream* s = (LogStream*)dt; nuclear@0: nuclear@0: s->write(msg); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file) nuclear@0: { nuclear@0: aiLogStream sout; nuclear@0: nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: LogStream* stream = LogStream::createDefaultStream(pStream,file); nuclear@0: if (!stream) { nuclear@0: sout.callback = NULL; nuclear@0: sout.user = NULL; nuclear@0: } nuclear@0: else { nuclear@0: sout.callback = &CallbackToLogRedirector; nuclear@0: sout.user = (char*)stream; nuclear@0: } nuclear@0: gPredefinedStreams.push_back(stream); nuclear@0: ASSIMP_END_EXCEPTION_REGION(aiLogStream); nuclear@0: return sout; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API void aiAttachLogStream( const aiLogStream* stream ) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: #ifdef AI_C_THREADSAFE nuclear@0: boost::mutex::scoped_lock lock(gLogStreamMutex); nuclear@0: #endif nuclear@0: nuclear@0: LogStream* lg = new LogToCallbackRedirector(*stream); nuclear@0: gActiveLogStreams[*stream] = lg; nuclear@0: nuclear@0: if (DefaultLogger::isNullLogger()) { nuclear@0: DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); nuclear@0: } nuclear@0: DefaultLogger::get()->attachStream(lg); nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: #ifdef AI_C_THREADSAFE nuclear@0: boost::mutex::scoped_lock lock(gLogStreamMutex); nuclear@0: #endif nuclear@0: // find the logstream associated with this data nuclear@0: LogStreamMap::iterator it = gActiveLogStreams.find( *stream); nuclear@0: // it should be there... else the user is playing fools with us nuclear@0: if( it == gActiveLogStreams.end()) { nuclear@0: return AI_FAILURE; nuclear@0: } nuclear@0: DefaultLogger::get()->detatchStream( it->second ); nuclear@0: delete it->second; nuclear@0: nuclear@0: gActiveLogStreams.erase( it); nuclear@0: nuclear@0: if (gActiveLogStreams.empty()) { nuclear@0: DefaultLogger::kill(); nuclear@0: } nuclear@0: ASSIMP_END_EXCEPTION_REGION(aiReturn); nuclear@0: return AI_SUCCESS; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API void aiDetachAllLogStreams(void) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: #ifdef AI_C_THREADSAFE nuclear@0: boost::mutex::scoped_lock lock(gLogStreamMutex); nuclear@0: #endif nuclear@0: for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) { nuclear@0: DefaultLogger::get()->detatchStream( it->second ); nuclear@0: delete it->second; nuclear@0: } nuclear@0: gActiveLogStreams.clear(); nuclear@0: DefaultLogger::kill(); nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API void aiEnableVerboseLogging(aiBool d) nuclear@0: { nuclear@0: if (!DefaultLogger::isNullLogger()) { nuclear@0: DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); nuclear@0: } nuclear@0: gVerboseLogging = d; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns the error text of the last failed import process. nuclear@0: const char* aiGetErrorString() nuclear@0: { nuclear@0: return gLastErrorString.c_str(); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Returns the error text of the last failed import process. nuclear@0: aiBool aiIsExtensionSupported(const char* szExtension) nuclear@0: { nuclear@0: ai_assert(NULL != szExtension); nuclear@0: aiBool candoit=AI_FALSE; nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: // FIXME: no need to create a temporary Importer instance just for that .. nuclear@0: Assimp::Importer tmp; nuclear@0: candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE; nuclear@0: nuclear@0: ASSIMP_END_EXCEPTION_REGION(aiBool); nuclear@0: return candoit; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get a list of all file extensions supported by ASSIMP nuclear@0: void aiGetExtensionList(aiString* szOut) nuclear@0: { nuclear@0: ai_assert(NULL != szOut); nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: // FIXME: no need to create a temporary Importer instance just for that .. nuclear@0: Assimp::Importer tmp; nuclear@0: tmp.GetExtensionList(*szOut); nuclear@0: nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Get the memory requirements for a particular import. nuclear@0: void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn, nuclear@0: C_STRUCT aiMemoryInfo* in) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: nuclear@0: // find the importer associated with this data nuclear@0: const ScenePrivateData* priv = ScenePriv(pIn); nuclear@0: if( !priv || !priv->mOrigImporter) { nuclear@0: ReportSceneNotFoundError(); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: return priv->mOrigImporter->GetMemoryRequirements(*in); nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void) nuclear@0: { nuclear@0: return reinterpret_cast( new PropertyMap() ); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p) nuclear@0: { nuclear@0: delete reinterpret_cast(p); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Importer::SetPropertyInteger nuclear@0: ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: PropertyMap* pp = reinterpret_cast(p); nuclear@0: SetGenericProperty(pp->ints,szName,value,NULL); nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Importer::SetPropertyFloat nuclear@0: ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, float value) nuclear@0: { nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: PropertyMap* pp = reinterpret_cast(p); nuclear@0: SetGenericProperty(pp->floats,szName,value,NULL); nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Importer::SetPropertyString nuclear@0: ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName, nuclear@0: const C_STRUCT aiString* st) nuclear@0: { nuclear@0: if (!st) { nuclear@0: return; nuclear@0: } nuclear@0: ASSIMP_BEGIN_EXCEPTION_REGION(); nuclear@0: PropertyMap* pp = reinterpret_cast(p); nuclear@0: SetGenericProperty(pp->strings,szName,std::string(st->C_Str()),NULL); nuclear@0: ASSIMP_END_EXCEPTION_REGION(void); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Rotation matrix to quaternion nuclear@0: ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat) nuclear@0: { nuclear@0: ai_assert(NULL != quat && NULL != mat); nuclear@0: *quat = aiQuaternion(*mat); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Matrix decomposition nuclear@0: ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling, nuclear@0: aiQuaternion* rotation, nuclear@0: aiVector3D* position) nuclear@0: { nuclear@0: ai_assert(NULL != rotation && NULL != position && NULL != scaling && NULL != mat); nuclear@0: mat->Decompose(*scaling,*rotation,*position); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Matrix transpose nuclear@0: ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat) nuclear@0: { nuclear@0: ai_assert(NULL != mat); nuclear@0: mat->Transpose(); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat) nuclear@0: { nuclear@0: ai_assert(NULL != mat); nuclear@0: mat->Transpose(); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Vector transformation nuclear@0: ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec, nuclear@0: const aiMatrix3x3* mat) nuclear@0: { nuclear@0: ai_assert(NULL != mat && NULL != vec); nuclear@0: *vec *= (*mat); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec, nuclear@0: const aiMatrix4x4* mat) nuclear@0: { nuclear@0: ai_assert(NULL != mat && NULL != vec); nuclear@0: *vec *= (*mat); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Matrix multiplication nuclear@0: ASSIMP_API void aiMultiplyMatrix4( nuclear@0: aiMatrix4x4* dst, nuclear@0: const aiMatrix4x4* src) nuclear@0: { nuclear@0: ai_assert(NULL != dst && NULL != src); nuclear@0: *dst = (*dst) * (*src); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API void aiMultiplyMatrix3( nuclear@0: aiMatrix3x3* dst, nuclear@0: const aiMatrix3x3* src) nuclear@0: { nuclear@0: ai_assert(NULL != dst && NULL != src); nuclear@0: *dst = (*dst) * (*src); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Matrix identity nuclear@0: ASSIMP_API void aiIdentityMatrix3( nuclear@0: aiMatrix3x3* mat) nuclear@0: { nuclear@0: ai_assert(NULL != mat); nuclear@0: *mat = aiMatrix3x3(); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: ASSIMP_API void aiIdentityMatrix4( nuclear@0: aiMatrix4x4* mat) nuclear@0: { nuclear@0: ai_assert(NULL != mat); nuclear@0: *mat = aiMatrix4x4(); nuclear@0: } nuclear@0: nuclear@0: