diff options
author | Gordon MacPherson <gordon@gordonite.tech> | 2020-12-22 21:31:06 +0000 |
---|---|---|
committer | Gordon MacPherson <gordon@gordonite.tech> | 2020-12-22 21:31:06 +0000 |
commit | 5b5fdb0adf99baab0ebcc872bb3c26bdff707a2a (patch) | |
tree | 5cacda57a8b34083ac7f454fa908bebcf3222256 /thirdparty/assimp/code | |
parent | 30d469a5e0f70860f3c4ce4508d6564ca389320b (diff) |
remove assimp pending fbx upgrade
Diffstat (limited to 'thirdparty/assimp/code')
140 files changed, 0 insertions, 44790 deletions
diff --git a/thirdparty/assimp/code/CApi/AssimpCExport.cpp b/thirdparty/assimp/code/CApi/AssimpCExport.cpp deleted file mode 100644 index 7557edcfc6..0000000000 --- a/thirdparty/assimp/code/CApi/AssimpCExport.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file AssimpCExport.cpp -Assimp C export interface. See Exporter.cpp for some notes. -*/ - -#ifndef ASSIMP_BUILD_NO_EXPORT - -#include "CInterfaceIOWrapper.h" -#include <assimp/SceneCombiner.h> -#include "Common/ScenePrivate.h" -#include <assimp/Exporter.hpp> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API size_t aiGetExportFormatCount(void) -{ - return Exporter().GetExportFormatCount(); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index) -{ - // Note: this is valid as the index always pertains to a built-in exporter, - // for which the returned structure is guaranteed to be of static storage duration. - Exporter exporter; - const aiExportFormatDesc* orig( exporter.GetExportFormatDescription( index ) ); - if (NULL == orig) { - return NULL; - } - - aiExportFormatDesc *desc = new aiExportFormatDesc; - desc->description = new char[ strlen( orig->description ) + 1 ](); - ::strncpy( (char*) desc->description, orig->description, strlen( orig->description ) ); - desc->fileExtension = new char[ strlen( orig->fileExtension ) + 1 ](); - ::strncpy( ( char* ) desc->fileExtension, orig->fileExtension, strlen( orig->fileExtension ) ); - desc->id = new char[ strlen( orig->id ) + 1 ](); - ::strncpy( ( char* ) desc->id, orig->id, strlen( orig->id ) ); - - return desc; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiReleaseExportFormatDescription( const aiExportFormatDesc *desc ) { - if (NULL == desc) { - return; - } - - delete [] desc->description; - delete [] desc->fileExtension; - delete [] desc->id; - delete desc; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut) -{ - if (!pOut || !pIn) { - return; - } - - SceneCombiner::CopyScene(pOut,pIn,true); - ScenePriv(*pOut)->mIsCopy = true; -} - - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiFreeScene(const C_STRUCT aiScene* pIn) -{ - // note: aiReleaseImport() is also able to delete scene copies, but in addition - // it also handles scenes with import metadata. - delete pIn; -} - - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing ) -{ - return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing); -} - - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, aiFileIO* pIO, unsigned int pPreprocessing ) -{ - Exporter exp; - - if (pIO) { - exp.SetIOHandler(new CIOSystemWrapper(pIO)); - } - return exp.Export(pScene,pFormatId,pFileName,pPreprocessing); -} - - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing ) -{ - Exporter exp; - if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) { - return NULL; - } - const aiExportDataBlob* blob = exp.GetOrphanedBlob(); - ai_assert(blob); - - return blob; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API C_STRUCT void aiReleaseExportBlob( const aiExportDataBlob* pData ) -{ - delete pData; -} - -#endif // !ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp b/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp deleted file mode 100644 index 5a3a49565a..0000000000 --- a/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file aiFileIO -> IOSystem wrapper*/ - -#include "CInterfaceIOWrapper.h" - -namespace Assimp { - -CIOStreamWrapper::~CIOStreamWrapper(void) -{ - /* Various places depend on this destructor to close the file */ - if (mFile) { - mIO->mFileSystem->CloseProc(mIO->mFileSystem, mFile); - mFile = nullptr; - } -} - -// ................................................................... -size_t CIOStreamWrapper::Read(void* pvBuffer, - size_t pSize, - size_t pCount -){ - // need to typecast here as C has no void* - return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount); -} - -// ................................................................... -size_t CIOStreamWrapper::Write(const void* pvBuffer, - size_t pSize, - size_t pCount -){ - // need to typecast here as C has no void* - return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount); -} - -// ................................................................... -aiReturn CIOStreamWrapper::Seek(size_t pOffset, - aiOrigin pOrigin -){ - return mFile->SeekProc(mFile,pOffset,pOrigin); -} - -// ................................................................... -size_t CIOStreamWrapper::Tell(void) const { - return mFile->TellProc(mFile); -} - -// ................................................................... -size_t CIOStreamWrapper::FileSize() const { - return mFile->FileSizeProc(mFile); -} - -// ................................................................... -void CIOStreamWrapper::Flush () { - return mFile->FlushProc(mFile); -} - -// ------------------------------------------------------------------------------------------------ -// Custom IOStream implementation for the C-API -bool CIOSystemWrapper::Exists( const char* pFile) const { - aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,"rb"); - if (p){ - mFileSystem->CloseProc(mFileSystem,p); - return true; - } - return false; -} - -// ................................................................... -char CIOSystemWrapper::getOsSeparator() const { -#ifndef _WIN32 - return '/'; -#else - return '\\'; -#endif -} - -// ................................................................... -IOStream* CIOSystemWrapper::Open(const char* pFile,const char* pMode) { - aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode); - if (!p) { - return NULL; - } - return new CIOStreamWrapper(p, this); -} - -// ................................................................... -void CIOSystemWrapper::Close( IOStream* pFile) { - if (!pFile) { - return; - } - delete pFile; -} - -} diff --git a/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.h b/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.h deleted file mode 100644 index 2162320302..0000000000 --- a/thirdparty/assimp/code/CApi/CInterfaceIOWrapper.h +++ /dev/null @@ -1,99 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file aiFileIO -> IOSystem wrapper*/ - -#ifndef AI_CIOSYSTEM_H_INCLUDED -#define AI_CIOSYSTEM_H_INCLUDED - -#include <assimp/cfileio.h> -#include <assimp/IOStream.hpp> -#include <assimp/IOSystem.hpp> - -namespace Assimp { - -class CIOSystemWrapper; - -// ------------------------------------------------------------------------------------------------ -// Custom IOStream implementation for the C-API -class CIOStreamWrapper : public IOStream -{ -public: - explicit CIOStreamWrapper(aiFile* pFile, CIOSystemWrapper* io) - : mFile(pFile), - mIO(io) - {} - ~CIOStreamWrapper(void); - - size_t Read(void* pvBuffer, size_t pSize, size_t pCount); - size_t Write(const void* pvBuffer, size_t pSize, size_t pCount); - aiReturn Seek(size_t pOffset, aiOrigin pOrigin); - size_t Tell(void) const; - size_t FileSize() const; - void Flush(); - -private: - aiFile* mFile; - CIOSystemWrapper* mIO; -}; - -class CIOSystemWrapper : public IOSystem -{ - friend class CIOStreamWrapper; -public: - explicit CIOSystemWrapper(aiFileIO* pFile) - : mFileSystem(pFile) - {} - - bool Exists( const char* pFile) const; - char getOsSeparator() const; - IOStream* Open(const char* pFile,const char* pMode = "rb"); - void Close( IOStream* pFile); -private: - aiFileIO* mFileSystem; -}; - -} - -#endif - diff --git a/thirdparty/assimp/code/Common/Assimp.cpp b/thirdparty/assimp/code/Common/Assimp.cpp deleted file mode 100644 index 178b2c01d0..0000000000 --- a/thirdparty/assimp/code/Common/Assimp.cpp +++ /dev/null @@ -1,695 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -/** @file Assimp.cpp - * @brief Implementation of the Plain-C API - */ - -#include <assimp/cimport.h> -#include <assimp/LogStream.hpp> -#include <assimp/DefaultLogger.hpp> -#include <assimp/Importer.hpp> -#include <assimp/importerdesc.h> -#include <assimp/scene.h> -#include <assimp/GenericProperty.h> -#include <assimp/Exceptional.h> -#include <assimp/BaseImporter.h> - -#include "CApi/CInterfaceIOWrapper.h" -#include "Importer.h" -#include "ScenePrivate.h" - -#include <list> - -// ------------------------------------------------------------------------------------------------ -#ifndef ASSIMP_BUILD_SINGLETHREADED -# include <thread> -# include <mutex> -#endif -// ------------------------------------------------------------------------------------------------ -using namespace Assimp; - -namespace Assimp { - // underlying structure for aiPropertyStore - typedef BatchLoader::PropertyMap PropertyMap; - - /** Stores the LogStream objects for all active C log streams */ - struct mpred { - bool operator () (const aiLogStream& s0, const aiLogStream& s1) const { - return s0.callback<s1.callback&&s0.user<s1.user; - } - }; - typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap; - - /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */ - typedef std::list<Assimp::LogStream*> PredefLogStreamMap; - - /** Local storage of all active log streams */ - static LogStreamMap gActiveLogStreams; - - /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */ - static PredefLogStreamMap gPredefinedStreams; - - /** Error message of the last failed import process */ - static std::string gLastErrorString; - - /** Verbose logging active or not? */ - static aiBool gVerboseLogging = false; - - /** will return all registered importers. */ - void GetImporterInstanceList(std::vector< BaseImporter* >& out); - - /** will delete all registered importers. */ - void DeleteImporterInstanceList(std::vector< BaseImporter* >& out); -} // namespace assimp - - -#ifndef ASSIMP_BUILD_SINGLETHREADED -/** Global mutex to manage the access to the log-stream map */ -static std::mutex gLogStreamMutex; -#endif - -// ------------------------------------------------------------------------------------------------ -// Custom LogStream implementation for the C-API -class LogToCallbackRedirector : public LogStream { -public: - explicit LogToCallbackRedirector(const aiLogStream& s) - : stream (s) { - ai_assert(NULL != s.callback); - } - - ~LogToCallbackRedirector() { -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard<std::mutex> lock(gLogStreamMutex); -#endif - // (HACK) Check whether the 'stream.user' pointer points to a - // custom LogStream allocated by #aiGetPredefinedLogStream. - // In this case, we need to delete it, too. Of course, this - // might cause strange problems, but the chance is quite low. - - PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(), - gPredefinedStreams.end(), (Assimp::LogStream*)stream.user); - - if (it != gPredefinedStreams.end()) { - delete *it; - gPredefinedStreams.erase(it); - } - } - - /** @copydoc LogStream::write */ - void write(const char* message) { - stream.callback(message,stream.user); - } - -private: - aiLogStream stream; -}; - -// ------------------------------------------------------------------------------------------------ -void ReportSceneNotFoundError() { - ASSIMP_LOG_ERROR("Unable to find the Assimp::Importer for this aiScene. " - "The C-API does not accept scenes produced by the C++ API and vice versa"); - - ai_assert(false); -} - -// ------------------------------------------------------------------------------------------------ -// Reads the given file and returns its content. -const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) { - return aiImportFileEx(pFile,pFlags,NULL); -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS) { - return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL); -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, - aiFileIO* pFS, const aiPropertyStore* props) { - ai_assert(NULL != pFile); - - const aiScene* scene = NULL; - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // create an Importer for this file - Assimp::Importer* imp = new Assimp::Importer(); - - // copy properties - if(props) { - const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props); - ImporterPimpl* pimpl = imp->Pimpl(); - pimpl->mIntProperties = pp->ints; - pimpl->mFloatProperties = pp->floats; - pimpl->mStringProperties = pp->strings; - pimpl->mMatrixProperties = pp->matrices; - } - // setup a custom IO system if necessary - if (pFS) { - imp->SetIOHandler( new CIOSystemWrapper (pFS) ); - } - - // and have it read the file - scene = imp->ReadFile( pFile, pFlags); - - // if succeeded, store the importer in the scene and keep it alive - if( scene) { - ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) ); - priv->mOrigImporter = imp; - } else { - // if failed, extract error code and destroy the import - gLastErrorString = imp->GetErrorString(); - delete imp; - } - - // return imported data. If the import failed the pointer is NULL anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - - return scene; -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileFromMemory( - const char* pBuffer, - unsigned int pLength, - unsigned int pFlags, - const char* pHint) -{ - return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL); -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileFromMemoryWithProperties( - const char* pBuffer, - unsigned int pLength, - unsigned int pFlags, - const char* pHint, - const aiPropertyStore* props) -{ - ai_assert( NULL != pBuffer ); - ai_assert( 0 != pLength ); - - const aiScene* scene = NULL; - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // create an Importer for this file - Assimp::Importer* imp = new Assimp::Importer(); - - // copy properties - if(props) { - const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props); - ImporterPimpl* pimpl = imp->Pimpl(); - pimpl->mIntProperties = pp->ints; - pimpl->mFloatProperties = pp->floats; - pimpl->mStringProperties = pp->strings; - pimpl->mMatrixProperties = pp->matrices; - } - - // and have it read the file from the memory buffer - scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint); - - // if succeeded, store the importer in the scene and keep it alive - if( scene) { - ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) ); - priv->mOrigImporter = imp; - } - else { - // if failed, extract error code and destroy the import - gLastErrorString = imp->GetErrorString(); - delete imp; - } - // return imported data. If the import failed the pointer is NULL anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return scene; -} - -// ------------------------------------------------------------------------------------------------ -// Releases all resources associated with the given import process. -void aiReleaseImport( const aiScene* pScene) -{ - if (!pScene) { - return; - } - - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv(pScene); - if( !priv || !priv->mOrigImporter) { - delete pScene; - } - else { - // deleting the Importer also deletes the scene - // Note: the reason that this is not written as 'delete priv->mOrigImporter' - // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339) - Importer* importer = priv->mOrigImporter; - delete importer; - } - - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene, - unsigned int pFlags) -{ - const aiScene* sc = NULL; - - - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv(pScene); - if( !priv || !priv->mOrigImporter) { - ReportSceneNotFoundError(); - return NULL; - } - - sc = priv->mOrigImporter->ApplyPostProcessing(pFlags); - - if (!sc) { - aiReleaseImport(pScene); - return NULL; - } - - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return sc; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API const aiScene *aiApplyCustomizedPostProcessing( const aiScene *scene, - BaseProcess* process, - bool requestValidation ) { - const aiScene* sc( NULL ); - - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv( scene ); - if ( NULL == priv || NULL == priv->mOrigImporter ) { - ReportSceneNotFoundError(); - return NULL; - } - - sc = priv->mOrigImporter->ApplyCustomizedPostProcessing( process, requestValidation ); - - if ( !sc ) { - aiReleaseImport( scene ); - return NULL; - } - - ASSIMP_END_EXCEPTION_REGION( const aiScene* ); - - return sc; -} - -// ------------------------------------------------------------------------------------------------ -void CallbackToLogRedirector (const char* msg, char* dt) -{ - ai_assert( NULL != msg ); - ai_assert( NULL != dt ); - LogStream* s = (LogStream*)dt; - - s->write(msg); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file) -{ - aiLogStream sout; - - ASSIMP_BEGIN_EXCEPTION_REGION(); - LogStream* stream = LogStream::createDefaultStream(pStream,file); - if (!stream) { - sout.callback = NULL; - sout.user = NULL; - } - else { - sout.callback = &CallbackToLogRedirector; - sout.user = (char*)stream; - } - gPredefinedStreams.push_back(stream); - ASSIMP_END_EXCEPTION_REGION(aiLogStream); - return sout; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiAttachLogStream( const aiLogStream* stream ) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard<std::mutex> lock(gLogStreamMutex); -#endif - - LogStream* lg = new LogToCallbackRedirector(*stream); - gActiveLogStreams[*stream] = lg; - - if (DefaultLogger::isNullLogger()) { - DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); - } - DefaultLogger::get()->attachStream(lg); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard<std::mutex> lock(gLogStreamMutex); -#endif - // find the log-stream associated with this data - LogStreamMap::iterator it = gActiveLogStreams.find( *stream); - // it should be there... else the user is playing fools with us - if( it == gActiveLogStreams.end()) { - return AI_FAILURE; - } - DefaultLogger::get()->detatchStream( it->second ); - delete it->second; - - gActiveLogStreams.erase( it); - - if (gActiveLogStreams.empty()) { - DefaultLogger::kill(); - } - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiDetachAllLogStreams(void) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard<std::mutex> lock(gLogStreamMutex); -#endif - Logger *logger( DefaultLogger::get() ); - if ( NULL == logger ) { - return; - } - - for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) { - logger->detatchStream( it->second ); - delete it->second; - } - gActiveLogStreams.clear(); - DefaultLogger::kill(); - - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiEnableVerboseLogging(aiBool d) -{ - if (!DefaultLogger::isNullLogger()) { - DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); - } - gVerboseLogging = d; -} - -// ------------------------------------------------------------------------------------------------ -// Returns the error text of the last failed import process. -const char* aiGetErrorString() -{ - return gLastErrorString.c_str(); -} - -// ----------------------------------------------------------------------------------------------- -// Return the description of a importer given its index -const aiImporterDesc* aiGetImportFormatDescription( size_t pIndex) -{ - return Importer().GetImporterInfo(pIndex); -} - -// ----------------------------------------------------------------------------------------------- -// Return the number of importers -size_t aiGetImportFormatCount(void) -{ - return Importer().GetImporterCount(); -} - -// ------------------------------------------------------------------------------------------------ -// Returns the error text of the last failed import process. -aiBool aiIsExtensionSupported(const char* szExtension) -{ - ai_assert(NULL != szExtension); - aiBool candoit=AI_FALSE; - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // FIXME: no need to create a temporary Importer instance just for that .. - Assimp::Importer tmp; - candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE; - - ASSIMP_END_EXCEPTION_REGION(aiBool); - return candoit; -} - -// ------------------------------------------------------------------------------------------------ -// Get a list of all file extensions supported by ASSIMP -void aiGetExtensionList(aiString* szOut) -{ - ai_assert(NULL != szOut); - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // FIXME: no need to create a temporary Importer instance just for that .. - Assimp::Importer tmp; - tmp.GetExtensionList(*szOut); - - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Get the memory requirements for a particular import. -void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn, - C_STRUCT aiMemoryInfo* in) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // find the importer associated with this data - const ScenePrivateData* priv = ScenePriv(pIn); - if( !priv || !priv->mOrigImporter) { - ReportSceneNotFoundError(); - return; - } - - return priv->mOrigImporter->GetMemoryRequirements(*in); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void) -{ - return reinterpret_cast<aiPropertyStore*>( new PropertyMap() ); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p) -{ - delete reinterpret_cast<PropertyMap*>(p); -} - -// ------------------------------------------------------------------------------------------------ -// Importer::SetPropertyInteger -ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast<PropertyMap*>(p); - SetGenericProperty<int>(pp->ints,szName,value); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Importer::SetPropertyFloat -ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, ai_real value) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast<PropertyMap*>(p); - SetGenericProperty<ai_real>(pp->floats,szName,value); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Importer::SetPropertyString -ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName, - const C_STRUCT aiString* st) -{ - if (!st) { - return; - } - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast<PropertyMap*>(p); - SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str())); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Importer::SetPropertyMatrix -ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName, - const C_STRUCT aiMatrix4x4* mat) -{ - if (!mat) { - return; - } - ASSIMP_BEGIN_EXCEPTION_REGION(); - PropertyMap* pp = reinterpret_cast<PropertyMap*>(p); - SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat); - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Rotation matrix to quaternion -ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat) -{ - ai_assert( NULL != quat ); - ai_assert( NULL != mat ); - *quat = aiQuaternion(*mat); -} - -// ------------------------------------------------------------------------------------------------ -// Matrix decomposition -ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling, - aiQuaternion* rotation, - aiVector3D* position) -{ - ai_assert( NULL != rotation ); - ai_assert( NULL != position ); - ai_assert( NULL != scaling ); - ai_assert( NULL != mat ); - mat->Decompose(*scaling,*rotation,*position); -} - -// ------------------------------------------------------------------------------------------------ -// Matrix transpose -ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat) -{ - ai_assert(NULL != mat); - mat->Transpose(); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat) -{ - ai_assert(NULL != mat); - mat->Transpose(); -} - -// ------------------------------------------------------------------------------------------------ -// Vector transformation -ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec, - const aiMatrix3x3* mat) -{ - ai_assert( NULL != mat ); - ai_assert( NULL != vec); - *vec *= (*mat); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec, - const aiMatrix4x4* mat) -{ - ai_assert( NULL != mat ); - ai_assert( NULL != vec ); - - *vec *= (*mat); -} - -// ------------------------------------------------------------------------------------------------ -// Matrix multiplication -ASSIMP_API void aiMultiplyMatrix4( - aiMatrix4x4* dst, - const aiMatrix4x4* src) -{ - ai_assert( NULL != dst ); - ai_assert( NULL != src ); - *dst = (*dst) * (*src); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiMultiplyMatrix3( - aiMatrix3x3* dst, - const aiMatrix3x3* src) -{ - ai_assert( NULL != dst ); - ai_assert( NULL != src ); - *dst = (*dst) * (*src); -} - -// ------------------------------------------------------------------------------------------------ -// Matrix identity -ASSIMP_API void aiIdentityMatrix3( - aiMatrix3x3* mat) -{ - ai_assert(NULL != mat); - *mat = aiMatrix3x3(); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API void aiIdentityMatrix4( - aiMatrix4x4* mat) -{ - ai_assert(NULL != mat); - *mat = aiMatrix4x4(); -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API C_STRUCT const aiImporterDesc* aiGetImporterDesc( const char *extension ) { - if( NULL == extension ) { - return NULL; - } - const aiImporterDesc *desc( NULL ); - std::vector< BaseImporter* > out; - GetImporterInstanceList( out ); - for( size_t i = 0; i < out.size(); ++i ) { - if( 0 == strncmp( out[ i ]->GetInfo()->mFileExtensions, extension, strlen( extension ) ) ) { - desc = out[ i ]->GetInfo(); - break; - } - } - - DeleteImporterInstanceList(out); - - return desc; -} - -// ------------------------------------------------------------------------------------------------ diff --git a/thirdparty/assimp/code/Common/BaseImporter.cpp b/thirdparty/assimp/code/Common/BaseImporter.cpp deleted file mode 100644 index 5c1e605549..0000000000 --- a/thirdparty/assimp/code/Common/BaseImporter.cpp +++ /dev/null @@ -1,656 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file BaseImporter.cpp - * @brief Implementation of BaseImporter - */ - -#include <assimp/BaseImporter.h> -#include <assimp/ParsingUtils.h> -#include "FileSystemFilter.h" -#include "Importer.h" -#include <assimp/ByteSwapper.h> -#include <assimp/scene.h> -#include <assimp/Importer.hpp> -#include <assimp/postprocess.h> -#include <assimp/importerdesc.h> - -#include <ios> -#include <list> -#include <memory> -#include <sstream> -#include <cctype> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -BaseImporter::BaseImporter() AI_NO_EXCEPT -: m_progress() { - /** - * Assimp Importer - * unit conversions available - * if you need another measurment unit add it below. - * it's currently defined in assimp that we prefer meters. - * - * NOTE: Initialised here rather than in the header file - * to workaround a VS2013 bug with brace initialisers - * */ - importerUnits[ImporterUnits::M] = 1.0; - importerUnits[ImporterUnits::CM] = 0.01; - importerUnits[ImporterUnits::MM] = 0.001; - importerUnits[ImporterUnits::INCHES] = 0.0254; - importerUnits[ImporterUnits::FEET] = 0.3048; -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -BaseImporter::~BaseImporter() { - // nothing to do here -} - -void BaseImporter::UpdateImporterScale( Importer* pImp ) -{ - ai_assert(pImp != nullptr); - ai_assert(importerScale != 0.0); - ai_assert(fileScale != 0.0); - - double activeScale = importerScale * fileScale; - - // Set active scaling - pImp->SetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, static_cast<float>( activeScale) ); - - ASSIMP_LOG_DEBUG_F("UpdateImporterScale scale set: %f", activeScale ); -} - -// ------------------------------------------------------------------------------------------------ -// Imports the given file and returns the imported data. -aiScene* BaseImporter::ReadFile(Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) { - - - m_progress = pImp->GetProgressHandler(); - if (nullptr == m_progress) { - return nullptr; - } - - ai_assert(m_progress); - - // Gather configuration properties for this run - SetupProperties( pImp ); - - // Construct a file system filter to improve our success ratio at reading external files - FileSystemFilter filter(pFile,pIOHandler); - - // create a scene object to hold the data - std::unique_ptr<aiScene> sc(new aiScene()); - - // dispatch importing - try - { - InternReadFile( pFile, sc.get(), &filter); - - // Calculate import scale hook - required because pImp not available anywhere else - // passes scale into ScaleProcess - UpdateImporterScale(pImp); - - - } catch( const std::exception& err ) { - // extract error description - m_ErrorText = err.what(); - ASSIMP_LOG_ERROR(m_ErrorText); - return nullptr; - } - - // return what we gathered from the import. - return sc.release(); -} - -// ------------------------------------------------------------------------------------------------ -void BaseImporter::SetupProperties(const Importer* pImp) -{ - // the default implementation does nothing -} - -// ------------------------------------------------------------------------------------------------ -void BaseImporter::GetExtensionList(std::set<std::string>& extensions) { - const aiImporterDesc* desc = GetInfo(); - ai_assert(desc != nullptr); - - const char* ext = desc->mFileExtensions; - ai_assert(ext != nullptr ); - - const char* last = ext; - do { - if (!*ext || *ext == ' ') { - extensions.insert(std::string(last,ext-last)); - ai_assert(ext-last > 0); - last = ext; - while(*last == ' ') { - ++last; - } - } - } - while(*ext++); -} - -// ------------------------------------------------------------------------------------------------ -/*static*/ bool BaseImporter::SearchFileHeaderForToken( IOSystem* pIOHandler, - const std::string& pFile, - const char** tokens, - unsigned int numTokens, - unsigned int searchBytes /* = 200 */, - bool tokensSol /* false */, - bool noAlphaBeforeTokens /* false */) -{ - ai_assert( nullptr != tokens ); - ai_assert( 0 != numTokens ); - ai_assert( 0 != searchBytes); - - if ( nullptr == pIOHandler ) { - return false; - } - - std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { - // read 200 characters from the file - std::unique_ptr<char[]> _buffer (new char[searchBytes+1 /* for the '\0' */]); - char *buffer( _buffer.get() ); - const size_t read( pStream->Read(buffer,1,searchBytes) ); - if( 0 == read ) { - return false; - } - - for( size_t i = 0; i < read; ++i ) { - buffer[ i ] = static_cast<char>( ::tolower( buffer[ i ] ) ); - } - - // It is not a proper handling of unicode files here ... - // ehm ... but it works in most cases. - char* cur = buffer,*cur2 = buffer,*end = &buffer[read]; - while (cur != end) { - if( *cur ) { - *cur2++ = *cur; - } - ++cur; - } - *cur2 = '\0'; - - std::string token; - for (unsigned int i = 0; i < numTokens; ++i ) { - ai_assert( nullptr != tokens[i] ); - const size_t len( strlen( tokens[ i ] ) ); - token.clear(); - const char *ptr( tokens[ i ] ); - for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) { - token.push_back( static_cast<char>( tolower( *ptr ) ) ); - ++ptr; - } - const char* r = strstr( buffer, token.c_str() ); - if( !r ) { - continue; - } - // We need to make sure that we didn't accidentially identify the end of another token as our token, - // e.g. in a previous version the "gltf " present in some gltf files was detected as "f " - if (noAlphaBeforeTokens && (r != buffer && isalpha(r[-1]))) { - continue; - } - // We got a match, either we don't care where it is, or it happens to - // be in the beginning of the file / line - if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') { - ASSIMP_LOG_DEBUG_F( "Found positive match for header keyword: ", tokens[i] ); - return true; - } - } - } - - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Simple check for file extension -/*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile, - const char* ext0, - const char* ext1, - const char* ext2) -{ - std::string::size_type pos = pFile.find_last_of('.'); - - // no file extension - can't read - if( pos == std::string::npos) - return false; - - const char* ext_real = & pFile[ pos+1 ]; - if( !ASSIMP_stricmp(ext_real,ext0) ) - return true; - - // check for other, optional, file extensions - if (ext1 && !ASSIMP_stricmp(ext_real,ext1)) - return true; - - if (ext2 && !ASSIMP_stricmp(ext_real,ext2)) - return true; - - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Get file extension from path -std::string BaseImporter::GetExtension( const std::string& file ) { - std::string::size_type pos = file.find_last_of('.'); - - // no file extension at all - if (pos == std::string::npos) { - return ""; - } - - - // thanks to Andy Maloney for the hint - std::string ret = file.substr( pos + 1 ); - std::transform( ret.begin(), ret.end(), ret.begin(), ToLower<char>); - - return ret; -} - -// ------------------------------------------------------------------------------------------------ -// Check for magic bytes at the beginning of the file. -/* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile, - const void* _magic, unsigned int num, unsigned int offset, unsigned int size) -{ - ai_assert( size <= 16 ); - ai_assert( _magic ); - - if (!pIOHandler) { - return false; - } - union { - const char* magic; - const uint16_t* magic_u16; - const uint32_t* magic_u32; - }; - magic = reinterpret_cast<const char*>(_magic); - std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile)); - if (pStream.get() ) { - - // skip to offset - pStream->Seek(offset,aiOrigin_SET); - - // read 'size' characters from the file - union { - char data[16]; - uint16_t data_u16[8]; - uint32_t data_u32[4]; - }; - if(size != pStream->Read(data,1,size)) { - return false; - } - - for (unsigned int i = 0; i < num; ++i) { - // also check against big endian versions of tokens with size 2,4 - // that's just for convenience, the chance that we cause conflicts - // is quite low and it can save some lines and prevent nasty bugs - if (2 == size) { - uint16_t rev = *magic_u16; - ByteSwap::Swap(&rev); - if (data_u16[0] == *magic_u16 || data_u16[0] == rev) { - return true; - } - } - else if (4 == size) { - uint32_t rev = *magic_u32; - ByteSwap::Swap(&rev); - if (data_u32[0] == *magic_u32 || data_u32[0] == rev) { - return true; - } - } - else { - // any length ... just compare - if(!memcmp(magic,data,size)) { - return true; - } - } - magic += size; - } - } - return false; -} - -#ifdef ASSIMP_USE_HUNTER -# include <utf8/utf8.h> -#else -# include "../contrib/utf8cpp/source/utf8.h" -#endif - -// ------------------------------------------------------------------------------------------------ -// Convert to UTF8 data -void BaseImporter::ConvertToUTF8(std::vector<char>& data) -{ - //ConversionResult result; - if(data.size() < 8) { - throw DeadlyImportError("File is too small"); - } - - // UTF 8 with BOM - if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) { - ASSIMP_LOG_DEBUG("Found UTF-8 BOM ..."); - - std::copy(data.begin()+3,data.end(),data.begin()); - data.resize(data.size()-3); - return; - } - - - // UTF 32 BE with BOM - if(*((uint32_t*)&data.front()) == 0xFFFE0000) { - - // swap the endianness .. - for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) { - AI_SWAP4P(p); - } - } - - // UTF 32 LE with BOM - if(*((uint32_t*)&data.front()) == 0x0000FFFE) { - ASSIMP_LOG_DEBUG("Found UTF-32 BOM ..."); - - std::vector<char> output; - int *ptr = (int*)&data[ 0 ]; - int *end = ptr + ( data.size() / sizeof(int) ) +1; - utf8::utf32to8( ptr, end, back_inserter(output)); - return; - } - - // UTF 16 BE with BOM - if(*((uint16_t*)&data.front()) == 0xFFFE) { - - // swap the endianness .. - for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) { - ByteSwap::Swap2(p); - } - } - - // UTF 16 LE with BOM - if(*((uint16_t*)&data.front()) == 0xFEFF) { - ASSIMP_LOG_DEBUG("Found UTF-16 BOM ..."); - - std::vector<unsigned char> output; - utf8::utf16to8(data.begin(), data.end(), back_inserter(output)); - return; - } -} - -// ------------------------------------------------------------------------------------------------ -// Convert to UTF8 data to ISO-8859-1 -void BaseImporter::ConvertUTF8toISO8859_1(std::string& data) -{ - size_t size = data.size(); - size_t i = 0, j = 0; - - while(i < size) { - if ((unsigned char) data[i] < (size_t) 0x80) { - data[j] = data[i]; - } else if(i < size - 1) { - if((unsigned char) data[i] == 0xC2) { - data[j] = data[++i]; - } else if((unsigned char) data[i] == 0xC3) { - data[j] = ((unsigned char) data[++i] + 0x40); - } else { - std::stringstream stream; - stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1."; - ASSIMP_LOG_ERROR( stream.str() ); - - data[j++] = data[i++]; - data[j] = data[i]; - } - } else { - ASSIMP_LOG_ERROR("UTF8 code but only one character remaining"); - - data[j] = data[i]; - } - - i++; j++; - } - - data.resize(j); -} - -// ------------------------------------------------------------------------------------------------ -void BaseImporter::TextFileToBuffer(IOStream* stream, - std::vector<char>& data, - TextFileMode mode) -{ - ai_assert(nullptr != stream); - - const size_t fileSize = stream->FileSize(); - if (mode == FORBID_EMPTY) { - if(!fileSize) { - throw DeadlyImportError("File is empty"); - } - } - - data.reserve(fileSize+1); - data.resize(fileSize); - if(fileSize > 0) { - if(fileSize != stream->Read( &data[0], 1, fileSize)) { - throw DeadlyImportError("File read error"); - } - - ConvertToUTF8(data); - } - - // append a binary zero to simplify string parsing - data.push_back(0); -} - -// ------------------------------------------------------------------------------------------------ -namespace Assimp { - // Represents an import request - struct LoadRequest { - LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id) - : file(_file) - , flags(_flags) - , refCnt(1) - , scene(NULL) - , loaded(false) - , id(_id) { - if ( _map ) { - map = *_map; - } - } - - bool operator== ( const std::string& f ) const { - return file == f; - } - - const std::string file; - unsigned int flags; - unsigned int refCnt; - aiScene *scene; - bool loaded; - BatchLoader::PropertyMap map; - unsigned int id; - }; -} - -// ------------------------------------------------------------------------------------------------ -// BatchLoader::pimpl data structure -struct Assimp::BatchData { - BatchData( IOSystem* pIO, bool validate ) - : pIOSystem( pIO ) - , pImporter( nullptr ) - , next_id(0xffff) - , validate( validate ) { - ai_assert( nullptr != pIO ); - - pImporter = new Importer(); - pImporter->SetIOHandler( pIO ); - } - - ~BatchData() { - pImporter->SetIOHandler( nullptr ); /* get pointer back into our possession */ - delete pImporter; - } - - // IO system to be used for all imports - IOSystem* pIOSystem; - - // Importer used to load all meshes - Importer* pImporter; - - // List of all imports - std::list<LoadRequest> requests; - - // Base path - std::string pathBase; - - // Id for next item - unsigned int next_id; - - // Validation enabled state - bool validate; -}; - -typedef std::list<LoadRequest>::iterator LoadReqIt; - -// ------------------------------------------------------------------------------------------------ -BatchLoader::BatchLoader(IOSystem* pIO, bool validate ) { - ai_assert(nullptr != pIO); - - m_data = new BatchData( pIO, validate ); -} - -// ------------------------------------------------------------------------------------------------ -BatchLoader::~BatchLoader() -{ - // delete all scenes what have not been polled by the user - for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) { - delete (*it).scene; - } - delete m_data; -} - -// ------------------------------------------------------------------------------------------------ -void BatchLoader::setValidation( bool enabled ) { - m_data->validate = enabled; -} - -// ------------------------------------------------------------------------------------------------ -bool BatchLoader::getValidation() const { - return m_data->validate; -} - -// ------------------------------------------------------------------------------------------------ -unsigned int BatchLoader::AddLoadRequest(const std::string& file, - unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/) -{ - ai_assert(!file.empty()); - - // check whether we have this loading request already - for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) { - // Call IOSystem's path comparison function here - if ( m_data->pIOSystem->ComparePaths((*it).file,file)) { - if (map) { - if ( !( ( *it ).map == *map ) ) { - continue; - } - } - else if ( !( *it ).map.empty() ) { - continue; - } - - (*it).refCnt++; - return (*it).id; - } - } - - // no, we don't have it. So add it to the queue ... - m_data->requests.push_back(LoadRequest(file,steps,map, m_data->next_id)); - return m_data->next_id++; -} - -// ------------------------------------------------------------------------------------------------ -aiScene* BatchLoader::GetImport( unsigned int which ) -{ - for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) { - if ((*it).id == which && (*it).loaded) { - aiScene* sc = (*it).scene; - if (!(--(*it).refCnt)) { - m_data->requests.erase(it); - } - return sc; - } - } - return nullptr; -} - - - -// ------------------------------------------------------------------------------------------------ -void BatchLoader::LoadAll() -{ - // no threaded implementation for the moment - for ( LoadReqIt it = m_data->requests.begin();it != m_data->requests.end(); ++it) { - // force validation in debug builds - unsigned int pp = (*it).flags; - if ( m_data->validate ) { - pp |= aiProcess_ValidateDataStructure; - } - - // setup config properties if necessary - ImporterPimpl* pimpl = m_data->pImporter->Pimpl(); - pimpl->mFloatProperties = (*it).map.floats; - pimpl->mIntProperties = (*it).map.ints; - pimpl->mStringProperties = (*it).map.strings; - pimpl->mMatrixProperties = (*it).map.matrices; - - if (!DefaultLogger::isNullLogger()) - { - ASSIMP_LOG_INFO("%%% BEGIN EXTERNAL FILE %%%"); - ASSIMP_LOG_INFO_F("File: ", (*it).file); - } - m_data->pImporter->ReadFile((*it).file,pp); - (*it).scene = m_data->pImporter->GetOrphanedScene(); - (*it).loaded = true; - - ASSIMP_LOG_INFO("%%% END EXTERNAL FILE %%%"); - } -} diff --git a/thirdparty/assimp/code/Common/BaseProcess.cpp b/thirdparty/assimp/code/Common/BaseProcess.cpp deleted file mode 100644 index e247be418d..0000000000 --- a/thirdparty/assimp/code/Common/BaseProcess.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of BaseProcess */ - -#include <assimp/BaseImporter.h> -#include "BaseProcess.h" -#include <assimp/DefaultLogger.hpp> -#include <assimp/scene.h> -#include "Importer.h" - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -BaseProcess::BaseProcess() AI_NO_EXCEPT -: shared() -, progress() -{ -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -BaseProcess::~BaseProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -void BaseProcess::ExecuteOnScene( Importer* pImp) -{ - ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene); - - progress = pImp->GetProgressHandler(); - ai_assert(progress); - - SetupProperties( pImp ); - - // catch exceptions thrown inside the PostProcess-Step - try - { - Execute(pImp->Pimpl()->mScene); - - } catch( const std::exception& err ) { - - // extract error description - pImp->Pimpl()->mErrorString = err.what(); - ASSIMP_LOG_ERROR(pImp->Pimpl()->mErrorString); - - // and kill the partially imported data - delete pImp->Pimpl()->mScene; - pImp->Pimpl()->mScene = nullptr; - } -} - -// ------------------------------------------------------------------------------------------------ -void BaseProcess::SetupProperties(const Importer* /*pImp*/) -{ - // the default implementation does nothing -} - -// ------------------------------------------------------------------------------------------------ -bool BaseProcess::RequireVerboseFormat() const -{ - return true; -} - diff --git a/thirdparty/assimp/code/Common/BaseProcess.h b/thirdparty/assimp/code/Common/BaseProcess.h deleted file mode 100644 index 4d5c7a76be..0000000000 --- a/thirdparty/assimp/code/Common/BaseProcess.h +++ /dev/null @@ -1,290 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Base class of all import post processing steps */ -#ifndef INCLUDED_AI_BASEPROCESS_H -#define INCLUDED_AI_BASEPROCESS_H - -#include <map> -#include <assimp/GenericProperty.h> - -struct aiScene; - -namespace Assimp { - -class Importer; - -// --------------------------------------------------------------------------- -/** Helper class to allow post-processing steps to interact with each other. - * - * The class maintains a simple property list that can be used by pp-steps - * to provide additional information to other steps. This is primarily - * intended for cross-step optimizations. - */ -class SharedPostProcessInfo -{ -public: - - struct Base - { - virtual ~Base() - {} - }; - - //! Represents data that is allocated on the heap, thus needs to be deleted - template <typename T> - struct THeapData : public Base - { - explicit THeapData(T* in) - : data (in) - {} - - ~THeapData() - { - delete data; - } - T* data; - }; - - //! Represents static, by-value data not allocated on the heap - template <typename T> - struct TStaticData : public Base - { - explicit TStaticData(T in) - : data (in) - {} - - ~TStaticData() - {} - - T data; - }; - - // some typedefs for cleaner code - typedef unsigned int KeyType; - typedef std::map<KeyType, Base*> PropertyMap; - -public: - - //! Destructor - ~SharedPostProcessInfo() - { - Clean(); - } - - //! Remove all stored properties from the table - void Clean() - { - // invoke the virtual destructor for all stored properties - for (PropertyMap::iterator it = pmap.begin(), end = pmap.end(); - it != end; ++it) - { - delete (*it).second; - } - pmap.clear(); - } - - //! Add a heap property to the list - template <typename T> - void AddProperty( const char* name, T* in ){ - AddProperty(name,(Base*)new THeapData<T>(in)); - } - - //! Add a static by-value property to the list - template <typename T> - void AddProperty( const char* name, T in ){ - AddProperty(name,(Base*)new TStaticData<T>(in)); - } - - - //! Get a heap property - template <typename T> - bool GetProperty( const char* name, T*& out ) const - { - THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name); - if(!t) - { - out = NULL; - return false; - } - out = t->data; - return true; - } - - //! Get a static, by-value property - template <typename T> - bool GetProperty( const char* name, T& out ) const - { - TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name); - if(!t)return false; - out = t->data; - return true; - } - - //! Remove a property of a specific type - void RemoveProperty( const char* name) { - SetGenericPropertyPtr<Base>(pmap,name,NULL); - } - -private: - - void AddProperty( const char* name, Base* data) { - SetGenericPropertyPtr<Base>(pmap,name,data); - } - - Base* GetPropertyInternal( const char* name) const { - return GetGenericProperty<Base*>(pmap,name,NULL); - } - -private: - - //! Map of all stored properties - PropertyMap pmap; -}; - -#if 0 - -// --------------------------------------------------------------------------- -/** @brief Represents a dependency table for a postprocessing steps. - * - * For future use. - */ - struct PPDependencyTable - { - unsigned int execute_me_before_these; - unsigned int execute_me_after_these; - unsigned int only_if_these_are_not_specified; - unsigned int mutually_exclusive_with; - }; - -#endif - - -#define AI_SPP_SPATIAL_SORT "$Spat" - -// --------------------------------------------------------------------------- -/** The BaseProcess defines a common interface for all post processing steps. - * A post processing step is run after a successful import if the caller - * specified the corresponding flag when calling ReadFile(). - * Enum #aiPostProcessSteps defines which flags are available. - * After a successful import the Importer iterates over its internal array - * of processes and calls IsActive() on each process to evaluate if the step - * should be executed. If the function returns true, the class' Execute() - * function is called subsequently. - */ -class ASSIMP_API_WINONLY BaseProcess { - friend class Importer; - -public: - /** Constructor to be privately used by Importer */ - BaseProcess() AI_NO_EXCEPT; - - /** Destructor, private as well */ - virtual ~BaseProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. A - * bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - virtual bool IsActive( unsigned int pFlags) const = 0; - - // ------------------------------------------------------------------- - /** Check whether this step expects its input vertex data to be - * in verbose format. */ - virtual bool RequireVerboseFormat() const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * The function deletes the scene if the postprocess step fails ( - * the object pointer will be set to NULL). - * @param pImp Importer instance (pImp->mScene must be valid) - */ - void ExecuteOnScene( Importer* pImp); - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * A process should throw an ImportErrorException* if it fails. - * This method must be implemented by deriving classes. - * @param pScene The imported data to work at. - */ - virtual void Execute( aiScene* pScene) = 0; - - - // ------------------------------------------------------------------- - /** Assign a new SharedPostProcessInfo to the step. This object - * allows multiple postprocess steps to share data. - * @param sh May be NULL - */ - inline void SetSharedData(SharedPostProcessInfo* sh) { - shared = sh; - } - - // ------------------------------------------------------------------- - /** Get the shared data that is assigned to the step. - */ - inline SharedPostProcessInfo* GetSharedData() { - return shared; - } - -protected: - - /** See the doc of #SharedPostProcessInfo for more details */ - SharedPostProcessInfo* shared; - - /** Currently active progress handler */ - ProgressHandler* progress; -}; - - -} // end of namespace Assimp - -#endif // AI_BASEPROCESS_H_INC diff --git a/thirdparty/assimp/code/Common/Bitmap.cpp b/thirdparty/assimp/code/Common/Bitmap.cpp deleted file mode 100644 index b22b71ea9e..0000000000 --- a/thirdparty/assimp/code/Common/Bitmap.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Bitmap.cpp - * @brief Defines bitmap format helper for textures - * - * Used for file formats which embed their textures into the model file. - */ - - -#include <assimp/Bitmap.h> -#include <assimp/texture.h> -#include <assimp/IOStream.hpp> -#include <assimp/ByteSwapper.h> - -namespace Assimp { - - void Bitmap::Save(aiTexture* texture, IOStream* file) { - if(file != NULL) { - Header header; - DIB dib; - - dib.size = DIB::dib_size; - dib.width = texture->mWidth; - dib.height = texture->mHeight; - dib.planes = 1; - dib.bits_per_pixel = 8 * mBytesPerPixel; - dib.compression = 0; - dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height; - dib.x_resolution = 0; - dib.y_resolution = 0; - dib.nb_colors = 0; - dib.nb_important_colors = 0; - - header.type = 0x4D42; // 'BM' - header.offset = Header::header_size + DIB::dib_size; - header.size = header.offset + dib.image_size; - header.reserved1 = 0; - header.reserved2 = 0; - - WriteHeader(header, file); - WriteDIB(dib, file); - WriteData(texture, file); - } - } - - template<typename T> - inline - std::size_t Copy(uint8_t* data, const T &field) { -#ifdef AI_BUILD_BIG_ENDIAN - T field_swapped=AI_BE(field); - std::memcpy(data, &field_swapped, sizeof(field)); return sizeof(field); -#else - std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field); -#endif - } - - void Bitmap::WriteHeader(Header& header, IOStream* file) { - uint8_t data[Header::header_size]; - - std::size_t offset = 0; - - offset += Copy(&data[offset], header.type); - offset += Copy(&data[offset], header.size); - offset += Copy(&data[offset], header.reserved1); - offset += Copy(&data[offset], header.reserved2); - Copy(&data[offset], header.offset); - - file->Write(data, Header::header_size, 1); - } - - void Bitmap::WriteDIB(DIB& dib, IOStream* file) { - uint8_t data[DIB::dib_size]; - - std::size_t offset = 0; - - offset += Copy(&data[offset], dib.size); - offset += Copy(&data[offset], dib.width); - offset += Copy(&data[offset], dib.height); - offset += Copy(&data[offset], dib.planes); - offset += Copy(&data[offset], dib.bits_per_pixel); - offset += Copy(&data[offset], dib.compression); - offset += Copy(&data[offset], dib.image_size); - offset += Copy(&data[offset], dib.x_resolution); - offset += Copy(&data[offset], dib.y_resolution); - offset += Copy(&data[offset], dib.nb_colors); - Copy(&data[offset], dib.nb_important_colors); - - file->Write(data, DIB::dib_size, 1); - } - - void Bitmap::WriteData(aiTexture* texture, IOStream* file) { - static const std::size_t padding_offset = 4; - static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0}; - - unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset; - uint8_t pixel[mBytesPerPixel]; - - for(std::size_t i = 0; i < texture->mHeight; ++i) { - for(std::size_t j = 0; j < texture->mWidth; ++j) { - const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format - - pixel[0] = texel.r; - pixel[1] = texel.g; - pixel[2] = texel.b; - pixel[3] = texel.a; - - file->Write(pixel, mBytesPerPixel, 1); - } - - file->Write(padding_data, padding, 1); - } - } - -} diff --git a/thirdparty/assimp/code/Common/CreateAnimMesh.cpp b/thirdparty/assimp/code/Common/CreateAnimMesh.cpp deleted file mode 100644 index 98b60e5319..0000000000 --- a/thirdparty/assimp/code/Common/CreateAnimMesh.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (C) 2016 The Qt Company Ltd. -Copyright (c) 2006-2012, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -#include <assimp/CreateAnimMesh.h> - -namespace Assimp { - -aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh) -{ - aiAnimMesh *animesh = new aiAnimMesh; - animesh->mNumVertices = mesh->mNumVertices; - if (mesh->mVertices) { - animesh->mVertices = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mVertices, mesh->mVertices, mesh->mNumVertices * sizeof(aiVector3D)); - } - if (mesh->mNormals) { - animesh->mNormals = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mNormals, mesh->mNormals, mesh->mNumVertices * sizeof(aiVector3D)); - } - if (mesh->mTangents) { - animesh->mTangents = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mTangents, mesh->mTangents, mesh->mNumVertices * sizeof(aiVector3D)); - } - if (mesh->mBitangents) { - animesh->mBitangents = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mBitangents, mesh->mBitangents, mesh->mNumVertices * sizeof(aiVector3D)); - } - - for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) { - if (mesh->mColors[i]) { - animesh->mColors[i] = new aiColor4D[animesh->mNumVertices]; - std::memcpy(animesh->mColors[i], mesh->mColors[i], mesh->mNumVertices * sizeof(aiColor4D)); - } else { - animesh->mColors[i] = NULL; - } - } - - for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->mTextureCoords[i]) { - animesh->mTextureCoords[i] = new aiVector3D[animesh->mNumVertices]; - std::memcpy(animesh->mTextureCoords[i], mesh->mTextureCoords[i], mesh->mNumVertices * sizeof(aiVector3D)); - } else { - animesh->mTextureCoords[i] = NULL; - } - } - return animesh; -} - -} // end of namespace Assimp diff --git a/thirdparty/assimp/code/Common/DefaultIOStream.cpp b/thirdparty/assimp/code/Common/DefaultIOStream.cpp deleted file mode 100644 index 1c100b6189..0000000000 --- a/thirdparty/assimp/code/Common/DefaultIOStream.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -/** @file DefaultIOStream.cpp - * @brief Default File I/O implementation for #Importer - */ - - -#include <assimp/ai_assert.h> -#include <assimp/DefaultIOStream.h> -#include <sys/types.h> -#include <sys/stat.h> - -using namespace Assimp; - -// ---------------------------------------------------------------------------------- -DefaultIOStream::~DefaultIOStream() -{ - if (mFile) { - ::fclose(mFile); - mFile = nullptr; - } -} - -// ---------------------------------------------------------------------------------- -size_t DefaultIOStream::Read(void* pvBuffer, - size_t pSize, - size_t pCount) -{ - ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount); - return (mFile ? ::fread(pvBuffer, pSize, pCount, mFile) : 0); -} - -// ---------------------------------------------------------------------------------- -size_t DefaultIOStream::Write(const void* pvBuffer, - size_t pSize, - size_t pCount) -{ - ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount); - return (mFile ? ::fwrite(pvBuffer, pSize, pCount, mFile) : 0); -} - -// ---------------------------------------------------------------------------------- -aiReturn DefaultIOStream::Seek(size_t pOffset, - aiOrigin pOrigin) -{ - if (!mFile) { - return AI_FAILURE; - } - - // Just to check whether our enum maps one to one with the CRT constants - static_assert(aiOrigin_CUR == SEEK_CUR && - aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET, "aiOrigin_CUR == SEEK_CUR && \ - aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET"); - - // do the seek - return (0 == ::fseek(mFile, (long)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE); -} - -// ---------------------------------------------------------------------------------- -size_t DefaultIOStream::Tell() const -{ - if (!mFile) { - return 0; - } - return ::ftell(mFile); -} - -// ---------------------------------------------------------------------------------- -size_t DefaultIOStream::FileSize() const -{ - if (! mFile || mFilename.empty()) { - return 0; - } - - if (SIZE_MAX == mCachedSize ) { - - // Although fseek/ftell would allow us to reuse the existing file handle here, - // it is generally unsafe because: - // - For binary streams, it is not technically well-defined - // - For text files the results are meaningless - // That's why we use the safer variant fstat here. - // - // See here for details: - // https://www.securecoding.cert.org/confluence/display/seccode/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file -#if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601) - struct __stat64 fileStat; - //using fileno + fstat avoids having to handle the filename - int err = _fstat64( _fileno(mFile), &fileStat ); - if (0 != err) - return 0; - mCachedSize = (size_t) (fileStat.st_size); -#elif defined __GNUC__ || defined __APPLE__ || defined __MACH__ || defined __FreeBSD__ - struct stat fileStat; - int err = stat(mFilename.c_str(), &fileStat ); - if (0 != err) - return 0; - const unsigned long long cachedSize = fileStat.st_size; - mCachedSize = static_cast< size_t >( cachedSize ); -#else -# error "Unknown platform" -#endif - } - return mCachedSize; -} - -// ---------------------------------------------------------------------------------- -void DefaultIOStream::Flush() -{ - if (mFile) { - ::fflush(mFile); - } -} - -// ---------------------------------------------------------------------------------- diff --git a/thirdparty/assimp/code/Common/DefaultIOSystem.cpp b/thirdparty/assimp/code/Common/DefaultIOSystem.cpp deleted file mode 100644 index 6fdc24dd80..0000000000 --- a/thirdparty/assimp/code/Common/DefaultIOSystem.cpp +++ /dev/null @@ -1,216 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -/** @file Default implementation of IOSystem using the standard C file functions */ - -#include <assimp/StringComparison.h> - -#include <assimp/DefaultIOSystem.h> -#include <assimp/DefaultIOStream.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/ai_assert.h> -#include <stdlib.h> - -#ifdef __unix__ -#include <sys/param.h> -#include <stdlib.h> -#endif - -#ifdef _WIN32 -#include <windows.h> -#endif - -using namespace Assimp; - -#ifdef _WIN32 -static std::wstring Utf8ToWide(const char* in) -{ - int size = MultiByteToWideChar(CP_UTF8, 0, in, -1, nullptr, 0); - // size includes terminating null; std::wstring adds null automatically - std::wstring out(static_cast<size_t>(size) - 1, L'\0'); - MultiByteToWideChar(CP_UTF8, 0, in, -1, &out[0], size); - return out; -} - -static std::string WideToUtf8(const wchar_t* in) -{ - int size = WideCharToMultiByte(CP_UTF8, 0, in, -1, nullptr, 0, nullptr, nullptr); - // size includes terminating null; std::string adds null automatically - std::string out(static_cast<size_t>(size) - 1, '\0'); - WideCharToMultiByte(CP_UTF8, 0, in, -1, &out[0], size, nullptr, nullptr); - return out; -} -#endif - -// ------------------------------------------------------------------------------------------------ -// Tests for the existence of a file at the given path. -bool DefaultIOSystem::Exists(const char* pFile) const -{ -#ifdef _WIN32 - struct __stat64 filestat; - if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) { - return false; - } -#else - FILE* file = ::fopen(pFile, "rb"); - if (!file) - return false; - - ::fclose(file); -#endif - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Open a new file with a given path. -IOStream* DefaultIOSystem::Open(const char* strFile, const char* strMode) -{ - ai_assert(strFile != nullptr); - ai_assert(strMode != nullptr); - FILE* file; -#ifdef _WIN32 - file = ::_wfopen(Utf8ToWide(strFile).c_str(), Utf8ToWide(strMode).c_str()); -#else - file = ::fopen(strFile, strMode); -#endif - if (!file) - return nullptr; - - return new DefaultIOStream(file, strFile); -} - -// ------------------------------------------------------------------------------------------------ -// Closes the given file and releases all resources associated with it. -void DefaultIOSystem::Close(IOStream* pFile) -{ - delete pFile; -} - -// ------------------------------------------------------------------------------------------------ -// Returns the operation specific directory separator -char DefaultIOSystem::getOsSeparator() const -{ -#ifndef _WIN32 - return '/'; -#else - return '\\'; -#endif -} - -// ------------------------------------------------------------------------------------------------ -// IOSystem default implementation (ComparePaths isn't a pure virtual function) -bool IOSystem::ComparePaths(const char* one, const char* second) const -{ - return !ASSIMP_stricmp(one, second); -} - -// ------------------------------------------------------------------------------------------------ -// Convert a relative path into an absolute path -inline static std::string MakeAbsolutePath(const char* in) -{ - ai_assert(in); - std::string out; -#ifdef _WIN32 - wchar_t* ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0); - if (ret) { - out = WideToUtf8(ret); - free(ret); - } -#else - char* ret = realpath(in, nullptr); - if (ret) { - out = ret; - free(ret); - } -#endif - if (!ret) { - // preserve the input path, maybe someone else is able to fix - // the path before it is accessed (e.g. our file system filter) - ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in)); - out = in; - } - return out; -} - -// ------------------------------------------------------------------------------------------------ -// DefaultIOSystem's more specialized implementation -bool DefaultIOSystem::ComparePaths(const char* one, const char* second) const -{ - // chances are quite good both paths are formatted identically, - // so we can hopefully return here already - if (!ASSIMP_stricmp(one, second)) - return true; - - std::string temp1 = MakeAbsolutePath(one); - std::string temp2 = MakeAbsolutePath(second); - - return !ASSIMP_stricmp(temp1, temp2); -} - -// ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::fileName(const std::string& path) -{ - std::string ret = path; - std::size_t last = ret.find_last_of("\\/"); - if (last != std::string::npos) ret = ret.substr(last + 1); - return ret; -} - -// ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::completeBaseName(const std::string& path) -{ - std::string ret = fileName(path); - std::size_t pos = ret.find_last_of('.'); - if (pos != std::string::npos) ret = ret.substr(0, pos); - return ret; -} - -// ------------------------------------------------------------------------------------------------ -std::string DefaultIOSystem::absolutePath(const std::string& path) -{ - std::string ret = path; - std::size_t last = ret.find_last_of("\\/"); - if (last != std::string::npos) ret = ret.substr(0, last); - return ret; -} - -// ------------------------------------------------------------------------------------------------ diff --git a/thirdparty/assimp/code/Common/DefaultLogger.cpp b/thirdparty/assimp/code/Common/DefaultLogger.cpp deleted file mode 100644 index de3528d2b4..0000000000 --- a/thirdparty/assimp/code/Common/DefaultLogger.cpp +++ /dev/null @@ -1,418 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file DefaultLogger.cpp - * @brief Implementation of DefaultLogger (and Logger) - */ - -// Default log streams -#include "Win32DebugLogStream.h" -#include "StdOStreamLogStream.h" -#include "FileLogStream.h" -#include <assimp/StringUtils.h> - -#include <assimp/DefaultIOSystem.h> -#include <assimp/NullLogger.hpp> -#include <assimp/DefaultLogger.hpp> -#include <assimp/ai_assert.h> -#include <iostream> -#include <stdio.h> - -#ifndef ASSIMP_BUILD_SINGLETHREADED -# include <thread> -# include <mutex> - std::mutex loggerMutex; -#endif - -namespace Assimp { - -// ---------------------------------------------------------------------------------- -NullLogger DefaultLogger::s_pNullLogger; -Logger *DefaultLogger::m_pLogger = &DefaultLogger::s_pNullLogger; - -static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging; - -// ---------------------------------------------------------------------------------- -// Represents a log-stream + its error severity -struct LogStreamInfo { - unsigned int m_uiErrorSeverity; - LogStream *m_pStream; - - // Constructor - LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) : - m_uiErrorSeverity( uiErrorSev ), - m_pStream( pStream ) { - // empty - } - - // Destructor - ~LogStreamInfo() { - delete m_pStream; - } -}; - -// ---------------------------------------------------------------------------------- -// Construct a default log stream -LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams, - const char* name /*= "AssimpLog.txt"*/, - IOSystem* io /*= NULL*/) -{ - switch (streams) - { - // This is a platform-specific feature - case aiDefaultLogStream_DEBUGGER: -#ifdef WIN32 - return new Win32DebugLogStream(); -#else - return nullptr; -#endif - - // Platform-independent default streams - case aiDefaultLogStream_STDERR: - return new StdOStreamLogStream(std::cerr); - case aiDefaultLogStream_STDOUT: - return new StdOStreamLogStream(std::cout); - case aiDefaultLogStream_FILE: - return (name && *name ? new FileLogStream(name,io) : nullptr ); - default: - // We don't know this default log stream, so raise an assertion - ai_assert(false); - - }; - - // For compilers without dead code path detection - return NULL; -} - -// ---------------------------------------------------------------------------------- -// Creates the only singleton instance -Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/, - LogSeverity severity /*= NORMAL*/, - unsigned int defStreams /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/, - IOSystem* io /*= NULL*/) { - // enter the mutex here to avoid concurrency problems -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard<std::mutex> lock(loggerMutex); -#endif - - if ( m_pLogger && !isNullLogger() ) { - delete m_pLogger; - } - - m_pLogger = new DefaultLogger( severity ); - - // Attach default log streams - // Stream the log to the MSVC debugger? - if ( defStreams & aiDefaultLogStream_DEBUGGER ) { - m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_DEBUGGER ) ); - } - - // Stream the log to COUT? - if ( defStreams & aiDefaultLogStream_STDOUT ) { - m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDOUT ) ); - } - - // Stream the log to CERR? - if ( defStreams & aiDefaultLogStream_STDERR ) { - m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDERR ) ); - } - - // Stream the log to a file - if ( defStreams & aiDefaultLogStream_FILE && name && *name ) { - m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_FILE, name, io ) ); - } - - return m_pLogger; -} - -// ---------------------------------------------------------------------------------- -void Logger::debug(const char* message) { - - // SECURITY FIX: otherwise it's easy to produce overruns since - // sometimes importers will include data from the input file - // (i.e. node names) in their messages. - if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) { - return; - } - return OnDebug(message); -} - -// ---------------------------------------------------------------------------------- -void Logger::info(const char* message) { - - // SECURITY FIX: see above - if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) { - return; - } - return OnInfo(message); -} - -// ---------------------------------------------------------------------------------- -void Logger::warn(const char* message) { - - // SECURITY FIX: see above - if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) { - return; - } - return OnWarn(message); -} - -// ---------------------------------------------------------------------------------- -void Logger::error(const char* message) { - // SECURITY FIX: see above - if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) { - return; - } - return OnError(message); -} - -// ---------------------------------------------------------------------------------- -void DefaultLogger::set( Logger *logger ) { - // enter the mutex here to avoid concurrency problems -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard<std::mutex> lock(loggerMutex); -#endif - - if ( nullptr == logger ) { - logger = &s_pNullLogger; - } - if ( nullptr != m_pLogger && !isNullLogger() ) { - delete m_pLogger; - } - - DefaultLogger::m_pLogger = logger; -} - -// ---------------------------------------------------------------------------------- -bool DefaultLogger::isNullLogger() { - return m_pLogger == &s_pNullLogger; -} - -// ---------------------------------------------------------------------------------- -Logger *DefaultLogger::get() { - return m_pLogger; -} - -// ---------------------------------------------------------------------------------- -// Kills the only instance -void DefaultLogger::kill() { - // enter the mutex here to avoid concurrency problems -#ifndef ASSIMP_BUILD_SINGLETHREADED - std::lock_guard<std::mutex> lock(loggerMutex); -#endif - - if ( m_pLogger == &s_pNullLogger ) { - return; - } - delete m_pLogger; - m_pLogger = &s_pNullLogger; -} - -// ---------------------------------------------------------------------------------- -// Debug message -void DefaultLogger::OnDebug( const char* message ) { - if ( m_Severity == Logger::NORMAL ) { - return; - } - - static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; - char msg[Size]; - ai_snprintf(msg, Size, "Debug, T%u: %s", GetThreadID(), message); - - WriteToStreams( msg, Logger::Debugging ); -} - -// ---------------------------------------------------------------------------------- -// Logs an info -void DefaultLogger::OnInfo( const char* message ){ - static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; - char msg[Size]; - ai_snprintf(msg, Size, "Info, T%u: %s", GetThreadID(), message ); - - WriteToStreams( msg , Logger::Info ); -} - -// ---------------------------------------------------------------------------------- -// Logs a warning -void DefaultLogger::OnWarn( const char* message ) { - static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; - char msg[Size]; - ai_snprintf(msg, Size, "Warn, T%u: %s", GetThreadID(), message ); - - WriteToStreams( msg, Logger::Warn ); -} - -// ---------------------------------------------------------------------------------- -// Logs an error -void DefaultLogger::OnError( const char* message ) { - static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; - char msg[ Size ]; - ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message ); - - WriteToStreams( msg, Logger::Err ); -} - -// ---------------------------------------------------------------------------------- -// Will attach a new stream -bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) { - if ( nullptr == pStream ) { - return false; - } - - if (0 == severity) { - severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging; - } - - for ( StreamIt it = m_StreamArray.begin(); - it != m_StreamArray.end(); - ++it ) - { - if ( (*it)->m_pStream == pStream ) { - (*it)->m_uiErrorSeverity |= severity; - return true; - } - } - - LogStreamInfo *pInfo = new LogStreamInfo( severity, pStream ); - m_StreamArray.push_back( pInfo ); - return true; -} - -// ---------------------------------------------------------------------------------- -// Detach a stream -bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) { - if ( nullptr == pStream ) { - return false; - } - - if (0 == severity) { - severity = SeverityAll; - } - - bool res( false ); - for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) { - if ( (*it)->m_pStream == pStream ) { - (*it)->m_uiErrorSeverity &= ~severity; - if ( (*it)->m_uiErrorSeverity == 0 ) { - // don't delete the underlying stream 'cause the caller gains ownership again - (**it).m_pStream = nullptr; - delete *it; - m_StreamArray.erase( it ); - res = true; - break; - } - return true; - } - } - return res; -} - -// ---------------------------------------------------------------------------------- -// Constructor -DefaultLogger::DefaultLogger(LogSeverity severity) - : Logger ( severity ) - , noRepeatMsg (false) - , lastLen( 0 ) { - lastMsg[0] = '\0'; -} - -// ---------------------------------------------------------------------------------- -// Destructor -DefaultLogger::~DefaultLogger() { - for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) { - // also frees the underlying stream, we are its owner. - delete *it; - } -} - -// ---------------------------------------------------------------------------------- -// Writes message to stream -void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev ) { - ai_assert(nullptr != message); - - // Check whether this is a repeated message - if (! ::strncmp( message,lastMsg, lastLen-1)) - { - if (!noRepeatMsg) - { - noRepeatMsg = true; - message = "Skipping one or more lines with the same contents\n"; - } - else return; - } - else - { - // append a new-line character to the message to be printed - lastLen = ::strlen(message); - ::memcpy(lastMsg,message,lastLen+1); - ::strcat(lastMsg+lastLen,"\n"); - - message = lastMsg; - noRepeatMsg = false; - ++lastLen; - } - for ( ConstStreamIt it = m_StreamArray.begin(); - it != m_StreamArray.end(); - ++it) - { - if ( ErrorSev & (*it)->m_uiErrorSeverity ) - (*it)->m_pStream->write( message); - } -} - -// ---------------------------------------------------------------------------------- -// Returns thread id, if not supported only a zero will be returned. -unsigned int DefaultLogger::GetThreadID() -{ - // fixme: we can get this value via std::threads - // std::this_thread::get_id().hash() returns a (big) size_t, not sure if this is useful in this case. -#ifdef WIN32 - return (unsigned int)::GetCurrentThreadId(); -#else - return 0; // not supported -#endif -} - -// ---------------------------------------------------------------------------------- - -} // !namespace Assimp diff --git a/thirdparty/assimp/code/Common/DefaultProgressHandler.h b/thirdparty/assimp/code/Common/DefaultProgressHandler.h deleted file mode 100644 index bd2cce00be..0000000000 --- a/thirdparty/assimp/code/Common/DefaultProgressHandler.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file ProgressHandler.hpp - * @brief Abstract base class 'ProgressHandler'. - */ -#ifndef INCLUDED_AI_DEFAULTPROGRESSHANDLER_H -#define INCLUDED_AI_DEFAULTPROGRESSHANDLER_H - -#include <assimp/ProgressHandler.hpp> - -namespace Assimp { - -// ------------------------------------------------------------------------------------ -/** @brief Internal default implementation of the #ProgressHandler interface. */ -class DefaultProgressHandler : public ProgressHandler { - - virtual bool Update(float /*percentage*/) { - return false; - } - - -}; // !class DefaultProgressHandler -} // Namespace Assimp - -#endif diff --git a/thirdparty/assimp/code/Common/Exporter.cpp b/thirdparty/assimp/code/Common/Exporter.cpp deleted file mode 100644 index 4ce1a2bd80..0000000000 --- a/thirdparty/assimp/code/Common/Exporter.cpp +++ /dev/null @@ -1,636 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Exporter.cpp - -Assimp export interface. While it's public interface bears many similarities -to the import interface (in fact, it is largely symmetric), the internal -implementations differs a lot. Exporters are considered stateless and are -simple callbacks which we maintain in a global list along with their -description strings. - -Here we implement only the C++ interface (Assimp::Exporter). -*/ - -#ifndef ASSIMP_BUILD_NO_EXPORT - -#include <assimp/BlobIOSystem.h> -#include <assimp/SceneCombiner.h> -#include <assimp/DefaultIOSystem.h> -#include <assimp/Exporter.hpp> -#include <assimp/mesh.h> -#include <assimp/postprocess.h> -#include <assimp/scene.h> -#include <assimp/Exceptional.h> - -#include "Common/DefaultProgressHandler.h" -#include "Common/BaseProcess.h" -#include "Common/ScenePrivate.h" -#include "PostProcessing/CalcTangentsProcess.h" -#include "PostProcessing/MakeVerboseFormat.h" -#include "PostProcessing/JoinVerticesProcess.h" -#include "PostProcessing/ConvertToLHProcess.h" -#include "PostProcessing/PretransformVertices.h" - -#include <memory> - -namespace Assimp { - -// PostStepRegistry.cpp -void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out); - -// ------------------------------------------------------------------------------------------------ -// Exporter worker function prototypes. Should not be necessary to #ifndef them, it's just a prototype -// do not use const, because some exporter need to convert the scene temporary -void ExportSceneCollada(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneXFile(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneStep(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneObj(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneObjNoMtl(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneSTL(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*); -void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneGLTF2(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneGLB2(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); -void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportSceneA3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); -void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); - -// ------------------------------------------------------------------------------------------------ -// global array of all export formats which Assimp supports in its current build -Exporter::ExportFormatEntry gExporters[] = -{ -#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER - Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada ), -#endif - -#ifndef ASSIMP_BUILD_NO_X_EXPORTER - Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile, - aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs ), -#endif - -#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER - Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER - Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj, - aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ), - Exporter::ExportFormatEntry( "objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl, - aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ), -#endif - -#ifndef ASSIMP_BUILD_NO_STL_EXPORTER - Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL, - aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices - ), - Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary, - aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices - ), -#endif - -#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER - Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly, - aiProcess_PreTransformVertices - ), - Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary, - aiProcess_PreTransformVertices - ), -#endif - -#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER - Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS, - aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices ), -#endif - -#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER - Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), - Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, - aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), -#endif - -#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER - Exporter::ExportFormatEntry( "assbin", "Assimp Binary File", "assbin" , &ExportSceneAssbin, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER - Exporter::ExportFormatEntry( "assxml", "Assimp XML Document", "assxml" , &ExportSceneAssxml, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER - Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ), - Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER - Exporter::ExportFormatEntry( "m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0 ), - Exporter::ExportFormatEntry( "a3d", "Model 3D (ascii)", "m3d", &ExportSceneA3D, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER - Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ), -#endif - -#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER - Exporter::ExportFormatEntry( "assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0) -#endif -}; - -#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0])) - - -class ExporterPimpl { -public: - ExporterPimpl() - : blob() - , mIOSystem(new Assimp::DefaultIOSystem()) - , mIsDefaultIOHandler(true) - , mProgressHandler( nullptr ) - , mIsDefaultProgressHandler( true ) - , mPostProcessingSteps() - , mError() - , mExporters() { - GetPostProcessingStepInstanceList(mPostProcessingSteps); - - // grab all built-in exporters - if ( 0 != ( ASSIMP_NUM_EXPORTERS ) ) { - mExporters.resize( ASSIMP_NUM_EXPORTERS ); - std::copy( gExporters, gExporters + ASSIMP_NUM_EXPORTERS, mExporters.begin() ); - } - } - - ~ExporterPimpl() { - delete blob; - - // Delete all post-processing plug-ins - for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) { - delete mPostProcessingSteps[a]; - } - delete mProgressHandler; - } - -public: - aiExportDataBlob* blob; - std::shared_ptr< Assimp::IOSystem > mIOSystem; - bool mIsDefaultIOHandler; - - /** The progress handler */ - ProgressHandler *mProgressHandler; - bool mIsDefaultProgressHandler; - - /** Post processing steps we can apply at the imported data. */ - std::vector< BaseProcess* > mPostProcessingSteps; - - /** Last fatal export error */ - std::string mError; - - /** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */ - std::vector<Exporter::ExportFormatEntry> mExporters; -}; - -} // end of namespace Assimp - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -Exporter :: Exporter() -: pimpl(new ExporterPimpl()) { - pimpl->mProgressHandler = new DefaultProgressHandler(); -} - -// ------------------------------------------------------------------------------------------------ -Exporter::~Exporter() { - FreeBlob(); - delete pimpl; -} - -// ------------------------------------------------------------------------------------------------ -void Exporter::SetIOHandler( IOSystem* pIOHandler) { - pimpl->mIsDefaultIOHandler = !pIOHandler; - pimpl->mIOSystem.reset(pIOHandler); -} - -// ------------------------------------------------------------------------------------------------ -IOSystem* Exporter::GetIOHandler() const { - return pimpl->mIOSystem.get(); -} - -// ------------------------------------------------------------------------------------------------ -bool Exporter::IsDefaultIOHandler() const { - return pimpl->mIsDefaultIOHandler; -} - -// ------------------------------------------------------------------------------------------------ -void Exporter::SetProgressHandler(ProgressHandler* pHandler) { - ai_assert(nullptr != pimpl); - - if ( nullptr == pHandler) { - // Release pointer in the possession of the caller - pimpl->mProgressHandler = new DefaultProgressHandler(); - pimpl->mIsDefaultProgressHandler = true; - return; - } - - if (pimpl->mProgressHandler == pHandler) { - return; - } - - delete pimpl->mProgressHandler; - pimpl->mProgressHandler = pHandler; - pimpl->mIsDefaultProgressHandler = false; -} - -// ------------------------------------------------------------------------------------------------ -const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId, - unsigned int pPreprocessing, const ExportProperties* pProperties) { - if (pimpl->blob) { - delete pimpl->blob; - pimpl->blob = nullptr; - } - - std::shared_ptr<IOSystem> old = pimpl->mIOSystem; - BlobIOSystem* blobio = new BlobIOSystem(); - pimpl->mIOSystem = std::shared_ptr<IOSystem>( blobio ); - - if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName(), pPreprocessing, pProperties)) { - pimpl->mIOSystem = old; - return nullptr; - } - - pimpl->blob = blobio->GetBlobChain(); - pimpl->mIOSystem = old; - - return pimpl->blob; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, - unsigned int pPreprocessing, const ExportProperties* pProperties) { - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // when they create scenes from scratch, users will likely create them not in verbose - // format. They will likely not be aware that there is a flag in the scene to indicate - // this, however. To avoid surprises and bug reports, we check for duplicates in - // meshes upfront. - const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || MakeVerboseFormatProcess::IsVerboseFormat(pScene); - - pimpl->mProgressHandler->UpdateFileWrite(0, 4); - - pimpl->mError = ""; - for (size_t i = 0; i < pimpl->mExporters.size(); ++i) { - const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i]; - if (!strcmp(exp.mDescription.id,pFormatId)) { - try { - // Always create a full copy of the scene. We might optimize this one day, - // but for now it is the most pragmatic way. - aiScene* scenecopy_tmp = nullptr; - SceneCombiner::CopyScene(&scenecopy_tmp,pScene); - - pimpl->mProgressHandler->UpdateFileWrite(1, 4); - - std::unique_ptr<aiScene> scenecopy(scenecopy_tmp); - const ScenePrivateData* const priv = ScenePriv(pScene); - - // steps that are not idempotent, i.e. we might need to run them again, usually to get back to the - // original state before the step was applied first. When checking which steps we don't need - // to run, those are excluded. - const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded; - - // Erase all pp steps that were already applied to this scene - const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy - ? (priv->mPPStepsApplied & ~nonIdempotentSteps) - : 0u); - - // If no extra post-processing was specified, and we obtained this scene from an - // Assimp importer, apply the reverse steps automatically. - // TODO: either drop this, or document it. Otherwise it is just a bad surprise. - //if (!pPreprocessing && priv) { - // pp |= (nonIdempotentSteps & priv->mPPStepsApplied); - //} - - // If the input scene is not in verbose format, but there is at least post-processing step that relies on it, - // we need to run the MakeVerboseFormat step first. - bool must_join_again = false; - if (!is_verbose_format) { - bool verbosify = false; - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - BaseProcess* const p = pimpl->mPostProcessingSteps[a]; - - if (p->IsActive(pp) && p->RequireVerboseFormat()) { - verbosify = true; - break; - } - } - - if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) { - ASSIMP_LOG_DEBUG("export: Scene data not in verbose format, applying MakeVerboseFormat step first"); - - MakeVerboseFormatProcess proc; - proc.Execute(scenecopy.get()); - - if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) { - must_join_again = true; - } - } - } - - pimpl->mProgressHandler->UpdateFileWrite(2, 4); - - if (pp) { - // the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout - { - FlipWindingOrderProcess step; - if (step.IsActive(pp)) { - step.Execute(scenecopy.get()); - } - } - - { - FlipUVsProcess step; - if (step.IsActive(pp)) { - step.Execute(scenecopy.get()); - } - } - - { - MakeLeftHandedProcess step; - if (step.IsActive(pp)) { - step.Execute(scenecopy.get()); - } - } - - bool exportPointCloud(false); - if (nullptr != pProperties) { - exportPointCloud = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); - } - - // dispatch other processes - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - BaseProcess* const p = pimpl->mPostProcessingSteps[a]; - - if (p->IsActive(pp) - && !dynamic_cast<FlipUVsProcess*>(p) - && !dynamic_cast<FlipWindingOrderProcess*>(p) - && !dynamic_cast<MakeLeftHandedProcess*>(p)) { - if (dynamic_cast<PretransformVertices*>(p) && exportPointCloud) { - continue; - } - p->Execute(scenecopy.get()); - } - } - ScenePrivateData* const privOut = ScenePriv(scenecopy.get()); - ai_assert(nullptr != privOut); - - privOut->mPPStepsApplied |= pp; - } - - pimpl->mProgressHandler->UpdateFileWrite(3, 4); - - if(must_join_again) { - JoinVerticesProcess proc; - proc.Execute(scenecopy.get()); - } - - ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry. - ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties; - pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again); - exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); - exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); - - pimpl->mProgressHandler->UpdateFileWrite(4, 4); - } catch (DeadlyExportError& err) { - pimpl->mError = err.what(); - return AI_FAILURE; - } - return AI_SUCCESS; - } - } - - pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId; - ASSIMP_END_EXCEPTION_REGION(aiReturn); - - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -const char* Exporter::GetErrorString() const { - return pimpl->mError.c_str(); -} - -// ------------------------------------------------------------------------------------------------ -void Exporter::FreeBlob() { - delete pimpl->blob; - pimpl->blob = nullptr; - - pimpl->mError = ""; -} - -// ------------------------------------------------------------------------------------------------ -const aiExportDataBlob* Exporter::GetBlob() const { - return pimpl->blob; -} - -// ------------------------------------------------------------------------------------------------ -const aiExportDataBlob* Exporter::GetOrphanedBlob() const { - const aiExportDataBlob* tmp = pimpl->blob; - pimpl->blob = nullptr; - return tmp; -} - -// ------------------------------------------------------------------------------------------------ -size_t Exporter::GetExportFormatCount() const { - return pimpl->mExporters.size(); -} - -// ------------------------------------------------------------------------------------------------ -const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const { - if (index >= GetExportFormatCount()) { - return nullptr; - } - - // Return from static storage if the requested index is built-in. - if (index < sizeof(gExporters) / sizeof(gExporters[0])) { - return &gExporters[index].mDescription; - } - - return &pimpl->mExporters[index].mDescription; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) { - for(const ExportFormatEntry& e : pimpl->mExporters) { - if (!strcmp(e.mDescription.id,desc.mDescription.id)) { - return aiReturn_FAILURE; - } - } - - pimpl->mExporters.push_back(desc); - return aiReturn_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -void Exporter::UnregisterExporter(const char* id) { - for(std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin(); - it != pimpl->mExporters.end(); ++it) { - if (!strcmp((*it).mDescription.id,id)) { - pimpl->mExporters.erase(it); - break; - } - } -} - -// ------------------------------------------------------------------------------------------------ -ExportProperties::ExportProperties() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -ExportProperties::ExportProperties(const ExportProperties &other) -: mIntProperties(other.mIntProperties) -, mFloatProperties(other.mFloatProperties) -, mStringProperties(other.mStringProperties) -, mMatrixProperties(other.mMatrixProperties) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool ExportProperties::SetPropertyInteger(const char* szName, int iValue) { - return SetGenericProperty<int>(mIntProperties, szName,iValue); -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool ExportProperties::SetPropertyFloat(const char* szName, ai_real iValue) { - return SetGenericProperty<ai_real>(mFloatProperties, szName,iValue); -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool ExportProperties::SetPropertyString(const char* szName, const std::string& value) { - return SetGenericProperty<std::string>(mStringProperties, szName,value); -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool ExportProperties::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) { - return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -int ExportProperties::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const { - return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -ai_real ExportProperties::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const { - return GetGenericProperty<ai_real>(mFloatProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -const std::string ExportProperties::GetPropertyString(const char* szName, - const std::string& iErrorReturn /*= ""*/) const { - return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -const aiMatrix4x4 ExportProperties::GetPropertyMatrix(const char* szName, - const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const { - return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyInteger(const char* szName) const { - return HasGenericProperty<int>(mIntProperties, szName); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyBool(const char* szName) const { - return HasGenericProperty<int>(mIntProperties, szName); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyFloat(const char* szName) const { - return HasGenericProperty<ai_real>(mFloatProperties, szName); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyString(const char* szName) const { - return HasGenericProperty<std::string>(mStringProperties, szName); -} - -// ------------------------------------------------------------------------------------------------ -// Has a configuration property -bool ExportProperties::HasPropertyMatrix(const char* szName) const { - return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName); -} - - -#endif // !ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/Common/FileLogStream.h b/thirdparty/assimp/code/Common/FileLogStream.h deleted file mode 100644 index 740c503192..0000000000 --- a/thirdparty/assimp/code/Common/FileLogStream.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -/** @file FileLofStream.h -*/ -#ifndef ASSIMP_FILELOGSTREAM_H_INC -#define ASSIMP_FILELOGSTREAM_H_INC - -#include <assimp/LogStream.hpp> -#include <assimp/IOStream.hpp> -#include <assimp/DefaultIOSystem.h> - -namespace Assimp { - -// ---------------------------------------------------------------------------------- -/** @class FileLogStream - * @brief Logstream to write into a file. - */ -class FileLogStream : - public LogStream -{ -public: - FileLogStream( const char* file, IOSystem* io = NULL ); - ~FileLogStream(); - void write( const char* message ); - -private: - IOStream *m_pStream; -}; - -// ---------------------------------------------------------------------------------- -// Constructor -inline FileLogStream::FileLogStream( const char* file, IOSystem* io ) : - m_pStream(NULL) -{ - if ( !file || 0 == *file ) - return; - - // If no IOSystem is specified: take a default one - if (!io) - { - DefaultIOSystem FileSystem; - m_pStream = FileSystem.Open( file, "wt"); - } - else m_pStream = io->Open( file, "wt" ); -} - -// ---------------------------------------------------------------------------------- -// Destructor -inline FileLogStream::~FileLogStream() -{ - // The virtual d'tor should destroy the underlying file - delete m_pStream; -} - -// ---------------------------------------------------------------------------------- -// Write method -inline void FileLogStream::write( const char* message ) -{ - if (m_pStream != NULL) - { - m_pStream->Write(message, sizeof(char), ::strlen(message)); - m_pStream->Flush(); - } -} - -// ---------------------------------------------------------------------------------- -} // !Namespace Assimp - -#endif // !! ASSIMP_FILELOGSTREAM_H_INC diff --git a/thirdparty/assimp/code/Common/FileSystemFilter.h b/thirdparty/assimp/code/Common/FileSystemFilter.h deleted file mode 100644 index 9923cdbdd3..0000000000 --- a/thirdparty/assimp/code/Common/FileSystemFilter.h +++ /dev/null @@ -1,345 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2008, assimp team -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FileSystemFilter.h - * Implements a filter system to filter calls to Exists() and Open() - * in order to improve the success rate of file opening ... - */ -#pragma once -#ifndef AI_FILESYSTEMFILTER_H_INC -#define AI_FILESYSTEMFILTER_H_INC - -#include <assimp/IOSystem.hpp> -#include <assimp/DefaultLogger.hpp> -#include <assimp/fast_atof.h> -#include <assimp/ParsingUtils.h> - -namespace Assimp { - -inline bool IsHex(char s) { - return (s>='0' && s<='9') || (s>='a' && s<='f') || (s>='A' && s<='F'); -} - -// --------------------------------------------------------------------------- -/** File system filter - */ -class FileSystemFilter : public IOSystem -{ -public: - /** Constructor. */ - FileSystemFilter(const std::string& file, IOSystem* old) - : mWrapped (old) - , mSrc_file(file) - , mSep(mWrapped->getOsSeparator()) { - ai_assert(nullptr != mWrapped); - - // Determine base directory - mBase = mSrc_file; - std::string::size_type ss2; - if (std::string::npos != (ss2 = mBase.find_last_of("\\/"))) { - mBase.erase(ss2,mBase.length()-ss2); - } else { - mBase = ""; - } - - // make sure the directory is terminated properly - char s; - - if ( mBase.empty() ) { - mBase = "."; - mBase += getOsSeparator(); - } else if ((s = *(mBase.end()-1)) != '\\' && s != '/') { - mBase += getOsSeparator(); - } - - DefaultLogger::get()->info("Import root directory is \'" + mBase + "\'"); - } - - /** Destructor. */ - ~FileSystemFilter() { - // empty - } - - // ------------------------------------------------------------------- - /** Tests for the existence of a file at the given path. */ - bool Exists( const char* pFile) const { - ai_assert( nullptr != mWrapped ); - - std::string tmp = pFile; - - // Currently this IOSystem is also used to open THE ONE FILE. - if (tmp != mSrc_file) { - BuildPath(tmp); - Cleanup(tmp); - } - - return mWrapped->Exists(tmp); - } - - // ------------------------------------------------------------------- - /** Returns the directory separator. */ - char getOsSeparator() const { - return mSep; - } - - // ------------------------------------------------------------------- - /** Open a new file with a given path. */ - IOStream* Open( const char* pFile, const char* pMode = "rb") { - ai_assert( nullptr != mWrapped ); - if ( nullptr == pFile || nullptr == pMode ) { - return nullptr; - } - - ai_assert( nullptr != pFile ); - ai_assert( nullptr != pMode ); - - // First try the unchanged path - IOStream* s = mWrapped->Open(pFile,pMode); - - if (nullptr == s) { - std::string tmp = pFile; - - // Try to convert between absolute and relative paths - BuildPath(tmp); - s = mWrapped->Open(tmp,pMode); - - if (nullptr == s) { - // Finally, look for typical issues with paths - // and try to correct them. This is our last - // resort. - tmp = pFile; - Cleanup(tmp); - BuildPath(tmp); - s = mWrapped->Open(tmp,pMode); - } - } - - return s; - } - - // ------------------------------------------------------------------- - /** Closes the given file and releases all resources associated with it. */ - void Close( IOStream* pFile) { - ai_assert( nullptr != mWrapped ); - return mWrapped->Close(pFile); - } - - // ------------------------------------------------------------------- - /** Compare two paths */ - bool ComparePaths (const char* one, const char* second) const { - ai_assert( nullptr != mWrapped ); - return mWrapped->ComparePaths (one,second); - } - - // ------------------------------------------------------------------- - /** Pushes a new directory onto the directory stack. */ - bool PushDirectory(const std::string &path ) { - ai_assert( nullptr != mWrapped ); - return mWrapped->PushDirectory(path); - } - - // ------------------------------------------------------------------- - /** Returns the top directory from the stack. */ - const std::string &CurrentDirectory() const { - ai_assert( nullptr != mWrapped ); - return mWrapped->CurrentDirectory(); - } - - // ------------------------------------------------------------------- - /** Returns the number of directories stored on the stack. */ - size_t StackSize() const { - ai_assert( nullptr != mWrapped ); - return mWrapped->StackSize(); - } - - // ------------------------------------------------------------------- - /** Pops the top directory from the stack. */ - bool PopDirectory() { - ai_assert( nullptr != mWrapped ); - return mWrapped->PopDirectory(); - } - - // ------------------------------------------------------------------- - /** Creates an new directory at the given path. */ - bool CreateDirectory(const std::string &path) { - ai_assert( nullptr != mWrapped ); - return mWrapped->CreateDirectory(path); - } - - // ------------------------------------------------------------------- - /** Will change the current directory to the given path. */ - bool ChangeDirectory(const std::string &path) { - ai_assert( nullptr != mWrapped ); - return mWrapped->ChangeDirectory(path); - } - - // ------------------------------------------------------------------- - /** Delete file. */ - bool DeleteFile(const std::string &file) { - ai_assert( nullptr != mWrapped ); - return mWrapped->DeleteFile(file); - } - -private: - // ------------------------------------------------------------------- - /** Build a valid path from a given relative or absolute path. - */ - void BuildPath (std::string& in) const { - ai_assert( nullptr != mWrapped ); - // if we can already access the file, great. - if (in.length() < 3 || mWrapped->Exists(in)) { - return; - } - - // Determine whether this is a relative path (Windows-specific - most assets are packaged on Windows). - if (in[1] != ':') { - - // append base path and try - const std::string tmp = mBase + in; - if (mWrapped->Exists(tmp)) { - in = tmp; - return; - } - } - - // Chop of the file name and look in the model directory, if - // this fails try all sub paths of the given path, i.e. - // if the given path is foo/bar/something.lwo, try - // <base>/something.lwo - // <base>/bar/something.lwo - // <base>/foo/bar/something.lwo - std::string::size_type pos = in.rfind('/'); - if (std::string::npos == pos) { - pos = in.rfind('\\'); - } - - if (std::string::npos != pos) { - std::string tmp; - std::string::size_type last_dirsep = std::string::npos; - - while(true) { - tmp = mBase; - tmp += mSep; - - std::string::size_type dirsep = in.rfind('/', last_dirsep); - if (std::string::npos == dirsep) { - dirsep = in.rfind('\\', last_dirsep); - } - - if (std::string::npos == dirsep || dirsep == 0) { - // we did try this already. - break; - } - - last_dirsep = dirsep-1; - - tmp += in.substr(dirsep+1, in.length()-pos); - if (mWrapped->Exists(tmp)) { - in = tmp; - return; - } - } - } - - // hopefully the underlying file system has another few tricks to access this file ... - } - - // ------------------------------------------------------------------- - /** Cleanup the given path - */ - void Cleanup (std::string& in) const { - if(in.empty()) { - return; - } - - // Remove a very common issue when we're parsing file names: spaces at the - // beginning of the path. - char last = 0; - std::string::iterator it = in.begin(); - while (IsSpaceOrNewLine( *it ))++it; - if (it != in.begin()) { - in.erase(in.begin(),it+1); - } - - const char separator = getOsSeparator(); - for (it = in.begin(); it != in.end(); ++it) { - // Exclude :// and \\, which remain untouched. - // https://sourceforge.net/tracker/?func=detail&aid=3031725&group_id=226462&atid=1067632 - if ( !strncmp(&*it, "://", 3 )) { - it += 3; - continue; - } - if (it == in.begin() && !strncmp(&*it, "\\\\", 2)) { - it += 2; - continue; - } - - // Cleanup path delimiters - if (*it == '/' || (*it) == '\\') { - *it = separator; - - // And we're removing double delimiters, frequent issue with - // incorrectly composited paths ... - if (last == *it) { - it = in.erase(it); - --it; - } - } else if (*it == '%' && in.end() - it > 2) { - // Hex sequence in URIs - if( IsHex((&*it)[0]) && IsHex((&*it)[1]) ) { - *it = HexOctetToDecimal(&*it); - it = in.erase(it+1,it+2); - --it; - } - } - - last = *it; - } - } - -private: - IOSystem *mWrapped; - std::string mSrc_file, mBase; - char mSep; -}; - -} //!ns Assimp - -#endif //AI_DEFAULTIOSYSTEM_H_INC diff --git a/thirdparty/assimp/code/Common/IFF.h b/thirdparty/assimp/code/Common/IFF.h deleted file mode 100644 index 91d7d48289..0000000000 --- a/thirdparty/assimp/code/Common/IFF.h +++ /dev/null @@ -1,102 +0,0 @@ -// Definitions for the Interchange File Format (IFF) -// Alexander Gessler, 2006 -// Adapted to Assimp August 2008 - -#ifndef AI_IFF_H_INCLUDED -#define AI_IFF_H_INCLUDED - -#include <assimp/ByteSwapper.h> - -namespace Assimp { -namespace IFF { - -///////////////////////////////////////////////////////////////////////////////// -//! Describes an IFF chunk header -///////////////////////////////////////////////////////////////////////////////// -struct ChunkHeader -{ - //! Type of the chunk header - FourCC - uint32_t type; - - //! Length of the chunk data, in bytes - uint32_t length; -}; - - -///////////////////////////////////////////////////////////////////////////////// -//! Describes an IFF sub chunk header -///////////////////////////////////////////////////////////////////////////////// -struct SubChunkHeader -{ - //! Type of the chunk header - FourCC - uint32_t type; - - //! Length of the chunk data, in bytes - uint16_t length; -}; - - -#define AI_IFF_FOURCC(a,b,c,d) ((uint32_t) (((uint8_t)a << 24u) | \ - ((uint8_t)b << 16u) | ((uint8_t)c << 8u) | ((uint8_t)d))) - - -#define AI_IFF_FOURCC_FORM AI_IFF_FOURCC('F','O','R','M') - - -///////////////////////////////////////////////////////////////////////////////// -//! Load a chunk header -//! @param outFile Pointer to the file data - points to the chunk data afterwards -//! @return Copy of the chunk header -///////////////////////////////////////////////////////////////////////////////// -inline ChunkHeader LoadChunk(uint8_t*& outFile) -{ - ChunkHeader head; - ::memcpy(&head.type, outFile, 4); - outFile += 4; - ::memcpy(&head.length, outFile, 4); - outFile += 4; - AI_LSWAP4(head.length); - AI_LSWAP4(head.type); - return head; -} - -///////////////////////////////////////////////////////////////////////////////// -//! Load a sub chunk header -//! @param outFile Pointer to the file data - points to the chunk data afterwards -//! @return Copy of the sub chunk header -///////////////////////////////////////////////////////////////////////////////// -inline SubChunkHeader LoadSubChunk(uint8_t*& outFile) -{ - SubChunkHeader head; - ::memcpy(&head.type, outFile, 4); - outFile += 4; - ::memcpy(&head.length, outFile, 2); - outFile += 2; - AI_LSWAP2(head.length); - AI_LSWAP4(head.type); - return head; -} - -///////////////////////////////////////////////////////////////////////////////// -//! Read the file header and return the type of the file and its size -//! @param outFile Pointer to the file data. The buffer must at -//! least be 12 bytes large. -//! @param fileType Receives the type of the file -//! @return 0 if everything was OK, otherwise an error message -///////////////////////////////////////////////////////////////////////////////// -inline const char* ReadHeader(uint8_t* outFile, uint32_t& fileType) -{ - ChunkHeader head = LoadChunk(outFile); - if(AI_IFF_FOURCC_FORM != head.type) - { - return "The file is not an IFF file: FORM chunk is missing"; - } - ::memcpy(&fileType, outFile, 4); - AI_LSWAP4(fileType); - return 0; -} - - -}} - -#endif // !! AI_IFF_H_INCLUDED diff --git a/thirdparty/assimp/code/Common/Importer.cpp b/thirdparty/assimp/code/Common/Importer.cpp deleted file mode 100644 index 91b50859a0..0000000000 --- a/thirdparty/assimp/code/Common/Importer.cpp +++ /dev/null @@ -1,1174 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Importer.cpp - * @brief Implementation of the CPP-API class #Importer - */ - -#include <assimp/version.h> -#include <assimp/config.h> -#include <assimp/importerdesc.h> - -// ------------------------------------------------------------------------------------------------ -/* Uncomment this line to prevent Assimp from catching unknown exceptions. - * - * Note that any Exception except DeadlyImportError may lead to - * undefined behaviour -> loaders could remain in an unusable state and - * further imports with the same Importer instance could fail/crash/burn ... - */ -// ------------------------------------------------------------------------------------------------ -#ifndef ASSIMP_BUILD_DEBUG -# define ASSIMP_CATCH_GLOBAL_EXCEPTIONS -#endif - -// ------------------------------------------------------------------------------------------------ -// Internal headers -// ------------------------------------------------------------------------------------------------ -#include "Common/Importer.h" -#include "Common/BaseProcess.h" -#include "Common/DefaultProgressHandler.h" -#include "PostProcessing/ProcessHelper.h" -#include "Common/ScenePreprocessor.h" -#include "Common/ScenePrivate.h" - -#include <assimp/BaseImporter.h> -#include <assimp/GenericProperty.h> -#include <assimp/MemoryIOWrapper.h> -#include <assimp/Profiler.h> -#include <assimp/TinyFormatter.h> -#include <assimp/Exceptional.h> -#include <assimp/Profiler.h> -#include <set> -#include <memory> -#include <cctype> - -#include <assimp/DefaultIOStream.h> -#include <assimp/DefaultIOSystem.h> - -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS -# include "PostProcessing/ValidateDataStructure.h" -#endif - -using namespace Assimp::Profiling; -using namespace Assimp::Formatter; - -namespace Assimp { - // ImporterRegistry.cpp - void GetImporterInstanceList(std::vector< BaseImporter* >& out); - void DeleteImporterInstanceList(std::vector< BaseImporter* >& out); - - // PostStepRegistry.cpp - void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out); -} - -using namespace Assimp; -using namespace Assimp::Intern; - -// ------------------------------------------------------------------------------------------------ -// Intern::AllocateFromAssimpHeap serves as abstract base class. It overrides -// new and delete (and their array counterparts) of public API classes (e.g. Logger) to -// utilize our DLL heap. -// See http://www.gotw.ca/publications/mill15.htm -// ------------------------------------------------------------------------------------------------ -void* AllocateFromAssimpHeap::operator new ( size_t num_bytes) { - return ::operator new(num_bytes); -} - -void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothrow_t& ) throw() { - try { - return AllocateFromAssimpHeap::operator new( num_bytes ); - } - catch( ... ) { - return NULL; - } -} - -void AllocateFromAssimpHeap::operator delete ( void* data) { - return ::operator delete(data); -} - -void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) { - return ::operator new[](num_bytes); -} - -void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() { - try { - return AllocateFromAssimpHeap::operator new[]( num_bytes ); - } - catch( ... ) { - return NULL; - } -} - -void AllocateFromAssimpHeap::operator delete[] ( void* data) { - return ::operator delete[](data); -} - -// ------------------------------------------------------------------------------------------------ -// Importer constructor. -Importer::Importer() - : pimpl( new ImporterPimpl ) { - pimpl->mScene = NULL; - pimpl->mErrorString = ""; - - // Allocate a default IO handler - pimpl->mIOHandler = new DefaultIOSystem; - pimpl->mIsDefaultHandler = true; - pimpl->bExtraVerbose = false; // disable extra verbose mode by default - - pimpl->mProgressHandler = new DefaultProgressHandler(); - pimpl->mIsDefaultProgressHandler = true; - - GetImporterInstanceList(pimpl->mImporter); - GetPostProcessingStepInstanceList(pimpl->mPostProcessingSteps); - - // Allocate a SharedPostProcessInfo object and store pointers to it in all post-process steps in the list. - pimpl->mPPShared = new SharedPostProcessInfo(); - for (std::vector<BaseProcess*>::iterator it = pimpl->mPostProcessingSteps.begin(); - it != pimpl->mPostProcessingSteps.end(); - ++it) { - - (*it)->SetSharedData(pimpl->mPPShared); - } -} - -// ------------------------------------------------------------------------------------------------ -// Destructor of Importer -Importer::~Importer() -{ - // Delete all import plugins - DeleteImporterInstanceList(pimpl->mImporter); - - // Delete all post-processing plug-ins - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) - delete pimpl->mPostProcessingSteps[a]; - - // Delete the assigned IO and progress handler - delete pimpl->mIOHandler; - delete pimpl->mProgressHandler; - - // Kill imported scene. Destructor's should do that recursively - delete pimpl->mScene; - - // Delete shared post-processing data - delete pimpl->mPPShared; - - // and finally the pimpl itself - delete pimpl; -} - -// ------------------------------------------------------------------------------------------------ -// Register a custom post-processing step -aiReturn Importer::RegisterPPStep(BaseProcess* pImp) -{ - ai_assert(NULL != pImp); - ASSIMP_BEGIN_EXCEPTION_REGION(); - - pimpl->mPostProcessingSteps.push_back(pImp); - ASSIMP_LOG_INFO("Registering custom post-processing step"); - - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Register a custom loader plugin -aiReturn Importer::RegisterLoader(BaseImporter* pImp) -{ - ai_assert(NULL != pImp); - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // -------------------------------------------------------------------- - // Check whether we would have two loaders for the same file extension - // This is absolutely OK, but we should warn the developer of the new - // loader that his code will probably never be called if the first - // loader is a bit too lazy in his file checking. - // -------------------------------------------------------------------- - std::set<std::string> st; - std::string baked; - pImp->GetExtensionList(st); - - for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) { - -#ifdef ASSIMP_BUILD_DEBUG - if (IsExtensionSupported(*it)) { - ASSIMP_LOG_WARN_F("The file extension ", *it, " is already in use"); - } -#endif - baked += *it; - } - - // add the loader - pimpl->mImporter.push_back(pImp); - ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked); - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Unregister a custom loader plugin -aiReturn Importer::UnregisterLoader(BaseImporter* pImp) -{ - if(!pImp) { - // unregistering a NULL importer is no problem for us ... really! - return AI_SUCCESS; - } - - ASSIMP_BEGIN_EXCEPTION_REGION(); - std::vector<BaseImporter*>::iterator it = std::find(pimpl->mImporter.begin(), - pimpl->mImporter.end(),pImp); - - if (it != pimpl->mImporter.end()) { - pimpl->mImporter.erase(it); - ASSIMP_LOG_INFO("Unregistering custom importer: "); - return AI_SUCCESS; - } - ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ..."); - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -// Unregister a custom loader plugin -aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) -{ - if(!pImp) { - // unregistering a NULL ppstep is no problem for us ... really! - return AI_SUCCESS; - } - - ASSIMP_BEGIN_EXCEPTION_REGION(); - std::vector<BaseProcess*>::iterator it = std::find(pimpl->mPostProcessingSteps.begin(), - pimpl->mPostProcessingSteps.end(),pImp); - - if (it != pimpl->mPostProcessingSteps.end()) { - pimpl->mPostProcessingSteps.erase(it); - ASSIMP_LOG_INFO("Unregistering custom post-processing step"); - return AI_SUCCESS; - } - ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you .."); - ASSIMP_END_EXCEPTION_REGION(aiReturn); - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -// Supplies a custom IO handler to the importer to open and access files. -void Importer::SetIOHandler( IOSystem* pIOHandler) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - // If the new handler is zero, allocate a default IO implementation. - if (!pIOHandler) - { - // Release pointer in the possession of the caller - pimpl->mIOHandler = new DefaultIOSystem(); - pimpl->mIsDefaultHandler = true; - } - // Otherwise register the custom handler - else if (pimpl->mIOHandler != pIOHandler) - { - delete pimpl->mIOHandler; - pimpl->mIOHandler = pIOHandler; - pimpl->mIsDefaultHandler = false; - } - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Get the currently set IO handler -IOSystem* Importer::GetIOHandler() const { - return pimpl->mIOHandler; -} - -// ------------------------------------------------------------------------------------------------ -// Check whether a custom IO handler is currently set -bool Importer::IsDefaultIOHandler() const { - return pimpl->mIsDefaultHandler; -} - -// ------------------------------------------------------------------------------------------------ -// Supplies a custom progress handler to get regular callbacks during importing -void Importer::SetProgressHandler ( ProgressHandler* pHandler ) { - ASSIMP_BEGIN_EXCEPTION_REGION(); - // If the new handler is zero, allocate a default implementation. - if (!pHandler) - { - // Release pointer in the possession of the caller - pimpl->mProgressHandler = new DefaultProgressHandler(); - pimpl->mIsDefaultProgressHandler = true; - } - // Otherwise register the custom handler - else if (pimpl->mProgressHandler != pHandler) - { - delete pimpl->mProgressHandler; - pimpl->mProgressHandler = pHandler; - pimpl->mIsDefaultProgressHandler = false; - } - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Get the currently set progress handler -ProgressHandler* Importer::GetProgressHandler() const { - return pimpl->mProgressHandler; -} - -// ------------------------------------------------------------------------------------------------ -// Check whether a custom progress handler is currently set -bool Importer::IsDefaultProgressHandler() const { - return pimpl->mIsDefaultProgressHandler; -} - -// ------------------------------------------------------------------------------------------------ -// Validate post process step flags -bool _ValidateFlags(unsigned int pFlags) -{ - if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) { - ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible"); - return false; - } - if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices) { - ASSIMP_LOG_ERROR("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible"); - return false; - } - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Free the current scene -void Importer::FreeScene( ) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - - delete pimpl->mScene; - pimpl->mScene = NULL; - - pimpl->mErrorString = ""; - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Get the current error string, if any -const char* Importer::GetErrorString() const -{ - /* Must remain valid as long as ReadFile() or FreeFile() are not called */ - return pimpl->mErrorString.c_str(); -} - -// ------------------------------------------------------------------------------------------------ -// Enable extra-verbose mode -void Importer::SetExtraVerbose(bool bDo) -{ - pimpl->bExtraVerbose = bDo; -} - -// ------------------------------------------------------------------------------------------------ -// Get the current scene -const aiScene* Importer::GetScene() const -{ - return pimpl->mScene; -} - -// ------------------------------------------------------------------------------------------------ -// Orphan the current scene and return it. -aiScene* Importer::GetOrphanedScene() -{ - aiScene* s = pimpl->mScene; - - ASSIMP_BEGIN_EXCEPTION_REGION(); - pimpl->mScene = NULL; - - pimpl->mErrorString = ""; /* reset error string */ - ASSIMP_END_EXCEPTION_REGION(aiScene*); - return s; -} - -// ------------------------------------------------------------------------------------------------ -// Validate post-processing flags -bool Importer::ValidateFlags(unsigned int pFlags) const -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - // run basic checks for mutually exclusive flags - if(!_ValidateFlags(pFlags)) { - return false; - } - - // ValidateDS does not anymore occur in the pp list, it plays an awesome extra role ... -#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - if (pFlags & aiProcess_ValidateDataStructure) { - return false; - } -#endif - pFlags &= ~aiProcess_ValidateDataStructure; - - // Now iterate through all bits which are set in the flags and check whether we find at least - // one pp plugin which handles it. - for (unsigned int mask = 1; mask < (1u << (sizeof(unsigned int)*8-1));mask <<= 1) { - - if (pFlags & mask) { - - bool have = false; - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - if (pimpl->mPostProcessingSteps[a]-> IsActive(mask) ) { - - have = true; - break; - } - } - if (!have) { - return false; - } - } - } - ASSIMP_END_EXCEPTION_REGION(bool); - return true; -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, - size_t pLength, - unsigned int pFlags, - const char* pHint /*= ""*/) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - if (!pHint) { - pHint = ""; - } - - if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) { - pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; - return NULL; - } - - // prevent deletion of the previous IOHandler - IOSystem* io = pimpl->mIOHandler; - pimpl->mIOHandler = NULL; - - SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io)); - - // read the file and recover the previous IOSystem - static const size_t BufSize(Importer::MaxLenHint + 28); - char fbuff[BufSize]; - ai_snprintf(fbuff, BufSize, "%s.%s",AI_MEMORYIO_MAGIC_FILENAME,pHint); - - ReadFile(fbuff,pFlags); - SetIOHandler(io); - - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return pimpl->mScene; -} - -// ------------------------------------------------------------------------------------------------ -void WriteLogOpening(const std::string& file) -{ - ASSIMP_LOG_INFO_F("Load ", file); - - // print a full version dump. This is nice because we don't - // need to ask the authors of incoming bug reports for - // the library version they're using - a log dump is - // sufficient. - const unsigned int flags( aiGetCompileFlags() ); - std::stringstream stream; - stream << "Assimp " << aiGetVersionMajor() << "." << aiGetVersionMinor() << "." << aiGetVersionRevision() << " " -#if defined(ASSIMP_BUILD_ARCHITECTURE) - << ASSIMP_BUILD_ARCHITECTURE -#elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__) - << "x86" -#elif defined(_M_X64) || defined(__x86_64__) - << "amd64" -#elif defined(_M_IA64) || defined(__ia64__) - << "itanium" -#elif defined(__ppc__) || defined(__powerpc__) - << "ppc32" -#elif defined(__powerpc64__) - << "ppc64" -#elif defined(__arm__) - << "arm" -#else - << "<unknown architecture>" -#endif - << " " -#if defined(ASSIMP_BUILD_COMPILER) - << ( ASSIMP_BUILD_COMPILER ) -#elif defined(_MSC_VER) - << "msvc" -#elif defined(__GNUC__) - << "gcc" -#else - << "<unknown compiler>" -#endif - -#ifdef ASSIMP_BUILD_DEBUG - << " debug" -#endif - - << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "") - << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "") - << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : ""); - - ASSIMP_LOG_DEBUG(stream.str()); -} - -// ------------------------------------------------------------------------------------------------ -// Reads the given file and returns its contents if successful. -const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - const std::string pFile(_pFile); - - // ---------------------------------------------------------------------- - // Put a large try block around everything to catch all std::exception's - // that might be thrown by STL containers or by new(). - // ImportErrorException's are throw by ourselves and caught elsewhere. - //----------------------------------------------------------------------- - - WriteLogOpening(pFile); - -#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS - try -#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS - { - // Check whether this Importer instance has already loaded - // a scene. In this case we need to delete the old one - if (pimpl->mScene) { - - ASSIMP_LOG_DEBUG("(Deleting previous scene)"); - FreeScene(); - } - - // First check if the file is accessible at all - if( !pimpl->mIOHandler->Exists( pFile)) { - - pimpl->mErrorString = "Unable to open file \"" + pFile + "\"."; - ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; - } - - std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); - if (profiler) { - profiler->BeginRegion("total"); - } - - // Find an worker class which can handle the file - BaseImporter* imp = NULL; - SetPropertyInteger("importerIndex", -1); - for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { - - if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) { - imp = pimpl->mImporter[a]; - SetPropertyInteger("importerIndex", a); - break; - } - } - - if (!imp) { - // not so bad yet ... try format auto detection. - const std::string::size_type s = pFile.find_last_of('.'); - if (s != std::string::npos) { - ASSIMP_LOG_INFO("File extension not known, trying signature-based detection"); - for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { - if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) { - imp = pimpl->mImporter[a]; - SetPropertyInteger("importerIndex", a); - break; - } - } - } - // Put a proper error message if no suitable importer was found - if( !imp) { - pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; - ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; - } - } - - // Get file size for progress handler - IOStream * fileIO = pimpl->mIOHandler->Open( pFile ); - uint32_t fileSize = 0; - if (fileIO) - { - fileSize = static_cast<uint32_t>(fileIO->FileSize()); - pimpl->mIOHandler->Close( fileIO ); - } - - // Dispatch the reading to the worker class for this format - const aiImporterDesc *desc( imp->GetInfo() ); - std::string ext( "unknown" ); - if ( NULL != desc ) { - ext = desc->mName; - } - ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." ); - pimpl->mProgressHandler->UpdateFileRead( 0, fileSize ); - - if (profiler) { - profiler->BeginRegion("import"); - } - - pimpl->mScene = imp->ReadFile( this, pFile, pimpl->mIOHandler); - pimpl->mProgressHandler->UpdateFileRead( fileSize, fileSize ); - - if (profiler) { - profiler->EndRegion("import"); - } - - SetPropertyString("sourceFilePath", pFile); - - // If successful, apply all active post processing steps to the imported data - if( pimpl->mScene) { - -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - // The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called. - if (pFlags & aiProcess_ValidateDataStructure) - { - ValidateDSProcess ds; - ds.ExecuteOnScene (this); - if (!pimpl->mScene) { - return NULL; - } - } -#endif // no validation - - // Preprocess the scene and prepare it for post-processing - if (profiler) { - profiler->BeginRegion("preprocess"); - } - - ScenePreprocessor pre(pimpl->mScene); - pre.ProcessScene(); - - if (profiler) { - profiler->EndRegion("preprocess"); - } - - // Ensure that the validation process won't be called twice - ApplyPostProcessing(pFlags & (~aiProcess_ValidateDataStructure)); - } - // if failed, extract the error string - else if( !pimpl->mScene) { - pimpl->mErrorString = imp->GetErrorText(); - } - - // clear any data allocated by post-process steps - pimpl->mPPShared->Clean(); - - if (profiler) { - profiler->EndRegion("total"); - } - } -#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS - catch (std::exception &e) - { -#if (defined _MSC_VER) && (defined _CPPRTTI) - // if we have RTTI get the full name of the exception that occurred - pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what(); -#else - pimpl->mErrorString = std::string("std::exception: ") + e.what(); -#endif - - ASSIMP_LOG_ERROR(pimpl->mErrorString); - delete pimpl->mScene; pimpl->mScene = NULL; - } -#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS - - // either successful or failure - the pointer expresses it anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return pimpl->mScene; -} - - -// ------------------------------------------------------------------------------------------------ -// Apply post-processing to the currently bound scene -const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - // Return immediately if no scene is active - if (!pimpl->mScene) { - return NULL; - } - - // If no flags are given, return the current scene with no further action - if (!pFlags) { - return pimpl->mScene; - } - - // In debug builds: run basic flag validation - ai_assert(_ValidateFlags(pFlags)); - ASSIMP_LOG_INFO("Entering post processing pipeline"); - -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - // The ValidateDS process plays an exceptional role. It isn't contained in the global - // list of post-processing steps, so we need to call it manually. - if (pFlags & aiProcess_ValidateDataStructure) - { - ValidateDSProcess ds; - ds.ExecuteOnScene (this); - if (!pimpl->mScene) { - return NULL; - } - } -#endif // no validation -#ifdef ASSIMP_BUILD_DEBUG - if (pimpl->bExtraVerbose) - { -#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings"); -#endif // no validation - pFlags |= aiProcess_ValidateDataStructure; - } -#else - if (pimpl->bExtraVerbose) { - ASSIMP_LOG_WARN("Not a debug build, ignoring extra verbose setting"); - } -#endif // ! DEBUG - - std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); - for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { - - BaseProcess* process = pimpl->mPostProcessingSteps[a]; - pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) ); - if( process->IsActive( pFlags)) { - - if (profiler) { - profiler->BeginRegion("postprocess"); - } - - process->ExecuteOnScene ( this ); - - if (profiler) { - profiler->EndRegion("postprocess"); - } - } - if( !pimpl->mScene) { - break; - } -#ifdef ASSIMP_BUILD_DEBUG - -#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - continue; -#endif // no validation - - // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step - if (pimpl->bExtraVerbose) { - ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures"); - - ValidateDSProcess ds; - ds.ExecuteOnScene (this); - if( !pimpl->mScene) { - ASSIMP_LOG_ERROR("Verbose Import: failed to re-validate data structures"); - break; - } - } -#endif // ! DEBUG - } - pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()), - static_cast<int>(pimpl->mPostProcessingSteps.size()) ); - - // update private scene flags - if( pimpl->mScene ) - ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags; - - // clear any data allocated by post-process steps - pimpl->mPPShared->Clean(); - ASSIMP_LOG_INFO("Leaving post processing pipeline"); - - ASSIMP_END_EXCEPTION_REGION(const aiScene*); - return pimpl->mScene; -} - -// ------------------------------------------------------------------------------------------------ -const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) { - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // Return immediately if no scene is active - if ( NULL == pimpl->mScene ) { - return NULL; - } - - // If no flags are given, return the current scene with no further action - if ( NULL == rootProcess ) { - return pimpl->mScene; - } - - // In debug builds: run basic flag validation - ASSIMP_LOG_INFO( "Entering customized post processing pipeline" ); - -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - // The ValidateDS process plays an exceptional role. It isn't contained in the global - // list of post-processing steps, so we need to call it manually. - if ( requestValidation ) - { - ValidateDSProcess ds; - ds.ExecuteOnScene( this ); - if ( !pimpl->mScene ) { - return NULL; - } - } -#endif // no validation -#ifdef ASSIMP_BUILD_DEBUG - if ( pimpl->bExtraVerbose ) - { -#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS - ASSIMP_LOG_ERROR( "Verbose Import is not available due to build settings" ); -#endif // no validation - } -#else - if ( pimpl->bExtraVerbose ) { - ASSIMP_LOG_WARN( "Not a debug build, ignoring extra verbose setting" ); - } -#endif // ! DEBUG - - std::unique_ptr<Profiler> profiler( GetPropertyInteger( AI_CONFIG_GLOB_MEASURE_TIME, 0 ) ? new Profiler() : NULL ); - - if ( profiler ) { - profiler->BeginRegion( "postprocess" ); - } - - rootProcess->ExecuteOnScene( this ); - - if ( profiler ) { - profiler->EndRegion( "postprocess" ); - } - - // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step - if ( pimpl->bExtraVerbose || requestValidation ) { - ASSIMP_LOG_DEBUG( "Verbose Import: revalidating data structures" ); - - ValidateDSProcess ds; - ds.ExecuteOnScene( this ); - if ( !pimpl->mScene ) { - ASSIMP_LOG_ERROR( "Verbose Import: failed to revalidate data structures" ); - } - } - - // clear any data allocated by post-process steps - pimpl->mPPShared->Clean(); - ASSIMP_LOG_INFO( "Leaving customized post processing pipeline" ); - - ASSIMP_END_EXCEPTION_REGION( const aiScene* ); - - return pimpl->mScene; -} - -// ------------------------------------------------------------------------------------------------ -// Helper function to check whether an extension is supported by ASSIMP -bool Importer::IsExtensionSupported(const char* szExtension) const -{ - return nullptr != GetImporter(szExtension); -} - -// ------------------------------------------------------------------------------------------------ -size_t Importer::GetImporterCount() const -{ - return pimpl->mImporter.size(); -} - -// ------------------------------------------------------------------------------------------------ -const aiImporterDesc* Importer::GetImporterInfo(size_t index) const -{ - if (index >= pimpl->mImporter.size()) { - return NULL; - } - return pimpl->mImporter[index]->GetInfo(); -} - - -// ------------------------------------------------------------------------------------------------ -BaseImporter* Importer::GetImporter (size_t index) const -{ - if (index >= pimpl->mImporter.size()) { - return NULL; - } - return pimpl->mImporter[index]; -} - -// ------------------------------------------------------------------------------------------------ -// Find a loader plugin for a given file extension -BaseImporter* Importer::GetImporter (const char* szExtension) const -{ - return GetImporter(GetImporterIndex(szExtension)); -} - -// ------------------------------------------------------------------------------------------------ -// Find a loader plugin for a given file extension -size_t Importer::GetImporterIndex (const char* szExtension) const { - ai_assert(nullptr != szExtension); - - ASSIMP_BEGIN_EXCEPTION_REGION(); - - // skip over wildcard and dot characters at string head -- - for ( ; *szExtension == '*' || *szExtension == '.'; ++szExtension ); - - std::string ext(szExtension); - if (ext.empty()) { - return static_cast<size_t>(-1); - } - std::transform( ext.begin(), ext.end(), ext.begin(), ToLower<char> ); - - std::set<std::string> str; - for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { - str.clear(); - - (*i)->GetExtensionList(str); - for (std::set<std::string>::const_iterator it = str.begin(); it != str.end(); ++it) { - if (ext == *it) { - return std::distance(static_cast< std::vector<BaseImporter*>::const_iterator >(pimpl->mImporter.begin()), i); - } - } - } - ASSIMP_END_EXCEPTION_REGION(size_t); - return static_cast<size_t>(-1); -} - -// ------------------------------------------------------------------------------------------------ -// Helper function to build a list of all file extensions supported by ASSIMP -void Importer::GetExtensionList(aiString& szOut) const -{ - ASSIMP_BEGIN_EXCEPTION_REGION(); - std::set<std::string> str; - for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { - (*i)->GetExtensionList(str); - } - - // List can be empty - if( !str.empty() ) { - for (std::set<std::string>::const_iterator it = str.begin();; ) { - szOut.Append("*."); - szOut.Append((*it).c_str()); - - if (++it == str.end()) { - break; - } - szOut.Append(";"); - } - } - ASSIMP_END_EXCEPTION_REGION(void); -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool Importer::SetPropertyInteger(const char* szName, int iValue) -{ - bool existing; - ASSIMP_BEGIN_EXCEPTION_REGION(); - existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue); - ASSIMP_END_EXCEPTION_REGION(bool); - return existing; -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) -{ - bool existing; - ASSIMP_BEGIN_EXCEPTION_REGION(); - existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue); - ASSIMP_END_EXCEPTION_REGION(bool); - return existing; -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool Importer::SetPropertyString(const char* szName, const std::string& value) -{ - bool existing; - ASSIMP_BEGIN_EXCEPTION_REGION(); - existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value); - ASSIMP_END_EXCEPTION_REGION(bool); - return existing; -} - -// ------------------------------------------------------------------------------------------------ -// Set a configuration property -bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) -{ - bool existing; - ASSIMP_BEGIN_EXCEPTION_REGION(); - existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value); - ASSIMP_END_EXCEPTION_REGION(bool); - return existing; -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -int Importer::GetPropertyInteger(const char* szName, - int iErrorReturn /*= 0xffffffff*/) const -{ - return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -ai_real Importer::GetPropertyFloat(const char* szName, - ai_real iErrorReturn /*= 10e10*/) const -{ - return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -const std::string Importer::GetPropertyString(const char* szName, - const std::string& iErrorReturn /*= ""*/) const -{ - return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get a configuration property -const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, - const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const -{ - return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn); -} - -// ------------------------------------------------------------------------------------------------ -// Get the memory requirements of a single node -inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) -{ - iScene += sizeof(aiNode); - iScene += sizeof(unsigned int) * pcNode->mNumMeshes; - iScene += sizeof(void*) * pcNode->mNumChildren; - - for (unsigned int i = 0; i < pcNode->mNumChildren;++i) { - AddNodeWeight(iScene,pcNode->mChildren[i]); - } -} - -// ------------------------------------------------------------------------------------------------ -// Get the memory requirements of the scene -void Importer::GetMemoryRequirements(aiMemoryInfo& in) const -{ - in = aiMemoryInfo(); - aiScene* mScene = pimpl->mScene; - - // return if we have no scene loaded - if (!pimpl->mScene) - return; - - - in.total = sizeof(aiScene); - - // add all meshes - for (unsigned int i = 0; i < mScene->mNumMeshes;++i) - { - in.meshes += sizeof(aiMesh); - if (mScene->mMeshes[i]->HasPositions()) { - in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; - } - - if (mScene->mMeshes[i]->HasNormals()) { - in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; - } - - if (mScene->mMeshes[i]->HasTangentsAndBitangents()) { - in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices * 2; - } - - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) { - if (mScene->mMeshes[i]->HasVertexColors(a)) { - in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices; - } - else break; - } - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { - if (mScene->mMeshes[i]->HasTextureCoords(a)) { - in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices; - } - else break; - } - if (mScene->mMeshes[i]->HasBones()) { - in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones; - for (unsigned int p = 0; p < mScene->mMeshes[i]->mNumBones;++p) { - in.meshes += sizeof(aiBone); - in.meshes += mScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight); - } - } - in.meshes += (sizeof(aiFace) + 3 * sizeof(unsigned int))*mScene->mMeshes[i]->mNumFaces; - } - in.total += in.meshes; - - // add all embedded textures - for (unsigned int i = 0; i < mScene->mNumTextures;++i) { - const aiTexture* pc = mScene->mTextures[i]; - in.textures += sizeof(aiTexture); - if (pc->mHeight) { - in.textures += 4 * pc->mHeight * pc->mWidth; - } - else in.textures += pc->mWidth; - } - in.total += in.textures; - - // add all animations - for (unsigned int i = 0; i < mScene->mNumAnimations;++i) { - const aiAnimation* pc = mScene->mAnimations[i]; - in.animations += sizeof(aiAnimation); - - // add all bone anims - for (unsigned int a = 0; a < pc->mNumChannels; ++a) { - const aiNodeAnim* pc2 = pc->mChannels[i]; - in.animations += sizeof(aiNodeAnim); - in.animations += pc2->mNumPositionKeys * sizeof(aiVectorKey); - in.animations += pc2->mNumScalingKeys * sizeof(aiVectorKey); - in.animations += pc2->mNumRotationKeys * sizeof(aiQuatKey); - } - } - in.total += in.animations; - - // add all cameras and all lights - in.total += in.cameras = sizeof(aiCamera) * mScene->mNumCameras; - in.total += in.lights = sizeof(aiLight) * mScene->mNumLights; - - // add all nodes - AddNodeWeight(in.nodes,mScene->mRootNode); - in.total += in.nodes; - - // add all materials - for (unsigned int i = 0; i < mScene->mNumMaterials;++i) { - const aiMaterial* pc = mScene->mMaterials[i]; - in.materials += sizeof(aiMaterial); - in.materials += pc->mNumAllocated * sizeof(void*); - - for (unsigned int a = 0; a < pc->mNumProperties;++a) { - in.materials += pc->mProperties[a]->mDataLength; - } - } - in.total += in.materials; -} diff --git a/thirdparty/assimp/code/Common/Importer.h b/thirdparty/assimp/code/Common/Importer.h deleted file mode 100644 index a439d99c2f..0000000000 --- a/thirdparty/assimp/code/Common/Importer.h +++ /dev/null @@ -1,247 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Importer.h mostly internal stuff for use by #Assimp::Importer */ -#pragma once -#ifndef INCLUDED_AI_IMPORTER_H -#define INCLUDED_AI_IMPORTER_H - -#include <map> -#include <vector> -#include <string> -#include <assimp/matrix4x4.h> - -struct aiScene; - -namespace Assimp { - class ProgressHandler; - class IOSystem; - class BaseImporter; - class BaseProcess; - class SharedPostProcessInfo; - - -//! @cond never -// --------------------------------------------------------------------------- -/** @brief Internal PIMPL implementation for Assimp::Importer - * - * Using this idiom here allows us to drop the dependency from - * std::vector and std::map in the public headers. Furthermore we are dropping - * any STL interface problems caused by mismatching STL settings. All - * size calculation are now done by us, not the app heap. */ -class ImporterPimpl { -public: - // Data type to store the key hash - typedef unsigned int KeyType; - - // typedefs for our four configuration maps. - // We don't need more, so there is no need for a generic solution - typedef std::map<KeyType, int> IntPropertyMap; - typedef std::map<KeyType, ai_real> FloatPropertyMap; - typedef std::map<KeyType, std::string> StringPropertyMap; - typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap; - - /** IO handler to use for all file accesses. */ - IOSystem* mIOHandler; - bool mIsDefaultHandler; - - /** Progress handler for feedback. */ - ProgressHandler* mProgressHandler; - bool mIsDefaultProgressHandler; - - /** Format-specific importer worker objects - one for each format we can read.*/ - std::vector< BaseImporter* > mImporter; - - /** Post processing steps we can apply at the imported data. */ - std::vector< BaseProcess* > mPostProcessingSteps; - - /** The imported data, if ReadFile() was successful, NULL otherwise. */ - aiScene* mScene; - - /** The error description, if there was one. */ - std::string mErrorString; - - /** List of integer properties */ - IntPropertyMap mIntProperties; - - /** List of floating-point properties */ - FloatPropertyMap mFloatProperties; - - /** List of string properties */ - StringPropertyMap mStringProperties; - - /** List of Matrix properties */ - MatrixPropertyMap mMatrixProperties; - - /** Used for testing - extra verbose mode causes the ValidateDataStructure-Step - * to be executed before and after every single post-process step */ - bool bExtraVerbose; - - /** Used by post-process steps to share data */ - SharedPostProcessInfo* mPPShared; - - /// The default class constructor. - ImporterPimpl() AI_NO_EXCEPT; -}; - -inline -ImporterPimpl::ImporterPimpl() AI_NO_EXCEPT -: mIOHandler( nullptr ) -, mIsDefaultHandler( false ) -, mProgressHandler( nullptr ) -, mIsDefaultProgressHandler( false ) -, mImporter() -, mPostProcessingSteps() -, mScene( nullptr ) -, mErrorString() -, mIntProperties() -, mFloatProperties() -, mStringProperties() -, mMatrixProperties() -, bExtraVerbose( false ) -, mPPShared( nullptr ) { - // empty -} -//! @endcond - - -struct BatchData; - -// --------------------------------------------------------------------------- -/** FOR IMPORTER PLUGINS ONLY: A helper class to the pleasure of importers - * that need to load many external meshes recursively. - * - * The class uses several threads to load these meshes (or at least it - * could, this has not yet been implemented at the moment). - * - * @note The class may not be used by more than one thread*/ -class ASSIMP_API BatchLoader -{ - // friend of Importer - -public: - //! @cond never - // ------------------------------------------------------------------- - /** Wraps a full list of configuration properties for an importer. - * Properties can be set using SetGenericProperty */ - struct PropertyMap - { - ImporterPimpl::IntPropertyMap ints; - ImporterPimpl::FloatPropertyMap floats; - ImporterPimpl::StringPropertyMap strings; - ImporterPimpl::MatrixPropertyMap matrices; - - bool operator == (const PropertyMap& prop) const { - // fixme: really isocpp? gcc complains - return ints == prop.ints && floats == prop.floats && strings == prop.strings && matrices == prop.matrices; - } - - bool empty () const { - return ints.empty() && floats.empty() && strings.empty() && matrices.empty(); - } - }; - //! @endcond - -public: - // ------------------------------------------------------------------- - /** Construct a batch loader from a given IO system to be used - * to access external files - */ - explicit BatchLoader(IOSystem* pIO, bool validate = false ); - - // ------------------------------------------------------------------- - /** The class destructor. - */ - ~BatchLoader(); - - // ------------------------------------------------------------------- - /** Sets the validation step. True for enable validation during postprocess. - * @param enable True for validation. - */ - void setValidation( bool enabled ); - - // ------------------------------------------------------------------- - /** Returns the current validation step. - * @return The current validation step. - */ - bool getValidation() const; - - // ------------------------------------------------------------------- - /** Add a new file to the list of files to be loaded. - * @param file File to be loaded - * @param steps Post-processing steps to be executed on the file - * @param map Optional configuration properties - * @return 'Load request channel' - an unique ID that can later - * be used to access the imported file data. - * @see GetImport */ - unsigned int AddLoadRequest ( - const std::string& file, - unsigned int steps = 0, - const PropertyMap* map = NULL - ); - - // ------------------------------------------------------------------- - /** Get an imported scene. - * This polls the import from the internal request list. - * If an import is requested several times, this function - * can be called several times, too. - * - * @param which LRWC returned by AddLoadRequest(). - * @return NULL if there is no scene with this file name - * in the queue of the scene hasn't been loaded yet. */ - aiScene* GetImport( - unsigned int which - ); - - // ------------------------------------------------------------------- - /** Waits until all scenes have been loaded. This returns - * immediately if no scenes are queued.*/ - void LoadAll(); - -private: - // No need to have that in the public API ... - BatchData *m_data; -}; - -} // Namespace Assimp - -#endif // INCLUDED_AI_IMPORTER_H diff --git a/thirdparty/assimp/code/Common/ImporterRegistry.cpp b/thirdparty/assimp/code/Common/ImporterRegistry.cpp deleted file mode 100644 index b9f28f0356..0000000000 --- a/thirdparty/assimp/code/Common/ImporterRegistry.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file ImporterRegistry.cpp - -Central registry for all importers available. Do not edit this file -directly (unless you are adding new loaders), instead use the -corresponding preprocessor flag to selectively disable formats. -*/ - -#include <vector> -#include <assimp/BaseImporter.h> - -// ------------------------------------------------------------------------------------------------ -// Importers -// (include_new_importers_here) -// ------------------------------------------------------------------------------------------------ -#ifndef ASSIMP_BUILD_NO_X_IMPORTER -# include "X/XFileImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER -# include "AMF/AMFImporter.hpp" -#endif -#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER -# include "3DS/3DSLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MD3_IMPORTER -# include "MD3/MD3Loader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MDL_IMPORTER -# include "MDL/MDLLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MD2_IMPORTER -# include "MD2/MD2Loader.h" -#endif -#ifndef ASSIMP_BUILD_NO_PLY_IMPORTER -# include "Ply/PlyLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_ASE_IMPORTER -# include "ASE/ASELoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER -# include "Obj/ObjFileImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_HMP_IMPORTER -# include "HMP/HMPLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_SMD_IMPORTER -# include "SMD/SMDLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MDC_IMPORTER -# include "MDC/MDCLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_MD5_IMPORTER -# include "MD5/MD5Loader.h" -#endif -#ifndef ASSIMP_BUILD_NO_STL_IMPORTER -# include "STL/STLLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_LWO_IMPORTER -# include "LWO/LWOLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_DXF_IMPORTER -# include "DXF/DXFLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_NFF_IMPORTER -# include "NFF/NFFLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_RAW_IMPORTER -# include "Raw/RawLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_SIB_IMPORTER -# include "SIB/SIBImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_OFF_IMPORTER -# include "OFF/OFFLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_AC_IMPORTER -# include "AC/ACLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_BVH_IMPORTER -# include "BVH/BVHLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER -# include "Irr/IRRMeshLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_IRR_IMPORTER -# include "Irr/IRRLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_Q3D_IMPORTER -# include "Q3D/Q3DLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_B3D_IMPORTER -# include "B3D/B3DImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER -# include "Collada/ColladaLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_TERRAGEN_IMPORTER -# include "Terragen/TerragenLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_CSM_IMPORTER -# include "CSM/CSMLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_3D_IMPORTER -# include "Unreal/UnrealLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_LWS_IMPORTER -# include "LWS/LWSLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER -# include "Ogre/OgreImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER -# include "OpenGEX/OpenGEXImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER -# include "MS3D/MS3DLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_COB_IMPORTER -# include "COB/COBLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER -# include "Blender/BlenderLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER -# include "Q3BSP/Q3BSPFileImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_NDO_IMPORTER -# include "NDO/NDOLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_IFC_IMPORTER -# include "Importer/IFC/IFCLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_XGL_IMPORTER -# include "XGL/XGLLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER -# include "FBX/FBXImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER -# include "Assbin/AssbinLoader.h" -#endif -#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER -# include "glTF/glTFImporter.h" -# include "glTF2/glTF2Importer.h" -#endif -#ifndef ASSIMP_BUILD_NO_C4D_IMPORTER -# include "C4D/C4DImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER -# include "3MF/D3MFImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER -# include "X3D/X3DImporter.hpp" -#endif -#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER -# include "MMD/MMDImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER -# include "M3D/M3DImporter.h" -#endif -#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER -# include "Importer/StepFile/StepFileImporter.h" -#endif - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -void GetImporterInstanceList(std::vector< BaseImporter* >& out) -{ - // ---------------------------------------------------------------------------- - // Add an instance of each worker class here - // (register_new_importers_here) - // ---------------------------------------------------------------------------- - out.reserve(64); -#if (!defined ASSIMP_BUILD_NO_X_IMPORTER) - out.push_back( new XFileImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_OBJ_IMPORTER) - out.push_back( new ObjFileImporter()); -#endif -#ifndef ASSIMP_BUILD_NO_AMF_IMPORTER - out.push_back( new AMFImporter() ); -#endif -#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER) - out.push_back( new Discreet3DSImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_M3D_IMPORTER) - out.push_back( new M3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER) - out.push_back( new MD3Importer()); -#endif -#if (!defined ASSIMP_BUILD_NO_MD2_IMPORTER) - out.push_back( new MD2Importer()); -#endif -#if (!defined ASSIMP_BUILD_NO_PLY_IMPORTER) - out.push_back( new PLYImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_MDL_IMPORTER) - out.push_back( new MDLImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_ASE_IMPORTER) - #if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER) - out.push_back( new ASEImporter()); -# endif -#endif -#if (!defined ASSIMP_BUILD_NO_HMP_IMPORTER) - out.push_back( new HMPImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_SMD_IMPORTER) - out.push_back( new SMDImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_MDC_IMPORTER) - out.push_back( new MDCImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_MD5_IMPORTER) - out.push_back( new MD5Importer()); -#endif -#if (!defined ASSIMP_BUILD_NO_STL_IMPORTER) - out.push_back( new STLImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_LWO_IMPORTER) - out.push_back( new LWOImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_DXF_IMPORTER) - out.push_back( new DXFImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_NFF_IMPORTER) - out.push_back( new NFFImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_RAW_IMPORTER) - out.push_back( new RAWImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_SIB_IMPORTER) - out.push_back( new SIBImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_OFF_IMPORTER) - out.push_back( new OFFImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_AC_IMPORTER) - out.push_back( new AC3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_BVH_IMPORTER) - out.push_back( new BVHLoader()); -#endif -#if (!defined ASSIMP_BUILD_NO_IRRMESH_IMPORTER) - out.push_back( new IRRMeshImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_IRR_IMPORTER) - out.push_back( new IRRImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_Q3D_IMPORTER) - out.push_back( new Q3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_B3D_IMPORTER) - out.push_back( new B3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_COLLADA_IMPORTER) - out.push_back( new ColladaLoader()); -#endif -#if (!defined ASSIMP_BUILD_NO_TERRAGEN_IMPORTER) - out.push_back( new TerragenImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_CSM_IMPORTER) - out.push_back( new CSMImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_3D_IMPORTER) - out.push_back( new UnrealImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_LWS_IMPORTER) - out.push_back( new LWSImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_OGRE_IMPORTER) - out.push_back( new Ogre::OgreImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_OPENGEX_IMPORTER ) - out.push_back( new OpenGEX::OpenGEXImporter() ); -#endif -#if (!defined ASSIMP_BUILD_NO_MS3D_IMPORTER) - out.push_back( new MS3DImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_COB_IMPORTER) - out.push_back( new COBImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_BLEND_IMPORTER) - out.push_back( new BlenderImporter()); -#endif -#if (!defined ASSIMP_BUILD_NO_Q3BSP_IMPORTER) - out.push_back( new Q3BSPFileImporter() ); -#endif -#if (!defined ASSIMP_BUILD_NO_NDO_IMPORTER) - out.push_back( new NDOImporter() ); -#endif -#if (!defined ASSIMP_BUILD_NO_IFC_IMPORTER) - out.push_back( new IFCImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_XGL_IMPORTER ) - out.push_back( new XGLImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_FBX_IMPORTER ) - out.push_back( new FBXImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_ASSBIN_IMPORTER ) - out.push_back( new AssbinImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_GLTF_IMPORTER ) - out.push_back( new glTFImporter() ); - out.push_back( new glTF2Importer() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_C4D_IMPORTER ) - out.push_back( new C4DImporter() ); -#endif -#if ( !defined ASSIMP_BUILD_NO_3MF_IMPORTER ) - out.push_back( new D3MFImporter() ); -#endif -#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER - out.push_back( new X3DImporter() ); -#endif -#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER - out.push_back( new MMDImporter() ); -#endif -#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER - out.push_back(new StepFile::StepFileImporter()); -#endif -} - -/** will delete all registered importers. */ -void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){ - for(size_t i= 0; i<deleteList.size();++i){ - delete deleteList[i]; - deleteList[i]=nullptr; - }//for -} - -} // namespace Assimp diff --git a/thirdparty/assimp/code/Common/PolyTools.h b/thirdparty/assimp/code/Common/PolyTools.h deleted file mode 100644 index fbbda0e7d1..0000000000 --- a/thirdparty/assimp/code/Common/PolyTools.h +++ /dev/null @@ -1,229 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file PolyTools.h, various utilities for our dealings with arbitrary polygons */ - -#ifndef AI_POLYTOOLS_H_INCLUDED -#define AI_POLYTOOLS_H_INCLUDED - -#include <assimp/material.h> -#include <assimp/ai_assert.h> - -namespace Assimp { - -// ------------------------------------------------------------------------------- -/** Compute the signed area of a triangle. - * The function accepts an unconstrained template parameter for use with - * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ -template <typename T> -inline double GetArea2D(const T& v1, const T& v2, const T& v3) -{ - return 0.5 * (v1.x * ((double)v3.y - v2.y) + v2.x * ((double)v1.y - v3.y) + v3.x * ((double)v2.y - v1.y)); -} - -// ------------------------------------------------------------------------------- -/** Test if a given point p2 is on the left side of the line formed by p0-p1. - * The function accepts an unconstrained template parameter for use with - * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ -template <typename T> -inline bool OnLeftSideOfLine2D(const T& p0, const T& p1,const T& p2) -{ - return GetArea2D(p0,p2,p1) > 0; -} - -// ------------------------------------------------------------------------------- -/** Test if a given point is inside a given triangle in R2. - * The function accepts an unconstrained template parameter for use with - * both aiVector3D and aiVector2D, but generally ignores the third coordinate.*/ -template <typename T> -inline bool PointInTriangle2D(const T& p0, const T& p1,const T& p2, const T& pp) -{ - // Point in triangle test using baryzentric coordinates - const aiVector2D v0 = p1 - p0; - const aiVector2D v1 = p2 - p0; - const aiVector2D v2 = pp - p0; - - double dot00 = v0 * v0; - double dot01 = v0 * v1; - double dot02 = v0 * v2; - double dot11 = v1 * v1; - double dot12 = v1 * v2; - - const double invDenom = 1 / (dot00 * dot11 - dot01 * dot01); - dot11 = (dot11 * dot02 - dot01 * dot12) * invDenom; - dot00 = (dot00 * dot12 - dot01 * dot02) * invDenom; - - return (dot11 > 0) && (dot00 > 0) && (dot11 + dot00 < 1); -} - - -// ------------------------------------------------------------------------------- -/** Check whether the winding order of a given polygon is counter-clockwise. - * The function accepts an unconstrained template parameter, but is intended - * to be used only with aiVector2D and aiVector3D (z axis is ignored, only - * x and y are taken into account). - * @note Code taken from http://cgm.cs.mcgill.ca/~godfried/teaching/cg-projects/97/Ian/applet1.html and translated to C++ - */ -template <typename T> -inline bool IsCCW(T* in, size_t npoints) { - double aa, bb, cc, b, c, theta; - double convex_turn; - double convex_sum = 0; - - ai_assert(npoints >= 3); - - for (size_t i = 0; i < npoints - 2; i++) { - aa = ((in[i+2].x - in[i].x) * (in[i+2].x - in[i].x)) + - ((-in[i+2].y + in[i].y) * (-in[i+2].y + in[i].y)); - - bb = ((in[i+1].x - in[i].x) * (in[i+1].x - in[i].x)) + - ((-in[i+1].y + in[i].y) * (-in[i+1].y + in[i].y)); - - cc = ((in[i+2].x - in[i+1].x) * - (in[i+2].x - in[i+1].x)) + - ((-in[i+2].y + in[i+1].y) * - (-in[i+2].y + in[i+1].y)); - - b = std::sqrt(bb); - c = std::sqrt(cc); - theta = std::acos((bb + cc - aa) / (2 * b * c)); - - if (OnLeftSideOfLine2D(in[i],in[i+2],in[i+1])) { - // if (convex(in[i].x, in[i].y, - // in[i+1].x, in[i+1].y, - // in[i+2].x, in[i+2].y)) { - convex_turn = AI_MATH_PI_F - theta; - convex_sum += convex_turn; - } - else { - convex_sum -= AI_MATH_PI_F - theta; - } - } - aa = ((in[1].x - in[npoints-2].x) * - (in[1].x - in[npoints-2].x)) + - ((-in[1].y + in[npoints-2].y) * - (-in[1].y + in[npoints-2].y)); - - bb = ((in[0].x - in[npoints-2].x) * - (in[0].x - in[npoints-2].x)) + - ((-in[0].y + in[npoints-2].y) * - (-in[0].y + in[npoints-2].y)); - - cc = ((in[1].x - in[0].x) * (in[1].x - in[0].x)) + - ((-in[1].y + in[0].y) * (-in[1].y + in[0].y)); - - b = std::sqrt(bb); - c = std::sqrt(cc); - theta = std::acos((bb + cc - aa) / (2 * b * c)); - - //if (convex(in[npoints-2].x, in[npoints-2].y, - // in[0].x, in[0].y, - // in[1].x, in[1].y)) { - if (OnLeftSideOfLine2D(in[npoints-2],in[1],in[0])) { - convex_turn = AI_MATH_PI_F - theta; - convex_sum += convex_turn; - } - else { - convex_sum -= AI_MATH_PI_F - theta; - } - - return convex_sum >= (2 * AI_MATH_PI_F); -} - - -// ------------------------------------------------------------------------------- -/** Compute the normal of an arbitrary polygon in R3. - * - * The code is based on Newell's formula, that is a polygons normal is the ratio - * of its area when projected onto the three coordinate axes. - * - * @param out Receives the output normal - * @param num Number of input vertices - * @param x X data source. x[ofs_x*n] is the n'th element. - * @param y Y data source. y[ofs_y*n] is the y'th element - * @param z Z data source. z[ofs_z*n] is the z'th element - * - * @note The data arrays must have storage for at least num+2 elements. Using - * this method is much faster than the 'other' NewellNormal() - */ -template <int ofs_x, int ofs_y, int ofs_z, typename TReal> -inline void NewellNormal (aiVector3t<TReal>& out, int num, TReal* x, TReal* y, TReal* z) -{ - // Duplicate the first two vertices at the end - x[(num+0)*ofs_x] = x[0]; - x[(num+1)*ofs_x] = x[ofs_x]; - - y[(num+0)*ofs_y] = y[0]; - y[(num+1)*ofs_y] = y[ofs_y]; - - z[(num+0)*ofs_z] = z[0]; - z[(num+1)*ofs_z] = z[ofs_z]; - - TReal sum_xy = 0.0, sum_yz = 0.0, sum_zx = 0.0; - - TReal *xptr = x +ofs_x, *xlow = x, *xhigh = x + ofs_x*2; - TReal *yptr = y +ofs_y, *ylow = y, *yhigh = y + ofs_y*2; - TReal *zptr = z +ofs_z, *zlow = z, *zhigh = z + ofs_z*2; - - for (int tmp=0; tmp < num; tmp++) { - sum_xy += (*xptr) * ( (*yhigh) - (*ylow) ); - sum_yz += (*yptr) * ( (*zhigh) - (*zlow) ); - sum_zx += (*zptr) * ( (*xhigh) - (*xlow) ); - - xptr += ofs_x; - xlow += ofs_x; - xhigh += ofs_x; - - yptr += ofs_y; - ylow += ofs_y; - yhigh += ofs_y; - - zptr += ofs_z; - zlow += ofs_z; - zhigh += ofs_z; - } - out = aiVector3t<TReal>(sum_yz,sum_zx,sum_xy); -} - -} // ! Assimp - -#endif diff --git a/thirdparty/assimp/code/Common/PostStepRegistry.cpp b/thirdparty/assimp/code/Common/PostStepRegistry.cpp deleted file mode 100644 index 8ff4af0400..0000000000 --- a/thirdparty/assimp/code/Common/PostStepRegistry.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file ImporterRegistry.cpp - -Central registry for all postprocessing steps available. Do not edit this file -directly (unless you are adding new steps), instead use the -corresponding preprocessor flag to selectively disable steps. -*/ - -#include "PostProcessing/ProcessHelper.h" - -#ifndef ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS -# include "PostProcessing/CalcTangentsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS -# include "PostProcessing/JoinVerticesProcess.h" -#endif -#if !(defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS && defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS && defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS) -# include "PostProcessing/ConvertToLHProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS -# include "PostProcessing/TriangulateProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_DROPFACENORMALS_PROCESS -# include "PostProcessing/DropFaceNormalsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS -# include "PostProcessing/GenFaceNormalsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS -# include "PostProcessing/GenVertexNormalsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_REMOVEVC_PROCESS -# include "PostProcessing/RemoveVCProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS -# include "PostProcessing/SplitLargeMeshes.h" -#endif -#ifndef ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS -# include "PostProcessing/PretransformVertices.h" -#endif -#ifndef ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS -# include "PostProcessing/LimitBoneWeightsProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS -# include "PostProcessing/ValidateDataStructure.h" -#endif -#ifndef ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS -# include "PostProcessing/ImproveCacheLocality.h" -#endif -#ifndef ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS -# include "PostProcessing/FixNormalsStep.h" -#endif -#ifndef ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS -# include "PostProcessing/RemoveRedundantMaterials.h" -#endif -#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS) -# include "PostProcessing/EmbedTexturesProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS -# include "PostProcessing/FindInvalidDataProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS -# include "PostProcessing/FindDegenerates.h" -#endif -#ifndef ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS -# include "PostProcessing/SortByPTypeProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS -# include "PostProcessing/ComputeUVMappingProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS -# include "PostProcessing/TextureTransform.h" -#endif -#ifndef ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS -# include "PostProcessing/FindInstancesProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS -# include "PostProcessing/OptimizeMeshes.h" -#endif -#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS -# include "PostProcessing/OptimizeGraph.h" -#endif -#ifndef ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS -# include "Common/SplitByBoneCountProcess.h" -#endif -#ifndef ASSIMP_BUILD_NO_DEBONE_PROCESS -# include "PostProcessing/DeboneProcess.h" -#endif -#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS) -# include "PostProcessing/ScaleProcess.h" -#endif -#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS) -# include "PostProcessing/ArmaturePopulate.h" -#endif -#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS) -# include "PostProcessing/GenBoundingBoxesProcess.h" -#endif - - - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out) -{ - // ---------------------------------------------------------------------------- - // Add an instance of each post processing step here in the order - // of sequence it is executed. Steps that are added here are not - // validated - as RegisterPPStep() does - all dependencies must be given. - // ---------------------------------------------------------------------------- - out.reserve(31); -#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS) - out.push_back( new MakeLeftHandedProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS) - out.push_back( new FlipUVsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS) - out.push_back( new FlipWindingOrderProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS) - out.push_back( new RemoveVCProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_REMOVE_REDUNDANTMATERIALS_PROCESS) - out.push_back( new RemoveRedundantMatsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_EMBEDTEXTURES_PROCESS) - out.push_back( new EmbedTexturesProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FINDINSTANCES_PROCESS) - out.push_back( new FindInstancesProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS) - out.push_back( new OptimizeGraphProcess()); -#endif -#ifndef ASSIMP_BUILD_NO_GENUVCOORDS_PROCESS - out.push_back( new ComputeUVMappingProcess()); -#endif -#ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS - out.push_back( new TextureTransformStep()); -#endif -#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS) - out.push_back( new ScaleProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS) - out.push_back( new ArmaturePopulate()); -#endif -#if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS) - out.push_back( new PretransformVertices()); -#endif -#if (!defined ASSIMP_BUILD_NO_TRIANGULATE_PROCESS) - out.push_back( new TriangulateProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS) - //find degenerates should run after triangulation (to sort out small - //generated triangles) but before sort by p types (in case there are lines - //and points generated and inserted into a mesh) - out.push_back( new FindDegeneratesProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_SORTBYPTYPE_PROCESS) - out.push_back( new SortByPTypeProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS) - out.push_back( new FindInvalidDataProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS) - out.push_back( new OptimizeMeshesProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS) - out.push_back( new FixInfacingNormalsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_SPLITBYBONECOUNT_PROCESS) - out.push_back( new SplitByBoneCountProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS) - out.push_back( new SplitLargeMeshesProcess_Triangle()); -#endif -#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS) - out.push_back( new DropFaceNormalsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS) - out.push_back( new GenFaceNormalsProcess()); -#endif - // ......................................................................... - // DON'T change the order of these five .. - // XXX this is actually a design weakness that dates back to the time - // when Importer would maintain the postprocessing step list exclusively. - // Now that others access it too, we need a better solution. - out.push_back( new ComputeSpatialSortProcess()); - // ......................................................................... - -#if (!defined ASSIMP_BUILD_NO_GENVERTEXNORMALS_PROCESS) - out.push_back( new GenVertexNormalsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_CALCTANGENTS_PROCESS) - out.push_back( new CalcTangentsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_JOINVERTICES_PROCESS) - out.push_back( new JoinVerticesProcess()); -#endif - - // ......................................................................... - out.push_back( new DestroySpatialSortProcess()); - // ......................................................................... - -#if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS) - out.push_back( new SplitLargeMeshesProcess_Vertex()); -#endif -#if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS) - out.push_back( new DeboneProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_LIMITBONEWEIGHTS_PROCESS) - out.push_back( new LimitBoneWeightsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS) - out.push_back( new ImproveCacheLocalityProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS) - out.push_back(new GenBoundingBoxesProcess); -#endif -} - -} diff --git a/thirdparty/assimp/code/Common/RemoveComments.cpp b/thirdparty/assimp/code/Common/RemoveComments.cpp deleted file mode 100644 index 91700a7699..0000000000 --- a/thirdparty/assimp/code/Common/RemoveComments.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file RemoveComments.cpp - * @brief Defines the CommentRemover utility class - */ - -#include <assimp/RemoveComments.h> -#include <assimp/ParsingUtils.h> - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -// Remove line comments from a file -void CommentRemover::RemoveLineComments(const char* szComment, - char* szBuffer, char chReplacement /* = ' ' */) -{ - // validate parameters - ai_assert(NULL != szComment && NULL != szBuffer && *szComment); - - const size_t len = strlen(szComment); - while (*szBuffer) { - - // skip over quotes - if (*szBuffer == '\"' || *szBuffer == '\'') - while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\''); - - if (!strncmp(szBuffer,szComment,len)) { - while (!IsLineEnd(*szBuffer)) - *szBuffer++ = chReplacement; - - if (!*szBuffer) { - break; - } - } - ++szBuffer; - } -} - -// ------------------------------------------------------------------------------------------------ -// Remove multi-line comments from a file -void CommentRemover::RemoveMultiLineComments(const char* szCommentStart, - const char* szCommentEnd,char* szBuffer, - char chReplacement) -{ - // validate parameters - ai_assert(NULL != szCommentStart && NULL != szCommentEnd && - NULL != szBuffer && *szCommentStart && *szCommentEnd); - - const size_t len = strlen(szCommentEnd); - const size_t len2 = strlen(szCommentStart); - - while (*szBuffer) { - // skip over quotes - if (*szBuffer == '\"' || *szBuffer == '\'') - while (*szBuffer++ && *szBuffer != '\"' && *szBuffer != '\''); - - if (!strncmp(szBuffer,szCommentStart,len2)) { - while (*szBuffer) { - if (!::strncmp(szBuffer,szCommentEnd,len)) { - for (unsigned int i = 0; i < len;++i) - *szBuffer++ = chReplacement; - - break; - } - *szBuffer++ = chReplacement; - } - continue; - } - ++szBuffer; - } -} - -} // !! Assimp diff --git a/thirdparty/assimp/code/Common/SGSpatialSort.cpp b/thirdparty/assimp/code/Common/SGSpatialSort.cpp deleted file mode 100644 index 120070b0aa..0000000000 --- a/thirdparty/assimp/code/Common/SGSpatialSort.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the helper class to quickly find -vertices close to a given position. Special implementation for -the 3ds loader handling smooth groups correctly */ - -#include <assimp/SGSpatialSort.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -SGSpatialSort::SGSpatialSort() -{ - // define the reference plane. We choose some arbitrary vector away from all basic axises - // in the hope that no model spreads all its vertices along this plane. - mPlaneNormal.Set( 0.8523f, 0.34321f, 0.5736f); - mPlaneNormal.Normalize(); -} -// ------------------------------------------------------------------------------------------------ -// Destructor -SGSpatialSort::~SGSpatialSort() -{ - // nothing to do here, everything destructs automatically -} -// ------------------------------------------------------------------------------------------------ -void SGSpatialSort::Add(const aiVector3D& vPosition, unsigned int index, - unsigned int smoothingGroup) -{ - // store position by index and distance - float distance = vPosition * mPlaneNormal; - mPositions.push_back( Entry( index, vPosition, - distance, smoothingGroup)); -} -// ------------------------------------------------------------------------------------------------ -void SGSpatialSort::Prepare() -{ - // now sort the array ascending by distance. - std::sort( this->mPositions.begin(), this->mPositions.end()); -} -// ------------------------------------------------------------------------------------------------ -// Returns an iterator for all positions close to the given position. -void SGSpatialSort::FindPositions( const aiVector3D& pPosition, - uint32_t pSG, - float pRadius, - std::vector<unsigned int>& poResults, - bool exactMatch /*= false*/) const -{ - float dist = pPosition * mPlaneNormal; - float minDist = dist - pRadius, maxDist = dist + pRadius; - - // clear the array - poResults.clear(); - - // quick check for positions outside the range - if( mPositions.empty() ) - return; - if( maxDist < mPositions.front().mDistance) - return; - if( minDist > mPositions.back().mDistance) - return; - - // do a binary search for the minimal distance to start the iteration there - unsigned int index = (unsigned int)mPositions.size() / 2; - unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4; - while( binaryStepSize > 1) - { - if( mPositions[index].mDistance < minDist) - index += binaryStepSize; - else - index -= binaryStepSize; - - binaryStepSize /= 2; - } - - // depending on the direction of the last step we need to single step a bit back or forth - // to find the actual beginning element of the range - while( index > 0 && mPositions[index].mDistance > minDist) - index--; - while( index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist) - index++; - - // Mow start iterating from there until the first position lays outside of the distance range. - // Add all positions inside the distance range within the given radius to the result aray - - float squareEpsilon = pRadius * pRadius; - std::vector<Entry>::const_iterator it = mPositions.begin() + index; - std::vector<Entry>::const_iterator end = mPositions.end(); - - if (exactMatch) - { - while( it->mDistance < maxDist) - { - if((it->mPosition - pPosition).SquareLength() < squareEpsilon && it->mSmoothGroups == pSG) - { - poResults.push_back( it->mIndex); - } - ++it; - if( end == it )break; - } - } - else - { - // if the given smoothing group is 0, we'll return all surrounding vertices - if (!pSG) - { - while( it->mDistance < maxDist) - { - if((it->mPosition - pPosition).SquareLength() < squareEpsilon) - poResults.push_back( it->mIndex); - ++it; - if( end == it)break; - } - } - else while( it->mDistance < maxDist) - { - if((it->mPosition - pPosition).SquareLength() < squareEpsilon && - (it->mSmoothGroups & pSG || !it->mSmoothGroups)) - { - poResults.push_back( it->mIndex); - } - ++it; - if( end == it)break; - } - } -} - - diff --git a/thirdparty/assimp/code/Common/SceneCombiner.cpp b/thirdparty/assimp/code/Common/SceneCombiner.cpp deleted file mode 100644 index f7b13cc951..0000000000 --- a/thirdparty/assimp/code/Common/SceneCombiner.cpp +++ /dev/null @@ -1,1350 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -// TODO: refactor entire file to get rid of the "flat-copy" first approach -// to copying structures. This easily breaks in the most unintuitive way -// possible as new fields are added to assimp structures. - -// ---------------------------------------------------------------------------- -/** - * @file Implements Assimp::SceneCombiner. This is a smart utility - * class that combines multiple scenes, meshes, ... into one. Currently - * these utilities are used by the IRR and LWS loaders and the - * OptimizeGraph step. - */ -// ---------------------------------------------------------------------------- -#include <assimp/SceneCombiner.h> -#include <assimp/StringUtils.h> -#include <assimp/fast_atof.h> -#include <assimp/metadata.h> -#include <assimp/Hash.h> -#include "time.h" -#include <assimp/DefaultLogger.hpp> -#include <assimp/scene.h> -#include <assimp/mesh.h> -#include <stdio.h> -#include "ScenePrivate.h" - -namespace Assimp { - -// ------------------------------------------------------------------------------------------------ -// Add a prefix to a string -inline -void PrefixString(aiString& string,const char* prefix, unsigned int len) { - // If the string is already prefixed, we won't prefix it a second time - if (string.length >= 1 && string.data[0] == '$') - return; - - if (len+string.length>=MAXLEN-1) { - ASSIMP_LOG_DEBUG("Can't add an unique prefix because the string is too long"); - ai_assert(false); - return; - } - - // Add the prefix - ::memmove(string.data+len,string.data,string.length+1); - ::memcpy (string.data, prefix, len); - - // And update the string's length - string.length += len; -} - -// ------------------------------------------------------------------------------------------------ -// Add node identifiers to a hashing set -void SceneCombiner::AddNodeHashes(aiNode* node, std::set<unsigned int>& hashes) { - // Add node name to hashing set if it is non-empty - empty nodes are allowed - // and they can't have any anims assigned so its absolutely safe to duplicate them. - if (node->mName.length) { - hashes.insert( SuperFastHash(node->mName.data, static_cast<uint32_t>(node->mName.length)) ); - } - - // Process all children recursively - for (unsigned int i = 0; i < node->mNumChildren;++i) - AddNodeHashes(node->mChildren[i],hashes); -} - -// ------------------------------------------------------------------------------------------------ -// Add a name prefix to all nodes in a hierarchy -void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len) { - ai_assert(NULL != prefix); - PrefixString(node->mName,prefix,len); - - // Process all children recursively - for ( unsigned int i = 0; i < node->mNumChildren; ++i ) { - AddNodePrefixes( node->mChildren[ i ], prefix, len ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Search for matching names -bool SceneCombiner::FindNameMatch(const aiString& name, std::vector<SceneHelper>& input, unsigned int cur) { - const unsigned int hash = SuperFastHash(name.data, static_cast<uint32_t>(name.length)); - - // Check whether we find a positive match in one of the given sets - for (unsigned int i = 0; i < input.size(); ++i) { - if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) { - return true; - } - } - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Add a name prefix to all nodes in a hierarchy if a hash match is found -void SceneCombiner::AddNodePrefixesChecked(aiNode* node, const char* prefix, unsigned int len, - std::vector<SceneHelper>& input, unsigned int cur) { - ai_assert(NULL != prefix); - const unsigned int hash = SuperFastHash(node->mName.data, static_cast<uint32_t>(node->mName.length)); - - // Check whether we find a positive match in one of the given sets - for (unsigned int i = 0; i < input.size(); ++i) { - if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) { - PrefixString(node->mName,prefix,len); - break; - } - } - - // Process all children recursively - for (unsigned int i = 0; i < node->mNumChildren;++i) - AddNodePrefixesChecked(node->mChildren[i],prefix,len,input,cur); -} - -// ------------------------------------------------------------------------------------------------ -// Add an offset to all mesh indices in a node graph -void SceneCombiner::OffsetNodeMeshIndices (aiNode* node, unsigned int offset) { - for (unsigned int i = 0; i < node->mNumMeshes;++i) - node->mMeshes[i] += offset; - - for ( unsigned int i = 0; i < node->mNumChildren; ++i ) { - OffsetNodeMeshIndices( node->mChildren[ i ], offset ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Merges two scenes. Currently only used by the LWS loader. -void SceneCombiner::MergeScenes(aiScene** _dest,std::vector<aiScene*>& src, unsigned int flags) { - if ( nullptr == _dest ) { - return; - } - - // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it - if (src.empty()) { - if (*_dest) { - (*_dest)->~aiScene(); - SceneCombiner::CopySceneFlat(_dest,src[0]); - } - else *_dest = src[0]; - return; - } - if (*_dest)(*_dest)->~aiScene(); - else *_dest = new aiScene(); - - // Create a dummy scene to serve as master for the others - aiScene* master = new aiScene(); - master->mRootNode = new aiNode(); - master->mRootNode->mName.Set("<MergeRoot>"); - - std::vector<AttachmentInfo> srcList (src.size()); - for (unsigned int i = 0; i < srcList.size();++i) { - srcList[i] = AttachmentInfo(src[i],master->mRootNode); - } - - // 'master' will be deleted afterwards - MergeScenes (_dest, master, srcList, flags); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInfo>& srcList) { - unsigned int cnt; - for ( cnt = 0; cnt < attach->mNumChildren; ++cnt ) { - AttachToGraph( attach->mChildren[ cnt ], srcList ); - } - - cnt = 0; - for (std::vector<NodeAttachmentInfo>::iterator it = srcList.begin(); - it != srcList.end(); ++it) - { - if ((*it).attachToNode == attach && !(*it).resolved) - ++cnt; - } - - if (cnt) { - aiNode** n = new aiNode*[cnt+attach->mNumChildren]; - if (attach->mNumChildren) { - ::memcpy(n,attach->mChildren,sizeof(void*)*attach->mNumChildren); - delete[] attach->mChildren; - } - attach->mChildren = n; - - n += attach->mNumChildren; - attach->mNumChildren += cnt; - - for (unsigned int i = 0; i < srcList.size();++i) { - NodeAttachmentInfo& att = srcList[i]; - if (att.attachToNode == attach && !att.resolved) { - *n = att.node; - (**n).mParent = attach; - ++n; - - // mark this attachment as resolved - att.resolved = true; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::AttachToGraph ( aiScene* master, std::vector<NodeAttachmentInfo>& src) { - ai_assert(NULL != master); - AttachToGraph(master->mRootNode,src); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, std::vector<AttachmentInfo>& srcList, unsigned int flags) { - if ( nullptr == _dest ) { - return; - } - - // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it - if (srcList.empty()) { - if (*_dest) { - SceneCombiner::CopySceneFlat(_dest,master); - } - else *_dest = master; - return; - } - if (*_dest) { - (*_dest)->~aiScene(); - new (*_dest) aiScene(); - } - else *_dest = new aiScene(); - - aiScene* dest = *_dest; - - std::vector<SceneHelper> src (srcList.size()+1); - src[0].scene = master; - for (unsigned int i = 0; i < srcList.size();++i) { - src[i+1] = SceneHelper( srcList[i].scene ); - } - - // this helper array specifies which scenes are duplicates of others - std::vector<unsigned int> duplicates(src.size(),UINT_MAX); - - // this helper array is used as lookup table several times - std::vector<unsigned int> offset(src.size()); - - // Find duplicate scenes - for (unsigned int i = 0; i < src.size();++i) { - if (duplicates[i] != i && duplicates[i] != UINT_MAX) { - continue; - } - - duplicates[i] = i; - for ( unsigned int a = i+1; a < src.size(); ++a) { - if (src[i].scene == src[a].scene) { - duplicates[a] = i; - } - } - } - - // Generate unique names for all named stuff? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) - { -#if 0 - // Construct a proper random number generator - boost::mt19937 rng( ); - boost::uniform_int<> dist(1u,1 << 24u); - boost::variate_generator<boost::mt19937&, boost::uniform_int<> > rndGen(rng, dist); -#endif - for (unsigned int i = 1; i < src.size();++i) - { - //if (i != duplicates[i]) - //{ - // // duplicate scenes share the same UID - // ::strcpy( src[i].id, src[duplicates[i]].id ); - // src[i].idlen = src[duplicates[i]].idlen; - - // continue; - //} - - src[i].idlen = ai_snprintf(src[i].id, 32, "$%.6X$_",i); - - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - - // Compute hashes for all identifiers in this scene and store them - // in a sorted table (for convenience I'm using std::set). We hash - // just the node and animation channel names, all identifiers except - // the material names should be caught by doing this. - AddNodeHashes(src[i]->mRootNode,src[i].hashes); - - for (unsigned int a = 0; a < src[i]->mNumAnimations;++a) { - aiAnimation* anim = src[i]->mAnimations[a]; - src[i].hashes.insert(SuperFastHash(anim->mName.data,static_cast<uint32_t>(anim->mName.length))); - } - } - } - } - - unsigned int cnt; - - // First find out how large the respective output arrays must be - for ( unsigned int n = 0; n < src.size();++n ) - { - SceneHelper* cur = &src[n]; - - if (n == duplicates[n] || flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) { - dest->mNumTextures += (*cur)->mNumTextures; - dest->mNumMaterials += (*cur)->mNumMaterials; - dest->mNumMeshes += (*cur)->mNumMeshes; - } - - dest->mNumLights += (*cur)->mNumLights; - dest->mNumCameras += (*cur)->mNumCameras; - dest->mNumAnimations += (*cur)->mNumAnimations; - - // Combine the flags of all scenes - // We need to process them flag-by-flag here to get correct results - // dest->mFlags ; //|= (*cur)->mFlags; - if ((*cur)->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { - dest->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; - } - } - - // generate the output texture list + an offset table for all texture indices - if (dest->mNumTextures) - { - aiTexture** pip = dest->mTextures = new aiTexture*[dest->mNumMaterials]; - cnt = 0; - for ( unsigned int n = 0; n < src.size();++n ) - { - SceneHelper* cur = &src[n]; - for (unsigned int i = 0; i < (*cur)->mNumTextures;++i) - { - if (n != duplicates[n]) - { - if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) - Copy(pip,(*cur)->mTextures[i]); - - else continue; - } - else *pip = (*cur)->mTextures[i]; - ++pip; - } - - offset[n] = cnt; - cnt = (unsigned int)(pip - dest->mTextures); - } - } - - // generate the output material list + an offset table for all material indices - if (dest->mNumMaterials) - { - aiMaterial** pip = dest->mMaterials = new aiMaterial*[dest->mNumMaterials]; - cnt = 0; - for ( unsigned int n = 0; n < src.size();++n ) { - SceneHelper* cur = &src[n]; - for (unsigned int i = 0; i < (*cur)->mNumMaterials;++i) - { - if (n != duplicates[n]) - { - if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) - Copy(pip,(*cur)->mMaterials[i]); - - else continue; - } - else *pip = (*cur)->mMaterials[i]; - - if ((*cur)->mNumTextures != dest->mNumTextures) { - // We need to update all texture indices of the mesh. So we need to search for - // a material property called '$tex.file' - - for (unsigned int a = 0; a < (*pip)->mNumProperties;++a) - { - aiMaterialProperty* prop = (*pip)->mProperties[a]; - if (!strncmp(prop->mKey.data,"$tex.file",9)) - { - // Check whether this texture is an embedded texture. - // In this case the property looks like this: *<n>, - // where n is the index of the texture. - aiString& s = *((aiString*)prop->mData); - if ('*' == s.data[0]) { - // Offset the index and write it back .. - const unsigned int idx = strtoul10(&s.data[1]) + offset[n]; - ASSIMP_itoa10(&s.data[1],sizeof(s.data)-1,idx); - } - } - - // Need to generate new, unique material names? - else if (!::strcmp( prop->mKey.data,"$mat.name" ) && flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) - { - aiString* pcSrc = (aiString*) prop->mData; - PrefixString(*pcSrc, (*cur).id, (*cur).idlen); - } - } - } - ++pip; - } - - offset[n] = cnt; - cnt = (unsigned int)(pip - dest->mMaterials); - } - } - - // generate the output mesh list + again an offset table for all mesh indices - if (dest->mNumMeshes) - { - aiMesh** pip = dest->mMeshes = new aiMesh*[dest->mNumMeshes]; - cnt = 0; - for ( unsigned int n = 0; n < src.size();++n ) - { - SceneHelper* cur = &src[n]; - for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i) - { - if (n != duplicates[n]) { - if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) - Copy(pip, (*cur)->mMeshes[i]); - - else continue; - } - else *pip = (*cur)->mMeshes[i]; - - // update the material index of the mesh - (*pip)->mMaterialIndex += offset[n]; - ++pip; - } - - // reuse the offset array - store now the mesh offset in it - offset[n] = cnt; - cnt = (unsigned int)(pip - dest->mMeshes); - } - } - - std::vector <NodeAttachmentInfo> nodes; - nodes.reserve(srcList.size()); - - // ---------------------------------------------------------------------------- - // Now generate the output node graph. We need to make those - // names in the graph that are referenced by anims or lights - // or cameras unique. So we add a prefix to them ... $<rand>_ - // We could also use a counter, but using a random value allows us to - // use just one prefix if we are joining multiple scene hierarchies recursively. - // Chances are quite good we don't collide, so we try that ... - // ---------------------------------------------------------------------------- - - // Allocate space for light sources, cameras and animations - aiLight** ppLights = dest->mLights = (dest->mNumLights - ? new aiLight*[dest->mNumLights] : NULL); - - aiCamera** ppCameras = dest->mCameras = (dest->mNumCameras - ? new aiCamera*[dest->mNumCameras] : NULL); - - aiAnimation** ppAnims = dest->mAnimations = (dest->mNumAnimations - ? new aiAnimation*[dest->mNumAnimations] : NULL); - - for ( int n = static_cast<int>(src.size()-1); n >= 0 ;--n ) /* !!! important !!! */ - { - SceneHelper* cur = &src[n]; - aiNode* node; - - // To offset or not to offset, this is the question - if (n != (int)duplicates[n]) - { - // Get full scene-graph copy - Copy( &node, (*cur)->mRootNode ); - OffsetNodeMeshIndices(node,offset[duplicates[n]]); - - if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) { - // (note:) they are already 'offseted' by offset[duplicates[n]] - OffsetNodeMeshIndices(node,offset[n] - offset[duplicates[n]]); - } - } - else // if (n == duplicates[n]) - { - node = (*cur)->mRootNode; - OffsetNodeMeshIndices(node,offset[n]); - } - if (n) // src[0] is the master node - nodes.push_back(NodeAttachmentInfo( node,srcList[n-1].attachToNode,n )); - - // add name prefixes? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { - - // or the whole scenegraph - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - AddNodePrefixesChecked(node,(*cur).id,(*cur).idlen,src,n); - } - else AddNodePrefixes(node,(*cur).id,(*cur).idlen); - - // meshes - for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i) { - aiMesh* mesh = (*cur)->mMeshes[i]; - - // rename all bones - for (unsigned int a = 0; a < mesh->mNumBones;++a) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch(mesh->mBones[a]->mName,src,n)) - continue; - } - PrefixString(mesh->mBones[a]->mName,(*cur).id,(*cur).idlen); - } - } - } - - // -------------------------------------------------------------------- - // Copy light sources - for (unsigned int i = 0; i < (*cur)->mNumLights;++i,++ppLights) - { - if (n != (int)duplicates[n]) // duplicate scene? - { - Copy(ppLights, (*cur)->mLights[i]); - } - else *ppLights = (*cur)->mLights[i]; - - - // Add name prefixes? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch((*ppLights)->mName,src,n)) - continue; - } - - PrefixString((*ppLights)->mName,(*cur).id,(*cur).idlen); - } - } - - // -------------------------------------------------------------------- - // Copy cameras - for (unsigned int i = 0; i < (*cur)->mNumCameras;++i,++ppCameras) { - if (n != (int)duplicates[n]) // duplicate scene? - { - Copy(ppCameras, (*cur)->mCameras[i]); - } - else *ppCameras = (*cur)->mCameras[i]; - - // Add name prefixes? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch((*ppCameras)->mName,src,n)) - continue; - } - - PrefixString((*ppCameras)->mName,(*cur).id,(*cur).idlen); - } - } - - // -------------------------------------------------------------------- - // Copy animations - for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i,++ppAnims) { - if (n != (int)duplicates[n]) // duplicate scene? - { - Copy(ppAnims, (*cur)->mAnimations[i]); - } - else *ppAnims = (*cur)->mAnimations[i]; - - // Add name prefixes? - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch((*ppAnims)->mName,src,n)) - continue; - } - - PrefixString((*ppAnims)->mName,(*cur).id,(*cur).idlen); - - // don't forget to update all node animation channels - for (unsigned int a = 0; a < (*ppAnims)->mNumChannels;++a) { - if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { - if (!FindNameMatch((*ppAnims)->mChannels[a]->mNodeName,src,n)) - continue; - } - - PrefixString((*ppAnims)->mChannels[a]->mNodeName,(*cur).id,(*cur).idlen); - } - } - } - } - - // Now build the output graph - AttachToGraph ( master, nodes); - dest->mRootNode = master->mRootNode; - - // Check whether we succeeded at building the output graph - for (std::vector <NodeAttachmentInfo> ::iterator it = nodes.begin(); - it != nodes.end(); ++it) - { - if (!(*it).resolved) { - if (flags & AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS) { - // search for this attachment point in all other imported scenes, too. - for ( unsigned int n = 0; n < src.size();++n ) { - if (n != (*it).src_idx) { - AttachToGraph(src[n].scene,nodes); - if ((*it).resolved) - break; - } - } - } - if (!(*it).resolved) { - ASSIMP_LOG_ERROR_F( "SceneCombiner: Failed to resolve attachment ", (*it).node->mName.data, - " ", (*it).attachToNode->mName.data ); - } - } - } - - // now delete all input scenes. Make sure duplicate scenes aren't - // deleted more than one time - for ( unsigned int n = 0; n < src.size();++n ) { - if (n != duplicates[n]) // duplicate scene? - continue; - - aiScene* deleteMe = src[n].scene; - - // We need to delete the arrays before the destructor is called - - // we are reusing the array members - delete[] deleteMe->mMeshes; deleteMe->mMeshes = NULL; - delete[] deleteMe->mCameras; deleteMe->mCameras = NULL; - delete[] deleteMe->mLights; deleteMe->mLights = NULL; - delete[] deleteMe->mMaterials; deleteMe->mMaterials = NULL; - delete[] deleteMe->mAnimations; deleteMe->mAnimations = NULL; - - deleteMe->mRootNode = NULL; - - // Now we can safely delete the scene - delete deleteMe; - } - - // Check flags - if (!dest->mNumMeshes || !dest->mNumMaterials) { - dest->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - } - - // We're finished -} - -// ------------------------------------------------------------------------------------------------ -// Build a list of unique bones -void SceneCombiner::BuildUniqueBoneList(std::list<BoneWithHash>& asBones, - std::vector<aiMesh*>::const_iterator it, - std::vector<aiMesh*>::const_iterator end) -{ - unsigned int iOffset = 0; - for (; it != end;++it) { - for (unsigned int l = 0; l < (*it)->mNumBones;++l) { - aiBone* p = (*it)->mBones[l]; - uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length); - - std::list<BoneWithHash>::iterator it2 = asBones.begin(); - std::list<BoneWithHash>::iterator end2 = asBones.end(); - - for (;it2 != end2;++it2) { - if ((*it2).first == itml) { - (*it2).pSrcBones.push_back(BoneSrcIndex(p,iOffset)); - break; - } - } - if (end2 == it2) { - // need to begin a new bone entry - asBones.push_back(BoneWithHash()); - BoneWithHash& btz = asBones.back(); - - // setup members - btz.first = itml; - btz.second = &p->mName; - btz.pSrcBones.push_back(BoneSrcIndex(p,iOffset)); - } - } - iOffset += (*it)->mNumVertices; - } -} - -// ------------------------------------------------------------------------------------------------ -// Merge a list of bones -void SceneCombiner::MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it, - std::vector<aiMesh*>::const_iterator end) -{ - if ( nullptr == out || out->mNumBones == 0 ) { - return; - } - - // find we need to build an unique list of all bones. - // we work with hashes to make the comparisons MUCH faster, - // at least if we have many bones. - std::list<BoneWithHash> asBones; - BuildUniqueBoneList( asBones, it, end ); - - // now create the output bones - out->mNumBones = 0; - out->mBones = new aiBone*[asBones.size()]; - - for (std::list<BoneWithHash>::const_iterator boneIt = asBones.begin(),boneEnd = asBones.end(); boneIt != boneEnd; ++boneIt ) { - // Allocate a bone and setup it's name - aiBone* pc = out->mBones[out->mNumBones++] = new aiBone(); - pc->mName = aiString( *( boneIt->second )); - - std::vector< BoneSrcIndex >::const_iterator wend = boneIt->pSrcBones.end(); - - // Loop through all bones to be joined for this bone - for (std::vector< BoneSrcIndex >::const_iterator wmit = boneIt->pSrcBones.begin(); wmit != wend; ++wmit) { - pc->mNumWeights += (*wmit).first->mNumWeights; - - // NOTE: different offset matrices for bones with equal names - // are - at the moment - not handled correctly. - if (wmit != boneIt->pSrcBones.begin() && pc->mOffsetMatrix != wmit->first->mOffsetMatrix) { - ASSIMP_LOG_WARN("Bones with equal names but different offset matrices can't be joined at the moment"); - continue; - } - pc->mOffsetMatrix = wmit->first->mOffsetMatrix; - } - - // Allocate the vertex weight array - aiVertexWeight* avw = pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - - // And copy the final weights - adjust the vertex IDs by the - // face index offset of the corresponding mesh. - for (std::vector< BoneSrcIndex >::const_iterator wmit = (*boneIt).pSrcBones.begin(); wmit != (*boneIt).pSrcBones.end(); ++wmit) { - if (wmit == wend) { - break; - } - - aiBone* pip = (*wmit).first; - for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw) { - const aiVertexWeight& vfi = pip->mWeights[mp]; - avw->mWeight = vfi.mWeight; - avw->mVertexId = vfi.mVertexId + (*wmit).second; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Merge a list of meshes -void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/, - std::vector<aiMesh*>::const_iterator begin, - std::vector<aiMesh*>::const_iterator end) -{ - if ( nullptr == _out ) { - return; - } - - if (begin == end) { - *_out = NULL; // no meshes ... - return; - } - - // Allocate the output mesh - aiMesh* out = *_out = new aiMesh(); - out->mMaterialIndex = (*begin)->mMaterialIndex; - - std::string name; - // Find out how much output storage we'll need - for (std::vector<aiMesh*>::const_iterator it = begin; it != end; ++it) { - const char *meshName( (*it)->mName.C_Str() ); - name += std::string( meshName ); - if ( it != end - 1 ) { - name += "."; - } - out->mNumVertices += (*it)->mNumVertices; - out->mNumFaces += (*it)->mNumFaces; - out->mNumBones += (*it)->mNumBones; - - // combine primitive type flags - out->mPrimitiveTypes |= (*it)->mPrimitiveTypes; - } - out->mName.Set( name.c_str() ); - - if (out->mNumVertices) { - aiVector3D* pv2; - - // copy vertex positions - if ((**begin).HasPositions()) { - - pv2 = out->mVertices = new aiVector3D[out->mNumVertices]; - for (std::vector<aiMesh*>::const_iterator it = begin; it != end; ++it) { - if ((*it)->mVertices) { - ::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D)); - } - else ASSIMP_LOG_WARN("JoinMeshes: Positions expected but input mesh contains no positions"); - pv2 += (*it)->mNumVertices; - } - } - // copy normals - if ((**begin).HasNormals()) { - - pv2 = out->mNormals = new aiVector3D[out->mNumVertices]; - for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) { - if ((*it)->mNormals) { - ::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D)); - } else { - ASSIMP_LOG_WARN( "JoinMeshes: Normals expected but input mesh contains no normals" ); - } - pv2 += (*it)->mNumVertices; - } - } - // copy tangents and bi-tangents - if ((**begin).HasTangentsAndBitangents()) { - - pv2 = out->mTangents = new aiVector3D[out->mNumVertices]; - aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices]; - - for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) { - if ((*it)->mTangents) { - ::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D)); - ::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D)); - } else { - ASSIMP_LOG_WARN( "JoinMeshes: Tangents expected but input mesh contains no tangents" ); - } - pv2 += (*it)->mNumVertices; - pv2b += (*it)->mNumVertices; - } - } - // copy texture coordinates - unsigned int n = 0; - while ((**begin).HasTextureCoords(n)) { - out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n]; - - pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices]; - for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) { - if ((*it)->mTextureCoords[n]) { - ::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D)); - } else { - ASSIMP_LOG_WARN( "JoinMeshes: UVs expected but input mesh contains no UVs" ); - } - pv2 += (*it)->mNumVertices; - } - ++n; - } - // copy vertex colors - n = 0; - while ((**begin).HasVertexColors(n)) { - aiColor4D *pVec2 = out->mColors[n] = new aiColor4D[out->mNumVertices]; - for ( std::vector<aiMesh*>::const_iterator it = begin; it != end; ++it ) { - if ((*it)->mColors[n]) { - ::memcpy( pVec2, (*it)->mColors[ n ], (*it)->mNumVertices * sizeof( aiColor4D ) ) ; - } else { - ASSIMP_LOG_WARN( "JoinMeshes: VCs expected but input mesh contains no VCs" ); - } - pVec2 += (*it)->mNumVertices; - } - ++n; - } - } - - if (out->mNumFaces) // just for safety - { - // copy faces - out->mFaces = new aiFace[out->mNumFaces]; - aiFace* pf2 = out->mFaces; - - unsigned int ofs = 0; - for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) { - for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2) { - aiFace& face = (*it)->mFaces[m]; - pf2->mNumIndices = face.mNumIndices; - pf2->mIndices = face.mIndices; - - if (ofs) { - // add the offset to the vertex - for (unsigned int q = 0; q < face.mNumIndices; ++q) - face.mIndices[q] += ofs; - } - face.mIndices = NULL; - } - ofs += (*it)->mNumVertices; - } - } - - // bones - as this is quite lengthy, I moved the code to a separate function - if (out->mNumBones) - MergeBones(out,begin,end); - - // delete all source meshes - for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) - delete *it; -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::MergeMaterials(aiMaterial** dest, - std::vector<aiMaterial*>::const_iterator begin, - std::vector<aiMaterial*>::const_iterator end) -{ - if ( nullptr == dest ) { - return; - } - - if (begin == end) { - *dest = NULL; // no materials ... - return; - } - - // Allocate the output material - aiMaterial* out = *dest = new aiMaterial(); - - // Get the maximal number of properties - unsigned int size = 0; - for (std::vector<aiMaterial*>::const_iterator it = begin; it != end; ++it) { - size += (*it)->mNumProperties; - } - - out->Clear(); - delete[] out->mProperties; - - out->mNumAllocated = size; - out->mNumProperties = 0; - out->mProperties = new aiMaterialProperty*[out->mNumAllocated]; - - for (std::vector<aiMaterial*>::const_iterator it = begin; it != end; ++it) { - for(unsigned int i = 0; i < (*it)->mNumProperties; ++i) { - aiMaterialProperty* sprop = (*it)->mProperties[i]; - - // Test if we already have a matching property - const aiMaterialProperty* prop_exist; - if(aiGetMaterialProperty(out, sprop->mKey.C_Str(), sprop->mSemantic, sprop->mIndex, &prop_exist) != AI_SUCCESS) { - // If not, we add it to the new material - aiMaterialProperty* prop = out->mProperties[out->mNumProperties] = new aiMaterialProperty(); - - prop->mDataLength = sprop->mDataLength; - prop->mData = new char[prop->mDataLength]; - ::memcpy(prop->mData, sprop->mData, prop->mDataLength); - - prop->mIndex = sprop->mIndex; - prop->mSemantic = sprop->mSemantic; - prop->mKey = sprop->mKey; - prop->mType = sprop->mType; - - out->mNumProperties++; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -template <typename Type> -inline -void CopyPtrArray (Type**& dest, const Type* const * src, ai_uint num) { - if (!num) { - dest = NULL; - return; - } - dest = new Type*[num]; - for (ai_uint i = 0; i < num;++i) { - SceneCombiner::Copy(&dest[i],src[i]); - } -} - -// ------------------------------------------------------------------------------------------------ -template <typename Type> -inline -void GetArrayCopy(Type*& dest, ai_uint num ) { - if ( !dest ) { - return; - } - Type* old = dest; - - dest = new Type[num]; - ::memcpy(dest, old, sizeof(Type) * num); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::CopySceneFlat(aiScene** _dest,const aiScene* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - // reuse the old scene or allocate a new? - if (*_dest) { - (*_dest)->~aiScene(); - new (*_dest) aiScene(); - } else { - *_dest = new aiScene(); - } - - ::memcpy(*_dest,src,sizeof(aiScene)); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - if (allocate) { - *_dest = new aiScene(); - } - aiScene* dest = *_dest; - ai_assert(nullptr != dest); - - // copy metadata - if ( nullptr != src->mMetaData ) { - dest->mMetaData = new aiMetadata( *src->mMetaData ); - } - - // copy animations - dest->mNumAnimations = src->mNumAnimations; - CopyPtrArray(dest->mAnimations,src->mAnimations, - dest->mNumAnimations); - - // copy textures - dest->mNumTextures = src->mNumTextures; - CopyPtrArray(dest->mTextures,src->mTextures, - dest->mNumTextures); - - // copy materials - dest->mNumMaterials = src->mNumMaterials; - CopyPtrArray(dest->mMaterials,src->mMaterials, - dest->mNumMaterials); - - // copy lights - dest->mNumLights = src->mNumLights; - CopyPtrArray(dest->mLights,src->mLights, - dest->mNumLights); - - // copy cameras - dest->mNumCameras = src->mNumCameras; - CopyPtrArray(dest->mCameras,src->mCameras, - dest->mNumCameras); - - // copy meshes - dest->mNumMeshes = src->mNumMeshes; - CopyPtrArray(dest->mMeshes,src->mMeshes, - dest->mNumMeshes); - - // now - copy the root node of the scene (deep copy, too) - Copy( &dest->mRootNode, src->mRootNode); - - // and keep the flags ... - dest->mFlags = src->mFlags; - - // source private data might be NULL if the scene is user-allocated (i.e. for use with the export API) - if (dest->mPrivate != NULL) { - ScenePriv(dest)->mPPStepsApplied = ScenePriv(src) ? ScenePriv(src)->mPPStepsApplied : 0; - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy( aiMesh** _dest, const aiMesh* src ) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiMesh* dest = *_dest = new aiMesh(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiMesh)); - - // and reallocate all arrays - GetArrayCopy( dest->mVertices, dest->mNumVertices ); - GetArrayCopy( dest->mNormals , dest->mNumVertices ); - GetArrayCopy( dest->mTangents, dest->mNumVertices ); - GetArrayCopy( dest->mBitangents, dest->mNumVertices ); - - unsigned int n = 0; - while (dest->HasTextureCoords(n)) - GetArrayCopy( dest->mTextureCoords[n++], dest->mNumVertices ); - - n = 0; - while (dest->HasVertexColors(n)) - GetArrayCopy( dest->mColors[n++], dest->mNumVertices ); - - // make a deep copy of all bones - CopyPtrArray(dest->mBones,dest->mBones,dest->mNumBones); - - // make a deep copy of all faces - GetArrayCopy(dest->mFaces,dest->mNumFaces); - for (unsigned int i = 0; i < dest->mNumFaces;++i) { - aiFace& f = dest->mFaces[i]; - GetArrayCopy(f.mIndices,f.mNumIndices); - } - - // make a deep copy of all blend shapes - CopyPtrArray(dest->mAnimMeshes, dest->mAnimMeshes, dest->mNumAnimMeshes); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiAnimMesh** _dest, const aiAnimMesh* src) { - if (nullptr == _dest || nullptr == src) { - return; - } - - aiAnimMesh* dest = *_dest = new aiAnimMesh(); - - // get a flat copy - ::memcpy(dest, src, sizeof(aiAnimMesh)); - - // and reallocate all arrays - GetArrayCopy(dest->mVertices, dest->mNumVertices); - GetArrayCopy(dest->mNormals, dest->mNumVertices); - GetArrayCopy(dest->mTangents, dest->mNumVertices); - GetArrayCopy(dest->mBitangents, dest->mNumVertices); - - unsigned int n = 0; - while (dest->HasTextureCoords(n)) - GetArrayCopy(dest->mTextureCoords[n++], dest->mNumVertices); - - n = 0; - while (dest->HasVertexColors(n)) - GetArrayCopy(dest->mColors[n++], dest->mNumVertices); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() ); - - dest->Clear(); - delete[] dest->mProperties; - - dest->mNumAllocated = src->mNumAllocated; - dest->mNumProperties = src->mNumProperties; - dest->mProperties = new aiMaterialProperty* [dest->mNumAllocated]; - - for (unsigned int i = 0; i < dest->mNumProperties;++i) - { - aiMaterialProperty* prop = dest->mProperties[i] = new aiMaterialProperty(); - aiMaterialProperty* sprop = src->mProperties[i]; - - prop->mDataLength = sprop->mDataLength; - prop->mData = new char[prop->mDataLength]; - ::memcpy(prop->mData,sprop->mData,prop->mDataLength); - - prop->mIndex = sprop->mIndex; - prop->mSemantic = sprop->mSemantic; - prop->mKey = sprop->mKey; - prop->mType = sprop->mType; - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiTexture** _dest, const aiTexture* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiTexture* dest = *_dest = new aiTexture(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiTexture)); - - // and reallocate all arrays. We must do it manually here - const char* old = (const char*)dest->pcData; - if (old) - { - unsigned int cpy; - if (!dest->mHeight)cpy = dest->mWidth; - else cpy = dest->mHeight * dest->mWidth * sizeof(aiTexel); - - if (!cpy) - { - dest->pcData = NULL; - return; - } - // the cast is legal, the aiTexel c'tor does nothing important - dest->pcData = (aiTexel*) new char[cpy]; - ::memcpy(dest->pcData, old, cpy); - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src ) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiAnimation* dest = *_dest = new aiAnimation(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiAnimation)); - - // and reallocate all arrays - CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels ); - CopyPtrArray( dest->mMorphMeshChannels, src->mMorphMeshChannels, dest->mNumMorphMeshChannels ); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiNodeAnim** _dest, const aiNodeAnim* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiNodeAnim* dest = *_dest = new aiNodeAnim(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiNodeAnim)); - - // and reallocate all arrays - GetArrayCopy( dest->mPositionKeys, dest->mNumPositionKeys ); - GetArrayCopy( dest->mScalingKeys, dest->mNumScalingKeys ); - GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys ); -} - -void SceneCombiner::Copy(aiMeshMorphAnim** _dest, const aiMeshMorphAnim* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiMeshMorphAnim* dest = *_dest = new aiMeshMorphAnim(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiMeshMorphAnim)); - - // and reallocate all arrays - GetArrayCopy( dest->mKeys, dest->mNumKeys ); - for (ai_uint i = 0; i < dest->mNumKeys;++i) { - dest->mKeys[i].mValues = new unsigned int[dest->mKeys[i].mNumValuesAndWeights]; - dest->mKeys[i].mWeights = new double[dest->mKeys[i].mNumValuesAndWeights]; - ::memcpy(dest->mKeys[i].mValues, src->mKeys[i].mValues, dest->mKeys[i].mNumValuesAndWeights * sizeof(unsigned int)); - ::memcpy(dest->mKeys[i].mWeights, src->mKeys[i].mWeights, dest->mKeys[i].mNumValuesAndWeights * sizeof(double)); - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy( aiCamera** _dest,const aiCamera* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiCamera* dest = *_dest = new aiCamera(); - - // get a flat copy, that's already OK - ::memcpy(dest,src,sizeof(aiCamera)); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiLight** _dest, const aiLight* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiLight* dest = *_dest = new aiLight(); - - // get a flat copy, that's already OK - ::memcpy(dest,src,sizeof(aiLight)); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiBone** _dest, const aiBone* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - aiBone* dest = *_dest = new aiBone(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiBone)); - - // and reallocate all arrays - GetArrayCopy( dest->mWeights, dest->mNumWeights ); -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy (aiNode** _dest, const aiNode* src) -{ - ai_assert(NULL != _dest && NULL != src); - - aiNode* dest = *_dest = new aiNode(); - - // get a flat copy - ::memcpy(dest,src,sizeof(aiNode)); - - if (src->mMetaData) { - Copy(&dest->mMetaData, src->mMetaData); - } - - // and reallocate all arrays - GetArrayCopy( dest->mMeshes, dest->mNumMeshes ); - CopyPtrArray( dest->mChildren, src->mChildren,dest->mNumChildren); - - // need to set the mParent fields to the created aiNode. - for( unsigned int i = 0; i < dest->mNumChildren; i ++ ) { - dest->mChildren[i]->mParent = dest; - } -} - -// ------------------------------------------------------------------------------------------------ -void SceneCombiner::Copy(aiMetadata** _dest, const aiMetadata* src) { - if ( nullptr == _dest || nullptr == src ) { - return; - } - - if ( 0 == src->mNumProperties ) { - return; - } - - aiMetadata* dest = *_dest = aiMetadata::Alloc( src->mNumProperties ); - std::copy(src->mKeys, src->mKeys + src->mNumProperties, dest->mKeys); - - dest->mValues = new aiMetadataEntry[src->mNumProperties]; - for (unsigned int i = 0; i < src->mNumProperties; ++i) { - aiMetadataEntry& in = src->mValues[i]; - aiMetadataEntry& out = dest->mValues[i]; - out.mType = in.mType; - switch (dest->mValues[i].mType) { - case AI_BOOL: - out.mData = new bool(*static_cast<bool*>(in.mData)); - break; - case AI_INT32: - out.mData = new int32_t(*static_cast<int32_t*>(in.mData)); - break; - case AI_UINT64: - out.mData = new uint64_t(*static_cast<uint64_t*>(in.mData)); - break; - case AI_FLOAT: - out.mData = new float(*static_cast<float*>(in.mData)); - break; - case AI_DOUBLE: - out.mData = new double(*static_cast<double*>(in.mData)); - break; - case AI_AISTRING: - out.mData = new aiString(*static_cast<aiString*>(in.mData)); - break; - case AI_AIVECTOR3D: - out.mData = new aiVector3D(*static_cast<aiVector3D*>(in.mData)); - break; - default: - ai_assert(false); - break; - } - } -} - -} // Namespace Assimp - diff --git a/thirdparty/assimp/code/Common/ScenePreprocessor.cpp b/thirdparty/assimp/code/Common/ScenePreprocessor.cpp deleted file mode 100644 index 432a3d7666..0000000000 --- a/thirdparty/assimp/code/Common/ScenePreprocessor.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -#include "ScenePreprocessor.h" -#include <assimp/ai_assert.h> -#include <assimp/scene.h> -#include <assimp/DefaultLogger.hpp> - - -using namespace Assimp; - -// --------------------------------------------------------------------------------------------- -void ScenePreprocessor::ProcessScene () -{ - ai_assert(scene != NULL); - - // Process all meshes - for (unsigned int i = 0; i < scene->mNumMeshes;++i) - ProcessMesh(scene->mMeshes[i]); - - // - nothing to do for nodes for the moment - // - nothing to do for textures for the moment - // - nothing to do for lights for the moment - // - nothing to do for cameras for the moment - - // Process all animations - for (unsigned int i = 0; i < scene->mNumAnimations;++i) - ProcessAnimation(scene->mAnimations[i]); - - // Generate a default material if none was specified - if (!scene->mNumMaterials && scene->mNumMeshes) { - scene->mMaterials = new aiMaterial*[2]; - aiMaterial* helper; - - aiString name; - - scene->mMaterials[scene->mNumMaterials] = helper = new aiMaterial(); - aiColor3D clr(0.6f,0.6f,0.6f); - helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); - - // setup the default name to make this material identifiable - name.Set(AI_DEFAULT_MATERIAL_NAME); - helper->AddProperty(&name,AI_MATKEY_NAME); - - ASSIMP_LOG_DEBUG("ScenePreprocessor: Adding default material \'" AI_DEFAULT_MATERIAL_NAME "\'"); - - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { - scene->mMeshes[i]->mMaterialIndex = scene->mNumMaterials; - } - - scene->mNumMaterials++; - } -} - -// --------------------------------------------------------------------------------------------- -void ScenePreprocessor::ProcessMesh (aiMesh* mesh) -{ - // If aiMesh::mNumUVComponents is *not* set assign the default value of 2 - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (!mesh->mTextureCoords[i]) { - mesh->mNumUVComponents[i] = 0; - } else { - if (!mesh->mNumUVComponents[i]) - mesh->mNumUVComponents[i] = 2; - - aiVector3D* p = mesh->mTextureCoords[i], *end = p+mesh->mNumVertices; - - // Ensure unused components are zeroed. This will make 1D texture channels work - // as if they were 2D channels .. just in case an application doesn't handle - // this case - if (2 == mesh->mNumUVComponents[i]) { - for (; p != end; ++p) - p->z = 0.f; - } - else if (1 == mesh->mNumUVComponents[i]) { - for (; p != end; ++p) - p->z = p->y = 0.f; - } - else if (3 == mesh->mNumUVComponents[i]) { - // Really 3D coordinates? Check whether the third coordinate is != 0 for at least one element - for (; p != end; ++p) { - if (p->z != 0) - break; - } - if (p == end) { - ASSIMP_LOG_WARN("ScenePreprocessor: UVs are declared to be 3D but they're obviously not. Reverting to 2D."); - mesh->mNumUVComponents[i] = 2; - } - } - } - } - - // If the information which primitive types are there in the - // mesh is currently not available, compute it. - if (!mesh->mPrimitiveTypes) { - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { - aiFace& face = mesh->mFaces[a]; - switch (face.mNumIndices) - { - case 3u: - mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - - case 2u: - mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - - case 1u: - mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - - default: - mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - } - } - - // If tangents and normals are given but no bitangents compute them - if (mesh->mTangents && mesh->mNormals && !mesh->mBitangents) { - - mesh->mBitangents = new aiVector3D[mesh->mNumVertices]; - for (unsigned int i = 0; i < mesh->mNumVertices;++i) { - mesh->mBitangents[i] = mesh->mNormals[i] ^ mesh->mTangents[i]; - } - } -} - -// --------------------------------------------------------------------------------------------- -void ScenePreprocessor::ProcessAnimation (aiAnimation* anim) -{ - double first = 10e10, last = -10e10; - for (unsigned int i = 0; i < anim->mNumChannels;++i) { - aiNodeAnim* channel = anim->mChannels[i]; - - /* If the exact duration of the animation is not given - * compute it now. - */ - if (anim->mDuration == -1.) { - - // Position keys - for (unsigned int j = 0; j < channel->mNumPositionKeys;++j) { - aiVectorKey& key = channel->mPositionKeys[j]; - first = std::min (first, key.mTime); - last = std::max (last, key.mTime); - } - - // Scaling keys - for (unsigned int j = 0; j < channel->mNumScalingKeys;++j ) { - aiVectorKey& key = channel->mScalingKeys[j]; - first = std::min (first, key.mTime); - last = std::max (last, key.mTime); - } - - // Rotation keys - for (unsigned int j = 0; j < channel->mNumRotationKeys;++j ) { - aiQuatKey& key = channel->mRotationKeys[ j ]; - first = std::min (first, key.mTime); - last = std::max (last, key.mTime); - } - } - - /* Check whether the animation channel has no rotation - * or position tracks. In this case we generate a dummy - * track from the information we have in the transformation - * matrix of the corresponding node. - */ - if (!channel->mNumRotationKeys || !channel->mNumPositionKeys || !channel->mNumScalingKeys) { - // Find the node that belongs to this animation - aiNode* node = scene->mRootNode->FindNode(channel->mNodeName); - if (node) // ValidateDS will complain later if 'node' is NULL - { - // Decompose the transformation matrix of the node - aiVector3D scaling, position; - aiQuaternion rotation; - - node->mTransformation.Decompose(scaling, rotation,position); - - // No rotation keys? Generate a dummy track - if (!channel->mNumRotationKeys) { - channel->mNumRotationKeys = 1; - channel->mRotationKeys = new aiQuatKey[1]; - aiQuatKey& q = channel->mRotationKeys[0]; - - q.mTime = 0.; - q.mValue = rotation; - - ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy rotation track has been generated"); - } - - // No scaling keys? Generate a dummy track - if (!channel->mNumScalingKeys) { - channel->mNumScalingKeys = 1; - channel->mScalingKeys = new aiVectorKey[1]; - aiVectorKey& q = channel->mScalingKeys[0]; - - q.mTime = 0.; - q.mValue = scaling; - - ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy scaling track has been generated"); - } - - // No position keys? Generate a dummy track - if (!channel->mNumPositionKeys) { - channel->mNumPositionKeys = 1; - channel->mPositionKeys = new aiVectorKey[1]; - aiVectorKey& q = channel->mPositionKeys[0]; - - q.mTime = 0.; - q.mValue = position; - - ASSIMP_LOG_DEBUG("ScenePreprocessor: Dummy position track has been generated"); - } - } - } - } - - if (anim->mDuration == -1.) { - ASSIMP_LOG_DEBUG("ScenePreprocessor: Setting animation duration"); - anim->mDuration = last - std::min( first, 0. ); - } -} diff --git a/thirdparty/assimp/code/Common/ScenePreprocessor.h b/thirdparty/assimp/code/Common/ScenePreprocessor.h deleted file mode 100644 index 3f4c8d7c3f..0000000000 --- a/thirdparty/assimp/code/Common/ScenePreprocessor.h +++ /dev/null @@ -1,125 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to search all meshes for - degenerated faces */ -#ifndef AI_SCENE_PREPROCESSOR_H_INC -#define AI_SCENE_PREPROCESSOR_H_INC - -#include <assimp/defs.h> -#include <stddef.h> - -struct aiScene; -struct aiAnimation; -struct aiMesh; - -class ScenePreprocessorTest; -namespace Assimp { - -// ---------------------------------------------------------------------------------- -/** ScenePreprocessor: Preprocess a scene before any post-processing - * steps are executed. - * - * The step computes data that needn't necessarily be provided by the - * importer, such as aiMesh::mPrimitiveTypes. -*/ -// ---------------------------------------------------------------------------------- -class ASSIMP_API ScenePreprocessor -{ - // Make ourselves a friend of the corresponding test unit. - friend class ::ScenePreprocessorTest; -public: - - // ---------------------------------------------------------------- - /** Default c'tpr. Use SetScene() to assign a scene to the object. - */ - ScenePreprocessor() - : scene (NULL) - {} - - /** Constructs the object and assigns a specific scene to it - */ - ScenePreprocessor(aiScene* _scene) - : scene (_scene) - {} - - // ---------------------------------------------------------------- - /** Assign a (new) scene to the object. - * - * One 'SceneProcessor' can be used for multiple scenes. - * Call ProcessScene to have the scene preprocessed. - * @param sc Scene to be processed. - */ - void SetScene (aiScene* sc) { - scene = sc; - } - - // ---------------------------------------------------------------- - /** Preprocess the current scene - */ - void ProcessScene (); - -protected: - - // ---------------------------------------------------------------- - /** Preprocess an animation in the scene - * @param anim Anim to be preprocessed. - */ - void ProcessAnimation (aiAnimation* anim); - - - // ---------------------------------------------------------------- - /** Preprocess a mesh in the scene - * @param mesh Mesh to be preprocessed. - */ - void ProcessMesh (aiMesh* mesh); - -protected: - - //! Scene we're currently working on - aiScene* scene; -}; - - -} // ! end namespace Assimp - -#endif // include guard diff --git a/thirdparty/assimp/code/Common/ScenePrivate.h b/thirdparty/assimp/code/Common/ScenePrivate.h deleted file mode 100644 index f336aafc9a..0000000000 --- a/thirdparty/assimp/code/Common/ScenePrivate.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Stuff to deal with aiScene::mPrivate - */ -#pragma once -#ifndef AI_SCENEPRIVATE_H_INCLUDED -#define AI_SCENEPRIVATE_H_INCLUDED - -#include <assimp/ai_assert.h> -#include <assimp/scene.h> - -namespace Assimp { - -// Forward declarations -class Importer; - -struct ScenePrivateData { - // The struct constructor. - ScenePrivateData() AI_NO_EXCEPT; - - // Importer that originally loaded the scene though the C-API - // If set, this object is owned by this private data instance. - Assimp::Importer* mOrigImporter; - - // List of post-processing steps already applied to the scene. - unsigned int mPPStepsApplied; - - // true if the scene is a copy made with aiCopyScene() - // or the corresponding C++ API. This means that user code - // may have made modifications to it, so mPPStepsApplied - // and mOrigImporter are no longer safe to rely on and only - // serve informative purposes. - bool mIsCopy; -}; - -inline -ScenePrivateData::ScenePrivateData() AI_NO_EXCEPT -: mOrigImporter( nullptr ) -, mPPStepsApplied( 0 ) -, mIsCopy( false ) { - // empty -} - -// Access private data stored in the scene -inline -ScenePrivateData* ScenePriv(aiScene* in) { - ai_assert( nullptr != in ); - if ( nullptr == in ) { - return nullptr; - } - return static_cast<ScenePrivateData*>(in->mPrivate); -} - -inline -const ScenePrivateData* ScenePriv(const aiScene* in) { - ai_assert( nullptr != in ); - if ( nullptr == in ) { - return nullptr; - } - return static_cast<const ScenePrivateData*>(in->mPrivate); -} - -} // Namespace Assimp - -#endif // AI_SCENEPRIVATE_H_INCLUDED diff --git a/thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp b/thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp deleted file mode 100644 index 06cfe034e9..0000000000 --- a/thirdparty/assimp/code/Common/SkeletonMeshBuilder.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file SkeletonMeshBuilder.cpp - * @brief Implementation of a little class to construct a dummy mesh for a skeleton - */ - -#include <assimp/scene.h> -#include <assimp/SkeletonMeshBuilder.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// The constructor processes the given scene and adds a mesh there. -SkeletonMeshBuilder::SkeletonMeshBuilder( aiScene* pScene, aiNode* root, bool bKnobsOnly) -{ - // nothing to do if there's mesh data already present at the scene - if( pScene->mNumMeshes > 0 || pScene->mRootNode == NULL) - return; - - if (!root) - root = pScene->mRootNode; - - mKnobsOnly = bKnobsOnly; - - // build some faces around each node - CreateGeometry( root ); - - // create a mesh to hold all the generated faces - pScene->mNumMeshes = 1; - pScene->mMeshes = new aiMesh*[1]; - pScene->mMeshes[0] = CreateMesh(); - // and install it at the root node - root->mNumMeshes = 1; - root->mMeshes = new unsigned int[1]; - root->mMeshes[0] = 0; - - // create a dummy material for the mesh - if(pScene->mNumMaterials==0){ - pScene->mNumMaterials = 1; - pScene->mMaterials = new aiMaterial*[1]; - pScene->mMaterials[0] = CreateMaterial(); - } -} - -// ------------------------------------------------------------------------------------------------ -// Recursively builds a simple mesh representation for the given node -void SkeletonMeshBuilder::CreateGeometry( const aiNode* pNode) -{ - // add a joint entry for the node. - const unsigned int vertexStartIndex = static_cast<unsigned int>(mVertices.size()); - - // now build the geometry. - if( pNode->mNumChildren > 0 && !mKnobsOnly) - { - // If the node has children, we build little pointers to each of them - for( unsigned int a = 0; a < pNode->mNumChildren; a++) - { - // find a suitable coordinate system - const aiMatrix4x4& childTransform = pNode->mChildren[a]->mTransformation; - aiVector3D childpos( childTransform.a4, childTransform.b4, childTransform.c4); - ai_real distanceToChild = childpos.Length(); - if( distanceToChild < 0.0001) - continue; - aiVector3D up = aiVector3D( childpos).Normalize(); - - aiVector3D orth( 1.0, 0.0, 0.0); - if( std::fabs( orth * up) > 0.99) - orth.Set( 0.0, 1.0, 0.0); - - aiVector3D front = (up ^ orth).Normalize(); - aiVector3D side = (front ^ up).Normalize(); - - unsigned int localVertexStart = static_cast<unsigned int>(mVertices.size()); - mVertices.push_back( -front * distanceToChild * (ai_real)0.1); - mVertices.push_back( childpos); - mVertices.push_back( -side * distanceToChild * (ai_real)0.1); - mVertices.push_back( -side * distanceToChild * (ai_real)0.1); - mVertices.push_back( childpos); - mVertices.push_back( front * distanceToChild * (ai_real)0.1); - mVertices.push_back( front * distanceToChild * (ai_real)0.1); - mVertices.push_back( childpos); - mVertices.push_back( side * distanceToChild * (ai_real)0.1); - mVertices.push_back( side * distanceToChild * (ai_real)0.1); - mVertices.push_back( childpos); - mVertices.push_back( -front * distanceToChild * (ai_real)0.1); - - mFaces.push_back( Face( localVertexStart + 0, localVertexStart + 1, localVertexStart + 2)); - mFaces.push_back( Face( localVertexStart + 3, localVertexStart + 4, localVertexStart + 5)); - mFaces.push_back( Face( localVertexStart + 6, localVertexStart + 7, localVertexStart + 8)); - mFaces.push_back( Face( localVertexStart + 9, localVertexStart + 10, localVertexStart + 11)); - } - } - else - { - // if the node has no children, it's an end node. Put a little knob there instead - aiVector3D ownpos( pNode->mTransformation.a4, pNode->mTransformation.b4, pNode->mTransformation.c4); - ai_real sizeEstimate = ownpos.Length() * ai_real( 0.18 ); - - mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate)); - mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate)); - mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate)); - mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, -sizeEstimate)); - - mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate)); - mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate)); - mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( sizeEstimate, 0.0, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate)); - mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, -sizeEstimate, 0.0)); - mVertices.push_back( aiVector3D( 0.0, 0.0, sizeEstimate)); - mVertices.push_back( aiVector3D( -sizeEstimate, 0.0, 0.0)); - - mFaces.push_back( Face( vertexStartIndex + 0, vertexStartIndex + 1, vertexStartIndex + 2)); - mFaces.push_back( Face( vertexStartIndex + 3, vertexStartIndex + 4, vertexStartIndex + 5)); - mFaces.push_back( Face( vertexStartIndex + 6, vertexStartIndex + 7, vertexStartIndex + 8)); - mFaces.push_back( Face( vertexStartIndex + 9, vertexStartIndex + 10, vertexStartIndex + 11)); - mFaces.push_back( Face( vertexStartIndex + 12, vertexStartIndex + 13, vertexStartIndex + 14)); - mFaces.push_back( Face( vertexStartIndex + 15, vertexStartIndex + 16, vertexStartIndex + 17)); - mFaces.push_back( Face( vertexStartIndex + 18, vertexStartIndex + 19, vertexStartIndex + 20)); - mFaces.push_back( Face( vertexStartIndex + 21, vertexStartIndex + 22, vertexStartIndex + 23)); - } - - unsigned int numVertices = static_cast<unsigned int>(mVertices.size() - vertexStartIndex); - if( numVertices > 0) - { - // create a bone affecting all the newly created vertices - aiBone* bone = new aiBone; - mBones.push_back( bone); - bone->mName = pNode->mName; - - // calculate the bone offset matrix by concatenating the inverse transformations of all parents - bone->mOffsetMatrix = aiMatrix4x4( pNode->mTransformation).Inverse(); - for( aiNode* parent = pNode->mParent; parent != NULL; parent = parent->mParent) - bone->mOffsetMatrix = aiMatrix4x4( parent->mTransformation).Inverse() * bone->mOffsetMatrix; - - // add all the vertices to the bone's influences - bone->mNumWeights = numVertices; - bone->mWeights = new aiVertexWeight[numVertices]; - for( unsigned int a = 0; a < numVertices; a++) - bone->mWeights[a] = aiVertexWeight( vertexStartIndex + a, 1.0); - - // HACK: (thom) transform all vertices to the bone's local space. Should be done before adding - // them to the array, but I'm tired now and I'm annoyed. - aiMatrix4x4 boneToMeshTransform = aiMatrix4x4( bone->mOffsetMatrix).Inverse(); - for( unsigned int a = vertexStartIndex; a < mVertices.size(); a++) - mVertices[a] = boneToMeshTransform * mVertices[a]; - } - - // and finally recurse into the children list - for( unsigned int a = 0; a < pNode->mNumChildren; a++) - CreateGeometry( pNode->mChildren[a]); -} - -// ------------------------------------------------------------------------------------------------ -// Creates the mesh from the internally accumulated stuff and returns it. -aiMesh* SkeletonMeshBuilder::CreateMesh() -{ - aiMesh* mesh = new aiMesh(); - - // add points - mesh->mNumVertices = static_cast<unsigned int>(mVertices.size()); - mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - std::copy( mVertices.begin(), mVertices.end(), mesh->mVertices); - - mesh->mNormals = new aiVector3D[mesh->mNumVertices]; - - // add faces - mesh->mNumFaces = static_cast<unsigned int>(mFaces.size()); - mesh->mFaces = new aiFace[mesh->mNumFaces]; - for( unsigned int a = 0; a < mesh->mNumFaces; a++) - { - const Face& inface = mFaces[a]; - aiFace& outface = mesh->mFaces[a]; - outface.mNumIndices = 3; - outface.mIndices = new unsigned int[3]; - outface.mIndices[0] = inface.mIndices[0]; - outface.mIndices[1] = inface.mIndices[1]; - outface.mIndices[2] = inface.mIndices[2]; - - // Compute per-face normals ... we don't want the bones to be smoothed ... they're built to visualize - // the skeleton, so it's good if there's a visual difference to the rest of the geometry - aiVector3D nor = ((mVertices[inface.mIndices[2]] - mVertices[inface.mIndices[0]]) ^ - (mVertices[inface.mIndices[1]] - mVertices[inface.mIndices[0]])); - - if (nor.Length() < 1e-5) /* ensure that FindInvalidData won't remove us ...*/ - nor = aiVector3D(1.0,0.0,0.0); - - for (unsigned int n = 0; n < 3; ++n) - mesh->mNormals[inface.mIndices[n]] = nor; - } - - // add the bones - mesh->mNumBones = static_cast<unsigned int>(mBones.size()); - mesh->mBones = new aiBone*[mesh->mNumBones]; - std::copy( mBones.begin(), mBones.end(), mesh->mBones); - - // default - mesh->mMaterialIndex = 0; - - return mesh; -} - -// ------------------------------------------------------------------------------------------------ -// Creates a dummy material and returns it. -aiMaterial* SkeletonMeshBuilder::CreateMaterial() -{ - aiMaterial* matHelper = new aiMaterial; - - // Name - aiString matName( std::string( "SkeletonMaterial")); - matHelper->AddProperty( &matName, AI_MATKEY_NAME); - - // Prevent backface culling - const int no_cull = 1; - matHelper->AddProperty(&no_cull,1,AI_MATKEY_TWOSIDED); - - return matHelper; -} diff --git a/thirdparty/assimp/code/Common/SpatialSort.cpp b/thirdparty/assimp/code/Common/SpatialSort.cpp deleted file mode 100644 index a4f3a4e4b8..0000000000 --- a/thirdparty/assimp/code/Common/SpatialSort.cpp +++ /dev/null @@ -1,342 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the helper class to quickly find vertices close to a given position */ - -#include <assimp/SpatialSort.h> -#include <assimp/ai_assert.h> - -using namespace Assimp; - -// CHAR_BIT seems to be defined under MVSC, but not under GCC. Pray that the correct value is 8. -#ifndef CHAR_BIT -# define CHAR_BIT 8 -#endif - -// ------------------------------------------------------------------------------------------------ -// Constructs a spatially sorted representation from the given position array. -SpatialSort::SpatialSort( const aiVector3D* pPositions, unsigned int pNumPositions, - unsigned int pElementOffset) - - // define the reference plane. We choose some arbitrary vector away from all basic axises - // in the hope that no model spreads all its vertices along this plane. - : mPlaneNormal(0.8523f, 0.34321f, 0.5736f) -{ - mPlaneNormal.Normalize(); - Fill(pPositions,pNumPositions,pElementOffset); -} - -// ------------------------------------------------------------------------------------------------ -SpatialSort :: SpatialSort() -: mPlaneNormal(0.8523f, 0.34321f, 0.5736f) -{ - mPlaneNormal.Normalize(); -} - -// ------------------------------------------------------------------------------------------------ -// Destructor -SpatialSort::~SpatialSort() -{ - // nothing to do here, everything destructs automatically -} - -// ------------------------------------------------------------------------------------------------ -void SpatialSort::Fill( const aiVector3D* pPositions, unsigned int pNumPositions, - unsigned int pElementOffset, - bool pFinalize /*= true */) -{ - mPositions.clear(); - Append(pPositions,pNumPositions,pElementOffset,pFinalize); -} - -// ------------------------------------------------------------------------------------------------ -void SpatialSort :: Finalize() -{ - std::sort( mPositions.begin(), mPositions.end()); -} - -// ------------------------------------------------------------------------------------------------ -void SpatialSort::Append( const aiVector3D* pPositions, unsigned int pNumPositions, - unsigned int pElementOffset, - bool pFinalize /*= true */) -{ - // store references to all given positions along with their distance to the reference plane - const size_t initial = mPositions.size(); - mPositions.reserve(initial + (pFinalize?pNumPositions:pNumPositions*2)); - for( unsigned int a = 0; a < pNumPositions; a++) - { - const char* tempPointer = reinterpret_cast<const char*> (pPositions); - const aiVector3D* vec = reinterpret_cast<const aiVector3D*> (tempPointer + a * pElementOffset); - - // store position by index and distance - ai_real distance = *vec * mPlaneNormal; - mPositions.push_back( Entry( static_cast<unsigned int>(a+initial), *vec, distance)); - } - - if (pFinalize) { - // now sort the array ascending by distance. - Finalize(); - } -} - -// ------------------------------------------------------------------------------------------------ -// Returns an iterator for all positions close to the given position. -void SpatialSort::FindPositions( const aiVector3D& pPosition, - ai_real pRadius, std::vector<unsigned int>& poResults) const -{ - const ai_real dist = pPosition * mPlaneNormal; - const ai_real minDist = dist - pRadius, maxDist = dist + pRadius; - - // clear the array - poResults.clear(); - - // quick check for positions outside the range - if( mPositions.size() == 0) - return; - if( maxDist < mPositions.front().mDistance) - return; - if( minDist > mPositions.back().mDistance) - return; - - // do a binary search for the minimal distance to start the iteration there - unsigned int index = (unsigned int)mPositions.size() / 2; - unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4; - while( binaryStepSize > 1) - { - if( mPositions[index].mDistance < minDist) - index += binaryStepSize; - else - index -= binaryStepSize; - - binaryStepSize /= 2; - } - - // depending on the direction of the last step we need to single step a bit back or forth - // to find the actual beginning element of the range - while( index > 0 && mPositions[index].mDistance > minDist) - index--; - while( index < (mPositions.size() - 1) && mPositions[index].mDistance < minDist) - index++; - - // Mow start iterating from there until the first position lays outside of the distance range. - // Add all positions inside the distance range within the given radius to the result aray - std::vector<Entry>::const_iterator it = mPositions.begin() + index; - const ai_real pSquared = pRadius*pRadius; - while( it->mDistance < maxDist) - { - if( (it->mPosition - pPosition).SquareLength() < pSquared) - poResults.push_back( it->mIndex); - ++it; - if( it == mPositions.end()) - break; - } - - // that's it -} - -namespace { - - // Binary, signed-integer representation of a single-precision floating-point value. - // IEEE 754 says: "If two floating-point numbers in the same format are ordered then they are - // ordered the same way when their bits are reinterpreted as sign-magnitude integers." - // This allows us to convert all floating-point numbers to signed integers of arbitrary size - // and then use them to work with ULPs (Units in the Last Place, for high-precision - // computations) or to compare them (integer comparisons are faster than floating-point - // comparisons on many platforms). - typedef ai_int BinFloat; - - // -------------------------------------------------------------------------------------------- - // Converts the bit pattern of a floating-point number to its signed integer representation. - BinFloat ToBinary( const ai_real & pValue) { - - // If this assertion fails, signed int is not big enough to store a float on your platform. - // Please correct the declaration of BinFloat a few lines above - but do it in a portable, - // #ifdef'd manner! - static_assert( sizeof(BinFloat) >= sizeof(ai_real), "sizeof(BinFloat) >= sizeof(ai_real)"); - - #if defined( _MSC_VER) - // If this assertion fails, Visual C++ has finally moved to ILP64. This means that this - // code has just become legacy code! Find out the current value of _MSC_VER and modify - // the #if above so it evaluates false on the current and all upcoming VC versions (or - // on the current platform, if LP64 or LLP64 are still used on other platforms). - static_assert( sizeof(BinFloat) == sizeof(ai_real), "sizeof(BinFloat) == sizeof(ai_real)"); - - // This works best on Visual C++, but other compilers have their problems with it. - const BinFloat binValue = reinterpret_cast<BinFloat const &>(pValue); - #else - // On many compilers, reinterpreting a float address as an integer causes aliasing - // problems. This is an ugly but more or less safe way of doing it. - union { - ai_real asFloat; - BinFloat asBin; - } conversion; - conversion.asBin = 0; // zero empty space in case sizeof(BinFloat) > sizeof(float) - conversion.asFloat = pValue; - const BinFloat binValue = conversion.asBin; - #endif - - // floating-point numbers are of sign-magnitude format, so find out what signed number - // representation we must convert negative values to. - // See http://en.wikipedia.org/wiki/Signed_number_representations. - - // Two's complement? - if( (-42 == (~42 + 1)) && (binValue & 0x80000000)) - return BinFloat(1 << (CHAR_BIT * sizeof(BinFloat) - 1)) - binValue; - // One's complement? - else if ( (-42 == ~42) && (binValue & 0x80000000)) - return BinFloat(-0) - binValue; - // Sign-magnitude? - else if( (-42 == (42 | (-0))) && (binValue & 0x80000000)) // -0 = 1000... binary - return binValue; - else - return binValue; - } - -} // namespace - -// ------------------------------------------------------------------------------------------------ -// Fills an array with indices of all positions identical to the given position. In opposite to -// FindPositions(), not an epsilon is used but a (very low) tolerance of four floating-point units. -void SpatialSort::FindIdenticalPositions( const aiVector3D& pPosition, - std::vector<unsigned int>& poResults) const -{ - // Epsilons have a huge disadvantage: they are of constant precision, while floating-point - // values are of log2 precision. If you apply e=0.01 to 100, the epsilon is rather small, but - // if you apply it to 0.001, it is enormous. - - // The best way to overcome this is the unit in the last place (ULP). A precision of 2 ULPs - // tells us that a float does not differ more than 2 bits from the "real" value. ULPs are of - // logarithmic precision - around 1, they are 1*(2^24) and around 10000, they are 0.00125. - - // For standard C math, we can assume a precision of 0.5 ULPs according to IEEE 754. The - // incoming vertex positions might have already been transformed, probably using rather - // inaccurate SSE instructions, so we assume a tolerance of 4 ULPs to safely identify - // identical vertex positions. - static const int toleranceInULPs = 4; - // An interesting point is that the inaccuracy grows linear with the number of operations: - // multiplying to numbers, each inaccurate to four ULPs, results in an inaccuracy of four ULPs - // plus 0.5 ULPs for the multiplication. - // To compute the distance to the plane, a dot product is needed - that is a multiplication and - // an addition on each number. - static const int distanceToleranceInULPs = toleranceInULPs + 1; - // The squared distance between two 3D vectors is computed the same way, but with an additional - // subtraction. - static const int distance3DToleranceInULPs = distanceToleranceInULPs + 1; - - // Convert the plane distance to its signed integer representation so the ULPs tolerance can be - // applied. For some reason, VC won't optimize two calls of the bit pattern conversion. - const BinFloat minDistBinary = ToBinary( pPosition * mPlaneNormal) - distanceToleranceInULPs; - const BinFloat maxDistBinary = minDistBinary + 2 * distanceToleranceInULPs; - - // clear the array in this strange fashion because a simple clear() would also deallocate - // the array which we want to avoid - poResults.resize( 0 ); - - // do a binary search for the minimal distance to start the iteration there - unsigned int index = (unsigned int)mPositions.size() / 2; - unsigned int binaryStepSize = (unsigned int)mPositions.size() / 4; - while( binaryStepSize > 1) - { - // Ugly, but conditional jumps are faster with integers than with floats - if( minDistBinary > ToBinary(mPositions[index].mDistance)) - index += binaryStepSize; - else - index -= binaryStepSize; - - binaryStepSize /= 2; - } - - // depending on the direction of the last step we need to single step a bit back or forth - // to find the actual beginning element of the range - while( index > 0 && minDistBinary < ToBinary(mPositions[index].mDistance) ) - index--; - while( index < (mPositions.size() - 1) && minDistBinary > ToBinary(mPositions[index].mDistance)) - index++; - - // Now start iterating from there until the first position lays outside of the distance range. - // Add all positions inside the distance range within the tolerance to the result array - std::vector<Entry>::const_iterator it = mPositions.begin() + index; - while( ToBinary(it->mDistance) < maxDistBinary) - { - if( distance3DToleranceInULPs >= ToBinary((it->mPosition - pPosition).SquareLength())) - poResults.push_back(it->mIndex); - ++it; - if( it == mPositions.end()) - break; - } - - // that's it -} - -// ------------------------------------------------------------------------------------------------ -unsigned int SpatialSort::GenerateMappingTable(std::vector<unsigned int>& fill, ai_real pRadius) const -{ - fill.resize(mPositions.size(),UINT_MAX); - ai_real dist, maxDist; - - unsigned int t=0; - const ai_real pSquared = pRadius*pRadius; - for (size_t i = 0; i < mPositions.size();) { - dist = mPositions[i].mPosition * mPlaneNormal; - maxDist = dist + pRadius; - - fill[mPositions[i].mIndex] = t; - const aiVector3D& oldpos = mPositions[i].mPosition; - for (++i; i < fill.size() && mPositions[i].mDistance < maxDist - && (mPositions[i].mPosition - oldpos).SquareLength() < pSquared; ++i) - { - fill[mPositions[i].mIndex] = t; - } - ++t; - } - -#ifdef ASSIMP_BUILD_DEBUG - - // debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1 - for (size_t i = 0; i < fill.size(); ++i) { - ai_assert(fill[i]<mPositions.size()); - } - -#endif - return t; -} diff --git a/thirdparty/assimp/code/Common/SplitByBoneCountProcess.cpp b/thirdparty/assimp/code/Common/SplitByBoneCountProcess.cpp deleted file mode 100644 index 2ef66a9afc..0000000000 --- a/thirdparty/assimp/code/Common/SplitByBoneCountProcess.cpp +++ /dev/null @@ -1,407 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - - -/// @file SplitByBoneCountProcess.cpp -/// Implementation of the SplitByBoneCount postprocessing step - -// internal headers of the post-processing framework -#include "SplitByBoneCountProcess.h" -#include <assimp/postprocess.h> -#include <assimp/DefaultLogger.hpp> - -#include <limits> -#include <assimp/TinyFormatter.h> - -using namespace Assimp; -using namespace Assimp::Formatter; - -// ------------------------------------------------------------------------------------------------ -// Constructor -SplitByBoneCountProcess::SplitByBoneCountProcess() -{ - // set default, might be overridden by importer config - mMaxBoneCount = AI_SBBC_DEFAULT_MAX_BONES; -} - -// ------------------------------------------------------------------------------------------------ -// Destructor -SplitByBoneCountProcess::~SplitByBoneCountProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag. -bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const -{ - return !!(pFlags & aiProcess_SplitByBoneCount); -} - -// ------------------------------------------------------------------------------------------------ -// Updates internal properties -void SplitByBoneCountProcess::SetupProperties(const Importer* pImp) -{ - mMaxBoneCount = pImp->GetPropertyInteger(AI_CONFIG_PP_SBBC_MAX_BONES,AI_SBBC_DEFAULT_MAX_BONES); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitByBoneCountProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("SplitByBoneCountProcess begin"); - - // early out - bool isNecessary = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) - if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount ) - isNecessary = true; - - if( !isNecessary ) - { - ASSIMP_LOG_DEBUG( format() << "SplitByBoneCountProcess early-out: no meshes with more than " << mMaxBoneCount << " bones." ); - return; - } - - // we need to do something. Let's go. - mSubMeshIndices.clear(); - mSubMeshIndices.resize( pScene->mNumMeshes); - - // build a new array of meshes for the scene - std::vector<aiMesh*> meshes; - - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) - { - aiMesh* srcMesh = pScene->mMeshes[a]; - - std::vector<aiMesh*> newMeshes; - SplitMesh( pScene->mMeshes[a], newMeshes); - - // mesh was split - if( !newMeshes.empty() ) - { - // store new meshes and indices of the new meshes - for( unsigned int b = 0; b < newMeshes.size(); ++b) - { - mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size())); - meshes.push_back( newMeshes[b]); - } - - // and destroy the source mesh. It should be completely contained inside the new submeshes - delete srcMesh; - } - else - { - // Mesh is kept unchanged - store it's new place in the mesh array - mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size())); - meshes.push_back( srcMesh); - } - } - - // rebuild the scene's mesh array - pScene->mNumMeshes = static_cast<unsigned int>(meshes.size()); - delete [] pScene->mMeshes; - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - std::copy( meshes.begin(), meshes.end(), pScene->mMeshes); - - // recurse through all nodes and translate the node's mesh indices to fit the new mesh array - UpdateNode( pScene->mRootNode); - - ASSIMP_LOG_DEBUG( format() << "SplitByBoneCountProcess end: split " << mSubMeshIndices.size() << " meshes into " << meshes.size() << " submeshes." ); -} - -// ------------------------------------------------------------------------------------------------ -// Splits the given mesh by bone count. -void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const -{ - // skip if not necessary - if( pMesh->mNumBones <= mMaxBoneCount ) - return; - - // necessary optimisation: build a list of all affecting bones for each vertex - // TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays - typedef std::pair<unsigned int, float> BoneWeight; - std::vector< std::vector<BoneWeight> > vertexBones( pMesh->mNumVertices); - for( unsigned int a = 0; a < pMesh->mNumBones; ++a) - { - const aiBone* bone = pMesh->mBones[a]; - for( unsigned int b = 0; b < bone->mNumWeights; ++b) - vertexBones[ bone->mWeights[b].mVertexId ].push_back( BoneWeight( a, bone->mWeights[b].mWeight)); - } - - unsigned int numFacesHandled = 0; - std::vector<bool> isFaceHandled( pMesh->mNumFaces, false); - while( numFacesHandled < pMesh->mNumFaces ) - { - // which bones are used in the current submesh - unsigned int numBones = 0; - std::vector<bool> isBoneUsed( pMesh->mNumBones, false); - // indices of the faces which are going to go into this submesh - std::vector<unsigned int> subMeshFaces; - subMeshFaces.reserve( pMesh->mNumFaces); - // accumulated vertex count of all the faces in this submesh - unsigned int numSubMeshVertices = 0; - // a small local array of new bones for the current face. State of all used bones for that face - // can only be updated AFTER the face is completely analysed. Thanks to imre for the fix. - std::vector<unsigned int> newBonesAtCurrentFace; - - // add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit - for( unsigned int a = 0; a < pMesh->mNumFaces; ++a) - { - // skip if the face is already stored in a submesh - if( isFaceHandled[a] ) - continue; - - const aiFace& face = pMesh->mFaces[a]; - // check every vertex if its bones would still fit into the current submesh - for( unsigned int b = 0; b < face.mNumIndices; ++b ) - { - const std::vector<BoneWeight>& vb = vertexBones[face.mIndices[b]]; - for( unsigned int c = 0; c < vb.size(); ++c) - { - unsigned int boneIndex = vb[c].first; - // if the bone is already used in this submesh, it's ok - if( isBoneUsed[boneIndex] ) - continue; - - // if it's not used, yet, we would need to add it. Store its bone index - if( std::find( newBonesAtCurrentFace.begin(), newBonesAtCurrentFace.end(), boneIndex) == newBonesAtCurrentFace.end() ) - newBonesAtCurrentFace.push_back( boneIndex); - } - } - - // leave out the face if the new bones required for this face don't fit the bone count limit anymore - if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount ) - continue; - - // mark all new bones as necessary - while( !newBonesAtCurrentFace.empty() ) - { - unsigned int newIndex = newBonesAtCurrentFace.back(); - newBonesAtCurrentFace.pop_back(); // this also avoids the deallocation which comes with a clear() - if( isBoneUsed[newIndex] ) - continue; - - isBoneUsed[newIndex] = true; - numBones++; - } - - // store the face index and the vertex count - subMeshFaces.push_back( a); - numSubMeshVertices += face.mNumIndices; - - // remember that this face is handled - isFaceHandled[a] = true; - numFacesHandled++; - } - - // create a new mesh to hold this subset of the source mesh - aiMesh* newMesh = new aiMesh; - if( pMesh->mName.length > 0 ) - newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size()); - newMesh->mMaterialIndex = pMesh->mMaterialIndex; - newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes; - poNewMeshes.push_back( newMesh); - - // create all the arrays for this mesh if the old mesh contained them - newMesh->mNumVertices = numSubMeshVertices; - newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size()); - newMesh->mVertices = new aiVector3D[newMesh->mNumVertices]; - if( pMesh->HasNormals() ) - newMesh->mNormals = new aiVector3D[newMesh->mNumVertices]; - if( pMesh->HasTangentsAndBitangents() ) - { - newMesh->mTangents = new aiVector3D[newMesh->mNumVertices]; - newMesh->mBitangents = new aiVector3D[newMesh->mNumVertices]; - } - for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) - { - if( pMesh->HasTextureCoords( a) ) - newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices]; - newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a]; - } - for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) - { - if( pMesh->HasVertexColors( a) ) - newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices]; - } - - // and copy over the data, generating faces with linear indices along the way - newMesh->mFaces = new aiFace[subMeshFaces.size()]; - unsigned int nvi = 0; // next vertex index - std::vector<unsigned int> previousVertexIndices( numSubMeshVertices, std::numeric_limits<unsigned int>::max()); // per new vertex: its index in the source mesh - for( unsigned int a = 0; a < subMeshFaces.size(); ++a ) - { - const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; - aiFace& dstFace = newMesh->mFaces[a]; - dstFace.mNumIndices = srcFace.mNumIndices; - dstFace.mIndices = new unsigned int[dstFace.mNumIndices]; - - // accumulate linearly all the vertices of the source face - for( unsigned int b = 0; b < dstFace.mNumIndices; ++b ) - { - unsigned int srcIndex = srcFace.mIndices[b]; - dstFace.mIndices[b] = nvi; - previousVertexIndices[nvi] = srcIndex; - - newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex]; - if( pMesh->HasNormals() ) - newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex]; - if( pMesh->HasTangentsAndBitangents() ) - { - newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex]; - newMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex]; - } - for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c ) - { - if( pMesh->HasTextureCoords( c) ) - newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex]; - } - for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c ) - { - if( pMesh->HasVertexColors( c) ) - newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex]; - } - - nvi++; - } - } - - ai_assert( nvi == numSubMeshVertices ); - - // Create the bones for the new submesh: first create the bone array - newMesh->mNumBones = 0; - newMesh->mBones = new aiBone*[numBones]; - - std::vector<unsigned int> mappedBoneIndex( pMesh->mNumBones, std::numeric_limits<unsigned int>::max()); - for( unsigned int a = 0; a < pMesh->mNumBones; ++a ) - { - if( !isBoneUsed[a] ) - continue; - - // create the new bone - const aiBone* srcBone = pMesh->mBones[a]; - aiBone* dstBone = new aiBone; - mappedBoneIndex[a] = newMesh->mNumBones; - newMesh->mBones[newMesh->mNumBones++] = dstBone; - dstBone->mName = srcBone->mName; - dstBone->mOffsetMatrix = srcBone->mOffsetMatrix; - dstBone->mNumWeights = 0; - } - - ai_assert( newMesh->mNumBones == numBones ); - - // iterate over all new vertices and count which bones affected its old vertex in the source mesh - for( unsigned int a = 0; a < numSubMeshVertices; ++a ) - { - unsigned int oldIndex = previousVertexIndices[a]; - const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[oldIndex]; - - for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b ) - { - unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ]; - if( newBoneIndex != std::numeric_limits<unsigned int>::max() ) - newMesh->mBones[newBoneIndex]->mNumWeights++; - } - } - - // allocate all bone weight arrays accordingly - for( unsigned int a = 0; a < newMesh->mNumBones; ++a ) - { - aiBone* bone = newMesh->mBones[a]; - ai_assert( bone->mNumWeights > 0 ); - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - bone->mNumWeights = 0; // for counting up in the next step - } - - // now copy all the bone vertex weights for all the vertices which made it into the new submesh - for( unsigned int a = 0; a < numSubMeshVertices; ++a) - { - // find the source vertex for it in the source mesh - unsigned int previousIndex = previousVertexIndices[a]; - // these bones were affecting it - const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[previousIndex]; - // all of the bones affecting it should be present in the new submesh, or else - // the face it comprises shouldn't be present - for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b) - { - unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ]; - ai_assert( newBoneIndex != std::numeric_limits<unsigned int>::max() ); - aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights; - newMesh->mBones[newBoneIndex]->mNumWeights++; - - dstWeight->mVertexId = a; - dstWeight->mWeight = bonesOnThisVertex[b].second; - } - } - - // I have the strange feeling that this will break apart at some point in time... - } -} - -// ------------------------------------------------------------------------------------------------ -// Recursively updates the node's mesh list to account for the changed mesh list -void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const -{ - // rebuild the node's mesh index list - if( pNode->mNumMeshes > 0 ) - { - std::vector<unsigned int> newMeshList; - for( unsigned int a = 0; a < pNode->mNumMeshes; ++a) - { - unsigned int srcIndex = pNode->mMeshes[a]; - const std::vector<unsigned int>& replaceMeshes = mSubMeshIndices[srcIndex]; - newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end()); - } - - delete [] pNode->mMeshes; - pNode->mNumMeshes = static_cast<unsigned int>(newMeshList.size()); - pNode->mMeshes = new unsigned int[pNode->mNumMeshes]; - std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes); - } - - // do that also recursively for all children - for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) - { - UpdateNode( pNode->mChildren[a]); - } -} diff --git a/thirdparty/assimp/code/Common/SplitByBoneCountProcess.h b/thirdparty/assimp/code/Common/SplitByBoneCountProcess.h deleted file mode 100644 index 6c904a9df4..0000000000 --- a/thirdparty/assimp/code/Common/SplitByBoneCountProcess.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/// @file SplitByBoneCountProcess.h -/// Defines a post processing step to split meshes with many bones into submeshes -#ifndef AI_SPLITBYBONECOUNTPROCESS_H_INC -#define AI_SPLITBYBONECOUNTPROCESS_H_INC - -#include <vector> -#include "BaseProcess.h" - -#include <assimp/mesh.h> -#include <assimp/scene.h> - -namespace Assimp -{ - - -/** Postprocessing filter to split meshes with many bones into submeshes - * so that each submesh has a certain max bone count. - * - * Applied BEFORE the JoinVertices-Step occurs. - * Returns NON-UNIQUE vertices, splits by bone count. -*/ -class SplitByBoneCountProcess : public BaseProcess -{ -public: - - SplitByBoneCountProcess(); - ~SplitByBoneCountProcess(); - -public: - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. A - * bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - -protected: - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - /// Splits the given mesh by bone count. - /// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split. - /// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary. - void SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const; - - /// Recursively updates the node's mesh list to account for the changed mesh list - void UpdateNode( aiNode* pNode) const; - -public: - /// Max bone count. Splitting occurs if a mesh has more than that number of bones. - size_t mMaxBoneCount; - - /// Per mesh index: Array of indices of the new submeshes. - std::vector< std::vector<unsigned int> > mSubMeshIndices; -}; - -} // end of namespace Assimp - -#endif // !!AI_SPLITBYBONECOUNTPROCESS_H_INC diff --git a/thirdparty/assimp/code/Common/StandardShapes.cpp b/thirdparty/assimp/code/Common/StandardShapes.cpp deleted file mode 100644 index 2e5100130f..0000000000 --- a/thirdparty/assimp/code/Common/StandardShapes.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file StandardShapes.cpp - * @brief Implementation of the StandardShapes class - * - * The primitive geometry data comes from - * http://geometrictools.com/Documentation/PlatonicSolids.pdf. - */ - -#include <assimp/StandardShapes.h> -#include <assimp/StringComparison.h> -#include <stddef.h> -#include <assimp/Defines.h> -#include <assimp/mesh.h> - -namespace Assimp { - - -# define ADD_TRIANGLE(n0,n1,n2) \ - positions.push_back(n0); \ - positions.push_back(n1); \ - positions.push_back(n2); - -# define ADD_PENTAGON(n0,n1,n2,n3,n4) \ - if (polygons) \ - { \ - positions.push_back(n0); \ - positions.push_back(n1); \ - positions.push_back(n2); \ - positions.push_back(n3); \ - positions.push_back(n4); \ - } \ - else \ - { \ - ADD_TRIANGLE(n0, n1, n2) \ - ADD_TRIANGLE(n0, n2, n3) \ - ADD_TRIANGLE(n0, n3, n4) \ - } - -# define ADD_QUAD(n0,n1,n2,n3) \ - if (polygons) \ - { \ - positions.push_back(n0); \ - positions.push_back(n1); \ - positions.push_back(n2); \ - positions.push_back(n3); \ - } \ - else \ - { \ - ADD_TRIANGLE(n0, n1, n2) \ - ADD_TRIANGLE(n0, n2, n3) \ - } - - -// ------------------------------------------------------------------------------------------------ -// Fast subdivision for a mesh whose verts have a magnitude of 1 -void Subdivide(std::vector<aiVector3D>& positions) -{ - // assume this to be constant - (fixme: must be 1.0? I think so) - const ai_real fl1 = positions[0].Length(); - - unsigned int origSize = (unsigned int)positions.size(); - for (unsigned int i = 0 ; i < origSize ; i+=3) - { - aiVector3D& tv0 = positions[i]; - aiVector3D& tv1 = positions[i+1]; - aiVector3D& tv2 = positions[i+2]; - - aiVector3D a = tv0, b = tv1, c = tv2; - aiVector3D v1 = aiVector3D(a.x+b.x, a.y+b.y, a.z+b.z).Normalize()*fl1; - aiVector3D v2 = aiVector3D(a.x+c.x, a.y+c.y, a.z+c.z).Normalize()*fl1; - aiVector3D v3 = aiVector3D(b.x+c.x, b.y+c.y, b.z+c.z).Normalize()*fl1; - - tv0 = v1; tv1 = v3; tv2 = v2; // overwrite the original - ADD_TRIANGLE(v1, v2, a); - ADD_TRIANGLE(v2, v3, c); - ADD_TRIANGLE(v3, v1, b); - } -} - -// ------------------------------------------------------------------------------------------------ -// Construct a mesh from given vertex positions -aiMesh* StandardShapes::MakeMesh(const std::vector<aiVector3D>& positions, - unsigned int numIndices) -{ - if (positions.empty() || !numIndices) return NULL; - - // Determine which kinds of primitives the mesh consists of - aiMesh* out = new aiMesh(); - switch (numIndices) { - case 1: - out->mPrimitiveTypes = aiPrimitiveType_POINT; - break; - case 2: - out->mPrimitiveTypes = aiPrimitiveType_LINE; - break; - case 3: - out->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - break; - default: - out->mPrimitiveTypes = aiPrimitiveType_POLYGON; - break; - }; - - out->mNumFaces = (unsigned int)positions.size() / numIndices; - out->mFaces = new aiFace[out->mNumFaces]; - for (unsigned int i = 0, a = 0; i < out->mNumFaces;++i) { - aiFace& f = out->mFaces[i]; - f.mNumIndices = numIndices; - f.mIndices = new unsigned int[numIndices]; - for (unsigned int j = 0; i < numIndices; ++i, ++a) { - f.mIndices[j] = a; - } - } - out->mNumVertices = (unsigned int)positions.size(); - out->mVertices = new aiVector3D[out->mNumVertices]; - ::memcpy(out->mVertices,&positions[0],out->mNumVertices*sizeof(aiVector3D)); - - return out; -} - -// ------------------------------------------------------------------------------------------------ -// Construct a mesh with a specific shape (callback) -aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)( - std::vector<aiVector3D>&)) -{ - std::vector<aiVector3D> temp; - unsigned num = (*GenerateFunc)(temp); - return MakeMesh(temp,num); -} - -// ------------------------------------------------------------------------------------------------ -// Construct a mesh with a specific shape (callback) -aiMesh* StandardShapes::MakeMesh ( unsigned int (*GenerateFunc)( - std::vector<aiVector3D>&, bool)) -{ - std::vector<aiVector3D> temp; - unsigned num = (*GenerateFunc)(temp,true); - return MakeMesh(temp,num); -} - -// ------------------------------------------------------------------------------------------------ -// Construct a mesh with a specific shape (callback) -aiMesh* StandardShapes::MakeMesh (unsigned int num, void (*GenerateFunc)( - unsigned int,std::vector<aiVector3D>&)) -{ - std::vector<aiVector3D> temp; - (*GenerateFunc)(num,temp); - return MakeMesh(temp,3); -} - -// ------------------------------------------------------------------------------------------------ -// Build an incosahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeIcosahedron(std::vector<aiVector3D>& positions) -{ - positions.reserve(positions.size()+60); - - const ai_real t = ( ai_real( 1.0 )+ ai_real( 2.236067977 ) ) / ai_real( 2.0 ); - const ai_real s = std::sqrt(ai_real(1.0) + t*t); - - const aiVector3D v0 = aiVector3D(t,1.0, 0.0)/s; - const aiVector3D v1 = aiVector3D(-t,1.0, 0.0)/s; - const aiVector3D v2 = aiVector3D(t,-1.0, 0.0)/s; - const aiVector3D v3 = aiVector3D(-t,-1.0, 0.0)/s; - const aiVector3D v4 = aiVector3D(1.0, 0.0, t)/s; - const aiVector3D v5 = aiVector3D(1.0, 0.0,-t)/s; - const aiVector3D v6 = aiVector3D(-1.0, 0.0,t)/s; - const aiVector3D v7 = aiVector3D(-1.0, 0.0,-t)/s; - const aiVector3D v8 = aiVector3D(0.0, t, 1.0)/s; - const aiVector3D v9 = aiVector3D(0.0,-t, 1.0)/s; - const aiVector3D v10 = aiVector3D(0.0, t,-1.0)/s; - const aiVector3D v11 = aiVector3D(0.0,-t,-1.0)/s; - - ADD_TRIANGLE(v0,v8,v4); - ADD_TRIANGLE(v0,v5,v10); - ADD_TRIANGLE(v2,v4,v9); - ADD_TRIANGLE(v2,v11,v5); - - ADD_TRIANGLE(v1,v6,v8); - ADD_TRIANGLE(v1,v10,v7); - ADD_TRIANGLE(v3,v9,v6); - ADD_TRIANGLE(v3,v7,v11); - - ADD_TRIANGLE(v0,v10,v8); - ADD_TRIANGLE(v1,v8,v10); - ADD_TRIANGLE(v2,v9,v11); - ADD_TRIANGLE(v3,v11,v9); - - ADD_TRIANGLE(v4,v2,v0); - ADD_TRIANGLE(v5,v0,v2); - ADD_TRIANGLE(v6,v1,v3); - ADD_TRIANGLE(v7,v3,v1); - - ADD_TRIANGLE(v8,v6,v4); - ADD_TRIANGLE(v9,v4,v6); - ADD_TRIANGLE(v10,v5,v7); - ADD_TRIANGLE(v11,v7,v5); - return 3; -} - -// ------------------------------------------------------------------------------------------------ -// Build a dodecahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeDodecahedron(std::vector<aiVector3D>& positions, - bool polygons /*= false*/) -{ - positions.reserve(positions.size()+108); - - const ai_real a = ai_real( 1.0 ) / ai_real(1.7320508); - const ai_real b = std::sqrt(( ai_real( 3.0 )- ai_real( 2.23606797))/ ai_real( 6.0) ); - const ai_real c = std::sqrt(( ai_real( 3.0 )+ ai_real( 2.23606797f))/ ai_real( 6.0) ); - - const aiVector3D v0 = aiVector3D(a,a,a); - const aiVector3D v1 = aiVector3D(a,a,-a); - const aiVector3D v2 = aiVector3D(a,-a,a); - const aiVector3D v3 = aiVector3D(a,-a,-a); - const aiVector3D v4 = aiVector3D(-a,a,a); - const aiVector3D v5 = aiVector3D(-a,a,-a); - const aiVector3D v6 = aiVector3D(-a,-a,a); - const aiVector3D v7 = aiVector3D(-a,-a,-a); - const aiVector3D v8 = aiVector3D(b,c,0.0); - const aiVector3D v9 = aiVector3D(-b,c,0.0); - const aiVector3D v10 = aiVector3D(b,-c,0.0); - const aiVector3D v11 = aiVector3D(-b,-c,0.0); - const aiVector3D v12 = aiVector3D(c, 0.0, b); - const aiVector3D v13 = aiVector3D(c, 0.0, -b); - const aiVector3D v14 = aiVector3D(-c, 0.0, b); - const aiVector3D v15 = aiVector3D(-c, 0.0, -b); - const aiVector3D v16 = aiVector3D(0.0, b, c); - const aiVector3D v17 = aiVector3D(0.0, -b, c); - const aiVector3D v18 = aiVector3D(0.0, b, -c); - const aiVector3D v19 = aiVector3D(0.0, -b, -c); - - ADD_PENTAGON(v0, v8, v9, v4, v16); - ADD_PENTAGON(v0, v12, v13, v1, v8); - ADD_PENTAGON(v0, v16, v17, v2, v12); - ADD_PENTAGON(v8, v1, v18, v5, v9); - ADD_PENTAGON(v12, v2, v10, v3, v13); - ADD_PENTAGON(v16, v4, v14, v6, v17); - ADD_PENTAGON(v9, v5, v15, v14, v4); - - ADD_PENTAGON(v6, v11, v10, v2, v17); - ADD_PENTAGON(v3, v19, v18, v1, v13); - ADD_PENTAGON(v7, v15, v5, v18, v19); - ADD_PENTAGON(v7, v11, v6, v14, v15); - ADD_PENTAGON(v7, v19, v3, v10, v11); - return (polygons ? 5 : 3); -} - -// ------------------------------------------------------------------------------------------------ -// Build an octahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeOctahedron(std::vector<aiVector3D>& positions) -{ - positions.reserve(positions.size()+24); - - const aiVector3D v0 = aiVector3D(1.0, 0.0, 0.0) ; - const aiVector3D v1 = aiVector3D(-1.0, 0.0, 0.0); - const aiVector3D v2 = aiVector3D(0.0, 1.0, 0.0); - const aiVector3D v3 = aiVector3D(0.0, -1.0, 0.0); - const aiVector3D v4 = aiVector3D(0.0, 0.0, 1.0); - const aiVector3D v5 = aiVector3D(0.0, 0.0, -1.0); - - ADD_TRIANGLE(v4,v0,v2); - ADD_TRIANGLE(v4,v2,v1); - ADD_TRIANGLE(v4,v1,v3); - ADD_TRIANGLE(v4,v3,v0); - - ADD_TRIANGLE(v5,v2,v0); - ADD_TRIANGLE(v5,v1,v2); - ADD_TRIANGLE(v5,v3,v1); - ADD_TRIANGLE(v5,v0,v3); - return 3; -} - -// ------------------------------------------------------------------------------------------------ -// Build a tetrahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeTetrahedron(std::vector<aiVector3D>& positions) -{ - positions.reserve(positions.size()+9); - - const ai_real invThree = ai_real( 1.0 ) / ai_real( 3.0 ); - const ai_real a = ai_real( 1.41421 ) * invThree; - const ai_real b = ai_real( 2.4494 ) * invThree; - - const aiVector3D v0 = aiVector3D(0.0,0.0,1.0); - const aiVector3D v1 = aiVector3D(2*a,0,-invThree ); - const aiVector3D v2 = aiVector3D(-a,b,-invThree ); - const aiVector3D v3 = aiVector3D(-a,-b,-invThree ); - - ADD_TRIANGLE(v0,v1,v2); - ADD_TRIANGLE(v0,v2,v3); - ADD_TRIANGLE(v0,v3,v1); - ADD_TRIANGLE(v1,v3,v2); - return 3; -} - -// ------------------------------------------------------------------------------------------------ -// Build a hexahedron with points.magnitude == 1 -unsigned int StandardShapes::MakeHexahedron(std::vector<aiVector3D>& positions, - bool polygons /*= false*/) -{ - positions.reserve(positions.size()+36); - const ai_real length = ai_real(1.0)/ai_real(1.73205080); - - const aiVector3D v0 = aiVector3D(-1.0,-1.0,-1.0)*length; - const aiVector3D v1 = aiVector3D(1.0,-1.0,-1.0)*length; - const aiVector3D v2 = aiVector3D(1.0,1.0,-1.0)*length; - const aiVector3D v3 = aiVector3D(-1.0,1.0,-1.0)*length; - const aiVector3D v4 = aiVector3D(-1.0,-1.0,1.0)*length; - const aiVector3D v5 = aiVector3D(1.0,-1.0,1.0)*length; - const aiVector3D v6 = aiVector3D(1.0,1.0,1.0)*length; - const aiVector3D v7 = aiVector3D(-1.0,1.0,1.0)*length; - - ADD_QUAD(v0,v3,v2,v1); - ADD_QUAD(v0,v1,v5,v4); - ADD_QUAD(v0,v4,v7,v3); - ADD_QUAD(v6,v5,v1,v2); - ADD_QUAD(v6,v2,v3,v7); - ADD_QUAD(v6,v7,v4,v5); - return (polygons ? 4 : 3); -} - -// Cleanup ... -#undef ADD_TRIANGLE -#undef ADD_QUAD -#undef ADD_PENTAGON - -// ------------------------------------------------------------------------------------------------ -// Create a subdivision sphere -void StandardShapes::MakeSphere(unsigned int tess, - std::vector<aiVector3D>& positions) -{ - // Reserve enough storage. Every subdivision - // splits each triangle in 4, the icosahedron consists of 60 verts - positions.reserve(positions.size()+60 * integer_pow(4, tess)); - - // Construct an icosahedron to start with - MakeIcosahedron(positions); - - // ... and subdivide it until the requested output - // tessellation is reached - for (unsigned int i = 0; i<tess;++i) - Subdivide(positions); -} - -// ------------------------------------------------------------------------------------------------ -// Build a cone -void StandardShapes::MakeCone(ai_real height,ai_real radius1, - ai_real radius2,unsigned int tess, - std::vector<aiVector3D>& positions,bool bOpen /*= false */) -{ - // Sorry, a cone with less than 3 segments makes ABSOLUTELY NO SENSE - if (tess < 3 || !height) - return; - - size_t old = positions.size(); - - // No negative radii - radius1 = std::fabs(radius1); - radius2 = std::fabs(radius2); - - ai_real halfHeight = height / ai_real(2.0); - - // radius1 is always the smaller one - if (radius2 > radius1) - { - std::swap(radius2,radius1); - halfHeight = -halfHeight; - } - else old = SIZE_MAX; - - // Use a large epsilon to check whether the cone is pointy - if (radius1 < (radius2-radius1)*10e-3)radius1 = 0.0; - - // We will need 3*2 verts per segment + 3*2 verts per segment - // if the cone is closed - const unsigned int mem = tess*6 + (!bOpen ? tess*3 * (radius1 ? 2 : 1) : 0); - positions.reserve(positions.size () + mem); - - // Now construct all segments - const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess; - const ai_real angle_max = (ai_real)AI_MATH_TWO_PI; - - ai_real s = 1.0; // std::cos(angle == 0); - ai_real t = 0.0; // std::sin(angle == 0); - - for (ai_real angle = 0.0; angle < angle_max; ) - { - const aiVector3D v1 = aiVector3D (s * radius1, -halfHeight, t * radius1 ); - const aiVector3D v2 = aiVector3D (s * radius2, halfHeight, t * radius2 ); - - const ai_real next = angle + angle_delta; - ai_real s2 = std::cos(next); - ai_real t2 = std::sin(next); - - const aiVector3D v3 = aiVector3D (s2 * radius2, halfHeight, t2 * radius2 ); - const aiVector3D v4 = aiVector3D (s2 * radius1, -halfHeight, t2 * radius1 ); - - positions.push_back(v1); - positions.push_back(v2); - positions.push_back(v3); - positions.push_back(v4); - positions.push_back(v1); - positions.push_back(v3); - - if (!bOpen) - { - // generate the end 'cap' - positions.push_back(aiVector3D(s * radius2, halfHeight, t * radius2 )); - positions.push_back(aiVector3D(s2 * radius2, halfHeight, t2 * radius2 )); - positions.push_back(aiVector3D(0.0, halfHeight, 0.0)); - - - if (radius1) - { - // generate the other end 'cap' - positions.push_back(aiVector3D(s * radius1, -halfHeight, t * radius1 )); - positions.push_back(aiVector3D(s2 * radius1, -halfHeight, t2 * radius1 )); - positions.push_back(aiVector3D(0.0, -halfHeight, 0.0)); - - } - } - s = s2; - t = t2; - angle = next; - } - - // Need to flip face order? - if ( SIZE_MAX != old ) { - for (size_t p = old; p < positions.size();p += 3) { - std::swap(positions[p],positions[p+1]); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Build a circle -void StandardShapes::MakeCircle(ai_real radius, unsigned int tess, - std::vector<aiVector3D>& positions) -{ - // Sorry, a circle with less than 3 segments makes ABSOLUTELY NO SENSE - if (tess < 3 || !radius) - return; - - radius = std::fabs(radius); - - // We will need 3 vertices per segment - positions.reserve(positions.size()+tess*3); - - const ai_real angle_delta = (ai_real)AI_MATH_TWO_PI / tess; - const ai_real angle_max = (ai_real)AI_MATH_TWO_PI; - - ai_real s = 1.0; // std::cos(angle == 0); - ai_real t = 0.0; // std::sin(angle == 0); - - for (ai_real angle = 0.0; angle < angle_max; ) - { - positions.push_back(aiVector3D(s * radius,0.0,t * radius)); - angle += angle_delta; - s = std::cos(angle); - t = std::sin(angle); - positions.push_back(aiVector3D(s * radius,0.0,t * radius)); - - positions.push_back(aiVector3D(0.0,0.0,0.0)); - } -} - -} // ! Assimp diff --git a/thirdparty/assimp/code/Common/StdOStreamLogStream.h b/thirdparty/assimp/code/Common/StdOStreamLogStream.h deleted file mode 100644 index 893e261a2b..0000000000 --- a/thirdparty/assimp/code/Common/StdOStreamLogStream.h +++ /dev/null @@ -1,101 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file StdOStreamLogStream.h -* @brief Implementation of StdOStreamLogStream -*/ - -#ifndef AI_STROSTREAMLOGSTREAM_H_INC -#define AI_STROSTREAMLOGSTREAM_H_INC - -#include <assimp/LogStream.hpp> -#include <ostream> - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** @class StdOStreamLogStream - * @brief Logs into a std::ostream - */ -class StdOStreamLogStream : public LogStream { -public: - /** @brief Construction from an existing std::ostream - * @param _ostream Output stream to be used - */ - explicit StdOStreamLogStream(std::ostream& _ostream); - - /** @brief Destructor */ - ~StdOStreamLogStream(); - - /** @brief Writer */ - void write(const char* message); - -private: - std::ostream& mOstream; -}; - -// --------------------------------------------------------------------------- -// Default constructor -inline StdOStreamLogStream::StdOStreamLogStream(std::ostream& _ostream) -: mOstream (_ostream){ - // empty -} - -// --------------------------------------------------------------------------- -// Default constructor -inline StdOStreamLogStream::~StdOStreamLogStream() { - // empty -} - -// --------------------------------------------------------------------------- -// Write method -inline void StdOStreamLogStream::write(const char* message) { - mOstream << message; - mOstream.flush(); -} - -// --------------------------------------------------------------------------- - -} // Namespace Assimp - -#endif // guard diff --git a/thirdparty/assimp/code/Common/Subdivision.cpp b/thirdparty/assimp/code/Common/Subdivision.cpp deleted file mode 100644 index 60c54939f5..0000000000 --- a/thirdparty/assimp/code/Common/Subdivision.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -#include <assimp/Subdivision.h> -#include <assimp/SceneCombiner.h> -#include <assimp/SpatialSort.h> -#include <assimp/Vertex.h> -#include <assimp/ai_assert.h> - -#include "PostProcessing/ProcessHelper.h" - -#include <stdio.h> - -using namespace Assimp; -void mydummy() {} - -// ------------------------------------------------------------------------------------------------ -/** Subdivider stub class to implement the Catmull-Clarke subdivision algorithm. The - * implementation is basing on recursive refinement. Directly evaluating the result is also - * possible and much quicker, but it depends on lengthy matrix lookup tables. */ -// ------------------------------------------------------------------------------------------------ -class CatmullClarkSubdivider : public Subdivider { -public: - void Subdivide (aiMesh* mesh, aiMesh*& out, unsigned int num, bool discard_input); - void Subdivide (aiMesh** smesh, size_t nmesh, - aiMesh** out, unsigned int num, bool discard_input); - - // --------------------------------------------------------------------------- - /** Intermediate description of an edge between two corners of a polygon*/ - // --------------------------------------------------------------------------- - struct Edge - { - Edge() - : ref(0) - {} - Vertex edge_point, midpoint; - unsigned int ref; - }; - - typedef std::vector<unsigned int> UIntVector; - typedef std::map<uint64_t,Edge> EdgeMap; - - // --------------------------------------------------------------------------- - // Hashing function to derive an index into an #EdgeMap from two given - // 'unsigned int' vertex coordinates (!!distinct coordinates - same - // vertex position == same index!!). - // NOTE - this leads to rare hash collisions if a) sizeof(unsigned int)>4 - // and (id[0]>2^32-1 or id[0]>2^32-1). - // MAKE_EDGE_HASH() uses temporaries, so INIT_EDGE_HASH() needs to be put - // at the head of every function which is about to use MAKE_EDGE_HASH(). - // Reason is that the hash is that hash construction needs to hold the - // invariant id0<id1 to identify an edge - else two hashes would refer - // to the same edge. - // --------------------------------------------------------------------------- -#define MAKE_EDGE_HASH(id0,id1) (eh_tmp0__=id0,eh_tmp1__=id1,\ - (eh_tmp0__<eh_tmp1__?std::swap(eh_tmp0__,eh_tmp1__):mydummy()),(uint64_t)eh_tmp0__^((uint64_t)eh_tmp1__<<32u)) - - -#define INIT_EDGE_HASH_TEMPORARIES()\ - unsigned int eh_tmp0__, eh_tmp1__; - -private: - void InternSubdivide (const aiMesh* const * smesh, - size_t nmesh,aiMesh** out, unsigned int num); -}; - - -// ------------------------------------------------------------------------------------------------ -// Construct a subdivider of a specific type -Subdivider* Subdivider::Create (Algorithm algo) -{ - switch (algo) - { - case CATMULL_CLARKE: - return new CatmullClarkSubdivider(); - }; - - ai_assert(false); - return NULL; // shouldn't happen -} - -// ------------------------------------------------------------------------------------------------ -// Call the Catmull Clark subdivision algorithm for one mesh -void CatmullClarkSubdivider::Subdivide ( - aiMesh* mesh, - aiMesh*& out, - unsigned int num, - bool discard_input - ) -{ - ai_assert(mesh != out); - - Subdivide(&mesh,1,&out,num,discard_input); -} - -// ------------------------------------------------------------------------------------------------ -// Call the Catmull Clark subdivision algorithm for multiple meshes -void CatmullClarkSubdivider::Subdivide ( - aiMesh** smesh, - size_t nmesh, - aiMesh** out, - unsigned int num, - bool discard_input - ) -{ - ai_assert( NULL != smesh ); - ai_assert( NULL != out ); - - // course, both regions may not overlap - ai_assert(smesh<out || smesh+nmesh>out+nmesh); - if (!num) { - // No subdivision at all. Need to copy all the meshes .. argh. - if (discard_input) { - for (size_t s = 0; s < nmesh; ++s) { - out[s] = smesh[s]; - smesh[s] = NULL; - } - } - else { - for (size_t s = 0; s < nmesh; ++s) { - SceneCombiner::Copy(out+s,smesh[s]); - } - } - return; - } - - std::vector<aiMesh*> inmeshes; - std::vector<aiMesh*> outmeshes; - std::vector<unsigned int> maptbl; - - inmeshes.reserve(nmesh); - outmeshes.reserve(nmesh); - maptbl.reserve(nmesh); - - // Remove pure line and point meshes from the working set to reduce the - // number of edge cases the subdivider is forced to deal with. Line and - // point meshes are simply passed through. - for (size_t s = 0; s < nmesh; ++s) { - aiMesh* i = smesh[s]; - // FIX - mPrimitiveTypes might not yet be initialized - if (i->mPrimitiveTypes && (i->mPrimitiveTypes & (aiPrimitiveType_LINE|aiPrimitiveType_POINT))==i->mPrimitiveTypes) { - ASSIMP_LOG_DEBUG("Catmull-Clark Subdivider: Skipping pure line/point mesh"); - - if (discard_input) { - out[s] = i; - smesh[s] = NULL; - } - else { - SceneCombiner::Copy(out+s,i); - } - continue; - } - - outmeshes.push_back(NULL);inmeshes.push_back(i); - maptbl.push_back(static_cast<unsigned int>(s)); - } - - // Do the actual subdivision on the preallocated storage. InternSubdivide - // *always* assumes that enough storage is available, it does not bother - // checking any ranges. - ai_assert(inmeshes.size()==outmeshes.size()&&inmeshes.size()==maptbl.size()); - if (inmeshes.empty()) { - ASSIMP_LOG_WARN("Catmull-Clark Subdivider: Pure point/line scene, I can't do anything"); - return; - } - InternSubdivide(&inmeshes.front(),inmeshes.size(),&outmeshes.front(),num); - for (unsigned int i = 0; i < maptbl.size(); ++i) { - ai_assert(nullptr != outmeshes[i]); - out[maptbl[i]] = outmeshes[i]; - } - - if (discard_input) { - for (size_t s = 0; s < nmesh; ++s) { - delete smesh[s]; - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Note - this is an implementation of the standard (recursive) Cm-Cl algorithm without further -// optimizations (except we're using some nice LUTs). A description of the algorithm can be found -// here: http://en.wikipedia.org/wiki/Catmull-Clark_subdivision_surface -// -// The code is mostly O(n), however parts are O(nlogn) which is therefore the algorithm's -// expected total runtime complexity. The implementation is able to work in-place on the same -// mesh arrays. Calling #InternSubdivide() directly is not encouraged. The code can operate -// in-place unless 'smesh' and 'out' are equal (no strange overlaps or reorderings). -// Previous data is replaced/deleted then. -// ------------------------------------------------------------------------------------------------ -void CatmullClarkSubdivider::InternSubdivide ( - const aiMesh* const * smesh, - size_t nmesh, - aiMesh** out, - unsigned int num - ) -{ - ai_assert(NULL != smesh && NULL != out); - INIT_EDGE_HASH_TEMPORARIES(); - - // no subdivision requested or end of recursive refinement - if (!num) { - return; - } - - UIntVector maptbl; - SpatialSort spatial; - - // --------------------------------------------------------------------- - // 0. Offset table to index all meshes continuously, generate a spatially - // sorted representation of all vertices in all meshes. - // --------------------------------------------------------------------- - typedef std::pair<unsigned int,unsigned int> IntPair; - std::vector<IntPair> moffsets(nmesh); - unsigned int totfaces = 0, totvert = 0; - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* mesh = smesh[t]; - - spatial.Append(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D),false); - moffsets[t] = IntPair(totfaces,totvert); - - totfaces += mesh->mNumFaces; - totvert += mesh->mNumVertices; - } - - spatial.Finalize(); - const unsigned int num_unique = spatial.GenerateMappingTable(maptbl,ComputePositionEpsilon(smesh,nmesh)); - - -#define FLATTEN_VERTEX_IDX(mesh_idx, vert_idx) (moffsets[mesh_idx].second+vert_idx) -#define FLATTEN_FACE_IDX(mesh_idx, face_idx) (moffsets[mesh_idx].first+face_idx) - - // --------------------------------------------------------------------- - // 1. Compute the centroid point for all faces - // --------------------------------------------------------------------- - std::vector<Vertex> centroids(totfaces); - unsigned int nfacesout = 0; - for (size_t t = 0, n = 0; t < nmesh; ++t) { - const aiMesh* mesh = smesh[t]; - for (unsigned int i = 0; i < mesh->mNumFaces;++i,++n) - { - const aiFace& face = mesh->mFaces[i]; - Vertex& c = centroids[n]; - - for (unsigned int a = 0; a < face.mNumIndices;++a) { - c += Vertex(mesh,face.mIndices[a]); - } - - c /= static_cast<float>(face.mNumIndices); - nfacesout += face.mNumIndices; - } - } - - { - // we want edges to go away before the recursive calls so begin a new scope - EdgeMap edges; - - // --------------------------------------------------------------------- - // 2. Set each edge point to be the average of all neighbouring - // face points and original points. Every edge exists twice - // if there is a neighboring face. - // --------------------------------------------------------------------- - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* mesh = smesh[t]; - - for (unsigned int i = 0; i < mesh->mNumFaces;++i) { - const aiFace& face = mesh->mFaces[i]; - - for (unsigned int p =0; p< face.mNumIndices; ++p) { - const unsigned int id[] = { - face.mIndices[p], - face.mIndices[p==face.mNumIndices-1?0:p+1] - }; - const unsigned int mp[] = { - maptbl[FLATTEN_VERTEX_IDX(t,id[0])], - maptbl[FLATTEN_VERTEX_IDX(t,id[1])] - }; - - Edge& e = edges[MAKE_EDGE_HASH(mp[0],mp[1])]; - e.ref++; - if (e.ref<=2) { - if (e.ref==1) { // original points (end points) - add only once - e.edge_point = e.midpoint = Vertex(mesh,id[0])+Vertex(mesh,id[1]); - e.midpoint *= 0.5f; - } - e.edge_point += centroids[FLATTEN_FACE_IDX(t,i)]; - } - } - } - } - - // --------------------------------------------------------------------- - // 3. Normalize edge points - // --------------------------------------------------------------------- - {unsigned int bad_cnt = 0; - for (EdgeMap::iterator it = edges.begin(); it != edges.end(); ++it) { - if ((*it).second.ref < 2) { - ai_assert((*it).second.ref); - ++bad_cnt; - } - (*it).second.edge_point *= 1.f/((*it).second.ref+2.f); - } - - if (bad_cnt) { - // Report the number of bad edges. bad edges are referenced by less than two - // faces in the mesh. They occur at outer model boundaries in non-closed - // shapes. - ASSIMP_LOG_DEBUG_F("Catmull-Clark Subdivider: got ", bad_cnt, " bad edges touching only one face (totally ", - static_cast<unsigned int>(edges.size()), " edges). "); - }} - - // --------------------------------------------------------------------- - // 4. Compute a vertex-face adjacency table. We can't reuse the code - // from VertexTriangleAdjacency because we need the table for multiple - // meshes and out vertex indices need to be mapped to distinct values - // first. - // --------------------------------------------------------------------- - UIntVector faceadjac(nfacesout), cntadjfac(maptbl.size(),0), ofsadjvec(maptbl.size()+1,0); { - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* const minp = smesh[t]; - for (unsigned int i = 0; i < minp->mNumFaces; ++i) { - - const aiFace& f = minp->mFaces[i]; - for (unsigned int n = 0; n < f.mNumIndices; ++n) { - ++cntadjfac[maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]]; - } - } - } - unsigned int cur = 0; - for (size_t i = 0; i < cntadjfac.size(); ++i) { - ofsadjvec[i+1] = cur; - cur += cntadjfac[i]; - } - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* const minp = smesh[t]; - for (unsigned int i = 0; i < minp->mNumFaces; ++i) { - - const aiFace& f = minp->mFaces[i]; - for (unsigned int n = 0; n < f.mNumIndices; ++n) { - faceadjac[ofsadjvec[1+maptbl[FLATTEN_VERTEX_IDX(t,f.mIndices[n])]]++] = FLATTEN_FACE_IDX(t,i); - } - } - } - - // check the other way round for consistency -#ifdef ASSIMP_BUILD_DEBUG - - for (size_t t = 0; t < ofsadjvec.size()-1; ++t) { - for (unsigned int m = 0; m < cntadjfac[t]; ++m) { - const unsigned int fidx = faceadjac[ofsadjvec[t]+m]; - ai_assert(fidx < totfaces); - for (size_t n = 1; n < nmesh; ++n) { - - if (moffsets[n].first > fidx) { - const aiMesh* msh = smesh[--n]; - const aiFace& f = msh->mFaces[fidx-moffsets[n].first]; - - bool haveit = false; - for (unsigned int i = 0; i < f.mNumIndices; ++i) { - if (maptbl[FLATTEN_VERTEX_IDX(n,f.mIndices[i])]==(unsigned int)t) { - haveit = true; - break; - } - } - ai_assert(haveit); - if (!haveit) { - ASSIMP_LOG_DEBUG("Catmull-Clark Subdivider: Index not used"); - } - break; - } - } - } - } - -#endif - } - -#define GET_ADJACENT_FACES_AND_CNT(vidx,fstartout,numout) \ - fstartout = &faceadjac[ofsadjvec[vidx]], numout = cntadjfac[vidx] - - typedef std::pair<bool,Vertex> TouchedOVertex; - std::vector<TouchedOVertex > new_points(num_unique,TouchedOVertex(false,Vertex())); - // --------------------------------------------------------------------- - // 5. Spawn a quad from each face point to the corresponding edge points - // the original points being the fourth quad points. - // --------------------------------------------------------------------- - for (size_t t = 0; t < nmesh; ++t) { - const aiMesh* const minp = smesh[t]; - aiMesh* const mout = out[t] = new aiMesh(); - - for (unsigned int a = 0; a < minp->mNumFaces; ++a) { - mout->mNumFaces += minp->mFaces[a].mNumIndices; - } - - // We need random access to the old face buffer, so reuse is not possible. - mout->mFaces = new aiFace[mout->mNumFaces]; - - mout->mNumVertices = mout->mNumFaces*4; - mout->mVertices = new aiVector3D[mout->mNumVertices]; - - // quads only, keep material index - mout->mPrimitiveTypes = aiPrimitiveType_POLYGON; - mout->mMaterialIndex = minp->mMaterialIndex; - - if (minp->HasNormals()) { - mout->mNormals = new aiVector3D[mout->mNumVertices]; - } - - if (minp->HasTangentsAndBitangents()) { - mout->mTangents = new aiVector3D[mout->mNumVertices]; - mout->mBitangents = new aiVector3D[mout->mNumVertices]; - } - - for(unsigned int i = 0; minp->HasTextureCoords(i); ++i) { - mout->mTextureCoords[i] = new aiVector3D[mout->mNumVertices]; - mout->mNumUVComponents[i] = minp->mNumUVComponents[i]; - } - - for(unsigned int i = 0; minp->HasVertexColors(i); ++i) { - mout->mColors[i] = new aiColor4D[mout->mNumVertices]; - } - - mout->mNumVertices = mout->mNumFaces<<2u; - for (unsigned int i = 0, v = 0, n = 0; i < minp->mNumFaces;++i) { - - const aiFace& face = minp->mFaces[i]; - for (unsigned int a = 0; a < face.mNumIndices;++a) { - - // Get a clean new face. - aiFace& faceOut = mout->mFaces[n++]; - faceOut.mIndices = new unsigned int [faceOut.mNumIndices = 4]; - - // Spawn a new quadrilateral (ccw winding) for this original point between: - // a) face centroid - centroids[FLATTEN_FACE_IDX(t,i)].SortBack(mout,faceOut.mIndices[0]=v++); - - // b) adjacent edge on the left, seen from the centroid - const Edge& e0 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])], - maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a==face.mNumIndices-1?0:a+1]) - ])]; // fixme: replace with mod face.mNumIndices? - - // c) adjacent edge on the right, seen from the centroid - const Edge& e1 = edges[MAKE_EDGE_HASH(maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])], - maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[!a?face.mNumIndices-1:a-1]) - ])]; // fixme: replace with mod face.mNumIndices? - - e0.edge_point.SortBack(mout,faceOut.mIndices[3]=v++); - e1.edge_point.SortBack(mout,faceOut.mIndices[1]=v++); - - // d= original point P with distinct index i - // F := 0 - // R := 0 - // n := 0 - // for each face f containing i - // F := F+ centroid of f - // R := R+ midpoint of edge of f from i to i+1 - // n := n+1 - // - // (F+2R+(n-3)P)/n - const unsigned int org = maptbl[FLATTEN_VERTEX_IDX(t,face.mIndices[a])]; - TouchedOVertex& ov = new_points[org]; - - if (!ov.first) { - ov.first = true; - - const unsigned int* adj; unsigned int cnt; - GET_ADJACENT_FACES_AND_CNT(org,adj,cnt); - - if (cnt < 3) { - ov.second = Vertex(minp,face.mIndices[a]); - } - else { - - Vertex F,R; - for (unsigned int o = 0; o < cnt; ++o) { - ai_assert(adj[o] < totfaces); - F += centroids[adj[o]]; - - // adj[0] is a global face index - search the face in the mesh list - const aiMesh* mp = NULL; - size_t nidx; - - if (adj[o] < moffsets[0].first) { - mp = smesh[nidx=0]; - } - else { - for (nidx = 1; nidx<= nmesh; ++nidx) { - if (nidx == nmesh ||moffsets[nidx].first > adj[o]) { - mp = smesh[--nidx]; - break; - } - } - } - - ai_assert(adj[o]-moffsets[nidx].first < mp->mNumFaces); - const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first]; - bool haveit = false; - - // find our original point in the face - for (unsigned int m = 0; m < f.mNumIndices; ++m) { - if (maptbl[FLATTEN_VERTEX_IDX(nidx,f.mIndices[m])] == org) { - - // add *both* edges. this way, we can be sure that we add - // *all* adjacent edges to R. In a closed shape, every - // edge is added twice - so we simply leave out the - // factor 2.f in the amove formula and get the right - // result. - - const Edge& c0 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX( - nidx,f.mIndices[!m?f.mNumIndices-1:m-1])])]; - // fixme: replace with mod face.mNumIndices? - - const Edge& c1 = edges[MAKE_EDGE_HASH(org,maptbl[FLATTEN_VERTEX_IDX( - nidx,f.mIndices[m==f.mNumIndices-1?0:m+1])])]; - // fixme: replace with mod face.mNumIndices? - R += c0.midpoint+c1.midpoint; - - haveit = true; - break; - } - } - - // this invariant *must* hold if the vertex-to-face adjacency table is valid - ai_assert(haveit); - if ( !haveit ) { - ASSIMP_LOG_WARN( "OBJ: no name for material library specified." ); - } - } - - const float div = static_cast<float>(cnt), divsq = 1.f/(div*div); - ov.second = Vertex(minp,face.mIndices[a])*((div-3.f) / div) + R*divsq + F*divsq; - } - } - ov.second.SortBack(mout,faceOut.mIndices[2]=v++); - } - } - } - } // end of scope for edges, freeing its memory - - // --------------------------------------------------------------------- - // 7. Apply the next subdivision step. - // --------------------------------------------------------------------- - if (num != 1) { - std::vector<aiMesh*> tmp(nmesh); - InternSubdivide (out,nmesh,&tmp.front(),num-1); - for (size_t i = 0; i < nmesh; ++i) { - delete out[i]; - out[i] = tmp[i]; - } - } -} diff --git a/thirdparty/assimp/code/Common/TargetAnimation.cpp b/thirdparty/assimp/code/Common/TargetAnimation.cpp deleted file mode 100644 index b8062499ff..0000000000 --- a/thirdparty/assimp/code/Common/TargetAnimation.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -#include "TargetAnimation.h" -#include <algorithm> -#include <assimp/ai_assert.h> - -using namespace Assimp; - - -// ------------------------------------------------------------------------------------------------ -KeyIterator::KeyIterator(const std::vector<aiVectorKey>* _objPos, - const std::vector<aiVectorKey>* _targetObjPos, - const aiVector3D* defaultObjectPos /*= NULL*/, - const aiVector3D* defaultTargetPos /*= NULL*/) - - : reachedEnd (false) - , curTime (-1.) - , objPos (_objPos) - , targetObjPos (_targetObjPos) - , nextObjPos (0) - , nextTargetObjPos(0) -{ - // Generate default transformation tracks if necessary - if (!objPos || objPos->empty()) - { - defaultObjPos.resize(1); - defaultObjPos.front().mTime = 10e10; - - if (defaultObjectPos) - defaultObjPos.front().mValue = *defaultObjectPos; - - objPos = & defaultObjPos; - } - if (!targetObjPos || targetObjPos->empty()) - { - defaultTargetObjPos.resize(1); - defaultTargetObjPos.front().mTime = 10e10; - - if (defaultTargetPos) - defaultTargetObjPos.front().mValue = *defaultTargetPos; - - targetObjPos = & defaultTargetObjPos; - } -} - -// ------------------------------------------------------------------------------------------------ -template <class T> -inline T Interpolate(const T& one, const T& two, ai_real val) -{ - return one + (two-one)*val; -} - -// ------------------------------------------------------------------------------------------------ -void KeyIterator::operator ++() -{ - // If we are already at the end of all keyframes, return - if (reachedEnd) { - return; - } - - // Now search in all arrays for the time value closest - // to our current position on the time line - double d0,d1; - - d0 = objPos->at ( std::min ( nextObjPos, static_cast<unsigned int>(objPos->size()-1)) ).mTime; - d1 = targetObjPos->at( std::min ( nextTargetObjPos, static_cast<unsigned int>(targetObjPos->size()-1)) ).mTime; - - // Easiest case - all are identical. In this - // case we don't need to interpolate so we can - // return earlier - if ( d0 == d1 ) - { - curTime = d0; - curPosition = objPos->at(nextObjPos).mValue; - curTargetPosition = targetObjPos->at(nextTargetObjPos).mValue; - - // increment counters - if (objPos->size() != nextObjPos-1) - ++nextObjPos; - - if (targetObjPos->size() != nextTargetObjPos-1) - ++nextTargetObjPos; - } - - // An object position key is closest to us - else if (d0 < d1) - { - curTime = d0; - - // interpolate the other - if (1 == targetObjPos->size() || !nextTargetObjPos) { - curTargetPosition = targetObjPos->at(0).mValue; - } - else - { - const aiVectorKey& last = targetObjPos->at(nextTargetObjPos); - const aiVectorKey& first = targetObjPos->at(nextTargetObjPos-1); - - curTargetPosition = Interpolate(first.mValue, last.mValue, (ai_real) ( - (curTime-first.mTime) / (last.mTime-first.mTime) )); - } - - if (objPos->size() != nextObjPos-1) - ++nextObjPos; - } - // A target position key is closest to us - else - { - curTime = d1; - - // interpolate the other - if (1 == objPos->size() || !nextObjPos) { - curPosition = objPos->at(0).mValue; - } - else - { - const aiVectorKey& last = objPos->at(nextObjPos); - const aiVectorKey& first = objPos->at(nextObjPos-1); - - curPosition = Interpolate(first.mValue, last.mValue, (ai_real) ( - (curTime-first.mTime) / (last.mTime-first.mTime))); - } - - if (targetObjPos->size() != nextTargetObjPos-1) - ++nextTargetObjPos; - } - - if (nextObjPos >= objPos->size()-1 && - nextTargetObjPos >= targetObjPos->size()-1) - { - // We reached the very last keyframe - reachedEnd = true; - } -} - -// ------------------------------------------------------------------------------------------------ -void TargetAnimationHelper::SetTargetAnimationChannel ( - const std::vector<aiVectorKey>* _targetPositions) -{ - ai_assert(NULL != _targetPositions); - targetPositions = _targetPositions; -} - -// ------------------------------------------------------------------------------------------------ -void TargetAnimationHelper::SetMainAnimationChannel ( - const std::vector<aiVectorKey>* _objectPositions) -{ - ai_assert(NULL != _objectPositions); - objectPositions = _objectPositions; -} - -// ------------------------------------------------------------------------------------------------ -void TargetAnimationHelper::SetFixedMainAnimationChannel( - const aiVector3D& fixed) -{ - objectPositions = NULL; // just to avoid confusion - fixedMain = fixed; -} - -// ------------------------------------------------------------------------------------------------ -void TargetAnimationHelper::Process(std::vector<aiVectorKey>* distanceTrack) -{ - ai_assert(NULL != targetPositions && NULL != distanceTrack); - - // TODO: in most cases we won't need the extra array - std::vector<aiVectorKey> real; - - std::vector<aiVectorKey>* fill = (distanceTrack == objectPositions ? &real : distanceTrack); - fill->reserve(std::max( objectPositions->size(), targetPositions->size() )); - - // Iterate through all object keys and interpolate their values if necessary. - // Then get the corresponding target position, compute the difference - // vector between object and target position. Then compute a rotation matrix - // that rotates the base vector of the object coordinate system at that time - // to match the diff vector. - - KeyIterator iter(objectPositions,targetPositions,&fixedMain); - for (;!iter.Finished();++iter) - { - const aiVector3D& position = iter.GetCurPosition(); - const aiVector3D& tposition = iter.GetCurTargetPosition(); - - // diff vector - aiVector3D diff = tposition - position; - ai_real f = diff.Length(); - - // output distance vector - if (f) - { - fill->push_back(aiVectorKey()); - aiVectorKey& v = fill->back(); - v.mTime = iter.GetCurTime(); - v.mValue = diff; - - diff /= f; - } - else - { - // FIXME: handle this - } - - // diff is now the vector in which our camera is pointing - } - - if (real.size()) { - *distanceTrack = real; - } -} diff --git a/thirdparty/assimp/code/Common/TargetAnimation.h b/thirdparty/assimp/code/Common/TargetAnimation.h deleted file mode 100644 index 91634ab5aa..0000000000 --- a/thirdparty/assimp/code/Common/TargetAnimation.h +++ /dev/null @@ -1,183 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a helper class for the ASE and 3DS loaders to - help them compute camera and spot light animation channels */ -#ifndef AI_TARGET_ANIMATION_H_INC -#define AI_TARGET_ANIMATION_H_INC - -#include <assimp/anim.h> -#include <vector> - -namespace Assimp { - - - -// --------------------------------------------------------------------------- -/** Helper class to iterate through all keys in an animation channel. - * - * Missing tracks are interpolated. This is a helper class for - * TargetAnimationHelper, but it can be freely used for other purposes. -*/ -class KeyIterator -{ -public: - - - // ------------------------------------------------------------------ - /** Constructs a new key iterator - * - * @param _objPos Object position track. May be NULL. - * @param _targetObjPos Target object position track. May be NULL. - * @param defaultObjectPos Default object position to be used if - * no animated track is available. May be NULL. - * @param defaultTargetPos Default target position to be used if - * no animated track is available. May be NULL. - */ - KeyIterator(const std::vector<aiVectorKey>* _objPos, - const std::vector<aiVectorKey>* _targetObjPos, - const aiVector3D* defaultObjectPos = NULL, - const aiVector3D* defaultTargetPos = NULL); - - // ------------------------------------------------------------------ - /** Returns true if all keys have been processed - */ - bool Finished() const - {return reachedEnd;} - - // ------------------------------------------------------------------ - /** Increment the iterator - */ - void operator++(); - inline void operator++(int) - {return ++(*this);} - - - - // ------------------------------------------------------------------ - /** Getters to retrieve the current state of the iterator - */ - inline const aiVector3D& GetCurPosition() const - {return curPosition;} - - inline const aiVector3D& GetCurTargetPosition() const - {return curTargetPosition;} - - inline double GetCurTime() const - {return curTime;} - -private: - - //! Did we reach the end? - bool reachedEnd; - - //! Represents the current position of the iterator - aiVector3D curPosition, curTargetPosition; - - double curTime; - - //! Input tracks and the next key to process - const std::vector<aiVectorKey>* objPos,*targetObjPos; - - unsigned int nextObjPos, nextTargetObjPos; - std::vector<aiVectorKey> defaultObjPos,defaultTargetObjPos; -}; - -// --------------------------------------------------------------------------- -/** Helper class for the 3DS and ASE loaders to compute camera and spot light - * animations. - * - * 3DS and ASE store the differently to Assimp - there is an animation - * channel for the camera/spot light itself and a separate position - * animation channels specifying the position of the camera/spot light - * look-at target */ -class TargetAnimationHelper -{ -public: - - TargetAnimationHelper() - : targetPositions (NULL) - , objectPositions (NULL) - {} - - - // ------------------------------------------------------------------ - /** Sets the target animation channel - * - * This channel specifies the position of the camera/spot light - * target at a specific position. - * - * @param targetPositions Translation channel*/ - void SetTargetAnimationChannel (const - std::vector<aiVectorKey>* targetPositions); - - - // ------------------------------------------------------------------ - /** Sets the main animation channel - * - * @param objectPositions Translation channel */ - void SetMainAnimationChannel ( const - std::vector<aiVectorKey>* objectPositions); - - // ------------------------------------------------------------------ - /** Sets the main animation channel to a fixed value - * - * @param fixed Fixed value for the main animation channel*/ - void SetFixedMainAnimationChannel(const aiVector3D& fixed); - - - // ------------------------------------------------------------------ - /** Computes final animation channels - * @param distanceTrack Receive camera translation keys ... != NULL. */ - void Process( std::vector<aiVectorKey>* distanceTrack ); - - -private: - - const std::vector<aiVectorKey>* targetPositions,*objectPositions; - aiVector3D fixedMain; -}; - - -} // ! end namespace Assimp - -#endif // include guard diff --git a/thirdparty/assimp/code/Common/Version.cpp b/thirdparty/assimp/code/Common/Version.cpp deleted file mode 100644 index cf1da7d5ba..0000000000 --- a/thirdparty/assimp/code/Common/Version.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -// Actually just a dummy, used by the compiler to build the precompiled header. - -#include <assimp/version.h> -#include <assimp/scene.h> -#include "ScenePrivate.h" - -#include "revision.h" - -// -------------------------------------------------------------------------------- -// Legal information string - don't remove this. -static const char* LEGAL_INFORMATION = - -"Open Asset Import Library (Assimp).\n" -"A free C/C++ library to import various 3D file formats into applications\n\n" - -"(c) 2006-2019, assimp team\n" -"License under the terms and conditions of the 3-clause BSD license\n" -"http://assimp.org\n" -; - -// ------------------------------------------------------------------------------------------------ -// Get legal string -ASSIMP_API const char* aiGetLegalString () { - return LEGAL_INFORMATION; -} - -// ------------------------------------------------------------------------------------------------ -// Get Assimp minor version -ASSIMP_API unsigned int aiGetVersionMinor () { - return VER_MINOR; -} - -// ------------------------------------------------------------------------------------------------ -// Get Assimp major version -ASSIMP_API unsigned int aiGetVersionMajor () { - return VER_MAJOR; -} - -// ------------------------------------------------------------------------------------------------ -// Get flags used for compilation -ASSIMP_API unsigned int aiGetCompileFlags () { - - unsigned int flags = 0; - -#ifdef ASSIMP_BUILD_BOOST_WORKAROUND - flags |= ASSIMP_CFLAGS_NOBOOST; -#endif -#ifdef ASSIMP_BUILD_SINGLETHREADED - flags |= ASSIMP_CFLAGS_SINGLETHREADED; -#endif -#ifdef ASSIMP_BUILD_DEBUG - flags |= ASSIMP_CFLAGS_DEBUG; -#endif -#ifdef ASSIMP_BUILD_DLL_EXPORT - flags |= ASSIMP_CFLAGS_SHARED; -#endif -#ifdef _STLPORT_VERSION - flags |= ASSIMP_CFLAGS_STLPORT; -#endif - - return flags; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API unsigned int aiGetVersionRevision() { - return GitVersion; -} - -ASSIMP_API const char *aiGetBranchName() { - return GitBranch; -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiScene::aiScene() -: mFlags(0) -, mRootNode(nullptr) -, mNumMeshes(0) -, mMeshes(nullptr) -, mNumMaterials(0) -, mMaterials(nullptr) -, mNumAnimations(0) -, mAnimations(nullptr) -, mNumTextures(0) -, mTextures(nullptr) -, mNumLights(0) -, mLights(nullptr) -, mNumCameras(0) -, mCameras(nullptr) -, mMetaData(nullptr) -, mPrivate(new Assimp::ScenePrivateData()) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -ASSIMP_API aiScene::~aiScene() { - // delete all sub-objects recursively - delete mRootNode; - - // To make sure we won't crash if the data is invalid it's - // much better to check whether both mNumXXX and mXXX are - // valid instead of relying on just one of them. - if (mNumMeshes && mMeshes) - for( unsigned int a = 0; a < mNumMeshes; a++) - delete mMeshes[a]; - delete [] mMeshes; - - if (mNumMaterials && mMaterials) { - for (unsigned int a = 0; a < mNumMaterials; ++a ) { - delete mMaterials[ a ]; - } - } - delete [] mMaterials; - - if (mNumAnimations && mAnimations) - for( unsigned int a = 0; a < mNumAnimations; a++) - delete mAnimations[a]; - delete [] mAnimations; - - if (mNumTextures && mTextures) - for( unsigned int a = 0; a < mNumTextures; a++) - delete mTextures[a]; - delete [] mTextures; - - if (mNumLights && mLights) - for( unsigned int a = 0; a < mNumLights; a++) - delete mLights[a]; - delete [] mLights; - - if (mNumCameras && mCameras) - for( unsigned int a = 0; a < mNumCameras; a++) - delete mCameras[a]; - delete [] mCameras; - - aiMetadata::Dealloc(mMetaData); - mMetaData = nullptr; - - delete static_cast<Assimp::ScenePrivateData*>( mPrivate ); -} - diff --git a/thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp b/thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp deleted file mode 100644 index 7cfd1a3505..0000000000 --- a/thirdparty/assimp/code/Common/VertexTriangleAdjacency.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the VertexTriangleAdjacency helper class - */ - -// internal headers -#include "VertexTriangleAdjacency.h" -#include <assimp/mesh.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces, - unsigned int iNumFaces, - unsigned int iNumVertices /*= 0*/, - bool bComputeNumTriangles /*= false*/) -{ - // compute the number of referenced vertices if it wasn't specified by the caller - const aiFace* const pcFaceEnd = pcFaces + iNumFaces; - if (!iNumVertices) { - for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) { - ai_assert( nullptr != pcFace ); - ai_assert(3 == pcFace->mNumIndices); - iNumVertices = std::max(iNumVertices,pcFace->mIndices[0]); - iNumVertices = std::max(iNumVertices,pcFace->mIndices[1]); - iNumVertices = std::max(iNumVertices,pcFace->mIndices[2]); - } - } - - mNumVertices = iNumVertices; - - unsigned int* pi; - - // allocate storage - if (bComputeNumTriangles) { - pi = mLiveTriangles = new unsigned int[iNumVertices+1]; - ::memset(mLiveTriangles,0,sizeof(unsigned int)*(iNumVertices+1)); - mOffsetTable = new unsigned int[iNumVertices+2]+1; - } else { - pi = mOffsetTable = new unsigned int[iNumVertices+2]+1; - ::memset(mOffsetTable,0,sizeof(unsigned int)*(iNumVertices+1)); - mLiveTriangles = NULL; // important, otherwise the d'tor would crash - } - - // get a pointer to the end of the buffer - unsigned int* piEnd = pi+iNumVertices; - *piEnd++ = 0u; - - // first pass: compute the number of faces referencing each vertex - for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) - { - unsigned nind = pcFace->mNumIndices; - unsigned * ind = pcFace->mIndices; - if (nind > 0) pi[ind[0]]++; - if (nind > 1) pi[ind[1]]++; - if (nind > 2) pi[ind[2]]++; - } - - // second pass: compute the final offset table - unsigned int iSum = 0; - unsigned int* piCurOut = this->mOffsetTable; - for (unsigned int* piCur = pi; piCur != piEnd;++piCur,++piCurOut) { - - unsigned int iLastSum = iSum; - iSum += *piCur; - *piCurOut = iLastSum; - } - pi = this->mOffsetTable; - - // third pass: compute the final table - this->mAdjacencyTable = new unsigned int[iSum]; - iSum = 0; - for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace,++iSum) { - unsigned nind = pcFace->mNumIndices; - unsigned * ind = pcFace->mIndices; - - if (nind > 0) mAdjacencyTable[pi[ind[0]]++] = iSum; - if (nind > 1) mAdjacencyTable[pi[ind[1]]++] = iSum; - if (nind > 2) mAdjacencyTable[pi[ind[2]]++] = iSum; - } - // fourth pass: undo the offset computations made during the third pass - // We could do this in a separate buffer, but this would be TIMES slower. - --mOffsetTable; - *mOffsetTable = 0u; -} -// ------------------------------------------------------------------------------------------------ -VertexTriangleAdjacency::~VertexTriangleAdjacency() -{ - // delete allocated storage - delete[] mOffsetTable; - delete[] mAdjacencyTable; - delete[] mLiveTriangles; -} diff --git a/thirdparty/assimp/code/Common/VertexTriangleAdjacency.h b/thirdparty/assimp/code/Common/VertexTriangleAdjacency.h deleted file mode 100644 index f3be47612d..0000000000 --- a/thirdparty/assimp/code/Common/VertexTriangleAdjacency.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a helper class to compute a vertex-triangle adjacency map */ -#ifndef AI_VTADJACENCY_H_INC -#define AI_VTADJACENCY_H_INC - -#include "BaseProcess.h" -#include <assimp/types.h> -#include <assimp/ai_assert.h> - -struct aiMesh; -struct aiFace; - -namespace Assimp { - -// -------------------------------------------------------------------------------------------- -/** @brief The VertexTriangleAdjacency class computes a vertex-triangle - * adjacency map from a given index buffer. - * - * @note Although it is called #VertexTriangleAdjacency, the current version does also - * support arbitrary polygons. */ -// -------------------------------------------------------------------------------------------- -class ASSIMP_API VertexTriangleAdjacency { -public: - // ---------------------------------------------------------------------------- - /** @brief Construction from an existing index buffer - * @param pcFaces Index buffer - * @param iNumFaces Number of faces in the buffer - * @param iNumVertices Number of referenced vertices. This value - * is computed automatically if 0 is specified. - * @param bComputeNumTriangles If you want the class to compute - * a list containing the number of referenced triangles per vertex - * per vertex - pass true. */ - VertexTriangleAdjacency(aiFace* pcFaces,unsigned int iNumFaces, - unsigned int iNumVertices = 0, - bool bComputeNumTriangles = true); - - // ---------------------------------------------------------------------------- - /** @brief Destructor */ - ~VertexTriangleAdjacency(); - - // ---------------------------------------------------------------------------- - /** @brief Get all triangles adjacent to a vertex - * @param iVertIndex Index of the vertex - * @return A pointer to the adjacency list. */ - unsigned int* GetAdjacentTriangles(unsigned int iVertIndex) const { - ai_assert(iVertIndex < mNumVertices); - return &mAdjacencyTable[ mOffsetTable[iVertIndex]]; - } - - // ---------------------------------------------------------------------------- - /** @brief Get the number of triangles that are referenced by - * a vertex. This function returns a reference that can be modified - * @param iVertIndex Index of the vertex - * @return Number of referenced triangles */ - unsigned int& GetNumTrianglesPtr(unsigned int iVertIndex) { - ai_assert( iVertIndex < mNumVertices ); - ai_assert( nullptr != mLiveTriangles ); - return mLiveTriangles[iVertIndex]; - } - - //! Offset table - unsigned int* mOffsetTable; - - //! Adjacency table - unsigned int* mAdjacencyTable; - - //! Table containing the number of referenced triangles per vertex - unsigned int* mLiveTriangles; - - //! Debug: Number of referenced vertices - unsigned int mNumVertices; -}; - -} //! ns Assimp - -#endif // !! AI_VTADJACENCY_H_INC diff --git a/thirdparty/assimp/code/Common/Win32DebugLogStream.h b/thirdparty/assimp/code/Common/Win32DebugLogStream.h deleted file mode 100644 index a6063a261e..0000000000 --- a/thirdparty/assimp/code/Common/Win32DebugLogStream.h +++ /dev/null @@ -1,95 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Win32DebugLogStream.h -* @brief Implementation of Win32DebugLogStream -*/ -#ifndef AI_WIN32DEBUGLOGSTREAM_H_INC -#define AI_WIN32DEBUGLOGSTREAM_H_INC - -#ifdef _WIN32 - -#include <assimp/LogStream.hpp> -#include "windows.h" - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** @class Win32DebugLogStream - * @brief Logs into the debug stream from win32. - */ -class Win32DebugLogStream : public LogStream { -public: - /** @brief Default constructor */ - Win32DebugLogStream(); - - /** @brief Destructor */ - ~Win32DebugLogStream(); - - /** @brief Writer */ - void write(const char* messgae); -}; - -// --------------------------------------------------------------------------- -inline -Win32DebugLogStream::Win32DebugLogStream(){ - // empty -} - -// --------------------------------------------------------------------------- -inline -Win32DebugLogStream::~Win32DebugLogStream(){ - // empty -} - -// --------------------------------------------------------------------------- -inline -void Win32DebugLogStream::write(const char* message) { - ::OutputDebugStringA( message); -} - -// --------------------------------------------------------------------------- -} // Namespace Assimp - -#endif // ! _WIN32 -#endif // guard diff --git a/thirdparty/assimp/code/Common/assbin_chunks.h b/thirdparty/assimp/code/Common/assbin_chunks.h deleted file mode 100644 index 15e4af5e7d..0000000000 --- a/thirdparty/assimp/code/Common/assbin_chunks.h +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef INCLUDED_ASSBIN_CHUNKS_H -#define INCLUDED_ASSBIN_CHUNKS_H - -#define ASSBIN_VERSION_MAJOR 1 -#define ASSBIN_VERSION_MINOR 0 - -/** -@page assfile .ASS File formats - -@section over Overview -Assimp provides its own interchange format, which is intended to applications which need -to serialize 3D-models and to reload them quickly. Assimp's file formats are designed to -be read by Assimp itself. They encode additional information needed by Assimp to optimize -its postprocessing pipeline. If you once apply specific steps to a scene, then save it -and reread it from an ASS format using the same post processing settings, they won't -be executed again. - -The format comes in two flavours: XML and binary - both of them hold a complete dump of -the 'aiScene' data structure returned by the APIs. The focus for the binary format -(<tt>.assbin</tt>) is fast loading. Optional deflate compression helps reduce file size. The XML -flavour, <tt>.assxml</tt> or simply .xml, is just a plain-to-xml conversion of aiScene. - -ASSBIN is Assimp's binary interchange format. assimp_cmd (<tt><root>/tools/assimp_cmd</tt>) is able to -write it and the core library provides a loader for it. - -@section assxml XML File format - -The format is pretty much self-explanatory due to its similarity to the in-memory aiScene structure. -With few exceptions, C structures are wrapped in XML elements. - -The DTD for ASSXML can be found in <tt><root>/doc/AssXML_Scheme.xml</tt>. Or have look -at the output files generated by assimp_cmd. - -@section assbin Binary file format - -The ASSBIN file format is composed of chunks to represent the hierarchical aiScene data structure. -This makes the format extensible and allows backward-compatibility with future data structure -versions. The <tt><root>/code/assbin_chunks.h</tt> header contains some magic constants -for use by stand-alone ASSBIN loaders. Also, Assimp's own file writer can be found -in <tt><root>/tools/assimp_cmd/WriteDumb.cpp</tt> (yes, the 'b' is no typo ...). - -@verbatim - -------------------------------------------------------------------------------- -1. File structure: -------------------------------------------------------------------------------- - ----------------------- -| Header (512 bytes) | ----------------------- -| Variable chunks | ----------------------- - -------------------------------------------------------------------------------- -2. Definitions: -------------------------------------------------------------------------------- - -integer is four bytes wide, stored in little-endian byte order. -short is two bytes wide, stored in little-endian byte order. -byte is a single byte. -string is an integer n followed by n UTF-8 characters, not terminated by zero -float is an IEEE 754 single-precision floating-point value -double is an IEEE 754 double-precision floating-point value -t[n] is an array of n elements of type t - -------------------------------------------------------------------------------- -2. Header: -------------------------------------------------------------------------------- - -byte[44] Magic identification string for ASSBIN files. - 'ASSIMP.binary' - -integer Major version of the Assimp library which wrote the file -integer Minor version of the Assimp library which wrote the file - match these against ASSBIN_VERSION_MAJOR and ASSBIN_VERSION_MINOR - -integer SVN revision of the Assimp library (intended for our internal - debugging - if you write Ass files from your own APPs, set this value to 0. -integer Assimp compile flags - -short 0 for normal files, 1 for shortened dumps for regression tests - these should have the file extension assbin.regress - -short 1 if the data after the header is compressed with the DEFLATE algorithm, - 0 for uncompressed files. - For compressed files, the first integer after the header is - always the uncompressed data size - -byte[256] Zero-terminated source file name, UTF-8 -byte[128] Zero-terminated command line parameters passed to assimp_cmd, UTF-8 - -byte[64] Reserved for future use ----> Total length: 512 bytes - -------------------------------------------------------------------------------- -3. Chunks: -------------------------------------------------------------------------------- - -integer Magic chunk ID (ASSBIN_CHUNK_XXX) -integer Chunk data length, in bytes - (unknown chunks are possible, a good reader skips over them) - (chunk-data-length does not include the first two integers) - -byte[n] chunk-data-length bytes of data, depending on the chunk type - -Chunks can contain nested chunks. Nested chunks are ALWAYS at the end of the chunk, -their size is included in chunk-data-length. - -The chunk layout for all ASSIMP data structures is derived from their C declarations. -The general 'rule' to get from Assimp headers to the serialized layout is: - - 1. POD members (i.e. aiMesh::mPrimitiveTypes, aiMesh::mNumVertices), - in order of declaration. - - 2. Array-members (aiMesh::mFaces, aiMesh::mVertices, aiBone::mWeights), - in order of declaration. - - 2. Object array members (i.e aiMesh::mBones, aiScene::mMeshes) are stored in - subchunks directly following the data written in 1.) and 2.) - - - Of course, there are some exceptions to this general order: - -[[aiScene]] - - - The root node holding the scene structure is naturally stored in - a ASSBIN_CHUNK_AINODE subchunk following 1.) and 2.) (which is - empty for aiScene). - -[[aiMesh]] - - - mTextureCoords and mNumUVComponents are serialized as follows: - - [number of used uv channels times] - integer mNumUVComponents[n] - float mTextureCoords[n][3] - - -> more than AI_MAX_TEXCOORD_CHANNELS can be stored. This allows Assimp - builds with different settings for AI_MAX_TEXCOORD_CHANNELS to exchange - data. - -> the on-disk format always uses 3 floats to write UV coordinates. - If mNumUVComponents[0] is 1, the corresponding mTextureCoords array - consists of 3 floats. - - - The array member block of aiMesh is prefixed with an integer that specifies - the kinds of vertex components actually present in the mesh. This is a - bitwise combination of the ASSBIN_MESH_HAS_xxx constants. - -[[aiFace]] - - - mNumIndices is stored as short - - mIndices are written as short, if aiMesh::mNumVertices<65536 - -[[aiNode]] - - - mParent is omitted - -[[aiLight]] - - - mAttenuationXXX not written if aiLight::mType == aiLightSource_DIRECTIONAL - - mAngleXXX not written if aiLight::mType != aiLightSource_SPOT - -[[aiMaterial]] - - - mNumAllocated is omitted, for obvious reasons :-) - - - @endverbatim*/ - - -#define ASSBIN_HEADER_LENGTH 512 - -// these are the magic chunk identifiers for the binary ASS file format -#define ASSBIN_CHUNK_AICAMERA 0x1234 -#define ASSBIN_CHUNK_AILIGHT 0x1235 -#define ASSBIN_CHUNK_AITEXTURE 0x1236 -#define ASSBIN_CHUNK_AIMESH 0x1237 -#define ASSBIN_CHUNK_AINODEANIM 0x1238 -#define ASSBIN_CHUNK_AISCENE 0x1239 -#define ASSBIN_CHUNK_AIBONE 0x123a -#define ASSBIN_CHUNK_AIANIMATION 0x123b -#define ASSBIN_CHUNK_AINODE 0x123c -#define ASSBIN_CHUNK_AIMATERIAL 0x123d -#define ASSBIN_CHUNK_AIMATERIALPROPERTY 0x123e - -#define ASSBIN_MESH_HAS_POSITIONS 0x1 -#define ASSBIN_MESH_HAS_NORMALS 0x2 -#define ASSBIN_MESH_HAS_TANGENTS_AND_BITANGENTS 0x4 -#define ASSBIN_MESH_HAS_TEXCOORD_BASE 0x100 -#define ASSBIN_MESH_HAS_COLOR_BASE 0x10000 - -#define ASSBIN_MESH_HAS_TEXCOORD(n) (ASSBIN_MESH_HAS_TEXCOORD_BASE << n) -#define ASSBIN_MESH_HAS_COLOR(n) (ASSBIN_MESH_HAS_COLOR_BASE << n) - - -#endif // INCLUDED_ASSBIN_CHUNKS_H diff --git a/thirdparty/assimp/code/Common/scene.cpp b/thirdparty/assimp/code/Common/scene.cpp deleted file mode 100644 index d15619acff..0000000000 --- a/thirdparty/assimp/code/Common/scene.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -#include <assimp/scene.h> - -aiNode::aiNode() -: mName("") -, mParent(nullptr) -, mNumChildren(0) -, mChildren(nullptr) -, mNumMeshes(0) -, mMeshes(nullptr) -, mMetaData(nullptr) { - // empty -} - -aiNode::aiNode(const std::string& name) -: mName(name) -, mParent(nullptr) -, mNumChildren(0) -, mChildren(nullptr) -, mNumMeshes(0) -, mMeshes(nullptr) -, mMetaData(nullptr) { - // empty -} - -/** Destructor */ -aiNode::~aiNode() { - // delete all children recursively - // to make sure we won't crash if the data is invalid ... - if (mNumChildren && mChildren) - { - for (unsigned int a = 0; a < mNumChildren; a++) - delete mChildren[a]; - } - delete[] mChildren; - delete[] mMeshes; - delete mMetaData; -} - -const aiNode *aiNode::FindNode(const char* name) const { - if (nullptr == name) { - return nullptr; - } - if (!::strcmp(mName.data, name)) { - return this; - } - for (unsigned int i = 0; i < mNumChildren; ++i) { - const aiNode* const p = mChildren[i]->FindNode(name); - if (p) { - return p; - } - } - // there is definitely no sub-node with this name - return nullptr; -} - -aiNode *aiNode::FindNode(const char* name) { - if (!::strcmp(mName.data, name))return this; - for (unsigned int i = 0; i < mNumChildren; ++i) - { - aiNode* const p = mChildren[i]->FindNode(name); - if (p) { - return p; - } - } - // there is definitely no sub-node with this name - return nullptr; -} - -void aiNode::addChildren(unsigned int numChildren, aiNode **children) { - if (nullptr == children || 0 == numChildren) { - return; - } - - for (unsigned int i = 0; i < numChildren; i++) { - aiNode *child = children[i]; - if (nullptr != child) { - child->mParent = this; - } - } - - if (mNumChildren > 0) { - aiNode **tmp = new aiNode*[mNumChildren]; - ::memcpy(tmp, mChildren, sizeof(aiNode*) * mNumChildren); - delete[] mChildren; - mChildren = new aiNode*[mNumChildren + numChildren]; - ::memcpy(mChildren, tmp, sizeof(aiNode*) * mNumChildren); - ::memcpy(&mChildren[mNumChildren], children, sizeof(aiNode*)* numChildren); - mNumChildren += numChildren; - delete[] tmp; - } - else { - mChildren = new aiNode*[numChildren]; - for (unsigned int i = 0; i < numChildren; i++) { - mChildren[i] = children[i]; - } - mNumChildren = numChildren; - } -} diff --git a/thirdparty/assimp/code/Common/simd.cpp b/thirdparty/assimp/code/Common/simd.cpp deleted file mode 100644 index 04615f408e..0000000000 --- a/thirdparty/assimp/code/Common/simd.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -#include "simd.h" - -namespace Assimp { - -bool CPUSupportsSSE2() { -#if defined(__x86_64__) || defined(_M_X64) - //* x86_64 always has SSE2 instructions */ - return true; -#elif defined(__GNUC__) && defined(i386) - // for GCC x86 we check cpuid - unsigned int d; - __asm__( - "pushl %%ebx\n\t" - "cpuid\n\t" - "popl %%ebx\n\t" - : "=d" ( d ) - :"a" ( 1 ) ); - return ( d & 0x04000000 ) != 0; -#elif (defined(_MSC_VER) && defined(_M_IX86)) - // also check cpuid for MSVC x86 - unsigned int d; - __asm { - xor eax, eax - inc eax - push ebx - cpuid - pop ebx - mov d, edx - } - return ( d & 0x04000000 ) != 0; -#else - return false; -#endif -} - - -} // Namespace Assimp diff --git a/thirdparty/assimp/code/Common/simd.h b/thirdparty/assimp/code/Common/simd.h deleted file mode 100644 index 3eecdd4581..0000000000 --- a/thirdparty/assimp/code/Common/simd.h +++ /dev/null @@ -1,53 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -#pragma once - -#include <assimp/defs.h> - -namespace Assimp { - -/// @brief Checks if the platform supports SSE2 optimization -/// @return true, if SSE2 is supported. false if SSE2 is not supported. -bool ASSIMP_API CPUSupportsSSE2(); - -} // Namespace Assimp diff --git a/thirdparty/assimp/code/FBX/FBXAnimation.cpp b/thirdparty/assimp/code/FBX/FBXAnimation.cpp deleted file mode 100644 index 874914431b..0000000000 --- a/thirdparty/assimp/code/FBX/FBXAnimation.cpp +++ /dev/null @@ -1,305 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXAnimation.cpp - * @brief Assimp::FBX::AnimationCurve, Assimp::FBX::AnimationCurveNode, - * Assimp::FBX::AnimationLayer, Assimp::FBX::AnimationStack - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXImporter.h" -#include "FBXDocumentUtil.h" - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/) -: Object(id, element, name) -{ - const Scope& sc = GetRequiredScope(element); - const Element& KeyTime = GetRequiredElement(sc,"KeyTime"); - const Element& KeyValueFloat = GetRequiredElement(sc,"KeyValueFloat"); - - ParseVectorDataArray(keys, KeyTime); - ParseVectorDataArray(values, KeyValueFloat); - - if(keys.size() != values.size()) { - DOMError("the number of key times does not match the number of keyframe values",&KeyTime); - } - - // check if the key times are well-ordered - if(!std::equal(keys.begin(), keys.end() - 1, keys.begin() + 1, std::less<KeyTimeList::value_type>())) { - DOMError("the keyframes are not in ascending order",&KeyTime); - } - - const Element* KeyAttrDataFloat = sc["KeyAttrDataFloat"]; - if(KeyAttrDataFloat) { - ParseVectorDataArray(attributes, *KeyAttrDataFloat); - } - - const Element* KeyAttrFlags = sc["KeyAttrFlags"]; - if(KeyAttrFlags) { - ParseVectorDataArray(flags, *KeyAttrFlags); - } -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurve::~AnimationCurve() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, - const Document& doc, const char* const * target_prop_whitelist /*= NULL*/, - size_t whitelist_size /*= 0*/) -: Object(id, element, name) -, target() -, doc(doc) -{ - const Scope& sc = GetRequiredScope(element); - - // find target node - const char* whitelist[] = {"Model","NodeAttribute","Deformer"}; - const std::vector<const Connection*>& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,3); - - for(const Connection* con : conns) { - - // link should go for a property - if (!con->PropertyName().length()) { - continue; - } - - if(target_prop_whitelist) { - const char* const s = con->PropertyName().c_str(); - bool ok = false; - for (size_t i = 0; i < whitelist_size; ++i) { - if (!strcmp(s, target_prop_whitelist[i])) { - ok = true; - break; - } - } - - if (!ok) { - throw std::range_error("AnimationCurveNode target property is not in whitelist"); - } - } - - const Object* const ob = con->DestinationObject(); - if(!ob) { - DOMWarning("failed to read destination object for AnimationCurveNode->Model link, ignoring",&element); - continue; - } - - // XXX support constraints as DOM class - //ai_assert(dynamic_cast<const Model*>(ob) || dynamic_cast<const NodeAttribute*>(ob)); - target = ob; - if(!target) { - continue; - } - - prop = con->PropertyName(); - break; - } - - if(!target) { - DOMWarning("failed to resolve target Model/NodeAttribute/Constraint for AnimationCurveNode",&element); - } - - props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false); -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurveNode::~AnimationCurveNode() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -const AnimationCurveMap& AnimationCurveNode::Curves() const -{ - if ( curves.empty() ) { - // resolve attached animation curves - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve"); - - for(const Connection* con : conns) { - - // link should go for a property - if (!con->PropertyName().length()) { - continue; - } - - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for AnimationCurve->AnimationCurveNode link, ignoring",&element); - continue; - } - - const AnimationCurve* const anim = dynamic_cast<const AnimationCurve*>(ob); - if(!anim) { - DOMWarning("source object for ->AnimationCurveNode link is not an AnimationCurve",&element); - continue; - } - - curves[con->PropertyName()] = anim; - } - } - - return curves; -} - -// ------------------------------------------------------------------------------------------------ -AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc) -: Object(id, element, name) -, doc(doc) -{ - const Scope& sc = GetRequiredScope(element); - - // note: the props table here bears little importance and is usually absent - props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true); -} - -// ------------------------------------------------------------------------------------------------ -AnimationLayer::~AnimationLayer() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/, - size_t whitelist_size /*= 0*/) const -{ - AnimationCurveNodeList nodes; - - // resolve attached animation nodes - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurveNode"); - nodes.reserve(conns.size()); - - for(const Connection* con : conns) { - - // link should not go to a property - if (con->PropertyName().length()) { - continue; - } - - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for AnimationCurveNode->AnimationLayer link, ignoring",&element); - continue; - } - - const AnimationCurveNode* const anim = dynamic_cast<const AnimationCurveNode*>(ob); - if(!anim) { - DOMWarning("source object for ->AnimationLayer link is not an AnimationCurveNode",&element); - continue; - } - - if(target_prop_whitelist) { - const char* s = anim->TargetProperty().c_str(); - bool ok = false; - for (size_t i = 0; i < whitelist_size; ++i) { - if (!strcmp(s, target_prop_whitelist[i])) { - ok = true; - break; - } - } - if(!ok) { - continue; - } - } - nodes.push_back(anim); - } - - return nodes; // pray for NRVO -} - -// ------------------------------------------------------------------------------------------------ -AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc) -: Object(id, element, name) -{ - const Scope& sc = GetRequiredScope(element); - - // note: we don't currently use any of these properties so we shouldn't bother if it is missing - props = GetPropertyTable(doc,"AnimationStack.FbxAnimStack",element,sc, true); - - // resolve attached animation layers - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationLayer"); - layers.reserve(conns.size()); - - for(const Connection* con : conns) { - - // link should not go to a property - if (con->PropertyName().length()) { - continue; - } - - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for AnimationLayer->AnimationStack link, ignoring",&element); - continue; - } - - const AnimationLayer* const anim = dynamic_cast<const AnimationLayer*>(ob); - if(!anim) { - DOMWarning("source object for ->AnimationStack link is not an AnimationLayer",&element); - continue; - } - layers.push_back(anim); - } -} - -// ------------------------------------------------------------------------------------------------ -AnimationStack::~AnimationStack() -{ - // empty -} - -} //!FBX -} //!Assimp - -#endif // ASSIMP_BUILD_NO_FBX_IMPORTER diff --git a/thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp b/thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp deleted file mode 100644 index a4a2bc8e79..0000000000 --- a/thirdparty/assimp/code/FBX/FBXBinaryTokenizer.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -/** @file FBXBinaryTokenizer.cpp - * @brief Implementation of a fake lexer for binary fbx files - - * we emit tokens so the parser needs almost no special handling - * for binary files. - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXTokenizer.h" -#include "FBXUtil.h" -#include <assimp/defs.h> -#include <stdint.h> -#include <assimp/Exceptional.h> -#include <assimp/ByteSwapper.h> - -namespace Assimp { -namespace FBX { - -//enum Flag -//{ -// e_unknown_0 = 1 << 0, -// e_unknown_1 = 1 << 1, -// e_unknown_2 = 1 << 2, -// e_unknown_3 = 1 << 3, -// e_unknown_4 = 1 << 4, -// e_unknown_5 = 1 << 5, -// e_unknown_6 = 1 << 6, -// e_unknown_7 = 1 << 7, -// e_unknown_8 = 1 << 8, -// e_unknown_9 = 1 << 9, -// e_unknown_10 = 1 << 10, -// e_unknown_11 = 1 << 11, -// e_unknown_12 = 1 << 12, -// e_unknown_13 = 1 << 13, -// e_unknown_14 = 1 << 14, -// e_unknown_15 = 1 << 15, -// e_unknown_16 = 1 << 16, -// e_unknown_17 = 1 << 17, -// e_unknown_18 = 1 << 18, -// e_unknown_19 = 1 << 19, -// e_unknown_20 = 1 << 20, -// e_unknown_21 = 1 << 21, -// e_unknown_22 = 1 << 22, -// e_unknown_23 = 1 << 23, -// e_flag_field_size_64_bit = 1 << 24, // Not sure what is -// e_unknown_25 = 1 << 25, -// e_unknown_26 = 1 << 26, -// e_unknown_27 = 1 << 27, -// e_unknown_28 = 1 << 28, -// e_unknown_29 = 1 << 29, -// e_unknown_30 = 1 << 30, -// e_unknown_31 = 1 << 31 -//}; -// -//bool check_flag(uint32_t flags, Flag to_check) -//{ -// return (flags & to_check) != 0; -//} -// ------------------------------------------------------------------------------------------------ -Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset) - : - #ifdef DEBUG - contents(sbegin, static_cast<size_t>(send-sbegin)), - #endif - sbegin(sbegin) - , send(send) - , type(type) - , line(offset) - , column(BINARY_MARKER) -{ - ai_assert(sbegin); - ai_assert(send); - - // binary tokens may have zero length because they are sometimes dummies - // inserted by TokenizeBinary() - ai_assert(send >= sbegin); -} - - -namespace { - -// ------------------------------------------------------------------------------------------------ -// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError. -AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX; -AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) -{ - throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset)); -} - - -// ------------------------------------------------------------------------------------------------ -size_t Offset(const char* begin, const char* cursor) { - ai_assert(begin <= cursor); - - return cursor - begin; -} - -// ------------------------------------------------------------------------------------------------ -void TokenizeError(const std::string& message, const char* begin, const char* cursor) { - TokenizeError(message, Offset(begin, cursor)); -} - -// ------------------------------------------------------------------------------------------------ -uint32_t ReadWord(const char* input, const char*& cursor, const char* end) { - const size_t k_to_read = sizeof( uint32_t ); - if(Offset(cursor, end) < k_to_read ) { - TokenizeError("cannot ReadWord, out of bounds",input, cursor); - } - - uint32_t word; - ::memcpy(&word, cursor, 4); - AI_SWAP4(word); - - cursor += k_to_read; - - return word; -} - -// ------------------------------------------------------------------------------------------------ -uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) { - const size_t k_to_read = sizeof(uint64_t); - if(Offset(cursor, end) < k_to_read) { - TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor); - } - - uint64_t dword /*= *reinterpret_cast<const uint64_t*>(cursor)*/; - ::memcpy( &dword, cursor, sizeof( uint64_t ) ); - AI_SWAP8(dword); - - cursor += k_to_read; - - return dword; -} - -// ------------------------------------------------------------------------------------------------ -uint8_t ReadByte(const char* input, const char*& cursor, const char* end) { - if(Offset(cursor, end) < sizeof( uint8_t ) ) { - TokenizeError("cannot ReadByte, out of bounds",input, cursor); - } - - uint8_t word;/* = *reinterpret_cast< const uint8_t* >( cursor )*/ - ::memcpy( &word, cursor, sizeof( uint8_t ) ); - ++cursor; - - return word; -} - -// ------------------------------------------------------------------------------------------------ -unsigned int ReadString(const char*& sbegin_out, const char*& send_out, const char* input, - const char*& cursor, const char* end, bool long_length = false, bool allow_null = false) { - const uint32_t len_len = long_length ? 4 : 1; - if(Offset(cursor, end) < len_len) { - TokenizeError("cannot ReadString, out of bounds reading length",input, cursor); - } - - const uint32_t length = long_length ? ReadWord(input, cursor, end) : ReadByte(input, cursor, end); - - if (Offset(cursor, end) < length) { - TokenizeError("cannot ReadString, length is out of bounds",input, cursor); - } - - sbegin_out = cursor; - cursor += length; - - send_out = cursor; - - if(!allow_null) { - for (unsigned int i = 0; i < length; ++i) { - if(sbegin_out[i] == '\0') { - TokenizeError("failed ReadString, unexpected NUL character in string",input, cursor); - } - } - } - - return length; -} - -// ------------------------------------------------------------------------------------------------ -void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, const char*& cursor, const char* end) { - if(Offset(cursor, end) < 1) { - TokenizeError("cannot ReadData, out of bounds reading length",input, cursor); - } - - const char type = *cursor; - sbegin_out = cursor++; - - switch(type) - { - // 16 bit int - case 'Y': - cursor += 2; - break; - - // 1 bit bool flag (yes/no) - case 'C': - cursor += 1; - break; - - // 32 bit int - case 'I': - // <- fall through - - // float - case 'F': - cursor += 4; - break; - - // double - case 'D': - cursor += 8; - break; - - // 64 bit int - case 'L': - cursor += 8; - break; - - // note: do not write cursor += ReadWord(...cursor) as this would be UB - - // raw binary data - case 'R': - { - const uint32_t length = ReadWord(input, cursor, end); - cursor += length; - break; - } - - case 'b': - // TODO: what is the 'b' type code? Right now we just skip over it / - // take the full range we could get - cursor = end; - break; - - // array of * - case 'f': - case 'd': - case 'l': - case 'i': - case 'c': { - const uint32_t length = ReadWord(input, cursor, end); - const uint32_t encoding = ReadWord(input, cursor, end); - - const uint32_t comp_len = ReadWord(input, cursor, end); - - // compute length based on type and check against the stored value - if(encoding == 0) { - uint32_t stride = 0; - switch(type) - { - case 'f': - case 'i': - stride = 4; - break; - - case 'd': - case 'l': - stride = 8; - break; - - case 'c': - stride = 1; - break; - - default: - ai_assert(false); - }; - ai_assert(stride > 0); - if(length * stride != comp_len) { - TokenizeError("cannot ReadData, calculated data stride differs from what the file claims",input, cursor); - } - } - // zip/deflate algorithm (encoding==1)? take given length. anything else? die - else if (encoding != 1) { - TokenizeError("cannot ReadData, unknown encoding",input, cursor); - } - cursor += comp_len; - break; - } - - // string - case 'S': { - const char* sb, *se; - // 0 characters can legally happen in such strings - ReadString(sb, se, input, cursor, end, true, true); - break; - } - default: - TokenizeError("cannot ReadData, unexpected type code: " + std::string(&type, 1),input, cursor); - } - - if(cursor > end) { - TokenizeError("cannot ReadData, the remaining size is too small for the data type: " + std::string(&type, 1),input, cursor); - } - - // the type code is contained in the returned range - send_out = cursor; -} - - -// ------------------------------------------------------------------------------------------------ -bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits) -{ - // the first word contains the offset at which this block ends - const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); - - // we may get 0 if reading reached the end of the file - - // fbx files have a mysterious extra footer which I don't know - // how to extract any information from, but at least it always - // starts with a 0. - if(!end_offset) { - return false; - } - - if(end_offset > Offset(input, end)) { - TokenizeError("block offset is out of range",input, cursor); - } - else if(end_offset < Offset(input, cursor)) { - TokenizeError("block offset is negative out of range",input, cursor); - } - - // the second data word contains the number of properties in the scope - const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); - - // the third data word contains the length of the property list - const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); - - // now comes the name of the scope/key - const char* sbeg, *send; - ReadString(sbeg, send, input, cursor, end); - - output_tokens.push_back(new_Token(sbeg, send, TokenType_KEY, Offset(input, cursor) )); - - // now come the individual properties - const char* begin_cursor = cursor; - for (unsigned int i = 0; i < prop_count; ++i) { - ReadData(sbeg, send, input, cursor, begin_cursor + prop_length); - - output_tokens.push_back(new_Token(sbeg, send, TokenType_DATA, Offset(input, cursor) )); - - if(i != prop_count-1) { - output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_COMMA, Offset(input, cursor) )); - } - } - - if (Offset(begin_cursor, cursor) != prop_length) { - TokenizeError("property length not reached, something is wrong",input, cursor); - } - - // at the end of each nested block, there is a NUL record to indicate - // that the sub-scope exists (i.e. to distinguish between P: and P : {}) - // this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit. - const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t)* 3 + 1) : (sizeof(uint32_t)* 3 + 1); - - if (Offset(input, cursor) < end_offset) { - if (end_offset - Offset(input, cursor) < sentinel_block_length) { - TokenizeError("insufficient padding bytes at block end",input, cursor); - } - - output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_OPEN_BRACKET, Offset(input, cursor) )); - - // XXX this is vulnerable to stack overflowing .. - while(Offset(input, cursor) < end_offset - sentinel_block_length) { - ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits); - } - output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) )); - - for (unsigned int i = 0; i < sentinel_block_length; ++i) { - if(cursor[i] != '\0') { - TokenizeError("failed to read nested block sentinel, expected all bytes to be 0",input, cursor); - } - } - cursor += sentinel_block_length; - } - - if (Offset(input, cursor) != end_offset) { - TokenizeError("scope length not reached, something is wrong",input, cursor); - } - - return true; -} - -} // anonymous namespace - -// ------------------------------------------------------------------------------------------------ -// TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent -void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length) -{ - ai_assert(input); - - if(length < 0x1b) { - TokenizeError("file is too short",0); - } - - //uint32_t offset = 0x15; -/* const char* cursor = input + 0x15; - - const uint32_t flags = ReadWord(input, cursor, input + length); - - const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused - const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused*/ - - if (strncmp(input,"Kaydara FBX Binary",18)) { - TokenizeError("magic bytes not found",0); - } - - const char* cursor = input + 18; - /*Result ignored*/ ReadByte(input, cursor, input + length); - /*Result ignored*/ ReadByte(input, cursor, input + length); - /*Result ignored*/ ReadByte(input, cursor, input + length); - /*Result ignored*/ ReadByte(input, cursor, input + length); - /*Result ignored*/ ReadByte(input, cursor, input + length); - const uint32_t version = ReadWord(input, cursor, input + length); - const bool is64bits = version >= 7500; - const char *end = input + length; - while (cursor < end ) { - if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { - break; - } - } -} - -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXCommon.h b/thirdparty/assimp/code/FBX/FBXCommon.h deleted file mode 100644 index e516449130..0000000000 --- a/thirdparty/assimp/code/FBX/FBXCommon.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXCommon.h -* Some useful constants and enums for dealing with FBX files. -*/ -#ifndef AI_FBXCOMMON_H_INC -#define AI_FBXCOMMON_H_INC - -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -namespace Assimp { -namespace FBX -{ - const std::string NULL_RECORD = { // 13 null bytes - '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0' - }; // who knows why - const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings - const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import - const int64_t SECOND = 46186158000; // FBX's kTime unit - - // rotation order. We'll probably use EulerXYZ for everything - enum RotOrder { - RotOrder_EulerXYZ = 0, - RotOrder_EulerXZY, - RotOrder_EulerYZX, - RotOrder_EulerYXZ, - RotOrder_EulerZXY, - RotOrder_EulerZYX, - - RotOrder_SphericXYZ, - - RotOrder_MAX // end-of-enum sentinel - }; - - // transformation inheritance method. Most of the time RSrs - enum TransformInheritance { - TransformInheritance_RrSs = 0, - TransformInheritance_RSrs, - TransformInheritance_Rrs, - - TransformInheritance_MAX // end-of-enum sentinel - }; -} -} -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER - -#endif // AI_FBXCOMMON_H_INC diff --git a/thirdparty/assimp/code/FBX/FBXCompileConfig.h b/thirdparty/assimp/code/FBX/FBXCompileConfig.h deleted file mode 100644 index 03536a1823..0000000000 --- a/thirdparty/assimp/code/FBX/FBXCompileConfig.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXCompileConfig.h - * @brief FBX importer compile-time switches - */ -#ifndef INCLUDED_AI_FBX_COMPILECONFIG_H -#define INCLUDED_AI_FBX_COMPILECONFIG_H - -#include <map> -#include <set> - -// -#if _MSC_VER > 1500 || (defined __GNUC___) -# define ASSIMP_FBX_USE_UNORDERED_MULTIMAP -# else -# define fbx_unordered_map map -# define fbx_unordered_multimap multimap -# define fbx_unordered_set set -# define fbx_unordered_multiset multiset -#endif - -#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP -# include <unordered_map> -# include <unordered_set> -# if _MSC_VER > 1600 -# define fbx_unordered_map unordered_map -# define fbx_unordered_multimap unordered_multimap -# define fbx_unordered_set unordered_set -# define fbx_unordered_multiset unordered_multiset -# else -# define fbx_unordered_map tr1::unordered_map -# define fbx_unordered_multimap tr1::unordered_multimap -# define fbx_unordered_set tr1::unordered_set -# define fbx_unordered_multiset tr1::unordered_multiset -# endif -#endif - -#endif // INCLUDED_AI_FBX_COMPILECONFIG_H diff --git a/thirdparty/assimp/code/FBX/FBXConverter.cpp b/thirdparty/assimp/code/FBX/FBXConverter.cpp deleted file mode 100644 index d8a22d9f74..0000000000 --- a/thirdparty/assimp/code/FBX/FBXConverter.cpp +++ /dev/null @@ -1,3727 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXConverter.cpp - * @brief Implementation of the FBX DOM -> aiScene converter - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXConverter.h" -#include "FBXParser.h" -#include "FBXMeshGeometry.h" -#include "FBXDocument.h" -#include "FBXUtil.h" -#include "FBXProperties.h" -#include "FBXImporter.h" - -#include <assimp/StringComparison.h> -#include <assimp/MathFunctions.h> - -#include <assimp/scene.h> - -#include <assimp/CreateAnimMesh.h> - -#include <tuple> -#include <memory> -#include <iterator> -#include <vector> -#include <sstream> -#include <iomanip> -#include <cstdint> -#include <iostream> -#include <stdlib.h> - -namespace Assimp { - namespace FBX { - - using namespace Util; - -#define MAGIC_NODE_TAG "_$AssimpFbx$" - -#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL - - FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones ) - : defaultMaterialIndex() - , lights() - , cameras() - , textures() - , materials_converted() - , textures_converted() - , meshes_converted() - , node_anim_chain_bits() - , mNodeNames() - , anim_fps() - , out(out) - , doc(doc) { - // animations need to be converted first since this will - // populate the node_anim_chain_bits map, which is needed - // to determine which nodes need to be generated. - ConvertAnimations(); - // Embedded textures in FBX could be connected to nothing but to itself, - // for instance Texture -> Video connection only but not to the main graph, - // The idea here is to traverse all objects to find these Textures and convert them, - // so later during material conversion it will find converted texture in the textures_converted array. - if (doc.Settings().readTextures) - { - ConvertOrphantEmbeddedTextures(); - } - ConvertRootNode(); - - if (doc.Settings().readAllMaterials) { - // unfortunately this means we have to evaluate all objects - for (const ObjectMap::value_type& v : doc.Objects()) { - - const Object* ob = v.second->Get(); - if (!ob) { - continue; - } - - const Material* mat = dynamic_cast<const Material*>(ob); - if (mat) { - - if (materials_converted.find(mat) == materials_converted.end()) { - ConvertMaterial(*mat, 0); - } - } - } - } - - ConvertGlobalSettings(); - TransferDataToScene(); - - // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE - // to make sure the scene passes assimp's validation. FBX files - // need not contain geometry (i.e. camera animations, raw armatures). - if (out->mNumMeshes == 0) { - out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - } - } - - - FBXConverter::~FBXConverter() { - std::for_each(meshes.begin(), meshes.end(), Util::delete_fun<aiMesh>()); - std::for_each(materials.begin(), materials.end(), Util::delete_fun<aiMaterial>()); - std::for_each(animations.begin(), animations.end(), Util::delete_fun<aiAnimation>()); - std::for_each(lights.begin(), lights.end(), Util::delete_fun<aiLight>()); - std::for_each(cameras.begin(), cameras.end(), Util::delete_fun<aiCamera>()); - std::for_each(textures.begin(), textures.end(), Util::delete_fun<aiTexture>()); - } - - void FBXConverter::ConvertRootNode() { - out->mRootNode = new aiNode(); - std::string unique_name; - GetUniqueName("RootNode", unique_name); - out->mRootNode->mName.Set(unique_name); - - // root has ID 0 - ConvertNodes(0L, out->mRootNode, out->mRootNode); - } - - static std::string getAncestorBaseName(const aiNode* node) - { - const char* nodeName = nullptr; - size_t length = 0; - while (node && (!nodeName || length == 0)) - { - nodeName = node->mName.C_Str(); - length = node->mName.length; - node = node->mParent; - } - - if (!nodeName || length == 0) - { - return {}; - } - // could be std::string_view if c++17 available - return std::string(nodeName, length); - } - - // Make unique name - std::string FBXConverter::MakeUniqueNodeName(const Model* const model, const aiNode& parent) - { - std::string original_name = FixNodeName(model->Name()); - if (original_name.empty()) - { - original_name = getAncestorBaseName(&parent); - } - std::string unique_name; - GetUniqueName(original_name, unique_name); - return unique_name; - } - /// todo: pre-build node hierarchy - /// todo: get bone from stack - /// todo: make map of aiBone* to aiNode* - /// then update convert clusters to the new format - void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) { - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(id, "Model"); - - std::vector<aiNode*> nodes; - nodes.reserve(conns.size()); - - std::vector<aiNode*> nodes_chain; - std::vector<aiNode*> post_nodes_chain; - - try { - for (const Connection* con : conns) { - // ignore object-property links - if (con->PropertyName().length()) { - // really important we document why this is ignored. - FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored"); - continue; //? - } - - // convert connection source object into Object base class - const Object* const object = con->SourceObject(); - if (nullptr == object) { - FBXImporter::LogError("failed to convert source object for Model link"); - continue; - } - - // FBX Model::Cube, Model::Bone001, etc elements - // This detects if we can cast the object into this model structure. - const Model* const model = dynamic_cast<const Model*>(object); - - if (nullptr != model) { - nodes_chain.clear(); - post_nodes_chain.clear(); - - aiMatrix4x4 new_abs_transform = parent->mTransformation; - std::string node_name = FixNodeName(model->Name()); - // even though there is only a single input node, the design of - // assimp (or rather: the complicated transformation chain that - // is employed by fbx) means that we may need multiple aiNode's - // to represent a fbx node's transformation. - - - // generate node transforms - this includes pivot data - // if need_additional_node is true then you t - const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain); - - // assert that for the current node we must have at least a single transform - ai_assert(nodes_chain.size()); - - if (need_additional_node) { - nodes_chain.push_back(new aiNode(node_name)); - } - - //setup metadata on newest node - SetupNodeMetadata(*model, *nodes_chain.back()); - - // link all nodes in a row - aiNode* last_parent = parent; - for (aiNode* child : nodes_chain) { - ai_assert(child); - - if (last_parent != parent) { - last_parent->mNumChildren = 1; - last_parent->mChildren = new aiNode*[1]; - last_parent->mChildren[0] = child; - } - - child->mParent = last_parent; - last_parent = child; - - new_abs_transform *= child->mTransformation; - } - - // attach geometry - ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform); - - // check if there will be any child nodes - const std::vector<const Connection*>& child_conns - = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model"); - - // if so, link the geometric transform inverse nodes - // before we attach any child nodes - if (child_conns.size()) { - for (aiNode* postnode : post_nodes_chain) { - ai_assert(postnode); - - if (last_parent != parent) { - last_parent->mNumChildren = 1; - last_parent->mChildren = new aiNode*[1]; - last_parent->mChildren[0] = postnode; - } - - postnode->mParent = last_parent; - last_parent = postnode; - - new_abs_transform *= postnode->mTransformation; - } - } - else { - // free the nodes we allocated as we don't need them - Util::delete_fun<aiNode> deleter; - std::for_each( - post_nodes_chain.begin(), - post_nodes_chain.end(), - deleter - ); - } - - // recursion call - child nodes - ConvertNodes(model->ID(), last_parent, root_node); - - if (doc.Settings().readLights) { - ConvertLights(*model, node_name); - } - - if (doc.Settings().readCameras) { - ConvertCameras(*model, node_name); - } - - nodes.push_back(nodes_chain.front()); - nodes_chain.clear(); - } - } - - if (nodes.size()) { - parent->mChildren = new aiNode*[nodes.size()](); - parent->mNumChildren = static_cast<unsigned int>(nodes.size()); - - std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren); - } - else - { - parent->mNumChildren = 0; - parent->mChildren = nullptr; - } - - } - catch (std::exception&) { - Util::delete_fun<aiNode> deleter; - std::for_each(nodes.begin(), nodes.end(), deleter); - std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter); - std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter); - } - } - - - void FBXConverter::ConvertLights(const Model& model, const std::string &orig_name) { - const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes(); - for (const NodeAttribute* attr : node_attrs) { - const Light* const light = dynamic_cast<const Light*>(attr); - if (light) { - ConvertLight(*light, orig_name); - } - } - } - - void FBXConverter::ConvertCameras(const Model& model, const std::string &orig_name) { - const std::vector<const NodeAttribute*>& node_attrs = model.GetAttributes(); - for (const NodeAttribute* attr : node_attrs) { - const Camera* const cam = dynamic_cast<const Camera*>(attr); - if (cam) { - ConvertCamera(*cam, orig_name); - } - } - } - - void FBXConverter::ConvertLight(const Light& light, const std::string &orig_name) { - lights.push_back(new aiLight()); - aiLight* const out_light = lights.back(); - - out_light->mName.Set(orig_name); - - const float intensity = light.Intensity() / 100.0f; - const aiVector3D& col = light.Color(); - - out_light->mColorDiffuse = aiColor3D(col.x, col.y, col.z); - out_light->mColorDiffuse.r *= intensity; - out_light->mColorDiffuse.g *= intensity; - out_light->mColorDiffuse.b *= intensity; - - out_light->mColorSpecular = out_light->mColorDiffuse; - - //lights are defined along negative y direction - out_light->mPosition = aiVector3D(0.0f); - out_light->mDirection = aiVector3D(0.0f, -1.0f, 0.0f); - out_light->mUp = aiVector3D(0.0f, 0.0f, -1.0f); - - switch (light.LightType()) - { - case Light::Type_Point: - out_light->mType = aiLightSource_POINT; - break; - - case Light::Type_Directional: - out_light->mType = aiLightSource_DIRECTIONAL; - break; - - case Light::Type_Spot: - out_light->mType = aiLightSource_SPOT; - out_light->mAngleOuterCone = AI_DEG_TO_RAD(light.OuterAngle()); - out_light->mAngleInnerCone = AI_DEG_TO_RAD(light.InnerAngle()); - break; - - case Light::Type_Area: - FBXImporter::LogWarn("cannot represent area light, set to UNDEFINED"); - out_light->mType = aiLightSource_UNDEFINED; - break; - - case Light::Type_Volume: - FBXImporter::LogWarn("cannot represent volume light, set to UNDEFINED"); - out_light->mType = aiLightSource_UNDEFINED; - break; - default: - ai_assert(false); - } - - float decay = light.DecayStart(); - switch (light.DecayType()) - { - case Light::Decay_None: - out_light->mAttenuationConstant = decay; - out_light->mAttenuationLinear = 0.0f; - out_light->mAttenuationQuadratic = 0.0f; - break; - case Light::Decay_Linear: - out_light->mAttenuationConstant = 0.0f; - out_light->mAttenuationLinear = 2.0f / decay; - out_light->mAttenuationQuadratic = 0.0f; - break; - case Light::Decay_Quadratic: - out_light->mAttenuationConstant = 0.0f; - out_light->mAttenuationLinear = 0.0f; - out_light->mAttenuationQuadratic = 2.0f / (decay * decay); - break; - case Light::Decay_Cubic: - FBXImporter::LogWarn("cannot represent cubic attenuation, set to Quadratic"); - out_light->mAttenuationQuadratic = 1.0f; - break; - default: - ai_assert(false); - break; - } - } - - void FBXConverter::ConvertCamera(const Camera& cam, const std::string &orig_name) - { - cameras.push_back(new aiCamera()); - aiCamera* const out_camera = cameras.back(); - - out_camera->mName.Set(orig_name); - - out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); - - out_camera->mPosition = aiVector3D(0.0f); - out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f); - out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f); - - out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); - - out_camera->mClipPlaneNear = cam.NearPlane(); - out_camera->mClipPlaneFar = cam.FarPlane(); - - out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); - out_camera->mClipPlaneNear = cam.NearPlane(); - out_camera->mClipPlaneFar = cam.FarPlane(); - } - - void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName) - { - uniqueName = name; - auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count - unsigned int& i = it_pair.first->second; - while (!it_pair.second) - { - i++; - std::ostringstream ext; - ext << name << std::setfill('0') << std::setw(3) << i; - uniqueName = ext.str(); - it_pair = mNodeNames.insert({ uniqueName, 0 }); - } - } - - const char* FBXConverter::NameTransformationComp(TransformationComp comp) { - switch (comp) { - case TransformationComp_Translation: - return "Translation"; - case TransformationComp_RotationOffset: - return "RotationOffset"; - case TransformationComp_RotationPivot: - return "RotationPivot"; - case TransformationComp_PreRotation: - return "PreRotation"; - case TransformationComp_Rotation: - return "Rotation"; - case TransformationComp_PostRotation: - return "PostRotation"; - case TransformationComp_RotationPivotInverse: - return "RotationPivotInverse"; - case TransformationComp_ScalingOffset: - return "ScalingOffset"; - case TransformationComp_ScalingPivot: - return "ScalingPivot"; - case TransformationComp_Scaling: - return "Scaling"; - case TransformationComp_ScalingPivotInverse: - return "ScalingPivotInverse"; - case TransformationComp_GeometricScaling: - return "GeometricScaling"; - case TransformationComp_GeometricRotation: - return "GeometricRotation"; - case TransformationComp_GeometricTranslation: - return "GeometricTranslation"; - case TransformationComp_GeometricScalingInverse: - return "GeometricScalingInverse"; - case TransformationComp_GeometricRotationInverse: - return "GeometricRotationInverse"; - case TransformationComp_GeometricTranslationInverse: - return "GeometricTranslationInverse"; - case TransformationComp_MAXIMUM: // this is to silence compiler warnings - default: - break; - } - - ai_assert(false); - - return nullptr; - } - - const char* FBXConverter::NameTransformationCompProperty(TransformationComp comp) { - switch (comp) { - case TransformationComp_Translation: - return "Lcl Translation"; - case TransformationComp_RotationOffset: - return "RotationOffset"; - case TransformationComp_RotationPivot: - return "RotationPivot"; - case TransformationComp_PreRotation: - return "PreRotation"; - case TransformationComp_Rotation: - return "Lcl Rotation"; - case TransformationComp_PostRotation: - return "PostRotation"; - case TransformationComp_RotationPivotInverse: - return "RotationPivotInverse"; - case TransformationComp_ScalingOffset: - return "ScalingOffset"; - case TransformationComp_ScalingPivot: - return "ScalingPivot"; - case TransformationComp_Scaling: - return "Lcl Scaling"; - case TransformationComp_ScalingPivotInverse: - return "ScalingPivotInverse"; - case TransformationComp_GeometricScaling: - return "GeometricScaling"; - case TransformationComp_GeometricRotation: - return "GeometricRotation"; - case TransformationComp_GeometricTranslation: - return "GeometricTranslation"; - case TransformationComp_GeometricScalingInverse: - return "GeometricScalingInverse"; - case TransformationComp_GeometricRotationInverse: - return "GeometricRotationInverse"; - case TransformationComp_GeometricTranslationInverse: - return "GeometricTranslationInverse"; - case TransformationComp_MAXIMUM: // this is to silence compiler warnings - break; - } - - ai_assert(false); - - return nullptr; - } - - aiVector3D FBXConverter::TransformationCompDefaultValue(TransformationComp comp) - { - // XXX a neat way to solve the never-ending special cases for scaling - // would be to do everything in log space! - return comp == TransformationComp_Scaling ? aiVector3D(1.f, 1.f, 1.f) : aiVector3D(); - } - - void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out) - { - if (mode == Model::RotOrder_SphericXYZ) { - FBXImporter::LogError("Unsupported RotationMode: SphericXYZ"); - out = aiMatrix4x4(); - return; - } - - const float angle_epsilon = Math::getEpsilon<float>(); - - out = aiMatrix4x4(); - - bool is_id[3] = { true, true, true }; - - aiMatrix4x4 temp[3]; - if (std::fabs(rotation.z) > angle_epsilon) { - aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z), temp[2]); - is_id[2] = false; - } - if (std::fabs(rotation.y) > angle_epsilon) { - aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y), temp[1]); - is_id[1] = false; - } - if (std::fabs(rotation.x) > angle_epsilon) { - aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x), temp[0]); - is_id[0] = false; - } - - int order[3] = { -1, -1, -1 }; - - // note: rotation order is inverted since we're left multiplying as is usual in assimp - switch (mode) - { - case Model::RotOrder_EulerXYZ: - order[0] = 2; - order[1] = 1; - order[2] = 0; - break; - - case Model::RotOrder_EulerXZY: - order[0] = 1; - order[1] = 2; - order[2] = 0; - break; - - case Model::RotOrder_EulerYZX: - order[0] = 0; - order[1] = 2; - order[2] = 1; - break; - - case Model::RotOrder_EulerYXZ: - order[0] = 2; - order[1] = 0; - order[2] = 1; - break; - - case Model::RotOrder_EulerZXY: - order[0] = 1; - order[1] = 0; - order[2] = 2; - break; - - case Model::RotOrder_EulerZYX: - order[0] = 0; - order[1] = 1; - order[2] = 2; - break; - - default: - ai_assert(false); - break; - } - - ai_assert(order[0] >= 0); - ai_assert(order[0] <= 2); - ai_assert(order[1] >= 0); - ai_assert(order[1] <= 2); - ai_assert(order[2] >= 0); - ai_assert(order[2] <= 2); - - if (!is_id[order[0]]) { - out = temp[order[0]]; - } - - if (!is_id[order[1]]) { - out = out * temp[order[1]]; - } - - if (!is_id[order[2]]) { - out = out * temp[order[2]]; - } - } - - bool FBXConverter::NeedsComplexTransformationChain(const Model& model) - { - const PropertyTable& props = model.Props(); - bool ok; - - const float zero_epsilon = 1e-6f; - const aiVector3D all_ones(1.0f, 1.0f, 1.0f); - for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { - const TransformationComp comp = static_cast<TransformationComp>(i); - - if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) { - continue; - } - - bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling); - - const aiVector3D& v = PropertyGet<aiVector3D>(props, NameTransformationCompProperty(comp), ok); - if (ok && scale_compare) { - if ((v - all_ones).SquareLength() > zero_epsilon) { - return true; - } - } else if (ok) { - if (v.SquareLength() > zero_epsilon) { - return true; - } - } - } - - return false; - } - - std::string FBXConverter::NameTransformationChainNode(const std::string& name, TransformationComp comp) - { - return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp); - } - - bool FBXConverter::GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, - std::vector<aiNode*>& post_output_nodes) { - const PropertyTable& props = model.Props(); - const Model::RotOrder rot = model.RotationOrder(); - - bool ok; - - aiMatrix4x4 chain[TransformationComp_MAXIMUM]; - - ai_assert(TransformationComp_MAXIMUM < 32); - std::uint32_t chainBits = 0; - // A node won't need a node chain if it only has these. - const std::uint32_t chainMaskSimple = (1 << TransformationComp_Translation) + (1 << TransformationComp_Scaling) + (1 << TransformationComp_Rotation); - // A node will need a node chain if it has any of these. - const std::uint32_t chainMaskComplex = ((1 << (TransformationComp_MAXIMUM)) - 1) - chainMaskSimple; - - std::fill_n(chain, static_cast<unsigned int>(TransformationComp_MAXIMUM), aiMatrix4x4()); - - // generate transformation matrices for all the different transformation components - const float zero_epsilon = Math::getEpsilon<float>(); - const aiVector3D all_ones(1.0f, 1.0f, 1.0f); - - const aiVector3D& PreRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok); - if (ok && PreRotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_PreRotation); - - GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[TransformationComp_PreRotation]); - } - - const aiVector3D& PostRotation = PropertyGet<aiVector3D>(props, "PostRotation", ok); - if (ok && PostRotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_PostRotation); - - GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[TransformationComp_PostRotation]); - } - - const aiVector3D& RotationPivot = PropertyGet<aiVector3D>(props, "RotationPivot", ok); - if (ok && RotationPivot.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse); - - aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]); - aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]); - } - - const aiVector3D& RotationOffset = PropertyGet<aiVector3D>(props, "RotationOffset", ok); - if (ok && RotationOffset.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_RotationOffset); - - aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]); - } - - const aiVector3D& ScalingOffset = PropertyGet<aiVector3D>(props, "ScalingOffset", ok); - if (ok && ScalingOffset.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_ScalingOffset); - - aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]); - } - - const aiVector3D& ScalingPivot = PropertyGet<aiVector3D>(props, "ScalingPivot", ok); - if (ok && ScalingPivot.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_ScalingPivot) | (1 << TransformationComp_ScalingPivotInverse); - - aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]); - aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]); - } - - const aiVector3D& Translation = PropertyGet<aiVector3D>(props, "Lcl Translation", ok); - if (ok && Translation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_Translation); - - aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]); - } - - const aiVector3D& Scaling = PropertyGet<aiVector3D>(props, "Lcl Scaling", ok); - if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_Scaling); - - aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]); - } - - const aiVector3D& Rotation = PropertyGet<aiVector3D>(props, "Lcl Rotation", ok); - if (ok && Rotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_Rotation); - - GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]); - } - - const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok); - if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_GeometricScaling); - aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]); - aiVector3D GeometricScalingInverse = GeometricScaling; - bool canscale = true; - for (unsigned int i = 0; i < 3; ++i) { - if (std::fabs(GeometricScalingInverse[i]) > zero_epsilon) { - GeometricScalingInverse[i] = 1.0f / GeometricScaling[i]; - } - else { - FBXImporter::LogError("cannot invert geometric scaling matrix with a 0.0 scale component"); - canscale = false; - break; - } - } - if (canscale) { - chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse); - aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]); - } - } - - const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>(props, "GeometricRotation", ok); - if (ok && GeometricRotation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse); - GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]); - GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]); - chain[TransformationComp_GeometricRotationInverse].Inverse(); - } - - const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>(props, "GeometricTranslation", ok); - if (ok && GeometricTranslation.SquareLength() > zero_epsilon) { - chainBits = chainBits | (1 << TransformationComp_GeometricTranslation) | (1 << TransformationComp_GeometricTranslationInverse); - aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]); - aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]); - } - - // is_complex needs to be consistent with NeedsComplexTransformationChain() - // or the interplay between this code and the animation converter would - // not be guaranteed. - //ai_assert(NeedsComplexTransformationChain(model) == ((chainBits & chainMaskComplex) != 0)); - - // now, if we have more than just Translation, Scaling and Rotation, - // we need to generate a full node chain to accommodate for assimp's - // lack to express pivots and offsets. - if ((chainBits & chainMaskComplex) && doc.Settings().preservePivots) { - FBXImporter::LogInfo("generating full transformation chain for node: " + name); - - // query the anim_chain_bits dictionary to find out which chain elements - // have associated node animation channels. These can not be dropped - // even if they have identity transform in bind pose. - NodeAnimBitMap::const_iterator it = node_anim_chain_bits.find(name); - const unsigned int anim_chain_bitmask = (it == node_anim_chain_bits.end() ? 0 : (*it).second); - - unsigned int bit = 0x1; - for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) { - const TransformationComp comp = static_cast<TransformationComp>(i); - - if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) { - continue; - } - - if (comp == TransformationComp_PostRotation) { - chain[i] = chain[i].Inverse(); - } - - aiNode* nd = new aiNode(); - nd->mName.Set(NameTransformationChainNode(name, comp)); - nd->mTransformation = chain[i]; - - // geometric inverses go in a post-node chain - if (comp == TransformationComp_GeometricScalingInverse || - comp == TransformationComp_GeometricRotationInverse || - comp == TransformationComp_GeometricTranslationInverse - ) { - post_output_nodes.push_back(nd); - } - else { - output_nodes.push_back(nd); - } - } - - ai_assert(output_nodes.size()); - return true; - } - - // else, we can just multiply the matrices together - aiNode* nd = new aiNode(); - output_nodes.push_back(nd); - - // name passed to the method is already unique - nd->mName.Set(name); - - for (const auto &transform : chain) { - nd->mTransformation = nd->mTransformation * transform; - } - return false; - } - - void FBXConverter::SetupNodeMetadata(const Model& model, aiNode& nd) - { - const PropertyTable& props = model.Props(); - DirectPropertyMap unparsedProperties = props.GetUnparsedProperties(); - - // create metadata on node - const std::size_t numStaticMetaData = 2; - aiMetadata* data = aiMetadata::Alloc(static_cast<unsigned int>(unparsedProperties.size() + numStaticMetaData)); - nd.mMetaData = data; - int index = 0; - - // find user defined properties (3ds Max) - data->Set(index++, "UserProperties", aiString(PropertyGet<std::string>(props, "UDP3DSMAX", ""))); - // preserve the info that a node was marked as Null node in the original file. - data->Set(index++, "IsNull", model.IsNull() ? true : false); - - // add unparsed properties to the node's metadata - for (const DirectPropertyMap::value_type& prop : unparsedProperties) { - // Interpret the property as a concrete type - if (const TypedProperty<bool>* interpreted = prop.second->As<TypedProperty<bool> >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty<int>* interpreted = prop.second->As<TypedProperty<int> >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty<uint64_t>* interpreted = prop.second->As<TypedProperty<uint64_t> >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty<float>* interpreted = prop.second->As<TypedProperty<float> >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else if (const TypedProperty<std::string>* interpreted = prop.second->As<TypedProperty<std::string> >()) { - data->Set(index++, prop.first, aiString(interpreted->Value())); - } - else if (const TypedProperty<aiVector3D>* interpreted = prop.second->As<TypedProperty<aiVector3D> >()) { - data->Set(index++, prop.first, interpreted->Value()); - } - else { - ai_assert(false); - } - } - } - - void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - const std::vector<const Geometry*>& geos = model.GetGeometry(); - - std::vector<unsigned int> meshes; - meshes.reserve(geos.size()); - - for (const Geometry* geo : geos) { - - const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*>(geo); - const LineGeometry* const line = dynamic_cast<const LineGeometry*>(geo); - if (mesh) { - const std::vector<unsigned int>& indices = ConvertMesh(*mesh, model, parent, root_node, - absolute_transform); - std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); - } - else if (line) { - const std::vector<unsigned int>& indices = ConvertLine(*line, model, parent, root_node); - std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); - } - else { - FBXImporter::LogWarn("ignoring unrecognized geometry: " + geo->Name()); - } - } - - if (meshes.size()) { - parent->mMeshes = new unsigned int[meshes.size()](); - parent->mNumMeshes = static_cast<unsigned int>(meshes.size()); - - std::swap_ranges(meshes.begin(), meshes.end(), parent->mMeshes); - } - } - - std::vector<unsigned int> - FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - std::vector<unsigned int> temp; - - MeshMap::const_iterator it = meshes_converted.find(&mesh); - if (it != meshes_converted.end()) { - std::copy((*it).second.begin(), (*it).second.end(), std::back_inserter(temp)); - return temp; - } - - const std::vector<aiVector3D>& vertices = mesh.GetVertices(); - const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts(); - if (vertices.empty() || faces.empty()) { - FBXImporter::LogWarn("ignoring empty geometry: " + mesh.Name()); - return temp; - } - - // one material per mesh maps easily to aiMesh. Multiple material - // meshes need to be split. - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - if (doc.Settings().readMaterials && !mindices.empty()) { - const MatIndexArray::value_type base = mindices[0]; - for (MatIndexArray::value_type index : mindices) { - if (index != base) { - return ConvertMeshMultiMaterial(mesh, model, parent, root_node, absolute_transform); - } - } - } - - // faster code-path, just copy the data - temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node)); - return temp; - } - - std::vector<unsigned int> FBXConverter::ConvertLine(const LineGeometry& line, const Model& model, - aiNode *parent, aiNode *root_node) - { - std::vector<unsigned int> temp; - - const std::vector<aiVector3D>& vertices = line.GetVertices(); - const std::vector<int>& indices = line.GetIndices(); - if (vertices.empty() || indices.empty()) { - FBXImporter::LogWarn("ignoring empty line: " + line.Name()); - return temp; - } - - aiMesh* const out_mesh = SetupEmptyMesh(line, root_node); - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - - // copy vertices - out_mesh->mNumVertices = static_cast<unsigned int>(vertices.size()); - out_mesh->mVertices = new aiVector3D[out_mesh->mNumVertices]; - std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); - - //Number of line segments (faces) is "Number of Points - Number of Endpoints" - //N.B.: Endpoints in FbxLine are denoted by negative indices. - //If such an Index is encountered, add 1 and multiply by -1 to get the real index. - unsigned int epcount = 0; - for (unsigned i = 0; i < indices.size(); i++) - { - if (indices[i] < 0) { - epcount++; - } - } - unsigned int pcount = static_cast<unsigned int>( indices.size() ); - unsigned int scount = out_mesh->mNumFaces = pcount - epcount; - - aiFace* fac = out_mesh->mFaces = new aiFace[scount](); - for (unsigned int i = 0; i < pcount; ++i) { - if (indices[i] < 0) continue; - aiFace& f = *fac++; - f.mNumIndices = 2; //2 == aiPrimitiveType_LINE - f.mIndices = new unsigned int[2]; - f.mIndices[0] = indices[i]; - int segid = indices[(i + 1 == pcount ? 0 : i + 1)]; //If we have reached he last point, wrap around - f.mIndices[1] = (segid < 0 ? (segid + 1)*-1 : segid); //Convert EndPoint Index to normal Index - } - temp.push_back(static_cast<unsigned int>(meshes.size() - 1)); - return temp; - } - - aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode *parent) - { - aiMesh* const out_mesh = new aiMesh(); - meshes.push_back(out_mesh); - meshes_converted[&mesh].push_back(static_cast<unsigned int>(meshes.size() - 1)); - - // set name - std::string name = mesh.Name(); - if (name.substr(0, 10) == "Geometry::") { - name = name.substr(10); - } - - if (name.length()) { - out_mesh->mName.Set(name); - } - else - { - out_mesh->mName = parent->mName; - } - - return out_mesh; - } - - unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, - const aiMatrix4x4 &absolute_transform, aiNode *parent, - aiNode *root_node) - { - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent); - - const std::vector<aiVector3D>& vertices = mesh.GetVertices(); - const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts(); - - // copy vertices - out_mesh->mNumVertices = static_cast<unsigned int>(vertices.size()); - out_mesh->mVertices = new aiVector3D[vertices.size()]; - - std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); - - // generate dummy faces - out_mesh->mNumFaces = static_cast<unsigned int>(faces.size()); - aiFace* fac = out_mesh->mFaces = new aiFace[faces.size()](); - - unsigned int cursor = 0; - for (unsigned int pcount : faces) { - aiFace& f = *fac++; - f.mNumIndices = pcount; - f.mIndices = new unsigned int[pcount]; - switch (pcount) - { - case 1: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - for (unsigned int i = 0; i < pcount; ++i) { - f.mIndices[i] = cursor++; - } - } - - // copy normals - const std::vector<aiVector3D>& normals = mesh.GetNormals(); - if (normals.size()) { - ai_assert(normals.size() == vertices.size()); - - out_mesh->mNormals = new aiVector3D[vertices.size()]; - std::copy(normals.begin(), normals.end(), out_mesh->mNormals); - } - - // copy tangents - assimp requires both tangents and bitangents (binormals) - // to be present, or neither of them. Compute binormals from normals - // and tangents if needed. - const std::vector<aiVector3D>& tangents = mesh.GetTangents(); - const std::vector<aiVector3D>* binormals = &mesh.GetBinormals(); - - if (tangents.size()) { - std::vector<aiVector3D> tempBinormals; - if (!binormals->size()) { - if (normals.size()) { - tempBinormals.resize(normals.size()); - for (unsigned int i = 0; i < tangents.size(); ++i) { - tempBinormals[i] = normals[i] ^ tangents[i]; - } - - binormals = &tempBinormals; - } - else { - binormals = nullptr; - } - } - - if (binormals) { - ai_assert(tangents.size() == vertices.size()); - ai_assert(binormals->size() == vertices.size()); - - out_mesh->mTangents = new aiVector3D[vertices.size()]; - std::copy(tangents.begin(), tangents.end(), out_mesh->mTangents); - - out_mesh->mBitangents = new aiVector3D[vertices.size()]; - std::copy(binormals->begin(), binormals->end(), out_mesh->mBitangents); - } - } - - // copy texture coords - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - const std::vector<aiVector2D>& uvs = mesh.GetTextureCoords(i); - if (uvs.empty()) { - break; - } - - aiVector3D* out_uv = out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; - for (const aiVector2D& v : uvs) { - *out_uv++ = aiVector3D(v.x, v.y, 0.0f); - } - - out_mesh->mNumUVComponents[i] = 2; - } - - // copy vertex colors - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) { - const std::vector<aiColor4D>& colors = mesh.GetVertexColors(i); - if (colors.empty()) { - break; - } - - out_mesh->mColors[i] = new aiColor4D[vertices.size()]; - std::copy(colors.begin(), colors.end(), out_mesh->mColors[i]); - } - - if (!doc.Settings().readMaterials || mindices.empty()) { - FBXImporter::LogError("no material assigned to mesh, setting default material"); - out_mesh->mMaterialIndex = GetDefaultMaterial(); - } - else { - ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]); - } - - if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) { - ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, NO_MATERIAL_SEPARATION, - nullptr); - } - - std::vector<aiAnimMesh*> animMeshes; - for (const BlendShape* blendShape : mesh.GetBlendShapes()) { - for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) { - const std::vector<const ShapeGeometry*>& shapeGeometries = blendShapeChannel->GetShapeGeometries(); - for (size_t i = 0; i < shapeGeometries.size(); i++) { - aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); - const ShapeGeometry* shapeGeometry = shapeGeometries.at(i); - const std::vector<aiVector3D>& vertices = shapeGeometry->GetVertices(); - const std::vector<aiVector3D>& normals = shapeGeometry->GetNormals(); - const std::vector<unsigned int>& indices = shapeGeometry->GetIndices(); - animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); - for (size_t j = 0; j < indices.size(); j++) { - unsigned int index = indices.at(j); - aiVector3D vertex = vertices.at(j); - aiVector3D normal = normals.at(j); - unsigned int count = 0; - const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); - for (unsigned int k = 0; k < count; k++) { - unsigned int index = outIndices[k]; - animMesh->mVertices[index] += vertex; - if (animMesh->mNormals != nullptr) { - animMesh->mNormals[index] += normal; - animMesh->mNormals[index].NormalizeSafe(); - } - } - } - animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; - animMeshes.push_back(animMesh); - } - } - } - const size_t numAnimMeshes = animMeshes.size(); - if (numAnimMeshes > 0) { - out_mesh->mNumAnimMeshes = static_cast<unsigned int>(numAnimMeshes); - out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes]; - for (size_t i = 0; i < numAnimMeshes; i++) { - out_mesh->mAnimMeshes[i] = animMeshes.at(i); - } - } - return static_cast<unsigned int>(meshes.size() - 1); - } - - std::vector<unsigned int> - FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, - aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - ai_assert(mindices.size()); - - std::set<MatIndexArray::value_type> had; - std::vector<unsigned int> indices; - - for (MatIndexArray::value_type index : mindices) { - if (had.find(index) == had.end()) { - - indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node, absolute_transform)); - had.insert(index); - } - } - - return indices; - } - - unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, - MatIndexArray::value_type index, - aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform) - { - aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent); - - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - const std::vector<aiVector3D>& vertices = mesh.GetVertices(); - const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts(); - - const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != nullptr; - - unsigned int count_faces = 0; - unsigned int count_vertices = 0; - - // count faces - std::vector<unsigned int>::const_iterator itf = faces.begin(); - for (MatIndexArray::const_iterator it = mindices.begin(), - end = mindices.end(); it != end; ++it, ++itf) - { - if ((*it) != index) { - continue; - } - ++count_faces; - count_vertices += *itf; - } - - ai_assert(count_faces); - ai_assert(count_vertices); - - // mapping from output indices to DOM indexing, needed to resolve weights or blendshapes - std::vector<unsigned int> reverseMapping; - std::map<unsigned int, unsigned int> translateIndexMap; - if (process_weights || mesh.GetBlendShapes().size() > 0) { - reverseMapping.resize(count_vertices); - } - - // allocate output data arrays, but don't fill them yet - out_mesh->mNumVertices = count_vertices; - out_mesh->mVertices = new aiVector3D[count_vertices]; - - out_mesh->mNumFaces = count_faces; - aiFace* fac = out_mesh->mFaces = new aiFace[count_faces](); - - - // allocate normals - const std::vector<aiVector3D>& normals = mesh.GetNormals(); - if (normals.size()) { - ai_assert(normals.size() == vertices.size()); - out_mesh->mNormals = new aiVector3D[vertices.size()]; - } - - // allocate tangents, binormals. - const std::vector<aiVector3D>& tangents = mesh.GetTangents(); - const std::vector<aiVector3D>* binormals = &mesh.GetBinormals(); - std::vector<aiVector3D> tempBinormals; - - if (tangents.size()) { - if (!binormals->size()) { - if (normals.size()) { - // XXX this computes the binormals for the entire mesh, not only - // the part for which we need them. - tempBinormals.resize(normals.size()); - for (unsigned int i = 0; i < tangents.size(); ++i) { - tempBinormals[i] = normals[i] ^ tangents[i]; - } - - binormals = &tempBinormals; - } - else { - binormals = nullptr; - } - } - - if (binormals) { - ai_assert(tangents.size() == vertices.size() && binormals->size() == vertices.size()); - - out_mesh->mTangents = new aiVector3D[vertices.size()]; - out_mesh->mBitangents = new aiVector3D[vertices.size()]; - } - } - - // allocate texture coords - unsigned int num_uvs = 0; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i, ++num_uvs) { - const std::vector<aiVector2D>& uvs = mesh.GetTextureCoords(i); - if (uvs.empty()) { - break; - } - - out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; - out_mesh->mNumUVComponents[i] = 2; - } - - // allocate vertex colors - unsigned int num_vcs = 0; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i, ++num_vcs) { - const std::vector<aiColor4D>& colors = mesh.GetVertexColors(i); - if (colors.empty()) { - break; - } - - out_mesh->mColors[i] = new aiColor4D[vertices.size()]; - } - - unsigned int cursor = 0, in_cursor = 0; - - itf = faces.begin(); - for (MatIndexArray::const_iterator it = mindices.begin(), end = mindices.end(); it != end; ++it, ++itf) - { - const unsigned int pcount = *itf; - if ((*it) != index) { - in_cursor += pcount; - continue; - } - - aiFace& f = *fac++; - - f.mNumIndices = pcount; - f.mIndices = new unsigned int[pcount]; - switch (pcount) - { - case 1: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - for (unsigned int i = 0; i < pcount; ++i, ++cursor, ++in_cursor) { - f.mIndices[i] = cursor; - - if (reverseMapping.size()) { - reverseMapping[cursor] = in_cursor; - translateIndexMap[in_cursor] = cursor; - } - - out_mesh->mVertices[cursor] = vertices[in_cursor]; - - if (out_mesh->mNormals) { - out_mesh->mNormals[cursor] = normals[in_cursor]; - } - - if (out_mesh->mTangents) { - out_mesh->mTangents[cursor] = tangents[in_cursor]; - out_mesh->mBitangents[cursor] = (*binormals)[in_cursor]; - } - - for (unsigned int j = 0; j < num_uvs; ++j) { - const std::vector<aiVector2D>& uvs = mesh.GetTextureCoords(j); - out_mesh->mTextureCoords[j][cursor] = aiVector3D(uvs[in_cursor].x, uvs[in_cursor].y, 0.0f); - } - - for (unsigned int j = 0; j < num_vcs; ++j) { - const std::vector<aiColor4D>& cols = mesh.GetVertexColors(j); - out_mesh->mColors[j][cursor] = cols[in_cursor]; - } - } - } - - ConvertMaterialForMesh(out_mesh, model, mesh, index); - - if (process_weights) { - ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, index, &reverseMapping); - } - - std::vector<aiAnimMesh*> animMeshes; - for (const BlendShape* blendShape : mesh.GetBlendShapes()) { - for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) { - const std::vector<const ShapeGeometry*>& shapeGeometries = blendShapeChannel->GetShapeGeometries(); - for (size_t i = 0; i < shapeGeometries.size(); i++) { - aiAnimMesh* animMesh = aiCreateAnimMesh(out_mesh); - const ShapeGeometry* shapeGeometry = shapeGeometries.at(i); - const std::vector<aiVector3D>& vertices = shapeGeometry->GetVertices(); - const std::vector<aiVector3D>& normals = shapeGeometry->GetNormals(); - const std::vector<unsigned int>& indices = shapeGeometry->GetIndices(); - animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); - for (size_t j = 0; j < indices.size(); j++) { - unsigned int index = indices.at(j); - aiVector3D vertex = vertices.at(j); - aiVector3D normal = normals.at(j); - unsigned int count = 0; - const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); - for (unsigned int k = 0; k < count; k++) { - unsigned int outIndex = outIndices[k]; - if (translateIndexMap.find(outIndex) == translateIndexMap.end()) - continue; - unsigned int index = translateIndexMap[outIndex]; - animMesh->mVertices[index] += vertex; - if (animMesh->mNormals != nullptr) { - animMesh->mNormals[index] += normal; - animMesh->mNormals[index].NormalizeSafe(); - } - } - } - animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; - animMeshes.push_back(animMesh); - } - } - } - - const size_t numAnimMeshes = animMeshes.size(); - if (numAnimMeshes > 0) { - out_mesh->mNumAnimMeshes = static_cast<unsigned int>(numAnimMeshes); - out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes]; - for (size_t i = 0; i < numAnimMeshes; i++) { - out_mesh->mAnimMeshes[i] = animMeshes.at(i); - } - } - - return static_cast<unsigned int>(meshes.size() - 1); - } - - void FBXConverter::ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, - const aiMatrix4x4 &absolute_transform, - aiNode *parent, aiNode *root_node, unsigned int materialIndex, - std::vector<unsigned int> *outputVertStartIndices) - { - ai_assert(geo.DeformerSkin()); - - std::vector<size_t> out_indices; - std::vector<size_t> index_out_indices; - std::vector<size_t> count_out_indices; - - const Skin& sk = *geo.DeformerSkin(); - - std::vector<aiBone*> bones; - - const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION; - ai_assert(no_mat_check || outputVertStartIndices); - - try { - // iterate over the sub deformers - for (const Cluster* cluster : sk.Clusters()) { - ai_assert(cluster); - - const WeightIndexArray& indices = cluster->GetIndices(); - - const MatIndexArray& mats = geo.GetMaterialIndices(); - - const size_t no_index_sentinel = std::numeric_limits<size_t>::max(); - - count_out_indices.clear(); - index_out_indices.clear(); - out_indices.clear(); - - - // now check if *any* of these weights is contained in the output mesh, - // taking notes so we don't need to do it twice. - for (WeightIndexArray::value_type index : indices) { - - unsigned int count = 0; - const unsigned int* const out_idx = geo.ToOutputVertexIndex(index, count); - // ToOutputVertexIndex only returns nullptr if index is out of bounds - // which should never happen - ai_assert(out_idx != nullptr); - - index_out_indices.push_back(no_index_sentinel); - count_out_indices.push_back(0); - - for (unsigned int i = 0; i < count; ++i) { - if (no_mat_check || static_cast<size_t>(mats[geo.FaceForVertexIndex(out_idx[i])]) == materialIndex) { - - if (index_out_indices.back() == no_index_sentinel) { - index_out_indices.back() = out_indices.size(); - } - - if (no_mat_check) { - out_indices.push_back(out_idx[i]); - } else { - // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn) - const std::vector<unsigned int>::iterator it = std::lower_bound( - outputVertStartIndices->begin(), - outputVertStartIndices->end(), - out_idx[i] - ); - - out_indices.push_back(std::distance(outputVertStartIndices->begin(), it)); - } - - ++count_out_indices.back(); - } - } - } - - // if we found at least one, generate the output bones - // XXX this could be heavily simplified by collecting the bone - // data in a single step. - ConvertCluster(bones, cluster, out_indices, index_out_indices, - count_out_indices, absolute_transform, parent, root_node); - } - - bone_map.clear(); - } - catch (std::exception&e) { - std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>()); - throw; - } - - if (bones.empty()) { - out->mBones = nullptr; - out->mNumBones = 0; - return; - } else { - out->mBones = new aiBone *[bones.size()](); - out->mNumBones = static_cast<unsigned int>(bones.size()); - - std::swap_ranges(bones.begin(), bones.end(), out->mBones); - } - } - - const aiNode* FBXConverter::GetNodeByName( const aiString& name, aiNode *current_node ) - { - aiNode * iter = current_node; - //printf("Child count: %d", iter->mNumChildren); - return iter; - } - - void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl, - std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices, - std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform, - aiNode *parent, aiNode *root_node) { - ai_assert(cl); // make sure cluster valid - std::string deformer_name = cl->TargetNode()->Name(); - aiString bone_name = aiString(FixNodeName(deformer_name)); - - aiBone *bone = nullptr; - - if (bone_map.count(deformer_name)) { - std::cout << "retrieved bone from lookup " << bone_name.C_Str() << ". Deformer: " << deformer_name - << std::endl; - bone = bone_map[deformer_name]; - } else { - std::cout << "created new bone " << bone_name.C_Str() << ". Deformer: " << deformer_name << std::endl; - bone = new aiBone(); - bone->mName = bone_name; - - // store local transform link for post processing - bone->mOffsetMatrix = cl->TransformLink(); - bone->mOffsetMatrix.Inverse(); - - aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform; - - bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset - - - // - // Now calculate the aiVertexWeights - // - - aiVertexWeight *cursor = nullptr; - - bone->mNumWeights = static_cast<unsigned int>(out_indices.size()); - cursor = bone->mWeights = new aiVertexWeight[out_indices.size()]; - - const size_t no_index_sentinel = std::numeric_limits<size_t>::max(); - const WeightArray& weights = cl->GetWeights(); - - const size_t c = index_out_indices.size(); - for (size_t i = 0; i < c; ++i) { - const size_t index_index = index_out_indices[i]; - - if (index_index == no_index_sentinel) { - continue; - } - - const size_t cc = count_out_indices[i]; - for (size_t j = 0; j < cc; ++j) { - // cursor runs from first element relative to the start - // or relative to the start of the next indexes. - aiVertexWeight& out_weight = *cursor++; - - out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]); - out_weight.mWeight = weights[i]; - } - } - - bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone)); - } - - std::cout << "bone research: Indicies size: " << out_indices.size() << std::endl; - - // lookup must be populated in case something goes wrong - // this also allocates bones to mesh instance outside - local_mesh_bones.push_back(bone); - } - - void FBXConverter::ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, - MatIndexArray::value_type materialIndex) - { - // locate source materials for this mesh - const std::vector<const Material*>& mats = model.GetMaterials(); - if (static_cast<unsigned int>(materialIndex) >= mats.size() || materialIndex < 0) { - FBXImporter::LogError("material index out of bounds, setting default material"); - out->mMaterialIndex = GetDefaultMaterial(); - return; - } - - const Material* const mat = mats[materialIndex]; - MaterialMap::const_iterator it = materials_converted.find(mat); - if (it != materials_converted.end()) { - out->mMaterialIndex = (*it).second; - return; - } - - out->mMaterialIndex = ConvertMaterial(*mat, &geo); - materials_converted[mat] = out->mMaterialIndex; - } - - unsigned int FBXConverter::GetDefaultMaterial() - { - if (defaultMaterialIndex) { - return defaultMaterialIndex - 1; - } - - aiMaterial* out_mat = new aiMaterial(); - materials.push_back(out_mat); - - const aiColor3D diffuse = aiColor3D(0.8f, 0.8f, 0.8f); - out_mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - - aiString s; - s.Set(AI_DEFAULT_MATERIAL_NAME); - - out_mat->AddProperty(&s, AI_MATKEY_NAME); - - defaultMaterialIndex = static_cast<unsigned int>(materials.size()); - return defaultMaterialIndex - 1; - } - - - unsigned int FBXConverter::ConvertMaterial(const Material& material, const MeshGeometry* const mesh) - { - const PropertyTable& props = material.Props(); - - // generate empty output material - aiMaterial* out_mat = new aiMaterial(); - materials_converted[&material] = static_cast<unsigned int>(materials.size()); - - materials.push_back(out_mat); - - aiString str; - - // strip Material:: prefix - std::string name = material.Name(); - if (name.substr(0, 10) == "Material::") { - name = name.substr(10); - } - - // set material name if not empty - this could happen - // and there should be no key for it in this case. - if (name.length()) { - str.Set(name); - out_mat->AddProperty(&str, AI_MATKEY_NAME); - } - - // Set the shading mode as best we can: The FBX specification only mentions Lambert and Phong, and only Phong is mentioned in Assimp's aiShadingMode enum. - if (material.GetShadingModel() == "phong") - { - aiShadingMode shadingMode = aiShadingMode_Phong; - out_mat->AddProperty<aiShadingMode>(&shadingMode, 1, AI_MATKEY_SHADING_MODEL); - } - - // shading stuff and colors - SetShadingPropertiesCommon(out_mat, props); - SetShadingPropertiesRaw( out_mat, props, material.Textures(), mesh ); - - // texture assignments - SetTextureProperties(out_mat, material.Textures(), mesh); - SetTextureProperties(out_mat, material.LayeredTextures(), mesh); - - return static_cast<unsigned int>(materials.size() - 1); - } - - unsigned int FBXConverter::ConvertVideo(const Video& video) - { - // generate empty output texture - aiTexture* out_tex = new aiTexture(); - textures.push_back(out_tex); - - // assuming the texture is compressed - out_tex->mWidth = static_cast<unsigned int>(video.ContentLength()); // total data size - out_tex->mHeight = 0; // fixed to 0 - - // steal the data from the Video to avoid an additional copy - out_tex->pcData = reinterpret_cast<aiTexel*>(const_cast<Video&>(video).RelinquishContent()); - - // try to extract a hint from the file extension - const std::string& filename = video.RelativeFilename().empty() ? video.FileName() : video.RelativeFilename(); - std::string ext = BaseImporter::GetExtension(filename); - - if (ext == "jpeg") { - ext = "jpg"; - } - - if (ext.size() <= 3) { - memcpy(out_tex->achFormatHint, ext.c_str(), ext.size()); - } - - out_tex->mFilename.Set(filename.c_str()); - - return static_cast<unsigned int>(textures.size() - 1); - } - - aiString FBXConverter::GetTexturePath(const Texture* tex) - { - aiString path; - path.Set(tex->RelativeFilename()); - - const Video* media = tex->Media(); - if (media != nullptr) { - bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found) - unsigned int index; - - VideoMap::const_iterator it = textures_converted.find(*media); - if (it != textures_converted.end()) { - index = (*it).second; - textureReady = true; - } - else { - if (media->ContentLength() > 0) { - index = ConvertVideo(*media); - textures_converted[*media] = index; - textureReady = true; - } - } - - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready - if (doc.Settings().useLegacyEmbeddedTextureNaming) { - if (textureReady) { - // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" - // In FBX files textures are now stored internally by Assimp with their filename included - // Now Assimp can lookup through the loaded textures after all data is processed - // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it - // This may occur on this case too, it has to be studied - path.data[0] = '*'; - path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); - } - } - } - - return path; - } - - void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh) { - TextureMap::const_iterator it = textures.find(propName); - if (it == textures.end()) { - return; - } - - const Texture* const tex = (*it).second; - if (tex != 0) - { - aiString path = GetTexturePath(tex); - out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, 0); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0); - - const PropertyTable& props = tex->Props(); - - int uvIndex = 0; - - bool ok; - const std::string& uvSet = PropertyGet<std::string>(props, "UVSet", ok); - if (ok) { - // "default" is the name which usually appears in the FbxFileTexture template - if (uvSet != "default" && uvSet.length()) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), - std::find(materials.begin(), materials.end(), out_mat) - )); - - - uvIndex = -1; - if (!mesh) - { - for (const MeshMap::value_type& v : meshes_converted) { - const MeshGeometry* const meshGeom = dynamic_cast<const MeshGeometry*> (v.first); - if (!meshGeom) { - continue; - } - - const MatIndexArray& mats = meshGeom->GetMaterialIndices(); - if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { - continue; - } - - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (meshGeom->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = meshGeom->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast<int>(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; - } - - if (uvIndex == -1) { - uvIndex = index; - } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong"); - } - } - } - else - { - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast<int>(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - } - - if (uvIndex == -1) { - uvIndex = index; - } - } - - if (uvIndex == -1) { - FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); - uvIndex = 0; - } - } - } - - out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, 0); - } - } - - void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh) { - LayeredTextureMap::const_iterator it = layeredTextures.find(propName); - if (it == layeredTextures.end()) { - return; - } - - int texCount = (*it).second->textureCount(); - - // Set the blend mode for layered textures - int blendmode = (*it).second->GetBlendMode(); - out_mat->AddProperty(&blendmode, 1, _AI_MATKEY_TEXOP_BASE, target, 0); - - for (int texIndex = 0; texIndex < texCount; texIndex++) { - - const Texture* const tex = (*it).second->getTexture(texIndex); - - aiString path = GetTexturePath(tex); - out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, texIndex); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex); - - const PropertyTable& props = tex->Props(); - - int uvIndex = 0; - - bool ok; - const std::string& uvSet = PropertyGet<std::string>(props, "UVSet", ok); - if (ok) { - // "default" is the name which usually appears in the FbxFileTexture template - if (uvSet != "default" && uvSet.length()) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), - std::find(materials.begin(), materials.end(), out_mat) - )); - - uvIndex = -1; - if (!mesh) - { - for (const MeshMap::value_type& v : meshes_converted) { - const MeshGeometry* const meshGeom = dynamic_cast<const MeshGeometry*> (v.first); - if (!meshGeom) { - continue; - } - - const MatIndexArray& mats = meshGeom->GetMaterialIndices(); - if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { - continue; - } - - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (meshGeom->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = meshGeom->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast<int>(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; - } - - if (uvIndex == -1) { - uvIndex = index; - } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong"); - } - } - } - else - { - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast<int>(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - } - - if (uvIndex == -1) { - uvIndex = index; - } - } - - if (uvIndex == -1) { - FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); - uvIndex = 0; - } - } - } - - out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, texIndex); - } - } - - void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh) - { - TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); - TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh); - TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); - TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, textures, "SpecularFactor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh); - TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh); - TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); - TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS, mesh); - TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT, mesh); - TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh); - TrySetTextureProperties( out_mat, textures, "TransparencyFactor", aiTextureType_OPACITY, mesh ); - TrySetTextureProperties( out_mat, textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh ); - //Maya counterparts - TrySetTextureProperties(out_mat, textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh); - - // Maya PBR - TrySetTextureProperties(out_mat, textures, "Maya|baseColor|file", aiTextureType_BASE_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|normalCamera|file", aiTextureType_NORMAL_CAMERA, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|emissionColor|file", aiTextureType_EMISSION_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|metalness|file", aiTextureType_METALNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|diffuseRoughness|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - - // Maya stingray - TrySetTextureProperties(out_mat, textures, "Maya|TEX_color_map|file", aiTextureType_BASE_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_normal_map|file", aiTextureType_NORMAL_CAMERA, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh); - TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh); - } - - void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) - { - TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "SpecularFactor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh); - TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh); - TrySetTextureProperties( out_mat, layeredTextures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "TransparencyFactor", aiTextureType_OPACITY, mesh ); - } - - aiColor3D FBXConverter::GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName, - const std::string& factorName, bool& result, bool useTemplate) - { - result = true; - - bool ok; - aiVector3D BaseColor = PropertyGet<aiVector3D>(props, colorName, ok, useTemplate); - if (!ok) { - result = false; - return aiColor3D(0.0f, 0.0f, 0.0f); - } - - // if no factor name, return the colour as is - if (factorName.empty()) { - return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z); - } - - // otherwise it should be multiplied by the factor, if found. - float factor = PropertyGet<float>(props, factorName, ok, useTemplate); - if (ok) { - BaseColor *= factor; - } - return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z); - } - - aiColor3D FBXConverter::GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName, - bool& result) - { - return GetColorPropertyFactored(props, baseName + "Color", baseName + "Factor", result, true); - } - - aiColor3D FBXConverter::GetColorProperty(const PropertyTable& props, const std::string& colorName, - bool& result, bool useTemplate) - { - result = true; - bool ok; - const aiVector3D& ColorVec = PropertyGet<aiVector3D>(props, colorName, ok, useTemplate); - if (!ok) { - result = false; - return aiColor3D(0.0f, 0.0f, 0.0f); - } - return aiColor3D(ColorVec.x, ColorVec.y, ColorVec.z); - } - - void FBXConverter::SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props) - { - // Set shading properties. - // Modern FBX Files have two separate systems for defining these, - // with only the more comprehensive one described in the property template. - // Likely the other values are a legacy system, - // which is still always exported by the official FBX SDK. - // - // Blender's FBX import and export mostly ignore this legacy system, - // and as we only support recent versions of FBX anyway, we can do the same. - bool ok; - - const aiColor3D& Diffuse = GetColorPropertyFromMaterial(props, "Diffuse", ok); - if (ok) { - out_mat->AddProperty(&Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - } - - const aiColor3D& Emissive = GetColorPropertyFromMaterial(props, "Emissive", ok); - if (ok) { - out_mat->AddProperty(&Emissive, 1, AI_MATKEY_COLOR_EMISSIVE); - } - - const aiColor3D& Ambient = GetColorPropertyFromMaterial(props, "Ambient", ok); - if (ok) { - out_mat->AddProperty(&Ambient, 1, AI_MATKEY_COLOR_AMBIENT); - } - - // we store specular factor as SHININESS_STRENGTH, so just get the color - const aiColor3D& Specular = GetColorProperty(props, "SpecularColor", ok, true); - if (ok) { - out_mat->AddProperty(&Specular, 1, AI_MATKEY_COLOR_SPECULAR); - } - - // and also try to get SHININESS_STRENGTH - const float SpecularFactor = PropertyGet<float>(props, "SpecularFactor", ok, true); - if (ok) { - out_mat->AddProperty(&SpecularFactor, 1, AI_MATKEY_SHININESS_STRENGTH); - } - - // and the specular exponent - const float ShininessExponent = PropertyGet<float>(props, "ShininessExponent", ok); - if (ok) { - out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS); - } - - // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes: - const aiColor3D& Transparent = GetColorPropertyFactored(props, "TransparentColor", "TransparencyFactor", ok); - float CalculatedOpacity = 1.0f; - if (ok) { - out_mat->AddProperty(&Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT); - // as calculated by FBX SDK 2017: - CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f); - } - - // try to get the transparency factor - const float TransparencyFactor = PropertyGet<float>(props, "TransparencyFactor", ok); - if (ok) { - out_mat->AddProperty(&TransparencyFactor, 1, AI_MATKEY_TRANSPARENCYFACTOR); - } - - // use of TransparencyFactor is inconsistent. - // Maya always stores it as 1.0, - // so we can't use it to set AI_MATKEY_OPACITY. - // Blender is more sensible and stores it as the alpha value. - // However both the FBX SDK and Blender always write an additional - // legacy "Opacity" field, so we can try to use that. - // - // If we can't find it, - // we can fall back to the value which the FBX SDK calculates - // from transparency colour (RGB) and factor (F) as - // 1.0 - F*((R+G+B)/3). - // - // There's no consistent way to interpret this opacity value, - // so it's up to clients to do the correct thing. - const float Opacity = PropertyGet<float>(props, "Opacity", ok); - if (ok) { - out_mat->AddProperty(&Opacity, 1, AI_MATKEY_OPACITY); - } - else if (CalculatedOpacity != 1.0) { - out_mat->AddProperty(&CalculatedOpacity, 1, AI_MATKEY_OPACITY); - } - - // reflection color and factor are stored separately - const aiColor3D& Reflection = GetColorProperty(props, "ReflectionColor", ok, true); - if (ok) { - out_mat->AddProperty(&Reflection, 1, AI_MATKEY_COLOR_REFLECTIVE); - } - - float ReflectionFactor = PropertyGet<float>(props, "ReflectionFactor", ok, true); - if (ok) { - out_mat->AddProperty(&ReflectionFactor, 1, AI_MATKEY_REFLECTIVITY); - } - - const float BumpFactor = PropertyGet<float>(props, "BumpFactor", ok); - if (ok) { - out_mat->AddProperty(&BumpFactor, 1, AI_MATKEY_BUMPSCALING); - } - - const float DispFactor = PropertyGet<float>(props, "DisplacementFactor", ok); - if (ok) { - out_mat->AddProperty(&DispFactor, 1, "$mat.displacementscaling", 0, 0); - } -} - - -void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh) -{ - // Add all the unparsed properties with a "$raw." prefix - - const std::string prefix = "$raw."; - - for (const DirectPropertyMap::value_type& prop : props.GetUnparsedProperties()) { - - std::string name = prefix + prop.first; - - if (const TypedProperty<aiVector3D>* interpreted = prop.second->As<TypedProperty<aiVector3D> >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty<aiColor3D>* interpreted = prop.second->As<TypedProperty<aiColor3D> >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty<aiColor4D>* interpreted = prop.second->As<TypedProperty<aiColor4D> >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty<float>* interpreted = prop.second->As<TypedProperty<float> >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty<int>* interpreted = prop.second->As<TypedProperty<int> >()) - { - out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); - } - else if (const TypedProperty<bool>* interpreted = prop.second->As<TypedProperty<bool> >()) - { - int value = interpreted->Value() ? 1 : 0; - out_mat->AddProperty(&value, 1, name.c_str(), 0, 0); - } - else if (const TypedProperty<std::string>* interpreted = prop.second->As<TypedProperty<std::string> >()) - { - const aiString value = aiString(interpreted->Value()); - out_mat->AddProperty(&value, name.c_str(), 0, 0); - } - } - - // Add the textures' properties - - for (TextureMap::const_iterator it = textures.begin(); it != textures.end(); it++) { - - std::string name = prefix + it->first; - - const Texture* const tex = (*it).second; - if (tex != nullptr) - { - aiString path; - path.Set(tex->RelativeFilename()); - - const Video* media = tex->Media(); - if (media != nullptr && media->ContentLength() > 0) { - unsigned int index; - - VideoMap::const_iterator it = textures_converted.find(*media); - if (it != textures_converted.end()) { - index = (*it).second; - } - else { - index = ConvertVideo(*media); - textures_converted[*media] = index; - } - - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) - path.data[0] = '*'; - path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); - } - - out_mat->AddProperty(&path, (name + "|file").c_str(), aiTextureType_UNKNOWN, 0); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty(&uvTrafo, 1, (name + "|uvtrafo").c_str(), aiTextureType_UNKNOWN, 0); - - int uvIndex = 0; - - bool uvFound = false; - const std::string& uvSet = PropertyGet<std::string>(tex->Props(), "UVSet", uvFound); - if (uvFound) { - // "default" is the name which usually appears in the FbxFileTexture template - if (uvSet != "default" && uvSet.length()) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - std::vector<aiMaterial*>::iterator materialIt = std::find(materials.begin(), materials.end(), out_mat); - const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), materialIt)); - - uvIndex = -1; - if (!mesh) - { - for (const MeshMap::value_type& v : meshes_converted) { - const MeshGeometry* const meshGeom = dynamic_cast<const MeshGeometry*>(v.first); - if (!meshGeom) { - continue; - } - - const MatIndexArray& mats = meshGeom->GetMaterialIndices(); - if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { - continue; - } - - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (meshGeom->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = meshGeom->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast<int>(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - continue; - } - - if (uvIndex == -1) { - uvIndex = index; - } - else { - FBXImporter::LogWarn("the UV channel named " + uvSet + " appears at different positions in meshes, results will be wrong"); - } - } - } - else - { - int index = -1; - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { - if (mesh->GetTextureCoords(i).empty()) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName(i); - if (name == uvSet) { - index = static_cast<int>(i); - break; - } - } - if (index == -1) { - FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); - } - - if (uvIndex == -1) { - uvIndex = index; - } - } - - if (uvIndex == -1) { - FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); - uvIndex = 0; - } - } - } - - out_mat->AddProperty(&uvIndex, 1, (name + "|uvwsrc").c_str(), aiTextureType_UNKNOWN, 0); - } - } - } - - - double FBXConverter::FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal) { - switch (fp) { - case FileGlobalSettings::FrameRate_DEFAULT: - return 1.0; - - case FileGlobalSettings::FrameRate_120: - return 120.0; - - case FileGlobalSettings::FrameRate_100: - return 100.0; - - case FileGlobalSettings::FrameRate_60: - return 60.0; - - case FileGlobalSettings::FrameRate_50: - return 50.0; - - case FileGlobalSettings::FrameRate_48: - return 48.0; - - case FileGlobalSettings::FrameRate_30: - case FileGlobalSettings::FrameRate_30_DROP: - return 30.0; - - case FileGlobalSettings::FrameRate_NTSC_DROP_FRAME: - case FileGlobalSettings::FrameRate_NTSC_FULL_FRAME: - return 29.9700262; - - case FileGlobalSettings::FrameRate_PAL: - return 25.0; - - case FileGlobalSettings::FrameRate_CINEMA: - return 24.0; - - case FileGlobalSettings::FrameRate_1000: - return 1000.0; - - case FileGlobalSettings::FrameRate_CINEMA_ND: - return 23.976; - - case FileGlobalSettings::FrameRate_CUSTOM: - return customFPSVal; - - case FileGlobalSettings::FrameRate_MAX: // this is to silence compiler warnings - break; - } - - ai_assert(false); - - return -1.0f; - } - - - void FBXConverter::ConvertAnimations() - { - // first of all determine framerate - const FileGlobalSettings::FrameRate fps = doc.GlobalSettings().TimeMode(); - const float custom = doc.GlobalSettings().CustomFrameRate(); - anim_fps = FrameRateToDouble(fps, custom); - - const std::vector<const AnimationStack*>& animations = doc.AnimationStacks(); - for (const AnimationStack* stack : animations) { - ConvertAnimationStack(*stack); - } - } - - std::string FBXConverter::FixNodeName(const std::string& name) { - // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if - // this causes ambiguities, well possible between empty identifiers, - // such as "Model::" and ""). Make sure the behaviour is consistent - // across multiple calls to FixNodeName(). - if (name.substr(0, 7) == "Model::") { - std::string temp = name.substr(7); - return temp; - } - - return name; - } - - std::string FBXConverter::FixAnimMeshName(const std::string& name) { - if (name.length()) { - size_t indexOf = name.find_first_of("::"); - if (indexOf != std::string::npos && indexOf < name.size() - 2) { - return name.substr(indexOf + 2); - } - } - return name.length() ? name : "AnimMesh"; - } - - void FBXConverter::ConvertAnimationStack(const AnimationStack& st) - { - const AnimationLayerList& layers = st.Layers(); - if (layers.empty()) { - return; - } - - aiAnimation* const anim = new aiAnimation(); - animations.push_back(anim); - - // strip AnimationStack:: prefix - std::string name = st.Name(); - if (name.substr(0, 16) == "AnimationStack::") { - name = name.substr(16); - } - else if (name.substr(0, 11) == "AnimStack::") { - name = name.substr(11); - } - - anim->mName.Set(name); - - // need to find all nodes for which we need to generate node animations - - // it may happen that we need to merge multiple layers, though. - NodeMap node_map; - - // reverse mapping from curves to layers, much faster than querying - // the FBX DOM for it. - LayerMap layer_map; - - const char* prop_whitelist[] = { - "Lcl Scaling", - "Lcl Rotation", - "Lcl Translation", - "DeformPercent" - }; - - std::map<std::string, morphAnimData*> morphAnimDatas; - - for (const AnimationLayer* layer : layers) { - ai_assert(layer); - const AnimationCurveNodeList& nodes = layer->Nodes(prop_whitelist, 4); - for (const AnimationCurveNode* node : nodes) { - ai_assert(node); - const Model* const model = dynamic_cast<const Model*>(node->Target()); - if (model) { - const std::string& name = FixNodeName(model->Name()); - node_map[name].push_back(node); - layer_map[node] = layer; - continue; - } - const BlendShapeChannel* const bsc = dynamic_cast<const BlendShapeChannel*>(node->Target()); - if (bsc) { - ProcessMorphAnimDatas(&morphAnimDatas, bsc, node); - } - } - } - - // generate node animations - std::vector<aiNodeAnim*> node_anims; - - double min_time = 1e10; - double max_time = -1e10; - - int64_t start_time = st.LocalStart(); - int64_t stop_time = st.LocalStop(); - bool has_local_startstop = start_time != 0 || stop_time != 0; - if (!has_local_startstop) { - // no time range given, so accept every keyframe and use the actual min/max time - // the numbers are INT64_MIN/MAX, the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000 - start_time = -9223372036854775807ll + 20000; - stop_time = 9223372036854775807ll - 20000; - } - - try { - for (const NodeMap::value_type& kv : node_map) { - GenerateNodeAnimations(node_anims, - kv.first, - kv.second, - layer_map, - start_time, stop_time, - max_time, - min_time); - } - } - catch (std::exception&) { - std::for_each(node_anims.begin(), node_anims.end(), Util::delete_fun<aiNodeAnim>()); - throw; - } - - if (node_anims.size() || morphAnimDatas.size()) { - if (node_anims.size()) { - anim->mChannels = new aiNodeAnim*[node_anims.size()](); - anim->mNumChannels = static_cast<unsigned int>(node_anims.size()); - std::swap_ranges(node_anims.begin(), node_anims.end(), anim->mChannels); - } - if (morphAnimDatas.size()) { - unsigned int numMorphMeshChannels = static_cast<unsigned int>(morphAnimDatas.size()); - anim->mMorphMeshChannels = new aiMeshMorphAnim*[numMorphMeshChannels]; - anim->mNumMorphMeshChannels = numMorphMeshChannels; - unsigned int i = 0; - for (auto morphAnimIt : morphAnimDatas) { - morphAnimData* animData = morphAnimIt.second; - unsigned int numKeys = static_cast<unsigned int>(animData->size()); - aiMeshMorphAnim* meshMorphAnim = new aiMeshMorphAnim(); - meshMorphAnim->mName.Set(morphAnimIt.first); - meshMorphAnim->mNumKeys = numKeys; - meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys]; - unsigned int j = 0; - for (auto animIt : *animData) { - morphKeyData* keyData = animIt.second; - unsigned int numValuesAndWeights = static_cast<unsigned int>(keyData->values.size()); - meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights; - meshMorphAnim->mKeys[j].mValues = new unsigned int[numValuesAndWeights]; - meshMorphAnim->mKeys[j].mWeights = new double[numValuesAndWeights]; - meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first) * anim_fps; - for (unsigned int k = 0; k < numValuesAndWeights; k++) { - meshMorphAnim->mKeys[j].mValues[k] = keyData->values.at(k); - meshMorphAnim->mKeys[j].mWeights[k] = keyData->weights.at(k); - } - j++; - } - anim->mMorphMeshChannels[i++] = meshMorphAnim; - } - } - } - else { - // empty animations would fail validation, so drop them - delete anim; - animations.pop_back(); - FBXImporter::LogInfo("ignoring empty AnimationStack (using IK?): " + name); - return; - } - - double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time; - double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time; - - // adjust relative timing for animation - for (unsigned int c = 0; c < anim->mNumChannels; c++) { - aiNodeAnim* channel = anim->mChannels[c]; - for (uint32_t i = 0; i < channel->mNumPositionKeys; i++) { - channel->mPositionKeys[i].mTime -= start_time_fps; - } - for (uint32_t i = 0; i < channel->mNumRotationKeys; i++) { - channel->mRotationKeys[i].mTime -= start_time_fps; - } - for (uint32_t i = 0; i < channel->mNumScalingKeys; i++) { - channel->mScalingKeys[i].mTime -= start_time_fps; - } - } - for (unsigned int c = 0; c < anim->mNumMorphMeshChannels; c++) { - aiMeshMorphAnim* channel = anim->mMorphMeshChannels[c]; - for (uint32_t i = 0; i < channel->mNumKeys; i++) { - channel->mKeys[i].mTime -= start_time_fps; - } - } - - // for some mysterious reason, mDuration is simply the maximum key -- the - // validator always assumes animations to start at zero. - anim->mDuration = stop_time_fps - start_time_fps; - anim->mTicksPerSecond = anim_fps; - } - - // ------------------------------------------------------------------------------------------------ - void FBXConverter::ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node) { - std::vector<const Connection*> bscConnections = doc.GetConnectionsBySourceSequenced(bsc->ID(), "Deformer"); - for (const Connection* bscConnection : bscConnections) { - auto bs = dynamic_cast<const BlendShape*>(bscConnection->DestinationObject()); - if (bs) { - auto channelIt = std::find(bs->BlendShapeChannels().begin(), bs->BlendShapeChannels().end(), bsc); - if (channelIt != bs->BlendShapeChannels().end()) { - auto channelIndex = static_cast<unsigned int>(std::distance(bs->BlendShapeChannels().begin(), channelIt)); - std::vector<const Connection*> bsConnections = doc.GetConnectionsBySourceSequenced(bs->ID(), "Geometry"); - for (const Connection* bsConnection : bsConnections) { - auto geo = dynamic_cast<const Geometry*>(bsConnection->DestinationObject()); - if (geo) { - std::vector<const Connection*> geoConnections = doc.GetConnectionsBySourceSequenced(geo->ID(), "Model"); - for (const Connection* geoConnection : geoConnections) { - auto model = dynamic_cast<const Model*>(geoConnection->DestinationObject()); - if (model) { - auto geoIt = std::find(model->GetGeometry().begin(), model->GetGeometry().end(), geo); - auto geoIndex = static_cast<unsigned int>(std::distance(model->GetGeometry().begin(), geoIt)); - auto name = aiString(FixNodeName(model->Name() + "*")); - name.length = 1 + ASSIMP_itoa10(name.data + name.length, MAXLEN - 1, geoIndex); - morphAnimData* animData; - auto animIt = morphAnimDatas->find(name.C_Str()); - if (animIt == morphAnimDatas->end()) { - animData = new morphAnimData(); - morphAnimDatas->insert(std::make_pair(name.C_Str(), animData)); - } - else { - animData = animIt->second; - } - for (std::pair<std::string, const AnimationCurve*> curvesIt : node->Curves()) { - if (curvesIt.first == "d|DeformPercent") { - const AnimationCurve* animationCurve = curvesIt.second; - const KeyTimeList& keys = animationCurve->GetKeys(); - const KeyValueList& values = animationCurve->GetValues(); - unsigned int k = 0; - for (auto key : keys) { - morphKeyData* keyData; - auto keyIt = animData->find(key); - if (keyIt == animData->end()) { - keyData = new morphKeyData(); - animData->insert(std::make_pair(key, keyData)); - } - else { - keyData = keyIt->second; - } - keyData->values.push_back(channelIndex); - keyData->weights.push_back(values.at(k) / 100.0f); - k++; - } - } - } - } - } - } - } - } - } - } - } - - // ------------------------------------------------------------------------------------------------ -#ifdef ASSIMP_BUILD_DEBUG - // ------------------------------------------------------------------------------------------------ - // sanity check whether the input is ok - static void validateAnimCurveNodes(const std::vector<const AnimationCurveNode*>& curves, - bool strictMode) { - const Object* target(nullptr); - for (const AnimationCurveNode* node : curves) { - if (!target) { - target = node->Target(); - } - if (node->Target() != target) { - FBXImporter::LogWarn("Node target is nullptr type."); - } - if (strictMode) { - ai_assert(node->Target() == target); - } - } - } -#endif // ASSIMP_BUILD_DEBUG - - // ------------------------------------------------------------------------------------------------ - void FBXConverter::GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims, - const std::string& fixed_name, - const std::vector<const AnimationCurveNode*>& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time) - { - - NodeMap node_property_map; - ai_assert(curves.size()); - -#ifdef ASSIMP_BUILD_DEBUG - validateAnimCurveNodes(curves, doc.Settings().strictMode); -#endif - const AnimationCurveNode* curve_node = nullptr; - for (const AnimationCurveNode* node : curves) { - ai_assert(node); - - if (node->TargetProperty().empty()) { - FBXImporter::LogWarn("target property for animation curve not set: " + node->Name()); - continue; - } - - curve_node = node; - if (node->Curves().empty()) { - FBXImporter::LogWarn("no animation curves assigned to AnimationCurveNode: " + node->Name()); - continue; - } - - node_property_map[node->TargetProperty()].push_back(node); - } - - ai_assert(curve_node); - ai_assert(curve_node->TargetAsModel()); - - const Model& target = *curve_node->TargetAsModel(); - - // check for all possible transformation components - NodeMap::const_iterator chain[TransformationComp_MAXIMUM]; - - bool has_any = false; - bool has_complex = false; - - for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { - const TransformationComp comp = static_cast<TransformationComp>(i); - - // inverse pivots don't exist in the input, we just generate them - if (comp == TransformationComp_RotationPivotInverse || comp == TransformationComp_ScalingPivotInverse) { - chain[i] = node_property_map.end(); - continue; - } - - chain[i] = node_property_map.find(NameTransformationCompProperty(comp)); - if (chain[i] != node_property_map.end()) { - - // check if this curves contains redundant information by looking - // up the corresponding node's transformation chain. - if (doc.Settings().optimizeEmptyAnimationCurves && - IsRedundantAnimationData(target, comp, (*chain[i]).second)) { - - FBXImporter::LogDebug("dropping redundant animation channel for node " + target.Name()); - continue; - } - - has_any = true; - - if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation) - { - has_complex = true; - } - } - } - - if (!has_any) { - FBXImporter::LogWarn("ignoring node animation, did not find any transformation key frames"); - return; - } - - // this needs to play nicely with GenerateTransformationNodeChain() which will - // be invoked _later_ (animations come first). If this node has only rotation, - // scaling and translation _and_ there are no animated other components either, - // we can use a single node and also a single node animation channel. - if (!has_complex && !NeedsComplexTransformationChain(target)) { - - aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain, - node_property_map.end(), - layer_map, - start, stop, - max_time, - min_time, - true // input is TRS order, assimp is SRT - ); - - ai_assert(nd); - if (nd->mNumPositionKeys == 0 && nd->mNumRotationKeys == 0 && nd->mNumScalingKeys == 0) { - delete nd; - } - else { - node_anims.push_back(nd); - } - return; - } - - // otherwise, things get gruesome and we need separate animation channels - // for each part of the transformation chain. Remember which channels - // we generated and pass this information to the node conversion - // code to avoid nodes that have identity transform, but non-identity - // animations, being dropped. - unsigned int flags = 0, bit = 0x1; - for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) { - const TransformationComp comp = static_cast<TransformationComp>(i); - - if (chain[i] != node_property_map.end()) { - flags |= bit; - - ai_assert(comp != TransformationComp_RotationPivotInverse); - ai_assert(comp != TransformationComp_ScalingPivotInverse); - - const std::string& chain_name = NameTransformationChainNode(fixed_name, comp); - - aiNodeAnim* na = nullptr; - switch (comp) - { - case TransformationComp_Rotation: - case TransformationComp_PreRotation: - case TransformationComp_PostRotation: - case TransformationComp_GeometricRotation: - na = GenerateRotationNodeAnim(chain_name, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time); - - break; - - case TransformationComp_RotationOffset: - case TransformationComp_RotationPivot: - case TransformationComp_ScalingOffset: - case TransformationComp_ScalingPivot: - case TransformationComp_Translation: - case TransformationComp_GeometricTranslation: - na = GenerateTranslationNodeAnim(chain_name, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time); - - // pivoting requires us to generate an implicit inverse channel to undo the pivot translation - if (comp == TransformationComp_RotationPivot) { - const std::string& invName = NameTransformationChainNode(fixed_name, - TransformationComp_RotationPivotInverse); - - aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time, - true); - - ai_assert(inv); - if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) { - delete inv; - } - else { - node_anims.push_back(inv); - } - - ai_assert(TransformationComp_RotationPivotInverse > i); - flags |= bit << (TransformationComp_RotationPivotInverse - i); - } - else if (comp == TransformationComp_ScalingPivot) { - const std::string& invName = NameTransformationChainNode(fixed_name, - TransformationComp_ScalingPivotInverse); - - aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time, - true); - - ai_assert(inv); - if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) { - delete inv; - } - else { - node_anims.push_back(inv); - } - - ai_assert(TransformationComp_RotationPivotInverse > i); - flags |= bit << (TransformationComp_RotationPivotInverse - i); - } - - break; - - case TransformationComp_Scaling: - case TransformationComp_GeometricScaling: - na = GenerateScalingNodeAnim(chain_name, - target, - (*chain[i]).second, - layer_map, - start, stop, - max_time, - min_time); - - break; - - default: - ai_assert(false); - } - - ai_assert(na); - if (na->mNumPositionKeys == 0 && na->mNumRotationKeys == 0 && na->mNumScalingKeys == 0) { - delete na; - } - else { - node_anims.push_back(na); - } - continue; - } - } - - node_anim_chain_bits[fixed_name] = flags; - } - - - bool FBXConverter::IsRedundantAnimationData(const Model& target, - TransformationComp comp, - const std::vector<const AnimationCurveNode*>& curves) { - ai_assert(curves.size()); - - // look for animation nodes with - // * sub channels for all relevant components set - // * one key/value pair per component - // * combined values match up the corresponding value in the bind pose node transformation - // only such nodes are 'redundant' for this function. - - if (curves.size() > 1) { - return false; - } - - const AnimationCurveNode& nd = *curves.front(); - const AnimationCurveMap& sub_curves = nd.Curves(); - - const AnimationCurveMap::const_iterator dx = sub_curves.find("d|X"); - const AnimationCurveMap::const_iterator dy = sub_curves.find("d|Y"); - const AnimationCurveMap::const_iterator dz = sub_curves.find("d|Z"); - - if (dx == sub_curves.end() || dy == sub_curves.end() || dz == sub_curves.end()) { - return false; - } - - const KeyValueList& vx = (*dx).second->GetValues(); - const KeyValueList& vy = (*dy).second->GetValues(); - const KeyValueList& vz = (*dz).second->GetValues(); - - if (vx.size() != 1 || vy.size() != 1 || vz.size() != 1) { - return false; - } - - const aiVector3D dyn_val = aiVector3D(vx[0], vy[0], vz[0]); - const aiVector3D& static_val = PropertyGet<aiVector3D>(target.Props(), - NameTransformationCompProperty(comp), - TransformationCompDefaultValue(comp) - ); - - const float epsilon = Math::getEpsilon<float>(); - return (dyn_val - static_val).SquareLength() < epsilon; - } - - - aiNodeAnim* FBXConverter::GenerateRotationNodeAnim(const std::string& name, - const Model& target, - const std::vector<const AnimationCurveNode*>& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time) - { - std::unique_ptr<aiNodeAnim> na(new aiNodeAnim()); - na->mNodeName.Set(name); - - ConvertRotationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time, target.RotationOrder()); - - // dummy scaling key - na->mScalingKeys = new aiVectorKey[1]; - na->mNumScalingKeys = 1; - - na->mScalingKeys[0].mTime = 0.; - na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f); - - // dummy position key - na->mPositionKeys = new aiVectorKey[1]; - na->mNumPositionKeys = 1; - - na->mPositionKeys[0].mTime = 0.; - na->mPositionKeys[0].mValue = aiVector3D(); - - return na.release(); - } - - aiNodeAnim* FBXConverter::GenerateScalingNodeAnim(const std::string& name, - const Model& /*target*/, - const std::vector<const AnimationCurveNode*>& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time) - { - std::unique_ptr<aiNodeAnim> na(new aiNodeAnim()); - na->mNodeName.Set(name); - - ConvertScaleKeys(na.get(), curves, layer_map, start, stop, max_time, min_time); - - // dummy rotation key - na->mRotationKeys = new aiQuatKey[1]; - na->mNumRotationKeys = 1; - - na->mRotationKeys[0].mTime = 0.; - na->mRotationKeys[0].mValue = aiQuaternion(); - - // dummy position key - na->mPositionKeys = new aiVectorKey[1]; - na->mNumPositionKeys = 1; - - na->mPositionKeys[0].mTime = 0.; - na->mPositionKeys[0].mValue = aiVector3D(); - - return na.release(); - } - - aiNodeAnim* FBXConverter::GenerateTranslationNodeAnim(const std::string& name, - const Model& /*target*/, - const std::vector<const AnimationCurveNode*>& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool inverse) { - std::unique_ptr<aiNodeAnim> na(new aiNodeAnim()); - na->mNodeName.Set(name); - - ConvertTranslationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time); - - if (inverse) { - for (unsigned int i = 0; i < na->mNumPositionKeys; ++i) { - na->mPositionKeys[i].mValue *= -1.0f; - } - } - - // dummy scaling key - na->mScalingKeys = new aiVectorKey[1]; - na->mNumScalingKeys = 1; - - na->mScalingKeys[0].mTime = 0.; - na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f); - - // dummy rotation key - na->mRotationKeys = new aiQuatKey[1]; - na->mNumRotationKeys = 1; - - na->mRotationKeys[0].mTime = 0.; - na->mRotationKeys[0].mValue = aiQuaternion(); - - return na.release(); - } - - aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, - const Model& target, - NodeMap::const_iterator chain[TransformationComp_MAXIMUM], - NodeMap::const_iterator iter_end, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool reverse_order) - - { - std::unique_ptr<aiNodeAnim> na(new aiNodeAnim()); - na->mNodeName.Set(name); - - const PropertyTable& props = target.Props(); - - // need to convert from TRS order to SRT? - if (reverse_order) { - - aiVector3D def_scale = PropertyGet(props, "Lcl Scaling", aiVector3D(1.f, 1.f, 1.f)); - aiVector3D def_translate = PropertyGet(props, "Lcl Translation", aiVector3D(0.f, 0.f, 0.f)); - aiVector3D def_rot = PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f)); - - KeyFrameListList scaling; - KeyFrameListList translation; - KeyFrameListList rotation; - - if (chain[TransformationComp_Scaling] != iter_end) { - scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second, start, stop); - } - - if (chain[TransformationComp_Translation] != iter_end) { - translation = GetKeyframeList((*chain[TransformationComp_Translation]).second, start, stop); - } - - if (chain[TransformationComp_Rotation] != iter_end) { - rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second, start, stop); - } - - KeyFrameListList joined; - joined.insert(joined.end(), scaling.begin(), scaling.end()); - joined.insert(joined.end(), translation.begin(), translation.end()); - joined.insert(joined.end(), rotation.begin(), rotation.end()); - - const KeyTimeList& times = GetKeyTimeList(joined); - - aiQuatKey* out_quat = new aiQuatKey[times.size()]; - aiVectorKey* out_scale = new aiVectorKey[times.size()]; - aiVectorKey* out_translation = new aiVectorKey[times.size()]; - - if (times.size()) - { - ConvertTransformOrder_TRStoSRT(out_quat, out_scale, out_translation, - scaling, - translation, - rotation, - times, - max_time, - min_time, - target.RotationOrder(), - def_scale, - def_translate, - def_rot); - } - - // XXX remove duplicates / redundant keys which this operation did - // likely produce if not all three channels were equally dense. - - na->mNumScalingKeys = static_cast<unsigned int>(times.size()); - na->mNumRotationKeys = na->mNumScalingKeys; - na->mNumPositionKeys = na->mNumScalingKeys; - - na->mScalingKeys = out_scale; - na->mRotationKeys = out_quat; - na->mPositionKeys = out_translation; - } - else { - - // if a particular transformation is not given, grab it from - // the corresponding node to meet the semantics of aiNodeAnim, - // which requires all of rotation, scaling and translation - // to be set. - if (chain[TransformationComp_Scaling] != iter_end) { - ConvertScaleKeys(na.get(), (*chain[TransformationComp_Scaling]).second, - layer_map, - start, stop, - max_time, - min_time); - } - else { - na->mScalingKeys = new aiVectorKey[1]; - na->mNumScalingKeys = 1; - - na->mScalingKeys[0].mTime = 0.; - na->mScalingKeys[0].mValue = PropertyGet(props, "Lcl Scaling", - aiVector3D(1.f, 1.f, 1.f)); - } - - if (chain[TransformationComp_Rotation] != iter_end) { - ConvertRotationKeys(na.get(), (*chain[TransformationComp_Rotation]).second, - layer_map, - start, stop, - max_time, - min_time, - target.RotationOrder()); - } - else { - na->mRotationKeys = new aiQuatKey[1]; - na->mNumRotationKeys = 1; - - na->mRotationKeys[0].mTime = 0.; - na->mRotationKeys[0].mValue = EulerToQuaternion( - PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f)), - target.RotationOrder()); - } - - if (chain[TransformationComp_Translation] != iter_end) { - ConvertTranslationKeys(na.get(), (*chain[TransformationComp_Translation]).second, - layer_map, - start, stop, - max_time, - min_time); - } - else { - na->mPositionKeys = new aiVectorKey[1]; - na->mNumPositionKeys = 1; - - na->mPositionKeys[0].mTime = 0.; - na->mPositionKeys[0].mValue = PropertyGet(props, "Lcl Translation", - aiVector3D(0.f, 0.f, 0.f)); - } - - } - return na.release(); - } - - FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop) - { - KeyFrameListList inputs; - inputs.reserve(nodes.size() * 3); - - //give some breathing room for rounding errors - int64_t adj_start = start - 10000; - int64_t adj_stop = stop + 10000; - - for (const AnimationCurveNode* node : nodes) { - ai_assert(node); - - const AnimationCurveMap& curves = node->Curves(); - for (const AnimationCurveMap::value_type& kv : curves) { - - unsigned int mapto; - if (kv.first == "d|X") { - mapto = 0; - } - else if (kv.first == "d|Y") { - mapto = 1; - } - else if (kv.first == "d|Z") { - mapto = 2; - } - else { - FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component"); - continue; - } - - const AnimationCurve* const curve = kv.second; - ai_assert(curve->GetKeys().size() == curve->GetValues().size() && curve->GetKeys().size()); - - //get values within the start/stop time window - std::shared_ptr<KeyTimeList> Keys(new KeyTimeList()); - std::shared_ptr<KeyValueList> Values(new KeyValueList()); - const size_t count = curve->GetKeys().size(); - Keys->reserve(count); - Values->reserve(count); - for (size_t n = 0; n < count; n++) - { - int64_t k = curve->GetKeys().at(n); - if (k >= adj_start && k <= adj_stop) - { - Keys->push_back(k); - Values->push_back(curve->GetValues().at(n)); - } - } - - inputs.push_back(std::make_tuple(Keys, Values, mapto)); - } - } - return inputs; // pray for NRVO :-) - } - - - KeyTimeList FBXConverter::GetKeyTimeList(const KeyFrameListList& inputs) { - ai_assert(!inputs.empty()); - - // reserve some space upfront - it is likely that the key-frame lists - // have matching time values, so max(of all key-frame lists) should - // be a good estimate. - KeyTimeList keys; - - size_t estimate = 0; - for (const KeyFrameList& kfl : inputs) { - estimate = std::max(estimate, std::get<0>(kfl)->size()); - } - - keys.reserve(estimate); - - std::vector<unsigned int> next_pos; - next_pos.resize(inputs.size(), 0); - - const size_t count = inputs.size(); - while (true) { - - int64_t min_tick = std::numeric_limits<int64_t>::max(); - for (size_t i = 0; i < count; ++i) { - const KeyFrameList& kfl = inputs[i]; - - if (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) < min_tick) { - min_tick = std::get<0>(kfl)->at(next_pos[i]); - } - } - - if (min_tick == std::numeric_limits<int64_t>::max()) { - break; - } - keys.push_back(min_tick); - - for (size_t i = 0; i < count; ++i) { - const KeyFrameList& kfl = inputs[i]; - - - while (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == min_tick) { - ++next_pos[i]; - } - } - } - - return keys; - } - - void FBXConverter::InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& max_time, - double& min_time) { - ai_assert(!keys.empty()); - ai_assert(nullptr != valOut); - - std::vector<unsigned int> next_pos; - const size_t count(inputs.size()); - - next_pos.resize(inputs.size(), 0); - - for (KeyTimeList::value_type time : keys) { - ai_real result[3] = { def_value.x, def_value.y, def_value.z }; - - for (size_t i = 0; i < count; ++i) { - const KeyFrameList& kfl = inputs[i]; - - const size_t ksize = std::get<0>(kfl)->size(); - if (ksize == 0) { - continue; - } - if (ksize > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == time) { - ++next_pos[i]; - } - - const size_t id0 = next_pos[i] > 0 ? next_pos[i] - 1 : 0; - const size_t id1 = next_pos[i] == ksize ? ksize - 1 : next_pos[i]; - - // use lerp for interpolation - const KeyValueList::value_type valueA = std::get<1>(kfl)->at(id0); - const KeyValueList::value_type valueB = std::get<1>(kfl)->at(id1); - - const KeyTimeList::value_type timeA = std::get<0>(kfl)->at(id0); - const KeyTimeList::value_type timeB = std::get<0>(kfl)->at(id1); - - const ai_real factor = timeB == timeA ? ai_real(0.) : static_cast<ai_real>((time - timeA)) / (timeB - timeA); - const ai_real interpValue = static_cast<ai_real>(valueA + (valueB - valueA) * factor); - - result[std::get<2>(kfl)] = interpValue; - } - - // magic value to convert fbx times to seconds - valOut->mTime = CONVERT_FBX_TIME(time) * anim_fps; - - min_time = std::min(min_time, valOut->mTime); - max_time = std::max(max_time, valOut->mTime); - - valOut->mValue.x = result[0]; - valOut->mValue.y = result[1]; - valOut->mValue.z = result[2]; - - ++valOut; - } - } - - void FBXConverter::InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& maxTime, - double& minTime, - Model::RotOrder order) - { - ai_assert(!keys.empty()); - ai_assert(nullptr != valOut); - - std::unique_ptr<aiVectorKey[]> temp(new aiVectorKey[keys.size()]); - InterpolateKeys(temp.get(), keys, inputs, def_value, maxTime, minTime); - - aiMatrix4x4 m; - - aiQuaternion lastq; - - for (size_t i = 0, c = keys.size(); i < c; ++i) { - - valOut[i].mTime = temp[i].mTime; - - GetRotationMatrix(order, temp[i].mValue, m); - aiQuaternion quat = aiQuaternion(aiMatrix3x3(m)); - - // take shortest path by checking the inner product - // http://www.3dkingdoms.com/weekly/weekly.php?a=36 - if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0) - { - quat.x = -quat.x; - quat.y = -quat.y; - quat.z = -quat.z; - quat.w = -quat.w; - } - lastq = quat; - - valOut[i].mValue = quat; - } - } - - void FBXConverter::ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale, - aiVectorKey* out_translation, - const KeyFrameListList& scaling, - const KeyFrameListList& translation, - const KeyFrameListList& rotation, - const KeyTimeList& times, - double& maxTime, - double& minTime, - Model::RotOrder order, - const aiVector3D& def_scale, - const aiVector3D& def_translate, - const aiVector3D& def_rotation) - { - if (rotation.size()) { - InterpolateKeys(out_quat, times, rotation, def_rotation, maxTime, minTime, order); - } - else { - for (size_t i = 0; i < times.size(); ++i) { - out_quat[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; - out_quat[i].mValue = EulerToQuaternion(def_rotation, order); - } - } - - if (scaling.size()) { - InterpolateKeys(out_scale, times, scaling, def_scale, maxTime, minTime); - } - else { - for (size_t i = 0; i < times.size(); ++i) { - out_scale[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; - out_scale[i].mValue = def_scale; - } - } - - if (translation.size()) { - InterpolateKeys(out_translation, times, translation, def_translate, maxTime, minTime); - } - else { - for (size_t i = 0; i < times.size(); ++i) { - out_translation[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; - out_translation[i].mValue = def_translate; - } - } - - const size_t count = times.size(); - for (size_t i = 0; i < count; ++i) { - aiQuaternion& r = out_quat[i].mValue; - aiVector3D& s = out_scale[i].mValue; - aiVector3D& t = out_translation[i].mValue; - - aiMatrix4x4 mat, temp; - aiMatrix4x4::Translation(t, mat); - mat *= aiMatrix4x4(r.GetMatrix()); - mat *= aiMatrix4x4::Scaling(s, temp); - - mat.Decompose(s, r, t); - } - } - - aiQuaternion FBXConverter::EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order) - { - aiMatrix4x4 m; - GetRotationMatrix(order, rot, m); - - return aiQuaternion(aiMatrix3x3(m)); - } - - void FBXConverter::ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime) - { - ai_assert(nodes.size()); - - // XXX for now, assume scale should be blended geometrically (i.e. two - // layers should be multiplied with each other). There is a FBX - // property in the layer to specify the behaviour, though. - - const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop); - const KeyTimeList& keys = GetKeyTimeList(inputs); - - na->mNumScalingKeys = static_cast<unsigned int>(keys.size()); - na->mScalingKeys = new aiVectorKey[keys.size()]; - if (keys.size() > 0) { - InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime); - } - } - - void FBXConverter::ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime) - { - ai_assert(nodes.size()); - - // XXX see notes in ConvertScaleKeys() - const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop); - const KeyTimeList& keys = GetKeyTimeList(inputs); - - na->mNumPositionKeys = static_cast<unsigned int>(keys.size()); - na->mPositionKeys = new aiVectorKey[keys.size()]; - if (keys.size() > 0) - InterpolateKeys(na->mPositionKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime); - } - - void FBXConverter::ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime, - Model::RotOrder order) - { - ai_assert(nodes.size()); - - // XXX see notes in ConvertScaleKeys() - const std::vector< KeyFrameList >& inputs = GetKeyframeList(nodes, start, stop); - const KeyTimeList& keys = GetKeyTimeList(inputs); - - na->mNumRotationKeys = static_cast<unsigned int>(keys.size()); - na->mRotationKeys = new aiQuatKey[keys.size()]; - if (!keys.empty()) { - InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order); - } - } - - void FBXConverter::ConvertGlobalSettings() { - if (nullptr == out) { - return; - } - - out->mMetaData = aiMetadata::Alloc(15); - out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis()); - out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign()); - out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis()); - out->mMetaData->Set(3, "FrontAxisSign", doc.GlobalSettings().FrontAxisSign()); - out->mMetaData->Set(4, "CoordAxis", doc.GlobalSettings().CoordAxis()); - out->mMetaData->Set(5, "CoordAxisSign", doc.GlobalSettings().CoordAxisSign()); - out->mMetaData->Set(6, "OriginalUpAxis", doc.GlobalSettings().OriginalUpAxis()); - out->mMetaData->Set(7, "OriginalUpAxisSign", doc.GlobalSettings().OriginalUpAxisSign()); - out->mMetaData->Set(8, "UnitScaleFactor", (double)doc.GlobalSettings().UnitScaleFactor()); - out->mMetaData->Set(9, "OriginalUnitScaleFactor", doc.GlobalSettings().OriginalUnitScaleFactor()); - out->mMetaData->Set(10, "AmbientColor", doc.GlobalSettings().AmbientColor()); - out->mMetaData->Set(11, "FrameRate", (int)doc.GlobalSettings().TimeMode()); - out->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart()); - out->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop()); - out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate()); - } - - void FBXConverter::TransferDataToScene() - { - ai_assert(!out->mMeshes); - ai_assert(!out->mNumMeshes); - - // note: the trailing () ensures initialization with nullptr - not - // many C++ users seem to know this, so pointing it out to avoid - // confusion why this code works. - - if (meshes.size()) { - out->mMeshes = new aiMesh*[meshes.size()](); - out->mNumMeshes = static_cast<unsigned int>(meshes.size()); - - std::swap_ranges(meshes.begin(), meshes.end(), out->mMeshes); - } - - if (materials.size()) { - out->mMaterials = new aiMaterial*[materials.size()](); - out->mNumMaterials = static_cast<unsigned int>(materials.size()); - - std::swap_ranges(materials.begin(), materials.end(), out->mMaterials); - } - - if (animations.size()) { - out->mAnimations = new aiAnimation*[animations.size()](); - out->mNumAnimations = static_cast<unsigned int>(animations.size()); - - std::swap_ranges(animations.begin(), animations.end(), out->mAnimations); - } - - if (lights.size()) { - out->mLights = new aiLight*[lights.size()](); - out->mNumLights = static_cast<unsigned int>(lights.size()); - - std::swap_ranges(lights.begin(), lights.end(), out->mLights); - } - - if (cameras.size()) { - out->mCameras = new aiCamera*[cameras.size()](); - out->mNumCameras = static_cast<unsigned int>(cameras.size()); - - std::swap_ranges(cameras.begin(), cameras.end(), out->mCameras); - } - - if (textures.size()) { - out->mTextures = new aiTexture*[textures.size()](); - out->mNumTextures = static_cast<unsigned int>(textures.size()); - - std::swap_ranges(textures.begin(), textures.end(), out->mTextures); - } - } - - void FBXConverter::ConvertOrphantEmbeddedTextures() - { - // in C++14 it could be: - // for (auto&& [id, object] : objects) - for (auto&& id_and_object : doc.Objects()) - { - auto&& id = std::get<0>(id_and_object); - auto&& object = std::get<1>(id_and_object); - // If an object doesn't have parent - if (doc.ConnectionsBySource().count(id) == 0) - { - const Texture* realTexture = nullptr; - try - { - const auto& element = object->GetElement(); - const Token& key = element.KeyToken(); - const char* obtype = key.begin(); - const size_t length = static_cast<size_t>(key.end() - key.begin()); - if (strncmp(obtype, "Texture", length) == 0) - { - const Texture* texture = static_cast<const Texture*>(object->Get()); - if (texture->Media() && texture->Media()->ContentLength() > 0) - { - realTexture = texture; - } - } - } - catch (...) - { - // do nothing - } - if (realTexture) - { - const Video* media = realTexture->Media(); - unsigned int index = ConvertVideo(*media); - textures_converted[*media] = index; - } - } - } - } - - // ------------------------------------------------------------------------------------------------ - void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones) - { - FBXConverter converter(out, doc, removeEmptyBones); - } - - } // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXConverter.h b/thirdparty/assimp/code/FBX/FBXConverter.h deleted file mode 100644 index 46693bdca6..0000000000 --- a/thirdparty/assimp/code/FBX/FBXConverter.h +++ /dev/null @@ -1,491 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXDConverter.h - * @brief FBX DOM to aiScene conversion - */ -#ifndef INCLUDED_AI_FBX_CONVERTER_H -#define INCLUDED_AI_FBX_CONVERTER_H - -#include "FBXParser.h" -#include "FBXMeshGeometry.h" -#include "FBXDocument.h" -#include "FBXUtil.h" -#include "FBXProperties.h" -#include "FBXImporter.h" - -#include <assimp/anim.h> -#include <assimp/material.h> -#include <assimp/light.h> -#include <assimp/texture.h> -#include <assimp/camera.h> -#include <assimp/StringComparison.h> -#include <unordered_map> -#include <unordered_set> - -struct aiScene; -struct aiNode; -struct aiMaterial; - -struct morphKeyData { - std::vector<unsigned int> values; - std::vector<float> weights; -}; -typedef std::map<int64_t, morphKeyData*> morphAnimData; - -namespace Assimp { -namespace FBX { - -class Document; -/** - * Convert a FBX #Document to #aiScene - * @param out Empty scene to be populated - * @param doc Parsed FBX document - * @param removeEmptyBones Will remove bones, which do not have any references to vertices. - */ -void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones); - -/** Dummy class to encapsulate the conversion process */ -class FBXConverter { -public: - /** - * The different parts that make up the final local transformation of a fbx-node - */ - enum TransformationComp { - TransformationComp_GeometricScalingInverse = 0, - TransformationComp_GeometricRotationInverse, - TransformationComp_GeometricTranslationInverse, - TransformationComp_Translation, - TransformationComp_RotationOffset, - TransformationComp_RotationPivot, - TransformationComp_PreRotation, - TransformationComp_Rotation, - TransformationComp_PostRotation, - TransformationComp_RotationPivotInverse, - TransformationComp_ScalingOffset, - TransformationComp_ScalingPivot, - TransformationComp_Scaling, - TransformationComp_ScalingPivotInverse, - TransformationComp_GeometricTranslation, - TransformationComp_GeometricRotation, - TransformationComp_GeometricScaling, - - TransformationComp_MAXIMUM - }; - -public: - FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones); - ~FBXConverter(); - -private: - // ------------------------------------------------------------------------------------------------ - // find scene root and trigger recursive scene conversion - void ConvertRootNode(); - - // ------------------------------------------------------------------------------------------------ - // collect and assign child nodes - void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node); - - // ------------------------------------------------------------------------------------------------ - void ConvertLights(const Model& model, const std::string &orig_name ); - - // ------------------------------------------------------------------------------------------------ - void ConvertCameras(const Model& model, const std::string &orig_name ); - - // ------------------------------------------------------------------------------------------------ - void ConvertLight( const Light& light, const std::string &orig_name ); - - // ------------------------------------------------------------------------------------------------ - void ConvertCamera( const Camera& cam, const std::string &orig_name ); - - // ------------------------------------------------------------------------------------------------ - void GetUniqueName( const std::string &name, std::string& uniqueName ); - - // ------------------------------------------------------------------------------------------------ - // this returns unified names usable within assimp identifiers (i.e. no space characters - - // while these would be allowed, they are a potential trouble spot so better not use them). - const char* NameTransformationComp(TransformationComp comp); - - // ------------------------------------------------------------------------------------------------ - // Returns an unique name for a node or traverses up a hierarchy until a non-empty name is found and - // then makes this name unique - std::string MakeUniqueNodeName(const Model* const model, const aiNode& parent); - - // ------------------------------------------------------------------------------------------------ - // note: this returns the REAL fbx property names - const char* NameTransformationCompProperty(TransformationComp comp); - - // ------------------------------------------------------------------------------------------------ - aiVector3D TransformationCompDefaultValue(TransformationComp comp); - - // ------------------------------------------------------------------------------------------------ - void GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out); - // ------------------------------------------------------------------------------------------------ - /** - * checks if a node has more than just scaling, rotation and translation components - */ - bool NeedsComplexTransformationChain(const Model& model); - - // ------------------------------------------------------------------------------------------------ - // note: name must be a FixNodeName() result - std::string NameTransformationChainNode(const std::string& name, TransformationComp comp); - - // ------------------------------------------------------------------------------------------------ - /** - * note: memory for output_nodes will be managed by the caller - */ - bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes); - - // ------------------------------------------------------------------------------------------------ - void SetupNodeMetadata(const Model& model, aiNode& nd); - - // ------------------------------------------------------------------------------------------------ - void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform); - - // ------------------------------------------------------------------------------------------------ - // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed - std::vector<unsigned int> - ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform); - - // ------------------------------------------------------------------------------------------------ - std::vector<unsigned int> ConvertLine(const LineGeometry& line, const Model& model, - aiNode *parent, aiNode *root_node); - - // ------------------------------------------------------------------------------------------------ - aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent); - - // ------------------------------------------------------------------------------------------------ - unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model, - const aiMatrix4x4 &absolute_transform, aiNode *parent, - aiNode *root_node); - - // ------------------------------------------------------------------------------------------------ - std::vector<unsigned int> - ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node, - const aiMatrix4x4 &absolute_transform); - - // ------------------------------------------------------------------------------------------------ - unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index, - aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform); - - // ------------------------------------------------------------------------------------------------ - static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */ - static_cast<unsigned int>(-1); - - // ------------------------------------------------------------------------------------------------ - /** - * - if materialIndex == NO_MATERIAL_SEPARATION, materials are not taken into - * account when determining which weights to include. - * - outputVertStartIndices is only used when a material index is specified, it gives for - * each output vertex the DOM index it maps to. - */ - void ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform, - aiNode *parent = NULL, aiNode *root_node = NULL, - unsigned int materialIndex = NO_MATERIAL_SEPARATION, - std::vector<unsigned int> *outputVertStartIndices = NULL); - // lookup - static const aiNode* GetNodeByName( const aiString& name, aiNode *current_node ); - // ------------------------------------------------------------------------------------------------ - void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl, - std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices, - std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform, - aiNode *parent, aiNode *root_node); - - // ------------------------------------------------------------------------------------------------ - void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, - MatIndexArray::value_type materialIndex); - - // ------------------------------------------------------------------------------------------------ - unsigned int GetDefaultMaterial(); - - // ------------------------------------------------------------------------------------------------ - // Material -> aiMaterial - unsigned int ConvertMaterial(const Material& material, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - // Video -> aiTexture - unsigned int ConvertVideo(const Video& video); - - // ------------------------------------------------------------------------------------------------ - // convert embedded texture if necessary and return actual texture path - aiString GetTexturePath(const Texture* tex); - - // ------------------------------------------------------------------------------------------------ - void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - aiColor3D GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName, - bool& result); - aiColor3D GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName, - const std::string& factorName, bool& result, bool useTemplate = true); - aiColor3D GetColorProperty(const PropertyTable& props, const std::string& colorName, - bool& result, bool useTemplate = true); - - // ------------------------------------------------------------------------------------------------ - void SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props); - void SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh); - - // ------------------------------------------------------------------------------------------------ - // get the number of fps for a FrameRate enumerated value - static double FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal = -1.0); - - // ------------------------------------------------------------------------------------------------ - // convert animation data to aiAnimation et al - void ConvertAnimations(); - - // ------------------------------------------------------------------------------------------------ - // takes a fbx node name and returns the identifier to be used in the assimp output scene. - // the function is guaranteed to provide consistent results over multiple invocations - // UNLESS RenameNode() is called for a particular node name. - std::string FixNodeName(const std::string& name); - std::string FixAnimMeshName(const std::string& name); - - typedef std::map<const AnimationCurveNode*, const AnimationLayer*> LayerMap; - - // XXX: better use multi_map .. - typedef std::map<std::string, std::vector<const AnimationCurveNode*> > NodeMap; - - // ------------------------------------------------------------------------------------------------ - void ConvertAnimationStack(const AnimationStack& st); - - // ------------------------------------------------------------------------------------------------ - void ProcessMorphAnimDatas(std::map<std::string, morphAnimData*>* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node); - - // ------------------------------------------------------------------------------------------------ - void GenerateNodeAnimations(std::vector<aiNodeAnim*>& node_anims, - const std::string& fixed_name, - const std::vector<const AnimationCurveNode*>& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time); - - // ------------------------------------------------------------------------------------------------ - bool IsRedundantAnimationData(const Model& target, - TransformationComp comp, - const std::vector<const AnimationCurveNode*>& curves); - - // ------------------------------------------------------------------------------------------------ - aiNodeAnim* GenerateRotationNodeAnim(const std::string& name, - const Model& target, - const std::vector<const AnimationCurveNode*>& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time); - - // ------------------------------------------------------------------------------------------------ - aiNodeAnim* GenerateScalingNodeAnim(const std::string& name, - const Model& /*target*/, - const std::vector<const AnimationCurveNode*>& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time); - - // ------------------------------------------------------------------------------------------------ - aiNodeAnim* GenerateTranslationNodeAnim(const std::string& name, - const Model& /*target*/, - const std::vector<const AnimationCurveNode*>& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool inverse = false); - - // ------------------------------------------------------------------------------------------------ - // generate node anim, extracting only Rotation, Scaling and Translation from the given chain - aiNodeAnim* GenerateSimpleNodeAnim(const std::string& name, - const Model& target, - NodeMap::const_iterator chain[TransformationComp_MAXIMUM], - NodeMap::const_iterator iter_end, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool reverse_order = false); - - // key (time), value, mapto (component index) - typedef std::tuple<std::shared_ptr<KeyTimeList>, std::shared_ptr<KeyValueList>, unsigned int > KeyFrameList; - typedef std::vector<KeyFrameList> KeyFrameListList; - - // ------------------------------------------------------------------------------------------------ - KeyFrameListList GetKeyframeList(const std::vector<const AnimationCurveNode*>& nodes, int64_t start, int64_t stop); - - // ------------------------------------------------------------------------------------------------ - KeyTimeList GetKeyTimeList(const KeyFrameListList& inputs); - - // ------------------------------------------------------------------------------------------------ - void InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& max_time, - double& min_time); - - // ------------------------------------------------------------------------------------------------ - void InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& maxTime, - double& minTime, - Model::RotOrder order); - - // ------------------------------------------------------------------------------------------------ - void ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale, - aiVectorKey* out_translation, - const KeyFrameListList& scaling, - const KeyFrameListList& translation, - const KeyFrameListList& rotation, - const KeyTimeList& times, - double& maxTime, - double& minTime, - Model::RotOrder order, - const aiVector3D& def_scale, - const aiVector3D& def_translate, - const aiVector3D& def_rotation); - - // ------------------------------------------------------------------------------------------------ - // euler xyz -> quat - aiQuaternion EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order); - - // ------------------------------------------------------------------------------------------------ - void ConvertScaleKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime); - - // ------------------------------------------------------------------------------------------------ - void ConvertTranslationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime); - - // ------------------------------------------------------------------------------------------------ - void ConvertRotationKeys(aiNodeAnim* na, const std::vector<const AnimationCurveNode*>& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime, - Model::RotOrder order); - - void ConvertGlobalSettings(); - - // ------------------------------------------------------------------------------------------------ - // copy generated meshes, animations, lights, cameras and textures to the output scene - void TransferDataToScene(); - - // ------------------------------------------------------------------------------------------------ - // FBX file could have embedded textures not connected to anything - void ConvertOrphantEmbeddedTextures(); - -private: - // 0: not assigned yet, others: index is value - 1 - unsigned int defaultMaterialIndex; - - std::vector<aiMesh*> meshes; - std::vector<aiMaterial*> materials; - std::vector<aiAnimation*> animations; - std::vector<aiLight*> lights; - std::vector<aiCamera*> cameras; - std::vector<aiTexture*> textures; - - using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>; - MaterialMap materials_converted; - - using VideoMap = std::fbx_unordered_map<const Video, unsigned int>; - VideoMap textures_converted; - - using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >; - MeshMap meshes_converted; - - // fixed node name -> which trafo chain components have animations? - using NodeAnimBitMap = std::fbx_unordered_map<std::string, unsigned int> ; - NodeAnimBitMap node_anim_chain_bits; - - // number of nodes with the same name - using NodeNameCache = std::fbx_unordered_map<std::string, unsigned int>; - NodeNameCache mNodeNames; - - // Deformer name is not the same as a bone name - it does contain the bone name though :) - // Deformer names in FBX are always unique in an FBX file. - std::map<const std::string, aiBone *> bone_map; - - double anim_fps; - - aiScene* const out; - const FBX::Document& doc; - - static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene, - std::vector<aiBone*>& bones); - - void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene, - const std::vector<aiBone *> &bones, - std::map<aiBone *, aiNode *> &bone_stack, - std::vector<aiNode*> &node_stack ); - - static void BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes); - - static aiNode *GetNodeFromStack(const aiString &node_name, std::vector<aiNode *> &nodes); - - static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list); - - static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones); -}; - -} -} - -#endif // INCLUDED_AI_FBX_CONVERTER_H diff --git a/thirdparty/assimp/code/FBX/FBXDeformer.cpp b/thirdparty/assimp/code/FBX/FBXDeformer.cpp deleted file mode 100644 index 6927553450..0000000000 --- a/thirdparty/assimp/code/FBX/FBXDeformer.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXNoteAttribute.cpp - * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXMeshGeometry.h" -#include "FBXImporter.h" -#include "FBXDocumentUtil.h" - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Deformer::Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name) - : Object(id,element,name) -{ - const Scope& sc = GetRequiredScope(element); - - const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2)); - props = GetPropertyTable(doc,"Deformer.Fbx" + classname,element,sc,true); -} - - -// ------------------------------------------------------------------------------------------------ -Deformer::~Deformer() -{ - -} - - -// ------------------------------------------------------------------------------------------------ -Cluster::Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Deformer(id,element,doc,name) -, node() -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const Indexes = sc["Indexes"]; - const Element* const Weights = sc["Weights"]; - - const Element& Transform = GetRequiredElement(sc,"Transform",&element); - const Element& TransformLink = GetRequiredElement(sc,"TransformLink",&element); - - transform = ReadMatrix(Transform); - transformLink = ReadMatrix(TransformLink); - - // it is actually possible that there be Deformer's with no weights - if (!!Indexes != !!Weights) { - DOMError("either Indexes or Weights are missing from Cluster",&element); - } - - if(Indexes) { - ParseVectorDataArray(indices,*Indexes); - ParseVectorDataArray(weights,*Weights); - } - - if(indices.size() != weights.size()) { - DOMError("sizes of index and weight array don't match up",&element); - } - - // read assigned node - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Model"); - for(const Connection* con : conns) { - const Model* const mod = ProcessSimpleConnection<Model>(*con, false, "Model -> Cluster", element); - if(mod) { - node = mod; - break; - } - } - - if (!node) { - DOMError("failed to read target Node for Cluster",&element); - } -} - - -// ------------------------------------------------------------------------------------------------ -Cluster::~Cluster() -{ - -} - - -// ------------------------------------------------------------------------------------------------ -Skin::Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Deformer(id,element,doc,name) -, accuracy( 0.0f ) { - const Scope& sc = GetRequiredScope(element); - - const Element* const Link_DeformAcuracy = sc["Link_DeformAcuracy"]; - if(Link_DeformAcuracy) { - accuracy = ParseTokenAsFloat(GetRequiredToken(*Link_DeformAcuracy,0)); - } - - // resolve assigned clusters - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer"); - - clusters.reserve(conns.size()); - for(const Connection* con : conns) { - - const Cluster* const cluster = ProcessSimpleConnection<Cluster>(*con, false, "Cluster -> Skin", element); - if(cluster) { - clusters.push_back(cluster); - continue; - } - } -} - - -// ------------------------------------------------------------------------------------------------ -Skin::~Skin() -{ - -} -// ------------------------------------------------------------------------------------------------ -BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name) - : Deformer(id, element, doc, name) -{ - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer"); - blendShapeChannels.reserve(conns.size()); - for (const Connection* con : conns) { - const BlendShapeChannel* const bspc = ProcessSimpleConnection<BlendShapeChannel>(*con, false, "BlendShapeChannel -> BlendShape", element); - if (bspc) { - blendShapeChannels.push_back(bspc); - continue; - } - } -} -// ------------------------------------------------------------------------------------------------ -BlendShape::~BlendShape() -{ - -} -// ------------------------------------------------------------------------------------------------ -BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name) - : Deformer(id, element, doc, name) -{ - const Scope& sc = GetRequiredScope(element); - const Element* const DeformPercent = sc["DeformPercent"]; - if (DeformPercent) { - percent = ParseTokenAsFloat(GetRequiredToken(*DeformPercent, 0)); - } - const Element* const FullWeights = sc["FullWeights"]; - if (FullWeights) { - ParseVectorDataArray(fullWeights, *FullWeights); - } - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry"); - shapeGeometries.reserve(conns.size()); - for (const Connection* con : conns) { - const ShapeGeometry* const sg = ProcessSimpleConnection<ShapeGeometry>(*con, false, "Shape -> BlendShapeChannel", element); - if (sg) { - shapeGeometries.push_back(sg); - continue; - } - } -} -// ------------------------------------------------------------------------------------------------ -BlendShapeChannel::~BlendShapeChannel() -{ - -} -// ------------------------------------------------------------------------------------------------ -} -} -#endif - diff --git a/thirdparty/assimp/code/FBX/FBXDocument.cpp b/thirdparty/assimp/code/FBX/FBXDocument.cpp deleted file mode 100644 index 506fd978dd..0000000000 --- a/thirdparty/assimp/code/FBX/FBXDocument.cpp +++ /dev/null @@ -1,718 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the* - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXDocument.cpp - * @brief Implementation of the FBX DOM classes - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXDocument.h" -#include "FBXMeshGeometry.h" -#include "FBXParser.h" -#include "FBXUtil.h" -#include "FBXImporter.h" -#include "FBXImportSettings.h" -#include "FBXDocumentUtil.h" -#include "FBXProperties.h" - -#include <memory> -#include <functional> -#include <map> - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) -: doc(doc) -, element(element) -, id(id) -, flags() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -LazyObject::~LazyObject() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -const Object* LazyObject::Get(bool dieOnError) -{ - if(IsBeingConstructed() || FailedToConstruct()) { - return nullptr; - } - - if (object.get()) { - return object.get(); - } - - const Token& key = element.KeyToken(); - const TokenList& tokens = element.Tokens(); - - if(tokens.size() < 3) { - DOMError("expected at least 3 tokens: id, name and class tag",&element); - } - - const char* err; - std::string name = ParseTokenAsString(*tokens[1],err); - if (err) { - DOMError(err,&element); - } - - // small fix for binary reading: binary fbx files don't use - // prefixes such as Model:: in front of their names. The - // loading code expects this at many places, though! - // so convert the binary representation (a 0x0001) to the - // double colon notation. - if(tokens[1]->IsBinary()) { - for (size_t i = 0; i < name.length(); ++i) { - if (name[i] == 0x0 && name[i+1] == 0x1) { - name = name.substr(i+2) + "::" + name.substr(0,i); - } - } - } - - const std::string classtag = ParseTokenAsString(*tokens[2],err); - if (err) { - DOMError(err,&element); - } - - // prevent recursive calls - flags |= BEING_CONSTRUCTED; - - try { - // this needs to be relatively fast since it happens a lot, - // so avoid constructing strings all the time. - const char* obtype = key.begin(); - const size_t length = static_cast<size_t>(key.end()-key.begin()); - - // For debugging - //dumpObjectClassInfo( objtype, classtag ); - - if (!strncmp(obtype,"Geometry",length)) { - if (!strcmp(classtag.c_str(),"Mesh")) { - object.reset(new MeshGeometry(id,element,name,doc)); - } - if (!strcmp(classtag.c_str(), "Shape")) { - object.reset(new ShapeGeometry(id, element, name, doc)); - } - if (!strcmp(classtag.c_str(), "Line")) { - object.reset(new LineGeometry(id, element, name, doc)); - } - } - else if (!strncmp(obtype,"NodeAttribute",length)) { - if (!strcmp(classtag.c_str(),"Camera")) { - object.reset(new Camera(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"CameraSwitcher")) { - object.reset(new CameraSwitcher(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"Light")) { - object.reset(new Light(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"Null")) { - object.reset(new Null(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"LimbNode")) { - object.reset(new LimbNode(id,element,doc,name)); - } - } - else if (!strncmp(obtype,"Deformer",length)) { - if (!strcmp(classtag.c_str(),"Cluster")) { - object.reset(new Cluster(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(),"Skin")) { - object.reset(new Skin(id,element,doc,name)); - } - else if (!strcmp(classtag.c_str(), "BlendShape")) { - object.reset(new BlendShape(id, element, doc, name)); - } - else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) { - object.reset(new BlendShapeChannel(id, element, doc, name)); - } - } - else if ( !strncmp( obtype, "Model", length ) ) { - // FK and IK effectors are not supported - if ( strcmp( classtag.c_str(), "IKEffector" ) && strcmp( classtag.c_str(), "FKEffector" ) ) { - object.reset( new Model( id, element, doc, name ) ); - } - } - else if (!strncmp(obtype,"Material",length)) { - object.reset(new Material(id,element,doc,name)); - } - else if (!strncmp(obtype,"Texture",length)) { - object.reset(new Texture(id,element,doc,name)); - } - else if (!strncmp(obtype,"LayeredTexture",length)) { - object.reset(new LayeredTexture(id,element,doc,name)); - } - else if (!strncmp(obtype,"Video",length)) { - object.reset(new Video(id,element,doc,name)); - } - else if (!strncmp(obtype,"AnimationStack",length)) { - object.reset(new AnimationStack(id,element,name,doc)); - } - else if (!strncmp(obtype,"AnimationLayer",length)) { - object.reset(new AnimationLayer(id,element,name,doc)); - } - // note: order matters for these two - else if (!strncmp(obtype,"AnimationCurve",length)) { - object.reset(new AnimationCurve(id,element,name,doc)); - } - else if (!strncmp(obtype,"AnimationCurveNode",length)) { - object.reset(new AnimationCurveNode(id,element,name,doc)); - } - } - catch(std::exception& ex) { - flags &= ~BEING_CONSTRUCTED; - flags |= FAILED_TO_CONSTRUCT; - - if(dieOnError || doc.Settings().strictMode) { - throw; - } - - // note: the error message is already formatted, so raw logging is ok - if(!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_ERROR(ex.what()); - } - return NULL; - } - - if (!object.get()) { - //DOMError("failed to convert element to DOM object, class: " + classtag + ", name: " + name,&element); - } - - flags &= ~BEING_CONSTRUCTED; - return object.get(); -} - -// ------------------------------------------------------------------------------------------------ -Object::Object(uint64_t id, const Element& element, const std::string& name) -: element(element) -, name(name) -, id(id) -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -Object::~Object() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -FileGlobalSettings::FileGlobalSettings(const Document& doc, std::shared_ptr<const PropertyTable> props) -: props(props) -, doc(doc) -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -FileGlobalSettings::~FileGlobalSettings() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -Document::Document(const Parser& parser, const ImportSettings& settings) -: settings(settings) -, parser(parser) -{ - // Cannot use array default initialization syntax because vc8 fails on it - for (auto &timeStamp : creationTimeStamp) { - timeStamp = 0; - } - - ReadHeader(); - ReadPropertyTemplates(); - - ReadGlobalSettings(); - - // This order is important, connections need parsed objects to check - // whether connections are ok or not. Objects may not be evaluated yet, - // though, since this may require valid connections. - ReadObjects(); - ReadConnections(); -} - -// ------------------------------------------------------------------------------------------------ -Document::~Document() -{ - for(ObjectMap::value_type& v : objects) { - delete v.second; - } - - for(ConnectionMap::value_type& v : src_connections) { - delete v.second; - } - // |dest_connections| contain the same Connection objects as the |src_connections| -} - -// ------------------------------------------------------------------------------------------------ -static const unsigned int LowerSupportedVersion = 7100; -static const unsigned int UpperSupportedVersion = 7400; - -void Document::ReadHeader() { - // Read ID objects from "Objects" section - const Scope& sc = parser.GetRootScope(); - const Element* const ehead = sc["FBXHeaderExtension"]; - if(!ehead || !ehead->Compound()) { - DOMError("no FBXHeaderExtension dictionary found"); - } - - const Scope& shead = *ehead->Compound(); - fbxVersion = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(shead,"FBXVersion",ehead),0)); - - // While we may have some success with newer files, we don't support - // the older 6.n fbx format - if(fbxVersion < LowerSupportedVersion ) { - DOMError("unsupported, old format version, supported are only FBX 2011, FBX 2012 and FBX 2013"); - } - if(fbxVersion > UpperSupportedVersion ) { - if(Settings().strictMode) { - DOMError("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013" - " (turn off strict mode to try anyhow) "); - } - else { - DOMWarning("unsupported, newer format version, supported are only FBX 2011, FBX 2012 and FBX 2013," - " trying to read it nevertheless"); - } - } - - const Element* const ecreator = shead["Creator"]; - if(ecreator) { - creator = ParseTokenAsString(GetRequiredToken(*ecreator,0)); - } - - const Element* const etimestamp = shead["CreationTimeStamp"]; - if(etimestamp && etimestamp->Compound()) { - const Scope& stimestamp = *etimestamp->Compound(); - creationTimeStamp[0] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Year"),0)); - creationTimeStamp[1] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Month"),0)); - creationTimeStamp[2] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Day"),0)); - creationTimeStamp[3] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Hour"),0)); - creationTimeStamp[4] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Minute"),0)); - creationTimeStamp[5] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Second"),0)); - creationTimeStamp[6] = ParseTokenAsInt(GetRequiredToken(GetRequiredElement(stimestamp,"Millisecond"),0)); - } -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadGlobalSettings() -{ - const Scope& sc = parser.GetRootScope(); - const Element* const ehead = sc["GlobalSettings"]; - if ( nullptr == ehead || !ehead->Compound() ) { - DOMWarning( "no GlobalSettings dictionary found" ); - globals.reset(new FileGlobalSettings(*this, std::make_shared<const PropertyTable>())); - return; - } - - std::shared_ptr<const PropertyTable> props = GetPropertyTable( *this, "", *ehead, *ehead->Compound(), true ); - - //double v = PropertyGet<float>( *props.get(), std::string("UnitScaleFactor"), 1.0 ); - - if(!props) { - DOMError("GlobalSettings dictionary contains no property table"); - } - - globals.reset(new FileGlobalSettings(*this, props)); -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadObjects() -{ - // read ID objects from "Objects" section - const Scope& sc = parser.GetRootScope(); - const Element* const eobjects = sc["Objects"]; - if(!eobjects || !eobjects->Compound()) { - DOMError("no Objects dictionary found"); - } - - // add a dummy entry to represent the Model::RootNode object (id 0), - // which is only indirectly defined in the input file - objects[0] = new LazyObject(0L, *eobjects, *this); - - const Scope& sobjects = *eobjects->Compound(); - for(const ElementMap::value_type& el : sobjects.Elements()) { - - // extract ID - const TokenList& tok = el.second->Tokens(); - - if (tok.empty()) { - DOMError("expected ID after object key",el.second); - } - - const char* err; - const uint64_t id = ParseTokenAsID(*tok[0], err); - if(err) { - DOMError(err,el.second); - } - - // id=0 is normally implicit - if(id == 0L) { - DOMError("encountered object with implicitly defined id 0",el.second); - } - - if(objects.find(id) != objects.end()) { - DOMWarning("encountered duplicate object id, ignoring first occurrence",el.second); - } - - objects[id] = new LazyObject(id, *el.second, *this); - - // grab all animation stacks upfront since there is no listing of them - if(!strcmp(el.first.c_str(),"AnimationStack")) { - animationStacks.push_back(id); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadPropertyTemplates() -{ - const Scope& sc = parser.GetRootScope(); - // read property templates from "Definitions" section - const Element* const edefs = sc["Definitions"]; - if(!edefs || !edefs->Compound()) { - DOMWarning("no Definitions dictionary found"); - return; - } - - const Scope& sdefs = *edefs->Compound(); - const ElementCollection otypes = sdefs.GetCollection("ObjectType"); - for(ElementMap::const_iterator it = otypes.first; it != otypes.second; ++it) { - const Element& el = *(*it).second; - const Scope* sc = el.Compound(); - if(!sc) { - DOMWarning("expected nested scope in ObjectType, ignoring",&el); - continue; - } - - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - DOMWarning("expected name for ObjectType element, ignoring",&el); - continue; - } - - const std::string& oname = ParseTokenAsString(*tok[0]); - - const ElementCollection templs = sc->GetCollection("PropertyTemplate"); - for(ElementMap::const_iterator it = templs.first; it != templs.second; ++it) { - const Element& el = *(*it).second; - const Scope* sc = el.Compound(); - if(!sc) { - DOMWarning("expected nested scope in PropertyTemplate, ignoring",&el); - continue; - } - - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - DOMWarning("expected name for PropertyTemplate element, ignoring",&el); - continue; - } - - const std::string& pname = ParseTokenAsString(*tok[0]); - - const Element* Properties70 = (*sc)["Properties70"]; - if(Properties70) { - std::shared_ptr<const PropertyTable> props = std::make_shared<const PropertyTable>( - *Properties70,std::shared_ptr<const PropertyTable>(static_cast<const PropertyTable*>(NULL)) - ); - - templates[oname+"."+pname] = props; - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void Document::ReadConnections() -{ - const Scope& sc = parser.GetRootScope(); - // read property templates from "Definitions" section - const Element* const econns = sc["Connections"]; - if(!econns || !econns->Compound()) { - DOMError("no Connections dictionary found"); - } - - uint64_t insertionOrder = 0l; - const Scope& sconns = *econns->Compound(); - const ElementCollection conns = sconns.GetCollection("C"); - for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) { - const Element& el = *(*it).second; - const std::string& type = ParseTokenAsString(GetRequiredToken(el,0)); - - // PP = property-property connection, ignored for now - // (tokens: "PP", ID1, "Property1", ID2, "Property2") - if ( type == "PP" ) { - continue; - } - - const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1)); - const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2)); - - // OO = object-object connection - // OP = object-property connection, in which case the destination property follows the object ID - const std::string& prop = (type == "OP" ? ParseTokenAsString(GetRequiredToken(el,3)) : ""); - - if(objects.find(src) == objects.end()) { - DOMWarning("source object for connection does not exist",&el); - continue; - } - - // dest may be 0 (root node) but we added a dummy object before - if(objects.find(dest) == objects.end()) { - DOMWarning("destination object for connection does not exist",&el); - continue; - } - - // add new connection - const Connection* const c = new Connection(insertionOrder++,src,dest,prop,*this); - src_connections.insert(ConnectionMap::value_type(src,c)); - dest_connections.insert(ConnectionMap::value_type(dest,c)); - } -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<const AnimationStack*>& Document::AnimationStacks() const -{ - if (!animationStacksResolved.empty() || animationStacks.empty()) { - return animationStacksResolved; - } - - animationStacksResolved.reserve(animationStacks.size()); - for(uint64_t id : animationStacks) { - LazyObject* const lazy = GetObject(id); - const AnimationStack* stack; - if(!lazy || !(stack = lazy->Get<AnimationStack>())) { - DOMWarning("failed to read AnimationStack object"); - continue; - } - animationStacksResolved.push_back(stack); - } - - return animationStacksResolved; -} - -// ------------------------------------------------------------------------------------------------ -LazyObject* Document::GetObject(uint64_t id) const -{ - ObjectMap::const_iterator it = objects.find(id); - return it == objects.end() ? nullptr : (*it).second; -} - -#define MAX_CLASSNAMES 6 - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const -{ - std::vector<const Connection*> temp; - - const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range = - conns.equal_range(id); - - temp.reserve(std::distance(range.first,range.second)); - for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) { - temp.push_back((*it).second); - } - - std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare)); - - return temp; // NRVO should handle this -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bool is_src, - const ConnectionMap& conns, - const char* const* classnames, - size_t count) const - -{ - ai_assert(classnames); - ai_assert( count != 0 ); - ai_assert( count <= MAX_CLASSNAMES); - - size_t lengths[MAX_CLASSNAMES]; - - const size_t c = count; - for (size_t i = 0; i < c; ++i) { - lengths[ i ] = strlen(classnames[i]); - } - - std::vector<const Connection*> temp; - const std::pair<ConnectionMap::const_iterator,ConnectionMap::const_iterator> range = - conns.equal_range(id); - - temp.reserve(std::distance(range.first,range.second)); - for (ConnectionMap::const_iterator it = range.first; it != range.second; ++it) { - const Token& key = (is_src - ? (*it).second->LazyDestinationObject() - : (*it).second->LazySourceObject() - ).GetElement().KeyToken(); - - const char* obtype = key.begin(); - - for (size_t i = 0; i < c; ++i) { - ai_assert(classnames[i]); - if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lengths[i] && !strncmp(classnames[i],obtype,lengths[i])) { - obtype = nullptr; - break; - } - } - - if(obtype) { - continue; - } - - temp.push_back((*it).second); - } - - std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare)); - return temp; // NRVO should handle this -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source) const -{ - return GetConnectionsSequenced(source, ConnectionsBySource()); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t src, const char* classname) const -{ - const char* arr[] = {classname}; - return GetConnectionsBySourceSequenced(src, arr,1); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsBySourceSequenced(uint64_t source, - const char* const* classnames, size_t count) const -{ - return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest, - const char* classname) const -{ - const char* arr[] = {classname}; - return GetConnectionsByDestinationSequenced(dest, arr,1); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest) const -{ - return GetConnectionsSequenced(dest, ConnectionsByDestination()); -} - -// ------------------------------------------------------------------------------------------------ -std::vector<const Connection*> Document::GetConnectionsByDestinationSequenced(uint64_t dest, - const char* const* classnames, size_t count) const - -{ - return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count); -} - -// ------------------------------------------------------------------------------------------------ -Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop, - const Document& doc) - -: insertionOrder(insertionOrder) -, prop(prop) -, src(src) -, dest(dest) -, doc(doc) -{ - ai_assert(doc.Objects().find(src) != doc.Objects().end()); - // dest may be 0 (root node) - ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end()); -} - -// ------------------------------------------------------------------------------------------------ -Connection::~Connection() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -LazyObject& Connection::LazySourceObject() const -{ - LazyObject* const lazy = doc.GetObject(src); - ai_assert(lazy); - return *lazy; -} - -// ------------------------------------------------------------------------------------------------ -LazyObject& Connection::LazyDestinationObject() const -{ - LazyObject* const lazy = doc.GetObject(dest); - ai_assert(lazy); - return *lazy; -} - -// ------------------------------------------------------------------------------------------------ -const Object* Connection::SourceObject() const -{ - LazyObject* const lazy = doc.GetObject(src); - ai_assert(lazy); - return lazy->Get(); -} - -// ------------------------------------------------------------------------------------------------ -const Object* Connection::DestinationObject() const -{ - LazyObject* const lazy = doc.GetObject(dest); - ai_assert(lazy); - return lazy->Get(); -} - -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXDocument.h b/thirdparty/assimp/code/FBX/FBXDocument.h deleted file mode 100644 index a60d7d9efa..0000000000 --- a/thirdparty/assimp/code/FBX/FBXDocument.h +++ /dev/null @@ -1,1215 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXDocument.h - * @brief FBX DOM - */ -#ifndef INCLUDED_AI_FBX_DOCUMENT_H -#define INCLUDED_AI_FBX_DOCUMENT_H - -#include <numeric> -#include <stdint.h> -#include <assimp/mesh.h> -#include "FBXProperties.h" -#include "FBXParser.h" - -#define _AI_CONCAT(a,b) a ## b -#define AI_CONCAT(a,b) _AI_CONCAT(a,b) - -namespace Assimp { -namespace FBX { - -class Parser; -class Object; -struct ImportSettings; - -class PropertyTable; -class Document; -class Material; -class ShapeGeometry; -class LineGeometry; -class Geometry; - -class Video; - -class AnimationCurve; -class AnimationCurveNode; -class AnimationLayer; -class AnimationStack; - -class BlendShapeChannel; -class BlendShape; -class Skin; -class Cluster; - - -/** Represents a delay-parsed FBX objects. Many objects in the scene - * are not needed by assimp, so it makes no sense to parse them - * upfront. */ -class LazyObject { -public: - LazyObject(uint64_t id, const Element& element, const Document& doc); - - ~LazyObject(); - - const Object* Get(bool dieOnError = false); - - template <typename T> - const T* Get(bool dieOnError = false) { - const Object* const ob = Get(dieOnError); - return ob ? dynamic_cast<const T*>(ob) : NULL; - } - - uint64_t ID() const { - return id; - } - - bool IsBeingConstructed() const { - return (flags & BEING_CONSTRUCTED) != 0; - } - - bool FailedToConstruct() const { - return (flags & FAILED_TO_CONSTRUCT) != 0; - } - - const Element& GetElement() const { - return element; - } - - const Document& GetDocument() const { - return doc; - } - -private: - const Document& doc; - const Element& element; - std::unique_ptr<const Object> object; - - const uint64_t id; - - enum Flags { - BEING_CONSTRUCTED = 0x1, - FAILED_TO_CONSTRUCT = 0x2 - }; - - unsigned int flags; -}; - -/** Base class for in-memory (DOM) representations of FBX objects */ -class Object { -public: - Object(uint64_t id, const Element& element, const std::string& name); - - virtual ~Object(); - - const Element& SourceElement() const { - return element; - } - - const std::string& Name() const { - return name; - } - - uint64_t ID() const { - return id; - } - -protected: - const Element& element; - const std::string name; - const uint64_t id; -}; - -/** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table, - * fixed members are added by deriving classes. */ -class NodeAttribute : public Object { -public: - NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~NodeAttribute(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - -private: - std::shared_ptr<const PropertyTable> props; -}; - -/** DOM base class for FBX camera settings attached to a node */ -class CameraSwitcher : public NodeAttribute { -public: - CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~CameraSwitcher(); - - int CameraID() const { - return cameraId; - } - - const std::string& CameraName() const { - return cameraName; - } - - const std::string& CameraIndexName() const { - return cameraIndexName; - } - -private: - int cameraId; - std::string cameraName; - std::string cameraIndexName; -}; - -#define fbx_stringize(a) #a - -#define fbx_simple_property(name, type, default_value) \ - type name() const { \ - return PropertyGet<type>(Props(), fbx_stringize(name), (default_value)); \ - } - -// XXX improve logging -#define fbx_simple_enum_property(name, type, default_value) \ - type name() const { \ - const int ival = PropertyGet<int>(Props(), fbx_stringize(name), static_cast<int>(default_value)); \ - if (ival < 0 || ival >= AI_CONCAT(type, _MAX)) { \ - ai_assert(static_cast<int>(default_value) >= 0 && static_cast<int>(default_value) < AI_CONCAT(type, _MAX)); \ - return static_cast<type>(default_value); \ - } \ - return static_cast<type>(ival); \ -} - - -/** DOM base class for FBX cameras attached to a node */ -class Camera : public NodeAttribute { -public: - Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Camera(); - - fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0)) - fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0)) - fbx_simple_property(InterestPosition, aiVector3D, aiVector3D(0,0,0)) - - fbx_simple_property(AspectWidth, float, 1.0f) - fbx_simple_property(AspectHeight, float, 1.0f) - fbx_simple_property(FilmWidth, float, 1.0f) - fbx_simple_property(FilmHeight, float, 1.0f) - - fbx_simple_property(NearPlane, float, 0.1f) - fbx_simple_property(FarPlane, float, 100.0f) - - fbx_simple_property(FilmAspectRatio, float, 1.0f) - fbx_simple_property(ApertureMode, int, 0) - - fbx_simple_property(FieldOfView, float, 1.0f) - fbx_simple_property(FocalLength, float, 1.0f) -}; - -/** DOM base class for FBX null markers attached to a node */ -class Null : public NodeAttribute { -public: - Null(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Null(); -}; - -/** DOM base class for FBX limb node markers attached to a node */ -class LimbNode : public NodeAttribute { -public: - LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~LimbNode(); -}; - -/** DOM base class for FBX lights attached to a node */ -class Light : public NodeAttribute { -public: - Light(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Light(); - - enum Type - { - Type_Point, - Type_Directional, - Type_Spot, - Type_Area, - Type_Volume, - - Type_MAX // end-of-enum sentinel - }; - - enum Decay - { - Decay_None, - Decay_Linear, - Decay_Quadratic, - Decay_Cubic, - - Decay_MAX // end-of-enum sentinel - }; - - fbx_simple_property(Color, aiVector3D, aiVector3D(1,1,1)) - fbx_simple_enum_property(LightType, Type, 0) - fbx_simple_property(CastLightOnObject, bool, false) - fbx_simple_property(DrawVolumetricLight, bool, true) - fbx_simple_property(DrawGroundProjection, bool, true) - fbx_simple_property(DrawFrontFacingVolumetricLight, bool, false) - fbx_simple_property(Intensity, float, 100.0f) - fbx_simple_property(InnerAngle, float, 0.0f) - fbx_simple_property(OuterAngle, float, 45.0f) - fbx_simple_property(Fog, int, 50) - fbx_simple_enum_property(DecayType, Decay, 2) - fbx_simple_property(DecayStart, float, 1.0f) - fbx_simple_property(FileName, std::string, "") - - fbx_simple_property(EnableNearAttenuation, bool, false) - fbx_simple_property(NearAttenuationStart, float, 0.0f) - fbx_simple_property(NearAttenuationEnd, float, 0.0f) - fbx_simple_property(EnableFarAttenuation, bool, false) - fbx_simple_property(FarAttenuationStart, float, 0.0f) - fbx_simple_property(FarAttenuationEnd, float, 0.0f) - - fbx_simple_property(CastShadows, bool, true) - fbx_simple_property(ShadowColor, aiVector3D, aiVector3D(0,0,0)) - - fbx_simple_property(AreaLightShape, int, 0) - - fbx_simple_property(LeftBarnDoor, float, 20.0f) - fbx_simple_property(RightBarnDoor, float, 20.0f) - fbx_simple_property(TopBarnDoor, float, 20.0f) - fbx_simple_property(BottomBarnDoor, float, 20.0f) - fbx_simple_property(EnableBarnDoor, bool, true) -}; - -/** DOM base class for FBX models (even though its semantics are more "node" than "model" */ -class Model : public Object { -public: - enum RotOrder { - RotOrder_EulerXYZ = 0, - RotOrder_EulerXZY, - RotOrder_EulerYZX, - RotOrder_EulerYXZ, - RotOrder_EulerZXY, - RotOrder_EulerZYX, - - RotOrder_SphericXYZ, - - RotOrder_MAX // end-of-enum sentinel - }; - - enum TransformInheritance { - TransformInheritance_RrSs = 0, - TransformInheritance_RSrs, - TransformInheritance_Rrs, - - TransformInheritance_MAX // end-of-enum sentinel - }; - - Model(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Model(); - - fbx_simple_property(QuaternionInterpolate, int, 0) - - fbx_simple_property(RotationOffset, aiVector3D, aiVector3D()) - fbx_simple_property(RotationPivot, aiVector3D, aiVector3D()) - fbx_simple_property(ScalingOffset, aiVector3D, aiVector3D()) - fbx_simple_property(ScalingPivot, aiVector3D, aiVector3D()) - fbx_simple_property(TranslationActive, bool, false) - - fbx_simple_property(TranslationMin, aiVector3D, aiVector3D()) - fbx_simple_property(TranslationMax, aiVector3D, aiVector3D()) - - fbx_simple_property(TranslationMinX, bool, false) - fbx_simple_property(TranslationMaxX, bool, false) - fbx_simple_property(TranslationMinY, bool, false) - fbx_simple_property(TranslationMaxY, bool, false) - fbx_simple_property(TranslationMinZ, bool, false) - fbx_simple_property(TranslationMaxZ, bool, false) - - fbx_simple_enum_property(RotationOrder, RotOrder, 0) - fbx_simple_property(RotationSpaceForLimitOnly, bool, false) - fbx_simple_property(RotationStiffnessX, float, 0.0f) - fbx_simple_property(RotationStiffnessY, float, 0.0f) - fbx_simple_property(RotationStiffnessZ, float, 0.0f) - fbx_simple_property(AxisLen, float, 0.0f) - - fbx_simple_property(PreRotation, aiVector3D, aiVector3D()) - fbx_simple_property(PostRotation, aiVector3D, aiVector3D()) - fbx_simple_property(RotationActive, bool, false) - - fbx_simple_property(RotationMin, aiVector3D, aiVector3D()) - fbx_simple_property(RotationMax, aiVector3D, aiVector3D()) - - fbx_simple_property(RotationMinX, bool, false) - fbx_simple_property(RotationMaxX, bool, false) - fbx_simple_property(RotationMinY, bool, false) - fbx_simple_property(RotationMaxY, bool, false) - fbx_simple_property(RotationMinZ, bool, false) - fbx_simple_property(RotationMaxZ, bool, false) - fbx_simple_enum_property(InheritType, TransformInheritance, 0) - - fbx_simple_property(ScalingActive, bool, false) - fbx_simple_property(ScalingMin, aiVector3D, aiVector3D()) - fbx_simple_property(ScalingMax, aiVector3D, aiVector3D(1.f,1.f,1.f)) - fbx_simple_property(ScalingMinX, bool, false) - fbx_simple_property(ScalingMaxX, bool, false) - fbx_simple_property(ScalingMinY, bool, false) - fbx_simple_property(ScalingMaxY, bool, false) - fbx_simple_property(ScalingMinZ, bool, false) - fbx_simple_property(ScalingMaxZ, bool, false) - - fbx_simple_property(GeometricTranslation, aiVector3D, aiVector3D()) - fbx_simple_property(GeometricRotation, aiVector3D, aiVector3D()) - fbx_simple_property(GeometricScaling, aiVector3D, aiVector3D(1.f, 1.f, 1.f)) - - fbx_simple_property(MinDampRangeX, float, 0.0f) - fbx_simple_property(MinDampRangeY, float, 0.0f) - fbx_simple_property(MinDampRangeZ, float, 0.0f) - fbx_simple_property(MaxDampRangeX, float, 0.0f) - fbx_simple_property(MaxDampRangeY, float, 0.0f) - fbx_simple_property(MaxDampRangeZ, float, 0.0f) - - fbx_simple_property(MinDampStrengthX, float, 0.0f) - fbx_simple_property(MinDampStrengthY, float, 0.0f) - fbx_simple_property(MinDampStrengthZ, float, 0.0f) - fbx_simple_property(MaxDampStrengthX, float, 0.0f) - fbx_simple_property(MaxDampStrengthY, float, 0.0f) - fbx_simple_property(MaxDampStrengthZ, float, 0.0f) - - fbx_simple_property(PreferredAngleX, float, 0.0f) - fbx_simple_property(PreferredAngleY, float, 0.0f) - fbx_simple_property(PreferredAngleZ, float, 0.0f) - - fbx_simple_property(Show, bool, true) - fbx_simple_property(LODBox, bool, false) - fbx_simple_property(Freeze, bool, false) - - const std::string& Shading() const { - return shading; - } - - const std::string& Culling() const { - return culling; - } - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - /** Get material links */ - const std::vector<const Material*>& GetMaterials() const { - return materials; - } - - /** Get geometry links */ - const std::vector<const Geometry*>& GetGeometry() const { - return geometry; - } - - /** Get node attachments */ - const std::vector<const NodeAttribute*>& GetAttributes() const { - return attributes; - } - - /** convenience method to check if the node has a Null node marker */ - bool IsNull() const; - -private: - void ResolveLinks(const Element& element, const Document& doc); - -private: - std::vector<const Material*> materials; - std::vector<const Geometry*> geometry; - std::vector<const NodeAttribute*> attributes; - - std::string shading; - std::string culling; - std::shared_ptr<const PropertyTable> props; -}; - -/** DOM class for generic FBX textures */ -class Texture : public Object { -public: - Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Texture(); - - const std::string& Type() const { - return type; - } - - const std::string& FileName() const { - return fileName; - } - - const std::string& RelativeFilename() const { - return relativeFileName; - } - - const std::string& AlphaSource() const { - return alphaSource; - } - - const aiVector2D& UVTranslation() const { - return uvTrans; - } - - const aiVector2D& UVScaling() const { - return uvScaling; - } - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - // return a 4-tuple - const unsigned int* Crop() const { - return crop; - } - - const Video* Media() const { - return media; - } - -private: - aiVector2D uvTrans; - aiVector2D uvScaling; - - std::string type; - std::string relativeFileName; - std::string fileName; - std::string alphaSource; - std::shared_ptr<const PropertyTable> props; - - unsigned int crop[4]; - - const Video* media; -}; - -/** DOM class for layered FBX textures */ -class LayeredTexture : public Object { -public: - LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~LayeredTexture(); - - // Can only be called after construction of the layered texture object due to construction flag. - void fillTexture(const Document& doc); - - enum BlendMode { - BlendMode_Translucent, - BlendMode_Additive, - BlendMode_Modulate, - BlendMode_Modulate2, - BlendMode_Over, - BlendMode_Normal, - BlendMode_Dissolve, - BlendMode_Darken, - BlendMode_ColorBurn, - BlendMode_LinearBurn, - BlendMode_DarkerColor, - BlendMode_Lighten, - BlendMode_Screen, - BlendMode_ColorDodge, - BlendMode_LinearDodge, - BlendMode_LighterColor, - BlendMode_SoftLight, - BlendMode_HardLight, - BlendMode_VividLight, - BlendMode_LinearLight, - BlendMode_PinLight, - BlendMode_HardMix, - BlendMode_Difference, - BlendMode_Exclusion, - BlendMode_Subtract, - BlendMode_Divide, - BlendMode_Hue, - BlendMode_Saturation, - BlendMode_Color, - BlendMode_Luminosity, - BlendMode_Overlay, - BlendMode_BlendModeCount - }; - - const Texture* getTexture(int index=0) const - { - return textures[index]; - - } - int textureCount() const { - return static_cast<int>(textures.size()); - } - BlendMode GetBlendMode() const - { - return blendMode; - } - float Alpha() - { - return alpha; - } -private: - std::vector<const Texture*> textures; - BlendMode blendMode; - float alpha; -}; - -typedef std::fbx_unordered_map<std::string, const Texture*> TextureMap; -typedef std::fbx_unordered_map<std::string, const LayeredTexture*> LayeredTextureMap; - - -/** DOM class for generic FBX videos */ -class Video : public Object { -public: - Video(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Video(); - - const std::string& Type() const { - return type; - } - - const std::string& FileName() const { - return fileName; - } - - const std::string& RelativeFilename() const { - return relativeFileName; - } - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - const uint8_t* Content() const { - ai_assert(content); - return content; - } - - uint64_t ContentLength() const { - return contentLength; - } - - uint8_t* RelinquishContent() { - uint8_t* ptr = content; - content = 0; - return ptr; - } - - bool operator==(const Video& other) const - { - return ( - type == other.type - && relativeFileName == other.relativeFileName - && fileName == other.fileName - ); - } - - bool operator<(const Video& other) const - { - return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName); - } - -private: - std::string type; - std::string relativeFileName; - std::string fileName; - std::shared_ptr<const PropertyTable> props; - - uint64_t contentLength; - uint8_t* content; -}; - -/** DOM class for generic FBX materials */ -class Material : public Object { -public: - Material(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Material(); - - const std::string& GetShadingModel() const { - return shading; - } - - bool IsMultilayer() const { - return multilayer; - } - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - const TextureMap& Textures() const { - return textures; - } - - const LayeredTextureMap& LayeredTextures() const { - return layeredTextures; - } - -private: - std::string shading; - bool multilayer; - std::shared_ptr<const PropertyTable> props; - - TextureMap textures; - LayeredTextureMap layeredTextures; -}; - -typedef std::vector<int64_t> KeyTimeList; -typedef std::vector<float> KeyValueList; - -/** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */ -class AnimationCurve : public Object { -public: - AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc); - virtual ~AnimationCurve(); - - /** get list of keyframe positions (time). - * Invariant: |GetKeys()| > 0 */ - const KeyTimeList& GetKeys() const { - return keys; - } - - /** get list of keyframe values. - * Invariant: |GetKeys()| == |GetValues()| && |GetKeys()| > 0*/ - const KeyValueList& GetValues() const { - return values; - } - - const std::vector<float>& GetAttributes() const { - return attributes; - } - - const std::vector<unsigned int>& GetFlags() const { - return flags; - } - -private: - KeyTimeList keys; - KeyValueList values; - std::vector<float> attributes; - std::vector<unsigned int> flags; -}; - -// property-name -> animation curve -typedef std::map<std::string, const AnimationCurve*> AnimationCurveMap; - -/** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */ -class AnimationCurveNode : public Object { -public: - /* the optional white list specifies a list of property names for which the caller - wants animations for. If the curve node does not match one of these, std::range_error - will be thrown. */ - AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc, - const char* const * target_prop_whitelist = NULL, size_t whitelist_size = 0); - - virtual ~AnimationCurveNode(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - - const AnimationCurveMap& Curves() const; - - /** Object the curve is assigned to, this can be NULL if the - * target object has no DOM representation or could not - * be read for other reasons.*/ - const Object* Target() const { - return target; - } - - const Model* TargetAsModel() const { - return dynamic_cast<const Model*>(target); - } - - const NodeAttribute* TargetAsNodeAttribute() const { - return dynamic_cast<const NodeAttribute*>(target); - } - - /** Property of Target() that is being animated*/ - const std::string& TargetProperty() const { - return prop; - } - -private: - const Object* target; - std::shared_ptr<const PropertyTable> props; - mutable AnimationCurveMap curves; - - std::string prop; - const Document& doc; -}; - -typedef std::vector<const AnimationCurveNode*> AnimationCurveNodeList; - -/** Represents a FBX animation layer (i.e. a list of node animations) */ -class AnimationLayer : public Object { -public: - AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc); - virtual ~AnimationLayer(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - /* the optional white list specifies a list of property names for which the caller - wants animations for. Curves not matching this list will not be added to the - animation layer. */ - AnimationCurveNodeList Nodes(const char* const * target_prop_whitelist = nullptr, size_t whitelist_size = 0) const; - -private: - std::shared_ptr<const PropertyTable> props; - const Document& doc; -}; - -typedef std::vector<const AnimationLayer*> AnimationLayerList; - -/** Represents a FBX animation stack (i.e. a list of animation layers) */ -class AnimationStack : public Object { -public: - AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc); - virtual ~AnimationStack(); - - fbx_simple_property(LocalStart, int64_t, 0L) - fbx_simple_property(LocalStop, int64_t, 0L) - fbx_simple_property(ReferenceStart, int64_t, 0L) - fbx_simple_property(ReferenceStop, int64_t, 0L) - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - const AnimationLayerList& Layers() const { - return layers; - } - -private: - std::shared_ptr<const PropertyTable> props; - AnimationLayerList layers; -}; - - -/** DOM class for deformers */ -class Deformer : public Object { -public: - Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Deformer(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - -private: - std::shared_ptr<const PropertyTable> props; -}; - -typedef std::vector<float> WeightArray; -typedef std::vector<unsigned int> WeightIndexArray; - - -/** DOM class for BlendShapeChannel deformers */ -class BlendShapeChannel : public Deformer { -public: - BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~BlendShapeChannel(); - - float DeformPercent() const { - return percent; - } - - const WeightArray& GetFullWeights() const { - return fullWeights; - } - - const std::vector<const ShapeGeometry*>& GetShapeGeometries() const { - return shapeGeometries; - } - -private: - float percent; - WeightArray fullWeights; - std::vector<const ShapeGeometry*> shapeGeometries; -}; - -/** DOM class for BlendShape deformers */ -class BlendShape : public Deformer { -public: - BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~BlendShape(); - - const std::vector<const BlendShapeChannel*>& BlendShapeChannels() const { - return blendShapeChannels; - } - -private: - std::vector<const BlendShapeChannel*> blendShapeChannels; -}; - -/** DOM class for skin deformer clusters (aka sub-deformers) */ -class Cluster : public Deformer { -public: - Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Cluster(); - - /** get the list of deformer weights associated with this cluster. - * Use #GetIndices() to get the associated vertices. Both arrays - * have the same size (and may also be empty). */ - const WeightArray& GetWeights() const { - return weights; - } - - /** get indices into the vertex data of the geometry associated - * with this cluster. Use #GetWeights() to get the associated weights. - * Both arrays have the same size (and may also be empty). */ - const WeightIndexArray& GetIndices() const { - return indices; - } - - /** */ - const aiMatrix4x4& Transform() const { - return transform; - } - - const aiMatrix4x4& TransformLink() const { - return transformLink; - } - - const Model* TargetNode() const { - return node; - } - -private: - WeightArray weights; - WeightIndexArray indices; - - aiMatrix4x4 transform; - aiMatrix4x4 transformLink; - - const Model* node; -}; - -/** DOM class for skin deformers */ -class Skin : public Deformer { -public: - Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name); - - virtual ~Skin(); - - float DeformAccuracy() const { - return accuracy; - } - - const std::vector<const Cluster*>& Clusters() const { - return clusters; - } - -private: - float accuracy; - std::vector<const Cluster*> clusters; -}; - -/** Represents a link between two FBX objects. */ -class Connection { -public: - Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop, const Document& doc); - - ~Connection(); - - // note: a connection ensures that the source and dest objects exist, but - // not that they have DOM representations, so the return value of one of - // these functions can still be NULL. - const Object* SourceObject() const; - const Object* DestinationObject() const; - - // these, however, are always guaranteed to be valid - LazyObject& LazySourceObject() const; - LazyObject& LazyDestinationObject() const; - - - /** return the name of the property the connection is attached to. - * this is an empty string for object to object (OO) connections. */ - const std::string& PropertyName() const { - return prop; - } - - uint64_t InsertionOrder() const { - return insertionOrder; - } - - int CompareTo(const Connection* c) const { - ai_assert( nullptr != c ); - - // note: can't subtract because this would overflow uint64_t - if(InsertionOrder() > c->InsertionOrder()) { - return 1; - } - else if(InsertionOrder() < c->InsertionOrder()) { - return -1; - } - return 0; - } - - bool Compare(const Connection* c) const { - ai_assert( nullptr != c ); - - return InsertionOrder() < c->InsertionOrder(); - } - -public: - uint64_t insertionOrder; - const std::string prop; - - uint64_t src, dest; - const Document& doc; -}; - -// XXX again, unique_ptr would be useful. shared_ptr is too -// bloated since the objects have a well-defined single owner -// during their entire lifetime (Document). FBX files have -// up to many thousands of objects (most of which we never use), -// so the memory overhead for them should be kept at a minimum. -typedef std::fbx_unordered_map<uint64_t, LazyObject*> ObjectMap; -typedef std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > PropertyTemplateMap; - -typedef std::fbx_unordered_multimap<uint64_t, const Connection*> ConnectionMap; - -/** DOM class for global document settings, a single instance per document can - * be accessed via Document.Globals(). */ -class FileGlobalSettings { -public: - FileGlobalSettings(const Document& doc, std::shared_ptr<const PropertyTable> props); - - ~FileGlobalSettings(); - - const PropertyTable& Props() const { - ai_assert(props.get()); - return *props.get(); - } - - const Document& GetDocument() const { - return doc; - } - - fbx_simple_property(UpAxis, int, 1) - fbx_simple_property(UpAxisSign, int, 1) - fbx_simple_property(FrontAxis, int, 2) - fbx_simple_property(FrontAxisSign, int, 1) - fbx_simple_property(CoordAxis, int, 0) - fbx_simple_property(CoordAxisSign, int, 1) - fbx_simple_property(OriginalUpAxis, int, 0) - fbx_simple_property(OriginalUpAxisSign, int, 1) - fbx_simple_property(UnitScaleFactor, float, 1) - fbx_simple_property(OriginalUnitScaleFactor, float, 1) - fbx_simple_property(AmbientColor, aiVector3D, aiVector3D(0,0,0)) - fbx_simple_property(DefaultCamera, std::string, "") - - - enum FrameRate { - FrameRate_DEFAULT = 0, - FrameRate_120 = 1, - FrameRate_100 = 2, - FrameRate_60 = 3, - FrameRate_50 = 4, - FrameRate_48 = 5, - FrameRate_30 = 6, - FrameRate_30_DROP = 7, - FrameRate_NTSC_DROP_FRAME = 8, - FrameRate_NTSC_FULL_FRAME = 9, - FrameRate_PAL = 10, - FrameRate_CINEMA = 11, - FrameRate_1000 = 12, - FrameRate_CINEMA_ND = 13, - FrameRate_CUSTOM = 14, - - FrameRate_MAX// end-of-enum sentinel - }; - - fbx_simple_enum_property(TimeMode, FrameRate, FrameRate_DEFAULT) - fbx_simple_property(TimeSpanStart, uint64_t, 0L) - fbx_simple_property(TimeSpanStop, uint64_t, 0L) - fbx_simple_property(CustomFrameRate, float, -1.0f) - -private: - std::shared_ptr<const PropertyTable> props; - const Document& doc; -}; - -/** DOM root for a FBX file */ -class Document { -public: - Document(const Parser& parser, const ImportSettings& settings); - - ~Document(); - - LazyObject* GetObject(uint64_t id) const; - - bool IsBinary() const { - return parser.IsBinary(); - } - - unsigned int FBXVersion() const { - return fbxVersion; - } - - const std::string& Creator() const { - return creator; - } - - // elements (in this order): Year, Month, Day, Hour, Second, Millisecond - const unsigned int* CreationTimeStamp() const { - return creationTimeStamp; - } - - const FileGlobalSettings& GlobalSettings() const { - ai_assert(globals.get()); - return *globals.get(); - } - - const PropertyTemplateMap& Templates() const { - return templates; - } - - const ObjectMap& Objects() const { - return objects; - } - - const ImportSettings& Settings() const { - return settings; - } - - const ConnectionMap& ConnectionsBySource() const { - return src_connections; - } - - const ConnectionMap& ConnectionsByDestination() const { - return dest_connections; - } - - // note: the implicit rule in all DOM classes is to always resolve - // from destination to source (since the FBX object hierarchy is, - // with very few exceptions, a DAG, this avoids cycles). In all - // cases that may involve back-facing edges in the object graph, - // use LazyObject::IsBeingConstructed() to check. - - std::vector<const Connection*> GetConnectionsBySourceSequenced(uint64_t source) const; - std::vector<const Connection*> GetConnectionsByDestinationSequenced(uint64_t dest) const; - - std::vector<const Connection*> GetConnectionsBySourceSequenced(uint64_t source, const char* classname) const; - std::vector<const Connection*> GetConnectionsByDestinationSequenced(uint64_t dest, const char* classname) const; - - std::vector<const Connection*> GetConnectionsBySourceSequenced(uint64_t source, - const char* const* classnames, size_t count) const; - std::vector<const Connection*> GetConnectionsByDestinationSequenced(uint64_t dest, - const char* const* classnames, - size_t count) const; - - const std::vector<const AnimationStack*>& AnimationStacks() const; - -private: - std::vector<const Connection*> GetConnectionsSequenced(uint64_t id, const ConnectionMap&) const; - std::vector<const Connection*> GetConnectionsSequenced(uint64_t id, bool is_src, - const ConnectionMap&, - const char* const* classnames, - size_t count) const; - void ReadHeader(); - void ReadObjects(); - void ReadPropertyTemplates(); - void ReadConnections(); - void ReadGlobalSettings(); - -private: - const ImportSettings& settings; - - ObjectMap objects; - const Parser& parser; - - PropertyTemplateMap templates; - ConnectionMap src_connections; - ConnectionMap dest_connections; - - unsigned int fbxVersion; - std::string creator; - unsigned int creationTimeStamp[7]; - - std::vector<uint64_t> animationStacks; - mutable std::vector<const AnimationStack*> animationStacksResolved; - - std::unique_ptr<FileGlobalSettings> globals; -}; - -} // Namespace FBX -} // Namespace Assimp - -namespace std -{ - template <> - struct hash<const Assimp::FBX::Video> - { - std::size_t operator()(const Assimp::FBX::Video& video) const - { - using std::size_t; - using std::hash; - using std::string; - - size_t res = 17; - res = res * 31 + hash<string>()(video.Name()); - res = res * 31 + hash<string>()(video.RelativeFilename()); - res = res * 31 + hash<string>()(video.Type()); - - return res; - } - }; -} - -#endif // INCLUDED_AI_FBX_DOCUMENT_H diff --git a/thirdparty/assimp/code/FBX/FBXDocumentUtil.cpp b/thirdparty/assimp/code/FBX/FBXDocumentUtil.cpp deleted file mode 100644 index f84691479a..0000000000 --- a/thirdparty/assimp/code/FBX/FBXDocumentUtil.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXDocumentUtil.cpp - * @brief Implementation of the FBX DOM utility functions declared in FBXDocumentUtil.h - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXUtil.h" -#include "FBXDocumentUtil.h" -#include "FBXProperties.h" - - -namespace Assimp { -namespace FBX { -namespace Util { - -// ------------------------------------------------------------------------------------------------ -// signal DOM construction error, this is always unrecoverable. Throws DeadlyImportError. -void DOMError(const std::string& message, const Token& token) -{ - throw DeadlyImportError(Util::AddTokenText("FBX-DOM",message,&token)); -} - -// ------------------------------------------------------------------------------------------------ -void DOMError(const std::string& message, const Element* element /*= NULL*/) -{ - if(element) { - DOMError(message,element->KeyToken()); - } - throw DeadlyImportError("FBX-DOM " + message); -} - - -// ------------------------------------------------------------------------------------------------ -// print warning, do return -void DOMWarning(const std::string& message, const Token& token) -{ - if(DefaultLogger::get()) { - ASSIMP_LOG_WARN(Util::AddTokenText("FBX-DOM",message,&token)); - } -} - -// ------------------------------------------------------------------------------------------------ -void DOMWarning(const std::string& message, const Element* element /*= NULL*/) -{ - if(element) { - DOMWarning(message,element->KeyToken()); - return; - } - if(DefaultLogger::get()) { - ASSIMP_LOG_WARN("FBX-DOM: " + message); - } -} - - -// ------------------------------------------------------------------------------------------------ -// fetch a property table and the corresponding property template -std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc, - const std::string& templateName, - const Element &element, - const Scope& sc, - bool no_warn /*= false*/) -{ - const Element* const Properties70 = sc["Properties70"]; - std::shared_ptr<const PropertyTable> templateProps = std::shared_ptr<const PropertyTable>( - static_cast<const PropertyTable*>(NULL)); - - if(templateName.length()) { - PropertyTemplateMap::const_iterator it = doc.Templates().find(templateName); - if(it != doc.Templates().end()) { - templateProps = (*it).second; - } - } - - if(!Properties70 || !Properties70->Compound()) { - if(!no_warn) { - DOMWarning("property table (Properties70) not found",&element); - } - if(templateProps) { - return templateProps; - } - else { - return std::make_shared<const PropertyTable>(); - } - } - return std::make_shared<const PropertyTable>(*Properties70,templateProps); -} -} // !Util -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXDocumentUtil.h b/thirdparty/assimp/code/FBX/FBXDocumentUtil.h deleted file mode 100644 index 2450109e59..0000000000 --- a/thirdparty/assimp/code/FBX/FBXDocumentUtil.h +++ /dev/null @@ -1,120 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2012, assimp team -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXDocumentUtil.h - * @brief FBX internal utilities used by the DOM reading code - */ -#ifndef INCLUDED_AI_FBX_DOCUMENT_UTIL_H -#define INCLUDED_AI_FBX_DOCUMENT_UTIL_H - -#include <assimp/defs.h> -#include <string> -#include <memory> -#include "FBXDocument.h" - -struct Token; -struct Element; - -namespace Assimp { -namespace FBX { -namespace Util { - -/* DOM/Parse error reporting - does not return */ -AI_WONT_RETURN void DOMError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX; -AI_WONT_RETURN void DOMError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX; - -// does return -void DOMWarning(const std::string& message, const Token& token); -void DOMWarning(const std::string& message, const Element* element = NULL); - - -// fetch a property table and the corresponding property template -std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc, - const std::string& templateName, - const Element &element, - const Scope& sc, - bool no_warn = false); - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline -const T* ProcessSimpleConnection(const Connection& con, - bool is_object_property_conn, - const char* name, - const Element& element, - const char** propNameOut = nullptr) -{ - if (is_object_property_conn && !con.PropertyName().length()) { - DOMWarning("expected incoming " + std::string(name) + - " link to be an object-object connection, ignoring", - &element - ); - return nullptr; - } - else if (!is_object_property_conn && con.PropertyName().length()) { - DOMWarning("expected incoming " + std::string(name) + - " link to be an object-property connection, ignoring", - &element - ); - return nullptr; - } - - if(is_object_property_conn && propNameOut) { - // note: this is ok, the return value of PropertyValue() is guaranteed to - // remain valid and unchanged as long as the document exists. - *propNameOut = con.PropertyName().c_str(); - } - - const Object* const ob = con.SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for incoming " + std::string(name) + - " link, ignoring", - &element); - return nullptr; - } - - return dynamic_cast<const T*>(ob); -} - -} //!Util -} //!FBX -} //!Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXExportNode.cpp b/thirdparty/assimp/code/FBX/FBXExportNode.cpp deleted file mode 100644 index 06c89cee46..0000000000 --- a/thirdparty/assimp/code/FBX/FBXExportNode.cpp +++ /dev/null @@ -1,571 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -#ifndef ASSIMP_BUILD_NO_EXPORT -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExportNode.h" -#include "FBXCommon.h" - -#include <assimp/StreamWriter.h> // StreamWriterLE -#include <assimp/Exceptional.h> // DeadlyExportError -#include <assimp/ai_assert.h> -#include <assimp/StringUtils.h> // ai_snprintf - -#include <string> -#include <ostream> -#include <sstream> // ostringstream -#include <memory> // shared_ptr - -namespace Assimp { -// AddP70<type> helpers... there's no usable pattern here, -// so all are defined as separate functions. -// Even "animatable" properties are often completely different -// from the standard (nonanimated) property definition, -// so they are specified with an 'A' suffix. - -void FBX::Node::AddP70int( - const std::string& name, int32_t value -) { - FBX::Node n("P"); - n.AddProperties(name, "int", "Integer", "", value); - AddChild(n); -} - -void FBX::Node::AddP70bool( - const std::string& name, bool value -) { - FBX::Node n("P"); - n.AddProperties(name, "bool", "", "", int32_t(value)); - AddChild(n); -} - -void FBX::Node::AddP70double( - const std::string& name, double value -) { - FBX::Node n("P"); - n.AddProperties(name, "double", "Number", "", value); - AddChild(n); -} - -void FBX::Node::AddP70numberA( - const std::string& name, double value -) { - FBX::Node n("P"); - n.AddProperties(name, "Number", "", "A", value); - AddChild(n); -} - -void FBX::Node::AddP70color( - const std::string& name, double r, double g, double b -) { - FBX::Node n("P"); - n.AddProperties(name, "ColorRGB", "Color", "", r, g, b); - AddChild(n); -} - -void FBX::Node::AddP70colorA( - const std::string& name, double r, double g, double b -) { - FBX::Node n("P"); - n.AddProperties(name, "Color", "", "A", r, g, b); - AddChild(n); -} - -void FBX::Node::AddP70vector( - const std::string& name, double x, double y, double z -) { - FBX::Node n("P"); - n.AddProperties(name, "Vector3D", "Vector", "", x, y, z); - AddChild(n); -} - -void FBX::Node::AddP70vectorA( - const std::string& name, double x, double y, double z -) { - FBX::Node n("P"); - n.AddProperties(name, "Vector", "", "A", x, y, z); - AddChild(n); -} - -void FBX::Node::AddP70string( - const std::string& name, const std::string& value -) { - FBX::Node n("P"); - n.AddProperties(name, "KString", "", "", value); - AddChild(n); -} - -void FBX::Node::AddP70enum( - const std::string& name, int32_t value -) { - FBX::Node n("P"); - n.AddProperties(name, "enum", "", "", value); - AddChild(n); -} - -void FBX::Node::AddP70time( - const std::string& name, int64_t value -) { - FBX::Node n("P"); - n.AddProperties(name, "KTime", "Time", "", value); - AddChild(n); -} - - -// public member functions for writing nodes to stream - -void FBX::Node::Dump( - std::shared_ptr<Assimp::IOStream> outfile, - bool binary, int indent -) { - if (binary) { - Assimp::StreamWriterLE outstream(outfile); - DumpBinary(outstream); - } else { - std::ostringstream ss; - DumpAscii(ss, indent); - std::string s = ss.str(); - outfile->Write(s.c_str(), s.size(), 1); - } -} - -void FBX::Node::Dump( - Assimp::StreamWriterLE &outstream, - bool binary, int indent -) { - if (binary) { - DumpBinary(outstream); - } else { - std::ostringstream ss; - DumpAscii(ss, indent); - outstream.PutString(ss.str()); - } -} - - -// public member functions for low-level writing - -void FBX::Node::Begin( - Assimp::StreamWriterLE &s, - bool binary, int indent -) { - if (binary) { - BeginBinary(s); - } else { - // assume we're at the correct place to start already - (void)indent; - std::ostringstream ss; - BeginAscii(ss, indent); - s.PutString(ss.str()); - } -} - -void FBX::Node::DumpProperties( - Assimp::StreamWriterLE& s, - bool binary, int indent -) { - if (binary) { - DumpPropertiesBinary(s); - } else { - std::ostringstream ss; - DumpPropertiesAscii(ss, indent); - s.PutString(ss.str()); - } -} - -void FBX::Node::EndProperties( - Assimp::StreamWriterLE &s, - bool binary, int indent -) { - EndProperties(s, binary, indent, properties.size()); -} - -void FBX::Node::EndProperties( - Assimp::StreamWriterLE &s, - bool binary, int indent, - size_t num_properties -) { - if (binary) { - EndPropertiesBinary(s, num_properties); - } else { - // nothing to do - (void)indent; - } -} - -void FBX::Node::BeginChildren( - Assimp::StreamWriterLE &s, - bool binary, int indent -) { - if (binary) { - // nothing to do - } else { - std::ostringstream ss; - BeginChildrenAscii(ss, indent); - s.PutString(ss.str()); - } -} - -void FBX::Node::DumpChildren( - Assimp::StreamWriterLE& s, - bool binary, int indent -) { - if (binary) { - DumpChildrenBinary(s); - } else { - std::ostringstream ss; - DumpChildrenAscii(ss, indent); - if (ss.tellp() > 0) - s.PutString(ss.str()); - } -} - -void FBX::Node::End( - Assimp::StreamWriterLE &s, - bool binary, int indent, - bool has_children -) { - if (binary) { - EndBinary(s, has_children); - } else { - std::ostringstream ss; - EndAscii(ss, indent, has_children); - if (ss.tellp() > 0) - s.PutString(ss.str()); - } -} - - -// public member functions for writing to binary fbx - -void FBX::Node::DumpBinary(Assimp::StreamWriterLE &s) -{ - // write header section (with placeholders for some things) - BeginBinary(s); - - // write properties - DumpPropertiesBinary(s); - - // go back and fill in property related placeholders - EndPropertiesBinary(s, properties.size()); - - // write children - DumpChildrenBinary(s); - - // finish, filling in end offset placeholder - EndBinary(s, force_has_children || !children.empty()); -} - - -// public member functions for writing to ascii fbx - -void FBX::Node::DumpAscii(std::ostream &s, int indent) -{ - // write name - BeginAscii(s, indent); - - // write properties - DumpPropertiesAscii(s, indent); - - if (force_has_children || !children.empty()) { - // begin children (with a '{') - BeginChildrenAscii(s, indent + 1); - // write children - DumpChildrenAscii(s, indent + 1); - } - - // finish (also closing the children bracket '}') - EndAscii(s, indent, force_has_children || !children.empty()); -} - - -// private member functions for low-level writing to fbx - -void FBX::Node::BeginBinary(Assimp::StreamWriterLE &s) -{ - // remember start pos so we can come back and write the end pos - this->start_pos = s.Tell(); - - // placeholders for end pos and property section info - s.PutU4(0); // end pos - s.PutU4(0); // number of properties - s.PutU4(0); // total property section length - - // node name - s.PutU1(uint8_t(name.size())); // length of node name - s.PutString(name); // node name as raw bytes - - // property data comes after here - this->property_start = s.Tell(); -} - -void FBX::Node::DumpPropertiesBinary(Assimp::StreamWriterLE& s) -{ - for (auto &p : properties) { - p.DumpBinary(s); - } -} - -void FBX::Node::EndPropertiesBinary( - Assimp::StreamWriterLE &s, - size_t num_properties -) { - if (num_properties == 0) { return; } - size_t pos = s.Tell(); - ai_assert(pos > property_start); - size_t property_section_size = pos - property_start; - s.Seek(start_pos + 4); - s.PutU4(uint32_t(num_properties)); - s.PutU4(uint32_t(property_section_size)); - s.Seek(pos); -} - -void FBX::Node::DumpChildrenBinary(Assimp::StreamWriterLE& s) -{ - for (FBX::Node& child : children) { - child.DumpBinary(s); - } -} - -void FBX::Node::EndBinary( - Assimp::StreamWriterLE &s, - bool has_children -) { - // if there were children, add a null record - if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD); } - - // now go back and write initial pos - this->end_pos = s.Tell(); - s.Seek(start_pos); - s.PutU4(uint32_t(end_pos)); - s.Seek(end_pos); -} - - -void FBX::Node::BeginAscii(std::ostream& s, int indent) -{ - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << name << ": "; -} - -void FBX::Node::DumpPropertiesAscii(std::ostream &s, int indent) -{ - for (size_t i = 0; i < properties.size(); ++i) { - if (i > 0) { s << ", "; } - properties[i].DumpAscii(s, indent); - } -} - -void FBX::Node::BeginChildrenAscii(std::ostream& s, int indent) -{ - // only call this if there are actually children - s << " {"; - (void)indent; -} - -void FBX::Node::DumpChildrenAscii(std::ostream& s, int indent) -{ - // children will need a lot of padding and corralling - if (children.size() || force_has_children) { - for (size_t i = 0; i < children.size(); ++i) { - // no compression in ascii files, so skip this node if it exists - if (children[i].name == "EncryptionType") { continue; } - // the child can dump itself - children[i].DumpAscii(s, indent); - } - } -} - -void FBX::Node::EndAscii(std::ostream& s, int indent, bool has_children) -{ - if (!has_children) { return; } // nothing to do - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "}"; -} - -// private helpers for static member functions - -// ascii property node from vector of doubles -void FBX::Node::WritePropertyNodeAscii( - const std::string& name, - const std::vector<double>& v, - Assimp::StreamWriterLE& s, - int indent -){ - char buffer[32]; - FBX::Node node(name); - node.Begin(s, false, indent); - std::string vsize = to_string(v.size()); - // *<size> { - s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n"); - // indent + 1 - for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); } - // a: value,value,value,... - s.PutString("a: "); - int count = 0; - for (size_t i = 0; i < v.size(); ++i) { - if (i > 0) { s.PutChar(','); } - int len = ai_snprintf(buffer, sizeof(buffer), "%f", v[i]); - count += len; - if (count > 2048) { s.PutChar('\n'); count = 0; } - if (len < 0 || len > 31) { - // this should never happen - throw DeadlyExportError("failed to convert double to string"); - } - for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); } - } - // } - s.PutChar('\n'); - for (int i = 0; i < indent; ++i) { s.PutChar('\t'); } - s.PutChar('}'); s.PutChar(' '); - node.End(s, false, indent, false); -} - -// ascii property node from vector of int32_t -void FBX::Node::WritePropertyNodeAscii( - const std::string& name, - const std::vector<int32_t>& v, - Assimp::StreamWriterLE& s, - int indent -){ - char buffer[32]; - FBX::Node node(name); - node.Begin(s, false, indent); - std::string vsize = to_string(v.size()); - // *<size> { - s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n"); - // indent + 1 - for (int i = 0; i < indent + 1; ++i) { s.PutChar('\t'); } - // a: value,value,value,... - s.PutString("a: "); - int count = 0; - for (size_t i = 0; i < v.size(); ++i) { - if (i > 0) { s.PutChar(','); } - int len = ai_snprintf(buffer, sizeof(buffer), "%d", v[i]); - count += len; - if (count > 2048) { s.PutChar('\n'); count = 0; } - if (len < 0 || len > 31) { - // this should never happen - throw DeadlyExportError("failed to convert double to string"); - } - for (int j = 0; j < len; ++j) { s.PutChar(buffer[j]); } - } - // } - s.PutChar('\n'); - for (int i = 0; i < indent; ++i) { s.PutChar('\t'); } - s.PutChar('}'); s.PutChar(' '); - node.End(s, false, indent, false); -} - -// binary property node from vector of doubles -// TODO: optional zip compression! -void FBX::Node::WritePropertyNodeBinary( - const std::string& name, - const std::vector<double>& v, - Assimp::StreamWriterLE& s -){ - FBX::Node node(name); - node.BeginBinary(s); - s.PutU1('d'); - s.PutU4(uint32_t(v.size())); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - s.PutU4(uint32_t(v.size()) * 8); // data size - for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); } - node.EndPropertiesBinary(s, 1); - node.EndBinary(s, false); -} - -// binary property node from vector of int32_t -// TODO: optional zip compression! -void FBX::Node::WritePropertyNodeBinary( - const std::string& name, - const std::vector<int32_t>& v, - Assimp::StreamWriterLE& s -){ - FBX::Node node(name); - node.BeginBinary(s); - s.PutU1('i'); - s.PutU4(uint32_t(v.size())); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - s.PutU4(uint32_t(v.size()) * 4); // data size - for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); } - node.EndPropertiesBinary(s, 1); - node.EndBinary(s, false); -} - -// public static member functions - -// convenience function to create and write a property node, -// holding a single property which is an array of values. -// does not copy the data, so is efficient for large arrays. -void FBX::Node::WritePropertyNode( - const std::string& name, - const std::vector<double>& v, - Assimp::StreamWriterLE& s, - bool binary, int indent -){ - if (binary) { - FBX::Node::WritePropertyNodeBinary(name, v, s); - } else { - FBX::Node::WritePropertyNodeAscii(name, v, s, indent); - } -} - -// convenience function to create and write a property node, -// holding a single property which is an array of values. -// does not copy the data, so is efficient for large arrays. -void FBX::Node::WritePropertyNode( - const std::string& name, - const std::vector<int32_t>& v, - Assimp::StreamWriterLE& s, - bool binary, int indent -){ - if (binary) { - FBX::Node::WritePropertyNodeBinary(name, v, s); - } else { - FBX::Node::WritePropertyNodeAscii(name, v, s, indent); - } -} -} -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER -#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/FBX/FBXExportNode.h b/thirdparty/assimp/code/FBX/FBXExportNode.h deleted file mode 100644 index ef3bc781a4..0000000000 --- a/thirdparty/assimp/code/FBX/FBXExportNode.h +++ /dev/null @@ -1,271 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXExportNode.h -* Declares the FBX::Node helper class for fbx export. -*/ -#ifndef AI_FBXEXPORTNODE_H_INC -#define AI_FBXEXPORTNODE_H_INC - -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExportProperty.h" - -#include <assimp/StreamWriter.h> // StreamWriterLE - -#include <string> -#include <vector> - -namespace Assimp { -namespace FBX { - class Node; -} - -class FBX::Node { -public: - // TODO: accessors - std::string name; // node name - std::vector<FBX::FBXExportProperty> properties; // node properties - std::vector<FBX::Node> children; // child nodes - - // some nodes always pretend they have children... - bool force_has_children = false; - -public: // constructors - /// The default class constructor. - Node() = default; - - /// The class constructor with the name. - Node(const std::string& n) - : name(n) - , properties() - , children() - , force_has_children( false ) { - // empty - } - - // convenience template to construct with properties directly - template <typename... More> - Node(const std::string& n, const More... more) - : name(n) - , properties() - , children() - , force_has_children(false) { - AddProperties(more...); - } - -public: // functions to add properties or children - // add a single property to the node - template <typename T> - void AddProperty(T value) { - properties.emplace_back(value); - } - - // convenience function to add multiple properties at once - template <typename T, typename... More> - void AddProperties(T value, More... more) { - properties.emplace_back(value); - AddProperties(more...); - } - void AddProperties() {} - - // add a child node directly - void AddChild(const Node& node) { children.push_back(node); } - - // convenience function to add a child node with a single property - template <typename... More> - void AddChild( - const std::string& name, - More... more - ) { - FBX::Node c(name); - c.AddProperties(more...); - children.push_back(c); - } - -public: // support specifically for dealing with Properties70 nodes - - // it really is simpler to make these all separate functions. - // the versions with 'A' suffixes are for animatable properties. - // those often follow a completely different format internally in FBX. - void AddP70int(const std::string& name, int32_t value); - void AddP70bool(const std::string& name, bool value); - void AddP70double(const std::string& name, double value); - void AddP70numberA(const std::string& name, double value); - void AddP70color(const std::string& name, double r, double g, double b); - void AddP70colorA(const std::string& name, double r, double g, double b); - void AddP70vector(const std::string& name, double x, double y, double z); - void AddP70vectorA(const std::string& name, double x, double y, double z); - void AddP70string(const std::string& name, const std::string& value); - void AddP70enum(const std::string& name, int32_t value); - void AddP70time(const std::string& name, int64_t value); - - // template for custom P70 nodes. - // anything that doesn't fit in the above can be created manually. - template <typename... More> - void AddP70( - const std::string& name, - const std::string& type, - const std::string& type2, - const std::string& flags, - More... more - ) { - Node n("P"); - n.AddProperties(name, type, type2, flags, more...); - AddChild(n); - } - -public: // member functions for writing data to a file or stream - - // write the full node to the given file or stream - void Dump( - std::shared_ptr<Assimp::IOStream> outfile, - bool binary, int indent - ); - void Dump(Assimp::StreamWriterLE &s, bool binary, int indent); - - // these other functions are for writing data piece by piece. - // they must be used carefully. - // for usage examples see FBXExporter.cpp. - void Begin(Assimp::StreamWriterLE &s, bool binary, int indent); - void DumpProperties(Assimp::StreamWriterLE& s, bool binary, int indent); - void EndProperties(Assimp::StreamWriterLE &s, bool binary, int indent); - void EndProperties( - Assimp::StreamWriterLE &s, bool binary, int indent, - size_t num_properties - ); - void BeginChildren(Assimp::StreamWriterLE &s, bool binary, int indent); - void DumpChildren(Assimp::StreamWriterLE& s, bool binary, int indent); - void End( - Assimp::StreamWriterLE &s, bool binary, int indent, - bool has_children - ); - -private: // internal functions used for writing - - void DumpBinary(Assimp::StreamWriterLE &s); - void DumpAscii(Assimp::StreamWriterLE &s, int indent); - void DumpAscii(std::ostream &s, int indent); - - void BeginBinary(Assimp::StreamWriterLE &s); - void DumpPropertiesBinary(Assimp::StreamWriterLE& s); - void EndPropertiesBinary(Assimp::StreamWriterLE &s); - void EndPropertiesBinary(Assimp::StreamWriterLE &s, size_t num_properties); - void DumpChildrenBinary(Assimp::StreamWriterLE& s); - void EndBinary(Assimp::StreamWriterLE &s, bool has_children); - - void BeginAscii(std::ostream &s, int indent); - void DumpPropertiesAscii(std::ostream &s, int indent); - void BeginChildrenAscii(std::ostream &s, int indent); - void DumpChildrenAscii(std::ostream &s, int indent); - void EndAscii(std::ostream &s, int indent, bool has_children); - -private: // data used for binary dumps - size_t start_pos; // starting position in stream - size_t end_pos; // ending position in stream - size_t property_start; // starting position of property section - -public: // static member functions - - // convenience function to create a node with a single property, - // and write it to the stream. - template <typename T> - static void WritePropertyNode( - const std::string& name, - const T value, - Assimp::StreamWriterLE& s, - bool binary, int indent - ) { - FBX::FBXExportProperty p(value); - FBX::Node node(name, p); - node.Dump(s, binary, indent); - } - - // convenience function to create and write a property node, - // holding a single property which is an array of values. - // does not copy the data, so is efficient for large arrays. - static void WritePropertyNode( - const std::string& name, - const std::vector<double>& v, - Assimp::StreamWriterLE& s, - bool binary, int indent - ); - - // convenience function to create and write a property node, - // holding a single property which is an array of values. - // does not copy the data, so is efficient for large arrays. - static void WritePropertyNode( - const std::string& name, - const std::vector<int32_t>& v, - Assimp::StreamWriterLE& s, - bool binary, int indent - ); - -private: // static helper functions - static void WritePropertyNodeAscii( - const std::string& name, - const std::vector<double>& v, - Assimp::StreamWriterLE& s, - int indent - ); - static void WritePropertyNodeAscii( - const std::string& name, - const std::vector<int32_t>& v, - Assimp::StreamWriterLE& s, - int indent - ); - static void WritePropertyNodeBinary( - const std::string& name, - const std::vector<double>& v, - Assimp::StreamWriterLE& s - ); - static void WritePropertyNodeBinary( - const std::string& name, - const std::vector<int32_t>& v, - Assimp::StreamWriterLE& s - ); - -}; -} - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER - -#endif // AI_FBXEXPORTNODE_H_INC diff --git a/thirdparty/assimp/code/FBX/FBXExportProperty.cpp b/thirdparty/assimp/code/FBX/FBXExportProperty.cpp deleted file mode 100644 index f2a63b72b9..0000000000 --- a/thirdparty/assimp/code/FBX/FBXExportProperty.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -#ifndef ASSIMP_BUILD_NO_EXPORT -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExportProperty.h" - -#include <assimp/StreamWriter.h> // StreamWriterLE -#include <assimp/Exceptional.h> // DeadlyExportError - -#include <string> -#include <vector> -#include <ostream> -#include <locale> -#include <sstream> // ostringstream - -namespace Assimp { -namespace FBX { - -// constructors for single element properties - -FBXExportProperty::FBXExportProperty(bool v) -: type('C') -, data(1, uint8_t(v)) {} - -FBXExportProperty::FBXExportProperty(int16_t v) -: type('Y') -, data(2) { - uint8_t* d = data.data(); - (reinterpret_cast<int16_t*>(d))[0] = v; -} - -FBXExportProperty::FBXExportProperty(int32_t v) -: type('I') -, data(4) { - uint8_t* d = data.data(); - (reinterpret_cast<int32_t*>(d))[0] = v; -} - -FBXExportProperty::FBXExportProperty(float v) -: type('F') -, data(4) { - uint8_t* d = data.data(); - (reinterpret_cast<float*>(d))[0] = v; -} - -FBXExportProperty::FBXExportProperty(double v) -: type('D') -, data(8) { - uint8_t* d = data.data(); - (reinterpret_cast<double*>(d))[0] = v; -} - -FBXExportProperty::FBXExportProperty(int64_t v) -: type('L') -, data(8) { - uint8_t* d = data.data(); - (reinterpret_cast<int64_t*>(d))[0] = v; -} - -// constructors for array-type properties - -FBXExportProperty::FBXExportProperty(const char* c, bool raw) -: FBXExportProperty(std::string(c), raw) { - // empty -} - -// strings can either be saved as "raw" (R) data, or "string" (S) data -FBXExportProperty::FBXExportProperty(const std::string& s, bool raw) -: type(raw ? 'R' : 'S') -, data(s.size()) { - for (size_t i = 0; i < s.size(); ++i) { - data[i] = uint8_t(s[i]); - } -} - -FBXExportProperty::FBXExportProperty(const std::vector<uint8_t>& r) -: type('R') -, data(r) { - // empty -} - -FBXExportProperty::FBXExportProperty(const std::vector<int32_t>& va) -: type('i') -, data(4 * va.size() ) { - int32_t* d = reinterpret_cast<int32_t*>(data.data()); - for (size_t i = 0; i < va.size(); ++i) { - d[i] = va[i]; - } -} - -FBXExportProperty::FBXExportProperty(const std::vector<int64_t>& va) -: type('l') -, data(8 * va.size()) { - int64_t* d = reinterpret_cast<int64_t*>(data.data()); - for (size_t i = 0; i < va.size(); ++i) { - d[i] = va[i]; - } -} - -FBXExportProperty::FBXExportProperty(const std::vector<float>& va) -: type('f') -, data(4 * va.size()) { - float* d = reinterpret_cast<float*>(data.data()); - for (size_t i = 0; i < va.size(); ++i) { - d[i] = va[i]; - } -} - -FBXExportProperty::FBXExportProperty(const std::vector<double>& va) -: type('d') -, data(8 * va.size()) { - double* d = reinterpret_cast<double*>(data.data()); - for (size_t i = 0; i < va.size(); ++i) { - d[i] = va[i]; - } -} - -FBXExportProperty::FBXExportProperty(const aiMatrix4x4& vm) -: type('d') -, data(8 * 16) { - double* d = reinterpret_cast<double*>(data.data()); - for (unsigned int c = 0; c < 4; ++c) { - for (unsigned int r = 0; r < 4; ++r) { - d[4 * c + r] = vm[r][c]; - } - } -} - -// public member functions - -size_t FBXExportProperty::size() { - switch (type) { - case 'C': - case 'Y': - case 'I': - case 'F': - case 'D': - case 'L': - return data.size() + 1; - case 'S': - case 'R': - return data.size() + 5; - case 'i': - case 'd': - return data.size() + 13; - default: - throw DeadlyExportError("Requested size on property of unknown type"); - } -} - -void FBXExportProperty::DumpBinary(Assimp::StreamWriterLE& s) { - s.PutU1(type); - uint8_t* d = data.data(); - size_t N; - switch (type) { - case 'C': s.PutU1(*(reinterpret_cast<uint8_t*>(d))); return; - case 'Y': s.PutI2(*(reinterpret_cast<int16_t*>(d))); return; - case 'I': s.PutI4(*(reinterpret_cast<int32_t*>(d))); return; - case 'F': s.PutF4(*(reinterpret_cast<float*>(d))); return; - case 'D': s.PutF8(*(reinterpret_cast<double*>(d))); return; - case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(d))); return; - case 'S': - case 'R': - s.PutU4(uint32_t(data.size())); - for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); } - return; - case 'i': - N = data.size() / 4; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutI4((reinterpret_cast<int32_t*>(d))[i]); - } - return; - case 'l': - N = data.size() / 8; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutI8((reinterpret_cast<int64_t*>(d))[i]); - } - return; - case 'f': - N = data.size() / 4; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutF4((reinterpret_cast<float*>(d))[i]); - } - return; - case 'd': - N = data.size() / 8; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutF8((reinterpret_cast<double*>(d))[i]); - } - return; - default: - std::ostringstream err; - err << "Tried to dump property with invalid type '"; - err << type << "'!"; - throw DeadlyExportError(err.str()); - } -} - -void FBXExportProperty::DumpAscii(Assimp::StreamWriterLE& outstream, int indent) { - std::ostringstream ss; - ss.imbue(std::locale::classic()); - ss.precision(15); // this seems to match official FBX SDK exports - DumpAscii(ss, indent); - outstream.PutString(ss.str()); -} - -void FBXExportProperty::DumpAscii(std::ostream& s, int indent) { - // no writing type... or anything. just shove it into the stream. - uint8_t* d = data.data(); - size_t N; - size_t swap = data.size(); - size_t count = 0; - switch (type) { - case 'C': - if (*(reinterpret_cast<uint8_t*>(d))) { s << 'T'; } - else { s << 'F'; } - return; - case 'Y': s << *(reinterpret_cast<int16_t*>(d)); return; - case 'I': s << *(reinterpret_cast<int32_t*>(d)); return; - case 'F': s << *(reinterpret_cast<float*>(d)); return; - case 'D': s << *(reinterpret_cast<double*>(d)); return; - case 'L': s << *(reinterpret_cast<int64_t*>(d)); return; - case 'S': - // first search to see if it has "\x00\x01" in it - - // which separates fields which are reversed in the ascii version. - // yeah. - // FBX, yeah. - for (size_t i = 0; i < data.size(); ++i) { - if (data[i] == '\0') { - swap = i; - break; - } - } - case 'R': - s << '"'; - // we might as well check this now, - // probably it will never happen - for (size_t i = 0; i < data.size(); ++i) { - char c = data[i]; - if (c == '"') { - throw runtime_error("can't handle quotes in property string"); - } - } - // first write the SWAPPED member (if any) - for (size_t i = swap + 2; i < data.size(); ++i) { - char c = data[i]; - s << c; - } - // then a separator - if (swap != data.size()) { - s << "::"; - } - // then the initial member - for (size_t i = 0; i < swap; ++i) { - char c = data[i]; - s << c; - } - s << '"'; - return; - case 'i': - N = data.size() / 4; // number of elements - s << '*' << N << " {\n"; - for (int i = 0; i < indent + 1; ++i) { s << '\t'; } - s << "a: "; - for (size_t i = 0; i < N; ++i) { - if (i > 0) { s << ','; } - if (count++ > 120) { s << '\n'; count = 0; } - s << (reinterpret_cast<int32_t*>(d))[i]; - } - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "} "; - return; - case 'l': - N = data.size() / 8; - s << '*' << N << " {\n"; - for (int i = 0; i < indent + 1; ++i) { s << '\t'; } - s << "a: "; - for (size_t i = 0; i < N; ++i) { - if (i > 0) { s << ','; } - if (count++ > 120) { s << '\n'; count = 0; } - s << (reinterpret_cast<int64_t*>(d))[i]; - } - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "} "; - return; - case 'f': - N = data.size() / 4; - s << '*' << N << " {\n"; - for (int i = 0; i < indent + 1; ++i) { s << '\t'; } - s << "a: "; - for (size_t i = 0; i < N; ++i) { - if (i > 0) { s << ','; } - if (count++ > 120) { s << '\n'; count = 0; } - s << (reinterpret_cast<float*>(d))[i]; - } - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "} "; - return; - case 'd': - N = data.size() / 8; - s << '*' << N << " {\n"; - for (int i = 0; i < indent + 1; ++i) { s << '\t'; } - s << "a: "; - // set precision to something that can handle doubles - s.precision(15); - for (size_t i = 0; i < N; ++i) { - if (i > 0) { s << ','; } - if (count++ > 120) { s << '\n'; count = 0; } - s << (reinterpret_cast<double*>(d))[i]; - } - s << '\n'; - for (int i = 0; i < indent; ++i) { s << '\t'; } - s << "} "; - return; - default: - std::ostringstream err; - err << "Tried to dump property with invalid type '"; - err << type << "'!"; - throw runtime_error(err.str()); - } -} - -} // Namespace FBX -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER -#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/FBX/FBXExportProperty.h b/thirdparty/assimp/code/FBX/FBXExportProperty.h deleted file mode 100644 index d692fe6ee3..0000000000 --- a/thirdparty/assimp/code/FBX/FBXExportProperty.h +++ /dev/null @@ -1,129 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXExportProperty.h -* Declares the FBX::Property helper class for fbx export. -*/ -#ifndef AI_FBXEXPORTPROPERTY_H_INC -#define AI_FBXEXPORTPROPERTY_H_INC - -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include <assimp/types.h> // aiMatrix4x4 -#include <assimp/StreamWriter.h> // StreamWriterLE - -#include <string> -#include <vector> -#include <ostream> -#include <type_traits> // is_void - -namespace Assimp { -namespace FBX { - -/** @brief FBX::Property - * - * Holds a value of any of FBX's recognized types, - * each represented by a particular one-character code. - * C : 1-byte uint8, usually 0x00 or 0x01 to represent boolean false and true - * Y : 2-byte int16 - * I : 4-byte int32 - * F : 4-byte float - * D : 8-byte double - * L : 8-byte int64 - * i : array of int32 - * f : array of float - * d : array of double - * l : array of int64 - * b : array of 1-byte booleans (0x00 or 0x01) - * S : string (array of 1-byte char) - * R : raw data (array of bytes) - */ -class FBXExportProperty { -public: - // constructors for basic types. - // all explicit to avoid accidental typecasting - explicit FBXExportProperty(bool v); - // TODO: determine if there is actually a byte type, - // or if this always means <bool>. 'C' seems to imply <char>, - // so possibly the above was intended to represent both. - explicit FBXExportProperty(int16_t v); - explicit FBXExportProperty(int32_t v); - explicit FBXExportProperty(float v); - explicit FBXExportProperty(double v); - explicit FBXExportProperty(int64_t v); - // strings can either be stored as 'R' (raw) or 'S' (string) type - explicit FBXExportProperty(const char* c, bool raw = false); - explicit FBXExportProperty(const std::string& s, bool raw = false); - explicit FBXExportProperty(const std::vector<uint8_t>& r); - explicit FBXExportProperty(const std::vector<int32_t>& va); - explicit FBXExportProperty(const std::vector<int64_t>& va); - explicit FBXExportProperty(const std::vector<double>& va); - explicit FBXExportProperty(const std::vector<float>& va); - explicit FBXExportProperty(const aiMatrix4x4& vm); - - // this will catch any type not defined above, - // so that we don't accidentally convert something we don't want. - // for example (const char*) --> (bool)... seriously wtf C++ - template <class T> - explicit FBXExportProperty(T v) : type('X') { - static_assert(std::is_void<T>::value, "TRIED TO CREATE FBX PROPERTY WITH UNSUPPORTED TYPE, CHECK YOUR PROPERTY INSTANTIATION"); - } // note: no line wrap so it appears verbatim on the compiler error - - // the size of this property node in a binary file, in bytes - size_t size(); - - // write this property node as binary data to the given stream - void DumpBinary(Assimp::StreamWriterLE& s); - void DumpAscii(Assimp::StreamWriterLE& s, int indent = 0); - void DumpAscii(std::ostream& s, int indent = 0); - // note: make sure the ostream is in classic "C" locale - -private: - char type; - std::vector<uint8_t> data; -}; - -} // Namespace FBX -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER - -#endif // AI_FBXEXPORTPROPERTY_H_INC diff --git a/thirdparty/assimp/code/FBX/FBXExporter.cpp b/thirdparty/assimp/code/FBX/FBXExporter.cpp deleted file mode 100644 index 9316dc4f02..0000000000 --- a/thirdparty/assimp/code/FBX/FBXExporter.cpp +++ /dev/null @@ -1,2556 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -#ifndef ASSIMP_BUILD_NO_EXPORT -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExporter.h" -#include "FBXExportNode.h" -#include "FBXExportProperty.h" -#include "FBXCommon.h" -#include "FBXUtil.h" - -#include <assimp/version.h> // aiGetVersion -#include <assimp/IOSystem.hpp> -#include <assimp/Exporter.hpp> -#include <assimp/DefaultLogger.hpp> -#include <assimp/StreamWriter.h> // StreamWriterLE -#include <assimp/Exceptional.h> // DeadlyExportError -#include <assimp/material.h> // aiTextureType -#include <assimp/scene.h> -#include <assimp/mesh.h> - -// Header files, standard library. -#include <memory> // shared_ptr -#include <string> -#include <sstream> // stringstream -#include <ctime> // localtime, tm_* -#include <map> -#include <set> -#include <vector> -#include <array> -#include <unordered_set> -#include <numeric> - -// RESOURCES: -// https://code.blender.org/2013/08/fbx-binary-file-format-specification/ -// https://wiki.blender.org/index.php/User:Mont29/Foundation/FBX_File_Structure - -const ai_real DEG = ai_real( 57.29577951308232087679815481 ); // degrees per radian - -using namespace Assimp; -using namespace Assimp::FBX; - -// some constants that we'll use for writing metadata -namespace Assimp { -namespace FBX { - const std::string EXPORT_VERSION_STR = "7.4.0"; - const uint32_t EXPORT_VERSION_INT = 7400; // 7.4 == 2014/2015 - // FBX files have some hashed values that depend on the creation time field, - // but for now we don't actually know how to generate these. - // what we can do is set them to a known-working version. - // this is the data that Blender uses in their FBX export process. - const std::string GENERIC_CTIME = "1970-01-01 10:00:00:000"; - const std::string GENERIC_FILEID = - "\x28\xb3\x2a\xeb\xb6\x24\xcc\xc2\xbf\xc8\xb0\x2a\xa9\x2b\xfc\xf1"; - const std::string GENERIC_FOOTID = - "\xfa\xbc\xab\x09\xd0\xc8\xd4\x66\xb1\x76\xfb\x83\x1c\xf7\x26\x7e"; - const std::string FOOT_MAGIC = - "\xf8\x5a\x8c\x6a\xde\xf5\xd9\x7e\xec\xe9\x0c\xe3\x75\x8f\x29\x0b"; - const std::string COMMENT_UNDERLINE = - ";------------------------------------------------------------------"; -} - - // --------------------------------------------------------------------- - // Worker function for exporting a scene to binary FBX. - // Prototyped and registered in Exporter.cpp - void ExportSceneFBX ( - const char* pFile, - IOSystem* pIOSystem, - const aiScene* pScene, - const ExportProperties* pProperties - ){ - // initialize the exporter - FBXExporter exporter(pScene, pProperties); - - // perform binary export - exporter.ExportBinary(pFile, pIOSystem); - } - - // --------------------------------------------------------------------- - // Worker function for exporting a scene to ASCII FBX. - // Prototyped and registered in Exporter.cpp - void ExportSceneFBXA ( - const char* pFile, - IOSystem* pIOSystem, - const aiScene* pScene, - const ExportProperties* pProperties - - ){ - // initialize the exporter - FBXExporter exporter(pScene, pProperties); - - // perform ascii export - exporter.ExportAscii(pFile, pIOSystem); - } - -} // end of namespace Assimp - -FBXExporter::FBXExporter ( const aiScene* pScene, const ExportProperties* pProperties ) -: binary(false) -, mScene(pScene) -, mProperties(pProperties) -, outfile() -, connections() -, mesh_uids() -, material_uids() -, node_uids() { - // will probably need to determine UIDs, connections, etc here. - // basically anything that needs to be known - // before we start writing sections to the stream. -} - -void FBXExporter::ExportBinary ( - const char* pFile, - IOSystem* pIOSystem -){ - // remember that we're exporting in binary mode - binary = true; - - // we're not currently using these preferences, - // but clang will cry about it if we never touch it. - // TODO: some of these might be relevant to export - (void)mProperties; - - // open the indicated file for writing (in binary mode) - outfile.reset(pIOSystem->Open(pFile,"wb")); - if (!outfile) { - throw DeadlyExportError( - "could not open output .fbx file: " + std::string(pFile) - ); - } - - // first a binary-specific file header - WriteBinaryHeader(); - - // the rest of the file is in node entries. - // we have to serialize each entry before we write to the output, - // as the first thing we write is the byte offset of the _next_ entry. - // Either that or we can skip back to write the offset when we finish. - WriteAllNodes(); - - // finally we have a binary footer to the file - WriteBinaryFooter(); - - // explicitly release file pointer, - // so we don't have to rely on class destruction. - outfile.reset(); -} - -void FBXExporter::ExportAscii ( - const char* pFile, - IOSystem* pIOSystem -){ - // remember that we're exporting in ascii mode - binary = false; - - // open the indicated file for writing in text mode - outfile.reset(pIOSystem->Open(pFile,"wt")); - if (!outfile) { - throw DeadlyExportError( - "could not open output .fbx file: " + std::string(pFile) - ); - } - - // write the ascii header - WriteAsciiHeader(); - - // write all the sections - WriteAllNodes(); - - // make sure the file ends with a newline. - // note: if the file is opened in text mode, - // this should do the right cross-platform thing. - outfile->Write("\n", 1, 1); - - // explicitly release file pointer, - // so we don't have to rely on class destruction. - outfile.reset(); -} - -void FBXExporter::WriteAsciiHeader() -{ - // basically just a comment at the top of the file - std::stringstream head; - head << "; FBX " << EXPORT_VERSION_STR << " project file\n"; - head << "; Created by the Open Asset Import Library (Assimp)\n"; - head << "; http://assimp.org\n"; - head << "; -------------------------------------------------\n"; - const std::string ascii_header = head.str(); - outfile->Write(ascii_header.c_str(), ascii_header.size(), 1); -} - -void FBXExporter::WriteAsciiSectionHeader(const std::string& title) -{ - StreamWriterLE outstream(outfile); - std::stringstream s; - s << "\n\n; " << title << '\n'; - s << FBX::COMMENT_UNDERLINE << "\n"; - outstream.PutString(s.str()); -} - -void FBXExporter::WriteBinaryHeader() -{ - // first a specific sequence of 23 bytes, always the same - const char binary_header[24] = "Kaydara FBX Binary\x20\x20\x00\x1a\x00"; - outfile->Write(binary_header, 1, 23); - - // then FBX version number, "multiplied" by 1000, as little-endian uint32. - // so 7.3 becomes 7300 == 0x841C0000, 7.4 becomes 7400 == 0xE81C0000, etc - { - StreamWriterLE outstream(outfile); - outstream.PutU4(EXPORT_VERSION_INT); - } // StreamWriter destructor writes the data to the file - - // after this the node data starts immediately - // (probably with the FBXHEaderExtension node) -} - -void FBXExporter::WriteBinaryFooter() -{ - outfile->Write(NULL_RECORD.c_str(), NULL_RECORD.size(), 1); - - outfile->Write(GENERIC_FOOTID.c_str(), GENERIC_FOOTID.size(), 1); - - // here some padding is added for alignment to 16 bytes. - // if already aligned, the full 16 bytes is added. - size_t pos = outfile->Tell(); - size_t pad = 16 - (pos % 16); - for (size_t i = 0; i < pad; ++i) { - outfile->Write("\x00", 1, 1); - } - - // not sure what this is, but it seems to always be 0 in modern files - for (size_t i = 0; i < 4; ++i) { - outfile->Write("\x00", 1, 1); - } - - // now the file version again - { - StreamWriterLE outstream(outfile); - outstream.PutU4(EXPORT_VERSION_INT); - } // StreamWriter destructor writes the data to the file - - // and finally some binary footer added to all files - for (size_t i = 0; i < 120; ++i) { - outfile->Write("\x00", 1, 1); - } - outfile->Write(FOOT_MAGIC.c_str(), FOOT_MAGIC.size(), 1); -} - -void FBXExporter::WriteAllNodes () -{ - // header - // (and fileid, creation time, creator, if binary) - WriteHeaderExtension(); - - // global settings - WriteGlobalSettings(); - - // documents - WriteDocuments(); - - // references - WriteReferences(); - - // definitions - WriteDefinitions(); - - // objects - WriteObjects(); - - // connections - WriteConnections(); - - // WriteTakes? (deprecated since at least 2015 (fbx 7.4)) -} - -//FBXHeaderExtension top-level node -void FBXExporter::WriteHeaderExtension () -{ - if (!binary) { - // no title, follows directly from the top comment - } - FBX::Node n("FBXHeaderExtension"); - StreamWriterLE outstream(outfile); - int indent = 0; - - // begin node - n.Begin(outstream, binary, indent); - - // write properties - // (none) - - // finish properties - n.EndProperties(outstream, binary, indent, 0); - - // begin children - n.BeginChildren(outstream, binary, indent); - - indent = 1; - - // write child nodes - FBX::Node::WritePropertyNode( - "FBXHeaderVersion", int32_t(1003), outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "FBXVersion", int32_t(EXPORT_VERSION_INT), outstream, binary, indent - ); - if (binary) { - FBX::Node::WritePropertyNode( - "EncryptionType", int32_t(0), outstream, binary, indent - ); - } - - FBX::Node CreationTimeStamp("CreationTimeStamp"); - time_t rawtime; - time(&rawtime); - struct tm * now = localtime(&rawtime); - CreationTimeStamp.AddChild("Version", int32_t(1000)); - CreationTimeStamp.AddChild("Year", int32_t(now->tm_year + 1900)); - CreationTimeStamp.AddChild("Month", int32_t(now->tm_mon + 1)); - CreationTimeStamp.AddChild("Day", int32_t(now->tm_mday)); - CreationTimeStamp.AddChild("Hour", int32_t(now->tm_hour)); - CreationTimeStamp.AddChild("Minute", int32_t(now->tm_min)); - CreationTimeStamp.AddChild("Second", int32_t(now->tm_sec)); - CreationTimeStamp.AddChild("Millisecond", int32_t(0)); - CreationTimeStamp.Dump(outstream, binary, indent); - - std::stringstream creator; - creator << "Open Asset Import Library (Assimp) " << aiGetVersionMajor() - << "." << aiGetVersionMinor() << "." << aiGetVersionRevision(); - FBX::Node::WritePropertyNode( - "Creator", creator.str(), outstream, binary, indent - ); - - //FBX::Node sceneinfo("SceneInfo"); - //sceneinfo.AddProperty("GlobalInfo" + FBX::SEPARATOR + "SceneInfo"); - // not sure if any of this is actually needed, - // so just write an empty node for now. - //sceneinfo.Dump(outstream, binary, indent); - - indent = 0; - - // finish node - n.End(outstream, binary, indent, true); - - // that's it for FBXHeaderExtension... - if (!binary) { return; } - - // but binary files also need top-level FileID, CreationTime, Creator: - std::vector<uint8_t> raw(GENERIC_FILEID.size()); - for (size_t i = 0; i < GENERIC_FILEID.size(); ++i) { - raw[i] = uint8_t(GENERIC_FILEID[i]); - } - FBX::Node::WritePropertyNode( - "FileId", raw, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "CreationTime", GENERIC_CTIME, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "Creator", creator.str(), outstream, binary, indent - ); -} - -void FBXExporter::WriteGlobalSettings () -{ - if (!binary) { - // no title, follows directly from the header extension - } - FBX::Node gs("GlobalSettings"); - gs.AddChild("Version", int32_t(1000)); - - FBX::Node p("Properties70"); - p.AddP70int("UpAxis", 1); - p.AddP70int("UpAxisSign", 1); - p.AddP70int("FrontAxis", 2); - p.AddP70int("FrontAxisSign", 1); - p.AddP70int("CoordAxis", 0); - p.AddP70int("CoordAxisSign", 1); - p.AddP70int("OriginalUpAxis", 1); - p.AddP70int("OriginalUpAxisSign", 1); - p.AddP70double("UnitScaleFactor", 1.0); - p.AddP70double("OriginalUnitScaleFactor", 1.0); - p.AddP70color("AmbientColor", 0.0, 0.0, 0.0); - p.AddP70string("DefaultCamera", "Producer Perspective"); - p.AddP70enum("TimeMode", 11); - p.AddP70enum("TimeProtocol", 2); - p.AddP70enum("SnapOnFrameMode", 0); - p.AddP70time("TimeSpanStart", 0); // TODO: animation support - p.AddP70time("TimeSpanStop", FBX::SECOND); // TODO: animation support - p.AddP70double("CustomFrameRate", -1.0); - p.AddP70("TimeMarker", "Compound", "", ""); // not sure what this is - p.AddP70int("CurrentTimeMarker", -1); - gs.AddChild(p); - - gs.Dump(outfile, binary, 0); -} - -void FBXExporter::WriteDocuments () -{ - if (!binary) { - WriteAsciiSectionHeader("Documents Description"); - } - - // not sure what the use of multiple documents would be, - // or whether any end-application supports it - FBX::Node docs("Documents"); - docs.AddChild("Count", int32_t(1)); - FBX::Node doc("Document"); - - // generate uid - int64_t uid = generate_uid(); - doc.AddProperties(uid, "", "Scene"); - FBX::Node p("Properties70"); - p.AddP70("SourceObject", "object", "", ""); // what is this even for? - p.AddP70string("ActiveAnimStackName", ""); // should do this properly? - doc.AddChild(p); - - // UID for root node in scene hierarchy. - // always set to 0 in the case of a single document. - // not sure what happens if more than one document exists, - // but that won't matter to us as we're exporting a single scene. - doc.AddChild("RootNode", int64_t(0)); - - docs.AddChild(doc); - docs.Dump(outfile, binary, 0); -} - -void FBXExporter::WriteReferences () -{ - if (!binary) { - WriteAsciiSectionHeader("Document References"); - } - // always empty for now. - // not really sure what this is for. - FBX::Node n("References"); - n.force_has_children = true; - n.Dump(outfile, binary, 0); -} - - -// --------------------------------------------------------------- -// some internal helper functions used for writing the definitions -// (before any actual data is written) -// --------------------------------------------------------------- - -size_t count_nodes(const aiNode* n) { - size_t count = 1; - for (size_t i = 0; i < n->mNumChildren; ++i) { - count += count_nodes(n->mChildren[i]); - } - return count; -} - -bool has_phong_mat(const aiScene* scene) -{ - // just search for any material with a shininess exponent - for (size_t i = 0; i < scene->mNumMaterials; ++i) { - aiMaterial* mat = scene->mMaterials[i]; - float shininess = 0; - mat->Get(AI_MATKEY_SHININESS, shininess); - if (shininess > 0) { - return true; - } - } - return false; -} - -size_t count_images(const aiScene* scene) { - std::unordered_set<std::string> images; - aiString texpath; - for (size_t i = 0; i < scene->mNumMaterials; ++i) { - aiMaterial* mat = scene->mMaterials[i]; - for ( - size_t tt = aiTextureType_DIFFUSE; - tt < aiTextureType_UNKNOWN; - ++tt - ){ - const aiTextureType textype = static_cast<aiTextureType>(tt); - const size_t texcount = mat->GetTextureCount(textype); - for (unsigned int j = 0; j < texcount; ++j) { - mat->GetTexture(textype, j, &texpath); - images.insert(std::string(texpath.C_Str())); - } - } - } - return images.size(); -} - -size_t count_textures(const aiScene* scene) { - size_t count = 0; - for (size_t i = 0; i < scene->mNumMaterials; ++i) { - aiMaterial* mat = scene->mMaterials[i]; - for ( - size_t tt = aiTextureType_DIFFUSE; - tt < aiTextureType_UNKNOWN; - ++tt - ){ - // TODO: handle layered textures - if (mat->GetTextureCount(static_cast<aiTextureType>(tt)) > 0) { - count += 1; - } - } - } - return count; -} - -size_t count_deformers(const aiScene* scene) { - size_t count = 0; - for (size_t i = 0; i < scene->mNumMeshes; ++i) { - const size_t n = scene->mMeshes[i]->mNumBones; - if (n) { - // 1 main deformer, 1 subdeformer per bone - count += n + 1; - } - } - return count; -} - -void FBXExporter::WriteDefinitions () -{ - // basically this is just bookkeeping: - // determining how many of each type of object there are - // and specifying the base properties to use when otherwise unspecified. - - // ascii section header - if (!binary) { - WriteAsciiSectionHeader("Object definitions"); - } - - // we need to count the objects - int32_t count; - int32_t total_count = 0; - - // and store them - std::vector<FBX::Node> object_nodes; - FBX::Node n, pt, p; - - // GlobalSettings - // this seems to always be here in Maya exports - n = FBX::Node("ObjectType", "GlobalSettings"); - count = 1; - n.AddChild("Count", count); - object_nodes.push_back(n); - total_count += count; - - // AnimationStack / FbxAnimStack - // this seems to always be here in Maya exports, - // but no harm seems to come of leaving it out. - count = mScene->mNumAnimations; - if (count) { - n = FBX::Node("ObjectType", "AnimationStack"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxAnimStack"); - p = FBX::Node("Properties70"); - p.AddP70string("Description", ""); - p.AddP70time("LocalStart", 0); - p.AddP70time("LocalStop", 0); - p.AddP70time("ReferenceStart", 0); - p.AddP70time("ReferenceStop", 0); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // AnimationLayer / FbxAnimLayer - // this seems to always be here in Maya exports, - // but no harm seems to come of leaving it out. - // Assimp doesn't support animation layers, - // so there will be one per aiAnimation - count = mScene->mNumAnimations; - if (count) { - n = FBX::Node("ObjectType", "AnimationLayer"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FBXAnimLayer"); - p = FBX::Node("Properties70"); - p.AddP70("Weight", "Number", "", "A", double(100)); - p.AddP70bool("Mute", 0); - p.AddP70bool("Solo", 0); - p.AddP70bool("Lock", 0); - p.AddP70color("Color", 0.8, 0.8, 0.8); - p.AddP70("BlendMode", "enum", "", "", int32_t(0)); - p.AddP70("RotationAccumulationMode", "enum", "", "", int32_t(0)); - p.AddP70("ScaleAccumulationMode", "enum", "", "", int32_t(0)); - p.AddP70("BlendModeBypass", "ULongLong", "", "", int64_t(0)); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // NodeAttribute - // this is completely absurd. - // there can only be one "NodeAttribute" template, - // but FbxSkeleton, FbxCamera, FbxLight all are "NodeAttributes". - // so if only one exists we should set the template for that, - // otherwise... we just pick one :/. - // the others have to set all their properties every instance, - // because there's no template. - count = 1; // TODO: select properly - if (count) { - // FbxSkeleton - n = FBX::Node("ObjectType", "NodeAttribute"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxSkeleton"); - p = FBX::Node("Properties70"); - p.AddP70color("Color", 0.8, 0.8, 0.8); - p.AddP70double("Size", 33.333333333333); - p.AddP70("LimbLength", "double", "Number", "H", double(1)); - // note: not sure what the "H" flag is for - hidden? - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Model / FbxNode - // <~~ node hierarchy - count = int32_t(count_nodes(mScene->mRootNode)) - 1; // (not counting root node) - if (count) { - n = FBX::Node("ObjectType", "Model"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxNode"); - p = FBX::Node("Properties70"); - p.AddP70enum("QuaternionInterpolate", 0); - p.AddP70vector("RotationOffset", 0.0, 0.0, 0.0); - p.AddP70vector("RotationPivot", 0.0, 0.0, 0.0); - p.AddP70vector("ScalingOffset", 0.0, 0.0, 0.0); - p.AddP70vector("ScalingPivot", 0.0, 0.0, 0.0); - p.AddP70bool("TranslationActive", 0); - p.AddP70vector("TranslationMin", 0.0, 0.0, 0.0); - p.AddP70vector("TranslationMax", 0.0, 0.0, 0.0); - p.AddP70bool("TranslationMinX", 0); - p.AddP70bool("TranslationMinY", 0); - p.AddP70bool("TranslationMinZ", 0); - p.AddP70bool("TranslationMaxX", 0); - p.AddP70bool("TranslationMaxY", 0); - p.AddP70bool("TranslationMaxZ", 0); - p.AddP70enum("RotationOrder", 0); - p.AddP70bool("RotationSpaceForLimitOnly", 0); - p.AddP70double("RotationStiffnessX", 0.0); - p.AddP70double("RotationStiffnessY", 0.0); - p.AddP70double("RotationStiffnessZ", 0.0); - p.AddP70double("AxisLen", 10.0); - p.AddP70vector("PreRotation", 0.0, 0.0, 0.0); - p.AddP70vector("PostRotation", 0.0, 0.0, 0.0); - p.AddP70bool("RotationActive", 0); - p.AddP70vector("RotationMin", 0.0, 0.0, 0.0); - p.AddP70vector("RotationMax", 0.0, 0.0, 0.0); - p.AddP70bool("RotationMinX", 0); - p.AddP70bool("RotationMinY", 0); - p.AddP70bool("RotationMinZ", 0); - p.AddP70bool("RotationMaxX", 0); - p.AddP70bool("RotationMaxY", 0); - p.AddP70bool("RotationMaxZ", 0); - p.AddP70enum("InheritType", 0); - p.AddP70bool("ScalingActive", 0); - p.AddP70vector("ScalingMin", 0.0, 0.0, 0.0); - p.AddP70vector("ScalingMax", 1.0, 1.0, 1.0); - p.AddP70bool("ScalingMinX", 0); - p.AddP70bool("ScalingMinY", 0); - p.AddP70bool("ScalingMinZ", 0); - p.AddP70bool("ScalingMaxX", 0); - p.AddP70bool("ScalingMaxY", 0); - p.AddP70bool("ScalingMaxZ", 0); - p.AddP70vector("GeometricTranslation", 0.0, 0.0, 0.0); - p.AddP70vector("GeometricRotation", 0.0, 0.0, 0.0); - p.AddP70vector("GeometricScaling", 1.0, 1.0, 1.0); - p.AddP70double("MinDampRangeX", 0.0); - p.AddP70double("MinDampRangeY", 0.0); - p.AddP70double("MinDampRangeZ", 0.0); - p.AddP70double("MaxDampRangeX", 0.0); - p.AddP70double("MaxDampRangeY", 0.0); - p.AddP70double("MaxDampRangeZ", 0.0); - p.AddP70double("MinDampStrengthX", 0.0); - p.AddP70double("MinDampStrengthY", 0.0); - p.AddP70double("MinDampStrengthZ", 0.0); - p.AddP70double("MaxDampStrengthX", 0.0); - p.AddP70double("MaxDampStrengthY", 0.0); - p.AddP70double("MaxDampStrengthZ", 0.0); - p.AddP70double("PreferedAngleX", 0.0); - p.AddP70double("PreferedAngleY", 0.0); - p.AddP70double("PreferedAngleZ", 0.0); - p.AddP70("LookAtProperty", "object", "", ""); - p.AddP70("UpVectorProperty", "object", "", ""); - p.AddP70bool("Show", 1); - p.AddP70bool("NegativePercentShapeSupport", 1); - p.AddP70int("DefaultAttributeIndex", -1); - p.AddP70bool("Freeze", 0); - p.AddP70bool("LODBox", 0); - p.AddP70( - "Lcl Translation", "Lcl Translation", "", "A", - double(0), double(0), double(0) - ); - p.AddP70( - "Lcl Rotation", "Lcl Rotation", "", "A", - double(0), double(0), double(0) - ); - p.AddP70( - "Lcl Scaling", "Lcl Scaling", "", "A", - double(1), double(1), double(1) - ); - p.AddP70("Visibility", "Visibility", "", "A", double(1)); - p.AddP70( - "Visibility Inheritance", "Visibility Inheritance", "", "", - int32_t(1) - ); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Geometry / FbxMesh - // <~~ aiMesh - count = mScene->mNumMeshes; - if (count) { - n = FBX::Node("ObjectType", "Geometry"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxMesh"); - p = FBX::Node("Properties70"); - p.AddP70color("Color", 0, 0, 0); - p.AddP70vector("BBoxMin", 0, 0, 0); - p.AddP70vector("BBoxMax", 0, 0, 0); - p.AddP70bool("Primary Visibility", 1); - p.AddP70bool("Casts Shadows", 1); - p.AddP70bool("Receive Shadows", 1); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Material / FbxSurfacePhong, FbxSurfaceLambert, FbxSurfaceMaterial - // <~~ aiMaterial - // basically if there's any phong material this is defined as phong, - // and otherwise lambert. - // More complex materials cause a bare-bones FbxSurfaceMaterial definition - // and are treated specially, as they're not really supported by FBX. - // TODO: support Maya's Stingray PBS material - count = mScene->mNumMaterials; - if (count) { - bool has_phong = has_phong_mat(mScene); - n = FBX::Node("ObjectType", "Material"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate"); - if (has_phong) { - pt.AddProperty("FbxSurfacePhong"); - } else { - pt.AddProperty("FbxSurfaceLambert"); - } - p = FBX::Node("Properties70"); - if (has_phong) { - p.AddP70string("ShadingModel", "Phong"); - } else { - p.AddP70string("ShadingModel", "Lambert"); - } - p.AddP70bool("MultiLayer", 0); - p.AddP70colorA("EmissiveColor", 0.0, 0.0, 0.0); - p.AddP70numberA("EmissiveFactor", 1.0); - p.AddP70colorA("AmbientColor", 0.2, 0.2, 0.2); - p.AddP70numberA("AmbientFactor", 1.0); - p.AddP70colorA("DiffuseColor", 0.8, 0.8, 0.8); - p.AddP70numberA("DiffuseFactor", 1.0); - p.AddP70vector("Bump", 0.0, 0.0, 0.0); - p.AddP70vector("NormalMap", 0.0, 0.0, 0.0); - p.AddP70double("BumpFactor", 1.0); - p.AddP70colorA("TransparentColor", 0.0, 0.0, 0.0); - p.AddP70numberA("TransparencyFactor", 0.0); - p.AddP70color("DisplacementColor", 0.0, 0.0, 0.0); - p.AddP70double("DisplacementFactor", 1.0); - p.AddP70color("VectorDisplacementColor", 0.0, 0.0, 0.0); - p.AddP70double("VectorDisplacementFactor", 1.0); - if (has_phong) { - p.AddP70colorA("SpecularColor", 0.2, 0.2, 0.2); - p.AddP70numberA("SpecularFactor", 1.0); - p.AddP70numberA("ShininessExponent", 20.0); - p.AddP70colorA("ReflectionColor", 0.0, 0.0, 0.0); - p.AddP70numberA("ReflectionFactor", 1.0); - } - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Video / FbxVideo - // one for each image file. - count = int32_t(count_images(mScene)); - if (count) { - n = FBX::Node("ObjectType", "Video"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxVideo"); - p = FBX::Node("Properties70"); - p.AddP70bool("ImageSequence", 0); - p.AddP70int("ImageSequenceOffset", 0); - p.AddP70double("FrameRate", 0.0); - p.AddP70int("LastFrame", 0); - p.AddP70int("Width", 0); - p.AddP70int("Height", 0); - p.AddP70("Path", "KString", "XRefUrl", "", ""); - p.AddP70int("StartFrame", 0); - p.AddP70int("StopFrame", 0); - p.AddP70double("PlaySpeed", 0.0); - p.AddP70time("Offset", 0); - p.AddP70enum("InterlaceMode", 0); - p.AddP70bool("FreeRunning", 0); - p.AddP70bool("Loop", 0); - p.AddP70enum("AccessMode", 0); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // Texture / FbxFileTexture - // <~~ aiTexture - count = int32_t(count_textures(mScene)); - if (count) { - n = FBX::Node("ObjectType", "Texture"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxFileTexture"); - p = FBX::Node("Properties70"); - p.AddP70enum("TextureTypeUse", 0); - p.AddP70numberA("Texture alpha", 1.0); - p.AddP70enum("CurrentMappingType", 0); - p.AddP70enum("WrapModeU", 0); - p.AddP70enum("WrapModeV", 0); - p.AddP70bool("UVSwap", 0); - p.AddP70bool("PremultiplyAlpha", 1); - p.AddP70vectorA("Translation", 0.0, 0.0, 0.0); - p.AddP70vectorA("Rotation", 0.0, 0.0, 0.0); - p.AddP70vectorA("Scaling", 1.0, 1.0, 1.0); - p.AddP70vector("TextureRotationPivot", 0.0, 0.0, 0.0); - p.AddP70vector("TextureScalingPivot", 0.0, 0.0, 0.0); - p.AddP70enum("CurrentTextureBlendMode", 1); - p.AddP70string("UVSet", "default"); - p.AddP70bool("UseMaterial", 0); - p.AddP70bool("UseMipMap", 0); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // AnimationCurveNode / FbxAnimCurveNode - count = mScene->mNumAnimations * 3; - if (count) { - n = FBX::Node("ObjectType", "AnimationCurveNode"); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", "FbxAnimCurveNode"); - p = FBX::Node("Properties70"); - p.AddP70("d", "Compound", "", ""); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // AnimationCurve / FbxAnimCurve - count = mScene->mNumAnimations * 9; - if (count) { - n = FBX::Node("ObjectType", "AnimationCurve"); - n.AddChild("Count", count); - object_nodes.push_back(n); - total_count += count; - } - - // Pose - count = 0; - for (size_t i = 0; i < mScene->mNumMeshes; ++i) { - aiMesh* mesh = mScene->mMeshes[i]; - if (mesh->HasBones()) { ++count; } - } - if (count) { - n = FBX::Node("ObjectType", "Pose"); - n.AddChild("Count", count); - object_nodes.push_back(n); - total_count += count; - } - - // Deformer - count = int32_t(count_deformers(mScene)); - if (count) { - n = FBX::Node("ObjectType", "Deformer"); - n.AddChild("Count", count); - object_nodes.push_back(n); - total_count += count; - } - - // (template) - count = 0; - if (count) { - n = FBX::Node("ObjectType", ""); - n.AddChild("Count", count); - pt = FBX::Node("PropertyTemplate", ""); - p = FBX::Node("Properties70"); - pt.AddChild(p); - n.AddChild(pt); - object_nodes.push_back(n); - total_count += count; - } - - // now write it all - FBX::Node defs("Definitions"); - defs.AddChild("Version", int32_t(100)); - defs.AddChild("Count", int32_t(total_count)); - for (auto &n : object_nodes) { defs.AddChild(n); } - defs.Dump(outfile, binary, 0); -} - - -// ------------------------------------------------------------------- -// some internal helper functions used for writing the objects section -// (which holds the actual data) -// ------------------------------------------------------------------- - -aiNode* get_node_for_mesh(unsigned int meshIndex, aiNode* node) -{ - for (size_t i = 0; i < node->mNumMeshes; ++i) { - if (node->mMeshes[i] == meshIndex) { - return node; - } - } - for (size_t i = 0; i < node->mNumChildren; ++i) { - aiNode* ret = get_node_for_mesh(meshIndex, node->mChildren[i]); - if (ret) { return ret; } - } - return nullptr; -} - -aiMatrix4x4 get_world_transform(const aiNode* node, const aiScene* scene) -{ - std::vector<const aiNode*> node_chain; - while (node != scene->mRootNode) { - node_chain.push_back(node); - node = node->mParent; - } - aiMatrix4x4 transform; - for (auto n = node_chain.rbegin(); n != node_chain.rend(); ++n) { - transform *= (*n)->mTransformation; - } - return transform; -} - -int64_t to_ktime(double ticks, const aiAnimation* anim) { - if (anim->mTicksPerSecond <= 0) { - return static_cast<int64_t>(ticks) * FBX::SECOND; - } - return (static_cast<int64_t>(ticks) / static_cast<int64_t>(anim->mTicksPerSecond)) * FBX::SECOND; -} - -int64_t to_ktime(double time) { - return (static_cast<int64_t>(time * FBX::SECOND)); -} - -void FBXExporter::WriteObjects () -{ - if (!binary) { - WriteAsciiSectionHeader("Object properties"); - } - // numbers should match those given in definitions! make sure to check - StreamWriterLE outstream(outfile); - FBX::Node object_node("Objects"); - int indent = 0; - object_node.Begin(outstream, binary, indent); - object_node.EndProperties(outstream, binary, indent); - object_node.BeginChildren(outstream, binary, indent); - - bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true); - std::vector<std::vector<int32_t>> vVertexIndice;//save vertex_indices as it is needed later - - // geometry (aiMesh) - mesh_uids.clear(); - indent = 1; - for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { - // it's all about this mesh - aiMesh* m = mScene->mMeshes[mi]; - - // start the node record - FBX::Node n("Geometry"); - int64_t uid = generate_uid(); - mesh_uids.push_back(uid); - n.AddProperty(uid); - n.AddProperty(FBX::SEPARATOR + "Geometry"); - n.AddProperty("Mesh"); - n.Begin(outstream, binary, indent); - n.DumpProperties(outstream, binary, indent); - n.EndProperties(outstream, binary, indent); - n.BeginChildren(outstream, binary, indent); - indent = 2; - - // output vertex data - each vertex should be unique (probably) - std::vector<double> flattened_vertices; - // index of original vertex in vertex data vector - std::vector<int32_t> vertex_indices; - // map of vertex value to its index in the data vector - std::map<aiVector3D,size_t> index_by_vertex_value; - if(bJoinIdenticalVertices){ - int32_t index = 0; - for (size_t vi = 0; vi < m->mNumVertices; ++vi) { - aiVector3D vtx = m->mVertices[vi]; - auto elem = index_by_vertex_value.find(vtx); - if (elem == index_by_vertex_value.end()) { - vertex_indices.push_back(index); - index_by_vertex_value[vtx] = index; - flattened_vertices.push_back(vtx[0]); - flattened_vertices.push_back(vtx[1]); - flattened_vertices.push_back(vtx[2]); - ++index; - } else { - vertex_indices.push_back(int32_t(elem->second)); - } - } - } - else { // do not join vertex, respect the export flag - vertex_indices.resize(m->mNumVertices); - std::iota(vertex_indices.begin(), vertex_indices.end(), 0); - for(unsigned int v = 0; v < m->mNumVertices; ++ v) { - aiVector3D vtx = m->mVertices[v]; - flattened_vertices.push_back(vtx.x); - flattened_vertices.push_back(vtx.y); - flattened_vertices.push_back(vtx.z); - } - } - vVertexIndice.push_back(vertex_indices); - - FBX::Node::WritePropertyNode( - "Vertices", flattened_vertices, outstream, binary, indent - ); - - // output polygon data as a flattened array of vertex indices. - // the last vertex index of each polygon is negated and - 1 - std::vector<int32_t> polygon_data; - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices - 1; ++pvi) { - polygon_data.push_back(vertex_indices[f.mIndices[pvi]]); - } - polygon_data.push_back( - -1 - vertex_indices[f.mIndices[f.mNumIndices-1]] - ); - } - FBX::Node::WritePropertyNode( - "PolygonVertexIndex", polygon_data, outstream, binary, indent - ); - - // here could be edges but they're insane. - // it's optional anyway, so let's ignore it. - - FBX::Node::WritePropertyNode( - "GeometryVersion", int32_t(124), outstream, binary, indent - ); - - // normals, if any - if (m->HasNormals()) { - FBX::Node normals("LayerElementNormal", int32_t(0)); - normals.Begin(outstream, binary, indent); - normals.DumpProperties(outstream, binary, indent); - normals.EndProperties(outstream, binary, indent); - normals.BeginChildren(outstream, binary, indent); - indent = 3; - FBX::Node::WritePropertyNode( - "Version", int32_t(101), outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "Name", "", outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", - outstream, binary, indent - ); - // TODO: vertex-normals or indexed normals when appropriate - FBX::Node::WritePropertyNode( - "ReferenceInformationType", "Direct", - outstream, binary, indent - ); - std::vector<double> normal_data; - normal_data.reserve(3 * polygon_data.size()); - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { - const aiVector3D &n = m->mNormals[f.mIndices[pvi]]; - normal_data.push_back(n.x); - normal_data.push_back(n.y); - normal_data.push_back(n.z); - } - } - FBX::Node::WritePropertyNode( - "Normals", normal_data, outstream, binary, indent - ); - // note: version 102 has a NormalsW also... not sure what it is, - // so we can stick with version 101 for now. - indent = 2; - normals.End(outstream, binary, indent, true); - } - - // colors, if any - // TODO only one color channel currently - const int32_t colorChannelIndex = 0; - if (m->HasVertexColors(colorChannelIndex)) { - FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex)); - vertexcolors.Begin(outstream, binary, indent); - vertexcolors.DumpProperties(outstream, binary, indent); - vertexcolors.EndProperties(outstream, binary, indent); - vertexcolors.BeginChildren(outstream, binary, indent); - indent = 3; - FBX::Node::WritePropertyNode( - "Version", int32_t(101), outstream, binary, indent - ); - char layerName[8]; - sprintf(layerName, "COLOR_%d", colorChannelIndex); - FBX::Node::WritePropertyNode( - "Name", (const char*)layerName, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", - outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "ReferenceInformationType", "Direct", - outstream, binary, indent - ); - std::vector<double> color_data; - color_data.reserve(4 * polygon_data.size()); - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { - const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]]; - color_data.push_back(c.r); - color_data.push_back(c.g); - color_data.push_back(c.b); - color_data.push_back(c.a); - } - } - FBX::Node::WritePropertyNode( - "Colors", color_data, outstream, binary, indent - ); - indent = 2; - vertexcolors.End(outstream, binary, indent, true); - } - - // uvs, if any - for (size_t uvi = 0; uvi < m->GetNumUVChannels(); ++uvi) { - if (m->mNumUVComponents[uvi] > 2) { - // FBX only supports 2-channel UV maps... - // or at least i'm not sure how to indicate a different number - std::stringstream err; - err << "Only 2-channel UV maps supported by FBX,"; - err << " but mesh " << mi; - if (m->mName.length) { - err << " (" << m->mName.C_Str() << ")"; - } - err << " UV map " << uvi; - err << " has " << m->mNumUVComponents[uvi]; - err << " components! Data will be preserved,"; - err << " but may be incorrectly interpreted on load."; - ASSIMP_LOG_WARN(err.str()); - } - FBX::Node uv("LayerElementUV", int32_t(uvi)); - uv.Begin(outstream, binary, indent); - uv.DumpProperties(outstream, binary, indent); - uv.EndProperties(outstream, binary, indent); - uv.BeginChildren(outstream, binary, indent); - indent = 3; - FBX::Node::WritePropertyNode( - "Version", int32_t(101), outstream, binary, indent - ); - // it doesn't seem like assimp keeps the uv map name, - // so just leave it blank. - FBX::Node::WritePropertyNode( - "Name", "", outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "MappingInformationType", "ByPolygonVertex", - outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "ReferenceInformationType", "IndexToDirect", - outstream, binary, indent - ); - - std::vector<double> uv_data; - std::vector<int32_t> uv_indices; - std::map<aiVector3D,int32_t> index_by_uv; - int32_t index = 0; - for (size_t fi = 0; fi < m->mNumFaces; ++fi) { - const aiFace &f = m->mFaces[fi]; - for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) { - const aiVector3D &uv = - m->mTextureCoords[uvi][f.mIndices[pvi]]; - auto elem = index_by_uv.find(uv); - if (elem == index_by_uv.end()) { - index_by_uv[uv] = index; - uv_indices.push_back(index); - for (unsigned int x = 0; x < m->mNumUVComponents[uvi]; ++x) { - uv_data.push_back(uv[x]); - } - ++index; - } else { - uv_indices.push_back(elem->second); - } - } - } - FBX::Node::WritePropertyNode( - "UV", uv_data, outstream, binary, indent - ); - FBX::Node::WritePropertyNode( - "UVIndex", uv_indices, outstream, binary, indent - ); - indent = 2; - uv.End(outstream, binary, indent, true); - } - - // i'm not really sure why this material section exists, - // as the material is linked via "Connections". - // it seems to always have the same "0" value. - FBX::Node mat("LayerElementMaterial", int32_t(0)); - mat.AddChild("Version", int32_t(101)); - mat.AddChild("Name", ""); - mat.AddChild("MappingInformationType", "AllSame"); - mat.AddChild("ReferenceInformationType", "IndexToDirect"); - std::vector<int32_t> mat_indices = {0}; - mat.AddChild("Materials", mat_indices); - mat.Dump(outstream, binary, indent); - - // finally we have the layer specifications, - // which select the normals / UV set / etc to use. - // TODO: handle multiple uv sets correctly? - FBX::Node layer("Layer", int32_t(0)); - layer.AddChild("Version", int32_t(100)); - FBX::Node le("LayerElement"); - le.AddChild("Type", "LayerElementNormal"); - le.AddChild("TypedIndex", int32_t(0)); - layer.AddChild(le); - // TODO only 1 color channel currently - le = FBX::Node("LayerElement"); - le.AddChild("Type", "LayerElementColor"); - le.AddChild("TypedIndex", int32_t(0)); - layer.AddChild(le); - le = FBX::Node("LayerElement"); - le.AddChild("Type", "LayerElementMaterial"); - le.AddChild("TypedIndex", int32_t(0)); - layer.AddChild(le); - le = FBX::Node("LayerElement"); - le.AddChild("Type", "LayerElementUV"); - le.AddChild("TypedIndex", int32_t(0)); - layer.AddChild(le); - layer.Dump(outstream, binary, indent); - - for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr) - { - FBX::Node layerExtra("Layer", int32_t(lr)); - layerExtra.AddChild("Version", int32_t(100)); - FBX::Node leExtra("LayerElement"); - leExtra.AddChild("Type", "LayerElementUV"); - leExtra.AddChild("TypedIndex", int32_t(lr)); - layerExtra.AddChild(leExtra); - layerExtra.Dump(outstream, binary, indent); - } - // finish the node record - indent = 1; - n.End(outstream, binary, indent, true); - } - - // aiMaterial - material_uids.clear(); - for (size_t i = 0; i < mScene->mNumMaterials; ++i) { - // it's all about this material - aiMaterial* m = mScene->mMaterials[i]; - - // these are used to receive material data - float f; aiColor3D c; - - // start the node record - FBX::Node n("Material"); - - int64_t uid = generate_uid(); - material_uids.push_back(uid); - n.AddProperty(uid); - - aiString name; - m->Get(AI_MATKEY_NAME, name); - n.AddProperty(name.C_Str() + FBX::SEPARATOR + "Material"); - - n.AddProperty(""); - - n.AddChild("Version", int32_t(102)); - f = 0; - m->Get(AI_MATKEY_SHININESS, f); - bool phong = (f > 0); - if (phong) { - n.AddChild("ShadingModel", "phong"); - } else { - n.AddChild("ShadingModel", "lambert"); - } - n.AddChild("MultiLayer", int32_t(0)); - - FBX::Node p("Properties70"); - - // materials exported using the FBX SDK have two sets of fields. - // there are the properties specified in the PropertyTemplate, - // which are those supported by the modernFBX SDK, - // and an extra set of properties with simpler names. - // The extra properties are a legacy material system from pre-2009. - // - // In the modern system, each property has "color" and "factor". - // Generally the interpretation of these seems to be - // that the colour is multiplied by the factor before use, - // but this is not always clear-cut. - // - // Usually assimp only stores the colour, - // so we can just leave the factors at the default "1.0". - - // first we can export the "standard" properties - if (m->Get(AI_MATKEY_COLOR_AMBIENT, c) == aiReturn_SUCCESS) { - p.AddP70colorA("AmbientColor", c.r, c.g, c.b); - //p.AddP70numberA("AmbientFactor", 1.0); - } - if (m->Get(AI_MATKEY_COLOR_DIFFUSE, c) == aiReturn_SUCCESS) { - p.AddP70colorA("DiffuseColor", c.r, c.g, c.b); - //p.AddP70numberA("DiffuseFactor", 1.0); - } - if (m->Get(AI_MATKEY_COLOR_TRANSPARENT, c) == aiReturn_SUCCESS) { - // "TransparentColor" / "TransparencyFactor"... - // thanks FBX, for your insightful interpretation of consistency - p.AddP70colorA("TransparentColor", c.r, c.g, c.b); - // TransparencyFactor defaults to 0.0, so set it to 1.0. - // note: Maya always sets this to 1.0, - // so we can't use it sensibly as "Opacity". - // In stead we rely on the legacy "Opacity" value, below. - // Blender also relies on "Opacity" not "TransparencyFactor", - // probably for a similar reason. - p.AddP70numberA("TransparencyFactor", 1.0); - } - if (m->Get(AI_MATKEY_COLOR_REFLECTIVE, c) == aiReturn_SUCCESS) { - p.AddP70colorA("ReflectionColor", c.r, c.g, c.b); - } - if (m->Get(AI_MATKEY_REFLECTIVITY, f) == aiReturn_SUCCESS) { - p.AddP70numberA("ReflectionFactor", f); - } - if (phong) { - if (m->Get(AI_MATKEY_COLOR_SPECULAR, c) == aiReturn_SUCCESS) { - p.AddP70colorA("SpecularColor", c.r, c.g, c.b); - } - if (m->Get(AI_MATKEY_SHININESS_STRENGTH, f) == aiReturn_SUCCESS) { - p.AddP70numberA("ShininessFactor", f); - } - if (m->Get(AI_MATKEY_SHININESS, f) == aiReturn_SUCCESS) { - p.AddP70numberA("ShininessExponent", f); - } - if (m->Get(AI_MATKEY_REFLECTIVITY, f) == aiReturn_SUCCESS) { - p.AddP70numberA("ReflectionFactor", f); - } - } - - // Now the legacy system. - // For safety let's include it. - // thrse values don't exist in the property template, - // and usually are completely ignored when loading. - // One notable exception is the "Opacity" property, - // which Blender uses as (1.0 - alpha). - c.r = 0.0f; c.g = 0.0f; c.b = 0.0f; - m->Get(AI_MATKEY_COLOR_EMISSIVE, c); - p.AddP70vector("Emissive", c.r, c.g, c.b); - c.r = 0.2f; c.g = 0.2f; c.b = 0.2f; - m->Get(AI_MATKEY_COLOR_AMBIENT, c); - p.AddP70vector("Ambient", c.r, c.g, c.b); - c.r = 0.8f; c.g = 0.8f; c.b = 0.8f; - m->Get(AI_MATKEY_COLOR_DIFFUSE, c); - p.AddP70vector("Diffuse", c.r, c.g, c.b); - // The FBX SDK determines "Opacity" from transparency colour (RGB) - // and factor (F) as: O = (1.0 - F * ((R + G + B) / 3)). - // However we actually have an opacity value, - // so we should take it from AI_MATKEY_OPACITY if possible. - // It might make more sense to use TransparencyFactor, - // but Blender actually loads "Opacity" correctly, so let's use it. - f = 1.0f; - if (m->Get(AI_MATKEY_COLOR_TRANSPARENT, c) == aiReturn_SUCCESS) { - f = 1.0f - ((c.r + c.g + c.b) / 3.0f); - } - m->Get(AI_MATKEY_OPACITY, f); - p.AddP70double("Opacity", f); - if (phong) { - // specular color is multiplied by shininess_strength - c.r = 0.2f; c.g = 0.2f; c.b = 0.2f; - m->Get(AI_MATKEY_COLOR_SPECULAR, c); - f = 1.0f; - m->Get(AI_MATKEY_SHININESS_STRENGTH, f); - p.AddP70vector("Specular", f*c.r, f*c.g, f*c.b); - f = 20.0f; - m->Get(AI_MATKEY_SHININESS, f); - p.AddP70double("Shininess", f); - // Legacy "Reflectivity" is F*F*((R+G+B)/3), - // where F is the proportion of light reflected (AKA reflectivity), - // and RGB is the reflective colour of the material. - // No idea why, but we might as well set it the same way. - f = 0.0f; - m->Get(AI_MATKEY_REFLECTIVITY, f); - c.r = 1.0f, c.g = 1.0f, c.b = 1.0f; - m->Get(AI_MATKEY_COLOR_REFLECTIVE, c); - p.AddP70double("Reflectivity", f*f*((c.r+c.g+c.b)/3.0)); - } - - n.AddChild(p); - - n.Dump(outstream, binary, indent); - } - - // we need to look up all the images we're using, - // so we can generate uids, and eliminate duplicates. - std::map<std::string, int64_t> uid_by_image; - for (size_t i = 0; i < mScene->mNumMaterials; ++i) { - aiString texpath; - aiMaterial* mat = mScene->mMaterials[i]; - for ( - size_t tt = aiTextureType_DIFFUSE; - tt < aiTextureType_UNKNOWN; - ++tt - ){ - const aiTextureType textype = static_cast<aiTextureType>(tt); - const size_t texcount = mat->GetTextureCount(textype); - for (size_t j = 0; j < texcount; ++j) { - mat->GetTexture(textype, (unsigned int)j, &texpath); - const std::string texstring = texpath.C_Str(); - auto elem = uid_by_image.find(texstring); - if (elem == uid_by_image.end()) { - uid_by_image[texstring] = generate_uid(); - } - } - } - } - - // FbxVideo - stores images used by textures. - for (const auto &it : uid_by_image) { - FBX::Node n("Video"); - const int64_t& uid = it.second; - const std::string name = ""; // TODO: ... name??? - n.AddProperties(uid, name + FBX::SEPARATOR + "Video", "Clip"); - n.AddChild("Type", "Clip"); - FBX::Node p("Properties70"); - // TODO: get full path... relative path... etc... ugh... - // for now just use the same path for everything, - // and hopefully one of them will work out. - std::string path = it.first; - // try get embedded texture - const aiTexture* embedded_texture = mScene->GetEmbeddedTexture(it.first.c_str()); - if (embedded_texture != nullptr) { - // change the path (use original filename, if available. If name is empty, concatenate texture index with file extension) - std::stringstream newPath; - if (embedded_texture->mFilename.length > 0) { - newPath << embedded_texture->mFilename.C_Str(); - } else if (embedded_texture->achFormatHint[0]) { - int texture_index = std::stoi(path.substr(1, path.size() - 1)); - newPath << texture_index << "." << embedded_texture->achFormatHint; - } - path = newPath.str(); - // embed the texture - size_t texture_size = static_cast<size_t>(embedded_texture->mWidth * std::max(embedded_texture->mHeight, 1u)); - if (binary) { - // embed texture as binary data - std::vector<uint8_t> tex_data; - tex_data.resize(texture_size); - memcpy(&tex_data[0], (char*)embedded_texture->pcData, texture_size); - n.AddChild("Content", tex_data); - } else { - // embed texture in base64 encoding - std::string encoded_texture = FBX::Util::EncodeBase64((char*)embedded_texture->pcData, texture_size); - n.AddChild("Content", encoded_texture); - } - } - p.AddP70("Path", "KString", "XRefUrl", "", path); - n.AddChild(p); - n.AddChild("UseMipMap", int32_t(0)); - n.AddChild("Filename", path); - n.AddChild("RelativeFilename", path); - n.Dump(outstream, binary, indent); - } - - // Textures - // referenced by material_index/texture_type pairs. - std::map<std::pair<size_t,size_t>,int64_t> texture_uids; - const std::map<aiTextureType,std::string> prop_name_by_tt = { - {aiTextureType_DIFFUSE, "DiffuseColor"}, - {aiTextureType_SPECULAR, "SpecularColor"}, - {aiTextureType_AMBIENT, "AmbientColor"}, - {aiTextureType_EMISSIVE, "EmissiveColor"}, - {aiTextureType_HEIGHT, "Bump"}, - {aiTextureType_NORMALS, "NormalMap"}, - {aiTextureType_SHININESS, "ShininessExponent"}, - {aiTextureType_OPACITY, "TransparentColor"}, - {aiTextureType_DISPLACEMENT, "DisplacementColor"}, - //{aiTextureType_LIGHTMAP, "???"}, - {aiTextureType_REFLECTION, "ReflectionColor"} - //{aiTextureType_UNKNOWN, ""} - }; - for (size_t i = 0; i < mScene->mNumMaterials; ++i) { - // textures are attached to materials - aiMaterial* mat = mScene->mMaterials[i]; - int64_t material_uid = material_uids[i]; - - for ( - size_t j = aiTextureType_DIFFUSE; - j < aiTextureType_UNKNOWN; - ++j - ) { - const aiTextureType tt = static_cast<aiTextureType>(j); - size_t n = mat->GetTextureCount(tt); - - if (n < 1) { // no texture of this type - continue; - } - - if (n > 1) { - // TODO: multilayer textures - std::stringstream err; - err << "Multilayer textures not supported (for now),"; - err << " skipping texture type " << j; - err << " of material " << i; - ASSIMP_LOG_WARN(err.str()); - } - - // get image path for this (single-image) texture - aiString tpath; - if (mat->GetTexture(tt, 0, &tpath) != aiReturn_SUCCESS) { - std::stringstream err; - err << "Failed to get texture 0 for texture of type " << tt; - err << " on material " << i; - err << ", however GetTextureCount returned 1."; - throw DeadlyExportError(err.str()); - } - const std::string texture_path(tpath.C_Str()); - - // get connected image uid - auto elem = uid_by_image.find(texture_path); - if (elem == uid_by_image.end()) { - // this should never happen - std::stringstream err; - err << "Failed to find video element for texture with path"; - err << " \"" << texture_path << "\""; - err << ", type " << j << ", material " << i; - throw DeadlyExportError(err.str()); - } - const int64_t image_uid = elem->second; - - // get the name of the material property to connect to - auto elem2 = prop_name_by_tt.find(tt); - if (elem2 == prop_name_by_tt.end()) { - // don't know how to handle this type of texture, - // so skip it. - std::stringstream err; - err << "Not sure how to handle texture of type " << j; - err << " on material " << i; - err << ", skipping..."; - ASSIMP_LOG_WARN(err.str()); - continue; - } - const std::string& prop_name = elem2->second; - - // generate a uid for this texture - const int64_t texture_uid = generate_uid(); - - // link the texture to the material - connections.emplace_back( - "C", "OP", texture_uid, material_uid, prop_name - ); - - // link the image data to the texture - connections.emplace_back("C", "OO", image_uid, texture_uid); - - // now write the actual texture node - FBX::Node tnode("Texture"); - // TODO: some way to determine texture name? - const std::string texture_name = "" + FBX::SEPARATOR + "Texture"; - tnode.AddProperties(texture_uid, texture_name, ""); - // there really doesn't seem to be a better type than this: - tnode.AddChild("Type", "TextureVideoClip"); - tnode.AddChild("Version", int32_t(202)); - tnode.AddChild("TextureName", texture_name); - FBX::Node p("Properties70"); - p.AddP70enum("CurrentTextureBlendMode", 0); // TODO: verify - //p.AddP70string("UVSet", ""); // TODO: how should this work? - p.AddP70bool("UseMaterial", 1); - tnode.AddChild(p); - // can't easily detrmine which texture path will be correct, - // so just store what we have in every field. - // these being incorrect is a common problem with FBX anyway. - tnode.AddChild("FileName", texture_path); - tnode.AddChild("RelativeFilename", texture_path); - tnode.AddChild("ModelUVTranslation", double(0.0), double(0.0)); - tnode.AddChild("ModelUVScaling", double(1.0), double(1.0)); - tnode.AddChild("Texture_Alpha_Source", "None"); - tnode.AddChild( - "Cropping", int32_t(0), int32_t(0), int32_t(0), int32_t(0) - ); - tnode.Dump(outstream, binary, indent); - } - } - - // bones. - // - // output structure: - // subset of node hierarchy that are "skeleton", - // i.e. do not have meshes but only bones. - // but.. i'm not sure how anyone could guarantee that... - // - // input... - // well, for each mesh it has "bones", - // and the bone names correspond to nodes. - // of course we also need the parent nodes, - // as they give some of the transform........ - // - // well. we can assume a sane input, i suppose. - // - // so input is the bone node hierarchy, - // with an extra thing for the transformation of the MESH in BONE space. - // - // output is a set of bone nodes, - // a "bindpose" which indicates the default local transform of all bones, - // and a set of "deformers". - // each deformer is parented to a mesh geometry, - // and has one or more "subdeformer"s as children. - // each subdeformer has one bone node as a child, - // and represents the influence of that bone on the grandparent mesh. - // the subdeformer has a list of indices, and weights, - // with indices specifying vertex indices, - // and weights specifying the corresponding influence of this bone. - // it also has Transform and TransformLink elements, - // specifying the transform of the MESH in BONE space, - // and the transformation of the BONE in WORLD space, - // likely in the bindpose. - // - // the input bone structure is different but similar, - // storing the number of weights for this bone, - // and an array of (vertex index, weight) pairs. - // - // one sticky point is that the number of vertices may not match, - // because assimp splits vertices by normal, uv, etc. - - // functor for aiNode sorting - struct SortNodeByName - { - bool operator()(const aiNode *lhs, const aiNode *rhs) const - { - return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0; - } - }; - - // first we should mark the skeleton for each mesh. - // the skeleton must include not only the aiBones, - // but also all their parent nodes. - // anything that affects the position of any bone node must be included. - // Use SorNodeByName to make sure the exported result will be the same across all systems - // Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent - std::vector<std::set<const aiNode*, SortNodeByName>> skeleton_by_mesh(mScene->mNumMeshes); - // at the same time we can build a list of all the skeleton nodes, - // which will be used later to mark them as type "limbNode". - std::unordered_set<const aiNode*> limbnodes; - - //actual bone nodes in fbx, without parenting-up - std::unordered_set<std::string> setAllBoneNamesInScene; - for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m) - { - aiMesh* pMesh = mScene->mMeshes[m]; - for(unsigned int b = 0; b < pMesh->mNumBones; ++ b) - setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data); - } - aiMatrix4x4 mxTransIdentity; - - // and a map of nodes by bone name, as finding them is annoying. - std::map<std::string,aiNode*> node_by_bone; - for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { - const aiMesh* m = mScene->mMeshes[mi]; - std::set<const aiNode*, SortNodeByName> skeleton; - for (size_t bi =0; bi < m->mNumBones; ++bi) { - const aiBone* b = m->mBones[bi]; - const std::string name(b->mName.C_Str()); - auto elem = node_by_bone.find(name); - aiNode* n; - if (elem != node_by_bone.end()) { - n = elem->second; - } else { - n = mScene->mRootNode->FindNode(b->mName); - if (!n) { - // this should never happen - std::stringstream err; - err << "Failed to find node for bone: \"" << name << "\""; - throw DeadlyExportError(err.str()); - } - node_by_bone[name] = n; - limbnodes.insert(n); - } - skeleton.insert(n); - // mark all parent nodes as skeleton as well, - // up until we find the root node, - // or else the node containing the mesh, - // or else the parent of a node containig the mesh. - for ( - const aiNode* parent = n->mParent; - parent && parent != mScene->mRootNode; - parent = parent->mParent - ) { - // if we've already done this node we can skip it all - if (skeleton.count(parent)) { - break; - } - // ignore fbx transform nodes as these will be collapsed later - // TODO: cache this by aiNode* - const std::string node_name(parent->mName.C_Str()); - if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) { - continue; - } - //not a bone in scene && no effect in transform - if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end() - && parent->mTransformation == mxTransIdentity) { - continue; - } - // otherwise check if this is the root of the skeleton - bool end = false; - // is the mesh part of this node? - for (size_t i = 0; i < parent->mNumMeshes; ++i) { - if (parent->mMeshes[i] == mi) { - end = true; - break; - } - } - // is the mesh in one of the children of this node? - for (size_t j = 0; j < parent->mNumChildren; ++j) { - aiNode* child = parent->mChildren[j]; - for (size_t i = 0; i < child->mNumMeshes; ++i) { - if (child->mMeshes[i] == mi) { - end = true; - break; - } - } - if (end) { break; } - } - - // if it was the skeleton root we can finish here - if (end) { break; } - } - } - skeleton_by_mesh[mi] = skeleton; - } - - // we'll need the uids for the bone nodes, so generate them now - for (size_t i = 0; i < mScene->mNumMeshes; ++i) { - auto &s = skeleton_by_mesh[i]; - for (const aiNode* n : s) { - auto elem = node_uids.find(n); - if (elem == node_uids.end()) { - node_uids[n] = generate_uid(); - } - } - } - - // now, for each aiMesh, we need to export a deformer, - // and for each aiBone a subdeformer, - // which should have all the skinning info. - // these will need to be connected properly to the mesh, - // and we can do that all now. - for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { - const aiMesh* m = mScene->mMeshes[mi]; - if (!m->HasBones()) { - continue; - } - // make a deformer for this mesh - int64_t deformer_uid = generate_uid(); - FBX::Node dnode("Deformer"); - dnode.AddProperties(deformer_uid, FBX::SEPARATOR + "Deformer", "Skin"); - dnode.AddChild("Version", int32_t(101)); - // "acuracy"... this is not a typo.... - dnode.AddChild("Link_DeformAcuracy", double(50)); - dnode.AddChild("SkinningType", "Linear"); // TODO: other modes? - dnode.Dump(outstream, binary, indent); - - // connect it - connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]); - - //computed before - std::vector<int32_t>& vertex_indices = vVertexIndice[mi]; - - // TODO, FIXME: this won't work if anything is not in the bind pose. - // for now if such a situation is detected, we throw an exception. - std::set<const aiBone*> not_in_bind_pose; - std::set<const aiNode*> no_offset_matrix; - - // first get this mesh's position in world space, - // as we'll need it for each subdeformer. - // - // ...of course taking the position of the MESH doesn't make sense, - // as it can be instanced to many nodes. - // All we can do is assume no instancing, - // and take the first node we find that contains the mesh. - aiNode* mesh_node = get_node_for_mesh((unsigned int)mi, mScene->mRootNode); - aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene); - - // now make a subdeformer for each bone in the skeleton - const std::set<const aiNode*, SortNodeByName> skeleton= skeleton_by_mesh[mi]; - for (const aiNode* bone_node : skeleton) { - // if there's a bone for this node, find it - const aiBone* b = nullptr; - for (size_t bi = 0; bi < m->mNumBones; ++bi) { - // TODO: this probably should index by something else - const std::string name(m->mBones[bi]->mName.C_Str()); - if (node_by_bone[name] == bone_node) { - b = m->mBones[bi]; - break; - } - } - if (!b) { - no_offset_matrix.insert(bone_node); - } - - // start the subdeformer node - const int64_t subdeformer_uid = generate_uid(); - FBX::Node sdnode("Deformer"); - sdnode.AddProperties( - subdeformer_uid, FBX::SEPARATOR + "SubDeformer", "Cluster" - ); - sdnode.AddChild("Version", int32_t(100)); - sdnode.AddChild("UserData", "", ""); - - // add indices and weights, if any - if (b) { - std::vector<int32_t> subdef_indices; - std::vector<double> subdef_weights; - int32_t last_index = -1; - for (size_t wi = 0; wi < b->mNumWeights; ++wi) { - int32_t vi = vertex_indices[b->mWeights[wi].mVertexId]; - if (vi == last_index) { - // only for vertices we exported to fbx - // TODO, FIXME: this assumes identically-located vertices - // will always deform in the same way. - // as assimp doesn't store a separate list of "positions", - // there's not much that can be done about this - // other than assuming that identical position means - // identical vertex. - continue; - } - subdef_indices.push_back(vi); - subdef_weights.push_back(b->mWeights[wi].mWeight); - last_index = vi; - } - // yes, "indexes" - sdnode.AddChild("Indexes", subdef_indices); - sdnode.AddChild("Weights", subdef_weights); - } - - // transform is the transform of the mesh, but in bone space. - // if the skeleton is in the bind pose, - // we can take the inverse of the world-space bone transform - // and multiply by the world-space transform of the mesh. - aiMatrix4x4 bone_xform = get_world_transform(bone_node, mScene); - aiMatrix4x4 inverse_bone_xform = bone_xform; - inverse_bone_xform.Inverse(); - aiMatrix4x4 tr = inverse_bone_xform * mesh_xform; - - sdnode.AddChild("Transform", tr); - - - sdnode.AddChild("TransformLink", bone_xform); - // note: this means we ALWAYS rely on the mesh node transform - // being unchanged from the time the skeleton was bound. - // there's not really any way around this at the moment. - - // done - sdnode.Dump(outstream, binary, indent); - - // lastly, connect to the parent deformer - connections.emplace_back( - "C", "OO", subdeformer_uid, deformer_uid - ); - - // we also need to connect the limb node to the subdeformer. - connections.emplace_back( - "C", "OO", node_uids[bone_node], subdeformer_uid - ); - } - - // if we cannot create a valid FBX file, simply die. - // this will both prevent unnecessary bug reports, - // and tell the user what they can do to fix the situation - // (i.e. export their model in the bind pose). - if (no_offset_matrix.size() && not_in_bind_pose.size()) { - std::stringstream err; - err << "Not enough information to construct bind pose"; - err << " for mesh " << mi << "!"; - err << " Transform matrix for bone \""; - err << (*not_in_bind_pose.begin())->mName.C_Str() << "\""; - if (not_in_bind_pose.size() > 1) { - err << " (and " << not_in_bind_pose.size() - 1 << " more)"; - } - err << " does not match mOffsetMatrix,"; - err << " and node \""; - err << (*no_offset_matrix.begin())->mName.C_Str() << "\""; - if (no_offset_matrix.size() > 1) { - err << " (and " << no_offset_matrix.size() - 1 << " more)"; - } - err << " has no offset matrix to rely on."; - err << " Please ensure bones are in the bind pose to export."; - throw DeadlyExportError(err.str()); - } - - } - - // BindPose - // - // This is a legacy system, which should be unnecessary. - // - // Somehow including it slows file loading by the official FBX SDK, - // and as it can reconstruct it from the deformers anyway, - // this is not currently included. - // - // The code is kept here in case it's useful in the future, - // but it's pretty much a hack anyway, - // as assimp doesn't store bindpose information for full skeletons. - // - /*for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { - aiMesh* mesh = mScene->mMeshes[mi]; - if (! mesh->HasBones()) { continue; } - int64_t bindpose_uid = generate_uid(); - FBX::Node bpnode("Pose"); - bpnode.AddProperty(bindpose_uid); - // note: this uid is never linked or connected to anything. - bpnode.AddProperty(FBX::SEPARATOR + "Pose"); // blank name - bpnode.AddProperty("BindPose"); - - bpnode.AddChild("Type", "BindPose"); - bpnode.AddChild("Version", int32_t(100)); - - aiNode* mesh_node = get_node_for_mesh(mi, mScene->mRootNode); - - // next get the whole skeleton for this mesh. - // we need it all to define the bindpose section. - // the FBX SDK will complain if it's missing, - // and also if parents of used bones don't have a subdeformer. - // order shouldn't matter. - std::set<aiNode*> skeleton; - for (size_t bi = 0; bi < mesh->mNumBones; ++bi) { - // bone node should have already been indexed - const aiBone* b = mesh->mBones[bi]; - const std::string bone_name(b->mName.C_Str()); - aiNode* parent = node_by_bone[bone_name]; - // insert all nodes down to the root or mesh node - while ( - parent - && parent != mScene->mRootNode - && parent != mesh_node - ) { - skeleton.insert(parent); - parent = parent->mParent; - } - } - - // number of pose nodes. includes one for the mesh itself. - bpnode.AddChild("NbPoseNodes", int32_t(1 + skeleton.size())); - - // the first pose node is always the mesh itself - FBX::Node pose("PoseNode"); - pose.AddChild("Node", mesh_uids[mi]); - aiMatrix4x4 mesh_node_xform = get_world_transform(mesh_node, mScene); - pose.AddChild("Matrix", mesh_node_xform); - bpnode.AddChild(pose); - - for (aiNode* bonenode : skeleton) { - // does this node have a uid yet? - int64_t node_uid; - auto node_uid_iter = node_uids.find(bonenode); - if (node_uid_iter != node_uids.end()) { - node_uid = node_uid_iter->second; - } else { - node_uid = generate_uid(); - node_uids[bonenode] = node_uid; - } - - // make a pose thingy - pose = FBX::Node("PoseNode"); - pose.AddChild("Node", node_uid); - aiMatrix4x4 node_xform = get_world_transform(bonenode, mScene); - pose.AddChild("Matrix", node_xform); - bpnode.AddChild(pose); - } - - // now write it - bpnode.Dump(outstream, binary, indent); - }*/ - - // TODO: cameras, lights - - // write nodes (i.e. model hierarchy) - // start at root node - WriteModelNodes( - outstream, mScene->mRootNode, 0, limbnodes - ); - - // animations - // - // in FBX there are: - // * AnimationStack - corresponds to an aiAnimation - // * AnimationLayer - a combinable animation component - // * AnimationCurveNode - links the property to be animated - // * AnimationCurve - defines animation data for a single property value - // - // the CurveNode also provides the default value for a property, - // such as the X, Y, Z coordinates for animatable translation. - // - // the Curve only specifies values for one component of the property, - // so there will be a separate AnimationCurve for X, Y, and Z. - // - // Assimp has: - // * aiAnimation - basically corresponds to an AnimationStack - // * aiNodeAnim - defines all animation for one aiNode - // * aiVectorKey/aiQuatKey - define the keyframe data for T/R/S - // - // assimp has no equivalent for AnimationLayer, - // and these are flattened on FBX import. - // we can assume there will be one per AnimationStack. - // - // the aiNodeAnim contains all animation data for a single aiNode, - // which will correspond to three AnimationCurveNode's: - // one each for translation, rotation and scale. - // The data for each of these will be put in 9 AnimationCurve's, - // T.X, T.Y, T.Z, R.X, R.Y, R.Z, etc. - - // AnimationStack / aiAnimation - std::vector<int64_t> animation_stack_uids(mScene->mNumAnimations); - for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) { - int64_t animstack_uid = generate_uid(); - animation_stack_uids[ai] = animstack_uid; - const aiAnimation* anim = mScene->mAnimations[ai]; - - FBX::Node asnode("AnimationStack"); - std::string name = anim->mName.C_Str() + FBX::SEPARATOR + "AnimStack"; - asnode.AddProperties(animstack_uid, name, ""); - FBX::Node p("Properties70"); - p.AddP70time("LocalStart", 0); // assimp doesn't store this - p.AddP70time("LocalStop", to_ktime(anim->mDuration, anim)); - p.AddP70time("ReferenceStart", 0); - p.AddP70time("ReferenceStop", to_ktime(anim->mDuration, anim)); - asnode.AddChild(p); - - // this node absurdly always pretends it has children - // (in this case it does, but just in case...) - asnode.force_has_children = true; - asnode.Dump(outstream, binary, indent); - - // note: animation stacks are not connected to anything - } - - // AnimationLayer - one per aiAnimation - std::vector<int64_t> animation_layer_uids(mScene->mNumAnimations); - for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) { - int64_t animlayer_uid = generate_uid(); - animation_layer_uids[ai] = animlayer_uid; - FBX::Node alnode("AnimationLayer"); - alnode.AddProperties(animlayer_uid, FBX::SEPARATOR + "AnimLayer", ""); - - // this node absurdly always pretends it has children - alnode.force_has_children = true; - alnode.Dump(outstream, binary, indent); - - // connect to the relevant animstack - connections.emplace_back( - "C", "OO", animlayer_uid, animation_stack_uids[ai] - ); - } - - // AnimCurveNode - three per aiNodeAnim - std::vector<std::vector<std::array<int64_t,3>>> curve_node_uids; - for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) { - const aiAnimation* anim = mScene->mAnimations[ai]; - const int64_t layer_uid = animation_layer_uids[ai]; - std::vector<std::array<int64_t,3>> nodeanim_uids; - for (size_t nai = 0; nai < anim->mNumChannels; ++nai) { - const aiNodeAnim* na = anim->mChannels[nai]; - // get the corresponding aiNode - const aiNode* node = mScene->mRootNode->FindNode(na->mNodeName); - // and its transform - const aiMatrix4x4 node_xfm = get_world_transform(node, mScene); - aiVector3D T, R, S; - node_xfm.Decompose(S, R, T); - - // AnimationCurveNode uids - std::array<int64_t,3> ids; - ids[0] = generate_uid(); // T - ids[1] = generate_uid(); // R - ids[2] = generate_uid(); // S - - // translation - WriteAnimationCurveNode(outstream, - ids[0], "T", T, "Lcl Translation", - layer_uid, node_uids[node] - ); - - // rotation - WriteAnimationCurveNode(outstream, - ids[1], "R", R, "Lcl Rotation", - layer_uid, node_uids[node] - ); - - // scale - WriteAnimationCurveNode(outstream, - ids[2], "S", S, "Lcl Scale", - layer_uid, node_uids[node] - ); - - // store the uids for later use - nodeanim_uids.push_back(ids); - } - curve_node_uids.push_back(nodeanim_uids); - } - - // AnimCurve - defines actual keyframe data. - // there's a separate curve for every component of every vector, - // for example a transform curvenode will have separate X/Y/Z AnimCurve's - for (size_t ai = 0; ai < mScene->mNumAnimations; ++ai) { - const aiAnimation* anim = mScene->mAnimations[ai]; - for (size_t nai = 0; nai < anim->mNumChannels; ++nai) { - const aiNodeAnim* na = anim->mChannels[nai]; - // get the corresponding aiNode - const aiNode* node = mScene->mRootNode->FindNode(na->mNodeName); - // and its transform - const aiMatrix4x4 node_xfm = get_world_transform(node, mScene); - aiVector3D T, R, S; - node_xfm.Decompose(S, R, T); - const std::array<int64_t,3>& ids = curve_node_uids[ai][nai]; - - std::vector<int64_t> times; - std::vector<float> xval, yval, zval; - - // position/translation - for (size_t ki = 0; ki < na->mNumPositionKeys; ++ki) { - const aiVectorKey& k = na->mPositionKeys[ki]; - times.push_back(to_ktime(k.mTime)); - xval.push_back(k.mValue.x); - yval.push_back(k.mValue.y); - zval.push_back(k.mValue.z); - } - // one curve each for X, Y, Z - WriteAnimationCurve(outstream, T.x, times, xval, ids[0], "d|X"); - WriteAnimationCurve(outstream, T.y, times, yval, ids[0], "d|Y"); - WriteAnimationCurve(outstream, T.z, times, zval, ids[0], "d|Z"); - - // rotation - times.clear(); xval.clear(); yval.clear(); zval.clear(); - for (size_t ki = 0; ki < na->mNumRotationKeys; ++ki) { - const aiQuatKey& k = na->mRotationKeys[ki]; - times.push_back(to_ktime(k.mTime)); - // TODO: aiQuaternion method to convert to Euler... - aiMatrix4x4 m(k.mValue.GetMatrix()); - aiVector3D qs, qr, qt; - m.Decompose(qs, qr, qt); - qr *= DEG; - xval.push_back(qr.x); - yval.push_back(qr.y); - zval.push_back(qr.z); - } - WriteAnimationCurve(outstream, R.x, times, xval, ids[1], "d|X"); - WriteAnimationCurve(outstream, R.y, times, yval, ids[1], "d|Y"); - WriteAnimationCurve(outstream, R.z, times, zval, ids[1], "d|Z"); - - // scaling/scale - times.clear(); xval.clear(); yval.clear(); zval.clear(); - for (size_t ki = 0; ki < na->mNumScalingKeys; ++ki) { - const aiVectorKey& k = na->mScalingKeys[ki]; - times.push_back(to_ktime(k.mTime)); - xval.push_back(k.mValue.x); - yval.push_back(k.mValue.y); - zval.push_back(k.mValue.z); - } - WriteAnimationCurve(outstream, S.x, times, xval, ids[2], "d|X"); - WriteAnimationCurve(outstream, S.y, times, yval, ids[2], "d|Y"); - WriteAnimationCurve(outstream, S.z, times, zval, ids[2], "d|Z"); - } - } - - indent = 0; - object_node.End(outstream, binary, indent, true); -} - -// convenience map of magic node name strings to FBX properties, -// including the expected type of transform. -const std::map<std::string,std::pair<std::string,char>> transform_types = { - {"Translation", {"Lcl Translation", 't'}}, - {"RotationOffset", {"RotationOffset", 't'}}, - {"RotationPivot", {"RotationPivot", 't'}}, - {"PreRotation", {"PreRotation", 'r'}}, - {"Rotation", {"Lcl Rotation", 'r'}}, - {"PostRotation", {"PostRotation", 'r'}}, - {"RotationPivotInverse", {"RotationPivotInverse", 'i'}}, - {"ScalingOffset", {"ScalingOffset", 't'}}, - {"ScalingPivot", {"ScalingPivot", 't'}}, - {"Scaling", {"Lcl Scaling", 's'}}, - {"ScalingPivotInverse", {"ScalingPivotInverse", 'i'}}, - {"GeometricScaling", {"GeometricScaling", 's'}}, - {"GeometricRotation", {"GeometricRotation", 'r'}}, - {"GeometricTranslation", {"GeometricTranslation", 't'}}, - {"GeometricTranslationInverse", {"GeometricTranslationInverse", 'i'}}, - {"GeometricRotationInverse", {"GeometricRotationInverse", 'i'}}, - {"GeometricScalingInverse", {"GeometricScalingInverse", 'i'}} -}; - -// write a single model node to the stream -void FBXExporter::WriteModelNode( - StreamWriterLE& outstream, - bool binary, - const aiNode* node, - int64_t node_uid, - const std::string& type, - const std::vector<std::pair<std::string,aiVector3D>>& transform_chain, - TransformInheritance inherit_type -){ - const aiVector3D zero = {0, 0, 0}; - const aiVector3D one = {1, 1, 1}; - FBX::Node m("Model"); - std::string name = node->mName.C_Str() + FBX::SEPARATOR + "Model"; - m.AddProperties(node_uid, name, type); - m.AddChild("Version", int32_t(232)); - FBX::Node p("Properties70"); - p.AddP70bool("RotationActive", 1); - p.AddP70int("DefaultAttributeIndex", 0); - p.AddP70enum("InheritType", inherit_type); - if (transform_chain.empty()) { - // decompose 4x4 transform matrix into TRS - aiVector3D t, r, s; - node->mTransformation.Decompose(s, r, t); - if (t != zero) { - p.AddP70( - "Lcl Translation", "Lcl Translation", "", "A", - double(t.x), double(t.y), double(t.z) - ); - } - if (r != zero) { - p.AddP70( - "Lcl Rotation", "Lcl Rotation", "", "A", - double(DEG*r.x), double(DEG*r.y), double(DEG*r.z) - ); - } - if (s != one) { - p.AddP70( - "Lcl Scaling", "Lcl Scaling", "", "A", - double(s.x), double(s.y), double(s.z) - ); - } - } else { - // apply the transformation chain. - // these transformation elements are created when importing FBX, - // which has a complex transformation hierarchy for each node. - // as such we can bake the hierarchy back into the node on export. - for (auto &item : transform_chain) { - auto elem = transform_types.find(item.first); - if (elem == transform_types.end()) { - // then this is a bug - std::stringstream err; - err << "unrecognized FBX transformation type: "; - err << item.first; - throw DeadlyExportError(err.str()); - } - const std::string &name = elem->second.first; - const aiVector3D &v = item.second; - if (name.compare(0, 4, "Lcl ") == 0) { - // special handling for animatable properties - p.AddP70( - name, name, "", "A", - double(v.x), double(v.y), double(v.z) - ); - } else { - p.AddP70vector(name, v.x, v.y, v.z); - } - } - } - m.AddChild(p); - - // not sure what these are for, - // but they seem to be omnipresent - m.AddChild("Shading", FBXExportProperty(true)); - m.AddChild("Culling", FBXExportProperty("CullingOff")); - - m.Dump(outstream, binary, 1); -} - -// wrapper for WriteModelNodes to create and pass a blank transform chain -void FBXExporter::WriteModelNodes( - StreamWriterLE& s, - const aiNode* node, - int64_t parent_uid, - const std::unordered_set<const aiNode*>& limbnodes -) { - std::vector<std::pair<std::string,aiVector3D>> chain; - WriteModelNodes(s, node, parent_uid, limbnodes, chain); -} - -void FBXExporter::WriteModelNodes( - StreamWriterLE& outstream, - const aiNode* node, - int64_t parent_uid, - const std::unordered_set<const aiNode*>& limbnodes, - std::vector<std::pair<std::string,aiVector3D>>& transform_chain -) { - // first collapse any expanded transformation chains created by FBX import. - std::string node_name(node->mName.C_Str()); - if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) { - auto pos = node_name.find(MAGIC_NODE_TAG) + MAGIC_NODE_TAG.size() + 1; - std::string type_name = node_name.substr(pos); - auto elem = transform_types.find(type_name); - if (elem == transform_types.end()) { - // then this is a bug and should be fixed - std::stringstream err; - err << "unrecognized FBX transformation node"; - err << " of type " << type_name << " in node " << node_name; - throw DeadlyExportError(err.str()); - } - aiVector3D t, r, s; - node->mTransformation.Decompose(s, r, t); - switch (elem->second.second) { - case 'i': // inverse - // we don't need to worry about the inverse matrices - break; - case 't': // translation - transform_chain.emplace_back(elem->first, t); - break; - case 'r': // rotation - r *= float(DEG); - transform_chain.emplace_back(elem->first, r); - break; - case 's': // scale - transform_chain.emplace_back(elem->first, s); - break; - default: - // this should never happen - std::stringstream err; - err << "unrecognized FBX transformation type code: "; - err << elem->second.second; - throw DeadlyExportError(err.str()); - } - // now continue on to any child nodes - for (unsigned i = 0; i < node->mNumChildren; ++i) { - WriteModelNodes( - outstream, - node->mChildren[i], - parent_uid, - limbnodes, - transform_chain - ); - } - return; - } - - int64_t node_uid = 0; - // generate uid and connect to parent, if not the root node, - if (node != mScene->mRootNode) { - auto elem = node_uids.find(node); - if (elem != node_uids.end()) { - node_uid = elem->second; - } else { - node_uid = generate_uid(); - node_uids[node] = node_uid; - } - connections.emplace_back("C", "OO", node_uid, parent_uid); - } - - // what type of node is this? - if (node == mScene->mRootNode) { - // handled later - } else if (node->mNumMeshes == 1) { - // connect to child mesh, which should have been written previously - connections.emplace_back( - "C", "OO", mesh_uids[node->mMeshes[0]], node_uid - ); - // also connect to the material for the child mesh - connections.emplace_back( - "C", "OO", - material_uids[mScene->mMeshes[node->mMeshes[0]]->mMaterialIndex], - node_uid - ); - // write model node - WriteModelNode( - outstream, binary, node, node_uid, "Mesh", transform_chain - ); - } else if (limbnodes.count(node)) { - WriteModelNode( - outstream, binary, node, node_uid, "LimbNode", transform_chain - ); - // we also need to write a nodeattribute to mark it as a skeleton - int64_t node_attribute_uid = generate_uid(); - FBX::Node na("NodeAttribute"); - na.AddProperties( - node_attribute_uid, FBX::SEPARATOR + "NodeAttribute", "LimbNode" - ); - na.AddChild("TypeFlags", FBXExportProperty("Skeleton")); - na.Dump(outstream, binary, 1); - // and connect them - connections.emplace_back("C", "OO", node_attribute_uid, node_uid); - } else { - // generate a null node so we can add children to it - WriteModelNode( - outstream, binary, node, node_uid, "Null", transform_chain - ); - } - - // if more than one child mesh, make nodes for each mesh - if (node->mNumMeshes > 1 || node == mScene->mRootNode) { - for (size_t i = 0; i < node->mNumMeshes; ++i) { - // make a new model node - int64_t new_node_uid = generate_uid(); - // connect to parent node - connections.emplace_back("C", "OO", new_node_uid, node_uid); - // connect to child mesh, which should have been written previously - connections.emplace_back( - "C", "OO", mesh_uids[node->mMeshes[i]], new_node_uid - ); - // also connect to the material for the child mesh - connections.emplace_back( - "C", "OO", - material_uids[ - mScene->mMeshes[node->mMeshes[i]]->mMaterialIndex - ], - new_node_uid - ); - // write model node - FBX::Node m("Model"); - // take name from mesh name, if it exists - std::string name = mScene->mMeshes[node->mMeshes[i]]->mName.C_Str(); - name += FBX::SEPARATOR + "Model"; - m.AddProperties(new_node_uid, name, "Mesh"); - m.AddChild("Version", int32_t(232)); - FBX::Node p("Properties70"); - p.AddP70enum("InheritType", 1); - m.AddChild(p); - m.Dump(outstream, binary, 1); - } - } - - // now recurse into children - for (size_t i = 0; i < node->mNumChildren; ++i) { - WriteModelNodes( - outstream, node->mChildren[i], node_uid, limbnodes - ); - } -} - - -void FBXExporter::WriteAnimationCurveNode( - StreamWriterLE& outstream, - int64_t uid, - const std::string& name, // "T", "R", or "S" - aiVector3D default_value, - std::string property_name, // "Lcl Translation" etc - int64_t layer_uid, - int64_t node_uid -) { - FBX::Node n("AnimationCurveNode"); - n.AddProperties(uid, name + FBX::SEPARATOR + "AnimCurveNode", ""); - FBX::Node p("Properties70"); - p.AddP70numberA("d|X", default_value.x); - p.AddP70numberA("d|Y", default_value.y); - p.AddP70numberA("d|Z", default_value.z); - n.AddChild(p); - n.Dump(outstream, binary, 1); - // connect to layer - this->connections.emplace_back("C", "OO", uid, layer_uid); - // connect to bone - this->connections.emplace_back("C", "OP", uid, node_uid, property_name); -} - - -void FBXExporter::WriteAnimationCurve( - StreamWriterLE& outstream, - double default_value, - const std::vector<int64_t>& times, - const std::vector<float>& values, - int64_t curvenode_uid, - const std::string& property_link // "d|X", "d|Y", etc -) { - FBX::Node n("AnimationCurve"); - int64_t curve_uid = generate_uid(); - n.AddProperties(curve_uid, FBX::SEPARATOR + "AnimCurve", ""); - n.AddChild("Default", default_value); - n.AddChild("KeyVer", int32_t(4009)); - n.AddChild("KeyTime", times); - n.AddChild("KeyValueFloat", values); - // TODO: keyattr flags and data (STUB for now) - n.AddChild("KeyAttrFlags", std::vector<int32_t>{0}); - n.AddChild("KeyAttrDataFloat", std::vector<float>{0,0,0,0}); - n.AddChild( - "KeyAttrRefCount", - std::vector<int32_t>{static_cast<int32_t>(times.size())} - ); - n.Dump(outstream, binary, 1); - this->connections.emplace_back( - "C", "OP", curve_uid, curvenode_uid, property_link - ); -} - - -void FBXExporter::WriteConnections () -{ - // we should have completed the connection graph already, - // so basically just dump it here - if (!binary) { - WriteAsciiSectionHeader("Object connections"); - } - // TODO: comments with names in the ascii version - FBX::Node conn("Connections"); - StreamWriterLE outstream(outfile); - conn.Begin(outstream, binary, 0); - conn.BeginChildren(outstream, binary, 0); - for (auto &n : connections) { - n.Dump(outstream, binary, 1); - } - conn.End(outstream, binary, 0, !connections.empty()); - connections.clear(); -} - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER -#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/thirdparty/assimp/code/FBX/FBXExporter.h b/thirdparty/assimp/code/FBX/FBXExporter.h deleted file mode 100644 index 1ae727eda9..0000000000 --- a/thirdparty/assimp/code/FBX/FBXExporter.h +++ /dev/null @@ -1,178 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXExporter.h -* Declares the exporter class to write a scene to an fbx file -*/ -#ifndef AI_FBXEXPORTER_H_INC -#define AI_FBXEXPORTER_H_INC - -#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - -#include "FBXExportNode.h" // FBX::Node -#include "FBXCommon.h" // FBX::TransformInheritance - -#include <assimp/types.h> -//#include <assimp/material.h> -#include <assimp/StreamWriter.h> // StreamWriterLE -#include <assimp/Exceptional.h> // DeadlyExportError - -#include <vector> -#include <map> -#include <unordered_set> -#include <memory> // shared_ptr -#include <sstream> // stringstream - -struct aiScene; -struct aiNode; -//struct aiMaterial; - -namespace Assimp -{ - class IOSystem; - class IOStream; - class ExportProperties; - - // --------------------------------------------------------------------- - /** Helper class to export a given scene to an FBX file. */ - // --------------------------------------------------------------------- - class FBXExporter - { - public: - /// Constructor for a specific scene to export - FBXExporter(const aiScene* pScene, const ExportProperties* pProperties); - - // call one of these methods to export - void ExportBinary(const char* pFile, IOSystem* pIOSystem); - void ExportAscii(const char* pFile, IOSystem* pIOSystem); - - private: - bool binary; // whether current export is in binary or ascii format - const aiScene* mScene; // the scene to export - const ExportProperties* mProperties; // currently unused - std::shared_ptr<IOStream> outfile; // file to write to - - std::vector<FBX::Node> connections; // connection storage - - std::vector<int64_t> mesh_uids; - std::vector<int64_t> material_uids; - std::map<const aiNode*,int64_t> node_uids; - - // this crude unique-ID system is actually fine - int64_t last_uid = 999999; - int64_t generate_uid() { return ++last_uid; } - - // binary files have a specific header and footer, - // in addition to the actual data - void WriteBinaryHeader(); - void WriteBinaryFooter(); - - // ascii files have a comment at the top - void WriteAsciiHeader(); - - // WriteAllNodes does the actual export. - // It just calls all the Write<Section> methods below in order. - void WriteAllNodes(); - - // Methods to write individual sections. - // The order here matches the order inside an FBX file. - // Each method corresponds to a top-level FBX section, - // except WriteHeader which also includes some binary-only sections - // and WriteFooter which is binary data only. - void WriteHeaderExtension(); - // WriteFileId(); // binary-only, included in WriteHeader - // WriteCreationTime(); // binary-only, included in WriteHeader - // WriteCreator(); // binary-only, included in WriteHeader - void WriteGlobalSettings(); - void WriteDocuments(); - void WriteReferences(); - void WriteDefinitions(); - void WriteObjects(); - void WriteConnections(); - // WriteTakes(); // deprecated since at least 2015 (fbx 7.4) - - // helpers - void WriteAsciiSectionHeader(const std::string& title); - void WriteModelNodes( - Assimp::StreamWriterLE& s, - const aiNode* node, - int64_t parent_uid, - const std::unordered_set<const aiNode*>& limbnodes - ); - void WriteModelNodes( // usually don't call this directly - StreamWriterLE& s, - const aiNode* node, - int64_t parent_uid, - const std::unordered_set<const aiNode*>& limbnodes, - std::vector<std::pair<std::string,aiVector3D>>& transform_chain - ); - void WriteModelNode( // nor this - StreamWriterLE& s, - bool binary, - const aiNode* node, - int64_t node_uid, - const std::string& type, - const std::vector<std::pair<std::string,aiVector3D>>& xfm_chain, - FBX::TransformInheritance ti_type=FBX::TransformInheritance_RSrs - ); - void WriteAnimationCurveNode( - StreamWriterLE& outstream, - int64_t uid, - const std::string& name, // "T", "R", or "S" - aiVector3D default_value, - std::string property_name, // "Lcl Translation" etc - int64_t animation_layer_uid, - int64_t node_uid - ); - void WriteAnimationCurve( - StreamWriterLE& outstream, - double default_value, - const std::vector<int64_t>& times, - const std::vector<float>& values, - int64_t curvenode_id, - const std::string& property_link // "d|X", "d|Y", etc - ); - }; -} - -#endif // ASSIMP_BUILD_NO_FBX_EXPORTER - -#endif // AI_FBXEXPORTER_H_INC diff --git a/thirdparty/assimp/code/FBX/FBXImportSettings.h b/thirdparty/assimp/code/FBX/FBXImportSettings.h deleted file mode 100644 index 1a4c80f8b2..0000000000 --- a/thirdparty/assimp/code/FBX/FBXImportSettings.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXImportSettings.h - * @brief FBX importer runtime configuration - */ -#ifndef INCLUDED_AI_FBX_IMPORTSETTINGS_H -#define INCLUDED_AI_FBX_IMPORTSETTINGS_H - -namespace Assimp { -namespace FBX { - -/** FBX import settings, parts of which are publicly accessible via their corresponding AI_CONFIG constants */ -struct ImportSettings -{ - ImportSettings() - : strictMode(true) - , readAllLayers(true) - , readAllMaterials(false) - , readMaterials(true) - , readTextures(true) - , readCameras(true) - , readLights(true) - , readAnimations(true) - , readWeights(true) - , preservePivots(true) - , optimizeEmptyAnimationCurves(true) - , useLegacyEmbeddedTextureNaming(false) - , removeEmptyBones( true ) - , convertToMeters( false ) { - // empty - } - - - /** enable strict mode: - * - only accept fbx 2012, 2013 files - * - on the slightest error, give up. - * - * Basically, strict mode means that the fbx file will actually - * be validated. Strict mode is off by default. */ - bool strictMode; - - /** specifies whether all geometry layers are read and scanned for - * usable data channels. The FBX spec indicates that many readers - * will only read the first channel and that this is in some way - * the recommended way- in reality, however, it happens a lot that - * vertex data is spread among multiple layers. The default - * value for this option is true.*/ - bool readAllLayers; - - /** specifies whether all materials are read, or only those that - * are referenced by at least one mesh. Reading all materials - * may make FBX reading a lot slower since all objects - * need to be processed . - * This bit is ignored unless readMaterials=true*/ - bool readAllMaterials; - - - /** import materials (true) or skip them and assign a default - * material. The default value is true.*/ - bool readMaterials; - - /** import embedded textures? Default value is true.*/ - bool readTextures; - - /** import cameras? Default value is true.*/ - bool readCameras; - - /** import light sources? Default value is true.*/ - bool readLights; - - /** import animations (i.e. animation curves, the node - * skeleton is always imported). Default value is true. */ - bool readAnimations; - - /** read bones (vertex weights and deform info). - * Default value is true. */ - bool readWeights; - - /** preserve transformation pivots and offsets. Since these can - * not directly be represented in assimp, additional dummy - * nodes will be generated. Note that settings this to false - * can make animation import a lot slower. The default value - * is true. - * - * The naming scheme for the generated nodes is: - * <OriginalName>_$AssimpFbx$_<TransformName> - * - * where <TransformName> is one of - * RotationPivot - * RotationOffset - * PreRotation - * PostRotation - * ScalingPivot - * ScalingOffset - * Translation - * Scaling - * Rotation - **/ - bool preservePivots; - - /** do not import animation curves that specify a constant - * values matching the corresponding node transformation. - * The default value is true. */ - bool optimizeEmptyAnimationCurves; - - /** use legacy naming for embedded textures eg: (*0, *1, *2) - */ - bool useLegacyEmbeddedTextureNaming; - - /** Empty bones shall be removed - */ - bool removeEmptyBones; - - /** Set to true to perform a conversion from cm to meter after the import - */ - bool convertToMeters; -}; - - -} // !FBX -} // !Assimp - -#endif - diff --git a/thirdparty/assimp/code/FBX/FBXImporter.cpp b/thirdparty/assimp/code/FBX/FBXImporter.cpp deleted file mode 100644 index afcc1ddc78..0000000000 --- a/thirdparty/assimp/code/FBX/FBXImporter.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. -r -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXImporter.cpp - * @brief Implementation of the FBX importer. - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXImporter.h" - -#include "FBXConverter.h" -#include "FBXDocument.h" -#include "FBXParser.h" -#include "FBXTokenizer.h" -#include "FBXUtil.h" - -#include <assimp/MemoryIOWrapper.h> -#include <assimp/StreamReader.h> -#include <assimp/importerdesc.h> -#include <assimp/Importer.hpp> - -namespace Assimp { - -template <> -const char *LogFunctions<FBXImporter>::Prefix() { - static auto prefix = "FBX: "; - return prefix; -} - -} // namespace Assimp - -using namespace Assimp; -using namespace Assimp::Formatter; -using namespace Assimp::FBX; - -namespace { - -static const aiImporterDesc desc = { - "Autodesk FBX Importer", - "", - "", - "", - aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "fbx" -}; -} - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by #Importer -FBXImporter::FBXImporter() { -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FBXImporter::~FBXImporter() { -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the class can handle the format of the given file. -bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { - const std::string &extension = GetExtension(pFile); - if (extension == std::string(desc.mFileExtensions)) { - return true; - } - - else if ((!extension.length() || checkSig) && pIOHandler) { - // at least ASCII-FBX files usually have a 'FBX' somewhere in their head - const char *tokens[] = { "fbx" }; - return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); - } - return false; -} - -// ------------------------------------------------------------------------------------------------ -// List all extensions handled by this loader -const aiImporterDesc *FBXImporter::GetInfo() const { - return &desc; -} - -// ------------------------------------------------------------------------------------------------ -// Setup configuration properties for the loader -void FBXImporter::SetupProperties(const Importer *pImp) { - settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true); - settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false); - settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true); - settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true); - settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true); - settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true); - settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true); - settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false); - settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true); - settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true); - settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false); - settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true); - settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false); -} - -// ------------------------------------------------------------------------------------------------ -// Imports the given file into the given scene structure. -void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { - std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb")); - if (!stream) { - ThrowException("Could not open file for reading"); - } - - // read entire file into memory - no streaming for this, fbx - // files can grow large, but the assimp output data structure - // then becomes very large, too. Assimp doesn't support - // streaming for its output data structures so the net win with - // streaming input data would be very low. - std::vector<char> contents; - contents.resize(stream->FileSize() + 1); - stream->Read(&*contents.begin(), 1, contents.size() - 1); - contents[contents.size() - 1] = 0; - const char *const begin = &*contents.begin(); - - // broadphase tokenizing pass in which we identify the core - // syntax elements of FBX (brackets, commas, key:value mappings) - TokenList tokens; - try { - - bool is_binary = false; - if (!strncmp(begin, "Kaydara FBX Binary", 18)) { - is_binary = true; - TokenizeBinary(tokens, begin, contents.size()); - } else { - Tokenize(tokens, begin); - } - - // use this information to construct a very rudimentary - // parse-tree representing the FBX scope structure - Parser parser(tokens, is_binary); - - // take the raw parse-tree and convert it to a FBX DOM - Document doc(parser, settings); - - // convert the FBX DOM to aiScene - ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones); - - // size relative to cm - float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor(); - - // Set FBX file scale is relative to CM must be converted to M for - // assimp universal format (M) - SetFileScale(size_relative_to_cm * 0.01f); - - std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>()); - } catch (std::exception &) { - std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>()); - throw; - } -} - -#endif // !ASSIMP_BUILD_NO_FBX_IMPORTER diff --git a/thirdparty/assimp/code/FBX/FBXImporter.h b/thirdparty/assimp/code/FBX/FBXImporter.h deleted file mode 100644 index c365b2cddf..0000000000 --- a/thirdparty/assimp/code/FBX/FBXImporter.h +++ /dev/null @@ -1,100 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXImporter.h - * @brief Declaration of the FBX main importer class - */ -#ifndef INCLUDED_AI_FBX_IMPORTER_H -#define INCLUDED_AI_FBX_IMPORTER_H - -#include <assimp/BaseImporter.h> -#include <assimp/LogAux.h> - -#include "FBXImportSettings.h" - -namespace Assimp { - -// TinyFormatter.h -namespace Formatter { - template <typename T,typename TR, typename A> class basic_formatter; - typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format; -} - -// ------------------------------------------------------------------------------------------- -/** Load the Autodesk FBX file format. - - See http://en.wikipedia.org/wiki/FBX -*/ -// ------------------------------------------------------------------------------------------- -class FBXImporter : public BaseImporter, public LogFunctions<FBXImporter> -{ -public: - FBXImporter(); - virtual ~FBXImporter(); - - // -------------------- - bool CanRead( const std::string& pFile, - IOSystem* pIOHandler, - bool checkSig - ) const; - -protected: - - // -------------------- - const aiImporterDesc* GetInfo () const; - - // -------------------- - void SetupProperties(const Importer* pImp); - - // -------------------- - void InternReadFile( const std::string& pFile, - aiScene* pScene, - IOSystem* pIOHandler - ); - -private: - FBX::ImportSettings settings; -}; // !class FBXImporter - -} // end of namespace Assimp -#endif // !INCLUDED_AI_FBX_IMPORTER_H - diff --git a/thirdparty/assimp/code/FBX/FBXMaterial.cpp b/thirdparty/assimp/code/FBX/FBXMaterial.cpp deleted file mode 100644 index f43a8b84b0..0000000000 --- a/thirdparty/assimp/code/FBX/FBXMaterial.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXMaterial.cpp - * @brief Assimp::FBX::Material and Assimp::FBX::Texture implementation - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXImporter.h" -#include "FBXImportSettings.h" -#include "FBXDocumentUtil.h" -#include "FBXProperties.h" -#include <assimp/ByteSwapper.h> - -#include <algorithm> // std::transform -#include "FBXUtil.h" - -namespace Assimp { -namespace FBX { - - using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Material::Material(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Object(id,element,name) -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const ShadingModel = sc["ShadingModel"]; - const Element* const MultiLayer = sc["MultiLayer"]; - - if(MultiLayer) { - multilayer = !!ParseTokenAsInt(GetRequiredToken(*MultiLayer,0)); - } - - if(ShadingModel) { - shading = ParseTokenAsString(GetRequiredToken(*ShadingModel,0)); - } - else { - DOMWarning("shading mode not specified, assuming phong",&element); - shading = "phong"; - } - - std::string templateName; - - // lower-case shading because Blender (for example) writes "Phong" - std::transform(shading.begin(), shading.end(), shading.begin(), ::tolower); - if(shading == "phong") { - templateName = "Material.FbxSurfacePhong"; - } - else if(shading == "lambert") { - templateName = "Material.FbxSurfaceLambert"; - } - else { - DOMWarning("shading mode not recognized: " + shading,&element); - } - - props = GetPropertyTable(doc,templateName,element,sc); - - // resolve texture links - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID()); - for(const Connection* con : conns) { - - // texture link to properties, not objects - if (!con->PropertyName().length()) { - continue; - } - - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for texture link, ignoring",&element); - continue; - } - - const Texture* const tex = dynamic_cast<const Texture*>(ob); - if(!tex) { - const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob); - if(!layeredTexture) { - DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element); - continue; - } - const std::string& prop = con->PropertyName(); - if (layeredTextures.find(prop) != layeredTextures.end()) { - DOMWarning("duplicate layered texture link: " + prop,&element); - } - - layeredTextures[prop] = layeredTexture; - ((LayeredTexture*)layeredTexture)->fillTexture(doc); - } - else - { - const std::string& prop = con->PropertyName(); - if (textures.find(prop) != textures.end()) { - DOMWarning("duplicate texture link: " + prop,&element); - } - - textures[prop] = tex; - } - - } -} - - -// ------------------------------------------------------------------------------------------------ -Material::~Material() -{ -} - - -// ------------------------------------------------------------------------------------------------ -Texture::Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Object(id,element,name) -, uvScaling(1.0f,1.0f) -, media(0) -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const Type = sc["Type"]; - const Element* const FileName = sc["FileName"]; - const Element* const RelativeFilename = sc["RelativeFilename"]; - const Element* const ModelUVTranslation = sc["ModelUVTranslation"]; - const Element* const ModelUVScaling = sc["ModelUVScaling"]; - const Element* const Texture_Alpha_Source = sc["Texture_Alpha_Source"]; - const Element* const Cropping = sc["Cropping"]; - - if(Type) { - type = ParseTokenAsString(GetRequiredToken(*Type,0)); - } - - if(FileName) { - fileName = ParseTokenAsString(GetRequiredToken(*FileName,0)); - } - - if(RelativeFilename) { - relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0)); - } - - if(ModelUVTranslation) { - uvTrans = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,0)), - ParseTokenAsFloat(GetRequiredToken(*ModelUVTranslation,1)) - ); - } - - if(ModelUVScaling) { - uvScaling = aiVector2D(ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,0)), - ParseTokenAsFloat(GetRequiredToken(*ModelUVScaling,1)) - ); - } - - if(Cropping) { - crop[0] = ParseTokenAsInt(GetRequiredToken(*Cropping,0)); - crop[1] = ParseTokenAsInt(GetRequiredToken(*Cropping,1)); - crop[2] = ParseTokenAsInt(GetRequiredToken(*Cropping,2)); - crop[3] = ParseTokenAsInt(GetRequiredToken(*Cropping,3)); - } - else { - // vc8 doesn't support the crop() syntax in initialization lists - // (and vc9 WARNS about the new (i.e. compliant) behaviour). - crop[0] = crop[1] = crop[2] = crop[3] = 0; - } - - if(Texture_Alpha_Source) { - alphaSource = ParseTokenAsString(GetRequiredToken(*Texture_Alpha_Source,0)); - } - - props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc); - - // 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available. - bool ok; - const aiVector3D& scaling = PropertyGet<aiVector3D>(*props, "Scaling", ok); - if (ok) { - uvScaling.x = scaling.x; - uvScaling.y = scaling.y; - } - - const aiVector3D& trans = PropertyGet<aiVector3D>(*props, "Translation", ok); - if (ok) { - uvTrans.x = trans.x; - uvTrans.y = trans.y; - } - - // resolve video links - if(doc.Settings().readTextures) { - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID()); - for(const Connection* con : conns) { - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for texture link, ignoring",&element); - continue; - } - - const Video* const video = dynamic_cast<const Video*>(ob); - if(video) { - media = video; - } - } - } -} - - -Texture::~Texture() -{ - -} - -LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& /*doc*/, const std::string& name) -: Object(id,element,name) -,blendMode(BlendMode_Modulate) -,alpha(1) -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const BlendModes = sc["BlendModes"]; - const Element* const Alphas = sc["Alphas"]; - - - if(BlendModes!=0) - { - blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0)); - } - if(Alphas!=0) - { - alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0)); - } -} - -LayeredTexture::~LayeredTexture() -{ - -} - -void LayeredTexture::fillTexture(const Document& doc) -{ - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID()); - for(size_t i = 0; i < conns.size();++i) - { - const Connection* con = conns.at(i); - - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for texture link, ignoring",&element); - continue; - } - - const Texture* const tex = dynamic_cast<const Texture*>(ob); - - textures.push_back(tex); - } -} - - -// ------------------------------------------------------------------------------------------------ -Video::Video(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Object(id,element,name) -, contentLength(0) -, content(0) -{ - const Scope& sc = GetRequiredScope(element); - - const Element* const Type = sc["Type"]; - const Element* const FileName = sc.FindElementCaseInsensitive("FileName"); //some files retain the information as "Filename", others "FileName", who knows - const Element* const RelativeFilename = sc["RelativeFilename"]; - const Element* const Content = sc["Content"]; - - if(Type) { - type = ParseTokenAsString(GetRequiredToken(*Type,0)); - } - - if(FileName) { - fileName = ParseTokenAsString(GetRequiredToken(*FileName,0)); - } - - if(RelativeFilename) { - relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0)); - } - - if(Content && !Content->Tokens().empty()) { - //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found - try { - const Token& token = GetRequiredToken(*Content, 0); - const char* data = token.begin(); - if (!token.IsBinary()) { - if (*data != '"') { - DOMError("embedded content is not surrounded by quotation marks", &element); - } - else { - size_t targetLength = 0; - auto numTokens = Content->Tokens().size(); - // First time compute size (it could be large like 64Gb and it is good to allocate it once) - for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) - { - const Token& dataToken = GetRequiredToken(*Content, tokenIdx); - size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes - const char* base64data = dataToken.begin() + 1; - const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength); - if (outLength == 0) - { - DOMError("Corrupted embedded content found", &element); - } - targetLength += outLength; - } - if (targetLength == 0) - { - DOMError("Corrupted embedded content found", &element); - } - content = new uint8_t[targetLength]; - contentLength = static_cast<uint64_t>(targetLength); - size_t dst_offset = 0; - for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) - { - const Token& dataToken = GetRequiredToken(*Content, tokenIdx); - size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes - const char* base64data = dataToken.begin() + 1; - dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset); - } - if (targetLength != dst_offset) - { - delete[] content; - contentLength = 0; - DOMError("Corrupted embedded content found", &element); - } - } - } - else if (static_cast<size_t>(token.end() - data) < 5) { - DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element); - } - else if (*data != 'R') { - DOMWarning("video content is not raw binary data, ignoring", &element); - } - else { - // read number of elements - uint32_t len = 0; - ::memcpy(&len, data + 1, sizeof(len)); - AI_SWAP4(len); - - contentLength = len; - - content = new uint8_t[len]; - ::memcpy(content, data + 5, len); - } - } catch (const runtime_error& runtimeError) - { - //we don't need the content data for contents that has already been loaded - ASSIMP_LOG_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ", - runtimeError.what()); - } - } - - props = GetPropertyTable(doc,"Video.FbxVideo",element,sc); -} - - -Video::~Video() -{ - if(content) { - delete[] content; - } -} - -} //!FBX -} //!Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp b/thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp deleted file mode 100644 index 1386e2383c..0000000000 --- a/thirdparty/assimp/code/FBX/FBXMeshGeometry.cpp +++ /dev/null @@ -1,709 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXMeshGeometry.cpp - * @brief Assimp::FBX::MeshGeometry implementation - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include <functional> - -#include "FBXMeshGeometry.h" -#include "FBXDocument.h" -#include "FBXImporter.h" -#include "FBXImportSettings.h" -#include "FBXDocumentUtil.h" - - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) - : Object(id, element, name) - , skin() -{ - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer"); - for(const Connection* con : conns) { - const Skin* const sk = ProcessSimpleConnection<Skin>(*con, false, "Skin -> Geometry", element); - if(sk) { - skin = sk; - } - const BlendShape* const bsp = ProcessSimpleConnection<BlendShape>(*con, false, "BlendShape -> Geometry", element); - if (bsp) { - blendShapes.push_back(bsp); - } - } -} - -// ------------------------------------------------------------------------------------------------ -Geometry::~Geometry() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<const BlendShape*>& Geometry::GetBlendShapes() const { - return blendShapes; -} - -// ------------------------------------------------------------------------------------------------ -const Skin* Geometry::DeformerSkin() const { - return skin; -} - -// ------------------------------------------------------------------------------------------------ -MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) -: Geometry(id, element,name, doc) -{ - const Scope* sc = element.Compound(); - if (!sc) { - DOMError("failed to read Geometry object (class: Mesh), no data scope found"); - } - - // must have Mesh elements: - const Element& Vertices = GetRequiredElement(*sc,"Vertices",&element); - const Element& PolygonVertexIndex = GetRequiredElement(*sc,"PolygonVertexIndex",&element); - - // optional Mesh elements: - const ElementCollection& Layer = sc->GetCollection("Layer"); - - std::vector<aiVector3D> tempVerts; - ParseVectorDataArray(tempVerts,Vertices); - - if(tempVerts.empty()) { - FBXImporter::LogWarn("encountered mesh with no vertices"); - } - - std::vector<int> tempFaces; - ParseVectorDataArray(tempFaces,PolygonVertexIndex); - - if(tempFaces.empty()) { - FBXImporter::LogWarn("encountered mesh with no faces"); - } - - m_vertices.reserve(tempFaces.size()); - m_faces.reserve(tempFaces.size() / 3); - - m_mapping_offsets.resize(tempVerts.size()); - m_mapping_counts.resize(tempVerts.size(),0); - m_mappings.resize(tempFaces.size()); - - const size_t vertex_count = tempVerts.size(); - - // generate output vertices, computing an adjacency table to - // preserve the mapping from fbx indices to *this* indexing. - unsigned int count = 0; - for(int index : tempFaces) { - const int absi = index < 0 ? (-index - 1) : index; - if(static_cast<size_t>(absi) >= vertex_count) { - DOMError("polygon vertex index out of range",&PolygonVertexIndex); - } - - m_vertices.push_back(tempVerts[absi]); - ++count; - - ++m_mapping_counts[absi]; - - if (index < 0) { - m_faces.push_back(count); - count = 0; - } - } - - unsigned int cursor = 0; - for (size_t i = 0, e = tempVerts.size(); i < e; ++i) { - m_mapping_offsets[i] = cursor; - cursor += m_mapping_counts[i]; - - m_mapping_counts[i] = 0; - } - - cursor = 0; - for(int index : tempFaces) { - const int absi = index < 0 ? (-index - 1) : index; - m_mappings[m_mapping_offsets[absi] + m_mapping_counts[absi]++] = cursor++; - } - - // if settings.readAllLayers is true: - // * read all layers, try to load as many vertex channels as possible - // if settings.readAllLayers is false: - // * read only the layer with index 0, but warn about any further layers - for (ElementMap::const_iterator it = Layer.first; it != Layer.second; ++it) { - const TokenList& tokens = (*it).second->Tokens(); - - const char* err; - const int index = ParseTokenAsInt(*tokens[0], err); - if(err) { - DOMError(err,&element); - } - - if(doc.Settings().readAllLayers || index == 0) { - const Scope& layer = GetRequiredScope(*(*it).second); - ReadLayer(layer); - } - else { - FBXImporter::LogWarn("ignoring additional geometry layers"); - } - } -} - -// ------------------------------------------------------------------------------------------------ -MeshGeometry::~MeshGeometry() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<aiVector3D>& MeshGeometry::GetVertices() const { - return m_vertices; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<aiVector3D>& MeshGeometry::GetNormals() const { - return m_normals; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<aiVector3D>& MeshGeometry::GetTangents() const { - return m_tangents; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<aiVector3D>& MeshGeometry::GetBinormals() const { - return m_binormals; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<unsigned int>& MeshGeometry::GetFaceIndexCounts() const { - return m_faces; -} - -// ------------------------------------------------------------------------------------------------ -const std::vector<aiVector2D>& MeshGeometry::GetTextureCoords( unsigned int index ) const { - static const std::vector<aiVector2D> empty; - return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? empty : m_uvs[ index ]; -} - -std::string MeshGeometry::GetTextureCoordChannelName( unsigned int index ) const { - return index >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? "" : m_uvNames[ index ]; -} - -const std::vector<aiColor4D>& MeshGeometry::GetVertexColors( unsigned int index ) const { - static const std::vector<aiColor4D> empty; - return index >= AI_MAX_NUMBER_OF_COLOR_SETS ? empty : m_colors[ index ]; -} - -const MatIndexArray& MeshGeometry::GetMaterialIndices() const { - return m_materials; -} -// ------------------------------------------------------------------------------------------------ -const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const { - if ( in_index >= m_mapping_counts.size() ) { - return NULL; - } - - ai_assert( m_mapping_counts.size() == m_mapping_offsets.size() ); - count = m_mapping_counts[ in_index ]; - - ai_assert( m_mapping_offsets[ in_index ] + count <= m_mappings.size() ); - - return &m_mappings[ m_mapping_offsets[ in_index ] ]; -} - -// ------------------------------------------------------------------------------------------------ -unsigned int MeshGeometry::FaceForVertexIndex( unsigned int in_index ) const { - ai_assert( in_index < m_vertices.size() ); - - // in the current conversion pattern this will only be needed if - // weights are present, so no need to always pre-compute this table - if ( m_facesVertexStartIndices.empty() ) { - m_facesVertexStartIndices.resize( m_faces.size() + 1, 0 ); - - std::partial_sum( m_faces.begin(), m_faces.end(), m_facesVertexStartIndices.begin() + 1 ); - m_facesVertexStartIndices.pop_back(); - } - - ai_assert( m_facesVertexStartIndices.size() == m_faces.size() ); - const std::vector<unsigned int>::iterator it = std::upper_bound( - m_facesVertexStartIndices.begin(), - m_facesVertexStartIndices.end(), - in_index - ); - - return static_cast< unsigned int >( std::distance( m_facesVertexStartIndices.begin(), it - 1 ) ); -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadLayer(const Scope& layer) -{ - const ElementCollection& LayerElement = layer.GetCollection("LayerElement"); - for (ElementMap::const_iterator eit = LayerElement.first; eit != LayerElement.second; ++eit) { - const Scope& elayer = GetRequiredScope(*(*eit).second); - - ReadLayerElement(elayer); - } -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadLayerElement(const Scope& layerElement) -{ - const Element& Type = GetRequiredElement(layerElement,"Type"); - const Element& TypedIndex = GetRequiredElement(layerElement,"TypedIndex"); - - const std::string& type = ParseTokenAsString(GetRequiredToken(Type,0)); - const int typedIndex = ParseTokenAsInt(GetRequiredToken(TypedIndex,0)); - - const Scope& top = GetRequiredScope(element); - const ElementCollection candidates = top.GetCollection(type); - - for (ElementMap::const_iterator it = candidates.first; it != candidates.second; ++it) { - const int index = ParseTokenAsInt(GetRequiredToken(*(*it).second,0)); - if(index == typedIndex) { - ReadVertexData(type,typedIndex,GetRequiredScope(*(*it).second)); - return; - } - } - - FBXImporter::LogError(Formatter::format("failed to resolve vertex layer element: ") - << type << ", index: " << typedIndex); -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scope& source) -{ - const std::string& MappingInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(source,"MappingInformationType"),0) - ); - - const std::string& ReferenceInformationType = ParseTokenAsString(GetRequiredToken( - GetRequiredElement(source,"ReferenceInformationType"),0) - ); - - if (type == "LayerElementUV") { - if(index >= AI_MAX_NUMBER_OF_TEXTURECOORDS) { - FBXImporter::LogError(Formatter::format("ignoring UV layer, maximum number of UV channels exceeded: ") - << index << " (limit is " << AI_MAX_NUMBER_OF_TEXTURECOORDS << ")" ); - return; - } - - const Element* Name = source["Name"]; - m_uvNames[index] = ""; - if(Name) { - m_uvNames[index] = ParseTokenAsString(GetRequiredToken(*Name,0)); - } - - ReadVertexDataUV(m_uvs[index],source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementMaterial") { - if (m_materials.size() > 0) { - FBXImporter::LogError("ignoring additional material layer"); - return; - } - - std::vector<int> temp_materials; - - ReadVertexDataMaterials(temp_materials,source, - MappingInformationType, - ReferenceInformationType - ); - - // sometimes, there will be only negative entries. Drop the material - // layer in such a case (I guess it means a default material should - // be used). This is what the converter would do anyway, and it - // avoids losing the material if there are more material layers - // coming of which at least one contains actual data (did observe - // that with one test file). - const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; }); - if(count_neg == temp_materials.size()) { - FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)"); - return; - } - - std::swap(temp_materials, m_materials); - } - else if (type == "LayerElementNormal") { - if (m_normals.size() > 0) { - FBXImporter::LogError("ignoring additional normal layer"); - return; - } - - ReadVertexDataNormals(m_normals,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementTangent") { - if (m_tangents.size() > 0) { - FBXImporter::LogError("ignoring additional tangent layer"); - return; - } - - ReadVertexDataTangents(m_tangents,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementBinormal") { - if (m_binormals.size() > 0) { - FBXImporter::LogError("ignoring additional binormal layer"); - return; - } - - ReadVertexDataBinormals(m_binormals,source, - MappingInformationType, - ReferenceInformationType - ); - } - else if (type == "LayerElementColor") { - if(index >= AI_MAX_NUMBER_OF_COLOR_SETS) { - FBXImporter::LogError(Formatter::format("ignoring vertex color layer, maximum number of color sets exceeded: ") - << index << " (limit is " << AI_MAX_NUMBER_OF_COLOR_SETS << ")" ); - return; - } - - ReadVertexDataColors(m_colors[index],source, - MappingInformationType, - ReferenceInformationType - ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Lengthy utility function to read and resolve a FBX vertex data array - that is, the -// output is in polygon vertex order. This logic is used for reading normals, UVs, colors, -// tangents .. -template <typename T> -void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType, - const char* dataElementName, - const char* indexDataElementName, - size_t vertex_count, - const std::vector<unsigned int>& mapping_counts, - const std::vector<unsigned int>& mapping_offsets, - const std::vector<unsigned int>& mappings) -{ - bool isDirect = ReferenceInformationType == "Direct"; - bool isIndexToDirect = ReferenceInformationType == "IndexToDirect"; - - // fall-back to direct data if there is no index data element - if ( isIndexToDirect && !HasElement( source, indexDataElementName ) ) { - isDirect = true; - isIndexToDirect = false; - } - - // handle permutations of Mapping and Reference type - it would be nice to - // deal with this more elegantly and with less redundancy, but right - // now it seems unavoidable. - if (MappingInformationType == "ByVertice" && isDirect) { - if (!HasElement(source, dataElementName)) { - return; - } - std::vector<T> tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - - data_out.resize(vertex_count); - for (size_t i = 0, e = tempData.size(); i < e; ++i) { - - const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; - for (unsigned int j = istart; j < iend; ++j) { - data_out[mappings[j]] = tempData[i]; - } - } - } - else if (MappingInformationType == "ByVertice" && isIndexToDirect) { - std::vector<T> tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - - data_out.resize(vertex_count); - - std::vector<int> uvIndices; - ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); - for (size_t i = 0, e = uvIndices.size(); i < e; ++i) { - - const unsigned int istart = mapping_offsets[i], iend = istart + mapping_counts[i]; - for (unsigned int j = istart; j < iend; ++j) { - if (static_cast<size_t>(uvIndices[i]) >= tempData.size()) { - DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); - } - data_out[mappings[j]] = tempData[uvIndices[i]]; - } - } - } - else if (MappingInformationType == "ByPolygonVertex" && isDirect) { - std::vector<T> tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - - if (tempData.size() != vertex_count) { - FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") - << tempData.size() << ", expected " << vertex_count - ); - return; - } - - data_out.swap(tempData); - } - else if (MappingInformationType == "ByPolygonVertex" && isIndexToDirect) { - std::vector<T> tempData; - ParseVectorDataArray(tempData, GetRequiredElement(source, dataElementName)); - - data_out.resize(vertex_count); - - std::vector<int> uvIndices; - ParseVectorDataArray(uvIndices,GetRequiredElement(source,indexDataElementName)); - - if (uvIndices.size() != vertex_count) { - FBXImporter::LogError("length of input data unexpected for ByPolygonVertex mapping"); - return; - } - - const T empty; - unsigned int next = 0; - for(int i : uvIndices) { - if ( -1 == i ) { - data_out[ next++ ] = empty; - continue; - } - if (static_cast<size_t>(i) >= tempData.size()) { - DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); - } - - data_out[next++] = tempData[i]; - } - } - else { - FBXImporter::LogError(Formatter::format("ignoring vertex data channel, access type not implemented: ") - << MappingInformationType << "," << ReferenceInformationType); - } -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - ResolveVertexDataArray(normals_out,source,MappingInformationType,ReferenceInformationType, - "Normals", - "NormalsIndex", - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - ResolveVertexDataArray(uv_out,source,MappingInformationType,ReferenceInformationType, - "UV", - "UVIndex", - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - ResolveVertexDataArray(colors_out,source,MappingInformationType,ReferenceInformationType, - "Colors", - "ColorIndex", - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - -// ------------------------------------------------------------------------------------------------ -static const char *TangentIndexToken = "TangentIndex"; -static const char *TangentsIndexToken = "TangentsIndex"; - -void MeshGeometry::ReadVertexDataTangents(std::vector<aiVector3D>& tangents_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent"; - const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken; - ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType, - str, - strIdx, - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - -// ------------------------------------------------------------------------------------------------ -static const std::string BinormalIndexToken = "BinormalIndex"; -static const std::string BinormalsIndexToken = "BinormalsIndex"; - -void MeshGeometry::ReadVertexDataBinormals(std::vector<aiVector3D>& binormals_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - const char * str = source.Elements().count( "Binormals" ) > 0 ? "Binormals" : "Binormal"; - const char * strIdx = source.Elements().count( "Binormals" ) > 0 ? BinormalsIndexToken.c_str() : BinormalIndexToken.c_str(); - ResolveVertexDataArray(binormals_out,source,MappingInformationType,ReferenceInformationType, - str, - strIdx, - m_vertices.size(), - m_mapping_counts, - m_mapping_offsets, - m_mappings); -} - - -// ------------------------------------------------------------------------------------------------ -void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType) -{ - const size_t face_count = m_faces.size(); - if( 0 == face_count ) - { - return; - } - - // materials are handled separately. First of all, they are assigned per-face - // and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect - // has a slightly different meaning for materials. - ParseVectorDataArray(materials_out,GetRequiredElement(source,"Materials")); - - if (MappingInformationType == "AllSame") { - // easy - same material for all faces - if (materials_out.empty()) { - FBXImporter::LogError(Formatter::format("expected material index, ignoring")); - return; - } else if (materials_out.size() > 1) { - FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one")); - materials_out.clear(); - } - - materials_out.resize(m_vertices.size()); - std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0)); - } else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") { - materials_out.resize(face_count); - - if(materials_out.size() != face_count) { - FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") - << materials_out.size() << ", expected " << face_count - ); - return; - } - } else { - FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ") - << MappingInformationType << "," << ReferenceInformationType); - } -} -// ------------------------------------------------------------------------------------------------ -ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) -: Geometry(id, element, name, doc) { - const Scope *sc = element.Compound(); - if (nullptr == sc) { - DOMError("failed to read Geometry object (class: Shape), no data scope found"); - } - const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element); - const Element& Normals = GetRequiredElement(*sc, "Normals", &element); - const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element); - ParseVectorDataArray(m_indices, Indexes); - ParseVectorDataArray(m_vertices, Vertices); - ParseVectorDataArray(m_normals, Normals); -} - -// ------------------------------------------------------------------------------------------------ -ShapeGeometry::~ShapeGeometry() { - // empty -} -// ------------------------------------------------------------------------------------------------ -const std::vector<aiVector3D>& ShapeGeometry::GetVertices() const { - return m_vertices; -} -// ------------------------------------------------------------------------------------------------ -const std::vector<aiVector3D>& ShapeGeometry::GetNormals() const { - return m_normals; -} -// ------------------------------------------------------------------------------------------------ -const std::vector<unsigned int>& ShapeGeometry::GetIndices() const { - return m_indices; -} -// ------------------------------------------------------------------------------------------------ -LineGeometry::LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) - : Geometry(id, element, name, doc) -{ - const Scope* sc = element.Compound(); - if (!sc) { - DOMError("failed to read Geometry object (class: Line), no data scope found"); - } - const Element& Points = GetRequiredElement(*sc, "Points", &element); - const Element& PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element); - ParseVectorDataArray(m_vertices, Points); - ParseVectorDataArray(m_indices, PointsIndex); -} - -// ------------------------------------------------------------------------------------------------ -LineGeometry::~LineGeometry() { - // empty -} -// ------------------------------------------------------------------------------------------------ -const std::vector<aiVector3D>& LineGeometry::GetVertices() const { - return m_vertices; -} -// ------------------------------------------------------------------------------------------------ -const std::vector<int>& LineGeometry::GetIndices() const { - return m_indices; -} -} // !FBX -} // !Assimp -#endif - diff --git a/thirdparty/assimp/code/FBX/FBXMeshGeometry.h b/thirdparty/assimp/code/FBX/FBXMeshGeometry.h deleted file mode 100644 index d6d4512177..0000000000 --- a/thirdparty/assimp/code/FBX/FBXMeshGeometry.h +++ /dev/null @@ -1,235 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXImporter.h -* @brief Declaration of the FBX main importer class -*/ -#ifndef INCLUDED_AI_FBX_MESHGEOMETRY_H -#define INCLUDED_AI_FBX_MESHGEOMETRY_H - -#include "FBXParser.h" -#include "FBXDocument.h" - -namespace Assimp { -namespace FBX { - -/** - * DOM base class for all kinds of FBX geometry - */ -class Geometry : public Object -{ -public: - Geometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); - virtual ~Geometry(); - - /** Get the Skin attached to this geometry or NULL */ - const Skin* DeformerSkin() const; - - /** Get the BlendShape attached to this geometry or NULL */ - const std::vector<const BlendShape*>& GetBlendShapes() const; - -private: - const Skin* skin; - std::vector<const BlendShape*> blendShapes; - -}; - -typedef std::vector<int> MatIndexArray; - - -/** - * DOM class for FBX geometry of type "Mesh" - */ -class MeshGeometry : public Geometry -{ -public: - /** The class constructor */ - MeshGeometry( uint64_t id, const Element& element, const std::string& name, const Document& doc ); - - /** The class destructor */ - virtual ~MeshGeometry(); - - /** Get a list of all vertex points, non-unique*/ - const std::vector<aiVector3D>& GetVertices() const; - - /** Get a list of all vertex normals or an empty array if - * no normals are specified. */ - const std::vector<aiVector3D>& GetNormals() const; - - /** Get a list of all vertex tangents or an empty array - * if no tangents are specified */ - const std::vector<aiVector3D>& GetTangents() const; - - /** Get a list of all vertex bi-normals or an empty array - * if no bi-normals are specified */ - const std::vector<aiVector3D>& GetBinormals() const; - - /** Return list of faces - each entry denotes a face and specifies - * how many vertices it has. Vertices are taken from the - * vertex data arrays in sequential order. */ - const std::vector<unsigned int>& GetFaceIndexCounts() const; - - /** Get a UV coordinate slot, returns an empty array if - * the requested slot does not exist. */ - const std::vector<aiVector2D>& GetTextureCoords( unsigned int index ) const; - - /** Get a UV coordinate slot, returns an empty array if - * the requested slot does not exist. */ - std::string GetTextureCoordChannelName( unsigned int index ) const; - - /** Get a vertex color coordinate slot, returns an empty array if - * the requested slot does not exist. */ - const std::vector<aiColor4D>& GetVertexColors( unsigned int index ) const; - - /** Get per-face-vertex material assignments */ - const MatIndexArray& GetMaterialIndices() const; - - /** Convert from a fbx file vertex index (for example from a #Cluster weight) or NULL - * if the vertex index is not valid. */ - const unsigned int* ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const; - - /** Determine the face to which a particular output vertex index belongs. - * This mapping is always unique. */ - unsigned int FaceForVertexIndex( unsigned int in_index ) const; -private: - void ReadLayer( const Scope& layer ); - void ReadLayerElement( const Scope& layerElement ); - void ReadVertexData( const std::string& type, int index, const Scope& source ); - - void ReadVertexDataUV( std::vector<aiVector2D>& uv_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataNormals( std::vector<aiVector3D>& normals_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataColors( std::vector<aiColor4D>& colors_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataTangents( std::vector<aiVector3D>& tangents_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataBinormals( std::vector<aiVector3D>& binormals_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - - void ReadVertexDataMaterials( MatIndexArray& materials_out, const Scope& source, - const std::string& MappingInformationType, - const std::string& ReferenceInformationType ); - -private: - // cached data arrays - MatIndexArray m_materials; - std::vector<aiVector3D> m_vertices; - std::vector<unsigned int> m_faces; - mutable std::vector<unsigned int> m_facesVertexStartIndices; - std::vector<aiVector3D> m_tangents; - std::vector<aiVector3D> m_binormals; - std::vector<aiVector3D> m_normals; - - std::string m_uvNames[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; - std::vector<aiVector2D> m_uvs[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; - std::vector<aiColor4D> m_colors[ AI_MAX_NUMBER_OF_COLOR_SETS ]; - - std::vector<unsigned int> m_mapping_counts; - std::vector<unsigned int> m_mapping_offsets; - std::vector<unsigned int> m_mappings; -}; - -/** -* DOM class for FBX geometry of type "Shape" -*/ -class ShapeGeometry : public Geometry -{ -public: - /** The class constructor */ - ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc); - - /** The class destructor */ - virtual ~ShapeGeometry(); - - /** Get a list of all vertex points, non-unique*/ - const std::vector<aiVector3D>& GetVertices() const; - - /** Get a list of all vertex normals or an empty array if - * no normals are specified. */ - const std::vector<aiVector3D>& GetNormals() const; - - /** Return list of vertex indices. */ - const std::vector<unsigned int>& GetIndices() const; - -private: - std::vector<aiVector3D> m_vertices; - std::vector<aiVector3D> m_normals; - std::vector<unsigned int> m_indices; -}; -/** -* DOM class for FBX geometry of type "Line" -*/ -class LineGeometry : public Geometry -{ -public: - /** The class constructor */ - LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc); - - /** The class destructor */ - virtual ~LineGeometry(); - - /** Get a list of all vertex points, non-unique*/ - const std::vector<aiVector3D>& GetVertices() const; - - /** Return list of vertex indices. */ - const std::vector<int>& GetIndices() const; - -private: - std::vector<aiVector3D> m_vertices; - std::vector<int> m_indices; -}; - -} -} - -#endif // INCLUDED_AI_FBX_MESHGEOMETRY_H - diff --git a/thirdparty/assimp/code/FBX/FBXModel.cpp b/thirdparty/assimp/code/FBX/FBXModel.cpp deleted file mode 100644 index 589af36ac7..0000000000 --- a/thirdparty/assimp/code/FBX/FBXModel.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXModel.cpp - * @brief Assimp::FBX::Model implementation - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXParser.h" -#include "FBXMeshGeometry.h" -#include "FBXDocument.h" -#include "FBXImporter.h" -#include "FBXDocumentUtil.h" - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Model::Model(uint64_t id, const Element& element, const Document& doc, const std::string& name) - : Object(id,element,name) - , shading("Y") -{ - const Scope& sc = GetRequiredScope(element); - const Element* const Shading = sc["Shading"]; - const Element* const Culling = sc["Culling"]; - - if(Shading) { - shading = GetRequiredToken(*Shading,0).StringContents(); - } - - if (Culling) { - culling = ParseTokenAsString(GetRequiredToken(*Culling,0)); - } - - props = GetPropertyTable(doc,"Model.FbxNode",element,sc); - ResolveLinks(element,doc); -} - -// ------------------------------------------------------------------------------------------------ -Model::~Model() -{ - -} - -// ------------------------------------------------------------------------------------------------ -void Model::ResolveLinks(const Element& element, const Document& doc) -{ - const char* const arr[] = {"Geometry","Material","NodeAttribute"}; - - // resolve material - const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID(),arr, 3); - - materials.reserve(conns.size()); - geometry.reserve(conns.size()); - attributes.reserve(conns.size()); - for(const Connection* con : conns) { - - // material and geometry links should be Object-Object connections - if (con->PropertyName().length()) { - continue; - } - - const Object* const ob = con->SourceObject(); - if(!ob) { - DOMWarning("failed to read source object for incoming Model link, ignoring",&element); - continue; - } - - const Material* const mat = dynamic_cast<const Material*>(ob); - if(mat) { - materials.push_back(mat); - continue; - } - - const Geometry* const geo = dynamic_cast<const Geometry*>(ob); - if(geo) { - geometry.push_back(geo); - continue; - } - - const NodeAttribute* const att = dynamic_cast<const NodeAttribute*>(ob); - if(att) { - attributes.push_back(att); - continue; - } - - DOMWarning("source object for model link is neither Material, NodeAttribute nor Geometry, ignoring",&element); - continue; - } -} - -// ------------------------------------------------------------------------------------------------ -bool Model::IsNull() const -{ - const std::vector<const NodeAttribute*>& attrs = GetAttributes(); - for(const NodeAttribute* att : attrs) { - - const Null* null_tag = dynamic_cast<const Null*>(att); - if(null_tag) { - return true; - } - } - - return false; -} - - -} //!FBX -} //!Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXNodeAttribute.cpp b/thirdparty/assimp/code/FBX/FBXNodeAttribute.cpp deleted file mode 100644 index b72e5637ee..0000000000 --- a/thirdparty/assimp/code/FBX/FBXNodeAttribute.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXNoteAttribute.cpp - * @brief Assimp::FBX::NodeAttribute (and subclasses) implementation - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXImporter.h" -#include "FBXDocumentUtil.h" - -namespace Assimp { -namespace FBX { - -using namespace Util; - -// ------------------------------------------------------------------------------------------------ -NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: Object(id,element,name) -, props() -{ - const Scope& sc = GetRequiredScope(element); - - const std::string& classname = ParseTokenAsString(GetRequiredToken(element,2)); - - // hack on the deriving type but Null/LimbNode attributes are the only case in which - // the property table is by design absent and no warning should be generated - // for it. - const bool is_null_or_limb = !strcmp(classname.c_str(), "Null") || !strcmp(classname.c_str(), "LimbNode"); - props = GetPropertyTable(doc,"NodeAttribute.Fbx" + classname,element,sc, is_null_or_limb); -} - - -// ------------------------------------------------------------------------------------------------ -NodeAttribute::~NodeAttribute() -{ - // empty -} - - -// ------------------------------------------------------------------------------------------------ -CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name) - : NodeAttribute(id,element,doc,name) -{ - const Scope& sc = GetRequiredScope(element); - const Element* const CameraId = sc["CameraId"]; - const Element* const CameraName = sc["CameraName"]; - const Element* const CameraIndexName = sc["CameraIndexName"]; - - if(CameraId) { - cameraId = ParseTokenAsInt(GetRequiredToken(*CameraId,0)); - } - - if(CameraName) { - cameraName = GetRequiredToken(*CameraName,0).StringContents(); - } - - if(CameraIndexName && CameraIndexName->Tokens().size()) { - cameraIndexName = GetRequiredToken(*CameraIndexName,0).StringContents(); - } -} - -// ------------------------------------------------------------------------------------------------ -CameraSwitcher::~CameraSwitcher() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: NodeAttribute(id,element,doc,name) -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -Camera::~Camera() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: NodeAttribute(id,element,doc,name) -{ - // empty -} - - -// ------------------------------------------------------------------------------------------------ -Light::~Light() -{ -} - - -// ------------------------------------------------------------------------------------------------ -Null::Null(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: NodeAttribute(id,element,doc,name) -{ - -} - - -// ------------------------------------------------------------------------------------------------ -Null::~Null() -{ - -} - - -// ------------------------------------------------------------------------------------------------ -LimbNode::LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name) -: NodeAttribute(id,element,doc,name) -{ - -} - - -// ------------------------------------------------------------------------------------------------ -LimbNode::~LimbNode() -{ - -} - -} -} - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXParser.cpp b/thirdparty/assimp/code/FBX/FBXParser.cpp deleted file mode 100644 index 4a9346040d..0000000000 --- a/thirdparty/assimp/code/FBX/FBXParser.cpp +++ /dev/null @@ -1,1309 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXParser.cpp - * @brief Implementation of the FBX parser and the rudimentary DOM that we use - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include <zlib.h> -#else -# include "../contrib/zlib/zlib.h" -#endif - -#include "FBXTokenizer.h" -#include "FBXParser.h" -#include "FBXUtil.h" - -#include <assimp/ParsingUtils.h> -#include <assimp/fast_atof.h> -#include <assimp/ByteSwapper.h> - -#include <iostream> - -using namespace Assimp; -using namespace Assimp::FBX; - -namespace { - - // ------------------------------------------------------------------------------------------------ - // signal parse error, this is always unrecoverable. Throws DeadlyImportError. - AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX; - AI_WONT_RETURN void ParseError(const std::string& message, const Token& token) - { - throw DeadlyImportError(Util::AddTokenText("FBX-Parser",message,&token)); - } - - // ------------------------------------------------------------------------------------------------ - AI_WONT_RETURN void ParseError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX; - AI_WONT_RETURN void ParseError(const std::string& message, const Element* element) - { - if(element) { - ParseError(message,element->KeyToken()); - } - throw DeadlyImportError("FBX-Parser " + message); - } - - - // ------------------------------------------------------------------------------------------------ - void ParseError(const std::string& message, TokenPtr token) - { - if(token) { - ParseError(message, *token); - } - ParseError(message); - } - - // Initially, we did reinterpret_cast, breaking strict aliasing rules. - // This actually caused trouble on Android, so let's be safe this time. - // https://github.com/assimp/assimp/issues/24 - template <typename T> - T SafeParse(const char* data, const char* end) { - // Actual size validation happens during Tokenization so - // this is valid as an assertion. - (void)(end); - ai_assert(static_cast<size_t>(end - data) >= sizeof(T)); - T result = static_cast<T>(0); - ::memcpy(&result, data, sizeof(T)); - return result; - } -} - -namespace Assimp { -namespace FBX { - -// ------------------------------------------------------------------------------------------------ -Element::Element(const Token& key_token, Parser& parser) -: key_token(key_token) -{ - TokenPtr n = nullptr; - do { - n = parser.AdvanceToNextToken(); - if(!n) { - ParseError("unexpected end of file, expected closing bracket",parser.LastToken()); - } - - if (n->Type() == TokenType_DATA) { - tokens.push_back(n); - TokenPtr prev = n; - n = parser.AdvanceToNextToken(); - if(!n) { - ParseError("unexpected end of file, expected bracket, comma or key",parser.LastToken()); - } - - const TokenType ty = n->Type(); - - // some exporters are missing a comma on the next line - if (ty == TokenType_DATA && prev->Type() == TokenType_DATA && (n->Line() == prev->Line() + 1)) { - tokens.push_back(n); - continue; - } - - if (ty != TokenType_OPEN_BRACKET && ty != TokenType_CLOSE_BRACKET && ty != TokenType_COMMA && ty != TokenType_KEY) { - ParseError("unexpected token; expected bracket, comma or key",n); - } - } - - if (n->Type() == TokenType_OPEN_BRACKET) { - compound.reset(new Scope(parser)); - - // current token should be a TOK_CLOSE_BRACKET - n = parser.CurrentToken(); - ai_assert(n); - - if (n->Type() != TokenType_CLOSE_BRACKET) { - ParseError("expected closing bracket",n); - } - - parser.AdvanceToNextToken(); - return; - } - } - while(n->Type() != TokenType_KEY && n->Type() != TokenType_CLOSE_BRACKET); -} - -// ------------------------------------------------------------------------------------------------ -Element::~Element() -{ - // no need to delete tokens, they are owned by the parser -} - -// ------------------------------------------------------------------------------------------------ -Scope::Scope(Parser& parser,bool topLevel) -{ - if(!topLevel) { - TokenPtr t = parser.CurrentToken(); - if (t->Type() != TokenType_OPEN_BRACKET) { - ParseError("expected open bracket",t); - } - } - - TokenPtr n = parser.AdvanceToNextToken(); - if(n == NULL) { - ParseError("unexpected end of file"); - } - - // note: empty scopes are allowed - while(n->Type() != TokenType_CLOSE_BRACKET) { - if (n->Type() != TokenType_KEY) { - ParseError("unexpected token, expected TOK_KEY",n); - } - - const std::string& str = n->StringContents(); - elements.insert(ElementMap::value_type(str,new_Element(*n,parser))); - - // Element() should stop at the next Key token (or right after a Close token) - n = parser.CurrentToken(); - if(n == NULL) { - if (topLevel) { - return; - } - ParseError("unexpected end of file",parser.LastToken()); - } - } -} - -// ------------------------------------------------------------------------------------------------ -Scope::~Scope() -{ - for(ElementMap::value_type& v : elements) { - delete v.second; - } -} - -// ------------------------------------------------------------------------------------------------ -Parser::Parser (const TokenList& tokens, bool is_binary) -: tokens(tokens) -, last() -, current() -, cursor(tokens.begin()) -, is_binary(is_binary) -{ - root.reset(new Scope(*this,true)); -} - -// ------------------------------------------------------------------------------------------------ -Parser::~Parser() -{ - // empty -} - -// ------------------------------------------------------------------------------------------------ -TokenPtr Parser::AdvanceToNextToken() -{ - last = current; - if (cursor == tokens.end()) { - current = NULL; - } else { - current = *cursor++; - } - return current; -} - -// ------------------------------------------------------------------------------------------------ -TokenPtr Parser::CurrentToken() const -{ - return current; -} - -// ------------------------------------------------------------------------------------------------ -TokenPtr Parser::LastToken() const -{ - return last; -} - -// ------------------------------------------------------------------------------------------------ -uint64_t ParseTokenAsID(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0L; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'L') { - err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; - return 0L; - } - - BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end()); - AI_SWAP8(id); - return id; - } - - // XXX: should use size_t here - unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); - ai_assert(length > 0); - - const char* out = nullptr; - const uint64_t id = strtoul10_64(t.begin(),&out,&length); - if (out > t.end()) { - err_out = "failed to parse ID (text)"; - return 0L; - } - - return id; -} - -// ------------------------------------------------------------------------------------------------ -size_t ParseTokenAsDim(const Token& t, const char*& err_out) -{ - // same as ID parsing, except there is a trailing asterisk - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'L') { - err_out = "failed to parse ID, unexpected data type, expected L(ong) (binary)"; - return 0; - } - - BE_NCONST uint64_t id = SafeParse<uint64_t>(data+1, t.end()); - AI_SWAP8(id); - return static_cast<size_t>(id); - } - - if(*t.begin() != '*') { - err_out = "expected asterisk before array dimension"; - return 0; - } - - // XXX: should use size_t here - unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); - if(length == 0) { - err_out = "expected valid integer number after asterisk"; - return 0; - } - - const char* out = nullptr; - const size_t id = static_cast<size_t>(strtoul10_64(t.begin() + 1,&out,&length)); - if (out > t.end()) { - err_out = "failed to parse ID"; - return 0; - } - - return id; -} - - -// ------------------------------------------------------------------------------------------------ -float ParseTokenAsFloat(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0.0f; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'F' && data[0] != 'D') { - err_out = "failed to parse F(loat) or D(ouble), unexpected data type (binary)"; - return 0.0f; - } - - if (data[0] == 'F') { - return SafeParse<float>(data+1, t.end()); - } - else { - return static_cast<float>( SafeParse<double>(data+1, t.end()) ); - } - } - - // need to copy the input string to a temporary buffer - // first - next in the fbx token stream comes ',', - // which fast_atof could interpret as decimal point. -#define MAX_FLOAT_LENGTH 31 - char temp[MAX_FLOAT_LENGTH + 1]; - const size_t length = static_cast<size_t>(t.end()-t.begin()); - std::copy(t.begin(),t.end(),temp); - temp[std::min(static_cast<size_t>(MAX_FLOAT_LENGTH),length)] = '\0'; - - return fast_atof(temp); -} - - -// ------------------------------------------------------------------------------------------------ -int ParseTokenAsInt(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'I') { - err_out = "failed to parse I(nt), unexpected data type (binary)"; - return 0; - } - - BE_NCONST int32_t ival = SafeParse<int32_t>(data+1, t.end()); - AI_SWAP4(ival); - return static_cast<int>(ival); - } - - ai_assert(static_cast<size_t>(t.end() - t.begin()) > 0); - - const char* out; - const int intval = strtol10(t.begin(),&out); - if (out != t.end()) { - err_out = "failed to parse ID"; - return 0; - } - - return intval; -} - - -// ------------------------------------------------------------------------------------------------ -int64_t ParseTokenAsInt64(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return 0L; - } - - if (t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'L') { - err_out = "failed to parse Int64, unexpected data type"; - return 0L; - } - - BE_NCONST int64_t id = SafeParse<int64_t>(data + 1, t.end()); - AI_SWAP8(id); - return id; - } - - // XXX: should use size_t here - unsigned int length = static_cast<unsigned int>(t.end() - t.begin()); - ai_assert(length > 0); - - const char* out = nullptr; - const int64_t id = strtol10_64(t.begin(), &out, &length); - if (out > t.end()) { - err_out = "failed to parse Int64 (text)"; - return 0L; - } - - return id; -} - -// ------------------------------------------------------------------------------------------------ -std::string ParseTokenAsString(const Token& t, const char*& err_out) -{ - err_out = NULL; - - if (t.Type() != TokenType_DATA) { - err_out = "expected TOK_DATA token"; - return ""; - } - - if(t.IsBinary()) - { - const char* data = t.begin(); - if (data[0] != 'S') { - err_out = "failed to parse S(tring), unexpected data type (binary)"; - return ""; - } - - // read string length - BE_NCONST int32_t len = SafeParse<int32_t>(data+1, t.end()); - AI_SWAP4(len); - - ai_assert(t.end() - data == 5 + len); - return std::string(data + 5, len); - } - - const size_t length = static_cast<size_t>(t.end() - t.begin()); - if(length < 2) { - err_out = "token is too short to hold a string"; - return ""; - } - - const char* s = t.begin(), *e = t.end() - 1; - if (*s != '\"' || *e != '\"') { - err_out = "expected double quoted string"; - return ""; - } - - return std::string(s+1,length-2); -} - - -namespace { - -// ------------------------------------------------------------------------------------------------ -// read the type code and element count of a binary data array and stop there -void ReadBinaryDataArrayHead(const char*& data, const char* end, char& type, uint32_t& count, - const Element& el) -{ - if (static_cast<size_t>(end-data) < 5) { - ParseError("binary data array is too short, need five (5) bytes for type signature and element count",&el); - } - - // data type - type = *data; - - // read number of elements - BE_NCONST uint32_t len = SafeParse<uint32_t>(data+1, end); - AI_SWAP4(len); - - count = len; - data += 5; -} - - -// ------------------------------------------------------------------------------------------------ -// read binary data array, assume cursor points to the 'compression mode' field (i.e. behind the header) -void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const char* end, - std::vector<char>& buff, - const Element& /*el*/) -{ - BE_NCONST uint32_t encmode = SafeParse<uint32_t>(data, end); - AI_SWAP4(encmode); - data += 4; - - // next comes the compressed length - BE_NCONST uint32_t comp_len = SafeParse<uint32_t>(data, end); - AI_SWAP4(comp_len); - data += 4; - - ai_assert(data + comp_len == end); - - // determine the length of the uncompressed data by looking at the type signature - uint32_t stride = 0; - switch(type) - { - case 'f': - case 'i': - stride = 4; - break; - - case 'd': - case 'l': - stride = 8; - break; - - default: - ai_assert(false); - }; - - const uint32_t full_length = stride * count; - buff.resize(full_length); - - if(encmode == 0) { - ai_assert(full_length == comp_len); - - // plain data, no compression - std::copy(data, end, buff.begin()); - } - else if(encmode == 1) { - // zlib/deflate, next comes ZIP head (0x78 0x01) - // see http://www.ietf.org/rfc/rfc1950.txt - - z_stream zstream; - zstream.opaque = Z_NULL; - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.data_type = Z_BINARY; - - // http://hewgill.com/journal/entries/349-how-to-decompress-gzip-stream-with-zlib - if(Z_OK != inflateInit(&zstream)) { - ParseError("failure initializing zlib"); - } - - zstream.next_in = reinterpret_cast<Bytef*>( const_cast<char*>(data) ); - zstream.avail_in = comp_len; - - zstream.avail_out = static_cast<uInt>(buff.size()); - zstream.next_out = reinterpret_cast<Bytef*>(&*buff.begin()); - const int ret = inflate(&zstream, Z_FINISH); - - if (ret != Z_STREAM_END && ret != Z_OK) { - ParseError("failure decompressing compressed data section"); - } - - // terminate zlib - inflateEnd(&zstream); - } -#ifdef ASSIMP_BUILD_DEBUG - else { - // runtime check for this happens at tokenization stage - ai_assert(false); - } -#endif - - data += comp_len; - ai_assert(data == end); -} - -} // !anon - - -// ------------------------------------------------------------------------------------------------ -// read an array of float3 tuples -void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el) -{ - out.resize( 0 ); - - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(count % 3 != 0) { - ParseError("number of floats is not a multiple of three (3) (binary)",&el); - } - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count3 = count / 3; - out.reserve(count3); - - if (type == 'd') { - const double* d = reinterpret_cast<const double*>(&buff[0]); - for (unsigned int i = 0; i < count3; ++i, d += 3) { - out.push_back(aiVector3D(static_cast<ai_real>(d[0]), - static_cast<ai_real>(d[1]), - static_cast<ai_real>(d[2]))); - } - // for debugging - /*for ( size_t i = 0; i < out.size(); i++ ) { - aiVector3D vec3( out[ i ] ); - std::stringstream stream; - stream << " vec3.x = " << vec3.x << " vec3.y = " << vec3.y << " vec3.z = " << vec3.z << std::endl; - DefaultLogger::get()->info( stream.str() ); - }*/ - } - else if (type == 'f') { - const float* f = reinterpret_cast<const float*>(&buff[0]); - for (unsigned int i = 0; i < count3; ++i, f += 3) { - out.push_back(aiVector3D(f[0],f[1],f[2])); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // may throw bad_alloc if the input is rubbish, but this need - // not to be prevented - importing would fail but we wouldn't - // crash since assimp handles this case properly. - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - if (a.Tokens().size() % 3 != 0) { - ParseError("number of floats is not a multiple of three (3)",&el); - } - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - aiVector3D v; - v.x = ParseTokenAsFloat(**it++); - v.y = ParseTokenAsFloat(**it++); - v.z = ParseTokenAsFloat(**it++); - - out.push_back(v); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of color4 tuples -void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(count % 4 != 0) { - ParseError("number of floats is not a multiple of four (4) (binary)",&el); - } - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count4 = count / 4; - out.reserve(count4); - - if (type == 'd') { - const double* d = reinterpret_cast<const double*>(&buff[0]); - for (unsigned int i = 0; i < count4; ++i, d += 4) { - out.push_back(aiColor4D(static_cast<float>(d[0]), - static_cast<float>(d[1]), - static_cast<float>(d[2]), - static_cast<float>(d[3]))); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast<const float*>(&buff[0]); - for (unsigned int i = 0; i < count4; ++i, f += 4) { - out.push_back(aiColor4D(f[0],f[1],f[2],f[3])); - } - } - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() above - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - if (a.Tokens().size() % 4 != 0) { - ParseError("number of floats is not a multiple of four (4)",&el); - } - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - aiColor4D v; - v.r = ParseTokenAsFloat(**it++); - v.g = ParseTokenAsFloat(**it++); - v.b = ParseTokenAsFloat(**it++); - v.a = ParseTokenAsFloat(**it++); - - out.push_back(v); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of float2 tuples -void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(count % 2 != 0) { - ParseError("number of floats is not a multiple of two (2) (binary)",&el); - } - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - const uint32_t count2 = count / 2; - out.reserve(count2); - - if (type == 'd') { - const double* d = reinterpret_cast<const double*>(&buff[0]); - for (unsigned int i = 0; i < count2; ++i, d += 2) { - out.push_back(aiVector2D(static_cast<float>(d[0]), - static_cast<float>(d[1]))); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast<const float*>(&buff[0]); - for (unsigned int i = 0; i < count2; ++i, f += 2) { - out.push_back(aiVector2D(f[0],f[1])); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() above - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - if (a.Tokens().size() % 2 != 0) { - ParseError("number of floats is not a multiple of two (2)",&el); - } - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - aiVector2D v; - v.x = ParseTokenAsFloat(**it++); - v.y = ParseTokenAsFloat(**it++); - - out.push_back(v); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of ints -void ParseVectorDataArray(std::vector<int>& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(!count) { - return; - } - - if (type != 'i') { - ParseError("expected int array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * 4); - - out.reserve(count); - - const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST int32_t val = *ip; - AI_SWAP4(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const int ival = ParseTokenAsInt(**it++); - out.push_back(ival); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of floats -void ParseVectorDataArray(std::vector<float>& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(!count) { - return; - } - - if (type != 'd' && type != 'f') { - ParseError("expected float or double array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * (type == 'd' ? 8 : 4)); - - if (type == 'd') { - const double* d = reinterpret_cast<const double*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++d) { - out.push_back(static_cast<float>(*d)); - } - } - else if (type == 'f') { - const float* f = reinterpret_cast<const float*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++f) { - out.push_back(*f); - } - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const float ival = ParseTokenAsFloat(**it++); - out.push_back(ival); - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of uints -void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(!count) { - return; - } - - if (type != 'i') { - ParseError("expected (u)int array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * 4); - - out.reserve(count); - - const int32_t* ip = reinterpret_cast<const int32_t*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST int32_t val = *ip; - if(val < 0) { - ParseError("encountered negative integer index (binary)"); - } - - AI_SWAP4(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const int ival = ParseTokenAsInt(**it++); - if(ival < 0) { - ParseError("encountered negative integer index"); - } - out.push_back(static_cast<unsigned int>(ival)); - } -} - - -// ------------------------------------------------------------------------------------------------ -// read an array of uint64_ts -void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if(tok.empty()) { - ParseError("unexpected empty element",&el); - } - - if(tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if(!count) { - return; - } - - if (type != 'l') { - ParseError("expected long array (binary)",&el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * 8); - - out.reserve(count); - - const uint64_t* ip = reinterpret_cast<const uint64_t*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST uint64_t val = *ip; - AI_SWAP8(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope,"a",&el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end; ) { - const uint64_t ival = ParseTokenAsID(**it++); - - out.push_back(ival); - } -} - -// ------------------------------------------------------------------------------------------------ -// read an array of int64_ts -void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el) -{ - out.resize( 0 ); - const TokenList& tok = el.Tokens(); - if (tok.empty()) { - ParseError("unexpected empty element", &el); - } - - if (tok[0]->IsBinary()) { - const char* data = tok[0]->begin(), *end = tok[0]->end(); - - char type; - uint32_t count; - ReadBinaryDataArrayHead(data, end, type, count, el); - - if (!count) { - return; - } - - if (type != 'l') { - ParseError("expected long array (binary)", &el); - } - - std::vector<char> buff; - ReadBinaryDataArray(type, count, data, end, buff, el); - - ai_assert(data == end); - ai_assert(buff.size() == count * 8); - - out.reserve(count); - - const int64_t* ip = reinterpret_cast<const int64_t*>(&buff[0]); - for (unsigned int i = 0; i < count; ++i, ++ip) { - BE_NCONST int64_t val = *ip; - AI_SWAP8(val); - out.push_back(val); - } - - return; - } - - const size_t dim = ParseTokenAsDim(*tok[0]); - - // see notes in ParseVectorDataArray() - out.reserve(dim); - - const Scope& scope = GetRequiredScope(el); - const Element& a = GetRequiredElement(scope, "a", &el); - - for (TokenList::const_iterator it = a.Tokens().begin(), end = a.Tokens().end(); it != end;) { - const int64_t ival = ParseTokenAsInt64(**it++); - - out.push_back(ival); - } -} - -// ------------------------------------------------------------------------------------------------ -aiMatrix4x4 ReadMatrix(const Element& element) -{ - std::vector<float> values; - ParseVectorDataArray(values,element); - - if(values.size() != 16) { - ParseError("expected 16 matrix elements"); - } - - aiMatrix4x4 result; - - - result.a1 = values[0]; - result.a2 = values[1]; - result.a3 = values[2]; - result.a4 = values[3]; - - result.b1 = values[4]; - result.b2 = values[5]; - result.b3 = values[6]; - result.b4 = values[7]; - - result.c1 = values[8]; - result.c2 = values[9]; - result.c3 = values[10]; - result.c4 = values[11]; - - result.d1 = values[12]; - result.d2 = values[13]; - result.d3 = values[14]; - result.d4 = values[15]; - - result.Transpose(); - return result; -} - - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsString() with ParseError handling -std::string ParseTokenAsString(const Token& t) -{ - const char* err; - const std::string& i = ParseTokenAsString(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - -bool HasElement( const Scope& sc, const std::string& index ) { - const Element* el = sc[ index ]; - if ( nullptr == el ) { - return false; - } - - return true; -} - -// ------------------------------------------------------------------------------------------------ -// extract a required element from a scope, abort if the element cannot be found -const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element /*= NULL*/) -{ - const Element* el = sc[index]; - if(!el) { - ParseError("did not find required element \"" + index + "\"",element); - } - return *el; -} - - -// ------------------------------------------------------------------------------------------------ -// extract required compound scope -const Scope& GetRequiredScope(const Element& el) -{ - const Scope* const s = el.Compound(); - if(!s) { - ParseError("expected compound scope",&el); - } - - return *s; -} - - -// ------------------------------------------------------------------------------------------------ -// get token at a particular index -const Token& GetRequiredToken(const Element& el, unsigned int index) -{ - const TokenList& t = el.Tokens(); - if(index >= t.size()) { - ParseError(Formatter::format( "missing token at index " ) << index,&el); - } - - return *t[index]; -} - - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsID() with ParseError handling -uint64_t ParseTokenAsID(const Token& t) -{ - const char* err; - const uint64_t i = ParseTokenAsID(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsDim() with ParseError handling -size_t ParseTokenAsDim(const Token& t) -{ - const char* err; - const size_t i = ParseTokenAsDim(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsFloat() with ParseError handling -float ParseTokenAsFloat(const Token& t) -{ - const char* err; - const float i = ParseTokenAsFloat(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsInt() with ParseError handling -int ParseTokenAsInt(const Token& t) -{ - const char* err; - const int i = ParseTokenAsInt(t,err); - if(err) { - ParseError(err,t); - } - return i; -} - -// ------------------------------------------------------------------------------------------------ -// wrapper around ParseTokenAsInt64() with ParseError handling -int64_t ParseTokenAsInt64(const Token& t) -{ - const char* err; - const int64_t i = ParseTokenAsInt64(t, err); - if (err) { - ParseError(err, t); - } - return i; -} - -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXParser.h b/thirdparty/assimp/code/FBX/FBXParser.h deleted file mode 100644 index 7b0cf72039..0000000000 --- a/thirdparty/assimp/code/FBX/FBXParser.h +++ /dev/null @@ -1,235 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXParser.h - * @brief FBX parsing code - */ -#ifndef INCLUDED_AI_FBX_PARSER_H -#define INCLUDED_AI_FBX_PARSER_H - -#include <stdint.h> -#include <map> -#include <memory> -#include <assimp/LogAux.h> -#include <assimp/fast_atof.h> - -#include "FBXCompileConfig.h" -#include "FBXTokenizer.h" - -namespace Assimp { -namespace FBX { - -class Scope; -class Parser; -class Element; - -// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03 -typedef std::vector< Scope* > ScopeList; -typedef std::fbx_unordered_multimap< std::string, Element* > ElementMap; - -typedef std::pair<ElementMap::const_iterator,ElementMap::const_iterator> ElementCollection; - -# define new_Scope new Scope -# define new_Element new Element - - -/** FBX data entity that consists of a key:value tuple. - * - * Example: - * @verbatim - * AnimationCurve: 23, "AnimCurve::", "" { - * [..] - * } - * @endverbatim - * - * As can be seen in this sample, elements can contain nested #Scope - * as their trailing member. **/ -class Element -{ -public: - Element(const Token& key_token, Parser& parser); - ~Element(); - - const Scope* Compound() const { - return compound.get(); - } - - const Token& KeyToken() const { - return key_token; - } - - const TokenList& Tokens() const { - return tokens; - } - -private: - const Token& key_token; - TokenList tokens; - std::unique_ptr<Scope> compound; -}; - -/** FBX data entity that consists of a 'scope', a collection - * of not necessarily unique #Element instances. - * - * Example: - * @verbatim - * GlobalSettings: { - * Version: 1000 - * Properties70: - * [...] - * } - * @endverbatim */ -class Scope -{ -public: - Scope(Parser& parser, bool topLevel = false); - ~Scope(); - - const Element* operator[] (const std::string& index) const { - ElementMap::const_iterator it = elements.find(index); - return it == elements.end() ? NULL : (*it).second; - } - - const Element* FindElementCaseInsensitive(const std::string& elementName) const { - const char* elementNameCStr = elementName.c_str(); - for (auto element = elements.begin(); element != elements.end(); ++element) - { - if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, MAXLEN)) { - return element->second; - } - } - return NULL; - } - - ElementCollection GetCollection(const std::string& index) const { - return elements.equal_range(index); - } - - const ElementMap& Elements() const { - return elements; - } - -private: - ElementMap elements; -}; - -/** FBX parsing class, takes a list of input tokens and generates a hierarchy - * of nested #Scope instances, representing the fbx DOM.*/ -class Parser -{ -public: - /** Parse given a token list. Does not take ownership of the tokens - - * the objects must persist during the entire parser lifetime */ - Parser (const TokenList& tokens,bool is_binary); - ~Parser(); - - const Scope& GetRootScope() const { - return *root.get(); - } - - bool IsBinary() const { - return is_binary; - } - -private: - friend class Scope; - friend class Element; - - TokenPtr AdvanceToNextToken(); - TokenPtr LastToken() const; - TokenPtr CurrentToken() const; - -private: - const TokenList& tokens; - - TokenPtr last, current; - TokenList::const_iterator cursor; - std::unique_ptr<Scope> root; - - const bool is_binary; -}; - - -/* token parsing - this happens when building the DOM out of the parse-tree*/ -uint64_t ParseTokenAsID(const Token& t, const char*& err_out); -size_t ParseTokenAsDim(const Token& t, const char*& err_out); - -float ParseTokenAsFloat(const Token& t, const char*& err_out); -int ParseTokenAsInt(const Token& t, const char*& err_out); -int64_t ParseTokenAsInt64(const Token& t, const char*& err_out); -std::string ParseTokenAsString(const Token& t, const char*& err_out); - -/* wrapper around ParseTokenAsXXX() with DOMError handling */ -uint64_t ParseTokenAsID(const Token& t); -size_t ParseTokenAsDim(const Token& t); -float ParseTokenAsFloat(const Token& t); -int ParseTokenAsInt(const Token& t); -int64_t ParseTokenAsInt64(const Token& t); -std::string ParseTokenAsString(const Token& t); - -/* read data arrays */ -void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el); -void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el); -void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el); -void ParseVectorDataArray(std::vector<int>& out, const Element& el); -void ParseVectorDataArray(std::vector<float>& out, const Element& el); -void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el); -void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& e); -void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el); - -bool HasElement( const Scope& sc, const std::string& index ); - -// extract a required element from a scope, abort if the element cannot be found -const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL); - -// extract required compound scope -const Scope& GetRequiredScope(const Element& el); -// get token at a particular index -const Token& GetRequiredToken(const Element& el, unsigned int index); - -// read a 4x4 matrix from an array of 16 floats -aiMatrix4x4 ReadMatrix(const Element& element); - -} // ! FBX -} // ! Assimp - -#endif // ! INCLUDED_AI_FBX_PARSER_H diff --git a/thirdparty/assimp/code/FBX/FBXProperties.cpp b/thirdparty/assimp/code/FBX/FBXProperties.cpp deleted file mode 100644 index 8d7036b6a9..0000000000 --- a/thirdparty/assimp/code/FBX/FBXProperties.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXProperties.cpp - * @brief Implementation of the FBX dynamic properties system - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXTokenizer.h" -#include "FBXParser.h" -#include "FBXDocument.h" -#include "FBXDocumentUtil.h" -#include "FBXProperties.h" - -namespace Assimp { -namespace FBX { - - using namespace Util; - -// ------------------------------------------------------------------------------------------------ -Property::Property() -{ -} - -// ------------------------------------------------------------------------------------------------ -Property::~Property() -{ -} - -namespace { - -// ------------------------------------------------------------------------------------------------ -// read a typed property out of a FBX element. The return value is NULL if the property cannot be read. -Property* ReadTypedProperty(const Element& element) -{ - ai_assert(element.KeyToken().StringContents() == "P"); - - const TokenList& tok = element.Tokens(); - ai_assert(tok.size() >= 5); - - const std::string& s = ParseTokenAsString(*tok[1]); - const char* const cs = s.c_str(); - if (!strcmp(cs,"KString")) { - return new TypedProperty<std::string>(ParseTokenAsString(*tok[4])); - } - else if (!strcmp(cs,"bool") || !strcmp(cs,"Bool")) { - return new TypedProperty<bool>(ParseTokenAsInt(*tok[4]) != 0); - } - else if (!strcmp(cs, "int") || !strcmp(cs, "Int") || !strcmp(cs, "enum") || !strcmp(cs, "Enum")) { - return new TypedProperty<int>(ParseTokenAsInt(*tok[4])); - } - else if (!strcmp(cs, "ULongLong")) { - return new TypedProperty<uint64_t>(ParseTokenAsID(*tok[4])); - } - else if (!strcmp(cs, "KTime")) { - return new TypedProperty<int64_t>(ParseTokenAsInt64(*tok[4])); - } - else if (!strcmp(cs,"Vector3D") || - !strcmp(cs,"ColorRGB") || - !strcmp(cs,"Vector") || - !strcmp(cs,"Color") || - !strcmp(cs,"Lcl Translation") || - !strcmp(cs,"Lcl Rotation") || - !strcmp(cs,"Lcl Scaling") - ) { - return new TypedProperty<aiVector3D>(aiVector3D( - ParseTokenAsFloat(*tok[4]), - ParseTokenAsFloat(*tok[5]), - ParseTokenAsFloat(*tok[6])) - ); - } - else if (!strcmp(cs,"double") || !strcmp(cs,"Number") || !strcmp(cs,"Float") || !strcmp(cs,"FieldOfView") || !strcmp( cs, "UnitScaleFactor" ) ) { - return new TypedProperty<float>(ParseTokenAsFloat(*tok[4])); - } - return NULL; -} - - -// ------------------------------------------------------------------------------------------------ -// peek into an element and check if it contains a FBX property, if so return its name. -std::string PeekPropertyName(const Element& element) -{ - ai_assert(element.KeyToken().StringContents() == "P"); - const TokenList& tok = element.Tokens(); - if(tok.size() < 4) { - return ""; - } - - return ParseTokenAsString(*tok[0]); -} - -} //! anon - - -// ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable() -: templateProps() -, element() -{ -} - -// ------------------------------------------------------------------------------------------------ -PropertyTable::PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps) -: templateProps(templateProps) -, element(&element) -{ - const Scope& scope = GetRequiredScope(element); - for(const ElementMap::value_type& v : scope.Elements()) { - if(v.first != "P") { - DOMWarning("expected only P elements in property table",v.second); - continue; - } - - const std::string& name = PeekPropertyName(*v.second); - if(!name.length()) { - DOMWarning("could not read property name",v.second); - continue; - } - - LazyPropertyMap::const_iterator it = lazyProps.find(name); - if (it != lazyProps.end()) { - DOMWarning("duplicate property name, will hide previous value: " + name,v.second); - continue; - } - - lazyProps[name] = v.second; - } -} - - -// ------------------------------------------------------------------------------------------------ -PropertyTable::~PropertyTable() -{ - for(PropertyMap::value_type& v : props) { - delete v.second; - } -} - - -// ------------------------------------------------------------------------------------------------ -const Property* PropertyTable::Get(const std::string& name) const -{ - PropertyMap::const_iterator it = props.find(name); - if (it == props.end()) { - // hasn't been parsed yet? - LazyPropertyMap::const_iterator lit = lazyProps.find(name); - if(lit != lazyProps.end()) { - props[name] = ReadTypedProperty(*(*lit).second); - it = props.find(name); - - ai_assert(it != props.end()); - } - - if (it == props.end()) { - // check property template - if(templateProps) { - return templateProps->Get(name); - } - - return NULL; - } - } - - return (*it).second; -} - -DirectPropertyMap PropertyTable::GetUnparsedProperties() const -{ - DirectPropertyMap result; - - // Loop through all the lazy properties (which is all the properties) - for(const LazyPropertyMap::value_type& element : lazyProps) { - - // Skip parsed properties - if (props.end() != props.find(element.first)) continue; - - // Read the element's value. - // Wrap the naked pointer (since the call site is required to acquire ownership) - // std::unique_ptr from C++11 would be preferred both as a wrapper and a return value. - std::shared_ptr<Property> prop = std::shared_ptr<Property>(ReadTypedProperty(*element.second)); - - // Element could not be read. Skip it. - if (!prop) continue; - - // Add to result - result[element.first] = prop; - } - - return result; -} - -} //! FBX -} //! Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXProperties.h b/thirdparty/assimp/code/FBX/FBXProperties.h deleted file mode 100644 index 58755542fc..0000000000 --- a/thirdparty/assimp/code/FBX/FBXProperties.h +++ /dev/null @@ -1,185 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXProperties.h - * @brief FBX dynamic properties - */ -#ifndef INCLUDED_AI_FBX_PROPERTIES_H -#define INCLUDED_AI_FBX_PROPERTIES_H - -#include "FBXCompileConfig.h" -#include <memory> -#include <string> - -namespace Assimp { -namespace FBX { - -// Forward declarations -class Element; - -/** Represents a dynamic property. Type info added by deriving classes, - * see #TypedProperty. - Example: - @verbatim - P: "ShininessExponent", "double", "Number", "",0.5 - @endvebatim -*/ -class Property { -protected: - Property(); - -public: - virtual ~Property(); - -public: - template <typename T> - const T* As() const { - return dynamic_cast<const T*>(this); - } -}; - -template<typename T> -class TypedProperty : public Property { -public: - explicit TypedProperty(const T& value) - : value(value) { - // empty - } - - const T& Value() const { - return value; - } - -private: - T value; -}; - - -typedef std::fbx_unordered_map<std::string,std::shared_ptr<Property> > DirectPropertyMap; -typedef std::fbx_unordered_map<std::string,const Property*> PropertyMap; -typedef std::fbx_unordered_map<std::string,const Element*> LazyPropertyMap; - -/** - * Represents a property table as can be found in the newer FBX files (Properties60, Properties70) - */ -class PropertyTable { -public: - // in-memory property table with no source element - PropertyTable(); - PropertyTable(const Element& element, std::shared_ptr<const PropertyTable> templateProps); - ~PropertyTable(); - - const Property* Get(const std::string& name) const; - - // PropertyTable's need not be coupled with FBX elements so this can be NULL - const Element* GetElement() const { - return element; - } - - const PropertyTable* TemplateProps() const { - return templateProps.get(); - } - - DirectPropertyMap GetUnparsedProperties() const; - -private: - LazyPropertyMap lazyProps; - mutable PropertyMap props; - const std::shared_ptr<const PropertyTable> templateProps; - const Element* const element; -}; - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline -T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) { - const Property* const prop = in.Get(name); - if( nullptr == prop) { - return defaultValue; - } - - // strong typing, no need to be lenient - const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >(); - if( nullptr == tprop) { - return defaultValue; - } - - return tprop->Value(); -} - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline -T PropertyGet(const PropertyTable& in, const std::string& name, bool& result, bool useTemplate=false ) { - const Property* prop = in.Get(name); - if( nullptr == prop) { - if ( ! useTemplate ) { - result = false; - return T(); - } - const PropertyTable* templ = in.TemplateProps(); - if ( nullptr == templ ) { - result = false; - return T(); - } - prop = templ->Get(name); - if ( nullptr == prop ) { - result = false; - return T(); - } - } - - // strong typing, no need to be lenient - const TypedProperty<T>* const tprop = prop->As< TypedProperty<T> >(); - if( nullptr == tprop) { - result = false; - return T(); - } - - result = true; - return tprop->Value(); -} - -} //! FBX -} //! Assimp - -#endif // INCLUDED_AI_FBX_PROPERTIES_H diff --git a/thirdparty/assimp/code/FBX/FBXTokenizer.cpp b/thirdparty/assimp/code/FBX/FBXTokenizer.cpp deleted file mode 100644 index 252cce3557..0000000000 --- a/thirdparty/assimp/code/FBX/FBXTokenizer.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXTokenizer.cpp - * @brief Implementation of the FBX broadphase lexer - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -// tab width for logging columns -#define ASSIMP_FBX_TAB_WIDTH 4 - -#include <assimp/ParsingUtils.h> - -#include "FBXTokenizer.h" -#include "FBXUtil.h" -#include <assimp/Exceptional.h> - -namespace Assimp { -namespace FBX { - -// ------------------------------------------------------------------------------------------------ -Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column) - : -#ifdef DEBUG - contents(sbegin, static_cast<size_t>(send-sbegin)), -#endif - sbegin(sbegin) - , send(send) - , type(type) - , line(line) - , column(column) -{ - ai_assert(sbegin); - ai_assert(send); - - // tokens must be of non-zero length - ai_assert(static_cast<size_t>(send-sbegin) > 0); -} - -// ------------------------------------------------------------------------------------------------ -Token::~Token() -{ -} - -namespace { - -// ------------------------------------------------------------------------------------------------ -// signal tokenization error, this is always unrecoverable. Throws DeadlyImportError. -AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) AI_WONT_RETURN_SUFFIX; -AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int line, unsigned int column) -{ - throw DeadlyImportError(Util::AddLineAndColumn("FBX-Tokenize",message,line,column)); -} - - -// process a potential data token up to 'cur', adding it to 'output_tokens'. -// ------------------------------------------------------------------------------------------------ -void ProcessDataToken( TokenList& output_tokens, const char*& start, const char*& end, - unsigned int line, - unsigned int column, - TokenType type = TokenType_DATA, - bool must_have_token = false) -{ - if (start && end) { - // sanity check: - // tokens should have no whitespace outside quoted text and [start,end] should - // properly delimit the valid range. - bool in_double_quotes = false; - for (const char* c = start; c != end + 1; ++c) { - if (*c == '\"') { - in_double_quotes = !in_double_quotes; - } - - if (!in_double_quotes && IsSpaceOrNewLine(*c)) { - TokenizeError("unexpected whitespace in token", line, column); - } - } - - if (in_double_quotes) { - TokenizeError("non-terminated double quotes", line, column); - } - - output_tokens.push_back(new_Token(start,end + 1,type,line,column)); - } - else if (must_have_token) { - TokenizeError("unexpected character, expected data token", line, column); - } - - start = end = NULL; -} - -} - -// ------------------------------------------------------------------------------------------------ -void Tokenize(TokenList& output_tokens, const char* input) -{ - ai_assert(input); - - // line and column numbers numbers are one-based - unsigned int line = 1; - unsigned int column = 1; - - bool comment = false; - bool in_double_quotes = false; - bool pending_data_token = false; - - const char* token_begin = NULL, *token_end = NULL; - for (const char* cur = input;*cur;column += (*cur == '\t' ? ASSIMP_FBX_TAB_WIDTH : 1), ++cur) { - const char c = *cur; - - if (IsLineEnd(c)) { - comment = false; - - column = 0; - ++line; - } - - if(comment) { - continue; - } - - if(in_double_quotes) { - if (c == '\"') { - in_double_quotes = false; - token_end = cur; - - ProcessDataToken(output_tokens,token_begin,token_end,line,column); - pending_data_token = false; - } - continue; - } - - switch(c) - { - case '\"': - if (token_begin) { - TokenizeError("unexpected double-quote", line, column); - } - token_begin = cur; - in_double_quotes = true; - continue; - - case ';': - ProcessDataToken(output_tokens,token_begin,token_end,line,column); - comment = true; - continue; - - case '{': - ProcessDataToken(output_tokens,token_begin,token_end, line, column); - output_tokens.push_back(new_Token(cur,cur+1,TokenType_OPEN_BRACKET,line,column)); - continue; - - case '}': - ProcessDataToken(output_tokens,token_begin,token_end,line,column); - output_tokens.push_back(new_Token(cur,cur+1,TokenType_CLOSE_BRACKET,line,column)); - continue; - - case ',': - if (pending_data_token) { - ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_DATA,true); - } - output_tokens.push_back(new_Token(cur,cur+1,TokenType_COMMA,line,column)); - continue; - - case ':': - if (pending_data_token) { - ProcessDataToken(output_tokens,token_begin,token_end,line,column,TokenType_KEY,true); - } - else { - TokenizeError("unexpected colon", line, column); - } - continue; - } - - if (IsSpaceOrNewLine(c)) { - - if (token_begin) { - // peek ahead and check if the next token is a colon in which - // case this counts as KEY token. - TokenType type = TokenType_DATA; - for (const char* peek = cur; *peek && IsSpaceOrNewLine(*peek); ++peek) { - if (*peek == ':') { - type = TokenType_KEY; - cur = peek; - break; - } - } - - ProcessDataToken(output_tokens,token_begin,token_end,line,column,type); - } - - pending_data_token = false; - } - else { - token_end = cur; - if (!token_begin) { - token_begin = cur; - } - - pending_data_token = true; - } - } -} - -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXTokenizer.h b/thirdparty/assimp/code/FBX/FBXTokenizer.h deleted file mode 100644 index afa588a470..0000000000 --- a/thirdparty/assimp/code/FBX/FBXTokenizer.h +++ /dev/null @@ -1,187 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXTokenizer.h - * @brief FBX lexer - */ -#ifndef INCLUDED_AI_FBX_TOKENIZER_H -#define INCLUDED_AI_FBX_TOKENIZER_H - -#include "FBXCompileConfig.h" -#include <assimp/ai_assert.h> -#include <vector> -#include <string> - -namespace Assimp { -namespace FBX { - -/** Rough classification for text FBX tokens used for constructing the - * basic scope hierarchy. */ -enum TokenType -{ - // { - TokenType_OPEN_BRACKET = 0, - - // } - TokenType_CLOSE_BRACKET, - - // '"blablubb"', '2', '*14' - very general token class, - // further processing happens at a later stage. - TokenType_DATA, - - // - TokenType_BINARY_DATA, - - // , - TokenType_COMMA, - - // blubb: - TokenType_KEY -}; - - -/** Represents a single token in a FBX file. Tokens are - * classified by the #TokenType enumerated types. - * - * Offers iterator protocol. Tokens are immutable. */ -class Token -{ -private: - static const unsigned int BINARY_MARKER = static_cast<unsigned int>(-1); - -public: - /** construct a textual token */ - Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column); - - /** construct a binary token */ - Token(const char* sbegin, const char* send, TokenType type, size_t offset); - - ~Token(); - -public: - std::string StringContents() const { - return std::string(begin(),end()); - } - - bool IsBinary() const { - return column == BINARY_MARKER; - } - - const char* begin() const { - return sbegin; - } - - const char* end() const { - return send; - } - - TokenType Type() const { - return type; - } - - size_t Offset() const { - ai_assert(IsBinary()); - return offset; - } - - unsigned int Line() const { - ai_assert(!IsBinary()); - return static_cast<unsigned int>(line); - } - - unsigned int Column() const { - ai_assert(!IsBinary()); - return column; - } - -private: - -#ifdef DEBUG - // full string copy for the sole purpose that it nicely appears - // in msvc's debugger window. - const std::string contents; -#endif - - - const char* const sbegin; - const char* const send; - const TokenType type; - - union { - size_t line; - size_t offset; - }; - const unsigned int column; -}; - -// XXX should use C++11's unique_ptr - but assimp's need to keep working with 03 -typedef const Token* TokenPtr; -typedef std::vector< TokenPtr > TokenList; - -#define new_Token new Token - - -/** Main FBX tokenizer function. Transform input buffer into a list of preprocessed tokens. - * - * Skips over comments and generates line and column numbers. - * - * @param output_tokens Receives a list of all tokens in the input data. - * @param input_buffer Textual input buffer to be processed, 0-terminated. - * @throw DeadlyImportError if something goes wrong */ -void Tokenize(TokenList& output_tokens, const char* input); - - -/** Tokenizer function for binary FBX files. - * - * Emits a token list suitable for direct parsing. - * - * @param output_tokens Receives a list of all tokens in the input data. - * @param input_buffer Binary input buffer to be processed. - * @param length Length of input buffer, in bytes. There is no 0-terminal. - * @throw DeadlyImportError if something goes wrong */ -void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length); - - -} // ! FBX -} // ! Assimp - -#endif // ! INCLUDED_AI_FBX_PARSER_H diff --git a/thirdparty/assimp/code/FBX/FBXUtil.cpp b/thirdparty/assimp/code/FBX/FBXUtil.cpp deleted file mode 100644 index c10e057c8c..0000000000 --- a/thirdparty/assimp/code/FBX/FBXUtil.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXUtil.cpp - * @brief Implementation of internal FBX utility functions - */ - -#include "FBXUtil.h" -#include "FBXTokenizer.h" - -#include <assimp/TinyFormatter.h> -#include <string> -#include <cstring> - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -namespace Assimp { -namespace FBX { -namespace Util { - -// ------------------------------------------------------------------------------------------------ -const char* TokenTypeString(TokenType t) -{ - switch(t) { - case TokenType_OPEN_BRACKET: - return "TOK_OPEN_BRACKET"; - - case TokenType_CLOSE_BRACKET: - return "TOK_CLOSE_BRACKET"; - - case TokenType_DATA: - return "TOK_DATA"; - - case TokenType_COMMA: - return "TOK_COMMA"; - - case TokenType_KEY: - return "TOK_KEY"; - - case TokenType_BINARY_DATA: - return "TOK_BINARY_DATA"; - } - - ai_assert(false); - return ""; -} - - -// ------------------------------------------------------------------------------------------------ -std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset) -{ - return static_cast<std::string>( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) ); -} - -// ------------------------------------------------------------------------------------------------ -std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column) -{ - return static_cast<std::string>( (Formatter::format() << prefix << " (line " << line << " << col " << column << ") " << text) ); -} - -// ------------------------------------------------------------------------------------------------ -std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok) -{ - if(tok->IsBinary()) { - return static_cast<std::string>( (Formatter::format() << prefix << - " (" << TokenTypeString(tok->Type()) << - ", offset 0x" << std::hex << tok->Offset() << ") " << - text) ); - } - - return static_cast<std::string>( (Formatter::format() << prefix << - " (" << TokenTypeString(tok->Type()) << - ", line " << tok->Line() << - ", col " << tok->Column() << ") " << - text) ); -} - -// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; -static const uint8_t base64DecodeTable[128] = { - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, - 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 -}; - -uint8_t DecodeBase64(char ch) -{ - const auto idx = static_cast<uint8_t>(ch); - if (idx > 127) - return 255; - return base64DecodeTable[idx]; -} - -size_t ComputeDecodedSizeBase64(const char* in, size_t inLength) -{ - if (inLength < 2) - { - return 0; - } - const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '='); - const size_t full_length = (inLength * 3) >> 2; // div by 4 - if (full_length < equals) - { - return 0; - } - return full_length - equals; -} - -size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength) -{ - if (maxOutLength == 0 || inLength < 2) { - return 0; - } - const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '='); - size_t dst_offset = 0; - int val = 0, valb = -8; - for (size_t src_offset = 0; src_offset < realLength; ++src_offset) - { - const uint8_t table_value = Util::DecodeBase64(in[src_offset]); - if (table_value == 255) - { - return 0; - } - val = (val << 6) + table_value; - valb += 6; - if (valb >= 0) - { - out[dst_offset++] = static_cast<uint8_t>((val >> valb) & 0xFF); - valb -= 8; - val &= 0xFFF; - } - } - return dst_offset; -} - -static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -char EncodeBase64(char byte) -{ - return to_base64_string[(size_t)byte]; -} - -/** Encodes a block of 4 bytes to base64 encoding -* -* @param bytes Bytes to encode. -* @param out_string String to write encoded values to. -* @param string_pos Position in out_string.*/ -void EncodeByteBlock(const char* bytes, std::string& out_string, size_t string_pos) -{ - char b0 = (bytes[0] & 0xFC) >> 2; - char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4); - char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6); - char b3 = (bytes[2] & 0x3F); - - out_string[string_pos + 0] = EncodeBase64(b0); - out_string[string_pos + 1] = EncodeBase64(b1); - out_string[string_pos + 2] = EncodeBase64(b2); - out_string[string_pos + 3] = EncodeBase64(b3); -} - -std::string EncodeBase64(const char* data, size_t length) -{ - // calculate extra bytes needed to get a multiple of 3 - size_t extraBytes = 3 - length % 3; - - // number of base64 bytes - size_t encodedBytes = 4 * (length + extraBytes) / 3; - - std::string encoded_string(encodedBytes, '='); - - // read blocks of 3 bytes - for (size_t ib3 = 0; ib3 < length / 3; ib3++) - { - const size_t iByte = ib3 * 3; - const size_t iEncodedByte = ib3 * 4; - const char* currData = &data[iByte]; - - EncodeByteBlock(currData, encoded_string, iEncodedByte); - } - - // if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed) - if (extraBytes > 0) - { - char finalBytes[4] = { 0,0,0,0 }; - memcpy(&finalBytes[0], &data[length - length % 3], length % 3); - - const size_t iEncodedByte = encodedBytes - 4; - EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte); - - // add '=' at the end - for (size_t i = 0; i < 4 * extraBytes / 3; i++) - encoded_string[encodedBytes - i - 1] = '='; - } - return encoded_string; -} - -} // !Util -} // !FBX -} // !Assimp - -#endif diff --git a/thirdparty/assimp/code/FBX/FBXUtil.h b/thirdparty/assimp/code/FBX/FBXUtil.h deleted file mode 100644 index b634418858..0000000000 --- a/thirdparty/assimp/code/FBX/FBXUtil.h +++ /dev/null @@ -1,137 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXUtil.h - * @brief FBX utility functions for internal use - */ -#ifndef INCLUDED_AI_FBX_UTIL_H -#define INCLUDED_AI_FBX_UTIL_H - -#include "FBXCompileConfig.h" -#include "FBXTokenizer.h" -#include <stdint.h> - -namespace Assimp { -namespace FBX { - - -namespace Util { - - -/** helper for std::for_each to delete all heap-allocated items in a container */ -template<typename T> -struct delete_fun -{ - void operator()(const volatile T* del) { - delete del; - } -}; - -/** Get a string representation for a #TokenType. */ -const char* TokenTypeString(TokenType t); - - - -/** Format log/error messages using a given offset in the source binary file - * - * @param prefix Message prefix to be preprended to the location info. - * @param text Message text - * @param line Line index, 1-based - * @param column Column index, 1-based - * @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/ -std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset); - - -/** Format log/error messages using a given line location in the source file. - * - * @param prefix Message prefix to be preprended to the location info. - * @param text Message text - * @param line Line index, 1-based - * @param column Column index, 1-based - * @return A string of the following format: {prefix} (line {line}, col {column}) {text}*/ -std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column); - - -/** Format log/error messages using a given cursor token. - * - * @param prefix Message prefix to be preprended to the location info. - * @param text Message text - * @param tok Token where parsing/processing stopped - * @return A string of the following format: {prefix} ({token-type}, line {line}, col {column}) {text}*/ -std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok); - -/** Decode a single Base64-encoded character. -* -* @param ch Character to decode (from base64 to binary). -* @return decoded byte value*/ -uint8_t DecodeBase64(char ch); - -/** Compute decoded size of a Base64-encoded string -* -* @param in Characters to decode. -* @param inLength Number of characters to decode. -* @return size of the decoded data (number of bytes)*/ -size_t ComputeDecodedSizeBase64(const char* in, size_t inLength); - -/** Decode a Base64-encoded string -* -* @param in Characters to decode. -* @param inLength Number of characters to decode. -* @param out Pointer where we will store the decoded data. -* @param maxOutLength Size of output buffer. -* @return size of the decoded data (number of bytes)*/ -size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength); - -char EncodeBase64(char byte); - -/** Encode bytes in base64-encoding -* -* @param data Binary data to encode. -* @param inLength Number of bytes to encode. -* @return base64-encoded string*/ -std::string EncodeBase64(const char* data, size_t length); - -} -} -} - -#endif // ! INCLUDED_AI_FBX_UTIL_H diff --git a/thirdparty/assimp/code/Material/MaterialSystem.cpp b/thirdparty/assimp/code/Material/MaterialSystem.cpp deleted file mode 100644 index 0be6e9f7bb..0000000000 --- a/thirdparty/assimp/code/Material/MaterialSystem.cpp +++ /dev/null @@ -1,632 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file MaterialSystem.cpp - * @brief Implementation of the material system of the library - */ - -#include <assimp/Hash.h> -#include <assimp/fast_atof.h> -#include <assimp/ParsingUtils.h> -#include "MaterialSystem.h" -#include <assimp/types.h> -#include <assimp/material.h> -#include <assimp/DefaultLogger.hpp> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Get a specific property from a material -aiReturn aiGetMaterialProperty(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - const aiMaterialProperty** pPropOut) -{ - ai_assert( pMat != NULL ); - ai_assert( pKey != NULL ); - ai_assert( pPropOut != NULL ); - - /* Just search for a property with exactly this name .. - * could be improved by hashing, but it's possibly - * no worth the effort (we're bound to C structures, - * thus std::map or derivates are not applicable. */ - for ( unsigned int i = 0; i < pMat->mNumProperties; ++i ) { - aiMaterialProperty* prop = pMat->mProperties[i]; - - if (prop /* just for safety ... */ - && 0 == strcmp( prop->mKey.data, pKey ) - && (UINT_MAX == type || prop->mSemantic == type) /* UINT_MAX is a wild-card, but this is undocumented :-) */ - && (UINT_MAX == index || prop->mIndex == index)) - { - *pPropOut = pMat->mProperties[i]; - return AI_SUCCESS; - } - } - *pPropOut = NULL; - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -// Get an array of floating-point values from the material. -aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - ai_real* pOut, - unsigned int* pMax) -{ - ai_assert( pOut != nullptr ); - ai_assert( pMat != nullptr ); - - const aiMaterialProperty* prop; - aiGetMaterialProperty(pMat,pKey,type,index, (const aiMaterialProperty**) &prop); - if ( nullptr == prop) { - return AI_FAILURE; - } - - // data is given in floats, convert to ai_real - unsigned int iWrite = 0; - if( aiPTI_Float == prop->mType || aiPTI_Buffer == prop->mType) { - iWrite = prop->mDataLength / sizeof(float); - if (pMax) { - iWrite = std::min(*pMax,iWrite); ; - } - - for (unsigned int a = 0; a < iWrite; ++a) { - pOut[ a ] = static_cast<ai_real> ( reinterpret_cast<float*>(prop->mData)[a] ); - } - - if (pMax) { - *pMax = iWrite; - } - } - // data is given in doubles, convert to float - else if( aiPTI_Double == prop->mType) { - iWrite = prop->mDataLength / sizeof(double); - if (pMax) { - iWrite = std::min(*pMax,iWrite); ; - } - for (unsigned int a = 0; a < iWrite;++a) { - pOut[a] = static_cast<ai_real> ( reinterpret_cast<double*>(prop->mData)[a] ); - } - if (pMax) { - *pMax = iWrite; - } - } - // data is given in ints, convert to float - else if( aiPTI_Integer == prop->mType) { - iWrite = prop->mDataLength / sizeof(int32_t); - if (pMax) { - iWrite = std::min(*pMax,iWrite); ; - } - for (unsigned int a = 0; a < iWrite;++a) { - pOut[a] = static_cast<ai_real> ( reinterpret_cast<int32_t*>(prop->mData)[a] ); - } - if (pMax) { - *pMax = iWrite; - } - } - // a string ... read floats separated by spaces - else { - if (pMax) { - iWrite = *pMax; - } - // strings are zero-terminated with a 32 bit length prefix, so this is safe - const char *cur = prop->mData + 4; - ai_assert( prop->mDataLength >= 5 ); - ai_assert( !prop->mData[ prop->mDataLength - 1 ] ); - for ( unsigned int a = 0; ;++a) { - cur = fast_atoreal_move<ai_real>(cur,pOut[a]); - if ( a==iWrite-1 ) { - break; - } - if ( !IsSpace(*cur) ) { - ASSIMP_LOG_ERROR("Material property" + std::string(pKey) + - " is a string; failed to parse a float array out of it."); - return AI_FAILURE; - } - } - - if (pMax) { - *pMax = iWrite; - } - } - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Get an array if integers from the material -aiReturn aiGetMaterialIntegerArray(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - int* pOut, - unsigned int* pMax) -{ - ai_assert( pOut != NULL ); - ai_assert( pMat != NULL ); - - const aiMaterialProperty* prop; - aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**) &prop); - if (!prop) { - return AI_FAILURE; - } - - // data is given in ints, simply copy it - unsigned int iWrite = 0; - if( aiPTI_Integer == prop->mType || aiPTI_Buffer == prop->mType) { - iWrite = std::max(static_cast<unsigned int>(prop->mDataLength / sizeof(int32_t)), 1u); - if (pMax) { - iWrite = std::min(*pMax,iWrite); - } - if (1 == prop->mDataLength) { - // bool type, 1 byte - *pOut = static_cast<int>(*prop->mData); - } - else { - for (unsigned int a = 0; a < iWrite;++a) { - pOut[a] = static_cast<int>(reinterpret_cast<int32_t*>(prop->mData)[a]); - } - } - if (pMax) { - *pMax = iWrite; - } - } - // data is given in floats convert to int - else if( aiPTI_Float == prop->mType) { - iWrite = prop->mDataLength / sizeof(float); - if (pMax) { - iWrite = std::min(*pMax,iWrite); ; - } - for (unsigned int a = 0; a < iWrite;++a) { - pOut[a] = static_cast<int>(reinterpret_cast<float*>(prop->mData)[a]); - } - if (pMax) { - *pMax = iWrite; - } - } - // it is a string ... no way to read something out of this - else { - if (pMax) { - iWrite = *pMax; - } - // strings are zero-terminated with a 32 bit length prefix, so this is safe - const char *cur = prop->mData+4; - ai_assert( prop->mDataLength >= 5 ); - ai_assert( !prop->mData[ prop->mDataLength - 1 ] ); - for (unsigned int a = 0; ;++a) { - pOut[a] = strtol10(cur,&cur); - if(a==iWrite-1) { - break; - } - if(!IsSpace(*cur)) { - ASSIMP_LOG_ERROR("Material property" + std::string(pKey) + - " is a string; failed to parse an integer array out of it."); - return AI_FAILURE; - } - } - - if (pMax) { - *pMax = iWrite; - } - } - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Get a color (3 or 4 floats) from the material -aiReturn aiGetMaterialColor(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - aiColor4D* pOut) -{ - unsigned int iMax = 4; - const aiReturn eRet = aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax); - - // if no alpha channel is defined: set it to 1.0 - if (3 == iMax) { - pOut->a = 1.0; - } - - return eRet; -} - -// ------------------------------------------------------------------------------------------------ -// Get a aiUVTransform (4 floats) from the material -aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - aiUVTransform* pOut) -{ - unsigned int iMax = 4; - return aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax); -} - -// ------------------------------------------------------------------------------------------------ -// Get a string from the material -aiReturn aiGetMaterialString(const aiMaterial* pMat, - const char* pKey, - unsigned int type, - unsigned int index, - aiString* pOut) -{ - ai_assert (pOut != NULL); - - const aiMaterialProperty* prop; - aiGetMaterialProperty(pMat,pKey,type,index,(const aiMaterialProperty**)&prop); - if (!prop) { - return AI_FAILURE; - } - - if( aiPTI_String == prop->mType) { - ai_assert(prop->mDataLength>=5); - - // The string is stored as 32 but length prefix followed by zero-terminated UTF8 data - pOut->length = static_cast<unsigned int>(*reinterpret_cast<uint32_t*>(prop->mData)); - - ai_assert( pOut->length+1+4==prop->mDataLength ); - ai_assert( !prop->mData[ prop->mDataLength - 1 ] ); - memcpy(pOut->data,prop->mData+4,pOut->length+1); - } - else { - // TODO - implement lexical cast as well - ASSIMP_LOG_ERROR("Material property" + std::string(pKey) + - " was found, but is no string" ); - return AI_FAILURE; - } - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -// Get the number of textures on a particular texture stack -unsigned int aiGetMaterialTextureCount(const C_STRUCT aiMaterial* pMat, - C_ENUM aiTextureType type) -{ - ai_assert (pMat != NULL); - - // Textures are always stored with ascending indices (ValidateDS provides a check, so we don't need to do it again) - unsigned int max = 0; - for (unsigned int i = 0; i < pMat->mNumProperties;++i) { - aiMaterialProperty* prop = pMat->mProperties[i]; - - if ( prop /* just a sanity check ... */ - && 0 == strcmp( prop->mKey.data, _AI_MATKEY_TEXTURE_BASE ) - && prop->mSemantic == type) { - - max = std::max(max,prop->mIndex+1); - } - } - return max; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn aiGetMaterialTexture(const C_STRUCT aiMaterial* mat, - aiTextureType type, - unsigned int index, - C_STRUCT aiString* path, - aiTextureMapping* _mapping /*= NULL*/, - unsigned int* uvindex /*= NULL*/, - ai_real* blend /*= NULL*/, - aiTextureOp* op /*= NULL*/, - aiTextureMapMode* mapmode /*= NULL*/, - unsigned int* flags /*= NULL*/ - ) -{ - ai_assert( NULL != mat ); - ai_assert( NULL != path ); - - // Get the path to the texture - if (AI_SUCCESS != aiGetMaterialString(mat,AI_MATKEY_TEXTURE(type,index),path)) { - return AI_FAILURE; - } - - // Determine mapping type - int mapping_ = static_cast<int>(aiTextureMapping_UV); - aiGetMaterialInteger(mat,AI_MATKEY_MAPPING(type,index), &mapping_); - aiTextureMapping mapping = static_cast<aiTextureMapping>(mapping_); - if (_mapping) - *_mapping = mapping; - - // Get UV index - if (aiTextureMapping_UV == mapping && uvindex) { - aiGetMaterialInteger(mat,AI_MATKEY_UVWSRC(type,index),(int*)uvindex); - } - // Get blend factor - if (blend) { - aiGetMaterialFloat(mat,AI_MATKEY_TEXBLEND(type,index),blend); - } - // Get texture operation - if (op){ - aiGetMaterialInteger(mat,AI_MATKEY_TEXOP(type,index),(int*)op); - } - // Get texture mapping modes - if (mapmode) { - aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_U(type,index),(int*)&mapmode[0]); - aiGetMaterialInteger(mat,AI_MATKEY_MAPPINGMODE_V(type,index),(int*)&mapmode[1]); - } - // Get texture flags - if (flags){ - aiGetMaterialInteger(mat,AI_MATKEY_TEXFLAGS(type,index),(int*)flags); - } - - return AI_SUCCESS; -} - - -static const unsigned int DefaultNumAllocated = 5; - -// ------------------------------------------------------------------------------------------------ -// Construction. Actually the one and only way to get an aiMaterial instance -aiMaterial::aiMaterial() -: mProperties( nullptr ) -, mNumProperties( 0 ) -, mNumAllocated( DefaultNumAllocated ) { - // Allocate 5 entries by default - mProperties = new aiMaterialProperty*[ DefaultNumAllocated ]; -} - -// ------------------------------------------------------------------------------------------------ -aiMaterial::~aiMaterial() -{ - Clear(); - - delete[] mProperties; -} - -// ------------------------------------------------------------------------------------------------ -aiString aiMaterial::GetName() { - aiString name; - Get(AI_MATKEY_NAME, name); - - return name; -} - -// ------------------------------------------------------------------------------------------------ -void aiMaterial::Clear() -{ - for ( unsigned int i = 0; i < mNumProperties; ++i ) { - // delete this entry - delete mProperties[ i ]; - AI_DEBUG_INVALIDATE_PTR(mProperties[i]); - } - mNumProperties = 0; - - // The array remains allocated, we just invalidated its contents -} - -// ------------------------------------------------------------------------------------------------ -aiReturn aiMaterial::RemoveProperty ( const char* pKey,unsigned int type, unsigned int index ) -{ - ai_assert( nullptr != pKey ); - - for (unsigned int i = 0; i < mNumProperties;++i) { - aiMaterialProperty* prop = mProperties[i]; - - if (prop && !strcmp( prop->mKey.data, pKey ) && - prop->mSemantic == type && prop->mIndex == index) - { - // Delete this entry - delete mProperties[i]; - - // collapse the array behind --. - --mNumProperties; - for (unsigned int a = i; a < mNumProperties;++a) { - mProperties[a] = mProperties[a+1]; - } - return AI_SUCCESS; - } - } - - return AI_FAILURE; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn aiMaterial::AddBinaryProperty (const void* pInput, - unsigned int pSizeInBytes, - const char* pKey, - unsigned int type, - unsigned int index, - aiPropertyTypeInfo pType - ) -{ - ai_assert( pInput != NULL ); - ai_assert( pKey != NULL ); - ai_assert( 0 != pSizeInBytes ); - - if ( 0 == pSizeInBytes ) { - - } - - // first search the list whether there is already an entry with this key - unsigned int iOutIndex( UINT_MAX ); - for ( unsigned int i = 0; i < mNumProperties; ++i ) { - aiMaterialProperty *prop( mProperties[ i ] ); - - if (prop /* just for safety */ && !strcmp( prop->mKey.data, pKey ) && - prop->mSemantic == type && prop->mIndex == index){ - - delete mProperties[i]; - iOutIndex = i; - } - } - - // Allocate a new material property - aiMaterialProperty* pcNew = new aiMaterialProperty(); - - // .. and fill it - pcNew->mType = pType; - pcNew->mSemantic = type; - pcNew->mIndex = index; - - pcNew->mDataLength = pSizeInBytes; - pcNew->mData = new char[pSizeInBytes]; - memcpy (pcNew->mData,pInput,pSizeInBytes); - - pcNew->mKey.length = ::strlen(pKey); - ai_assert ( MAXLEN > pcNew->mKey.length); - strcpy( pcNew->mKey.data, pKey ); - - if (UINT_MAX != iOutIndex) { - mProperties[iOutIndex] = pcNew; - return AI_SUCCESS; - } - - // resize the array ... double the storage allocated - if (mNumProperties == mNumAllocated) { - const unsigned int iOld = mNumAllocated; - mNumAllocated *= 2; - - aiMaterialProperty** ppTemp; - try { - ppTemp = new aiMaterialProperty*[mNumAllocated]; - } catch (std::bad_alloc&) { - delete pcNew; - return AI_OUTOFMEMORY; - } - - // just copy all items over; then replace the old array - memcpy (ppTemp,mProperties,iOld * sizeof(void*)); - - delete[] mProperties; - mProperties = ppTemp; - } - // push back ... - mProperties[mNumProperties++] = pcNew; - - return AI_SUCCESS; -} - -// ------------------------------------------------------------------------------------------------ -aiReturn aiMaterial::AddProperty (const aiString* pInput, - const char* pKey, - unsigned int type, - unsigned int index) -{ - ai_assert(sizeof(ai_uint32)==4); - return AddBinaryProperty(pInput, - static_cast<unsigned int>(pInput->length+1+4), - pKey, - type, - index, - aiPTI_String); -} - -// ------------------------------------------------------------------------------------------------ -uint32_t Assimp::ComputeMaterialHash(const aiMaterial* mat, bool includeMatName /*= false*/) -{ - uint32_t hash = 1503; // magic start value, chosen to be my birthday :-) - for ( unsigned int i = 0; i < mat->mNumProperties; ++i ) { - aiMaterialProperty* prop; - - // Exclude all properties whose first character is '?' from the hash - // See doc for aiMaterialProperty. - if ((prop = mat->mProperties[i]) && (includeMatName || prop->mKey.data[0] != '?')) { - - hash = SuperFastHash(prop->mKey.data,(unsigned int)prop->mKey.length,hash); - hash = SuperFastHash(prop->mData,prop->mDataLength,hash); - - // Combine the semantic and the index with the hash - hash = SuperFastHash((const char*)&prop->mSemantic,sizeof(unsigned int),hash); - hash = SuperFastHash((const char*)&prop->mIndex,sizeof(unsigned int),hash); - } - } - return hash; -} - -// ------------------------------------------------------------------------------------------------ -void aiMaterial::CopyPropertyList(aiMaterial* pcDest, - const aiMaterial* pcSrc - ) -{ - ai_assert(NULL != pcDest); - ai_assert(NULL != pcSrc); - - unsigned int iOldNum = pcDest->mNumProperties; - pcDest->mNumAllocated += pcSrc->mNumAllocated; - pcDest->mNumProperties += pcSrc->mNumProperties; - - aiMaterialProperty** pcOld = pcDest->mProperties; - pcDest->mProperties = new aiMaterialProperty*[pcDest->mNumAllocated]; - - if (iOldNum && pcOld) { - for (unsigned int i = 0; i < iOldNum;++i) { - pcDest->mProperties[i] = pcOld[i]; - } - } - - if ( pcOld ) { - delete[] pcOld; - } - - for (unsigned int i = iOldNum; i< pcDest->mNumProperties;++i) { - aiMaterialProperty* propSrc = pcSrc->mProperties[i]; - - // search whether we have already a property with this name -> if yes, overwrite it - aiMaterialProperty* prop; - for ( unsigned int q = 0; q < iOldNum; ++q ) { - prop = pcDest->mProperties[q]; - if (prop /* just for safety */ && prop->mKey == propSrc->mKey && prop->mSemantic == propSrc->mSemantic - && prop->mIndex == propSrc->mIndex) { - delete prop; - - // collapse the whole array ... - memmove(&pcDest->mProperties[q],&pcDest->mProperties[q+1],i-q); - i--; - pcDest->mNumProperties--; - } - } - - // Allocate the output property and copy the source property - prop = pcDest->mProperties[i] = new aiMaterialProperty(); - prop->mKey = propSrc->mKey; - prop->mDataLength = propSrc->mDataLength; - prop->mType = propSrc->mType; - prop->mSemantic = propSrc->mSemantic; - prop->mIndex = propSrc->mIndex; - - prop->mData = new char[propSrc->mDataLength]; - memcpy(prop->mData,propSrc->mData,prop->mDataLength); - } -} diff --git a/thirdparty/assimp/code/Material/MaterialSystem.h b/thirdparty/assimp/code/Material/MaterialSystem.h deleted file mode 100644 index 67d53578cb..0000000000 --- a/thirdparty/assimp/code/Material/MaterialSystem.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file MaterialSystem.h - * Now that #MaterialHelper is gone, this file only contains some - * internal material utility functions. - */ -#ifndef AI_MATERIALSYSTEM_H_INC -#define AI_MATERIALSYSTEM_H_INC - -#include <stdint.h> - -struct aiMaterial; - -namespace Assimp { - -// ------------------------------------------------------------------------------ -/** Computes a hash (hopefully unique) from all material properties - * The hash value reflects the current property state, so if you add any - * property and call this method again, the resulting hash value will be - * different. The hash is not persistent across different builds and platforms. - * - * @param includeMatName Set to 'true' to take all properties with - * '?' as initial character in their name into account. - * Currently #AI_MATKEY_NAME is the only example. - * @return 32 Bit jash value for the material - */ -uint32_t ComputeMaterialHash(const aiMaterial* mat, bool includeMatName = false); - - -} // ! namespace Assimp - -#endif //!! AI_MATERIALSYSTEM_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.cpp b/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.cpp deleted file mode 100644 index 75daeb6b59..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -#include "ArmaturePopulate.h" - -#include <assimp/BaseImporter.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/postprocess.h> -#include <assimp/scene.h> -#include <iostream> - -namespace Assimp { - -/// The default class constructor. -ArmaturePopulate::ArmaturePopulate() : BaseProcess() -{} - -/// The class destructor. -ArmaturePopulate::~ArmaturePopulate() -{} - -bool ArmaturePopulate::IsActive(unsigned int pFlags) const { - return (pFlags & aiProcess_PopulateArmatureData) != 0; -} - -void ArmaturePopulate::SetupProperties(const Importer *pImp) { - // do nothing -} - -void ArmaturePopulate::Execute(aiScene *out) { - - // Now convert all bone positions to the correct mOffsetMatrix - std::vector<aiBone *> bones; - std::vector<aiNode *> nodes; - std::map<aiBone *, aiNode *> bone_stack; - BuildBoneList(out->mRootNode, out->mRootNode, out, bones); - BuildNodeList(out->mRootNode, nodes); - - BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes); - - ASSIMP_LOG_DEBUG_F("Bone stack size: ", bone_stack.size()); - - for (std::pair<aiBone *, aiNode *> kvp : bone_stack) { - aiBone *bone = kvp.first; - aiNode *bone_node = kvp.second; - ASSIMP_LOG_DEBUG_F("active node lookup: ", bone->mName.C_Str()); - // lcl transform grab - done in generate_nodes :) - - // bone->mOffsetMatrix = bone_node->mTransformation; - aiNode *armature = GetArmatureRoot(bone_node, bones); - - ai_assert(armature); - - // set up bone armature id - bone->mArmature = armature; - - // set this bone node to be referenced properly - ai_assert(bone_node); - bone->mNode = bone_node; - } -} - - -/* Reprocess all nodes to calculate bone transforms properly based on the REAL - * mOffsetMatrix not the local. */ -/* Before this would use mesh transforms which is wrong for bone transforms */ -/* Before this would work for simple character skeletons but not complex meshes - * with multiple origins */ -/* Source: sketch fab log cutter fbx */ -void ArmaturePopulate::BuildBoneList(aiNode *current_node, - const aiNode *root_node, - const aiScene *scene, - std::vector<aiBone *> &bones) { - ai_assert(scene); - for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) { - aiNode *child = current_node->mChildren[nodeId]; - ai_assert(child); - - // check for bones - for (unsigned int meshId = 0; meshId < child->mNumMeshes; ++meshId) { - ai_assert(child->mMeshes); - unsigned int mesh_index = child->mMeshes[meshId]; - aiMesh *mesh = scene->mMeshes[mesh_index]; - ai_assert(mesh); - - for (unsigned int boneId = 0; boneId < mesh->mNumBones; ++boneId) { - aiBone *bone = mesh->mBones[boneId]; - ai_assert(bone); - - // duplicate meshes exist with the same bones sometimes :) - // so this must be detected - if (std::find(bones.begin(), bones.end(), bone) == bones.end()) { - // add the element once - bones.push_back(bone); - } - } - - // find mesh and get bones - // then do recursive lookup for bones in root node hierarchy - } - - BuildBoneList(child, root_node, scene, bones); - } -} - -/* Prepare flat node list which can be used for non recursive lookups later */ -void ArmaturePopulate::BuildNodeList(const aiNode *current_node, - std::vector<aiNode *> &nodes) { - ai_assert(current_node); - - for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) { - aiNode *child = current_node->mChildren[nodeId]; - ai_assert(child); - - nodes.push_back(child); - - BuildNodeList(child, nodes); - } -} - -/* A bone stack allows us to have multiple armatures, with the same bone names - * A bone stack allows us also to retrieve bones true transform even with - * duplicate names :) - */ -void ArmaturePopulate::BuildBoneStack(aiNode *current_node, - const aiNode *root_node, - const aiScene *scene, - const std::vector<aiBone *> &bones, - std::map<aiBone *, aiNode *> &bone_stack, - std::vector<aiNode *> &node_stack) { - ai_assert(scene); - ai_assert(root_node); - ai_assert(!node_stack.empty()); - - for (aiBone *bone : bones) { - ai_assert(bone); - aiNode *node = GetNodeFromStack(bone->mName, node_stack); - if (node == nullptr) { - node_stack.clear(); - BuildNodeList(root_node, node_stack); - ASSIMP_LOG_DEBUG_F("Resetting bone stack: nullptr element ", bone->mName.C_Str()); - - node = GetNodeFromStack(bone->mName, node_stack); - - if (!node) { - ASSIMP_LOG_ERROR("serious import issue node for bone was not detected"); - continue; - } - } - - ASSIMP_LOG_DEBUG_F("Successfully added bone[", bone->mName.C_Str(), "] to stack and bone node is: ", node->mName.C_Str()); - - bone_stack.insert(std::pair<aiBone *, aiNode *>(bone, node)); - } -} - - -/* Returns the armature root node */ -/* This is required to be detected for a bone initially, it will recurse up - * until it cannot find another bone and return the node No known failure - * points. (yet) - */ -aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node, - std::vector<aiBone *> &bone_list) { - while (bone_node) { - if (!IsBoneNode(bone_node->mName, bone_list)) { - ASSIMP_LOG_DEBUG_F("GetArmatureRoot() Found valid armature: ", bone_node->mName.C_Str()); - return bone_node; - } - - bone_node = bone_node->mParent; - } - - ASSIMP_LOG_ERROR("GetArmatureRoot() can't find armature!"); - - return nullptr; -} - - - -/* Simple IsBoneNode check if this could be a bone */ -bool ArmaturePopulate::IsBoneNode(const aiString &bone_name, - std::vector<aiBone *> &bones) { - for (aiBone *bone : bones) { - if (bone->mName == bone_name) { - return true; - } - } - - return false; -} - -/* Pop this node by name from the stack if found */ -/* Used in multiple armature situations with duplicate node / bone names */ -/* Known flaw: cannot have nodes with bone names, will be fixed in later release - */ -/* (serious to be fixed) Known flaw: nodes which have more than one bone could - * be prematurely dropped from stack */ -aiNode *ArmaturePopulate::GetNodeFromStack(const aiString &node_name, - std::vector<aiNode *> &nodes) { - std::vector<aiNode *>::iterator iter; - aiNode *found = nullptr; - for (iter = nodes.begin(); iter < nodes.end(); ++iter) { - aiNode *element = *iter; - ai_assert(element); - // node valid and node name matches - if (element->mName == node_name) { - found = element; - break; - } - } - - if (found != nullptr) { - ASSIMP_LOG_INFO_F("Removed node from stack: ", found->mName.C_Str()); - // now pop the element from the node list - nodes.erase(iter); - - return found; - } - - // unique names can cause this problem - ASSIMP_LOG_ERROR("[Serious] GetNodeFromStack() can't find node from stack!"); - - return nullptr; -} - - - - -} // Namespace Assimp diff --git a/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.h b/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.h deleted file mode 100644 index aa1ad7c80c..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ArmaturePopulate.h +++ /dev/null @@ -1,112 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -#ifndef ARMATURE_POPULATE_H_ -#define ARMATURE_POPULATE_H_ - -#include "Common/BaseProcess.h" -#include <assimp/BaseImporter.h> -#include <vector> -#include <map> - - -struct aiNode; -struct aiBone; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** Armature Populate: This is a post process designed - * To save you time when importing models into your game engines - * This was originally designed only for fbx but will work with other formats - * it is intended to auto populate aiBone data with armature and the aiNode - * This is very useful when dealing with skinned meshes - * or when dealing with many different skeletons - * It's off by default but recommend that you try it and use it - * It should reduce down any glue code you have in your - * importers - * You can contact RevoluPowered <gordon@gordonite.tech> - * For more info about this -*/ -class ASSIMP_API ArmaturePopulate : public BaseProcess { -public: - /// The default class constructor. - ArmaturePopulate(); - - /// The class destructor. - virtual ~ArmaturePopulate(); - - /// Overwritten, @see BaseProcess - virtual bool IsActive( unsigned int pFlags ) const; - - /// Overwritten, @see BaseProcess - virtual void SetupProperties( const Importer* pImp ); - - /// Overwritten, @see BaseProcess - virtual void Execute( aiScene* pScene ); - - static aiNode *GetArmatureRoot(aiNode *bone_node, - std::vector<aiBone *> &bone_list); - - static bool IsBoneNode(const aiString &bone_name, - std::vector<aiBone *> &bones); - - static aiNode *GetNodeFromStack(const aiString &node_name, - std::vector<aiNode *> &nodes); - - static void BuildNodeList(const aiNode *current_node, - std::vector<aiNode *> &nodes); - - static void BuildBoneList(aiNode *current_node, const aiNode *root_node, - const aiScene *scene, - std::vector<aiBone *> &bones); - - static void BuildBoneStack(aiNode *current_node, const aiNode *root_node, - const aiScene *scene, - const std::vector<aiBone *> &bones, - std::map<aiBone *, aiNode *> &bone_stack, - std::vector<aiNode *> &node_stack); -}; - -} // Namespace Assimp - - -#endif // SCALE_PROCESS_H_
\ No newline at end of file diff --git a/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.cpp b/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.cpp deleted file mode 100644 index a3f7dd2557..0000000000 --- a/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the post processing step to calculate - * tangents and bitangents for all imported meshes - */ - -// internal headers -#include "CalcTangentsProcess.h" -#include "ProcessHelper.h" -#include <assimp/TinyFormatter.h> -#include <assimp/qnan.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -CalcTangentsProcess::CalcTangentsProcess() -: configMaxAngle( AI_DEG_TO_RAD(45.f) ) -, configSourceUV( 0 ) { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -CalcTangentsProcess::~CalcTangentsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool CalcTangentsProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_CalcTangentSpace) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void CalcTangentsProcess::SetupProperties(const Importer* pImp) -{ - ai_assert( NULL != pImp ); - - // get the current value of the property - configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f); - configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f); - configMaxAngle = AI_DEG_TO_RAD(configMaxAngle); - - configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void CalcTangentsProcess::Execute( aiScene* pScene) -{ - ai_assert( NULL != pScene ); - - ASSIMP_LOG_DEBUG("CalcTangentsProcess begin"); - - bool bHas = false; - for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) { - if(ProcessMesh( pScene->mMeshes[a],a))bHas = true; - } - - if ( bHas ) { - ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated"); - } else { - ASSIMP_LOG_DEBUG("CalcTangentsProcess finished"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Calculates tangents and bi-tangents for the given mesh -bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) -{ - // we assume that the mesh is still in the verbose vertex format where each face has its own set - // of vertices and no vertices are shared between faces. Sadly I don't know any quick test to - // assert() it here. - // assert( must be verbose, dammit); - - if (pMesh->mTangents) // this implies that mBitangents is also there - return false; - - // If the mesh consists of lines and/or points but not of - // triangles or higher-order polygons the normal vectors - // are undefined. - if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) - { - ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes"); - return false; - } - - // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement - if( pMesh->mNormals == NULL) - { - ASSIMP_LOG_ERROR("Failed to compute tangents; need normals"); - return false; - } - if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] ) - { - ASSIMP_LOG_ERROR((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV)); - return false; - } - - const float angleEpsilon = 0.9999f; - - std::vector<bool> vertexDone( pMesh->mNumVertices, false); - const float qnan = get_qnan(); - - // create space for the tangents and bitangents - pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; - pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; - - const aiVector3D* meshPos = pMesh->mVertices; - const aiVector3D* meshNorm = pMesh->mNormals; - const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV]; - aiVector3D* meshTang = pMesh->mTangents; - aiVector3D* meshBitang = pMesh->mBitangents; - - // calculate the tangent and bitangent for every face - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - const aiFace& face = pMesh->mFaces[a]; - if (face.mNumIndices < 3) - { - // There are less than three indices, thus the tangent vector - // is not defined. We are finished with these vertices now, - // their tangent vectors are set to qnan. - for (unsigned int i = 0; i < face.mNumIndices;++i) - { - unsigned int idx = face.mIndices[i]; - vertexDone [idx] = true; - meshTang [idx] = aiVector3D(qnan); - meshBitang [idx] = aiVector3D(qnan); - } - - continue; - } - - // triangle or polygon... we always use only the first three indices. A polygon - // is supposed to be planar anyways.... - // FIXME: (thom) create correct calculation for multi-vertex polygons maybe? - const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2]; - - // position differences p1->p2 and p1->p3 - aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0]; - - // texture offset p1->p2 and p1->p3 - float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y; - float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y; - float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f; - // when t1, t2, t3 in same position in UV space, just use default UV direction. - if ( sx * ty == sy * tx ) { - sx = 0.0; sy = 1.0; - tx = 1.0; ty = 0.0; - } - - // tangent points in the direction where to positive X axis of the texture coord's would point in model space - // bitangent's points along the positive Y axis of the texture coord's, respectively - aiVector3D tangent, bitangent; - tangent.x = (w.x * sy - v.x * ty) * dirCorrection; - tangent.y = (w.y * sy - v.y * ty) * dirCorrection; - tangent.z = (w.z * sy - v.z * ty) * dirCorrection; - bitangent.x = (w.x * sx - v.x * tx) * dirCorrection; - bitangent.y = (w.y * sx - v.y * tx) * dirCorrection; - bitangent.z = (w.z * sx - v.z * tx) * dirCorrection; - - // store for every vertex of that face - for( unsigned int b = 0; b < face.mNumIndices; ++b ) { - unsigned int p = face.mIndices[b]; - - // project tangent and bitangent into the plane formed by the vertex' normal - aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]); - aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]); - localTangent.NormalizeSafe(); localBitangent.NormalizeSafe(); - - // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN. - bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z); - bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z); - if (invalid_tangent != invalid_bitangent) { - if (invalid_tangent) { - localTangent = meshNorm[p] ^ localBitangent; - localTangent.NormalizeSafe(); - } else { - localBitangent = localTangent ^ meshNorm[p]; - localBitangent.NormalizeSafe(); - } - } - - // and write it into the mesh. - meshTang[ p ] = localTangent; - meshBitang[ p ] = localBitangent; - } - } - - - // create a helper to quickly find locally close vertices among the vertex array - // FIX: check whether we can reuse the SpatialSort of a previous step - SpatialSort* vertexFinder = NULL; - SpatialSort _vertexFinder; - float posEpsilon; - if (shared) - { - std::vector<std::pair<SpatialSort,float> >* avf; - shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); - if (avf) - { - std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex); - vertexFinder = &blubb.first; - posEpsilon = blubb.second;; - } - } - if (!vertexFinder) - { - _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); - vertexFinder = &_vertexFinder; - posEpsilon = ComputePositionEpsilon(pMesh); - } - std::vector<unsigned int> verticesFound; - - const float fLimit = std::cos(configMaxAngle); - std::vector<unsigned int> closeVertices; - - // in the second pass we now smooth out all tangents and bitangents at the same local position - // if they are not too far off. - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) - { - if( vertexDone[a]) - continue; - - const aiVector3D& origPos = pMesh->mVertices[a]; - const aiVector3D& origNorm = pMesh->mNormals[a]; - const aiVector3D& origTang = pMesh->mTangents[a]; - const aiVector3D& origBitang = pMesh->mBitangents[a]; - closeVertices.resize( 0 ); - - // find all vertices close to that position - vertexFinder->FindPositions( origPos, posEpsilon, verticesFound); - - closeVertices.reserve (verticesFound.size()+5); - closeVertices.push_back( a); - - // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent - for( unsigned int b = 0; b < verticesFound.size(); b++) - { - unsigned int idx = verticesFound[b]; - if( vertexDone[idx]) - continue; - if( meshNorm[idx] * origNorm < angleEpsilon) - continue; - if( meshTang[idx] * origTang < fLimit) - continue; - if( meshBitang[idx] * origBitang < fLimit) - continue; - - // it's similar enough -> add it to the smoothing group - closeVertices.push_back( idx); - vertexDone[idx] = true; - } - - // smooth the tangents and bitangents of all vertices that were found to be close enough - aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0); - for( unsigned int b = 0; b < closeVertices.size(); ++b) - { - smoothTangent += meshTang[ closeVertices[b] ]; - smoothBitangent += meshBitang[ closeVertices[b] ]; - } - smoothTangent.Normalize(); - smoothBitangent.Normalize(); - - // and write it back into all affected tangents - for( unsigned int b = 0; b < closeVertices.size(); ++b) - { - meshTang[ closeVertices[b] ] = smoothTangent; - meshBitang[ closeVertices[b] ] = smoothBitangent; - } - } - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.h b/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.h deleted file mode 100644 index 3568a624f8..0000000000 --- a/thirdparty/assimp/code/PostProcessing/CalcTangentsProcess.h +++ /dev/null @@ -1,117 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - - -/** @file Defines a post processing step to calculate tangents and - bi-tangents on all imported meshes.*/ -#ifndef AI_CALCTANGENTSPROCESS_H_INC -#define AI_CALCTANGENTSPROCESS_H_INC - -#include "Common/BaseProcess.h" - -struct aiMesh; - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The CalcTangentsProcess calculates the tangent and bitangent for any vertex - * of all meshes. It is expected to be run before the JoinVerticesProcess runs - * because the joining of vertices also considers tangents and bitangents for - * uniqueness. - */ -class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess -{ -public: - - CalcTangentsProcess(); - ~CalcTangentsProcess(); - -public: - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. - * A bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); - - - // setter for configMaxAngle - inline void SetMaxSmoothAngle(float f) - { - configMaxAngle =f; - } - -protected: - - // ------------------------------------------------------------------- - /** Calculates tangents and bitangents for a specific mesh. - * @param pMesh The mesh to process. - * @param meshIndex Index of the mesh - */ - bool ProcessMesh( aiMesh* pMesh, unsigned int meshIndex); - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - -private: - - /** Configuration option: maximum smoothing angle, in radians*/ - float configMaxAngle; - unsigned int configSourceUV; -}; - -} // end of namespace Assimp - -#endif // AI_CALCTANGENTSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp b/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp deleted file mode 100644 index df4d44337d..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.cpp +++ /dev/null @@ -1,506 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file GenUVCoords step */ - - -#include "ComputeUVMappingProcess.h" -#include "ProcessHelper.h" -#include <assimp/Exceptional.h> - -using namespace Assimp; - -namespace { - - const static aiVector3D base_axis_y(0.0,1.0,0.0); - const static aiVector3D base_axis_x(1.0,0.0,0.0); - const static aiVector3D base_axis_z(0.0,0.0,1.0); - const static ai_real angle_epsilon = ai_real( 0.95 ); -} - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -ComputeUVMappingProcess::ComputeUVMappingProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -ComputeUVMappingProcess::~ComputeUVMappingProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_GenUVCoords) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Check whether a ray intersects a plane and find the intersection point -inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, - const aiVector3D& planeNormal, aiVector3D& pos) -{ - const ai_real b = planeNormal * (planePos - ray.pos); - ai_real h = ray.dir * planeNormal; - if ((h < 10e-5 && h > -10e-5) || (h = b/h) < 0) - return false; - - pos = ray.pos + (ray.dir * h); - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Find the first empty UV channel in a mesh -inline unsigned int FindEmptyUVChannel (aiMesh* mesh) -{ - for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m) - if (!mesh->mTextureCoords[m])return m; - - ASSIMP_LOG_ERROR("Unable to compute UV coordinates, no free UV slot found"); - return UINT_MAX; -} - -// ------------------------------------------------------------------------------------------------ -// Try to remove UV seams -void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) -{ - // TODO: just a very rough algorithm. I think it could be done - // much easier, but I don't know how and am currently too tired to - // to think about a better solution. - - const static ai_real LOWER_LIMIT = ai_real( 0.1 ); - const static ai_real UPPER_LIMIT = ai_real( 0.9 ); - - const static ai_real LOWER_EPSILON = ai_real( 10e-3 ); - const static ai_real UPPER_EPSILON = ai_real( 1.0-10e-3 ); - - for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) - { - const aiFace& face = mesh->mFaces[fidx]; - if (face.mNumIndices < 3) continue; // triangles and polygons only, please - - unsigned int small = face.mNumIndices, large = small; - bool zero = false, one = false, round_to_zero = false; - - // Check whether this face lies on a UV seam. We can just guess, - // but the assumption that a face with at least one very small - // on the one side and one very large U coord on the other side - // lies on a UV seam should work for most cases. - for (unsigned int n = 0; n < face.mNumIndices;++n) - { - if (out[face.mIndices[n]].x < LOWER_LIMIT) - { - small = n; - - // If we have a U value very close to 0 we can't - // round the others to 0, too. - if (out[face.mIndices[n]].x <= LOWER_EPSILON) - zero = true; - else round_to_zero = true; - } - if (out[face.mIndices[n]].x > UPPER_LIMIT) - { - large = n; - - // If we have a U value very close to 1 we can't - // round the others to 1, too. - if (out[face.mIndices[n]].x >= UPPER_EPSILON) - one = true; - } - } - if (small != face.mNumIndices && large != face.mNumIndices) - { - for (unsigned int n = 0; n < face.mNumIndices;++n) - { - // If the u value is over the upper limit and no other u - // value of that face is 0, round it to 0 - if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero) - out[face.mIndices[n]].x = 0.0; - - // If the u value is below the lower limit and no other u - // value of that face is 1, round it to 1 - else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one) - out[face.mIndices[n]].x = 1.0; - - // The face contains both 0 and 1 as UV coords. This can occur - // for faces which have an edge that lies directly on the seam. - // Due to numerical inaccuracies one U coord becomes 0, the - // other 1. But we do still have a third UV coord to determine - // to which side we must round to. - else if (one && zero) - { - if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON) - out[face.mIndices[n]].x = 0.0; - else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON) - out[face.mIndices[n]].x = 1.0; - } - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) -{ - aiVector3D center, min, max; - FindMeshCenter(mesh, center, min, max); - - // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... - // currently the mapping axis will always be one of x,y,z, except if the - // PretransformVertices step is used (it transforms the meshes into worldspace, - // thus changing the mapping axis) - if (axis * base_axis_x >= angle_epsilon) { - - // For each point get a normalized projection vector in the sphere, - // get its longitude and latitude and map them to their respective - // UV axes. Problems occur around the poles ... unsolvable. - // - // The spherical coordinate system looks like this: - // x = cos(lon)*cos(lat) - // y = sin(lon)*cos(lat) - // z = sin(lat) - // - // Thus we can derive: - // lat = arcsin (z) - // lon = arctan (y/x) - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); - } - } - else if (axis * base_axis_y >= angle_epsilon) { - // ... just the same again - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); - } - } - else if (axis * base_axis_z >= angle_epsilon) { - // ... just the same again - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); - } - } - // slower code path in case the mapping axis is not one of the coordinate system axes - else { - aiMatrix4x4 mTrafo; - aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); - - // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize(); - out[pnt] = aiVector3D((std::atan2(diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, - (std::asin(diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.0); - } - } - - - // Now find and remove UV seams. A seam occurs if a face has a tcoord - // close to zero on the one side, and a tcoord close to one on the - // other side. - RemoveUVSeams(mesh,out); -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) -{ - aiVector3D center, min, max; - - // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... - // currently the mapping axis will always be one of x,y,z, except if the - // PretransformVertices step is used (it transforms the meshes into worldspace, - // thus changing the mapping axis) - if (axis * base_axis_x >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - const ai_real diff = max.x - min.x; - - // If the main axis is 'z', the z coordinate of a point 'p' is mapped - // directly to the texture V axis. The other axis is derived from - // the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where - // 'c' is the center point of the mesh. - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; - - uv.y = (pos.x - min.x) / diff; - uv.x = (std::atan2( pos.z - center.z, pos.y - center.y) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; - } - } - else if (axis * base_axis_y >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - const ai_real diff = max.y - min.y; - - // just the same ... - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; - - uv.y = (pos.y - min.y) / diff; - uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; - } - } - else if (axis * base_axis_z >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - const ai_real diff = max.z - min.z; - - // just the same ... - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; - - uv.y = (pos.z - min.z) / diff; - uv.x = (std::atan2( pos.y - center.y, pos.x - center.x) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; - } - } - // slower code path in case the mapping axis is not one of the coordinate system axes - else { - aiMatrix4x4 mTrafo; - aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); - FindMeshCenterTransformed(mesh, center, min, max,mTrafo); - const ai_real diff = max.y - min.y; - - // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){ - const aiVector3D pos = mTrafo* mesh->mVertices[pnt]; - aiVector3D& uv = out[pnt]; - - uv.y = (pos.y - min.y) / diff; - uv.x = (std::atan2( pos.x - center.x, pos.z - center.z) +(ai_real)AI_MATH_PI ) / (ai_real)AI_MATH_TWO_PI; - } - } - - // Now find and remove UV seams. A seam occurs if a face has a tcoord - // close to zero on the one side, and a tcoord close to one on the - // other side. - RemoveUVSeams(mesh,out); -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) -{ - ai_real diffu,diffv; - aiVector3D center, min, max; - - // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... - // currently the mapping axis will always be one of x,y,z, except if the - // PretransformVertices step is used (it transforms the meshes into worldspace, - // thus changing the mapping axis) - if (axis * base_axis_x >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - diffu = max.z - min.z; - diffv = max.y - min.y; - - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.0); - } - } - else if (axis * base_axis_y >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - diffu = max.x - min.x; - diffv = max.z - min.z; - - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0); - } - } - else if (axis * base_axis_z >= angle_epsilon) { - FindMeshCenter(mesh, center, min, max); - diffu = max.x - min.x; - diffv = max.y - min.y; - - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D& pos = mesh->mVertices[pnt]; - out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0); - } - } - // slower code path in case the mapping axis is not one of the coordinate system axes - else - { - aiMatrix4x4 mTrafo; - aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); - FindMeshCenterTransformed(mesh, center, min, max,mTrafo); - diffu = max.x - min.x; - diffv = max.z - min.z; - - // again the same, except we're applying a transformation now - for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { - const aiVector3D pos = mTrafo * mesh->mVertices[pnt]; - out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.0); - } - } - - // shouldn't be necessary to remove UV seams ... -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* ) -{ - ASSIMP_LOG_ERROR("Mapping type currently not implemented"); -} - -// ------------------------------------------------------------------------------------------------ -void ComputeUVMappingProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin"); - char buffer[1024]; - - if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) - throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); - - std::list<MappingInfo> mappingStack; - - /* Iterate through all materials and search for non-UV mapped textures - */ - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) - { - mappingStack.clear(); - aiMaterial* mat = pScene->mMaterials[i]; - for (unsigned int a = 0; a < mat->mNumProperties;++a) - { - aiMaterialProperty* prop = mat->mProperties[a]; - if (!::strcmp( prop->mKey.data, "$tex.mapping")) - { - aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData); - if (aiTextureMapping_UV != mapping) - { - if (!DefaultLogger::isNullLogger()) - { - ai_snprintf(buffer, 1024, "Found non-UV mapped texture (%s,%u). Mapping type: %s", - TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex, - MappingTypeToString(mapping)); - - ASSIMP_LOG_INFO(buffer); - } - - if (aiTextureMapping_OTHER == mapping) - continue; - - MappingInfo info (mapping); - - // Get further properties - currently only the major axis - for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) - { - aiMaterialProperty* prop2 = mat->mProperties[a2]; - if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) - continue; - - if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) { - info.axis = *((aiVector3D*)prop2->mData); - break; - } - } - - unsigned int idx( 99999999 ); - - // Check whether we have this mapping mode already - std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info); - if (mappingStack.end() != it) - { - idx = (*it).uv; - } - else - { - /* We have found a non-UV mapped texture. Now - * we need to find all meshes using this material - * that we can compute UV channels for them. - */ - for (unsigned int m = 0; m < pScene->mNumMeshes;++m) - { - aiMesh* mesh = pScene->mMeshes[m]; - unsigned int outIdx = 0; - if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX || - !mesh->mNumVertices) - { - continue; - } - - // Allocate output storage - aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices]; - - switch (mapping) - { - case aiTextureMapping_SPHERE: - ComputeSphereMapping(mesh,info.axis,p); - break; - case aiTextureMapping_CYLINDER: - ComputeCylinderMapping(mesh,info.axis,p); - break; - case aiTextureMapping_PLANE: - ComputePlaneMapping(mesh,info.axis,p); - break; - case aiTextureMapping_BOX: - ComputeBoxMapping(mesh,p); - break; - default: - ai_assert(false); - } - if (m && idx != outIdx) - { - ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to " - "this material have equal numbers of UV channels. The UV index stored in " - "the material structure does therefore not apply for all meshes. "); - } - idx = outIdx; - } - info.uv = idx; - mappingStack.push_back(info); - } - - // Update the material property list - mapping = aiTextureMapping_UV; - ((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex)); - } - } - } - } - ASSIMP_LOG_DEBUG("GenUVCoordsProcess finished"); -} diff --git a/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.h b/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.h deleted file mode 100644 index a6d36e06ea..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ComputeUVMappingProcess.h +++ /dev/null @@ -1,149 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to compute UV coordinates - from abstract mappings, such as box or spherical*/ -#ifndef AI_COMPUTEUVMAPPING_H_INC -#define AI_COMPUTEUVMAPPING_H_INC - -#include "Common/BaseProcess.h" - -#include <assimp/mesh.h> -#include <assimp/material.h> -#include <assimp/types.h> - -class ComputeUVMappingTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** ComputeUVMappingProcess - converts special mappings, such as spherical, - * cylindrical or boxed to proper UV coordinates for rendering. -*/ -class ComputeUVMappingProcess : public BaseProcess -{ -public: - ComputeUVMappingProcess(); - ~ComputeUVMappingProcess(); - -public: - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - -protected: - - // ------------------------------------------------------------------- - /** Computes spherical UV coordinates for a mesh - * - * @param mesh Mesh to be processed - * @param axis Main axis - * @param out Receives output UV coordinates - */ - void ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, - aiVector3D* out); - - // ------------------------------------------------------------------- - /** Computes cylindrical UV coordinates for a mesh - * - * @param mesh Mesh to be processed - * @param axis Main axis - * @param out Receives output UV coordinates - */ - void ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, - aiVector3D* out); - - // ------------------------------------------------------------------- - /** Computes planar UV coordinates for a mesh - * - * @param mesh Mesh to be processed - * @param axis Main axis - * @param out Receives output UV coordinates - */ - void ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, - aiVector3D* out); - - // ------------------------------------------------------------------- - /** Computes cubic UV coordinates for a mesh - * - * @param mesh Mesh to be processed - * @param out Receives output UV coordinates - */ - void ComputeBoxMapping(aiMesh* mesh, aiVector3D* out); - -private: - - // temporary structure to describe a mapping - struct MappingInfo - { - explicit MappingInfo(aiTextureMapping _type) - : type (_type) - , axis (0.f,1.f,0.f) - , uv (0u) - {} - - aiTextureMapping type; - aiVector3D axis; - unsigned int uv; - - bool operator== (const MappingInfo& other) - { - return type == other.type && axis == other.axis; - } - }; -}; - -} // end of namespace Assimp - -#endif // AI_COMPUTEUVMAPPING_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.cpp b/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.cpp deleted file mode 100644 index b7cd4f0bc6..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.cpp +++ /dev/null @@ -1,414 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file MakeLeftHandedProcess.cpp - * @brief Implementation of the post processing step to convert all - * imported data to a left-handed coordinate system. - * - * Face order & UV flip are also implemented here, for the sake of a - * better location. - */ - - -#include "ConvertToLHProcess.h" -#include <assimp/scene.h> -#include <assimp/postprocess.h> -#include <assimp/DefaultLogger.hpp> - -using namespace Assimp; - -#ifndef ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS - -namespace { - -template <typename aiMeshType> -void flipUVs(aiMeshType* pMesh) { - if (pMesh == nullptr) { return; } - // mirror texture y coordinate - for (unsigned int tcIdx = 0; tcIdx < AI_MAX_NUMBER_OF_TEXTURECOORDS; tcIdx++) { - if (!pMesh->HasTextureCoords(tcIdx)) { - break; - } - - for (unsigned int vIdx = 0; vIdx < pMesh->mNumVertices; vIdx++) { - pMesh->mTextureCoords[tcIdx][vIdx].y = 1.0f - pMesh->mTextureCoords[tcIdx][vIdx].y; - } - } -} - -} // namespace - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -MakeLeftHandedProcess::MakeLeftHandedProcess() -: BaseProcess() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -MakeLeftHandedProcess::~MakeLeftHandedProcess() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool MakeLeftHandedProcess::IsActive( unsigned int pFlags) const -{ - return 0 != (pFlags & aiProcess_MakeLeftHanded); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void MakeLeftHandedProcess::Execute( aiScene* pScene) -{ - // Check for an existent root node to proceed - ai_assert(pScene->mRootNode != NULL); - ASSIMP_LOG_DEBUG("MakeLeftHandedProcess begin"); - - // recursively convert all the nodes - ProcessNode( pScene->mRootNode, aiMatrix4x4()); - - // process the meshes accordingly - for ( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) { - ProcessMesh( pScene->mMeshes[ a ] ); - } - - // process the materials accordingly - for ( unsigned int a = 0; a < pScene->mNumMaterials; ++a ) { - ProcessMaterial( pScene->mMaterials[ a ] ); - } - - // transform all animation channels as well - for( unsigned int a = 0; a < pScene->mNumAnimations; a++) - { - aiAnimation* anim = pScene->mAnimations[a]; - for( unsigned int b = 0; b < anim->mNumChannels; b++) - { - aiNodeAnim* nodeAnim = anim->mChannels[b]; - ProcessAnimation( nodeAnim); - } - } - ASSIMP_LOG_DEBUG("MakeLeftHandedProcess finished"); -} - -// ------------------------------------------------------------------------------------------------ -// Recursively converts a node, all of its children and all of its meshes -void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation) -{ - // mirror all base vectors at the local Z axis - pNode->mTransformation.c1 = -pNode->mTransformation.c1; - pNode->mTransformation.c2 = -pNode->mTransformation.c2; - pNode->mTransformation.c3 = -pNode->mTransformation.c3; - pNode->mTransformation.c4 = -pNode->mTransformation.c4; - - // now invert the Z axis again to keep the matrix determinant positive. - // The local meshes will be inverted accordingly so that the result should look just fine again. - pNode->mTransformation.a3 = -pNode->mTransformation.a3; - pNode->mTransformation.b3 = -pNode->mTransformation.b3; - pNode->mTransformation.c3 = -pNode->mTransformation.c3; - pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways... - - // continue for all children - for( size_t a = 0; a < pNode->mNumChildren; ++a ) { - ProcessNode( pNode->mChildren[ a ], pParentGlobalRotation * pNode->mTransformation ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single mesh to left handed coordinates. -void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) { - if ( nullptr == pMesh ) { - ASSIMP_LOG_ERROR( "Nullptr to mesh found." ); - return; - } - // mirror positions, normals and stuff along the Z axis - for( size_t a = 0; a < pMesh->mNumVertices; ++a) - { - pMesh->mVertices[a].z *= -1.0f; - if (pMesh->HasNormals()) { - pMesh->mNormals[a].z *= -1.0f; - } - if( pMesh->HasTangentsAndBitangents()) - { - pMesh->mTangents[a].z *= -1.0f; - pMesh->mBitangents[a].z *= -1.0f; - } - } - - // mirror anim meshes positions, normals and stuff along the Z axis - for (size_t m = 0; m < pMesh->mNumAnimMeshes; ++m) - { - for (size_t a = 0; a < pMesh->mAnimMeshes[m]->mNumVertices; ++a) - { - pMesh->mAnimMeshes[m]->mVertices[a].z *= -1.0f; - if (pMesh->mAnimMeshes[m]->HasNormals()) { - pMesh->mAnimMeshes[m]->mNormals[a].z *= -1.0f; - } - if (pMesh->mAnimMeshes[m]->HasTangentsAndBitangents()) - { - pMesh->mAnimMeshes[m]->mTangents[a].z *= -1.0f; - pMesh->mAnimMeshes[m]->mBitangents[a].z *= -1.0f; - } - } - } - - // mirror offset matrices of all bones - for( size_t a = 0; a < pMesh->mNumBones; ++a) - { - aiBone* bone = pMesh->mBones[a]; - bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3; - bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3; - bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3; - bone->mOffsetMatrix.c1 = -bone->mOffsetMatrix.c1; - bone->mOffsetMatrix.c2 = -bone->mOffsetMatrix.c2; - bone->mOffsetMatrix.c4 = -bone->mOffsetMatrix.c4; - } - - // mirror bitangents as well as they're derived from the texture coords - if( pMesh->HasTangentsAndBitangents()) - { - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) - pMesh->mBitangents[a] *= -1.0f; - } -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single material to left handed coordinates. -void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) { - if ( nullptr == _mat ) { - ASSIMP_LOG_ERROR( "Nullptr to aiMaterial found." ); - return; - } - - aiMaterial* mat = (aiMaterial*)_mat; - for (unsigned int a = 0; a < mat->mNumProperties;++a) { - aiMaterialProperty* prop = mat->mProperties[a]; - - // Mapping axis for UV mappings? - if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) { - ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */ - aiVector3D* pff = (aiVector3D*)prop->mData; - pff->z *= -1.f; - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Converts the given animation to LH coordinates. -void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim) -{ - // position keys - for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++) - pAnim->mPositionKeys[a].mValue.z *= -1.0f; - - // rotation keys - for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++) - { - /* That's the safe version, but the float errors add up. So we try the short version instead - aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix(); - rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3; - rotmat.c1 = -rotmat.c1; rotmat.c2 = -rotmat.c2; - aiQuaternion rotquat( rotmat); - pAnim->mRotationKeys[a].mValue = rotquat; - */ - pAnim->mRotationKeys[a].mValue.x *= -1.0f; - pAnim->mRotationKeys[a].mValue.y *= -1.0f; - } -} - -#endif // !! ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS -#ifndef ASSIMP_BUILD_NO_FLIPUVS_PROCESS -// # FlipUVsProcess - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FlipUVsProcess::FlipUVsProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FlipUVsProcess::~FlipUVsProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FlipUVsProcess::IsActive( unsigned int pFlags) const -{ - return 0 != (pFlags & aiProcess_FlipUVs); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FlipUVsProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("FlipUVsProcess begin"); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - ProcessMesh(pScene->mMeshes[i]); - - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) - ProcessMaterial(pScene->mMaterials[i]); - ASSIMP_LOG_DEBUG("FlipUVsProcess finished"); -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single material -void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat) -{ - aiMaterial* mat = (aiMaterial*)_mat; - for (unsigned int a = 0; a < mat->mNumProperties;++a) { - aiMaterialProperty* prop = mat->mProperties[a]; - if( !prop ) { - ASSIMP_LOG_DEBUG( "Property is null" ); - continue; - } - - // UV transformation key? - if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) { - ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); /* something is wrong with the validation if we end up here */ - aiUVTransform* uv = (aiUVTransform*)prop->mData; - - // just flip it, that's everything - uv->mTranslation.y *= -1.f; - uv->mRotation *= -1.f; - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single mesh -void FlipUVsProcess::ProcessMesh( aiMesh* pMesh) -{ - flipUVs(pMesh); - for (unsigned int idx = 0; idx < pMesh->mNumAnimMeshes; idx++) { - flipUVs(pMesh->mAnimMeshes[idx]); - } -} - -#endif // !ASSIMP_BUILD_NO_FLIPUVS_PROCESS -#ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS -// # FlipWindingOrderProcess - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FlipWindingOrderProcess::FlipWindingOrderProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FlipWindingOrderProcess::~FlipWindingOrderProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const -{ - return 0 != (pFlags & aiProcess_FlipWindingOrder); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FlipWindingOrderProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("FlipWindingOrderProcess begin"); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - ProcessMesh(pScene->mMeshes[i]); - ASSIMP_LOG_DEBUG("FlipWindingOrderProcess finished"); -} - -// ------------------------------------------------------------------------------------------------ -// Converts a single mesh -void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh) -{ - // invert the order of all faces in this mesh - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - aiFace& face = pMesh->mFaces[a]; - for (unsigned int b = 0; b < face.mNumIndices / 2; b++) { - std::swap(face.mIndices[b], face.mIndices[face.mNumIndices - 1 - b]); - } - } - - // invert the order of all components in this mesh anim meshes - for (unsigned int m = 0; m < pMesh->mNumAnimMeshes; m++) { - aiAnimMesh* animMesh = pMesh->mAnimMeshes[m]; - unsigned int numVertices = animMesh->mNumVertices; - if (animMesh->HasPositions()) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mVertices[a], animMesh->mVertices[numVertices - 1 - a]); - } - } - if (animMesh->HasNormals()) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mNormals[a], animMesh->mNormals[numVertices - 1 - a]); - } - } - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) { - if (animMesh->HasTextureCoords(i)) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mTextureCoords[i][a], animMesh->mTextureCoords[i][numVertices - 1 - a]); - } - } - } - if (animMesh->HasTangentsAndBitangents()) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mTangents[a], animMesh->mTangents[numVertices - 1 - a]); - std::swap(animMesh->mBitangents[a], animMesh->mBitangents[numVertices - 1 - a]); - } - } - for (unsigned int v = 0; v < AI_MAX_NUMBER_OF_COLOR_SETS; v++) { - if (animMesh->HasVertexColors(v)) { - for (unsigned int a = 0; a < numVertices; a++) - { - std::swap(animMesh->mColors[v][a], animMesh->mColors[v][numVertices - 1 - a]); - } - } - } - } -} - -#endif // !! ASSIMP_BUILD_NO_FLIPWINDING_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.h b/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.h deleted file mode 100644 index f32b91fc39..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ConvertToLHProcess.h +++ /dev/null @@ -1,171 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file MakeLeftHandedProcess.h - * @brief Defines a bunch of post-processing steps to handle - * coordinate system conversions. - * - * - LH to RH - * - UV origin upper-left to lower-left - * - face order cw to ccw - */ -#ifndef AI_CONVERTTOLHPROCESS_H_INC -#define AI_CONVERTTOLHPROCESS_H_INC - -#include <assimp/types.h> - -#include "Common/BaseProcess.h" - -struct aiMesh; -struct aiNodeAnim; -struct aiNode; -struct aiMaterial; - -namespace Assimp { - -// ----------------------------------------------------------------------------------- -/** @brief The MakeLeftHandedProcess converts all imported data to a left-handed - * coordinate system. - * - * This implies a mirroring of the Z axis of the coordinate system. But to keep - * transformation matrices free from reflections we shift the reflection to other - * places. We mirror the meshes and adapt the rotations. - * - * @note RH-LH and LH-RH is the same, so this class can be used for both - */ -class MakeLeftHandedProcess : public BaseProcess -{ - - -public: - MakeLeftHandedProcess(); - ~MakeLeftHandedProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - -protected: - - // ------------------------------------------------------------------- - /** Recursively converts a node and all of its children - */ - void ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation); - - // ------------------------------------------------------------------- - /** Converts a single mesh to left handed coordinates. - * This means that positions, normals and tangents are mirrored at - * the local Z axis and the order of all faces are inverted. - * @param pMesh The mesh to convert. - */ - void ProcessMesh( aiMesh* pMesh); - - // ------------------------------------------------------------------- - /** Converts a single material to left-handed coordinates - * @param pMat Material to convert - */ - void ProcessMaterial( aiMaterial* pMat); - - // ------------------------------------------------------------------- - /** Converts the given animation to LH coordinates. - * The rotation and translation keys are transformed, the scale keys - * work in local space and can therefore be left untouched. - * @param pAnim The bone animation to transform - */ - void ProcessAnimation( aiNodeAnim* pAnim); -}; - - -// --------------------------------------------------------------------------- -/** Postprocessing step to flip the face order of the imported data - */ -class FlipWindingOrderProcess : public BaseProcess -{ - friend class Importer; - -public: - /** Constructor to be privately used by Importer */ - FlipWindingOrderProcess(); - - /** Destructor, private as well */ - ~FlipWindingOrderProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - -protected: - void ProcessMesh( aiMesh* pMesh); -}; - -// --------------------------------------------------------------------------- -/** Postprocessing step to flip the UV coordinate system of the import data - */ -class FlipUVsProcess : public BaseProcess -{ - friend class Importer; - -public: - /** Constructor to be privately used by Importer */ - FlipUVsProcess(); - - /** Destructor, private as well */ - ~FlipUVsProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - -protected: - void ProcessMesh( aiMesh* pMesh); - void ProcessMaterial( aiMaterial* mat); -}; - -} // end of namespace Assimp - -#endif // AI_CONVERTTOLHPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/DeboneProcess.cpp b/thirdparty/assimp/code/PostProcessing/DeboneProcess.cpp deleted file mode 100644 index 83b8336bc9..0000000000 --- a/thirdparty/assimp/code/PostProcessing/DeboneProcess.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/// @file DeboneProcess.cpp -/** Implementation of the DeboneProcess post processing step */ - - - -// internal headers of the post-processing framework -#include "ProcessHelper.h" -#include "DeboneProcess.h" -#include <stdio.h> - - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -DeboneProcess::DeboneProcess() -{ - mNumBones = 0; - mNumBonesCanDoWithout = 0; - - mThreshold = AI_DEBONE_THRESHOLD; - mAllOrNone = false; -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -DeboneProcess::~DeboneProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool DeboneProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_Debone) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void DeboneProcess::SetupProperties(const Importer* pImp) -{ - // get the current value of the property - mAllOrNone = pImp->GetPropertyInteger(AI_CONFIG_PP_DB_ALL_OR_NONE,0)?true:false; - mThreshold = pImp->GetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD,AI_DEBONE_THRESHOLD); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void DeboneProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("DeboneProcess begin"); - - if(!pScene->mNumMeshes) { - return; - } - - std::vector<bool> splitList(pScene->mNumMeshes); - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - splitList[a] = ConsiderMesh( pScene->mMeshes[a] ); - } - - int numSplits = 0; - - if(!!mNumBonesCanDoWithout && (!mAllOrNone||mNumBonesCanDoWithout==mNumBones)) { - for(unsigned int a = 0; a < pScene->mNumMeshes; a++) { - if(splitList[a]) { - numSplits++; - } - } - } - - if(numSplits) { - // we need to do something. Let's go. - //mSubMeshIndices.clear(); // really needed? - mSubMeshIndices.resize(pScene->mNumMeshes); // because we're doing it here anyway - - // build a new array of meshes for the scene - std::vector<aiMesh*> meshes; - - for(unsigned int a=0;a<pScene->mNumMeshes;a++) - { - aiMesh* srcMesh = pScene->mMeshes[a]; - - std::vector<std::pair<aiMesh*,const aiBone*> > newMeshes; - - if(splitList[a]) { - SplitMesh(srcMesh,newMeshes); - } - - // mesh was split - if(!newMeshes.empty()) { - unsigned int out = 0, in = srcMesh->mNumBones; - - // store new meshes and indices of the new meshes - for(unsigned int b=0;b<newMeshes.size();b++) { - const aiString *find = newMeshes[b].second?&newMeshes[b].second->mName:0; - - aiNode *theNode = find?pScene->mRootNode->FindNode(*find):0; - std::pair<unsigned int,aiNode*> push_pair(static_cast<unsigned int>(meshes.size()),theNode); - - mSubMeshIndices[a].push_back(push_pair); - meshes.push_back(newMeshes[b].first); - - out+=newMeshes[b].first->mNumBones; - } - - if(!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F("Removed %u bones. Input bones:", in - out, ". Output bones: ", out); - } - - // and destroy the source mesh. It should be completely contained inside the new submeshes - delete srcMesh; - } - else { - // Mesh is kept unchanged - store it's new place in the mesh array - mSubMeshIndices[a].push_back(std::pair<unsigned int,aiNode*>(static_cast<unsigned int>(meshes.size()),(aiNode*)0)); - meshes.push_back(srcMesh); - } - } - - // rebuild the scene's mesh array - pScene->mNumMeshes = static_cast<unsigned int>(meshes.size()); - delete [] pScene->mMeshes; - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - std::copy( meshes.begin(), meshes.end(), pScene->mMeshes); - - // recurse through all nodes and translate the node's mesh indices to fit the new mesh array - UpdateNode( pScene->mRootNode); - } - - ASSIMP_LOG_DEBUG("DeboneProcess end"); -} - -// ------------------------------------------------------------------------------------------------ -// Counts bones total/removable in a given mesh. -bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh) -{ - if(!pMesh->HasBones()) { - return false; - } - - bool split = false; - - //interstitial faces not permitted - bool isInterstitialRequired = false; - - std::vector<bool> isBoneNecessary(pMesh->mNumBones,false); - std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX); - - const unsigned int cUnowned = UINT_MAX; - const unsigned int cCoowned = UINT_MAX-1; - - for(unsigned int i=0;i<pMesh->mNumBones;i++) { - for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) { - float w = pMesh->mBones[i]->mWeights[j].mWeight; - - if(w==0.0f) { - continue; - } - - unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId; - if(w>=mThreshold) { - - if(vertexBones[vid]!=cUnowned) { - if(vertexBones[vid]==i) //double entry - { - ASSIMP_LOG_WARN("Encountered double entry in bone weights"); - } - else //TODO: track attraction in order to break tie - { - vertexBones[vid] = cCoowned; - } - } - else vertexBones[vid] = i; - } - - if(!isBoneNecessary[i]) { - isBoneNecessary[i] = w<mThreshold; - } - } - - if(!isBoneNecessary[i]) { - isInterstitialRequired = true; - } - } - - if(isInterstitialRequired) { - for(unsigned int i=0;i<pMesh->mNumFaces;i++) { - unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]]; - - for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) { - unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]]; - - if(v!=w) { - if(v<pMesh->mNumBones) isBoneNecessary[v] = true; - if(w<pMesh->mNumBones) isBoneNecessary[w] = true; - } - } - } - } - - for(unsigned int i=0;i<pMesh->mNumBones;i++) { - if(!isBoneNecessary[i]) { - mNumBonesCanDoWithout++; - split = true; - } - - mNumBones++; - } - return split; -} - -// ------------------------------------------------------------------------------------------------ -// Splits the given mesh by bone count. -void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const -{ - // same deal here as ConsiderMesh basically - - std::vector<bool> isBoneNecessary(pMesh->mNumBones,false); - std::vector<unsigned int> vertexBones(pMesh->mNumVertices,UINT_MAX); - - const unsigned int cUnowned = UINT_MAX; - const unsigned int cCoowned = UINT_MAX-1; - - for(unsigned int i=0;i<pMesh->mNumBones;i++) { - for(unsigned int j=0;j<pMesh->mBones[i]->mNumWeights;j++) { - float w = pMesh->mBones[i]->mWeights[j].mWeight; - - if(w==0.0f) { - continue; - } - - unsigned int vid = pMesh->mBones[i]->mWeights[j].mVertexId; - - if(w>=mThreshold) { - if(vertexBones[vid]!=cUnowned) { - if(vertexBones[vid]==i) //double entry - { - ASSIMP_LOG_WARN("Encountered double entry in bone weights"); - } - else //TODO: track attraction in order to break tie - { - vertexBones[vid] = cCoowned; - } - } - else vertexBones[vid] = i; - } - - if(!isBoneNecessary[i]) { - isBoneNecessary[i] = w<mThreshold; - } - } - } - - unsigned int nFacesUnowned = 0; - - std::vector<unsigned int> faceBones(pMesh->mNumFaces,UINT_MAX); - std::vector<unsigned int> facesPerBone(pMesh->mNumBones,0); - - for(unsigned int i=0;i<pMesh->mNumFaces;i++) { - unsigned int nInterstitial = 1; - - unsigned int v = vertexBones[pMesh->mFaces[i].mIndices[0]]; - - for(unsigned int j=1;j<pMesh->mFaces[i].mNumIndices;j++) { - unsigned int w = vertexBones[pMesh->mFaces[i].mIndices[j]]; - - if(v!=w) { - if(v<pMesh->mNumBones) isBoneNecessary[v] = true; - if(w<pMesh->mNumBones) isBoneNecessary[w] = true; - } - else nInterstitial++; - } - - if(v<pMesh->mNumBones &&nInterstitial==pMesh->mFaces[i].mNumIndices) { - faceBones[i] = v; //primitive belongs to bone #v - facesPerBone[v]++; - } - else nFacesUnowned++; - } - - // invalidate any "cojoined" faces - for(unsigned int i=0;i<pMesh->mNumFaces;i++) { - if(faceBones[i]<pMesh->mNumBones&&isBoneNecessary[faceBones[i]]) - { - ai_assert(facesPerBone[faceBones[i]]>0); - facesPerBone[faceBones[i]]--; - - nFacesUnowned++; - faceBones[i] = cUnowned; - } - } - - if(nFacesUnowned) { - std::vector<unsigned int> subFaces; - - for(unsigned int i=0;i<pMesh->mNumFaces;i++) { - if(faceBones[i]==cUnowned) { - subFaces.push_back(i); - } - } - - aiMesh *baseMesh = MakeSubmesh(pMesh,subFaces,0); - std::pair<aiMesh*,const aiBone*> push_pair(baseMesh,(const aiBone*)0); - - poNewMeshes.push_back(push_pair); - } - - for(unsigned int i=0;i<pMesh->mNumBones;i++) { - - if(!isBoneNecessary[i]&&facesPerBone[i]>0) { - std::vector<unsigned int> subFaces; - - for(unsigned int j=0;j<pMesh->mNumFaces;j++) { - if(faceBones[j]==i) { - subFaces.push_back(j); - } - } - - unsigned int f = AI_SUBMESH_FLAGS_SANS_BONES; - aiMesh *subMesh =MakeSubmesh(pMesh,subFaces,f); - - //Lifted from PretransformVertices.cpp - ApplyTransform(subMesh,pMesh->mBones[i]->mOffsetMatrix); - std::pair<aiMesh*,const aiBone*> push_pair(subMesh,pMesh->mBones[i]); - - poNewMeshes.push_back(push_pair); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Recursively updates the node's mesh list to account for the changed mesh list -void DeboneProcess::UpdateNode(aiNode* pNode) const -{ - // rebuild the node's mesh index list - - std::vector<unsigned int> newMeshList; - - // this will require two passes - - unsigned int m = static_cast<unsigned int>(pNode->mNumMeshes), n = static_cast<unsigned int>(mSubMeshIndices.size()); - - // first pass, look for meshes which have not moved - - for(unsigned int a=0;a<m;a++) { - - unsigned int srcIndex = pNode->mMeshes[a]; - const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[srcIndex]; - unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size()); - - for(unsigned int b=0;b<nSubmeshes;b++) { - if(!subMeshes[b].second) { - newMeshList.push_back(subMeshes[b].first); - } - } - } - - // second pass, collect deboned meshes - - for(unsigned int a=0;a<n;a++) - { - const std::vector< std::pair< unsigned int,aiNode* > > &subMeshes = mSubMeshIndices[a]; - unsigned int nSubmeshes = static_cast<unsigned int>(subMeshes.size()); - - for(unsigned int b=0;b<nSubmeshes;b++) { - if(subMeshes[b].second == pNode) { - newMeshList.push_back(subMeshes[b].first); - } - } - } - - if( pNode->mNumMeshes > 0 ) { - delete [] pNode->mMeshes; pNode->mMeshes = NULL; - } - - pNode->mNumMeshes = static_cast<unsigned int>(newMeshList.size()); - - if(pNode->mNumMeshes) { - pNode->mMeshes = new unsigned int[pNode->mNumMeshes]; - std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes); - } - - // do that also recursively for all children - for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) { - UpdateNode( pNode->mChildren[a]); - } -} - -// ------------------------------------------------------------------------------------------------ -// Apply the node transformation to a mesh -void DeboneProcess::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const -{ - // Check whether we need to transform the coordinates at all - if (!mat.IsIdentity()) { - - if (mesh->HasPositions()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mVertices[i] = mat * mesh->mVertices[i]; - } - } - if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { - aiMatrix4x4 mWorldIT = mat; - mWorldIT.Inverse().Transpose(); - - // TODO: implement Inverse() for aiMatrix3x3 - aiMatrix3x3 m = aiMatrix3x3(mWorldIT); - - if (mesh->HasNormals()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize(); - } - } - if (mesh->HasTangentsAndBitangents()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize(); - mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize(); - } - } - } - } -} diff --git a/thirdparty/assimp/code/PostProcessing/DeboneProcess.h b/thirdparty/assimp/code/PostProcessing/DeboneProcess.h deleted file mode 100644 index 8b64c2acc6..0000000000 --- a/thirdparty/assimp/code/PostProcessing/DeboneProcess.h +++ /dev/null @@ -1,131 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** Defines a post processing step to limit the number of bones affecting a single vertex. */ -#ifndef AI_DEBONEPROCESS_H_INC -#define AI_DEBONEPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include <assimp/mesh.h> -#include <assimp/scene.h> - -#include <vector> -#include <utility> - -#// Forward declarations -class DeboneTest; - -namespace Assimp { - -#if (!defined AI_DEBONE_THRESHOLD) -# define AI_DEBONE_THRESHOLD 1.0f -#endif // !! AI_DEBONE_THRESHOLD - -// --------------------------------------------------------------------------- -/** This post processing step removes bones nearly losslessly or according to -* a configured threshold. In order to remove the bone, the primitives affected by -* the bone are split from the mesh. The split off (new) mesh is boneless. At any -* point in time, bones without affect upon a given mesh are to be removed. -*/ -class DeboneProcess : public BaseProcess { -public: - DeboneProcess(); - ~DeboneProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. - * A bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); - -protected: - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Counts bones total/removable in a given mesh. - * @param pMesh The mesh to process. - */ - bool ConsiderMesh( const aiMesh* pMesh); - - /// Splits the given mesh by bone count. - /// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split. - /// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary. - void SplitMesh(const aiMesh* pMesh, std::vector< std::pair< aiMesh*,const aiBone* > >& poNewMeshes) const; - - /// Recursively updates the node's mesh list to account for the changed mesh list - void UpdateNode(aiNode* pNode) const; - - // ------------------------------------------------------------------- - // Apply transformation to a mesh - void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat)const; - -public: - /** Number of bones present in the scene. */ - unsigned int mNumBones; - unsigned int mNumBonesCanDoWithout; - - float mThreshold; - bool mAllOrNone; - - /// Per mesh index: Array of indices of the new submeshes. - std::vector< std::vector< std::pair< unsigned int,aiNode* > > > mSubMeshIndices; -}; - -} // end of namespace Assimp - -#endif // AI_DEBONEPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp b/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp deleted file mode 100644 index b11615bb82..0000000000 --- a/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the post processing step to drop face -* normals for all imported faces. -*/ - - -#include "DropFaceNormalsProcess.h" -#include <assimp/postprocess.h> -#include <assimp/scene.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/Exceptional.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -DropFaceNormalsProcess::DropFaceNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -DropFaceNormalsProcess::~DropFaceNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool DropFaceNormalsProcess::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_DropNormals) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void DropFaceNormalsProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("DropFaceNormalsProcess begin"); - - if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { - throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); - } - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - bHas |= this->DropMeshFaceNormals( pScene->mMeshes[a]); - } - if (bHas) { - ASSIMP_LOG_INFO("DropFaceNormalsProcess finished. " - "Face normals have been removed"); - } else { - ASSIMP_LOG_DEBUG("DropFaceNormalsProcess finished. " - "No normals were present"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool DropFaceNormalsProcess::DropMeshFaceNormals (aiMesh* pMesh) { - if (NULL == pMesh->mNormals) { - return false; - } - - delete[] pMesh->mNormals; - pMesh->mNormals = nullptr; - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.h b/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.h deleted file mode 100644 index c710c5a5ee..0000000000 --- a/thirdparty/assimp/code/PostProcessing/DropFaceNormalsProcess.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to compute face normals for all loaded faces*/ -#ifndef AI_DROPFACENORMALPROCESS_H_INC -#define AI_DROPFACENORMALPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include <assimp/mesh.h> - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The DropFaceNormalsProcess computes face normals for all faces of all meshes -*/ -class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess { -public: - DropFaceNormalsProcess(); - ~DropFaceNormalsProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - -private: - bool DropMeshFaceNormals(aiMesh* pcMesh); -}; - -} // end of namespace Assimp - -#endif // !!AI_DROPFACENORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.cpp b/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.cpp deleted file mode 100644 index 739382a057..0000000000 --- a/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -#include "EmbedTexturesProcess.h" -#include <assimp/ParsingUtils.h> -#include "ProcessHelper.h" - -#include <fstream> - -using namespace Assimp; - -EmbedTexturesProcess::EmbedTexturesProcess() -: BaseProcess() { -} - -EmbedTexturesProcess::~EmbedTexturesProcess() { -} - -bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const { - return (pFlags & aiProcess_EmbedTextures) != 0; -} - -void EmbedTexturesProcess::SetupProperties(const Importer* pImp) { - mRootPath = pImp->GetPropertyString("sourceFilePath"); - mRootPath = mRootPath.substr(0, mRootPath.find_last_of("\\/") + 1u); -} - -void EmbedTexturesProcess::Execute(aiScene* pScene) { - if (pScene == nullptr || pScene->mRootNode == nullptr) return; - - aiString path; - - uint32_t embeddedTexturesCount = 0u; - - for (auto matId = 0u; matId < pScene->mNumMaterials; ++matId) { - auto material = pScene->mMaterials[matId]; - - for (auto ttId = 1u; ttId < AI_TEXTURE_TYPE_MAX; ++ttId) { - auto tt = static_cast<aiTextureType>(ttId); - auto texturesCount = material->GetTextureCount(tt); - - for (auto texId = 0u; texId < texturesCount; ++texId) { - material->GetTexture(tt, texId, &path); - if (path.data[0] == '*') continue; // Already embedded - - // Indeed embed - if (addTexture(pScene, path.data)) { - auto embeddedTextureId = pScene->mNumTextures - 1u; - ::ai_snprintf(path.data, 1024, "*%u", embeddedTextureId); - material->AddProperty(&path, AI_MATKEY_TEXTURE(tt, texId)); - embeddedTexturesCount++; - } - } - } - } - - ASSIMP_LOG_INFO_F("EmbedTexturesProcess finished. Embedded ", embeddedTexturesCount, " textures." ); -} - -bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const { - std::streampos imageSize = 0; - std::string imagePath = path; - - // Test path directly - std::ifstream file(imagePath, std::ios::binary | std::ios::ate); - if ((imageSize = file.tellg()) == std::streampos(-1)) { - ASSIMP_LOG_WARN_F("EmbedTexturesProcess: Cannot find image: ", imagePath, ". Will try to find it in root folder."); - - // Test path in root path - imagePath = mRootPath + path; - file.open(imagePath, std::ios::binary | std::ios::ate); - if ((imageSize = file.tellg()) == std::streampos(-1)) { - // Test path basename in root path - imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u); - file.open(imagePath, std::ios::binary | std::ios::ate); - if ((imageSize = file.tellg()) == std::streampos(-1)) { - ASSIMP_LOG_ERROR_F("EmbedTexturesProcess: Unable to embed texture: ", path, "."); - return false; - } - } - } - - aiTexel* imageContent = new aiTexel[ 1ul + static_cast<unsigned long>( imageSize ) / sizeof(aiTexel)]; - file.seekg(0, std::ios::beg); - file.read(reinterpret_cast<char*>(imageContent), imageSize); - - // Enlarging the textures table - unsigned int textureId = pScene->mNumTextures++; - auto oldTextures = pScene->mTextures; - pScene->mTextures = new aiTexture*[pScene->mNumTextures]; - ::memmove(pScene->mTextures, oldTextures, sizeof(aiTexture*) * (pScene->mNumTextures - 1u)); - - // Add the new texture - auto pTexture = new aiTexture; - pTexture->mHeight = 0; // Means that this is still compressed - pTexture->mWidth = static_cast<uint32_t>(imageSize); - pTexture->pcData = imageContent; - - auto extension = path.substr(path.find_last_of('.') + 1u); - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - if (extension == "jpeg") { - extension = "jpg"; - } - - size_t len = extension.size(); - if (len > HINTMAXTEXTURELEN -1 ) { - len = HINTMAXTEXTURELEN - 1; - } - ::strncpy(pTexture->achFormatHint, extension.c_str(), len); - pScene->mTextures[textureId] = pTexture; - - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.h b/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.h deleted file mode 100644 index 3c4b2eab4e..0000000000 --- a/thirdparty/assimp/code/PostProcessing/EmbedTexturesProcess.h +++ /dev/null @@ -1,85 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -#pragma once - -#include "Common/BaseProcess.h" - -#include <string> - -struct aiNode; - -namespace Assimp { - -/** - * Force embedding of textures (using the path = "*1" convention). - * If a texture's file does not exist at the specified path - * (due, for instance, to an absolute path generated on another system), - * it will check if a file with the same name exists at the root folder - * of the imported model. And if so, it uses that. - */ -class ASSIMP_API EmbedTexturesProcess : public BaseProcess { -public: - /// The default class constructor. - EmbedTexturesProcess(); - - /// The class destructor. - virtual ~EmbedTexturesProcess(); - - /// Overwritten, @see BaseProcess - virtual bool IsActive(unsigned int pFlags) const; - - /// Overwritten, @see BaseProcess - virtual void SetupProperties(const Importer* pImp); - - /// Overwritten, @see BaseProcess - virtual void Execute(aiScene* pScene); - -private: - // Resolve the path and add the file content to the scene as a texture. - bool addTexture(aiScene* pScene, std::string path) const; - -private: - std::string mRootPath; -}; - -} // namespace Assimp diff --git a/thirdparty/assimp/code/PostProcessing/FindDegenerates.cpp b/thirdparty/assimp/code/PostProcessing/FindDegenerates.cpp deleted file mode 100644 index 50fac46dba..0000000000 --- a/thirdparty/assimp/code/PostProcessing/FindDegenerates.cpp +++ /dev/null @@ -1,301 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file FindDegenerates.cpp - * @brief Implementation of the FindDegenerates post-process step. -*/ - - - -// internal headers -#include "ProcessHelper.h" -#include "FindDegenerates.h" -#include <assimp/Exceptional.h> - -using namespace Assimp; - -//remove mesh at position 'index' from the scene -static void removeMesh(aiScene* pScene, unsigned const index); -//correct node indices to meshes and remove references to deleted mesh -static void updateSceneGraph(aiNode* pNode, unsigned const index); - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FindDegeneratesProcess::FindDegeneratesProcess() -: mConfigRemoveDegenerates( false ) -, mConfigCheckAreaOfTriangle( false ){ - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FindDegeneratesProcess::~FindDegeneratesProcess() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FindDegeneratesProcess::IsActive( unsigned int pFlags) const { - return 0 != (pFlags & aiProcess_FindDegenerates); -} - -// ------------------------------------------------------------------------------------------------ -// Setup import configuration -void FindDegeneratesProcess::SetupProperties(const Importer* pImp) { - // Get the current value of AI_CONFIG_PP_FD_REMOVE - mConfigRemoveDegenerates = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_REMOVE,0)); - mConfigCheckAreaOfTriangle = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_PP_FD_CHECKAREA) ); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FindDegeneratesProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin"); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { - //Do not process point cloud, ExecuteOnMesh works only with faces data - if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) { - removeMesh(pScene, i); - --i; //the current i is removed, do not skip the next one - } - } - ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished"); -} - -static void removeMesh(aiScene* pScene, unsigned const index) { - //we start at index and copy the pointers one position forward - //save the mesh pointer to delete it later - auto delete_me = pScene->mMeshes[index]; - for (unsigned i = index; i < pScene->mNumMeshes - 1; ++i) { - pScene->mMeshes[i] = pScene->mMeshes[i+1]; - } - pScene->mMeshes[pScene->mNumMeshes - 1] = nullptr; - --(pScene->mNumMeshes); - delete delete_me; - - //removing a mesh also requires updating all references to it in the scene graph - updateSceneGraph(pScene->mRootNode, index); -} - -static void updateSceneGraph(aiNode* pNode, unsigned const index) { - for (unsigned i = 0; i < pNode->mNumMeshes; ++i) { - if (pNode->mMeshes[i] > index) { - --(pNode->mMeshes[i]); - continue; - } - if (pNode->mMeshes[i] == index) { - for (unsigned j = i; j < pNode->mNumMeshes -1; ++j) { - pNode->mMeshes[j] = pNode->mMeshes[j+1]; - } - --(pNode->mNumMeshes); - --i; - continue; - } - } - //recurse to all children - for (unsigned i = 0; i < pNode->mNumChildren; ++i) { - updateSceneGraph(pNode->mChildren[i], index); - } -} - -static ai_real heron( ai_real a, ai_real b, ai_real c ) { - ai_real s = (a + b + c) / 2; - ai_real area = pow((s * ( s - a ) * ( s - b ) * ( s - c ) ), (ai_real)0.5 ); - return area; -} - -static ai_real distance3D( const aiVector3D &vA, aiVector3D &vB ) { - const ai_real lx = ( vB.x - vA.x ); - const ai_real ly = ( vB.y - vA.y ); - const ai_real lz = ( vB.z - vA.z ); - ai_real a = lx*lx + ly*ly + lz*lz; - ai_real d = pow( a, (ai_real)0.5 ); - - return d; -} - -static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) { - ai_real area = 0; - - aiVector3D vA( mesh->mVertices[ face.mIndices[ 0 ] ] ); - aiVector3D vB( mesh->mVertices[ face.mIndices[ 1 ] ] ); - aiVector3D vC( mesh->mVertices[ face.mIndices[ 2 ] ] ); - - ai_real a( distance3D( vA, vB ) ); - ai_real b( distance3D( vB, vC ) ); - ai_real c( distance3D( vC, vA ) ); - area = heron( a, b, c ); - - return area; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported mesh -bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { - mesh->mPrimitiveTypes = 0; - - std::vector<bool> remove_me; - if (mConfigRemoveDegenerates) { - remove_me.resize( mesh->mNumFaces, false ); - } - - unsigned int deg = 0, limit; - for ( unsigned int a = 0; a < mesh->mNumFaces; ++a ) { - aiFace& face = mesh->mFaces[a]; - bool first = true; - - // check whether the face contains degenerated entries - for (unsigned int i = 0; i < face.mNumIndices; ++i) { - // Polygons with more than 4 points are allowed to have double points, that is - // simulating polygons with holes just with concave polygons. However, - // double points may not come directly after another. - limit = face.mNumIndices; - if (face.mNumIndices > 4) { - limit = std::min( limit, i+2 ); - } - - for (unsigned int t = i+1; t < limit; ++t) { - if (mesh->mVertices[face.mIndices[ i ] ] == mesh->mVertices[ face.mIndices[ t ] ]) { - // we have found a matching vertex position - // remove the corresponding index from the array - --face.mNumIndices; - --limit; - for (unsigned int m = t; m < face.mNumIndices; ++m) { - face.mIndices[ m ] = face.mIndices[ m+1 ]; - } - --t; - - // NOTE: we set the removed vertex index to an unique value - // to make sure the developer gets notified when his - // application attempts to access this data. - face.mIndices[ face.mNumIndices ] = 0xdeadbeef; - - if(first) { - ++deg; - first = false; - } - - if ( mConfigRemoveDegenerates ) { - remove_me[ a ] = true; - goto evil_jump_outside; // hrhrhrh ... yeah, this rocks baby! - } - } - } - - if ( mConfigCheckAreaOfTriangle ) { - if ( face.mNumIndices == 3 ) { - ai_real area = calculateAreaOfTriangle( face, mesh ); - if ( area < 1e-6 ) { - if ( mConfigRemoveDegenerates ) { - remove_me[ a ] = true; - ++deg; - goto evil_jump_outside; - } - - // todo: check for index which is corrupt. - } - } - } - } - - // We need to update the primitive flags array of the mesh. - switch (face.mNumIndices) - { - case 1u: - mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2u: - mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3u: - mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - }; -evil_jump_outside: - continue; - } - - // If AI_CONFIG_PP_FD_REMOVE is true, remove degenerated faces from the import - if (mConfigRemoveDegenerates && deg) { - unsigned int n = 0; - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) - { - aiFace& face_src = mesh->mFaces[a]; - if (!remove_me[a]) { - aiFace& face_dest = mesh->mFaces[n++]; - - // Do a manual copy, keep the index array - face_dest.mNumIndices = face_src.mNumIndices; - face_dest.mIndices = face_src.mIndices; - - if (&face_src != &face_dest) { - // clear source - face_src.mNumIndices = 0; - face_src.mIndices = nullptr; - } - } - else { - // Otherwise delete it if we don't need this face - delete[] face_src.mIndices; - face_src.mIndices = nullptr; - face_src.mNumIndices = 0; - } - } - // Just leave the rest of the array unreferenced, we don't care for now - mesh->mNumFaces = n; - if (!mesh->mNumFaces) { - //The whole mesh consists of degenerated faces - //signal upward, that this mesh should be deleted. - ASSIMP_LOG_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives"); - return true; - } - } - - if (deg && !DefaultLogger::isNullLogger()) { - ASSIMP_LOG_WARN_F( "Found ", deg, " degenerated primitives"); - } - return false; -} diff --git a/thirdparty/assimp/code/PostProcessing/FindDegenerates.h b/thirdparty/assimp/code/PostProcessing/FindDegenerates.h deleted file mode 100644 index 7a15e77cf1..0000000000 --- a/thirdparty/assimp/code/PostProcessing/FindDegenerates.h +++ /dev/null @@ -1,130 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to search all meshes for - degenerated faces */ -#ifndef AI_FINDDEGENERATESPROCESS_H_INC -#define AI_FINDDEGENERATESPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include <assimp/mesh.h> - -class FindDegeneratesProcessTest; -namespace Assimp { - - -// --------------------------------------------------------------------------- -/** FindDegeneratesProcess: Searches a mesh for degenerated triangles. -*/ -class ASSIMP_API FindDegeneratesProcess : public BaseProcess { -public: - FindDegeneratesProcess(); - ~FindDegeneratesProcess(); - - // ------------------------------------------------------------------- - // Check whether step is active - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Execute step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - // Execute step on a given mesh - ///@returns true if the current mesh should be deleted, false otherwise - bool ExecuteOnMesh( aiMesh* mesh); - - // ------------------------------------------------------------------- - /// @brief Enable the instant removal of degenerated primitives - /// @param enabled true for enabled. - void EnableInstantRemoval(bool enabled); - - // ------------------------------------------------------------------- - /// @brief Check whether instant removal is currently enabled - /// @return The instant removal state. - bool IsInstantRemoval() const; - - // ------------------------------------------------------------------- - /// @brief Enable the area check for triangles. - /// @param enabled true for enabled. - void EnableAreaCheck( bool enabled ); - - // ------------------------------------------------------------------- - /// @brief Check whether the area check is enabled. - /// @return The area check state. - bool isAreaCheckEnabled() const; - -private: - //! Configuration option: remove degenerates faces immediately - bool mConfigRemoveDegenerates; - //! Configuration option: check for area - bool mConfigCheckAreaOfTriangle; -}; - -inline -void FindDegeneratesProcess::EnableInstantRemoval(bool enabled) { - mConfigRemoveDegenerates = enabled; -} - -inline -bool FindDegeneratesProcess::IsInstantRemoval() const { - return mConfigRemoveDegenerates; -} - -inline -void FindDegeneratesProcess::EnableAreaCheck( bool enabled ) { - mConfigCheckAreaOfTriangle = enabled; -} - -inline -bool FindDegeneratesProcess::isAreaCheckEnabled() const { - return mConfigCheckAreaOfTriangle; -} - -} // Namespace Assimp - -#endif // !! AI_FINDDEGENERATESPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.cpp b/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.cpp deleted file mode 100644 index 64907458a1..0000000000 --- a/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file FindInstancesProcess.cpp - * @brief Implementation of the aiProcess_FindInstances postprocessing step -*/ - - -#include "FindInstancesProcess.h" -#include <memory> -#include <stdio.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FindInstancesProcess::FindInstancesProcess() -: configSpeedFlag (false) -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FindInstancesProcess::~FindInstancesProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FindInstancesProcess::IsActive( unsigned int pFlags) const -{ - // FindInstances makes absolutely no sense together with PreTransformVertices - // fixme: spawn error message somewhere else? - return 0 != (pFlags & aiProcess_FindInstances) && 0 == (pFlags & aiProcess_PreTransformVertices); -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties for the step -void FindInstancesProcess::SetupProperties(const Importer* pImp) -{ - // AI_CONFIG_FAVOUR_SPEED - configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0)); -} - -// ------------------------------------------------------------------------------------------------ -// Compare the bones of two meshes -bool CompareBones(const aiMesh* orig, const aiMesh* inst) -{ - for (unsigned int i = 0; i < orig->mNumBones;++i) { - aiBone* aha = orig->mBones[i]; - aiBone* oha = inst->mBones[i]; - - if (aha->mNumWeights != oha->mNumWeights || - aha->mOffsetMatrix != oha->mOffsetMatrix) { - return false; - } - - // compare weight per weight --- - for (unsigned int n = 0; n < aha->mNumWeights;++n) { - if (aha->mWeights[n].mVertexId != oha->mWeights[n].mVertexId || - (aha->mWeights[n].mWeight - oha->mWeights[n].mWeight) < 10e-3f) { - return false; - } - } - } - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Update mesh indices in the node graph -void UpdateMeshIndices(aiNode* node, unsigned int* lookup) -{ - for (unsigned int n = 0; n < node->mNumMeshes;++n) - node->mMeshes[n] = lookup[node->mMeshes[n]]; - - for (unsigned int n = 0; n < node->mNumChildren;++n) - UpdateMeshIndices(node->mChildren[n],lookup); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FindInstancesProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("FindInstancesProcess begin"); - if (pScene->mNumMeshes) { - - // use a pseudo hash for all meshes in the scene to quickly find - // the ones which are possibly equal. This step is executed early - // in the pipeline, so we could, depending on the file format, - // have several thousand small meshes. That's too much for a brute - // everyone-against-everyone check involving up to 10 comparisons - // each. - std::unique_ptr<uint64_t[]> hashes (new uint64_t[pScene->mNumMeshes]); - std::unique_ptr<unsigned int[]> remapping (new unsigned int[pScene->mNumMeshes]); - - unsigned int numMeshesOut = 0; - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - - aiMesh* inst = pScene->mMeshes[i]; - hashes[i] = GetMeshHash(inst); - - // Find an appropriate epsilon - // to compare position differences against - float epsilon = ComputePositionEpsilon(inst); - epsilon *= epsilon; - - for (int a = i-1; a >= 0; --a) { - if (hashes[i] == hashes[a]) - { - aiMesh* orig = pScene->mMeshes[a]; - if (!orig) - continue; - - // check for hash collision .. we needn't check - // the vertex format, it *must* match due to the - // (brilliant) construction of the hash - if (orig->mNumBones != inst->mNumBones || - orig->mNumFaces != inst->mNumFaces || - orig->mNumVertices != inst->mNumVertices || - orig->mMaterialIndex != inst->mMaterialIndex || - orig->mPrimitiveTypes != inst->mPrimitiveTypes) - continue; - - // up to now the meshes are equal. Now compare vertex positions, normals, - // tangents and bitangents using this epsilon. - if (orig->HasPositions()) { - if(!CompareArrays(orig->mVertices,inst->mVertices,orig->mNumVertices,epsilon)) - continue; - } - if (orig->HasNormals()) { - if(!CompareArrays(orig->mNormals,inst->mNormals,orig->mNumVertices,epsilon)) - continue; - } - if (orig->HasTangentsAndBitangents()) { - if (!CompareArrays(orig->mTangents,inst->mTangents,orig->mNumVertices,epsilon) || - !CompareArrays(orig->mBitangents,inst->mBitangents,orig->mNumVertices,epsilon)) - continue; - } - - // use a constant epsilon for colors and UV coordinates - static const float uvEpsilon = 10e-4f; - { - unsigned int j, end = orig->GetNumUVChannels(); - for(j = 0; j < end; ++j) { - if (!orig->mTextureCoords[j]) { - continue; - } - if(!CompareArrays(orig->mTextureCoords[j],inst->mTextureCoords[j],orig->mNumVertices,uvEpsilon)) { - break; - } - } - if (j != end) { - continue; - } - } - { - unsigned int j, end = orig->GetNumColorChannels(); - for(j = 0; j < end; ++j) { - if (!orig->mColors[j]) { - continue; - } - if(!CompareArrays(orig->mColors[j],inst->mColors[j],orig->mNumVertices,uvEpsilon)) { - break; - } - } - if (j != end) { - continue; - } - } - - // These two checks are actually quite expensive and almost *never* required. - // Almost. That's why they're still here. But there's no reason to do them - // in speed-targeted imports. - if (!configSpeedFlag) { - - // It seems to be strange, but we really need to check whether the - // bones are identical too. Although it's extremely unprobable - // that they're not if control reaches here, we need to deal - // with unprobable cases, too. It could still be that there are - // equal shapes which are deformed differently. - if (!CompareBones(orig,inst)) - continue; - - // For completeness ... compare even the index buffers for equality - // face order & winding order doesn't care. Input data is in verbose format. - std::unique_ptr<unsigned int[]> ftbl_orig(new unsigned int[orig->mNumVertices]); - std::unique_ptr<unsigned int[]> ftbl_inst(new unsigned int[orig->mNumVertices]); - - for (unsigned int tt = 0; tt < orig->mNumFaces;++tt) { - aiFace& f = orig->mFaces[tt]; - for (unsigned int nn = 0; nn < f.mNumIndices;++nn) - ftbl_orig[f.mIndices[nn]] = tt; - - aiFace& f2 = inst->mFaces[tt]; - for (unsigned int nn = 0; nn < f2.mNumIndices;++nn) - ftbl_inst[f2.mIndices[nn]] = tt; - } - if (0 != ::memcmp(ftbl_inst.get(),ftbl_orig.get(),orig->mNumVertices*sizeof(unsigned int))) - continue; - } - - // We're still here. Or in other words: 'inst' is an instance of 'orig'. - // Place a marker in our list that we can easily update mesh indices. - remapping[i] = remapping[a]; - - // Delete the instanced mesh, we don't need it anymore - delete inst; - pScene->mMeshes[i] = NULL; - break; - } - } - - // If we didn't find a match for the current mesh: keep it - if (pScene->mMeshes[i]) { - remapping[i] = numMeshesOut++; - } - } - ai_assert(0 != numMeshesOut); - if (numMeshesOut != pScene->mNumMeshes) { - - // Collapse the meshes array by removing all NULL entries - for (unsigned int real = 0, i = 0; real < numMeshesOut; ++i) { - if (pScene->mMeshes[i]) - pScene->mMeshes[real++] = pScene->mMeshes[i]; - } - - // And update the node graph with our nice lookup table - UpdateMeshIndices(pScene->mRootNode,remapping.get()); - - // write to log - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F( "FindInstancesProcess finished. Found ", (pScene->mNumMeshes - numMeshesOut), " instances" ); - } - pScene->mNumMeshes = numMeshesOut; - } else { - ASSIMP_LOG_DEBUG("FindInstancesProcess finished. No instanced meshes found"); - } - } -} diff --git a/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.h b/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.h deleted file mode 100644 index 64b838d7cc..0000000000 --- a/thirdparty/assimp/code/PostProcessing/FindInstancesProcess.h +++ /dev/null @@ -1,137 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FindInstancesProcess.h - * @brief Declares the aiProcess_FindInstances post-process step - */ -#ifndef AI_FINDINSTANCES_H_INC -#define AI_FINDINSTANCES_H_INC - -#include "Common/BaseProcess.h" -#include "PostProcessing/ProcessHelper.h" - -class FindInstancesProcessTest; -namespace Assimp { - -// ------------------------------------------------------------------------------- -/** @brief Get a pseudo(!)-hash representing a mesh. - * - * The hash is built from number of vertices, faces, primitive types, - * .... but *not* from the real mesh data. The funcction is not a perfect hash. - * @param in Input mesh - * @return Hash. - */ -inline -uint64_t GetMeshHash(aiMesh* in) { - ai_assert(nullptr != in); - - // ... get an unique value representing the vertex format of the mesh - const unsigned int fhash = GetMeshVFormatUnique(in); - - // and bake it with number of vertices/faces/bones/matidx/ptypes - return ((uint64_t)fhash << 32u) | (( - (in->mNumBones << 16u) ^ (in->mNumVertices) ^ - (in->mNumFaces<<4u) ^ (in->mMaterialIndex<<15) ^ - (in->mPrimitiveTypes<<28)) & 0xffffffff ); -} - -// ------------------------------------------------------------------------------- -/** @brief Perform a component-wise comparison of two arrays - * - * @param first First array - * @param second Second array - * @param size Size of both arrays - * @param e Epsilon - * @return true if the arrays are identical - */ -inline -bool CompareArrays(const aiVector3D* first, const aiVector3D* second, - unsigned int size, float e) { - for (const aiVector3D* end = first+size; first != end; ++first,++second) { - if ( (*first - *second).SquareLength() >= e) - return false; - } - return true; -} - -// and the same for colors ... -inline bool CompareArrays(const aiColor4D* first, const aiColor4D* second, - unsigned int size, float e) -{ - for (const aiColor4D* end = first+size; first != end; ++first,++second) { - if ( GetColorDifference(*first,*second) >= e) - return false; - } - return true; -} - -// --------------------------------------------------------------------------- -/** @brief A post-processing steps to search for instanced meshes -*/ -class FindInstancesProcess : public BaseProcess -{ -public: - - FindInstancesProcess(); - ~FindInstancesProcess(); - -public: - // ------------------------------------------------------------------- - // Check whether step is active in given flags combination - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Execute step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Setup properties prior to executing the process - void SetupProperties(const Importer* pImp); - -private: - - bool configSpeedFlag; - -}; // ! end class FindInstancesProcess -} // ! end namespace Assimp - -#endif // !! AI_FINDINSTANCES_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.cpp b/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.cpp deleted file mode 100644 index 016884c6e7..0000000000 --- a/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.cpp +++ /dev/null @@ -1,423 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to search an importer's output - for data that is obviously invalid */ - - - -#ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS - -// internal headers -#include "FindInvalidDataProcess.h" -#include "ProcessHelper.h" - -#include <assimp/Exceptional.h> -#include <assimp/qnan.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FindInvalidDataProcess::FindInvalidDataProcess() -: configEpsilon(0.0) -, mIgnoreTexCoods( false ){ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FindInvalidDataProcess::~FindInvalidDataProcess() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const { - return 0 != (pFlags & aiProcess_FindInvalidData); -} - -// ------------------------------------------------------------------------------------------------ -// Setup import configuration -void FindInvalidDataProcess::SetupProperties(const Importer* pImp) { - // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY - configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY,0.f)); - mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false); -} - -// ------------------------------------------------------------------------------------------------ -// Update mesh references in the node graph -void UpdateMeshReferences(aiNode* node, const std::vector<unsigned int>& meshMapping) { - if (node->mNumMeshes) { - unsigned int out = 0; - for (unsigned int a = 0; a < node->mNumMeshes;++a) { - - unsigned int ref = node->mMeshes[a]; - if (UINT_MAX != (ref = meshMapping[ref])) { - node->mMeshes[out++] = ref; - } - } - // just let the members that are unused, that's much cheaper - // than a full array realloc'n'copy party ... - if(!(node->mNumMeshes = out)) { - - delete[] node->mMeshes; - node->mMeshes = NULL; - } - } - // recursively update all children - for (unsigned int i = 0; i < node->mNumChildren;++i) { - UpdateMeshReferences(node->mChildren[i],meshMapping); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FindInvalidDataProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin"); - - bool out = false; - std::vector<unsigned int> meshMapping(pScene->mNumMeshes); - unsigned int real = 0; - - // Process meshes - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - - int result; - if ((result = ProcessMesh( pScene->mMeshes[a]))) { - out = true; - - if (2 == result) { - // remove this mesh - delete pScene->mMeshes[a]; - AI_DEBUG_INVALIDATE_PTR(pScene->mMeshes[a]); - - meshMapping[a] = UINT_MAX; - continue; - } - } - pScene->mMeshes[real] = pScene->mMeshes[a]; - meshMapping[a] = real++; - } - - // Process animations - for (unsigned int a = 0; a < pScene->mNumAnimations;++a) { - ProcessAnimation( pScene->mAnimations[a]); - } - - - if (out) { - if ( real != pScene->mNumMeshes) { - if (!real) { - throw DeadlyImportError("No meshes remaining"); - } - - // we need to remove some meshes. - // therefore we'll also need to remove all references - // to them from the scenegraph - UpdateMeshReferences(pScene->mRootNode,meshMapping); - pScene->mNumMeshes = real; - } - - ASSIMP_LOG_INFO("FindInvalidDataProcess finished. Found issues ..."); - } else { - ASSIMP_LOG_DEBUG("FindInvalidDataProcess finished. Everything seems to be OK."); - } -} - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline -const char* ValidateArrayContents(const T* /*arr*/, unsigned int /*size*/, - const std::vector<bool>& /*dirtyMask*/, bool /*mayBeIdentical = false*/, bool /*mayBeZero = true*/) -{ - return nullptr; -} - -// ------------------------------------------------------------------------------------------------ -template <> -inline -const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsigned int size, - const std::vector<bool>& dirtyMask, bool mayBeIdentical , bool mayBeZero ) { - bool b = false; - unsigned int cnt = 0; - for (unsigned int i = 0; i < size;++i) { - - if (dirtyMask.size() && dirtyMask[i]) { - continue; - } - ++cnt; - - const aiVector3D& v = arr[i]; - if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) { - return "INF/NAN was found in a vector component"; - } - if (!mayBeZero && !v.x && !v.y && !v.z ) { - return "Found zero-length vector"; - } - if (i && v != arr[i-1])b = true; - } - if (cnt > 1 && !b && !mayBeIdentical) { - return "All vectors are identical"; - } - return nullptr; -} - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline -bool ProcessArray(T*& in, unsigned int num,const char* name, - const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) { - const char* err = ValidateArrayContents(in,num,dirtyMask,mayBeIdentical,mayBeZero); - if (err) { - ASSIMP_LOG_ERROR_F( "FindInvalidDataProcess fails on mesh ", name, ": ", err); - delete[] in; - in = NULL; - return true; - } - return false; -} - -// ------------------------------------------------------------------------------------------------ -template <typename T> -AI_FORCE_INLINE bool EpsilonCompare(const T& n, const T& s, ai_real epsilon); - -// ------------------------------------------------------------------------------------------------ -AI_FORCE_INLINE bool EpsilonCompare(ai_real n, ai_real s, ai_real epsilon) { - return std::fabs(n-s)>epsilon; -} - -// ------------------------------------------------------------------------------------------------ -template <> -bool EpsilonCompare<aiVectorKey>(const aiVectorKey& n, const aiVectorKey& s, ai_real epsilon) { - return - EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) && - EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) && - EpsilonCompare(n.mValue.z,s.mValue.z,epsilon); -} - -// ------------------------------------------------------------------------------------------------ -template <> -bool EpsilonCompare<aiQuatKey>(const aiQuatKey& n, const aiQuatKey& s, ai_real epsilon) { - return - EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) && - EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) && - EpsilonCompare(n.mValue.z,s.mValue.z,epsilon) && - EpsilonCompare(n.mValue.w,s.mValue.w,epsilon); -} - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline -bool AllIdentical(T* in, unsigned int num, ai_real epsilon) { - if (num <= 1) { - return true; - } - - if (fabs(epsilon) > 0.f) { - for (unsigned int i = 0; i < num-1;++i) { - if (!EpsilonCompare(in[i],in[i+1],epsilon)) { - return false; - } - } - } else { - for (unsigned int i = 0; i < num-1;++i) { - if (in[i] != in[i+1]) { - return false; - } - } - } - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Search an animation for invalid content -void FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim) { - // Process all animation channels - for ( unsigned int a = 0; a < anim->mNumChannels; ++a ) { - ProcessAnimationChannel( anim->mChannels[a]); - } -} - -// ------------------------------------------------------------------------------------------------ -void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) { - ai_assert( nullptr != anim ); - if (anim->mNumPositionKeys == 0 && anim->mNumRotationKeys == 0 && anim->mNumScalingKeys == 0) { - ai_assert_entry(); - return; - } - - // Check whether all values in a tracks are identical - in this case - // we can remove al keys except one. - // POSITIONS - int i = 0; - if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys,configEpsilon)) { - aiVectorKey v = anim->mPositionKeys[0]; - - // Reallocate ... we need just ONE element, it makes no sense to reuse the array - delete[] anim->mPositionKeys; - anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys = 1]; - anim->mPositionKeys[0] = v; - i = 1; - } - - // ROTATIONS - if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys,configEpsilon)) { - aiQuatKey v = anim->mRotationKeys[0]; - - // Reallocate ... we need just ONE element, it makes no sense to reuse the array - delete[] anim->mRotationKeys; - anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys = 1]; - anim->mRotationKeys[0] = v; - i = 1; - } - - // SCALINGS - if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys,configEpsilon)) { - aiVectorKey v = anim->mScalingKeys[0]; - - // Reallocate ... we need just ONE element, it makes no sense to reuse the array - delete[] anim->mScalingKeys; - anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys = 1]; - anim->mScalingKeys[0] = v; - i = 1; - } - if ( 1 == i ) { - ASSIMP_LOG_WARN("Simplified dummy tracks with just one key"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Search a mesh for invalid contents -int FindInvalidDataProcess::ProcessMesh(aiMesh* pMesh) -{ - bool ret = false; - std::vector<bool> dirtyMask(pMesh->mNumVertices, pMesh->mNumFaces != 0); - - // Ignore elements that are not referenced by vertices. - // (they are, for example, caused by the FindDegenerates step) - for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) { - const aiFace& f = pMesh->mFaces[m]; - - for (unsigned int i = 0; i < f.mNumIndices; ++i) { - dirtyMask[f.mIndices[i]] = false; - } - } - - // Process vertex positions - if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) { - ASSIMP_LOG_ERROR("Deleting mesh: Unable to continue without vertex positions"); - - return 2; - } - - // process texture coordinates - if (!mIgnoreTexCoods) { - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) { - if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) { - pMesh->mNumUVComponents[i] = 0; - - // delete all subsequent texture coordinate sets. - for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { - delete[] pMesh->mTextureCoords[a]; - pMesh->mTextureCoords[a] = NULL; - pMesh->mNumUVComponents[a] = 0; - } - - ret = true; - } - } - } - - // -- we don't validate vertex colors, it's difficult to say whether - // they are invalid or not. - - // Normals and tangents are undefined for point and line faces. - if (pMesh->mNormals || pMesh->mTangents) { - - if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes || - aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) - { - if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes || - aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) - { - // We need to update the lookup-table - for (unsigned int m = 0; m < pMesh->mNumFaces;++m) { - const aiFace& f = pMesh->mFaces[ m ]; - - if (f.mNumIndices < 3) { - dirtyMask[f.mIndices[0]] = true; - if (f.mNumIndices == 2) { - dirtyMask[f.mIndices[1]] = true; - } - } - } - } - // Normals, tangents and bitangents are undefined for - // the whole mesh (and should not even be there) - else { - return ret; - } - } - - // Process mesh normals - if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices, - "normals",dirtyMask,true,false)) - ret = true; - - // Process mesh tangents - if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,"tangents",dirtyMask)) { - delete[] pMesh->mBitangents; pMesh->mBitangents = NULL; - ret = true; - } - - // Process mesh bitangents - if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,"bitangents",dirtyMask)) { - delete[] pMesh->mTangents; pMesh->mTangents = NULL; - ret = true; - } - } - return ret ? 1 : 0; -} - -#endif // !! ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.h b/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.h deleted file mode 100644 index ce7375f34f..0000000000 --- a/thirdparty/assimp/code/PostProcessing/FindInvalidDataProcess.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to search an importer's output - * for data that is obviously invalid - */ -#ifndef AI_FINDINVALIDDATA_H_INC -#define AI_FINDINVALIDDATA_H_INC - -#include "Common/BaseProcess.h" - -#include <assimp/types.h> -#include <assimp/anim.h> - -struct aiMesh; - -class FindInvalidDataProcessTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The FindInvalidData post-processing step. It searches the mesh data - * for parts that are obviously invalid and removes them. - * - * Originally this was a workaround for some models written by Blender - * which have zero normal vectors. */ -class ASSIMP_API FindInvalidDataProcess : public BaseProcess { -public: - FindInvalidDataProcess(); - ~FindInvalidDataProcess(); - - // ------------------------------------------------------------------- - // - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - // Run the step - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Executes the post-processing step on the given mesh - * @param pMesh The mesh to process. - * @return 0 - nothing, 1 - removed sth, 2 - please delete me */ - int ProcessMesh( aiMesh* pMesh); - - // ------------------------------------------------------------------- - /** Executes the post-processing step on the given animation - * @param anim The animation to process. */ - void ProcessAnimation (aiAnimation* anim); - - // ------------------------------------------------------------------- - /** Executes the post-processing step on the given anim channel - * @param anim The animation channel to process.*/ - void ProcessAnimationChannel (aiNodeAnim* anim); - -private: - ai_real configEpsilon; - bool mIgnoreTexCoods; -}; - -} // end of namespace Assimp - -#endif // AI_AI_FINDINVALIDDATA_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/FixNormalsStep.cpp b/thirdparty/assimp/code/PostProcessing/FixNormalsStep.cpp deleted file mode 100644 index bbbe6899b4..0000000000 --- a/thirdparty/assimp/code/PostProcessing/FixNormalsStep.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the post processing step to invert - * all normals in meshes with infacing normals. - */ - -// internal headers -#include "FixNormalsStep.h" -#include <assimp/StringUtils.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/postprocess.h> -#include <assimp/scene.h> -#include <stdio.h> - - -using namespace Assimp; - - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -FixInfacingNormalsProcess::FixInfacingNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -FixInfacingNormalsProcess::~FixInfacingNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_FixInfacingNormals) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void FixInfacingNormalsProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess begin"); - - bool bHas( false ); - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - if (ProcessMesh(pScene->mMeshes[a], a)) { - bHas = true; - } - } - - if (bHas) { - ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess finished. Found issues."); - } else { - ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess finished. No changes to the scene."); - } -} - -// ------------------------------------------------------------------------------------------------ -// Apply the step to the mesh -bool FixInfacingNormalsProcess::ProcessMesh( aiMesh* pcMesh, unsigned int index) -{ - ai_assert(nullptr != pcMesh); - - // Nothing to do if there are no model normals - if (!pcMesh->HasNormals()) { - return false; - } - - // Compute the bounding box of both the model vertices + normals and - // the unmodified model vertices. Then check whether the first BB - // is smaller than the second. In this case we can assume that the - // normals need to be flipped, although there are a few special cases .. - // convex, concave, planar models ... - - aiVector3D vMin0 (1e10f,1e10f,1e10f); - aiVector3D vMin1 (1e10f,1e10f,1e10f); - aiVector3D vMax0 (-1e10f,-1e10f,-1e10f); - aiVector3D vMax1 (-1e10f,-1e10f,-1e10f); - - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) - { - vMin1.x = std::min(vMin1.x,pcMesh->mVertices[i].x); - vMin1.y = std::min(vMin1.y,pcMesh->mVertices[i].y); - vMin1.z = std::min(vMin1.z,pcMesh->mVertices[i].z); - - vMax1.x = std::max(vMax1.x,pcMesh->mVertices[i].x); - vMax1.y = std::max(vMax1.y,pcMesh->mVertices[i].y); - vMax1.z = std::max(vMax1.z,pcMesh->mVertices[i].z); - - const aiVector3D vWithNormal = pcMesh->mVertices[i] + pcMesh->mNormals[i]; - - vMin0.x = std::min(vMin0.x,vWithNormal.x); - vMin0.y = std::min(vMin0.y,vWithNormal.y); - vMin0.z = std::min(vMin0.z,vWithNormal.z); - - vMax0.x = std::max(vMax0.x,vWithNormal.x); - vMax0.y = std::max(vMax0.y,vWithNormal.y); - vMax0.z = std::max(vMax0.z,vWithNormal.z); - } - - const float fDelta0_x = (vMax0.x - vMin0.x); - const float fDelta0_y = (vMax0.y - vMin0.y); - const float fDelta0_z = (vMax0.z - vMin0.z); - - const float fDelta1_x = (vMax1.x - vMin1.x); - const float fDelta1_y = (vMax1.y - vMin1.y); - const float fDelta1_z = (vMax1.z - vMin1.z); - - // Check whether the boxes are overlapping - if ((fDelta0_x > 0.0f) != (fDelta1_x > 0.0f))return false; - if ((fDelta0_y > 0.0f) != (fDelta1_y > 0.0f))return false; - if ((fDelta0_z > 0.0f) != (fDelta1_z > 0.0f))return false; - - // Check whether this is a planar surface - const float fDelta1_yz = fDelta1_y * fDelta1_z; - - if (fDelta1_x < 0.05f * std::sqrt( fDelta1_yz ))return false; - if (fDelta1_y < 0.05f * std::sqrt( fDelta1_z * fDelta1_x ))return false; - if (fDelta1_z < 0.05f * std::sqrt( fDelta1_y * fDelta1_x ))return false; - - // now compare the volumes of the bounding boxes - if (std::fabs(fDelta0_x * fDelta0_y * fDelta0_z) < std::fabs(fDelta1_x * fDelta1_yz)) { - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F("Mesh ", index, ": Normals are facing inwards (or the mesh is planar)", index); - } - - // Invert normals - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) - pcMesh->mNormals[i] *= -1.0f; - - // ... and flip faces - for (unsigned int i = 0; i < pcMesh->mNumFaces;++i) - { - aiFace& face = pcMesh->mFaces[i]; - for( unsigned int b = 0; b < face.mNumIndices / 2; b++) - std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]); - } - return true; - } - return false; -} diff --git a/thirdparty/assimp/code/PostProcessing/FixNormalsStep.h b/thirdparty/assimp/code/PostProcessing/FixNormalsStep.h deleted file mode 100644 index f60ce596a4..0000000000 --- a/thirdparty/assimp/code/PostProcessing/FixNormalsStep.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - - -/** @file Defines a post processing step to fix infacing normals */ -#ifndef AI_FIXNORMALSPROCESS_H_INC -#define AI_FIXNORMALSPROCESS_H_INC - -#include "Common/BaseProcess.h" - -struct aiMesh; - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The FixInfacingNormalsProcess tries to determine whether the normal - * vectors of an object are facing inwards. In this case they will be - * flipped. - */ -class FixInfacingNormalsProcess : public BaseProcess { -public: - FixInfacingNormalsProcess(); - ~FixInfacingNormalsProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - -protected: - - // ------------------------------------------------------------------- - /** Executes the step on the given mesh - * @param pMesh The mesh to process. - */ - bool ProcessMesh( aiMesh* pMesh, unsigned int index); -}; - -} // end of namespace Assimp - -#endif // AI_FIXNORMALSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp b/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp deleted file mode 100644 index c013454fc3..0000000000 --- a/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -#ifndef ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS - -#include "PostProcessing/GenBoundingBoxesProcess.h" - -#include <assimp/postprocess.h> -#include <assimp/scene.h> - -namespace Assimp { - -GenBoundingBoxesProcess::GenBoundingBoxesProcess() -: BaseProcess() { - -} - -GenBoundingBoxesProcess::~GenBoundingBoxesProcess() { - // empty -} - -bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const { - return 0 != ( pFlags & aiProcess_GenBoundingBoxes ); -} - -void checkMesh(aiMesh* mesh, aiVector3D& min, aiVector3D& max) { - ai_assert(nullptr != mesh); - - if (0 == mesh->mNumVertices) { - return; - } - - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - const aiVector3D &pos = mesh->mVertices[i]; - if (pos.x < min.x) { - min.x = pos.x; - } - if (pos.y < min.y) { - min.y = pos.y; - } - if (pos.z < min.z) { - min.z = pos.z; - } - - if (pos.x > max.x) { - max.x = pos.x; - } - if (pos.y > max.y) { - max.y = pos.y; - } - if (pos.z > max.z) { - max.z = pos.z; - } - } -} - -void GenBoundingBoxesProcess::Execute(aiScene* pScene) { - if (nullptr == pScene) { - return; - } - - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - aiMesh* mesh = pScene->mMeshes[i]; - if (nullptr == mesh) { - continue; - } - - aiVector3D min(999999, 999999, 999999), max(-999999, -999999, -999999); - checkMesh(mesh, min, max); - mesh->mAABB.mMin = min; - mesh->mAABB.mMax = max; - } -} - -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.h b/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.h deleted file mode 100644 index 4b43c82a42..0000000000 --- a/thirdparty/assimp/code/PostProcessing/GenBoundingBoxesProcess.h +++ /dev/null @@ -1,76 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Defines a post-processing step to generate Axis-aligned bounding - * volumes for all meshes. - */ - -#pragma once - -#ifndef AI_GENBOUNDINGBOXESPROCESS_H_INC -#define AI_GENBOUNDINGBOXESPROCESS_H_INC - -#ifndef ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS - -#include "Common/BaseProcess.h" - -namespace Assimp { - -/** Post-processing process to find axis-aligned bounding volumes for amm meshes - * used in a scene - */ -class ASSIMP_API GenBoundingBoxesProcess : public BaseProcess { -public: - /// The class constructor. - GenBoundingBoxesProcess(); - /// The class destructor. - ~GenBoundingBoxesProcess(); - /// Will return true, if aiProcess_GenBoundingBoxes is defined. - bool IsActive(unsigned int pFlags) const override; - /// The execution callback. - void Execute(aiScene* pScene) override; -}; - -} // Namespace Assimp - -#endif // #ifndef ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS - -#endif // AI_GENBOUNDINGBOXESPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp b/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp deleted file mode 100644 index 028334dec7..0000000000 --- a/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the post processing step to generate face -* normals for all imported faces. -*/ - - -#include "GenFaceNormalsProcess.h" -#include <assimp/postprocess.h> -#include <assimp/scene.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/Exceptional.h> -#include <assimp/qnan.h> - - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -GenFaceNormalsProcess::GenFaceNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -GenFaceNormalsProcess::~GenFaceNormalsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool GenFaceNormalsProcess::IsActive( unsigned int pFlags) const { - force_ = (pFlags & aiProcess_ForceGenNormals) != 0; - return (pFlags & aiProcess_GenNormals) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void GenFaceNormalsProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("GenFaceNormalsProcess begin"); - - if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { - throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); - } - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - if(this->GenMeshFaceNormals( pScene->mMeshes[a])) { - bHas = true; - } - } - if (bHas) { - ASSIMP_LOG_INFO("GenFaceNormalsProcess finished. " - "Face normals have been calculated"); - } else { - ASSIMP_LOG_DEBUG("GenFaceNormalsProcess finished. " - "Normals are already there"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh) -{ - if (NULL != pMesh->mNormals) { - if (force_) delete[] pMesh->mNormals; - else return false; - } - - // If the mesh consists of lines and/or points but not of - // triangles or higher-order polygons the normal vectors - // are undefined. - if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) { - ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes"); - return false; - } - - // allocate an array to hold the output normals - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - const float qnan = get_qnan(); - - // iterate through all faces and compute per-face normals but store them per-vertex. - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { - const aiFace& face = pMesh->mFaces[a]; - if (face.mNumIndices < 3) { - // either a point or a line -> no well-defined normal vector - for (unsigned int i = 0;i < face.mNumIndices;++i) { - pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan); - } - continue; - } - - const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; - const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; - const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]]; - const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe(); - - for (unsigned int i = 0;i < face.mNumIndices;++i) { - pMesh->mNormals[face.mIndices[i]] = vNor; - } - } - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.h b/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.h deleted file mode 100644 index c641fd6353..0000000000 --- a/thirdparty/assimp/code/PostProcessing/GenFaceNormalsProcess.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to compute face normals for all loaded faces*/ -#ifndef AI_GENFACENORMALPROCESS_H_INC -#define AI_GENFACENORMALPROCESS_H_INC - -#include "Common/BaseProcess.h" -#include <assimp/mesh.h> - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The GenFaceNormalsProcess computes face normals for all faces of all meshes -*/ -class ASSIMP_API_WINONLY GenFaceNormalsProcess : public BaseProcess -{ -public: - - GenFaceNormalsProcess(); - ~GenFaceNormalsProcess(); - -public: - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - -private: - bool GenMeshFaceNormals(aiMesh* pcMesh); - mutable bool force_ = false; -}; - -} // end of namespace Assimp - -#endif // !!AI_GENFACENORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp b/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp deleted file mode 100644 index 3f6c2f86bd..0000000000 --- a/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the post processing step to generate face -* normals for all imported faces. -*/ - - - -// internal headers -#include "GenVertexNormalsProcess.h" -#include "ProcessHelper.h" -#include <assimp/Exceptional.h> -#include <assimp/qnan.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -GenVertexNormalsProcess::GenVertexNormalsProcess() -: configMaxAngle( AI_DEG_TO_RAD( 175.f ) ) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -GenVertexNormalsProcess::~GenVertexNormalsProcess() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const -{ - force_ = (pFlags & aiProcess_ForceGenNormals) != 0; - return (pFlags & aiProcess_GenSmoothNormals) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void GenVertexNormalsProcess::SetupProperties(const Importer* pImp) -{ - // Get the current value of the AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE property - configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,(ai_real)175.0); - configMaxAngle = AI_DEG_TO_RAD(std::max(std::min(configMaxAngle,(ai_real)175.0),(ai_real)0.0)); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void GenVertexNormalsProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("GenVertexNormalsProcess begin"); - - if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { - throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); - } - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - if(GenMeshVertexNormals( pScene->mMeshes[a],a)) - bHas = true; - } - - if (bHas) { - ASSIMP_LOG_INFO("GenVertexNormalsProcess finished. " - "Vertex normals have been calculated"); - } else { - ASSIMP_LOG_DEBUG("GenVertexNormalsProcess finished. " - "Normals are already there"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex) -{ - if (NULL != pMesh->mNormals) { - if (force_) delete[] pMesh->mNormals; - else return false; - } - - // If the mesh consists of lines and/or points but not of - // triangles or higher-order polygons the normal vectors - // are undefined. - if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) - { - ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes"); - return false; - } - - // Allocate the array to hold the output normals - const float qnan = std::numeric_limits<ai_real>::quiet_NaN(); - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - - // Compute per-face normals but store them per-vertex - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - const aiFace& face = pMesh->mFaces[a]; - if (face.mNumIndices < 3) - { - // either a point or a line -> no normal vector - for (unsigned int i = 0;i < face.mNumIndices;++i) { - pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan); - } - - continue; - } - - const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; - const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; - const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]]; - const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe(); - - for (unsigned int i = 0;i < face.mNumIndices;++i) { - pMesh->mNormals[face.mIndices[i]] = vNor; - } - } - - // Set up a SpatialSort to quickly find all vertices close to a given position - // check whether we can reuse the SpatialSort of a previous step. - SpatialSort* vertexFinder = NULL; - SpatialSort _vertexFinder; - ai_real posEpsilon = ai_real( 1e-5 ); - if (shared) { - std::vector<std::pair<SpatialSort,ai_real> >* avf; - shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); - if (avf) - { - std::pair<SpatialSort,ai_real>& blubb = avf->operator [] (meshIndex); - vertexFinder = &blubb.first; - posEpsilon = blubb.second; - } - } - if (!vertexFinder) { - _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); - vertexFinder = &_vertexFinder; - posEpsilon = ComputePositionEpsilon(pMesh); - } - std::vector<unsigned int> verticesFound; - aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices]; - - if (configMaxAngle >= AI_DEG_TO_RAD( 175.f )) { - // There is no angle limit. Thus all vertices with positions close - // to each other will receive the same vertex normal. This allows us - // to optimize the whole algorithm a little bit ... - std::vector<bool> abHad(pMesh->mNumVertices,false); - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { - if (abHad[i]) { - continue; - } - - // Get all vertices that share this one ... - vertexFinder->FindPositions( pMesh->mVertices[i], posEpsilon, verticesFound); - - aiVector3D pcNor; - for (unsigned int a = 0; a < verticesFound.size(); ++a) { - const aiVector3D& v = pMesh->mNormals[verticesFound[a]]; - if (is_not_qnan(v.x))pcNor += v; - } - pcNor.NormalizeSafe(); - - // Write the smoothed normal back to all affected normals - for (unsigned int a = 0; a < verticesFound.size(); ++a) - { - unsigned int vidx = verticesFound[a]; - pcNew[vidx] = pcNor; - abHad[vidx] = true; - } - } - } - // Slower code path if a smooth angle is set. There are many ways to achieve - // the effect, this one is the most straightforward one. - else { - const ai_real fLimit = std::cos(configMaxAngle); - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { - // Get all vertices that share this one ... - vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound); - - aiVector3D vr = pMesh->mNormals[i]; - - aiVector3D pcNor; - for (unsigned int a = 0; a < verticesFound.size(); ++a) { - aiVector3D v = pMesh->mNormals[verticesFound[a]]; - - // Check whether the angle between the two normals is not too large. - // Skip the angle check on our own normal to avoid false negatives - // (v*v is not guaranteed to be 1.0 for all unit vectors v) - if (is_not_qnan(v.x) && (verticesFound[a] == i || (v * vr >= fLimit))) - pcNor += v; - } - pcNew[i] = pcNor.NormalizeSafe(); - } - } - - delete[] pMesh->mNormals; - pMesh->mNormals = pcNew; - - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.h b/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.h deleted file mode 100644 index 2ceee17e85..0000000000 --- a/thirdparty/assimp/code/PostProcessing/GenVertexNormalsProcess.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to compute vertex normals - for all loaded vertizes */ -#ifndef AI_GENVERTEXNORMALPROCESS_H_INC -#define AI_GENVERTEXNORMALPROCESS_H_INC - -#include "Common/assbin_chunks.h" -#include "Common/BaseProcess.h" - -#include <assimp/mesh.h> - -// Forward declarations -class GenNormalsTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The GenFaceNormalsProcess computes vertex normals for all vertices -*/ -class ASSIMP_API GenVertexNormalsProcess : public BaseProcess { -public: - GenVertexNormalsProcess(); - ~GenVertexNormalsProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. - * A bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - - // setter for configMaxAngle - inline void SetMaxSmoothAngle(ai_real f) { - configMaxAngle =f; - } - - // ------------------------------------------------------------------- - /** Computes normals for a specific mesh - * @param pcMesh Mesh - * @param meshIndex Index of the mesh - * @return true if vertex normals have been computed - */ - bool GenMeshVertexNormals (aiMesh* pcMesh, unsigned int meshIndex); - -private: - /** Configuration option: maximum smoothing angle, in radians*/ - ai_real configMaxAngle; - mutable bool force_ = false; -}; - -} // end of namespace Assimp - -#endif // !!AI_GENVERTEXNORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.cpp b/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.cpp deleted file mode 100644 index d0a016fa42..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the post processing step to improve the cache locality of a mesh. - * <br> - * The algorithm is roughly basing on this paper: - * http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf - * .. although overdraw reduction isn't implemented yet ... - */ - -// internal headers -#include "PostProcessing/ImproveCacheLocality.h" -#include "Common/VertexTriangleAdjacency.h" - -#include <assimp/StringUtils.h> -#include <assimp/postprocess.h> -#include <assimp/scene.h> -#include <assimp/DefaultLogger.hpp> -#include <stdio.h> -#include <stack> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() -: mConfigCacheDepth(PP_ICL_PTCACHE_SIZE) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -ImproveCacheLocalityProcess::~ImproveCacheLocalityProcess() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_ImproveCacheLocality) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Setup configuration -void ImproveCacheLocalityProcess::SetupProperties(const Importer* pImp) { - // AI_CONFIG_PP_ICL_PTCACHE_SIZE controls the target cache size for the optimizer - mConfigCacheDepth = pImp->GetPropertyInteger(AI_CONFIG_PP_ICL_PTCACHE_SIZE,PP_ICL_PTCACHE_SIZE); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void ImproveCacheLocalityProcess::Execute( aiScene* pScene) { - if (!pScene->mNumMeshes) { - ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess skipped; there are no meshes"); - return; - } - - ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess begin"); - - float out = 0.f; - unsigned int numf = 0, numm = 0; - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a ){ - const float res = ProcessMesh( pScene->mMeshes[a],a); - if (res) { - numf += pScene->mMeshes[a]->mNumFaces; - out += res; - ++numm; - } - } - if (!DefaultLogger::isNullLogger()) { - if (numf > 0) { - ASSIMP_LOG_INFO_F("Cache relevant are ", numm, " meshes (", numf, " faces). Average output ACMR is ", out / numf); - } - ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess finished. "); - } -} - -// ------------------------------------------------------------------------------------------------ -// Improves the cache coherency of a specific mesh -ai_real ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshNum) { - // TODO: rewrite this to use std::vector or boost::shared_array - ai_assert(nullptr != pMesh); - - // Check whether the input data is valid - // - there must be vertices and faces - // - all faces must be triangulated or we can't operate on them - if (!pMesh->HasFaces() || !pMesh->HasPositions()) - return static_cast<ai_real>(0.f); - - if (pMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) { - ASSIMP_LOG_ERROR("This algorithm works on triangle meshes only"); - return static_cast<ai_real>(0.f); - } - - if(pMesh->mNumVertices <= mConfigCacheDepth) { - return static_cast<ai_real>(0.f); - } - - ai_real fACMR = 3.f; - const aiFace* const pcEnd = pMesh->mFaces+pMesh->mNumFaces; - - // Input ACMR is for logging purposes only - if (!DefaultLogger::isNullLogger()) { - - unsigned int* piFIFOStack = new unsigned int[mConfigCacheDepth]; - memset(piFIFOStack,0xff,mConfigCacheDepth*sizeof(unsigned int)); - unsigned int* piCur = piFIFOStack; - const unsigned int* const piCurEnd = piFIFOStack + mConfigCacheDepth; - - // count the number of cache misses - unsigned int iCacheMisses = 0; - for (const aiFace* pcFace = pMesh->mFaces;pcFace != pcEnd;++pcFace) { - for (unsigned int qq = 0; qq < 3;++qq) { - bool bInCache = false; - for (unsigned int* pp = piFIFOStack;pp < piCurEnd;++pp) { - if (*pp == pcFace->mIndices[qq]) { - // the vertex is in cache - bInCache = true; - break; - } - } - if (!bInCache) { - ++iCacheMisses; - if (piCurEnd == piCur) { - piCur = piFIFOStack; - } - *piCur++ = pcFace->mIndices[qq]; - } - } - } - delete[] piFIFOStack; - fACMR = (ai_real) iCacheMisses / pMesh->mNumFaces; - if (3.0 == fACMR) { - char szBuff[128]; // should be sufficiently large in every case - - // the JoinIdenticalVertices process has not been executed on this - // mesh, otherwise this value would normally be at least minimally - // smaller than 3.0 ... - ai_snprintf(szBuff,128,"Mesh %u: Not suitable for vcache optimization",meshNum); - ASSIMP_LOG_WARN(szBuff); - return static_cast<ai_real>(0.f); - } - } - - // first we need to build a vertex-triangle adjacency list - VertexTriangleAdjacency adj(pMesh->mFaces,pMesh->mNumFaces, pMesh->mNumVertices,true); - - // build a list to store per-vertex caching time stamps - unsigned int* const piCachingStamps = new unsigned int[pMesh->mNumVertices]; - memset(piCachingStamps,0x0,pMesh->mNumVertices*sizeof(unsigned int)); - - // allocate an empty output index buffer. We store the output indices in one large array. - // Since the number of triangles won't change the input faces can be reused. This is how - // we save thousands of redundant mini allocations for aiFace::mIndices - const unsigned int iIdxCnt = pMesh->mNumFaces*3; - unsigned int* const piIBOutput = new unsigned int[iIdxCnt]; - unsigned int* piCSIter = piIBOutput; - - // allocate the flag array to hold the information - // whether a face has already been emitted or not - std::vector<bool> abEmitted(pMesh->mNumFaces,false); - - // dead-end vertex index stack - std::stack<unsigned int, std::vector<unsigned int> > sDeadEndVStack; - - // create a copy of the piNumTriPtr buffer - unsigned int* const piNumTriPtr = adj.mLiveTriangles; - const std::vector<unsigned int> piNumTriPtrNoModify(piNumTriPtr, piNumTriPtr + pMesh->mNumVertices); - - // get the largest number of referenced triangles and allocate the "candidate buffer" - unsigned int iMaxRefTris = 0; { - const unsigned int* piCur = adj.mLiveTriangles; - const unsigned int* const piCurEnd = adj.mLiveTriangles+pMesh->mNumVertices; - for (;piCur != piCurEnd;++piCur) { - iMaxRefTris = std::max(iMaxRefTris,*piCur); - } - } - ai_assert(iMaxRefTris > 0); - unsigned int* piCandidates = new unsigned int[iMaxRefTris*3]; - unsigned int iCacheMisses = 0; - - // ................................................................................... - /** PSEUDOCODE for the algorithm - - A = Build-Adjacency(I) Vertex-triangle adjacency - L = Get-Triangle-Counts(A) Per-vertex live triangle counts - C = Zero(Vertex-Count(I)) Per-vertex caching time stamps - D = Empty-Stack() Dead-end vertex stack - E = False(Triangle-Count(I)) Per triangle emitted flag - O = Empty-Index-Buffer() Empty output buffer - f = 0 Arbitrary starting vertex - s = k+1, i = 1 Time stamp and cursor - while f >= 0 For all valid fanning vertices - N = Empty-Set() 1-ring of next candidates - for each Triangle t in Neighbors(A, f) - if !Emitted(E,t) - for each Vertex v in t - Append(O,v) Output vertex - Push(D,v) Add to dead-end stack - Insert(N,v) Register as candidate - L[v] = L[v]-1 Decrease live triangle count - if s-C[v] > k If not in cache - C[v] = s Set time stamp - s = s+1 Increment time stamp - E[t] = true Flag triangle as emitted - Select next fanning vertex - f = Get-Next-Vertex(I,i,k,N,C,s,L,D) - return O - */ - // ................................................................................... - - int ivdx = 0; - int ics = 1; - int iStampCnt = mConfigCacheDepth+1; - while (ivdx >= 0) { - - unsigned int icnt = piNumTriPtrNoModify[ivdx]; - unsigned int* piList = adj.GetAdjacentTriangles(ivdx); - unsigned int* piCurCandidate = piCandidates; - - // get all triangles in the neighborhood - for (unsigned int tri = 0; tri < icnt;++tri) { - - // if they have not yet been emitted, add them to the output IB - const unsigned int fidx = *piList++; - if (!abEmitted[fidx]) { - - // so iterate through all vertices of the current triangle - const aiFace* pcFace = &pMesh->mFaces[ fidx ]; - unsigned nind = pcFace->mNumIndices; - for (unsigned ind = 0; ind < nind; ind++) { - unsigned dp = pcFace->mIndices[ind]; - - // the current vertex won't have any free triangles after this step - if (ivdx != (int)dp) { - // append the vertex to the dead-end stack - sDeadEndVStack.push(dp); - - // register as candidate for the next step - *piCurCandidate++ = dp; - - // decrease the per-vertex triangle counts - piNumTriPtr[dp]--; - } - - // append the vertex to the output index buffer - *piCSIter++ = dp; - - // if the vertex is not yet in cache, set its cache count - if (iStampCnt-piCachingStamps[dp] > mConfigCacheDepth) { - piCachingStamps[dp] = iStampCnt++; - ++iCacheMisses; - } - } - // flag triangle as emitted - abEmitted[fidx] = true; - } - } - - // the vertex has now no living adjacent triangles anymore - piNumTriPtr[ivdx] = 0; - - // get next fanning vertex - ivdx = -1; - int max_priority = -1; - for (unsigned int* piCur = piCandidates;piCur != piCurCandidate;++piCur) { - const unsigned int dp = *piCur; - - // must have live triangles - if (piNumTriPtr[dp] > 0) { - int priority = 0; - - // will the vertex be in cache, even after fanning occurs? - unsigned int tmp; - if ((tmp = iStampCnt-piCachingStamps[dp]) + 2*piNumTriPtr[dp] <= mConfigCacheDepth) { - priority = tmp; - } - - // keep best candidate - if (priority > max_priority) { - max_priority = priority; - ivdx = dp; - } - } - } - // did we reach a dead end? - if (-1 == ivdx) { - // need to get a non-local vertex for which we have a good chance that it is still - // in the cache ... - while (!sDeadEndVStack.empty()) { - unsigned int iCachedIdx = sDeadEndVStack.top(); - sDeadEndVStack.pop(); - if (piNumTriPtr[ iCachedIdx ] > 0) { - ivdx = iCachedIdx; - break; - } - } - - if (-1 == ivdx) { - // well, there isn't such a vertex. Simply get the next vertex in input order and - // hope it is not too bad ... - while (ics < (int)pMesh->mNumVertices) { - ++ics; - if (piNumTriPtr[ics] > 0) { - ivdx = ics; - break; - } - } - } - } - } - ai_real fACMR2 = 0.0f; - if (!DefaultLogger::isNullLogger()) { - fACMR2 = (float)iCacheMisses / pMesh->mNumFaces; - - // very intense verbose logging ... prepare for much text if there are many meshes - if ( DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) { - ASSIMP_LOG_DEBUG_F("Mesh %u | ACMR in: ", meshNum, " out: ", fACMR, " | ~", fACMR2, ((fACMR - fACMR2) / fACMR) * 100.f); - } - - fACMR2 *= pMesh->mNumFaces; - } - // sort the output index buffer back to the input array - piCSIter = piIBOutput; - for (aiFace* pcFace = pMesh->mFaces; pcFace != pcEnd;++pcFace) { - unsigned nind = pcFace->mNumIndices; - unsigned * ind = pcFace->mIndices; - if (nind > 0) ind[0] = *piCSIter++; - if (nind > 1) ind[1] = *piCSIter++; - if (nind > 2) ind[2] = *piCSIter++; - } - - // delete temporary storage - delete[] piCachingStamps; - delete[] piIBOutput; - delete[] piCandidates; - - return fACMR2; -} diff --git a/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.h b/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.h deleted file mode 100644 index de25ecd9fb..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ImproveCacheLocality.h +++ /dev/null @@ -1,101 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to reorder faces for - better cache locality*/ -#ifndef AI_IMPROVECACHELOCALITY_H_INC -#define AI_IMPROVECACHELOCALITY_H_INC - -#include "Common/BaseProcess.h" - -#include <assimp/types.h> - -struct aiMesh; - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The ImproveCacheLocalityProcess reorders all faces for improved vertex - * cache locality. It tries to arrange all faces to fans and to render - * faces which share vertices directly one after the other. - * - * @note This step expects triagulated input data. - */ -class ImproveCacheLocalityProcess : public BaseProcess -{ -public: - - ImproveCacheLocalityProcess(); - ~ImproveCacheLocalityProcess(); - -public: - - // ------------------------------------------------------------------- - // Check whether the pp step is active - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Executes the pp step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Configures the pp step - void SetupProperties(const Importer* pImp); - -protected: - // ------------------------------------------------------------------- - /** Executes the postprocessing step on the given mesh - * @param pMesh The mesh to process. - * @param meshNum Index of the mesh to process - */ - ai_real ProcessMesh( aiMesh* pMesh, unsigned int meshNum); - -private: - //! Configuration parameter: specifies the size of the cache to - //! optimize the vertex data for. - unsigned int mConfigCacheDepth; -}; - -} // end of namespace Assimp - -#endif // AI_IMPROVECACHELOCALITY_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.cpp b/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.cpp deleted file mode 100644 index f121fc60d3..0000000000 --- a/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the post processing step to join identical vertices - * for all imported meshes - */ - - -#ifndef ASSIMP_BUILD_NO_JOINVERTICES_PROCESS - -#include "JoinVerticesProcess.h" -#include "ProcessHelper.h" -#include <assimp/Vertex.h> -#include <assimp/TinyFormatter.h> -#include <stdio.h> -#include <unordered_set> - -using namespace Assimp; -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -JoinVerticesProcess::JoinVerticesProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -JoinVerticesProcess::~JoinVerticesProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool JoinVerticesProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_JoinIdenticalVertices) != 0; -} -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void JoinVerticesProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("JoinVerticesProcess begin"); - - // get the total number of vertices BEFORE the step is executed - int iNumOldVertices = 0; - if (!DefaultLogger::isNullLogger()) { - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { - iNumOldVertices += pScene->mMeshes[a]->mNumVertices; - } - } - - // execute the step - int iNumVertices = 0; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - iNumVertices += ProcessMesh( pScene->mMeshes[a],a); - - // if logging is active, print detailed statistics - if (!DefaultLogger::isNullLogger()) { - if (iNumOldVertices == iNumVertices) { - ASSIMP_LOG_DEBUG("JoinVerticesProcess finished "); - } else { - ASSIMP_LOG_INFO_F("JoinVerticesProcess finished | Verts in: ", iNumOldVertices, - " out: ", iNumVertices, " | ~", - ((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f ); - } - } - - pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; -} - -namespace { - -bool areVerticesEqual(const Vertex &lhs, const Vertex &rhs, bool complex) -{ - // A little helper to find locally close vertices faster. - // Try to reuse the lookup table from the last step. - const static float epsilon = 1e-5f; - // Squared because we check against squared length of the vector difference - static const float squareEpsilon = epsilon * epsilon; - - // Square compare is useful for animeshes vertices compare - if ((lhs.position - rhs.position).SquareLength() > squareEpsilon) { - return false; - } - - // We just test the other attributes even if they're not present in the mesh. - // In this case they're initialized to 0 so the comparison succeeds. - // By this method the non-present attributes are effectively ignored in the comparison. - if ((lhs.normal - rhs.normal).SquareLength() > squareEpsilon) { - return false; - } - - if ((lhs.texcoords[0] - rhs.texcoords[0]).SquareLength() > squareEpsilon) { - return false; - } - - if ((lhs.tangent - rhs.tangent).SquareLength() > squareEpsilon) { - return false; - } - - if ((lhs.bitangent - rhs.bitangent).SquareLength() > squareEpsilon) { - return false; - } - - // Usually we won't have vertex colors or multiple UVs, so we can skip from here - // Actually this increases runtime performance slightly, at least if branch - // prediction is on our side. - if (complex) { - for (int i = 0; i < 8; i++) { - if (i > 0 && (lhs.texcoords[i] - rhs.texcoords[i]).SquareLength() > squareEpsilon) { - return false; - } - if (GetColorDifference(lhs.colors[i], rhs.colors[i]) > squareEpsilon) { - return false; - } - } - } - return true; -} - -template<class XMesh> -void updateXMeshVertices(XMesh *pMesh, std::vector<Vertex> &uniqueVertices) { - // replace vertex data with the unique data sets - pMesh->mNumVertices = (unsigned int)uniqueVertices.size(); - - // ---------------------------------------------------------------------------- - // NOTE - we're *not* calling Vertex::SortBack() because it would check for - // presence of every single vertex component once PER VERTEX. And our CPU - // dislikes branches, even if they're easily predictable. - // ---------------------------------------------------------------------------- - - // Position, if present (check made for aiAnimMesh) - if (pMesh->mVertices) - { - delete [] pMesh->mVertices; - pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; - for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mVertices[a] = uniqueVertices[a].position; - } - } - - // Normals, if present - if (pMesh->mNormals) - { - delete [] pMesh->mNormals; - pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mNormals[a] = uniqueVertices[a].normal; - } - } - // Tangents, if present - if (pMesh->mTangents) - { - delete [] pMesh->mTangents; - pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; - for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mTangents[a] = uniqueVertices[a].tangent; - } - } - // Bitangents as well - if (pMesh->mBitangents) - { - delete [] pMesh->mBitangents; - pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; - for (unsigned int a = 0; a < pMesh->mNumVertices; a++) { - pMesh->mBitangents[a] = uniqueVertices[a].bitangent; - } - } - // Vertex colors - for (unsigned int a = 0; pMesh->HasVertexColors(a); a++) - { - delete [] pMesh->mColors[a]; - pMesh->mColors[a] = new aiColor4D[pMesh->mNumVertices]; - for( unsigned int b = 0; b < pMesh->mNumVertices; b++) { - pMesh->mColors[a][b] = uniqueVertices[b].colors[a]; - } - } - // Texture coords - for (unsigned int a = 0; pMesh->HasTextureCoords(a); a++) - { - delete [] pMesh->mTextureCoords[a]; - pMesh->mTextureCoords[a] = new aiVector3D[pMesh->mNumVertices]; - for (unsigned int b = 0; b < pMesh->mNumVertices; b++) { - pMesh->mTextureCoords[a][b] = uniqueVertices[b].texcoords[a]; - } - } -} -} // namespace - -// ------------------------------------------------------------------------------------------------ -// Unites identical vertices in the given mesh -int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) -{ - static_assert( AI_MAX_NUMBER_OF_COLOR_SETS == 8, "AI_MAX_NUMBER_OF_COLOR_SETS == 8"); - static_assert( AI_MAX_NUMBER_OF_TEXTURECOORDS == 8, "AI_MAX_NUMBER_OF_TEXTURECOORDS == 8"); - - // Return early if we don't have any positions - if (!pMesh->HasPositions() || !pMesh->HasFaces()) { - return 0; - } - - // We should care only about used vertices, not all of them - // (this can happen due to original file vertices buffer being used by - // multiple meshes) - std::unordered_set<unsigned int> usedVertexIndices; - usedVertexIndices.reserve(pMesh->mNumVertices); - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - aiFace& face = pMesh->mFaces[a]; - for( unsigned int b = 0; b < face.mNumIndices; b++) { - usedVertexIndices.insert(face.mIndices[b]); - } - } - - // We'll never have more vertices afterwards. - std::vector<Vertex> uniqueVertices; - uniqueVertices.reserve( pMesh->mNumVertices); - - // For each vertex the index of the vertex it was replaced by. - // Since the maximal number of vertices is 2^31-1, the most significand bit can be used to mark - // whether a new vertex was created for the index (true) or if it was replaced by an existing - // unique vertex (false). This saves an additional std::vector<bool> and greatly enhances - // branching performance. - static_assert(AI_MAX_VERTICES == 0x7fffffff, "AI_MAX_VERTICES == 0x7fffffff"); - std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff); - - // float posEpsilonSqr; - SpatialSort* vertexFinder = NULL; - SpatialSort _vertexFinder; - - typedef std::pair<SpatialSort,float> SpatPair; - if (shared) { - std::vector<SpatPair >* avf; - shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); - if (avf) { - SpatPair& blubb = (*avf)[meshIndex]; - vertexFinder = &blubb.first; - // posEpsilonSqr = blubb.second; - } - } - if (!vertexFinder) { - // bad, need to compute it. - _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); - vertexFinder = &_vertexFinder; - // posEpsilonSqr = ComputePositionEpsilon(pMesh); - } - - // Again, better waste some bytes than a realloc ... - std::vector<unsigned int> verticesFound; - verticesFound.reserve(10); - - // Run an optimized code path if we don't have multiple UVs or vertex colors. - // This should yield false in more than 99% of all imports ... - const bool complex = ( pMesh->GetNumColorChannels() > 0 || pMesh->GetNumUVChannels() > 1); - const bool hasAnimMeshes = pMesh->mNumAnimMeshes > 0; - - // We'll never have more vertices afterwards. - std::vector<std::vector<Vertex>> uniqueAnimatedVertices; - if (hasAnimMeshes) { - uniqueAnimatedVertices.resize(pMesh->mNumAnimMeshes); - for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { - uniqueAnimatedVertices[animMeshIndex].reserve(pMesh->mNumVertices); - } - } - - // Now check each vertex if it brings something new to the table - for( unsigned int a = 0; a < pMesh->mNumVertices; a++) { - if (usedVertexIndices.find(a) == usedVertexIndices.end()) { - continue; - } - - // collect the vertex data - Vertex v(pMesh,a); - - // collect all vertices that are close enough to the given position - vertexFinder->FindIdenticalPositions( v.position, verticesFound); - unsigned int matchIndex = 0xffffffff; - - // check all unique vertices close to the position if this vertex is already present among them - for( unsigned int b = 0; b < verticesFound.size(); b++) { - const unsigned int vidx = verticesFound[b]; - const unsigned int uidx = replaceIndex[ vidx]; - if( uidx & 0x80000000) - continue; - - const Vertex& uv = uniqueVertices[ uidx]; - - if (!areVerticesEqual(v, uv, complex)) { - continue; - } - - if (hasAnimMeshes) { - // If given vertex is animated, then it has to be preserver 1 to 1 (base mesh and animated mesh require same topology) - // NOTE: not doing this totaly breaks anim meshes as they don't have their own faces (they use pMesh->mFaces) - bool breaksAnimMesh = false; - for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { - const Vertex& animatedUV = uniqueAnimatedVertices[animMeshIndex][ uidx]; - Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a); - if (!areVerticesEqual(aniMeshVertex, animatedUV, complex)) { - breaksAnimMesh = true; - break; - } - } - if (breaksAnimMesh) { - continue; - } - } - - // we're still here -> this vertex perfectly matches our given vertex - matchIndex = uidx; - break; - } - - // found a replacement vertex among the uniques? - if( matchIndex != 0xffffffff) - { - // store where to found the matching unique vertex - replaceIndex[a] = matchIndex | 0x80000000; - } - else - { - // no unique vertex matches it up to now -> so add it - replaceIndex[a] = (unsigned int)uniqueVertices.size(); - uniqueVertices.push_back( v); - if (hasAnimMeshes) { - for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { - Vertex aniMeshVertex(pMesh->mAnimMeshes[animMeshIndex], a); - uniqueAnimatedVertices[animMeshIndex].push_back(aniMeshVertex); - } - } - } - } - - if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) { - ASSIMP_LOG_DEBUG_F( - "Mesh ",meshIndex, - " (", - (pMesh->mName.length ? pMesh->mName.data : "unnamed"), - ") | Verts in: ",pMesh->mNumVertices, - " out: ", - uniqueVertices.size(), - " | ~", - ((pMesh->mNumVertices - uniqueVertices.size()) / (float)pMesh->mNumVertices) * 100.f, - "%" - ); - } - - updateXMeshVertices(pMesh, uniqueVertices); - if (hasAnimMeshes) { - for (unsigned int animMeshIndex = 0; animMeshIndex < pMesh->mNumAnimMeshes; animMeshIndex++) { - updateXMeshVertices(pMesh->mAnimMeshes[animMeshIndex], uniqueAnimatedVertices[animMeshIndex]); - } - } - - // adjust the indices in all faces - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) - { - aiFace& face = pMesh->mFaces[a]; - for( unsigned int b = 0; b < face.mNumIndices; b++) { - face.mIndices[b] = replaceIndex[face.mIndices[b]] & ~0x80000000; - } - } - - // adjust bone vertex weights. - for( int a = 0; a < (int)pMesh->mNumBones; a++) { - aiBone* bone = pMesh->mBones[a]; - std::vector<aiVertexWeight> newWeights; - newWeights.reserve( bone->mNumWeights); - - if ( NULL != bone->mWeights ) { - for ( unsigned int b = 0; b < bone->mNumWeights; b++ ) { - const aiVertexWeight& ow = bone->mWeights[ b ]; - // if the vertex is a unique one, translate it - if ( !( replaceIndex[ ow.mVertexId ] & 0x80000000 ) ) { - aiVertexWeight nw; - nw.mVertexId = replaceIndex[ ow.mVertexId ]; - nw.mWeight = ow.mWeight; - newWeights.push_back( nw ); - } - } - } else { - ASSIMP_LOG_ERROR( "X-Export: aiBone shall contain weights, but pointer to them is NULL." ); - } - - if (newWeights.size() > 0) { - // kill the old and replace them with the translated weights - delete [] bone->mWeights; - bone->mNumWeights = (unsigned int)newWeights.size(); - - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight)); - } - } - return pMesh->mNumVertices; -} - -#endif // !! ASSIMP_BUILD_NO_JOINVERTICES_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.h b/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.h deleted file mode 100644 index e017ae62db..0000000000 --- a/thirdparty/assimp/code/PostProcessing/JoinVerticesProcess.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to join identical vertices - on all imported meshes.*/ -#ifndef AI_JOINVERTICESPROCESS_H_INC -#define AI_JOINVERTICESPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include <assimp/types.h> - -struct aiMesh; - -namespace Assimp -{ - -// --------------------------------------------------------------------------- -/** The JoinVerticesProcess unites identical vertices in all imported meshes. - * By default the importer returns meshes where each face addressed its own - * set of vertices even if that means that identical vertices are stored multiple - * times. The JoinVerticesProcess finds these identical vertices and - * erases all but one of the copies. This usually reduces the number of vertices - * in a mesh by a serious amount and is the standard form to render a mesh. - */ -class ASSIMP_API JoinVerticesProcess : public BaseProcess { -public: - JoinVerticesProcess(); - ~JoinVerticesProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Unites identical vertices in the given mesh. - * @param pMesh The mesh to process. - * @param meshIndex Index of the mesh to process - */ - int ProcessMesh( aiMesh* pMesh, unsigned int meshIndex); -}; - -} // end of namespace Assimp - -#endif // AI_CALCTANGENTSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp b/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp deleted file mode 100644 index d560f19287..0000000000 --- a/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** Implementation of the LimitBoneWeightsProcess post processing step */ - - -#include "LimitBoneWeightsProcess.h" -#include <assimp/StringUtils.h> -#include <assimp/postprocess.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/scene.h> -#include <stdio.h> - -using namespace Assimp; - - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -LimitBoneWeightsProcess::LimitBoneWeightsProcess() -{ - mMaxWeights = AI_LMW_MAX_WEIGHTS; -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -LimitBoneWeightsProcess::~LimitBoneWeightsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_LimitBoneWeights) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void LimitBoneWeightsProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin"); - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a ) { - ProcessMesh(pScene->mMeshes[a]); - } - - ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end"); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) -{ - // get the current value of the property - this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS); -} - -// ------------------------------------------------------------------------------------------------ -// Unites identical vertices in the given mesh -void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh) -{ - if( !pMesh->HasBones()) - return; - - // collect all bone weights per vertex - typedef std::vector< std::vector< Weight > > WeightsPerVertex; - WeightsPerVertex vertexWeights( pMesh->mNumVertices); - - // collect all weights per vertex - for( unsigned int a = 0; a < pMesh->mNumBones; a++) - { - const aiBone* bone = pMesh->mBones[a]; - for( unsigned int b = 0; b < bone->mNumWeights; b++) - { - const aiVertexWeight& w = bone->mWeights[b]; - vertexWeights[w.mVertexId].push_back( Weight( a, w.mWeight)); - } - } - - unsigned int removed = 0, old_bones = pMesh->mNumBones; - - // now cut the weight count if it exceeds the maximum - bool bChanged = false; - for( WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit) - { - if( vit->size() <= mMaxWeights) - continue; - - bChanged = true; - - // more than the defined maximum -> first sort by weight in descending order. That's - // why we defined the < operator in such a weird way. - std::sort( vit->begin(), vit->end()); - - // now kill everything beyond the maximum count - unsigned int m = static_cast<unsigned int>(vit->size()); - vit->erase( vit->begin() + mMaxWeights, vit->end()); - removed += static_cast<unsigned int>(m-vit->size()); - - // and renormalize the weights - float sum = 0.0f; - for( std::vector<Weight>::const_iterator it = vit->begin(); it != vit->end(); ++it ) { - sum += it->mWeight; - } - if( 0.0f != sum ) { - const float invSum = 1.0f / sum; - for( std::vector<Weight>::iterator it = vit->begin(); it != vit->end(); ++it ) { - it->mWeight *= invSum; - } - } - } - - if (bChanged) { - // rebuild the vertex weight array for all bones - typedef std::vector< std::vector< aiVertexWeight > > WeightsPerBone; - WeightsPerBone boneWeights( pMesh->mNumBones); - for( unsigned int a = 0; a < vertexWeights.size(); a++) - { - const std::vector<Weight>& vw = vertexWeights[a]; - for( std::vector<Weight>::const_iterator it = vw.begin(); it != vw.end(); ++it) - boneWeights[it->mBone].push_back( aiVertexWeight( a, it->mWeight)); - } - - // and finally copy the vertex weight list over to the mesh's bones - std::vector<bool> abNoNeed(pMesh->mNumBones,false); - bChanged = false; - - for( unsigned int a = 0; a < pMesh->mNumBones; a++) - { - const std::vector<aiVertexWeight>& bw = boneWeights[a]; - aiBone* bone = pMesh->mBones[a]; - - if ( bw.empty() ) - { - abNoNeed[a] = bChanged = true; - continue; - } - - // copy the weight list. should always be less weights than before, so we don't need a new allocation - ai_assert( bw.size() <= bone->mNumWeights); - bone->mNumWeights = static_cast<unsigned int>( bw.size() ); - ::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight)); - } - - if (bChanged) { - // the number of new bones is smaller than before, so we can reuse the old array - aiBone** ppcCur = pMesh->mBones;aiBone** ppcSrc = ppcCur; - - for (std::vector<bool>::const_iterator iter = abNoNeed.begin();iter != abNoNeed.end() ;++iter) { - if (*iter) { - delete *ppcSrc; - --pMesh->mNumBones; - } - else *ppcCur++ = *ppcSrc; - ++ppcSrc; - } - } - - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones ); - } - } -} diff --git a/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.h b/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.h deleted file mode 100644 index 73c2a68d53..0000000000 --- a/thirdparty/assimp/code/PostProcessing/LimitBoneWeightsProcess.h +++ /dev/null @@ -1,138 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** Defines a post processing step to limit the number of bones affecting a single vertex. */ -#ifndef AI_LIMITBONEWEIGHTSPROCESS_H_INC -#define AI_LIMITBONEWEIGHTSPROCESS_H_INC - -#include "Common/BaseProcess.h" - -// Forward declarations -struct aiMesh; - -class LimitBoneWeightsTest; - -namespace Assimp { - -// NOTE: If you change these limits, don't forget to change the -// corresponding values in all Assimp ports - -// ********************************************************** -// Java: ConfigProperty.java, -// ConfigProperty.DEFAULT_BONE_WEIGHT_LIMIT -// ********************************************************** - -#if (!defined AI_LMW_MAX_WEIGHTS) -# define AI_LMW_MAX_WEIGHTS 0x4 -#endif // !! AI_LMW_MAX_WEIGHTS - -// --------------------------------------------------------------------------- -/** This post processing step limits the number of bones affecting a vertex -* to a certain maximum value. If a vertex is affected by more than that number -* of bones, the bone weight with the least influence on this vertex are removed. -* The other weights on this bone are then renormalized to assure the sum weight -* to be 1. -*/ -class ASSIMP_API LimitBoneWeightsProcess : public BaseProcess { -public: - LimitBoneWeightsProcess(); - ~LimitBoneWeightsProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. - * A bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Limits the bone weight count for all vertices in the given mesh. - * @param pMesh The mesh to process. - */ - void ProcessMesh( aiMesh* pMesh); - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Describes a bone weight on a vertex */ - struct Weight { - unsigned int mBone; ///< Index of the bone - float mWeight; ///< Weight of that bone on this vertex - Weight() AI_NO_EXCEPT - : mBone(0) - , mWeight(0.0f) { - // empty - } - - Weight( unsigned int pBone, float pWeight) - : mBone(pBone) - , mWeight(pWeight) { - // empty - } - - /** Comparison operator to sort bone weights by descending weight */ - bool operator < (const Weight& pWeight) const { - return mWeight > pWeight.mWeight; - } - }; - - /** Maximum number of bones influencing any single vertex. */ - unsigned int mMaxWeights; -}; - -} // end of namespace Assimp - -#endif // AI_LIMITBONEWEIGHTSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.cpp b/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.cpp deleted file mode 100644 index 41f50a5ba5..0000000000 --- a/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -/** @file Implementation of the post processing step "MakeVerboseFormat" -*/ - - -#include "MakeVerboseFormat.h" -#include <assimp/scene.h> -#include <assimp/DefaultLogger.hpp> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -MakeVerboseFormatProcess::MakeVerboseFormatProcess() -{ - // nothing to do here -} -// ------------------------------------------------------------------------------------------------ -MakeVerboseFormatProcess::~MakeVerboseFormatProcess() -{ - // nothing to do here -} -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void MakeVerboseFormatProcess::Execute( aiScene* pScene) -{ - ai_assert(NULL != pScene); - ASSIMP_LOG_DEBUG("MakeVerboseFormatProcess begin"); - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - { - if( MakeVerboseFormat( pScene->mMeshes[a])) - bHas = true; - } - if (bHas) { - ASSIMP_LOG_INFO("MakeVerboseFormatProcess finished. There was much work to do ..."); - } else { - ASSIMP_LOG_DEBUG("MakeVerboseFormatProcess. There was nothing to do."); - } - - pScene->mFlags &= ~AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh) -{ - ai_assert(NULL != pcMesh); - - unsigned int iOldNumVertices = pcMesh->mNumVertices; - const unsigned int iNumVerts = pcMesh->mNumFaces*3; - - aiVector3D* pvPositions = new aiVector3D[ iNumVerts ]; - - aiVector3D* pvNormals = NULL; - if (pcMesh->HasNormals()) - { - pvNormals = new aiVector3D[iNumVerts]; - } - aiVector3D* pvTangents = NULL, *pvBitangents = NULL; - if (pcMesh->HasTangentsAndBitangents()) - { - pvTangents = new aiVector3D[iNumVerts]; - pvBitangents = new aiVector3D[iNumVerts]; - } - - aiVector3D* apvTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS] = {0}; - aiColor4D* apvColorSets[AI_MAX_NUMBER_OF_COLOR_SETS] = {0}; - - unsigned int p = 0; - while (pcMesh->HasTextureCoords(p)) - apvTextureCoords[p++] = new aiVector3D[iNumVerts]; - - p = 0; - while (pcMesh->HasVertexColors(p)) - apvColorSets[p++] = new aiColor4D[iNumVerts]; - - // allocate enough memory to hold output bones and vertex weights ... - std::vector<aiVertexWeight>* newWeights = new std::vector<aiVertexWeight>[pcMesh->mNumBones]; - for (unsigned int i = 0;i < pcMesh->mNumBones;++i) { - newWeights[i].reserve(pcMesh->mBones[i]->mNumWeights*3); - } - - // iterate through all faces and build a clean list - unsigned int iIndex = 0; - for (unsigned int a = 0; a< pcMesh->mNumFaces;++a) - { - aiFace* pcFace = &pcMesh->mFaces[a]; - for (unsigned int q = 0; q < pcFace->mNumIndices;++q,++iIndex) - { - // need to build a clean list of bones, too - for (unsigned int i = 0;i < pcMesh->mNumBones;++i) - { - for (unsigned int a = 0; a < pcMesh->mBones[i]->mNumWeights;a++) - { - const aiVertexWeight& w = pcMesh->mBones[i]->mWeights[a]; - if(pcFace->mIndices[q] == w.mVertexId) - { - aiVertexWeight wNew; - wNew.mVertexId = iIndex; - wNew.mWeight = w.mWeight; - newWeights[i].push_back(wNew); - } - } - } - - pvPositions[iIndex] = pcMesh->mVertices[pcFace->mIndices[q]]; - - if (pcMesh->HasNormals()) - { - pvNormals[iIndex] = pcMesh->mNormals[pcFace->mIndices[q]]; - } - if (pcMesh->HasTangentsAndBitangents()) - { - pvTangents[iIndex] = pcMesh->mTangents[pcFace->mIndices[q]]; - pvBitangents[iIndex] = pcMesh->mBitangents[pcFace->mIndices[q]]; - } - - unsigned int p = 0; - while (pcMesh->HasTextureCoords(p)) - { - apvTextureCoords[p][iIndex] = pcMesh->mTextureCoords[p][pcFace->mIndices[q]]; - ++p; - } - p = 0; - while (pcMesh->HasVertexColors(p)) - { - apvColorSets[p][iIndex] = pcMesh->mColors[p][pcFace->mIndices[q]]; - ++p; - } - pcFace->mIndices[q] = iIndex; - } - } - - - - // build output vertex weights - for (unsigned int i = 0;i < pcMesh->mNumBones;++i) - { - delete [] pcMesh->mBones[i]->mWeights; - if (!newWeights[i].empty()) { - pcMesh->mBones[i]->mWeights = new aiVertexWeight[newWeights[i].size()]; - aiVertexWeight *weightToCopy = &( newWeights[i][0] ); - memcpy(pcMesh->mBones[i]->mWeights, weightToCopy, - sizeof(aiVertexWeight) * newWeights[i].size()); - } else { - pcMesh->mBones[i]->mWeights = NULL; - } - } - delete[] newWeights; - - // delete the old members - delete[] pcMesh->mVertices; - pcMesh->mVertices = pvPositions; - - p = 0; - while (pcMesh->HasTextureCoords(p)) - { - delete[] pcMesh->mTextureCoords[p]; - pcMesh->mTextureCoords[p] = apvTextureCoords[p]; - ++p; - } - p = 0; - while (pcMesh->HasVertexColors(p)) - { - delete[] pcMesh->mColors[p]; - pcMesh->mColors[p] = apvColorSets[p]; - ++p; - } - pcMesh->mNumVertices = iNumVerts; - - if (pcMesh->HasNormals()) - { - delete[] pcMesh->mNormals; - pcMesh->mNormals = pvNormals; - } - if (pcMesh->HasTangentsAndBitangents()) - { - delete[] pcMesh->mTangents; - pcMesh->mTangents = pvTangents; - delete[] pcMesh->mBitangents; - pcMesh->mBitangents = pvBitangents; - } - return (pcMesh->mNumVertices != iOldNumVertices); -} - - -// ------------------------------------------------------------------------------------------------ -bool IsMeshInVerboseFormat(const aiMesh* mesh) { - // avoid slow vector<bool> specialization - std::vector<unsigned int> seen(mesh->mNumVertices,0); - for(unsigned int i = 0; i < mesh->mNumFaces; ++i) { - const aiFace& f = mesh->mFaces[i]; - for(unsigned int j = 0; j < f.mNumIndices; ++j) { - if(++seen[f.mIndices[j]] == 2) { - // found a duplicate index - return false; - } - } - } - - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool MakeVerboseFormatProcess::IsVerboseFormat(const aiScene* pScene) { - for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - if(!IsMeshInVerboseFormat(pScene->mMeshes[i])) { - return false; - } - } - - return true; -} diff --git a/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.h b/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.h deleted file mode 100644 index 8565d5933a..0000000000 --- a/thirdparty/assimp/code/PostProcessing/MakeVerboseFormat.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to bring a given scene - into the verbose format that is expected by most postprocess steps. - This is the inverse of the "JoinIdenticalVertices" step. */ -#ifndef AI_MAKEVERBOSEFORMAT_H_INC -#define AI_MAKEVERBOSEFORMAT_H_INC - -#include "Common/BaseProcess.h" - -struct aiMesh; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** MakeVerboseFormatProcess: Class to convert an asset to the verbose - * format which is expected by most postprocess steps. - * - * This is the inverse of what the "JoinIdenticalVertices" step is doing. - * This step has no official flag (since it wouldn't make sense to run it - * during import). It is intended for applications intending to modify the - * returned aiScene. After this step has been executed, they can execute - * other postprocess steps on the data. The code might also be useful to - * quickly adapt code that doesn't result in a verbose representation of - * the scene data. - * The step has been added because it was required by the viewer, however - * it has been moved to the main library since others might find it - * useful, too. */ -class ASSIMP_API_WINONLY MakeVerboseFormatProcess : public BaseProcess -{ -public: - - - MakeVerboseFormatProcess(); - ~MakeVerboseFormatProcess(); - -public: - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not */ - bool IsActive( unsigned int /*pFlags*/ ) const - { - // NOTE: There is no direct flag that corresponds to - // this postprocess step. - return false; - } - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. */ - void Execute( aiScene* pScene); - -public: - - // ------------------------------------------------------------------- - /** Checks whether the scene is already in verbose format. - * @param pScene The data to check. - * @return true if the scene is already in verbose format. */ - static bool IsVerboseFormat(const aiScene* pScene); - -private: - - //! Apply the postprocess step to a given submesh - bool MakeVerboseFormat (aiMesh* pcMesh); -}; - -} // end of namespace Assimp - -#endif // !!AI_KILLNORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/OptimizeGraph.cpp b/thirdparty/assimp/code/PostProcessing/OptimizeGraph.cpp deleted file mode 100644 index 5db51f58b6..0000000000 --- a/thirdparty/assimp/code/PostProcessing/OptimizeGraph.cpp +++ /dev/null @@ -1,351 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file OptimizeGraph.cpp - * @brief Implementation of the aiProcess_OptimizGraph step - */ - - -#ifndef ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS - -#include "OptimizeGraph.h" -#include "ProcessHelper.h" -#include <assimp/SceneCombiner.h> -#include <assimp/Exceptional.h> -#include <stdio.h> - -using namespace Assimp; - -#define AI_RESERVED_NODE_NAME "$Reserved_And_Evil" - -/* AI_OG_USE_HASHING enables the use of hashing to speed-up std::set lookups. - * The unhashed variant should be faster, except for *very* large data sets - */ -#ifdef AI_OG_USE_HASHING - // Use our standard hashing function to compute the hash -# define AI_OG_GETKEY(str) SuperFastHash(str.data,str.length) -#else - // Otherwise hope that std::string will utilize a static buffer - // for shorter node names. This would avoid endless heap copying. -# define AI_OG_GETKEY(str) std::string(str.data) -#endif - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -OptimizeGraphProcess::OptimizeGraphProcess() -: mScene() -, nodes_in() -, nodes_out() -, count_merged() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -OptimizeGraphProcess::~OptimizeGraphProcess() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool OptimizeGraphProcess::IsActive( unsigned int pFlags) const { - return (0 != (pFlags & aiProcess_OptimizeGraph)); -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties for the post-processing step -void OptimizeGraphProcess::SetupProperties(const Importer* pImp) { - // Get value of AI_CONFIG_PP_OG_EXCLUDE_LIST - std::string tmp = pImp->GetPropertyString(AI_CONFIG_PP_OG_EXCLUDE_LIST,""); - AddLockedNodeList(tmp); -} - -// ------------------------------------------------------------------------------------------------ -// Collect new children -void OptimizeGraphProcess::CollectNewChildren(aiNode* nd, std::list<aiNode*>& nodes) { - nodes_in += nd->mNumChildren; - - // Process children - std::list<aiNode*> child_nodes; - for (unsigned int i = 0; i < nd->mNumChildren; ++i) { - CollectNewChildren(nd->mChildren[i],child_nodes); - nd->mChildren[i] = nullptr; - } - - // Check whether we need this node; if not we can replace it by our own children (warn, danger of incest). - if (locked.find(AI_OG_GETKEY(nd->mName)) == locked.end() ) { - for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) { - - if (locked.find(AI_OG_GETKEY((*it)->mName)) == locked.end()) { - (*it)->mTransformation = nd->mTransformation * (*it)->mTransformation; - nodes.push_back(*it); - - it = child_nodes.erase(it); - continue; - } - ++it; - } - - if (nd->mNumMeshes || !child_nodes.empty()) { - nodes.push_back(nd); - } else { - delete nd; /* bye, node */ - return; - } - } else { - - // Retain our current position in the hierarchy - nodes.push_back(nd); - - // Now check for possible optimizations in our list of child nodes. join as many as possible - aiNode* join_master = NULL; - aiMatrix4x4 inv; - - const LockedSetType::const_iterator end = locked.end(); - - std::list<aiNode*> join; - for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end();) { - aiNode* child = *it; - if (child->mNumChildren == 0 && locked.find(AI_OG_GETKEY(child->mName)) == end) { - - // There may be no instanced meshes - unsigned int n = 0; - for (; n < child->mNumMeshes;++n) { - if (meshes[child->mMeshes[n]] > 1) { - break; - } - } - if (n == child->mNumMeshes) { - if (!join_master) { - join_master = child; - inv = join_master->mTransformation; - inv.Inverse(); - } else { - child->mTransformation = inv * child->mTransformation ; - - join.push_back(child); - it = child_nodes.erase(it); - continue; - } - } - } - ++it; - } - if (join_master && !join.empty()) { - join_master->mName.length = ::ai_snprintf(join_master->mName.data, MAXLEN, "$MergedNode_%i",count_merged++); - - unsigned int out_meshes = 0; - for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) { - out_meshes += (*it)->mNumMeshes; - } - - // copy all mesh references in one array - if (out_meshes) { - unsigned int* meshes = new unsigned int[out_meshes+join_master->mNumMeshes], *tmp = meshes; - for (unsigned int n = 0; n < join_master->mNumMeshes;++n) { - *tmp++ = join_master->mMeshes[n]; - } - - for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) { - for (unsigned int n = 0; n < (*it)->mNumMeshes; ++n) { - - *tmp = (*it)->mMeshes[n]; - aiMesh* mesh = mScene->mMeshes[*tmp++]; - - // manually move the mesh into the right coordinate system - const aiMatrix3x3 IT = aiMatrix3x3( (*it)->mTransformation ).Inverse().Transpose(); - for (unsigned int a = 0; a < mesh->mNumVertices; ++a) { - - mesh->mVertices[a] *= (*it)->mTransformation; - - if (mesh->HasNormals()) - mesh->mNormals[a] *= IT; - - if (mesh->HasTangentsAndBitangents()) { - mesh->mTangents[a] *= IT; - mesh->mBitangents[a] *= IT; - } - } - } - delete *it; // bye, node - } - delete[] join_master->mMeshes; - join_master->mMeshes = meshes; - join_master->mNumMeshes += out_meshes; - } - } - } - // reassign children if something changed - if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) { - - delete[] nd->mChildren; - - if (!child_nodes.empty()) { - nd->mChildren = new aiNode*[child_nodes.size()]; - } - else nd->mChildren = nullptr; - } - - nd->mNumChildren = static_cast<unsigned int>(child_nodes.size()); - - if (nd->mChildren) { - aiNode** tmp = nd->mChildren; - for (std::list<aiNode*>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) { - aiNode* node = *tmp++ = *it; - node->mParent = nd; - } - } - - nodes_out += static_cast<unsigned int>(child_nodes.size()); -} - -// ------------------------------------------------------------------------------------------------ -// Execute the post-processing step on the given scene -void OptimizeGraphProcess::Execute( aiScene* pScene) { - ASSIMP_LOG_DEBUG("OptimizeGraphProcess begin"); - nodes_in = nodes_out = count_merged = 0; - mScene = pScene; - - meshes.resize(pScene->mNumMeshes,0); - FindInstancedMeshes(pScene->mRootNode); - - // build a blacklist of identifiers. If the name of a node matches one of these, we won't touch it - locked.clear(); - for (std::list<std::string>::const_iterator it = locked_nodes.begin(); it != locked_nodes.end(); ++it) { -#ifdef AI_OG_USE_HASHING - locked.insert(SuperFastHash((*it).c_str())); -#else - locked.insert(*it); -#endif - } - - for (unsigned int i = 0; i < pScene->mNumAnimations; ++i) { - for (unsigned int a = 0; a < pScene->mAnimations[i]->mNumChannels; ++a) { - aiNodeAnim* anim = pScene->mAnimations[i]->mChannels[a]; - locked.insert(AI_OG_GETKEY(anim->mNodeName)); - } - } - - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - for (unsigned int a = 0; a < pScene->mMeshes[i]->mNumBones; ++a) { - - aiBone* bone = pScene->mMeshes[i]->mBones[a]; - locked.insert(AI_OG_GETKEY(bone->mName)); - - // HACK: Meshes referencing bones may not be transformed; we need to look them. - // The easiest way to do this is to increase their reference counters ... - meshes[i] += 2; - } - } - - for (unsigned int i = 0; i < pScene->mNumCameras; ++i) { - aiCamera* cam = pScene->mCameras[i]; - locked.insert(AI_OG_GETKEY(cam->mName)); - } - - for (unsigned int i = 0; i < pScene->mNumLights; ++i) { - aiLight* lgh = pScene->mLights[i]; - locked.insert(AI_OG_GETKEY(lgh->mName)); - } - - // Insert a dummy master node and make it read-only - aiNode* dummy_root = new aiNode(AI_RESERVED_NODE_NAME); - locked.insert(AI_OG_GETKEY(dummy_root->mName)); - - const aiString prev = pScene->mRootNode->mName; - pScene->mRootNode->mParent = dummy_root; - - dummy_root->mChildren = new aiNode*[dummy_root->mNumChildren = 1]; - dummy_root->mChildren[0] = pScene->mRootNode; - - // Do our recursive processing of scenegraph nodes. For each node collect - // a fully new list of children and allow their children to place themselves - // on the same hierarchy layer as their parents. - std::list<aiNode*> nodes; - CollectNewChildren (dummy_root,nodes); - - ai_assert(nodes.size() == 1); - - if (dummy_root->mNumChildren == 0) { - pScene->mRootNode = NULL; - throw DeadlyImportError("After optimizing the scene graph, no data remains"); - } - - if (dummy_root->mNumChildren > 1) { - pScene->mRootNode = dummy_root; - - // Keep the dummy node but assign the name of the old root node to it - pScene->mRootNode->mName = prev; - } - else { - - // Remove the dummy root node again. - pScene->mRootNode = dummy_root->mChildren[0]; - - dummy_root->mChildren[0] = NULL; - delete dummy_root; - } - - pScene->mRootNode->mParent = NULL; - if (!DefaultLogger::isNullLogger()) { - if ( nodes_in != nodes_out) { - ASSIMP_LOG_INFO_F("OptimizeGraphProcess finished; Input nodes: ", nodes_in, ", Output nodes: ", nodes_out); - } else { - ASSIMP_LOG_DEBUG("OptimizeGraphProcess finished"); - } - } - meshes.clear(); - locked.clear(); -} - -// ------------------------------------------------------------------------------------------------ -// Build a LUT of all instanced meshes -void OptimizeGraphProcess::FindInstancedMeshes (aiNode* pNode) -{ - for (unsigned int i = 0; i < pNode->mNumMeshes;++i) { - ++meshes[pNode->mMeshes[i]]; - } - - for (unsigned int i = 0; i < pNode->mNumChildren; ++i) - FindInstancedMeshes(pNode->mChildren[i]); -} - -#endif // !! ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/OptimizeGraph.h b/thirdparty/assimp/code/PostProcessing/OptimizeGraph.h deleted file mode 100644 index 82cc5db3fe..0000000000 --- a/thirdparty/assimp/code/PostProcessing/OptimizeGraph.h +++ /dev/null @@ -1,140 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file OptimizeGraph.h - * @brief Declares a post processing step to optimize the scenegraph - */ -#ifndef AI_OPTIMIZEGRAPHPROCESS_H_INC -#define AI_OPTIMIZEGRAPHPROCESS_H_INC - -#include "Common/BaseProcess.h" -#include "PostProcessing/ProcessHelper.h" - -#include <assimp/types.h> - -#include <set> - -// Forward declarations -struct aiMesh; - -class OptimizeGraphProcessTest; - -namespace Assimp { - -// ----------------------------------------------------------------------------- -/** @brief Postprocessing step to optimize the scenegraph - * - * The implementation tries to merge nodes, even if they use different - * transformations. Animations are preserved. - * - * @see aiProcess_OptimizeGraph for a detailed description of the - * algorithm being applied. - */ -class OptimizeGraphProcess : public BaseProcess { -public: - OptimizeGraphProcess(); - ~OptimizeGraphProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** @brief Add a list of node names to be locked and not modified. - * @param in List of nodes. See #AI_CONFIG_PP_OG_EXCLUDE_LIST for - * format explanations. - */ - inline void AddLockedNodeList(std::string& in) { - ConvertListToStrings (in,locked_nodes); - } - - // ------------------------------------------------------------------- - /** @brief Add another node to be locked and not modified. - * @param name Name to be locked - */ - inline void AddLockedNode(std::string& name) { - locked_nodes.push_back(name); - } - - // ------------------------------------------------------------------- - /** @brief Remove a node from the list of locked nodes. - * @param name Name to be unlocked - */ - inline void RemoveLockedNode(std::string& name) { - locked_nodes.remove(name); - } - -protected: - void CollectNewChildren(aiNode* nd, std::list<aiNode*>& nodes); - void FindInstancedMeshes (aiNode* pNode); - -private: -#ifdef AI_OG_USE_HASHING - typedef std::set<unsigned int> LockedSetType; -#else - typedef std::set<std::string> LockedSetType; -#endif - - //! Scene we're working with - aiScene* mScene; - - //! List of locked names. Stored is the hash of the name - LockedSetType locked; - - //! List of nodes to be locked in addition to those with animations, lights or cameras assigned. - std::list<std::string> locked_nodes; - - //! Node counters for logging purposes - unsigned int nodes_in,nodes_out, count_merged; - - //! Reference counters for meshes - std::vector<unsigned int> meshes; -}; - -} // end of namespace Assimp - -#endif // AI_OPTIMIZEGRAPHPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.cpp b/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.cpp deleted file mode 100644 index 3f6765f6ca..0000000000 --- a/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.cpp +++ /dev/null @@ -1,256 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file OptimizeMeshes.cpp - * @brief Implementation of the aiProcess_OptimizeMeshes step - */ - - -#ifndef ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS - - -#include "OptimizeMeshes.h" -#include "ProcessHelper.h" -#include <assimp/SceneCombiner.h> -#include <assimp/Exceptional.h> - -using namespace Assimp; - -static const unsigned int NotSet = 0xffffffff; -static const unsigned int DeadBeef = 0xdeadbeef; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -OptimizeMeshesProcess::OptimizeMeshesProcess() - : mScene() - , pts(false) - , max_verts( NotSet ) - , max_faces( NotSet ) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -OptimizeMeshesProcess::~OptimizeMeshesProcess() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const -{ - // Our behaviour needs to be different if the SortByPType or SplitLargeMeshes - // steps are active. Thus we need to query their flags here and store the - // information, although we're breaking const-correctness. - // That's a serious design flaw, consider redesign. - if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) { - pts = (0 != (pFlags & aiProcess_SortByPType)); - max_verts = ( 0 != ( pFlags & aiProcess_SplitLargeMeshes ) ) ? DeadBeef : max_verts; - return true; - } - return false; -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties for the post-processing step -void OptimizeMeshesProcess::SetupProperties(const Importer* pImp) -{ - if( max_verts == DeadBeef /* magic hack */ ) { - max_faces = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES); - max_verts = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES); - } -} - -// ------------------------------------------------------------------------------------------------ -// Execute step -void OptimizeMeshesProcess::Execute( aiScene* pScene) -{ - const unsigned int num_old = pScene->mNumMeshes; - if (num_old <= 1) { - ASSIMP_LOG_DEBUG("Skipping OptimizeMeshesProcess"); - return; - } - - ASSIMP_LOG_DEBUG("OptimizeMeshesProcess begin"); - mScene = pScene; - - // need to clear persistent members from previous runs - merge_list.resize( 0 ); - output.resize( 0 ); - - // ensure we have the right sizes - merge_list.reserve(pScene->mNumMeshes); - output.reserve(pScene->mNumMeshes); - - // Prepare lookup tables - meshes.resize(pScene->mNumMeshes); - FindInstancedMeshes(pScene->mRootNode); - if( max_verts == DeadBeef ) /* undo the magic hack */ - max_verts = NotSet; - - // ... instanced meshes are immediately processed and added to the output list - for (unsigned int i = 0, n = 0; i < pScene->mNumMeshes;++i) { - meshes[i].vertex_format = GetMeshVFormatUnique(pScene->mMeshes[i]); - - if (meshes[i].instance_cnt > 1 && meshes[i].output_id == NotSet ) { - meshes[i].output_id = n++; - output.push_back(mScene->mMeshes[i]); - } - } - - // and process all nodes in the scenegraph recursively - ProcessNode(pScene->mRootNode); - if (!output.size()) { - throw DeadlyImportError("OptimizeMeshes: No meshes remaining; there's definitely something wrong"); - } - - meshes.resize( 0 ); - ai_assert(output.size() <= num_old); - - mScene->mNumMeshes = static_cast<unsigned int>(output.size()); - std::copy(output.begin(),output.end(),mScene->mMeshes); - - if (output.size() != num_old) { - ASSIMP_LOG_DEBUG_F("OptimizeMeshesProcess finished. Input meshes: ", num_old, ", Output meshes: ", pScene->mNumMeshes); - } else { - ASSIMP_LOG_DEBUG( "OptimizeMeshesProcess finished" ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Process meshes for a single node -void OptimizeMeshesProcess::ProcessNode( aiNode* pNode) -{ - for (unsigned int i = 0; i < pNode->mNumMeshes;++i) { - unsigned int& im = pNode->mMeshes[i]; - - if (meshes[im].instance_cnt > 1) { - im = meshes[im].output_id; - } - else { - merge_list.resize( 0 ); - unsigned int verts = 0, faces = 0; - - // Find meshes to merge with us - for (unsigned int a = i+1; a < pNode->mNumMeshes;++a) { - unsigned int am = pNode->mMeshes[a]; - if (meshes[am].instance_cnt == 1 && CanJoin(im,am,verts,faces)) { - - merge_list.push_back(mScene->mMeshes[am]); - verts += mScene->mMeshes[am]->mNumVertices; - faces += mScene->mMeshes[am]->mNumFaces; - - pNode->mMeshes[a] = pNode->mMeshes[pNode->mNumMeshes - 1]; - --pNode->mNumMeshes; - --a; - } - } - - // and merge all meshes which we found, replace the old ones - if (!merge_list.empty()) { - merge_list.push_back(mScene->mMeshes[im]); - - aiMesh* out; - SceneCombiner::MergeMeshes(&out,0,merge_list.begin(),merge_list.end()); - output.push_back(out); - } else { - output.push_back(mScene->mMeshes[im]); - } - im = static_cast<unsigned int>(output.size()-1); - } - } - - - for( unsigned int i = 0; i < pNode->mNumChildren; ++i ) { - ProcessNode( pNode->mChildren[ i ] ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Check whether two meshes can be joined -bool OptimizeMeshesProcess::CanJoin ( unsigned int a, unsigned int b, unsigned int verts, unsigned int faces ) -{ - if (meshes[a].vertex_format != meshes[b].vertex_format) - return false; - - aiMesh* ma = mScene->mMeshes[a], *mb = mScene->mMeshes[b]; - - if ((NotSet != max_verts && verts+mb->mNumVertices > max_verts) || - (NotSet != max_faces && faces+mb->mNumFaces > max_faces)) { - return false; - } - - // Never merge unskinned meshes with skinned meshes - if (ma->mMaterialIndex != mb->mMaterialIndex || ma->HasBones() != mb->HasBones()) - return false; - - // Never merge meshes with different kinds of primitives if SortByPType did already - // do its work. We would destroy everything again ... - if (pts && ma->mPrimitiveTypes != mb->mPrimitiveTypes) - return false; - - // If both meshes are skinned, check whether we have many bones defined in both meshes. - // If yes, we can join them. - if (ma->HasBones()) { - // TODO - return false; - } - return true; -} - -// ------------------------------------------------------------------------------------------------ -// Build a LUT of all instanced meshes -void OptimizeMeshesProcess::FindInstancedMeshes (aiNode* pNode) -{ - for( unsigned int i = 0; i < pNode->mNumMeshes; ++i ) { - ++meshes[ pNode->mMeshes[ i ] ].instance_cnt; - } - - for( unsigned int i = 0; i < pNode->mNumChildren; ++i ) { - FindInstancedMeshes( pNode->mChildren[ i ] ); - } -} - -// ------------------------------------------------------------------------------------------------ - -#endif // !! ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.h b/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.h deleted file mode 100644 index dec4ab52de..0000000000 --- a/thirdparty/assimp/code/PostProcessing/OptimizeMeshes.h +++ /dev/null @@ -1,186 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file OptimizeMeshes.h - * @brief Declares a post processing step to join meshes, if possible - */ -#ifndef AI_OPTIMIZEMESHESPROCESS_H_INC -#define AI_OPTIMIZEMESHESPROCESS_H_INC - -#include "Common/BaseProcess.h" - -#include <assimp/types.h> - -#include <vector> - -struct aiMesh; -struct aiNode; -class OptimizeMeshesProcessTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** @brief Postprocessing step to optimize mesh usage - * - * The implementation looks for meshes that could be joined and joins them. - * Usually this will reduce the number of drawcalls. - * - * @note Instanced meshes are currently not processed. - */ -class OptimizeMeshesProcess : public BaseProcess { -public: - /// @brief The class constructor. - OptimizeMeshesProcess(); - - /// @brief The class destructor. - ~OptimizeMeshesProcess(); - - /** @brief Internal utility to store additional mesh info - */ - struct MeshInfo { - MeshInfo() AI_NO_EXCEPT - : instance_cnt(0) - , vertex_format(0) - , output_id(0xffffffff) { - // empty - } - - //! Number of times this mesh is referenced - unsigned int instance_cnt; - - //! Vertex format id - unsigned int vertex_format; - - //! Output ID - unsigned int output_id; - }; - -public: - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - - - // ------------------------------------------------------------------- - /** @brief Specify whether you want meshes with different - * primitive types to be merged as well. - * - * IsActive() sets this property automatically to true if the - * aiProcess_SortByPType flag is found. - */ - void EnablePrimitiveTypeSorting(bool enable) { - pts = enable; - } - - // Getter - bool IsPrimitiveTypeSortingEnabled () const { - return pts; - } - - - // ------------------------------------------------------------------- - /** @brief Specify a maximum size of a single output mesh. - * - * If a single input mesh already exceeds this limit, it won't - * be split. - * @param verts Maximum number of vertices per mesh - * @param faces Maximum number of faces per mesh - */ - void SetPreferredMeshSizeLimit (unsigned int verts, unsigned int faces) - { - max_verts = verts; - max_faces = faces; - } - - -protected: - - // ------------------------------------------------------------------- - /** @brief Do the actual optimization on all meshes of this node - * @param pNode Node we're working with - */ - void ProcessNode( aiNode* pNode); - - // ------------------------------------------------------------------- - /** @brief Returns true if b can be joined with a - * - * @param verts Number of output verts up to now - * @param faces Number of output faces up to now - */ - bool CanJoin ( unsigned int a, unsigned int b, - unsigned int verts, unsigned int faces ); - - // ------------------------------------------------------------------- - /** @brief Find instanced meshes, for the moment we're excluding - * them from all optimizations - */ - void FindInstancedMeshes (aiNode* pNode); - -private: - - //! Scene we're working with - aiScene* mScene; - - //! Per mesh info - std::vector<MeshInfo> meshes; - - //! Output meshes - std::vector<aiMesh*> output; - - //! @see EnablePrimitiveTypeSorting - mutable bool pts; - - //! @see SetPreferredMeshSizeLimit - mutable unsigned int max_verts,max_faces; - - //! Temporary storage - std::vector<aiMesh*> merge_list; -}; - -} // end of namespace Assimp - -#endif // AI_CALCTANGENTSPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/PretransformVertices.cpp b/thirdparty/assimp/code/PostProcessing/PretransformVertices.cpp deleted file mode 100644 index 52001a0578..0000000000 --- a/thirdparty/assimp/code/PostProcessing/PretransformVertices.cpp +++ /dev/null @@ -1,728 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file PretransformVertices.cpp - * @brief Implementation of the "PretransformVertices" post processing step -*/ - - -#include "PretransformVertices.h" -#include "ProcessHelper.h" -#include <assimp/SceneCombiner.h> -#include <assimp/Exceptional.h> - -using namespace Assimp; - -// some array offsets -#define AI_PTVS_VERTEX 0x0 -#define AI_PTVS_FACE 0x1 - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -PretransformVertices::PretransformVertices() -: configKeepHierarchy (false) -, configNormalize(false) -, configTransform(false) -, configTransformation() -, mConfigPointCloud( false ) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -PretransformVertices::~PretransformVertices() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool PretransformVertices::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_PreTransformVertices) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Setup import configuration -void PretransformVertices::SetupProperties(const Importer* pImp) -{ - // Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE, - // AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION - configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0)); - configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0)); - configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION,0)); - - configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4()); - - mConfigPointCloud = pImp->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS); -} - -// ------------------------------------------------------------------------------------------------ -// Count the number of nodes -unsigned int PretransformVertices::CountNodes( aiNode* pcNode ) -{ - unsigned int iRet = 1; - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) - { - iRet += CountNodes(pcNode->mChildren[i]); - } - return iRet; -} - -// ------------------------------------------------------------------------------------------------ -// Get a bitwise combination identifying the vertex format of a mesh -unsigned int PretransformVertices::GetMeshVFormat( aiMesh* pcMesh ) -{ - // the vertex format is stored in aiMesh::mBones for later retrieval. - // there isn't a good reason to compute it a few hundred times - // from scratch. The pointer is unused as animations are lost - // during PretransformVertices. - if (pcMesh->mBones) - return (unsigned int)(uint64_t)pcMesh->mBones; - - - const unsigned int iRet = GetMeshVFormatUnique(pcMesh); - - // store the value for later use - pcMesh->mBones = (aiBone**)(uint64_t)iRet; - return iRet; -} - -// ------------------------------------------------------------------------------------------------ -// Count the number of vertices in the whole scene and a given -// material index -void PretransformVertices::CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, - unsigned int iVFormat, unsigned int* piFaces, unsigned int* piVertices) -{ - for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) - { - aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ]; - if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) - { - *piVertices += pcMesh->mNumVertices; - *piFaces += pcMesh->mNumFaces; - } - } - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) - { - CountVerticesAndFaces(pcScene,pcNode->mChildren[i],iMat, - iVFormat,piFaces,piVertices); - } -} - -// ------------------------------------------------------------------------------------------------ -// Collect vertex/face data -void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsigned int iMat, - unsigned int iVFormat, aiMesh* pcMeshOut, - unsigned int aiCurrent[2], unsigned int* num_refs) -{ - // No need to multiply if there's no transformation - const bool identity = pcNode->mTransformation.IsIdentity(); - for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) - { - aiMesh* pcMesh = pcScene->mMeshes[ pcNode->mMeshes[i] ]; - if (iMat == pcMesh->mMaterialIndex && iVFormat == GetMeshVFormat(pcMesh)) - { - // Decrement mesh reference counter - unsigned int& num_ref = num_refs[pcNode->mMeshes[i]]; - ai_assert(0 != num_ref); - --num_ref; - // Save the name of the last mesh - if (num_ref==0) - { - pcMeshOut->mName = pcMesh->mName; - } - - if (identity) { - // copy positions without modifying them - ::memcpy(pcMeshOut->mVertices + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mVertices, - pcMesh->mNumVertices * sizeof(aiVector3D)); - - if (iVFormat & 0x2) { - // copy normals without modifying them - ::memcpy(pcMeshOut->mNormals + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mNormals, - pcMesh->mNumVertices * sizeof(aiVector3D)); - } - if (iVFormat & 0x4) - { - // copy tangents without modifying them - ::memcpy(pcMeshOut->mTangents + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mTangents, - pcMesh->mNumVertices * sizeof(aiVector3D)); - // copy bitangents without modifying them - ::memcpy(pcMeshOut->mBitangents + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mBitangents, - pcMesh->mNumVertices * sizeof(aiVector3D)); - } - } - else - { - // copy positions, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mVertices[aiCurrent[AI_PTVS_VERTEX]+n] = pcNode->mTransformation * pcMesh->mVertices[n]; - } - aiMatrix4x4 mWorldIT = pcNode->mTransformation; - mWorldIT.Inverse().Transpose(); - - // TODO: implement Inverse() for aiMatrix3x3 - aiMatrix3x3 m = aiMatrix3x3(mWorldIT); - - if (iVFormat & 0x2) - { - // copy normals, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mNormals[aiCurrent[AI_PTVS_VERTEX]+n] = - (m * pcMesh->mNormals[n]).Normalize(); - } - } - if (iVFormat & 0x4) - { - // copy tangents and bitangents, transform them to worldspace - for (unsigned int n = 0; n < pcMesh->mNumVertices;++n) { - pcMeshOut->mTangents [aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mTangents[n]).Normalize(); - pcMeshOut->mBitangents[aiCurrent[AI_PTVS_VERTEX]+n] = (m * pcMesh->mBitangents[n]).Normalize(); - } - } - } - unsigned int p = 0; - while (iVFormat & (0x100 << p)) - { - // copy texture coordinates - memcpy(pcMeshOut->mTextureCoords[p] + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mTextureCoords[p], - pcMesh->mNumVertices * sizeof(aiVector3D)); - ++p; - } - p = 0; - while (iVFormat & (0x1000000 << p)) - { - // copy vertex colors - memcpy(pcMeshOut->mColors[p] + aiCurrent[AI_PTVS_VERTEX], - pcMesh->mColors[p], - pcMesh->mNumVertices * sizeof(aiColor4D)); - ++p; - } - // now we need to copy all faces. since we will delete the source mesh afterwards, - // we don't need to reallocate the array of indices except if this mesh is - // referenced multiple times. - for (unsigned int planck = 0;planck < pcMesh->mNumFaces;++planck) - { - aiFace& f_src = pcMesh->mFaces[planck]; - aiFace& f_dst = pcMeshOut->mFaces[aiCurrent[AI_PTVS_FACE]+planck]; - - const unsigned int num_idx = f_src.mNumIndices; - - f_dst.mNumIndices = num_idx; - - unsigned int* pi; - if (!num_ref) { /* if last time the mesh is referenced -> no reallocation */ - pi = f_dst.mIndices = f_src.mIndices; - - // offset all vertex indices - for (unsigned int hahn = 0; hahn < num_idx;++hahn){ - pi[hahn] += aiCurrent[AI_PTVS_VERTEX]; - } - } - else { - pi = f_dst.mIndices = new unsigned int[num_idx]; - - // copy and offset all vertex indices - for (unsigned int hahn = 0; hahn < num_idx;++hahn){ - pi[hahn] = f_src.mIndices[hahn] + aiCurrent[AI_PTVS_VERTEX]; - } - } - - // Update the mPrimitiveTypes member of the mesh - switch (pcMesh->mFaces[planck].mNumIndices) - { - case 0x1: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 0x2: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 0x3: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - pcMeshOut->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - }; - } - aiCurrent[AI_PTVS_VERTEX] += pcMesh->mNumVertices; - aiCurrent[AI_PTVS_FACE] += pcMesh->mNumFaces; - } - } - - // append all children of us - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) { - CollectData(pcScene,pcNode->mChildren[i],iMat, - iVFormat,pcMeshOut,aiCurrent,num_refs); - } -} - -// ------------------------------------------------------------------------------------------------ -// Get a list of all vertex formats that occur for a given material index -// The output list contains duplicate elements -void PretransformVertices::GetVFormatList( aiScene* pcScene, unsigned int iMat, - std::list<unsigned int>& aiOut) -{ - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) - { - aiMesh* pcMesh = pcScene->mMeshes[ i ]; - if (iMat == pcMesh->mMaterialIndex) { - aiOut.push_back(GetMeshVFormat(pcMesh)); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Compute the absolute transformation matrices of each node -void PretransformVertices::ComputeAbsoluteTransform( aiNode* pcNode ) -{ - if (pcNode->mParent) { - pcNode->mTransformation = pcNode->mParent->mTransformation*pcNode->mTransformation; - } - - for (unsigned int i = 0;i < pcNode->mNumChildren;++i) { - ComputeAbsoluteTransform(pcNode->mChildren[i]); - } -} - -// ------------------------------------------------------------------------------------------------ -// Apply the node transformation to a mesh -void PretransformVertices::ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat) -{ - // Check whether we need to transform the coordinates at all - if (!mat.IsIdentity()) { - - if (mesh->HasPositions()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mVertices[i] = mat * mesh->mVertices[i]; - } - } - if (mesh->HasNormals() || mesh->HasTangentsAndBitangents()) { - aiMatrix4x4 mWorldIT = mat; - mWorldIT.Inverse().Transpose(); - - // TODO: implement Inverse() for aiMatrix3x3 - aiMatrix3x3 m = aiMatrix3x3(mWorldIT); - - if (mesh->HasNormals()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mNormals[i] = (m * mesh->mNormals[i]).Normalize(); - } - } - if (mesh->HasTangentsAndBitangents()) { - for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { - mesh->mTangents[i] = (m * mesh->mTangents[i]).Normalize(); - mesh->mBitangents[i] = (m * mesh->mBitangents[i]).Normalize(); - } - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Simple routine to build meshes in worldspace, no further optimization -void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in, - unsigned int numIn, aiNode* node) -{ - // NOTE: - // aiMesh::mNumBones store original source mesh, or UINT_MAX if not a copy - // aiMesh::mBones store reference to abs. transform we multiplied with - - // process meshes - for (unsigned int i = 0; i < node->mNumMeshes;++i) { - aiMesh* mesh = in[node->mMeshes[i]]; - - // check whether we can operate on this mesh - if (!mesh->mBones || *reinterpret_cast<aiMatrix4x4*>(mesh->mBones) == node->mTransformation) { - // yes, we can. - mesh->mBones = reinterpret_cast<aiBone**> (&node->mTransformation); - mesh->mNumBones = UINT_MAX; - } - else { - - // try to find us in the list of newly created meshes - for (unsigned int n = 0; n < out.size(); ++n) { - aiMesh* ctz = out[n]; - if (ctz->mNumBones == node->mMeshes[i] && *reinterpret_cast<aiMatrix4x4*>(ctz->mBones) == node->mTransformation) { - - // ok, use this one. Update node mesh index - node->mMeshes[i] = numIn + n; - } - } - if (node->mMeshes[i] < numIn) { - // Worst case. Need to operate on a full copy of the mesh - ASSIMP_LOG_INFO("PretransformVertices: Copying mesh due to mismatching transforms"); - aiMesh* ntz; - - const unsigned int tmp = mesh->mNumBones; // - mesh->mNumBones = 0; - SceneCombiner::Copy(&ntz,mesh); - mesh->mNumBones = tmp; - - ntz->mNumBones = node->mMeshes[i]; - ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation); - - out.push_back(ntz); - - node->mMeshes[i] = static_cast<unsigned int>(numIn + out.size() - 1); - } - } - } - - // call children - for (unsigned int i = 0; i < node->mNumChildren;++i) - BuildWCSMeshes(out,in,numIn,node->mChildren[i]); -} - -// ------------------------------------------------------------------------------------------------ -// Reset transformation matrices to identity -void PretransformVertices::MakeIdentityTransform(aiNode* nd) -{ - nd->mTransformation = aiMatrix4x4(); - - // call children - for (unsigned int i = 0; i < nd->mNumChildren;++i) - MakeIdentityTransform(nd->mChildren[i]); -} - -// ------------------------------------------------------------------------------------------------ -// Build reference counters for all meshes -void PretransformVertices::BuildMeshRefCountArray(aiNode* nd, unsigned int * refs) -{ - for (unsigned int i = 0; i< nd->mNumMeshes;++i) - refs[nd->mMeshes[i]]++; - - // call children - for (unsigned int i = 0; i < nd->mNumChildren;++i) - BuildMeshRefCountArray(nd->mChildren[i],refs); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void PretransformVertices::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("PretransformVerticesProcess begin"); - - // Return immediately if we have no meshes - if (!pScene->mNumMeshes) - return; - - const unsigned int iOldMeshes = pScene->mNumMeshes; - const unsigned int iOldAnimationChannels = pScene->mNumAnimations; - const unsigned int iOldNodes = CountNodes(pScene->mRootNode); - - if(configTransform) { - pScene->mRootNode->mTransformation = configTransformation; - } - - // first compute absolute transformation matrices for all nodes - ComputeAbsoluteTransform(pScene->mRootNode); - - // Delete aiMesh::mBones for all meshes. The bones are - // removed during this step and we need the pointer as - // temporary storage - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { - aiMesh* mesh = pScene->mMeshes[i]; - - for (unsigned int a = 0; a < mesh->mNumBones;++a) - delete mesh->mBones[a]; - - delete[] mesh->mBones; - mesh->mBones = NULL; - } - - // now build a list of output meshes - std::vector<aiMesh*> apcOutMeshes; - - // Keep scene hierarchy? It's an easy job in this case ... - // we go on and transform all meshes, if one is referenced by nodes - // with different absolute transformations a depth copy of the mesh - // is required. - if( configKeepHierarchy ) { - - // Hack: store the matrix we're transforming a mesh with in aiMesh::mBones - BuildWCSMeshes(apcOutMeshes,pScene->mMeshes,pScene->mNumMeshes, pScene->mRootNode); - - // ... if new meshes have been generated, append them to the end of the scene - if (apcOutMeshes.size() > 0) { - aiMesh** npp = new aiMesh*[pScene->mNumMeshes + apcOutMeshes.size()]; - - memcpy(npp,pScene->mMeshes,sizeof(aiMesh*)*pScene->mNumMeshes); - memcpy(npp+pScene->mNumMeshes,&apcOutMeshes[0],sizeof(aiMesh*)*apcOutMeshes.size()); - - pScene->mNumMeshes += static_cast<unsigned int>(apcOutMeshes.size()); - delete[] pScene->mMeshes; pScene->mMeshes = npp; - } - - // now iterate through all meshes and transform them to worldspace - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - ApplyTransform(pScene->mMeshes[i],*reinterpret_cast<aiMatrix4x4*>( pScene->mMeshes[i]->mBones )); - - // prevent improper destruction - pScene->mMeshes[i]->mBones = NULL; - pScene->mMeshes[i]->mNumBones = 0; - } - } else { - apcOutMeshes.reserve(pScene->mNumMaterials<<1u); - std::list<unsigned int> aiVFormats; - - std::vector<unsigned int> s(pScene->mNumMeshes,0); - BuildMeshRefCountArray(pScene->mRootNode,&s[0]); - - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - // get the list of all vertex formats for this material - aiVFormats.clear(); - GetVFormatList(pScene,i,aiVFormats); - aiVFormats.sort(); - aiVFormats.unique(); - for (std::list<unsigned int>::const_iterator j = aiVFormats.begin();j != aiVFormats.end();++j) { - unsigned int iVertices = 0; - unsigned int iFaces = 0; - CountVerticesAndFaces(pScene,pScene->mRootNode,i,*j,&iFaces,&iVertices); - if (0 != iFaces && 0 != iVertices) - { - apcOutMeshes.push_back(new aiMesh()); - aiMesh* pcMesh = apcOutMeshes.back(); - pcMesh->mNumFaces = iFaces; - pcMesh->mNumVertices = iVertices; - pcMesh->mFaces = new aiFace[iFaces]; - pcMesh->mVertices = new aiVector3D[iVertices]; - pcMesh->mMaterialIndex = i; - if ((*j) & 0x2)pcMesh->mNormals = new aiVector3D[iVertices]; - if ((*j) & 0x4) - { - pcMesh->mTangents = new aiVector3D[iVertices]; - pcMesh->mBitangents = new aiVector3D[iVertices]; - } - iFaces = 0; - while ((*j) & (0x100 << iFaces)) - { - pcMesh->mTextureCoords[iFaces] = new aiVector3D[iVertices]; - if ((*j) & (0x10000 << iFaces))pcMesh->mNumUVComponents[iFaces] = 3; - else pcMesh->mNumUVComponents[iFaces] = 2; - iFaces++; - } - iFaces = 0; - while ((*j) & (0x1000000 << iFaces)) - pcMesh->mColors[iFaces++] = new aiColor4D[iVertices]; - - // fill the mesh ... - unsigned int aiTemp[2] = {0,0}; - CollectData(pScene,pScene->mRootNode,i,*j,pcMesh,aiTemp,&s[0]); - } - } - } - - // If no meshes are referenced in the node graph it is possible that we get no output meshes. - if (apcOutMeshes.empty()) { - - throw DeadlyImportError("No output meshes: all meshes are orphaned and are not referenced by any nodes"); - } - else - { - // now delete all meshes in the scene and build a new mesh list - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { - aiMesh* mesh = pScene->mMeshes[i]; - mesh->mNumBones = 0; - mesh->mBones = NULL; - - // we're reusing the face index arrays. avoid destruction - for (unsigned int a = 0; a < mesh->mNumFaces; ++a) { - mesh->mFaces[a].mNumIndices = 0; - mesh->mFaces[a].mIndices = NULL; - } - - delete mesh; - - // Invalidate the contents of the old mesh array. We will most - // likely have less output meshes now, so the last entries of - // the mesh array are not overridden. We set them to NULL to - // make sure the developer gets notified when his application - // attempts to access these fields ... - mesh = NULL; - } - - // It is impossible that we have more output meshes than - // input meshes, so we can easily reuse the old mesh array - pScene->mNumMeshes = (unsigned int)apcOutMeshes.size(); - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { - pScene->mMeshes[i] = apcOutMeshes[i]; - } - } - } - - // remove all animations from the scene - for (unsigned int i = 0; i < pScene->mNumAnimations;++i) - delete pScene->mAnimations[i]; - delete[] pScene->mAnimations; - - pScene->mAnimations = NULL; - pScene->mNumAnimations = 0; - - // --- we need to keep all cameras and lights - for (unsigned int i = 0; i < pScene->mNumCameras;++i) - { - aiCamera* cam = pScene->mCameras[i]; - const aiNode* nd = pScene->mRootNode->FindNode(cam->mName); - ai_assert(NULL != nd); - - // multiply all properties of the camera with the absolute - // transformation of the corresponding node - cam->mPosition = nd->mTransformation * cam->mPosition; - cam->mLookAt = aiMatrix3x3( nd->mTransformation ) * cam->mLookAt; - cam->mUp = aiMatrix3x3( nd->mTransformation ) * cam->mUp; - } - - for (unsigned int i = 0; i < pScene->mNumLights;++i) - { - aiLight* l = pScene->mLights[i]; - const aiNode* nd = pScene->mRootNode->FindNode(l->mName); - ai_assert(NULL != nd); - - // multiply all properties of the camera with the absolute - // transformation of the corresponding node - l->mPosition = nd->mTransformation * l->mPosition; - l->mDirection = aiMatrix3x3( nd->mTransformation ) * l->mDirection; - l->mUp = aiMatrix3x3( nd->mTransformation ) * l->mUp; - } - - if( !configKeepHierarchy ) { - - // now delete all nodes in the scene and build a new - // flat node graph with a root node and some level 1 children - aiNode* newRoot = new aiNode(); - newRoot->mName = pScene->mRootNode->mName; - delete pScene->mRootNode; - pScene->mRootNode = newRoot; - - if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) - { - pScene->mRootNode->mNumMeshes = 1; - pScene->mRootNode->mMeshes = new unsigned int[1]; - pScene->mRootNode->mMeshes[0] = 0; - } - else - { - pScene->mRootNode->mNumChildren = pScene->mNumMeshes+pScene->mNumLights+pScene->mNumCameras; - aiNode** nodes = pScene->mRootNode->mChildren = new aiNode*[pScene->mRootNode->mNumChildren]; - - // generate mesh nodes - for (unsigned int i = 0; i < pScene->mNumMeshes;++i,++nodes) - { - aiNode* pcNode = new aiNode(); - *nodes = pcNode; - pcNode->mParent = pScene->mRootNode; - pcNode->mName = pScene->mMeshes[i]->mName; - - // setup mesh indices - pcNode->mNumMeshes = 1; - pcNode->mMeshes = new unsigned int[1]; - pcNode->mMeshes[0] = i; - } - // generate light nodes - for (unsigned int i = 0; i < pScene->mNumLights;++i,++nodes) - { - aiNode* pcNode = new aiNode(); - *nodes = pcNode; - pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ai_snprintf(pcNode->mName.data, MAXLEN, "light_%u",i); - pScene->mLights[i]->mName = pcNode->mName; - } - // generate camera nodes - for (unsigned int i = 0; i < pScene->mNumCameras;++i,++nodes) - { - aiNode* pcNode = new aiNode(); - *nodes = pcNode; - pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"cam_%u",i); - pScene->mCameras[i]->mName = pcNode->mName; - } - } - } - else { - // ... and finally set the transformation matrix of all nodes to identity - MakeIdentityTransform(pScene->mRootNode); - } - - if (configNormalize) { - // compute the boundary of all meshes - aiVector3D min,max; - MinMaxChooser<aiVector3D> ()(min,max); - - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - aiMesh* m = pScene->mMeshes[a]; - for (unsigned int i = 0; i < m->mNumVertices;++i) { - min = std::min(m->mVertices[i],min); - max = std::max(m->mVertices[i],max); - } - } - - // find the dominant axis - aiVector3D d = max-min; - const ai_real div = std::max(d.x,std::max(d.y,d.z))*ai_real( 0.5); - - d = min + d * (ai_real)0.5; - for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - aiMesh* m = pScene->mMeshes[a]; - for (unsigned int i = 0; i < m->mNumVertices;++i) { - m->mVertices[i] = (m->mVertices[i]-d)/div; - } - } - } - - // print statistics - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_DEBUG("PretransformVerticesProcess finished"); - - ASSIMP_LOG_INFO_F("Removed ", iOldNodes, " nodes and ", iOldAnimationChannels, " animation channels (", - CountNodes(pScene->mRootNode) ," output nodes)" ); - ASSIMP_LOG_INFO_F("Kept ", pScene->mNumLights, " lights and ", pScene->mNumCameras, " cameras." ); - ASSIMP_LOG_INFO_F("Moved ", iOldMeshes, " meshes to WCS (number of output meshes: ", pScene->mNumMeshes, ")"); - } -} diff --git a/thirdparty/assimp/code/PostProcessing/PretransformVertices.h b/thirdparty/assimp/code/PostProcessing/PretransformVertices.h deleted file mode 100644 index b2982951e0..0000000000 --- a/thirdparty/assimp/code/PostProcessing/PretransformVertices.h +++ /dev/null @@ -1,166 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file PretransformVertices.h - * @brief Defines a post processing step to pretransform all - * vertices in the scenegraph - */ -#ifndef AI_PRETRANSFORMVERTICES_H_INC -#define AI_PRETRANSFORMVERTICES_H_INC - -#include "Common/BaseProcess.h" - -#include <assimp/mesh.h> - -#include <list> -#include <vector> - -// Forward declarations -struct aiNode; - -class PretransformVerticesTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The PretransformVertices pre-transforms all vertices in the node tree - * and removes the whole graph. The output is a list of meshes, one for - * each material. -*/ -class ASSIMP_API PretransformVertices : public BaseProcess { -public: - PretransformVertices (); - ~PretransformVertices (); - - // ------------------------------------------------------------------- - // Check whether step is active - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Execute step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** @brief Toggle the 'keep hierarchy' option - * @param keep true for keep configuration. - */ - void KeepHierarchy(bool keep) { - configKeepHierarchy = keep; - } - - // ------------------------------------------------------------------- - /** @brief Check whether 'keep hierarchy' is currently enabled. - * @return ... - */ - bool IsHierarchyKept() const { - return configKeepHierarchy; - } - -private: - // ------------------------------------------------------------------- - // Count the number of nodes - unsigned int CountNodes( aiNode* pcNode ); - - // ------------------------------------------------------------------- - // Get a bitwise combination identifying the vertex format of a mesh - unsigned int GetMeshVFormat(aiMesh* pcMesh); - - // ------------------------------------------------------------------- - // Count the number of vertices in the whole scene and a given - // material index - void CountVerticesAndFaces( aiScene* pcScene, aiNode* pcNode, - unsigned int iMat, - unsigned int iVFormat, - unsigned int* piFaces, - unsigned int* piVertices); - - // ------------------------------------------------------------------- - // Collect vertex/face data - void CollectData( aiScene* pcScene, aiNode* pcNode, - unsigned int iMat, - unsigned int iVFormat, - aiMesh* pcMeshOut, - unsigned int aiCurrent[2], - unsigned int* num_refs); - - // ------------------------------------------------------------------- - // Get a list of all vertex formats that occur for a given material - // The output list contains duplicate elements - void GetVFormatList( aiScene* pcScene, unsigned int iMat, - std::list<unsigned int>& aiOut); - - // ------------------------------------------------------------------- - // Compute the absolute transformation matrices of each node - void ComputeAbsoluteTransform( aiNode* pcNode ); - - // ------------------------------------------------------------------- - // Simple routine to build meshes in worldspace, no further optimization - void BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in, - unsigned int numIn, aiNode* node); - - // ------------------------------------------------------------------- - // Apply the node transformation to a mesh - void ApplyTransform(aiMesh* mesh, const aiMatrix4x4& mat); - - // ------------------------------------------------------------------- - // Reset transformation matrices to identity - void MakeIdentityTransform(aiNode* nd); - - // ------------------------------------------------------------------- - // Build reference counters for all meshes - void BuildMeshRefCountArray(aiNode* nd, unsigned int * refs); - - //! Configuration option: keep scene hierarchy as long as possible - bool configKeepHierarchy; - bool configNormalize; - bool configTransform; - aiMatrix4x4 configTransformation; - bool mConfigPointCloud; -}; - -} // end of namespace Assimp - -#endif // !!AI_GENFACENORMALPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ProcessHelper.cpp b/thirdparty/assimp/code/PostProcessing/ProcessHelper.cpp deleted file mode 100644 index 59869fdff7..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ProcessHelper.cpp +++ /dev/null @@ -1,443 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/// @file ProcessHelper.cpp -/** Implement shared utility functions for postprocessing steps */ - - -#include "ProcessHelper.h" - - -#include <limits> - -namespace Assimp { - -// ------------------------------------------------------------------------------- -void ConvertListToStrings(const std::string& in, std::list<std::string>& out) -{ - const char* s = in.c_str(); - while (*s) { - SkipSpacesAndLineEnd(&s); - if (*s == '\'') { - const char* base = ++s; - while (*s != '\'') { - ++s; - if (*s == '\0') { - ASSIMP_LOG_ERROR("ConvertListToString: String list is ill-formatted"); - return; - } - } - out.push_back(std::string(base,(size_t)(s-base))); - ++s; - } - else { - out.push_back(GetNextToken(s)); - } - } -} - -// ------------------------------------------------------------------------------- -void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max, - const aiMatrix4x4& m) -{ - min = aiVector3D ( ai_real( 10e10 ), ai_real( 10e10 ), ai_real( 10e10 ) ); - max = aiVector3D ( ai_real( -10e10 ), ai_real( -10e10 ), ai_real( -10e10 ) ); - for (unsigned int i = 0;i < mesh->mNumVertices;++i) - { - const aiVector3D v = m * mesh->mVertices[i]; - min = std::min(v,min); - max = std::max(v,max); - } -} - -// ------------------------------------------------------------------------------- -void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max) -{ - ArrayBounds(mesh->mVertices,mesh->mNumVertices, min,max); - out = min + (max-min)*(ai_real)0.5; -} - -// ------------------------------------------------------------------------------- -void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector3D& max) { - if ( NULL == scene ) { - return; - } - - if ( 0 == scene->mNumMeshes ) { - return; - } - FindMeshCenter(scene->mMeshes[0], out, min, max); - for (unsigned int i = 1; i < scene->mNumMeshes; ++i) { - aiVector3D tout, tmin, tmax; - FindMeshCenter(scene->mMeshes[i], tout, tmin, tmax); - if (min[0] > tmin[0]) min[0] = tmin[0]; - if (min[1] > tmin[1]) min[1] = tmin[1]; - if (min[2] > tmin[2]) min[2] = tmin[2]; - if (max[0] < tmax[0]) max[0] = tmax[0]; - if (max[1] < tmax[1]) max[1] = tmax[1]; - if (max[2] < tmax[2]) max[2] = tmax[2]; - } - out = min + (max-min)*(ai_real)0.5; -} - - -// ------------------------------------------------------------------------------- -void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min, - aiVector3D& max, const aiMatrix4x4& m) -{ - FindAABBTransformed(mesh,min,max,m); - out = min + (max-min)*(ai_real)0.5; -} - -// ------------------------------------------------------------------------------- -void FindMeshCenter (aiMesh* mesh, aiVector3D& out) -{ - aiVector3D min,max; - FindMeshCenter(mesh,out,min,max); -} - -// ------------------------------------------------------------------------------- -void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, - const aiMatrix4x4& m) -{ - aiVector3D min,max; - FindMeshCenterTransformed(mesh,out,min,max,m); -} - -// ------------------------------------------------------------------------------- -ai_real ComputePositionEpsilon(const aiMesh* pMesh) -{ - const ai_real epsilon = ai_real( 1e-4 ); - - // calculate the position bounds so we have a reliable epsilon to check position differences against - aiVector3D minVec, maxVec; - ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,minVec,maxVec); - return (maxVec - minVec).Length() * epsilon; -} - -// ------------------------------------------------------------------------------- -ai_real ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num) -{ - ai_assert( NULL != pMeshes ); - - const ai_real epsilon = ai_real( 1e-4 ); - - // calculate the position bounds so we have a reliable epsilon to check position differences against - aiVector3D minVec, maxVec, mi, ma; - MinMaxChooser<aiVector3D>()(minVec,maxVec); - - for (size_t a = 0; a < num; ++a) { - const aiMesh* pMesh = pMeshes[a]; - ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,mi,ma); - - minVec = std::min(minVec,mi); - maxVec = std::max(maxVec,ma); - } - return (maxVec - minVec).Length() * epsilon; -} - - -// ------------------------------------------------------------------------------- -unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh) -{ - ai_assert(NULL != pcMesh); - - // FIX: the hash may never be 0. Otherwise a comparison against - // nullptr could be successful - unsigned int iRet = 1; - - // normals - if (pcMesh->HasNormals())iRet |= 0x2; - // tangents and bitangents - if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4; - -#ifdef BOOST_STATIC_ASSERT - BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS); - BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_TEXTURECOORDS); -#endif - - // texture coordinates - unsigned int p = 0; - while (pcMesh->HasTextureCoords(p)) - { - iRet |= (0x100 << p); - if (3 == pcMesh->mNumUVComponents[p]) - iRet |= (0x10000 << p); - - ++p; - } - // vertex colors - p = 0; - while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++); - return iRet; -} - -// ------------------------------------------------------------------------------- -VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) -{ - if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) { - return NULL; - } - - VertexWeightTable* avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices]; - for (unsigned int i = 0; i < pMesh->mNumBones;++i) { - - aiBone* bone = pMesh->mBones[i]; - for (unsigned int a = 0; a < bone->mNumWeights;++a) { - const aiVertexWeight& weight = bone->mWeights[a]; - avPerVertexWeights[weight.mVertexId].push_back( std::pair<unsigned int,float>(i,weight.mWeight) ); - } - } - return avPerVertexWeights; -} - - -// ------------------------------------------------------------------------------- -const char* TextureTypeToString(aiTextureType in) -{ - switch (in) - { - case aiTextureType_NONE: - return "n/a"; - case aiTextureType_DIFFUSE: - return "Diffuse"; - case aiTextureType_SPECULAR: - return "Specular"; - case aiTextureType_AMBIENT: - return "Ambient"; - case aiTextureType_EMISSIVE: - return "Emissive"; - case aiTextureType_OPACITY: - return "Opacity"; - case aiTextureType_NORMALS: - return "Normals"; - case aiTextureType_HEIGHT: - return "Height"; - case aiTextureType_SHININESS: - return "Shininess"; - case aiTextureType_DISPLACEMENT: - return "Displacement"; - case aiTextureType_LIGHTMAP: - return "Lightmap"; - case aiTextureType_REFLECTION: - return "Reflection"; - case aiTextureType_UNKNOWN: - return "Unknown"; - default: - break; - } - - ai_assert(false); - return "BUG"; -} - -// ------------------------------------------------------------------------------- -const char* MappingTypeToString(aiTextureMapping in) -{ - switch (in) - { - case aiTextureMapping_UV: - return "UV"; - case aiTextureMapping_BOX: - return "Box"; - case aiTextureMapping_SPHERE: - return "Sphere"; - case aiTextureMapping_CYLINDER: - return "Cylinder"; - case aiTextureMapping_PLANE: - return "Plane"; - case aiTextureMapping_OTHER: - return "Other"; - default: - break; - } - - ai_assert(false); - return "BUG"; -} - - -// ------------------------------------------------------------------------------- -aiMesh* MakeSubmesh(const aiMesh *pMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags) -{ - aiMesh *oMesh = new aiMesh(); - std::vector<unsigned int> vMap(pMesh->mNumVertices,UINT_MAX); - - size_t numSubVerts = 0; - size_t numSubFaces = subMeshFaces.size(); - - for(unsigned int i=0;i<numSubFaces;i++) { - const aiFace &f = pMesh->mFaces[subMeshFaces[i]]; - - for(unsigned int j=0;j<f.mNumIndices;j++) { - if(vMap[f.mIndices[j]]==UINT_MAX) { - vMap[f.mIndices[j]] = static_cast<unsigned int>(numSubVerts++); - } - } - } - - oMesh->mName = pMesh->mName; - - oMesh->mMaterialIndex = pMesh->mMaterialIndex; - oMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes; - - // create all the arrays for this mesh if the old mesh contained them - - oMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size()); - oMesh->mNumVertices = static_cast<unsigned int>(numSubVerts); - oMesh->mVertices = new aiVector3D[numSubVerts]; - if( pMesh->HasNormals() ) { - oMesh->mNormals = new aiVector3D[numSubVerts]; - } - - if( pMesh->HasTangentsAndBitangents() ) { - oMesh->mTangents = new aiVector3D[numSubVerts]; - oMesh->mBitangents = new aiVector3D[numSubVerts]; - } - - for( size_t a = 0; pMesh->HasTextureCoords(static_cast<unsigned int>(a)) ; ++a ) { - oMesh->mTextureCoords[a] = new aiVector3D[numSubVerts]; - oMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a]; - } - - for( size_t a = 0; pMesh->HasVertexColors( static_cast<unsigned int>(a)); ++a ) { - oMesh->mColors[a] = new aiColor4D[numSubVerts]; - } - - // and copy over the data, generating faces with linear indices along the way - oMesh->mFaces = new aiFace[numSubFaces]; - - for(unsigned int a = 0; a < numSubFaces; ++a ) { - - const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]]; - aiFace& dstFace = oMesh->mFaces[a]; - dstFace.mNumIndices = srcFace.mNumIndices; - dstFace.mIndices = new unsigned int[dstFace.mNumIndices]; - - // accumulate linearly all the vertices of the source face - for( size_t b = 0; b < dstFace.mNumIndices; ++b ) { - dstFace.mIndices[b] = vMap[srcFace.mIndices[b]]; - } - } - - for(unsigned int srcIndex = 0; srcIndex < pMesh->mNumVertices; ++srcIndex ) { - unsigned int nvi = vMap[srcIndex]; - if(nvi==UINT_MAX) { - continue; - } - - oMesh->mVertices[nvi] = pMesh->mVertices[srcIndex]; - if( pMesh->HasNormals() ) { - oMesh->mNormals[nvi] = pMesh->mNormals[srcIndex]; - } - - if( pMesh->HasTangentsAndBitangents() ) { - oMesh->mTangents[nvi] = pMesh->mTangents[srcIndex]; - oMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex]; - } - for( size_t c = 0, cc = pMesh->GetNumUVChannels(); c < cc; ++c ) { - oMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex]; - } - for( size_t c = 0, cc = pMesh->GetNumColorChannels(); c < cc; ++c ) { - oMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex]; - } - } - - if(~subFlags&AI_SUBMESH_FLAGS_SANS_BONES) { - std::vector<unsigned int> subBones(pMesh->mNumBones,0); - - for(unsigned int a=0;a<pMesh->mNumBones;++a) { - const aiBone* bone = pMesh->mBones[a]; - - for(unsigned int b=0;b<bone->mNumWeights;b++) { - unsigned int v = vMap[bone->mWeights[b].mVertexId]; - - if(v!=UINT_MAX) { - subBones[a]++; - } - } - } - - for(unsigned int a=0;a<pMesh->mNumBones;++a) { - if(subBones[a]>0) { - oMesh->mNumBones++; - } - } - - if(oMesh->mNumBones) { - oMesh->mBones = new aiBone*[oMesh->mNumBones](); - unsigned int nbParanoia = oMesh->mNumBones; - - oMesh->mNumBones = 0; //rewind - - for(unsigned int a=0;a<pMesh->mNumBones;++a) { - if(subBones[a]==0) { - continue; - } - aiBone *newBone = new aiBone; - oMesh->mBones[oMesh->mNumBones++] = newBone; - - const aiBone* bone = pMesh->mBones[a]; - - newBone->mName = bone->mName; - newBone->mOffsetMatrix = bone->mOffsetMatrix; - newBone->mWeights = new aiVertexWeight[subBones[a]]; - - for(unsigned int b=0;b<bone->mNumWeights;b++) { - const unsigned int v = vMap[bone->mWeights[b].mVertexId]; - - if(v!=UINT_MAX) { - aiVertexWeight w(v,bone->mWeights[b].mWeight); - newBone->mWeights[newBone->mNumWeights++] = w; - } - } - } - - ai_assert(nbParanoia==oMesh->mNumBones); - (void)nbParanoia; // remove compiler warning on release build - } - } - - return oMesh; -} - -} // namespace Assimp diff --git a/thirdparty/assimp/code/PostProcessing/ProcessHelper.h b/thirdparty/assimp/code/PostProcessing/ProcessHelper.h deleted file mode 100644 index 0afcc41420..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ProcessHelper.h +++ /dev/null @@ -1,386 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -#ifndef AI_PROCESS_HELPER_H_INCLUDED -#define AI_PROCESS_HELPER_H_INCLUDED - -#include <assimp/postprocess.h> -#include <assimp/anim.h> -#include <assimp/mesh.h> -#include <assimp/material.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/scene.h> - -#include <assimp/SpatialSort.h> -#include "Common/BaseProcess.h" -#include <assimp/ParsingUtils.h> - -#include <list> - -// ------------------------------------------------------------------------------- -// Some extensions to std namespace. Mainly std::min and std::max for all -// flat data types in the aiScene. They're used to quickly determine the -// min/max bounds of data arrays. -#ifdef __cplusplus -namespace std { - - // std::min for aiVector3D - template <typename TReal> - inline ::aiVector3t<TReal> min (const ::aiVector3t<TReal>& a, const ::aiVector3t<TReal>& b) { - return ::aiVector3t<TReal> (min(a.x,b.x),min(a.y,b.y),min(a.z,b.z)); - } - - // std::max for aiVector3t<TReal> - template <typename TReal> - inline ::aiVector3t<TReal> max (const ::aiVector3t<TReal>& a, const ::aiVector3t<TReal>& b) { - return ::aiVector3t<TReal> (max(a.x,b.x),max(a.y,b.y),max(a.z,b.z)); - } - - // std::min for aiVector2t<TReal> - template <typename TReal> - inline ::aiVector2t<TReal> min (const ::aiVector2t<TReal>& a, const ::aiVector2t<TReal>& b) { - return ::aiVector2t<TReal> (min(a.x,b.x),min(a.y,b.y)); - } - - // std::max for aiVector2t<TReal> - template <typename TReal> - inline ::aiVector2t<TReal> max (const ::aiVector2t<TReal>& a, const ::aiVector2t<TReal>& b) { - return ::aiVector2t<TReal> (max(a.x,b.x),max(a.y,b.y)); - } - - // std::min for aiColor4D - template <typename TReal> - inline ::aiColor4t<TReal> min (const ::aiColor4t<TReal>& a, const ::aiColor4t<TReal>& b) { - return ::aiColor4t<TReal> (min(a.r,b.r),min(a.g,b.g),min(a.b,b.b),min(a.a,b.a)); - } - - // std::max for aiColor4D - template <typename TReal> - inline ::aiColor4t<TReal> max (const ::aiColor4t<TReal>& a, const ::aiColor4t<TReal>& b) { - return ::aiColor4t<TReal> (max(a.r,b.r),max(a.g,b.g),max(a.b,b.b),max(a.a,b.a)); - } - - - // std::min for aiQuaterniont<TReal> - template <typename TReal> - inline ::aiQuaterniont<TReal> min (const ::aiQuaterniont<TReal>& a, const ::aiQuaterniont<TReal>& b) { - return ::aiQuaterniont<TReal> (min(a.w,b.w),min(a.x,b.x),min(a.y,b.y),min(a.z,b.z)); - } - - // std::max for aiQuaterniont<TReal> - template <typename TReal> - inline ::aiQuaterniont<TReal> max (const ::aiQuaterniont<TReal>& a, const ::aiQuaterniont<TReal>& b) { - return ::aiQuaterniont<TReal> (max(a.w,b.w),max(a.x,b.x),max(a.y,b.y),max(a.z,b.z)); - } - - - - // std::min for aiVectorKey - inline ::aiVectorKey min (const ::aiVectorKey& a, const ::aiVectorKey& b) { - return ::aiVectorKey (min(a.mTime,b.mTime),min(a.mValue,b.mValue)); - } - - // std::max for aiVectorKey - inline ::aiVectorKey max (const ::aiVectorKey& a, const ::aiVectorKey& b) { - return ::aiVectorKey (max(a.mTime,b.mTime),max(a.mValue,b.mValue)); - } - - // std::min for aiQuatKey - inline ::aiQuatKey min (const ::aiQuatKey& a, const ::aiQuatKey& b) { - return ::aiQuatKey (min(a.mTime,b.mTime),min(a.mValue,b.mValue)); - } - - // std::max for aiQuatKey - inline ::aiQuatKey max (const ::aiQuatKey& a, const ::aiQuatKey& b) { - return ::aiQuatKey (max(a.mTime,b.mTime),max(a.mValue,b.mValue)); - } - - // std::min for aiVertexWeight - inline ::aiVertexWeight min (const ::aiVertexWeight& a, const ::aiVertexWeight& b) { - return ::aiVertexWeight (min(a.mVertexId,b.mVertexId),min(a.mWeight,b.mWeight)); - } - - // std::max for aiVertexWeight - inline ::aiVertexWeight max (const ::aiVertexWeight& a, const ::aiVertexWeight& b) { - return ::aiVertexWeight (max(a.mVertexId,b.mVertexId),max(a.mWeight,b.mWeight)); - } - -} // end namespace std -#endif // !! C++ - -namespace Assimp { - -// ------------------------------------------------------------------------------- -// Start points for ArrayBounds<T> for all supported Ts -template <typename T> -struct MinMaxChooser; - -template <> struct MinMaxChooser<float> { - void operator ()(float& min,float& max) { - max = -1e10f; - min = 1e10f; -}}; -template <> struct MinMaxChooser<double> { - void operator ()(double& min,double& max) { - max = -1e10; - min = 1e10; -}}; -template <> struct MinMaxChooser<unsigned int> { - void operator ()(unsigned int& min,unsigned int& max) { - max = 0; - min = (1u<<(sizeof(unsigned int)*8-1)); -}}; - -template <typename T> struct MinMaxChooser< aiVector3t<T> > { - void operator ()(aiVector3t<T>& min,aiVector3t<T>& max) { - max = aiVector3t<T>(-1e10f,-1e10f,-1e10f); - min = aiVector3t<T>( 1e10f, 1e10f, 1e10f); -}}; -template <typename T> struct MinMaxChooser< aiVector2t<T> > { - void operator ()(aiVector2t<T>& min,aiVector2t<T>& max) { - max = aiVector2t<T>(-1e10f,-1e10f); - min = aiVector2t<T>( 1e10f, 1e10f); - }}; -template <typename T> struct MinMaxChooser< aiColor4t<T> > { - void operator ()(aiColor4t<T>& min,aiColor4t<T>& max) { - max = aiColor4t<T>(-1e10f,-1e10f,-1e10f,-1e10f); - min = aiColor4t<T>( 1e10f, 1e10f, 1e10f, 1e10f); -}}; - -template <typename T> struct MinMaxChooser< aiQuaterniont<T> > { - void operator ()(aiQuaterniont<T>& min,aiQuaterniont<T>& max) { - max = aiQuaterniont<T>(-1e10f,-1e10f,-1e10f,-1e10f); - min = aiQuaterniont<T>( 1e10f, 1e10f, 1e10f, 1e10f); -}}; - -template <> struct MinMaxChooser<aiVectorKey> { - void operator ()(aiVectorKey& min,aiVectorKey& max) { - MinMaxChooser<double>()(min.mTime,max.mTime); - MinMaxChooser<aiVector3D>()(min.mValue,max.mValue); -}}; -template <> struct MinMaxChooser<aiQuatKey> { - void operator ()(aiQuatKey& min,aiQuatKey& max) { - MinMaxChooser<double>()(min.mTime,max.mTime); - MinMaxChooser<aiQuaternion>()(min.mValue,max.mValue); -}}; - -template <> struct MinMaxChooser<aiVertexWeight> { - void operator ()(aiVertexWeight& min,aiVertexWeight& max) { - MinMaxChooser<unsigned int>()(min.mVertexId,max.mVertexId); - MinMaxChooser<float>()(min.mWeight,max.mWeight); -}}; - -// ------------------------------------------------------------------------------- -/** @brief Find the min/max values of an array of Ts - * @param in Input array - * @param size Number of elements to process - * @param[out] min minimum value - * @param[out] max maximum value - */ -template <typename T> -inline void ArrayBounds(const T* in, unsigned int size, T& min, T& max) -{ - MinMaxChooser<T> ()(min,max); - for (unsigned int i = 0; i < size;++i) { - min = std::min(in[i],min); - max = std::max(in[i],max); - } -} - - -// ------------------------------------------------------------------------------- -/** Little helper function to calculate the quadratic difference - * of two colours. - * @param pColor1 First color - * @param pColor2 second color - * @return Quadratic color difference */ -inline ai_real GetColorDifference( const aiColor4D& pColor1, const aiColor4D& pColor2) -{ - const aiColor4D c (pColor1.r - pColor2.r, pColor1.g - pColor2.g, pColor1.b - pColor2.b, pColor1.a - pColor2.a); - return c.r*c.r + c.g*c.g + c.b*c.b + c.a*c.a; -} - - -// ------------------------------------------------------------------------------- -/** @brief Extract single strings from a list of identifiers - * @param in Input string list. - * @param out Receives a list of clean output strings - * @sdee #AI_CONFIG_PP_OG_EXCLUDE_LIST */ -void ConvertListToStrings(const std::string& in, std::list<std::string>& out); - - -// ------------------------------------------------------------------------------- -/** @brief Compute the AABB of a mesh after applying a given transform - * @param mesh Input mesh - * @param[out] min Receives minimum transformed vertex - * @param[out] max Receives maximum transformed vertex - * @param m Transformation matrix to be applied */ -void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max, const aiMatrix4x4& m); - - -// ------------------------------------------------------------------------------- -/** @brief Helper function to determine the 'real' center of a mesh - * - * That is the center of its axis-aligned bounding box. - * @param mesh Input mesh - * @param[out] min Minimum vertex of the mesh - * @param[out] max maximum vertex of the mesh - * @param[out] out Center point */ -void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max); - -// ------------------------------------------------------------------------------- -/** @brief Helper function to determine the 'real' center of a scene - * - * That is the center of its axis-aligned bounding box. - * @param scene Input scene - * @param[out] min Minimum vertex of the scene - * @param[out] max maximum vertex of the scene - * @param[out] out Center point */ -void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector3D& max); - - -// ------------------------------------------------------------------------------- -// Helper function to determine the 'real' center of a mesh after applying a given transform -void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min,aiVector3D& max, const aiMatrix4x4& m); - - -// ------------------------------------------------------------------------------- -// Helper function to determine the 'real' center of a mesh -void FindMeshCenter (aiMesh* mesh, aiVector3D& out); - - -// ------------------------------------------------------------------------------- -// Helper function to determine the 'real' center of a mesh after applying a given transform -void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,const aiMatrix4x4& m); - - -// ------------------------------------------------------------------------------- -// Compute a good epsilon value for position comparisons on a mesh -ai_real ComputePositionEpsilon(const aiMesh* pMesh); - - -// ------------------------------------------------------------------------------- -// Compute a good epsilon value for position comparisons on a array of meshes -ai_real ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num); - - -// ------------------------------------------------------------------------------- -// Compute an unique value for the vertex format of a mesh -unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh); - - -// defs for ComputeVertexBoneWeightTable() -typedef std::pair <unsigned int,float> PerVertexWeight; -typedef std::vector <PerVertexWeight> VertexWeightTable; - -// ------------------------------------------------------------------------------- -// Compute a per-vertex bone weight table -VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh); - - -// ------------------------------------------------------------------------------- -// Get a string for a given aiTextureType -const char* TextureTypeToString(aiTextureType in); - - -// ------------------------------------------------------------------------------- -// Get a string for a given aiTextureMapping -const char* MappingTypeToString(aiTextureMapping in); - - -// flags for MakeSubmesh() -#define AI_SUBMESH_FLAGS_SANS_BONES 0x1 - -// ------------------------------------------------------------------------------- -// Split a mesh given a list of faces to be contained in the sub mesh -aiMesh* MakeSubmesh(const aiMesh *superMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags); - -// ------------------------------------------------------------------------------- -// Utility postprocess step to share the spatial sort tree between -// all steps which use it to speedup its computations. -class ComputeSpatialSortProcess : public BaseProcess -{ - bool IsActive( unsigned int pFlags) const - { - return NULL != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace | - aiProcess_GenNormals | aiProcess_JoinIdenticalVertices)); - } - - void Execute( aiScene* pScene) - { - typedef std::pair<SpatialSort, ai_real> _Type; - ASSIMP_LOG_DEBUG("Generate spatially-sorted vertex cache"); - - std::vector<_Type>* p = new std::vector<_Type>(pScene->mNumMeshes); - std::vector<_Type>::iterator it = p->begin(); - - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++it) { - aiMesh* mesh = pScene->mMeshes[i]; - _Type& blubb = *it; - blubb.first.Fill(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D)); - blubb.second = ComputePositionEpsilon(mesh); - } - - shared->AddProperty(AI_SPP_SPATIAL_SORT,p); - } -}; - -// ------------------------------------------------------------------------------- -// ... and the same again to cleanup the whole stuff -class DestroySpatialSortProcess : public BaseProcess -{ - bool IsActive( unsigned int pFlags) const - { - return NULL != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace | - aiProcess_GenNormals | aiProcess_JoinIdenticalVertices)); - } - - void Execute( aiScene* /*pScene*/) - { - shared->RemoveProperty(AI_SPP_SPATIAL_SORT); - } -}; - - - -} // ! namespace Assimp -#endif // !! AI_PROCESS_HELPER_H_INCLUDED diff --git a/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp b/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp deleted file mode 100644 index 49ec8f5c47..0000000000 --- a/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -/** @file RemoveRedundantMaterials.cpp - * @brief Implementation of the "RemoveRedundantMaterials" post processing step -*/ - -// internal headers - -#include "RemoveRedundantMaterials.h" -#include <assimp/ParsingUtils.h> -#include "ProcessHelper.h" -#include "Material/MaterialSystem.h" -#include <stdio.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() -: mConfigFixedMaterials() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -RemoveRedundantMatsProcess::~RemoveRedundantMatsProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_RemoveRedundantMaterials) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Setup import properties -void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) -{ - // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST - mConfigFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,""); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void RemoveRedundantMatsProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess begin"); - - unsigned int redundantRemoved = 0, unreferencedRemoved = 0; - if (pScene->mNumMaterials) - { - // Find out which materials are referenced by meshes - std::vector<bool> abReferenced(pScene->mNumMaterials,false); - for (unsigned int i = 0;i < pScene->mNumMeshes;++i) - abReferenced[pScene->mMeshes[i]->mMaterialIndex] = true; - - // If a list of materials to be excluded was given, match the list with - // our imported materials and 'salt' all positive matches to ensure that - // we get unique hashes later. - if (mConfigFixedMaterials.length()) { - - std::list<std::string> strings; - ConvertListToStrings(mConfigFixedMaterials,strings); - - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - aiMaterial* mat = pScene->mMaterials[i]; - - aiString name; - mat->Get(AI_MATKEY_NAME,name); - - if (name.length) { - std::list<std::string>::const_iterator it = std::find(strings.begin(), strings.end(), name.data); - if (it != strings.end()) { - - // Our brilliant 'salt': A single material property with ~ as first - // character to mark it as internal and temporary. - const int dummy = 1; - ((aiMaterial*)mat)->AddProperty(&dummy,1,"~RRM.UniqueMaterial",0,0); - - // Keep this material even if no mesh references it - abReferenced[i] = true; - ASSIMP_LOG_DEBUG_F( "Found positive match in exclusion list: \'", name.data, "\'"); - } - } - } - } - - // TODO: re-implement this algorithm to work in-place - unsigned int *aiMappingTable = new unsigned int[pScene->mNumMaterials]; - for ( unsigned int i=0; i<pScene->mNumMaterials; i++ ) { - aiMappingTable[ i ] = 0; - } - unsigned int iNewNum = 0; - - // Iterate through all materials and calculate a hash for them - // store all hashes in a list and so a quick search whether - // we do already have a specific hash. This allows us to - // determine which materials are identical. - uint32_t *aiHashes = new uint32_t[ pScene->mNumMaterials ];; - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) - { - // No mesh is referencing this material, remove it. - if (!abReferenced[i]) { - ++unreferencedRemoved; - delete pScene->mMaterials[i]; - pScene->mMaterials[i] = nullptr; - continue; - } - - // Check all previously mapped materials for a matching hash. - // On a match we can delete this material and just make it ref to the same index. - uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]); - for (unsigned int a = 0; a < i;++a) - { - if (abReferenced[a] && me == aiHashes[a]) { - ++redundantRemoved; - me = 0; - aiMappingTable[i] = aiMappingTable[a]; - delete pScene->mMaterials[i]; - pScene->mMaterials[i] = nullptr; - break; - } - } - // This is a new material that is referenced, add to the map. - if (me) { - aiMappingTable[i] = iNewNum++; - } - } - // If the new material count differs from the original, - // we need to rebuild the material list and remap mesh material indexes. - if (iNewNum != pScene->mNumMaterials) { - ai_assert(iNewNum > 0); - aiMaterial** ppcMaterials = new aiMaterial*[iNewNum]; - ::memset(ppcMaterials,0,sizeof(void*)*iNewNum); - for (unsigned int p = 0; p < pScene->mNumMaterials;++p) - { - // if the material is not referenced ... remove it - if (!abReferenced[p]) { - continue; - } - - // generate new names for modified materials that had no names - const unsigned int idx = aiMappingTable[p]; - if (ppcMaterials[idx]) { - aiString sz; - if( ppcMaterials[idx]->Get(AI_MATKEY_NAME, sz) != AI_SUCCESS ) { - sz.length = ::ai_snprintf(sz.data,MAXLEN,"JoinedMaterial_#%u",p); - ((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME); - } - } else { - ppcMaterials[idx] = pScene->mMaterials[p]; - } - } - // update all material indices - for (unsigned int p = 0; p < pScene->mNumMeshes;++p) { - aiMesh* mesh = pScene->mMeshes[p]; - ai_assert( NULL!=mesh ); - mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex]; - } - // delete the old material list - delete[] pScene->mMaterials; - pScene->mMaterials = ppcMaterials; - pScene->mNumMaterials = iNewNum; - } - // delete temporary storage - delete[] aiHashes; - delete[] aiMappingTable; - } - if (redundantRemoved == 0 && unreferencedRemoved == 0) - { - ASSIMP_LOG_DEBUG("RemoveRedundantMatsProcess finished "); - } - else - { - ASSIMP_LOG_INFO_F("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ", - unreferencedRemoved, " unused materials."); - } -} diff --git a/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.h b/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.h deleted file mode 100644 index 1f32a0abfb..0000000000 --- a/thirdparty/assimp/code/PostProcessing/RemoveRedundantMaterials.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file RemoveRedundantMaterials.h - * @brief Defines a post processing step to remove redundant materials - */ -#ifndef AI_REMOVEREDUNDANTMATERIALS_H_INC -#define AI_REMOVEREDUNDANTMATERIALS_H_INC - -#include "Common/BaseProcess.h" -#include <assimp/mesh.h> - -class RemoveRedundantMatsTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** RemoveRedundantMatsProcess: Post-processing step to remove redundant - * materials from the imported scene. - */ -class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess { -public: - /// The default class constructor. - RemoveRedundantMatsProcess(); - - /// The class destructor. - ~RemoveRedundantMatsProcess(); - - // ------------------------------------------------------------------- - // Check whether step is active - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - // Execute step on a given scene - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - // Setup import settings - void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** @brief Set list of fixed (inmutable) materials - * @param fixed See #AI_CONFIG_PP_RRM_EXCLUDE_LIST - */ - void SetFixedMaterialsString(const std::string& fixed = "") { - mConfigFixedMaterials = fixed; - } - - // ------------------------------------------------------------------- - /** @brief Get list of fixed (inmutable) materials - * @return See #AI_CONFIG_PP_RRM_EXCLUDE_LIST - */ - const std::string& GetFixedMaterialsString() const { - return mConfigFixedMaterials; - } - -private: - //! Configuration option: list of all fixed materials - std::string mConfigFixedMaterials; -}; - -} // end of namespace Assimp - -#endif // !!AI_REMOVEREDUNDANTMATERIALS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.cpp b/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.cpp deleted file mode 100644 index 99fd47a3aa..0000000000 --- a/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -/** @file Implementation of the post processing step to remove - * any parts of the mesh structure from the imported data. -*/ - - -#include "RemoveVCProcess.h" -#include <assimp/postprocess.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/scene.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -RemoveVCProcess::RemoveVCProcess() : - configDeleteFlags() - , mScene() -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -RemoveVCProcess::~RemoveVCProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool RemoveVCProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_RemoveComponent) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Small helper function to delete all elements in a T** aray using delete -template <typename T> -inline void ArrayDelete(T**& in, unsigned int& num) -{ - for (unsigned int i = 0; i < num; ++i) - delete in[i]; - - delete[] in; - in = NULL; - num = 0; -} - -#if 0 -// ------------------------------------------------------------------------------------------------ -// Updates the node graph - removes all nodes which have the "remove" flag set and the -// "don't remove" flag not set. Nodes with meshes are never deleted. -bool UpdateNodeGraph(aiNode* node,std::list<aiNode*>& childsOfParent,bool root) -{ - bool b = false; - - std::list<aiNode*> mine; - for (unsigned int i = 0; i < node->mNumChildren;++i) - { - if(UpdateNodeGraph(node->mChildren[i],mine,false)) - b = true; - } - - // somewhat tricky ... mNumMeshes must be originally 0 and MSB2 may not be set, - // so we can do a simple comparison against MSB here - if (!root && AI_RC_UINT_MSB == node->mNumMeshes ) - { - // this node needs to be removed - if(node->mNumChildren) - { - childsOfParent.insert(childsOfParent.end(),mine.begin(),mine.end()); - - // set all children to NULL to make sure they are not deleted when we delete ourself - for (unsigned int i = 0; i < node->mNumChildren;++i) - node->mChildren[i] = NULL; - } - b = true; - delete node; - } - else - { - AI_RC_UNMASK(node->mNumMeshes); - childsOfParent.push_back(node); - - if (b) - { - // reallocate the array of our children here - node->mNumChildren = (unsigned int)mine.size(); - aiNode** const children = new aiNode*[mine.size()]; - aiNode** ptr = children; - - for (std::list<aiNode*>::iterator it = mine.begin(), end = mine.end(); - it != end; ++it) - { - *ptr++ = *it; - } - delete[] node->mChildren; - node->mChildren = children; - return false; - } - } - return b; -} -#endif - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void RemoveVCProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("RemoveVCProcess begin"); - bool bHas = false; //,bMasked = false; - - mScene = pScene; - - // handle animations - if ( configDeleteFlags & aiComponent_ANIMATIONS) - { - - bHas = true; - ArrayDelete(pScene->mAnimations,pScene->mNumAnimations); - } - - // handle textures - if ( configDeleteFlags & aiComponent_TEXTURES) - { - bHas = true; - ArrayDelete(pScene->mTextures,pScene->mNumTextures); - } - - // handle materials - if ( configDeleteFlags & aiComponent_MATERIALS && pScene->mNumMaterials) - { - bHas = true; - for (unsigned int i = 1;i < pScene->mNumMaterials;++i) - delete pScene->mMaterials[i]; - - pScene->mNumMaterials = 1; - aiMaterial* helper = (aiMaterial*) pScene->mMaterials[0]; - ai_assert(NULL != helper); - helper->Clear(); - - // gray - aiColor3D clr(0.6f,0.6f,0.6f); - helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE); - - // add a small ambient color value - clr = aiColor3D(0.05f,0.05f,0.05f); - helper->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT); - - aiString s; - s.Set("Dummy_MaterialsRemoved"); - helper->AddProperty(&s,AI_MATKEY_NAME); - } - - // handle light sources - if ( configDeleteFlags & aiComponent_LIGHTS) - { - bHas = true; - ArrayDelete(pScene->mLights,pScene->mNumLights); - } - - // handle camneras - if ( configDeleteFlags & aiComponent_CAMERAS) - { - bHas = true; - ArrayDelete(pScene->mCameras,pScene->mNumCameras); - } - - // handle meshes - if (configDeleteFlags & aiComponent_MESHES) - { - bHas = true; - ArrayDelete(pScene->mMeshes,pScene->mNumMeshes); - } - else - { - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - { - if( ProcessMesh( pScene->mMeshes[a])) - bHas = true; - } - } - - - // now check whether the result is still a full scene - if (!pScene->mNumMeshes || !pScene->mNumMaterials) - { - pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - ASSIMP_LOG_DEBUG("Setting AI_SCENE_FLAGS_INCOMPLETE flag"); - - // If we have no meshes anymore we should also clear another flag ... - if (!pScene->mNumMeshes) - pScene->mFlags &= ~AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; - } - - if (bHas) { - ASSIMP_LOG_INFO("RemoveVCProcess finished. Data structure cleanup has been done."); - } else { - ASSIMP_LOG_DEBUG("RemoveVCProcess finished. Nothing to be done ..."); - } -} - -// ------------------------------------------------------------------------------------------------ -// Setup configuration properties for the step -void RemoveVCProcess::SetupProperties(const Importer* pImp) -{ - configDeleteFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,0x0); - if (!configDeleteFlags) - { - ASSIMP_LOG_WARN("RemoveVCProcess: AI_CONFIG_PP_RVC_FLAGS is zero."); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh) -{ - bool ret = false; - - // if all materials have been deleted let the material - // index of the mesh point to the created default material - if ( configDeleteFlags & aiComponent_MATERIALS) - pMesh->mMaterialIndex = 0; - - // handle normals - if (configDeleteFlags & aiComponent_NORMALS && pMesh->mNormals) - { - delete[] pMesh->mNormals; - pMesh->mNormals = NULL; - ret = true; - } - - // handle tangents and bitangents - if (configDeleteFlags & aiComponent_TANGENTS_AND_BITANGENTS && pMesh->mTangents) - { - delete[] pMesh->mTangents; - pMesh->mTangents = NULL; - - delete[] pMesh->mBitangents; - pMesh->mBitangents = NULL; - ret = true; - } - - // handle texture coordinates - bool b = (0 != (configDeleteFlags & aiComponent_TEXCOORDS)); - for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++real) - { - if (!pMesh->mTextureCoords[i])break; - if (configDeleteFlags & aiComponent_TEXCOORDSn(real) || b) - { - delete [] pMesh->mTextureCoords[i]; - pMesh->mTextureCoords[i] = NULL; - ret = true; - - if (!b) - { - // collapse the rest of the array - for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) - pMesh->mTextureCoords[a-1] = pMesh->mTextureCoords[a]; - - pMesh->mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS-1] = NULL; - continue; - } - } - ++i; - } - - // handle vertex colors - b = (0 != (configDeleteFlags & aiComponent_COLORS)); - for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_COLOR_SETS; ++real) - { - if (!pMesh->mColors[i])break; - if (configDeleteFlags & aiComponent_COLORSn(i) || b) - { - delete [] pMesh->mColors[i]; - pMesh->mColors[i] = NULL; - ret = true; - - if (!b) - { - // collapse the rest of the array - for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) - pMesh->mColors[a-1] = pMesh->mColors[a]; - - pMesh->mColors[AI_MAX_NUMBER_OF_COLOR_SETS-1] = NULL; - continue; - } - } - ++i; - } - - // handle bones - if (configDeleteFlags & aiComponent_BONEWEIGHTS && pMesh->mBones) - { - ArrayDelete(pMesh->mBones,pMesh->mNumBones); - ret = true; - } - return ret; -} diff --git a/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.h b/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.h deleted file mode 100644 index 7bb21a8330..0000000000 --- a/thirdparty/assimp/code/PostProcessing/RemoveVCProcess.h +++ /dev/null @@ -1,124 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to remove specific parts of the scene */ -#ifndef AI_REMOVEVCPROCESS_H_INCLUDED -#define AI_REMOVEVCPROCESS_H_INCLUDED - -#include "Common/BaseProcess.h" - -#include <assimp/mesh.h> - -class RemoveVCProcessTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** RemoveVCProcess: Class to exclude specific parts of the data structure - * from further processing by removing them, -*/ -class ASSIMP_API RemoveVCProcess : public BaseProcess { -public: - /// The default class constructor. - RemoveVCProcess(); - - /// The class destructor. - ~RemoveVCProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - - // ------------------------------------------------------------------- - /** Manually setup the configuration flags for the step - * - * @param Bitwise combination of the #aiComponent enumerated values. - */ - void SetDeleteFlags(unsigned int f) - { - configDeleteFlags = f; - } - - // ------------------------------------------------------------------- - /** Query the current configuration. - */ - unsigned int GetDeleteFlags() const - { - return configDeleteFlags; - } - -private: - - bool ProcessMesh (aiMesh* pcMesh); - - /** Configuration flag - */ - unsigned int configDeleteFlags; - - /** The scene we're working with - */ - aiScene* mScene; -}; - -// --------------------------------------------------------------------------- - -} // end of namespace Assimp - -#endif // !!AI_REMOVEVCPROCESS_H_INCLUDED diff --git a/thirdparty/assimp/code/PostProcessing/ScaleProcess.cpp b/thirdparty/assimp/code/PostProcessing/ScaleProcess.cpp deleted file mode 100644 index ac770c41f2..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ScaleProcess.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -#include "ScaleProcess.h" - -#include <assimp/scene.h> -#include <assimp/postprocess.h> -#include <assimp/BaseImporter.h> - -namespace Assimp { - -ScaleProcess::ScaleProcess() -: BaseProcess() -, mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) { -} - -ScaleProcess::~ScaleProcess() { - // empty -} - -void ScaleProcess::setScale( ai_real scale ) { - mScale = scale; -} - -ai_real ScaleProcess::getScale() const { - return mScale; -} - -bool ScaleProcess::IsActive( unsigned int pFlags ) const { - return ( pFlags & aiProcess_GlobalScale ) != 0; -} - -void ScaleProcess::SetupProperties( const Importer* pImp ) { - // User scaling - mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f ); - - // File scaling * Application Scaling - float importerScale = pImp->GetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, 1.0f ); - - // apply scale to the scale - // helps prevent bugs with backward compatibility for anyone using normal scaling. - mScale *= importerScale; -} - -void ScaleProcess::Execute( aiScene* pScene ) { - if(mScale == 1.0f) { - return; // nothing to scale - } - - ai_assert( mScale != 0 ); - ai_assert( nullptr != pScene ); - ai_assert( nullptr != pScene->mRootNode ); - - if ( nullptr == pScene ) { - return; - } - - if ( nullptr == pScene->mRootNode ) { - return; - } - - // Process animations and update position transform to new unit system - for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ ) - { - aiAnimation* animation = pScene->mAnimations[animationID]; - - for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++) - { - aiNodeAnim* anim = animation->mChannels[animationChannel]; - - for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++) - { - aiVectorKey& vectorKey = anim->mPositionKeys[posKey]; - vectorKey.mValue *= mScale; - } - } - } - - for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++) - { - aiMesh *mesh = pScene->mMeshes[meshID]; - - // Reconstruct mesh vertexes to the new unit system - for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++) - { - aiVector3D& vertex = mesh->mVertices[vertexID]; - vertex *= mScale; - } - - - // bone placement / scaling - for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++) - { - // Reconstruct matrix by transform rather than by scale - // This prevent scale values being changed which can - // be meaningful in some cases - // like when you want the modeller to see 1:1 compatibility. - aiBone* bone = mesh->mBones[boneID]; - - aiVector3D pos, scale; - aiQuaternion rotation; - - bone->mOffsetMatrix.Decompose( scale, rotation, pos); - - aiMatrix4x4 translation; - aiMatrix4x4::Translation( pos * mScale, translation ); - - aiMatrix4x4 scaling; - aiMatrix4x4::Scaling( aiVector3D(scale), scaling ); - - aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix()); - - bone->mOffsetMatrix = translation * RotMatrix * scaling; - } - - - // animation mesh processing - // convert by position rather than scale. - for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++) - { - aiAnimMesh * animMesh = mesh->mAnimMeshes[animMeshID]; - - for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++) - { - aiVector3D& vertex = animMesh->mVertices[vertexID]; - vertex *= mScale; - } - } - } - - traverseNodes( pScene->mRootNode ); -} - -void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) { - applyScaling( node ); - - for( size_t i = 0; i < node->mNumChildren; i++) - { - // recurse into the tree until we are done! - traverseNodes( node->mChildren[i], nested_node_id+1 ); - } -} - -void ScaleProcess::applyScaling( aiNode *currentNode ) { - if ( nullptr != currentNode ) { - // Reconstruct matrix by transform rather than by scale - // This prevent scale values being changed which can - // be meaningful in some cases - // like when you want the modeller to - // see 1:1 compatibility. - - aiVector3D pos, scale; - aiQuaternion rotation; - currentNode->mTransformation.Decompose( scale, rotation, pos); - - aiMatrix4x4 translation; - aiMatrix4x4::Translation( pos * mScale, translation ); - - aiMatrix4x4 scaling; - - // note: we do not use mScale here, this is on purpose. - aiMatrix4x4::Scaling( scale, scaling ); - - aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix()); - - currentNode->mTransformation = translation * RotMatrix * scaling; - } -} - -} // Namespace Assimp diff --git a/thirdparty/assimp/code/PostProcessing/ScaleProcess.h b/thirdparty/assimp/code/PostProcessing/ScaleProcess.h deleted file mode 100644 index 468a216736..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ScaleProcess.h +++ /dev/null @@ -1,97 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -#ifndef SCALE_PROCESS_H_ -#define SCALE_PROCESS_H_ - -#include "Common/BaseProcess.h" - -struct aiNode; - -#if (!defined AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT) -# define AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT 1.0f -#endif // !! AI_DEBONE_THRESHOLD - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** ScaleProcess: Class to rescale the whole model. - * Now rescales animations, bones, and blend shapes properly. - * Please note this will not write to 'scale' transform it will rewrite mesh - * and matrixes so that your scale values - * from your model package are preserved, so this is completely intentional - * bugs should be reported as soon as they are found. -*/ -class ASSIMP_API ScaleProcess : public BaseProcess { -public: - /// The default class constructor. - ScaleProcess(); - - /// The class destructor. - virtual ~ScaleProcess(); - - /// Will set the scale manually. - void setScale( ai_real scale ); - - /// Returns the current scaling value. - ai_real getScale() const; - - /// Overwritten, @see BaseProcess - virtual bool IsActive( unsigned int pFlags ) const; - - /// Overwritten, @see BaseProcess - virtual void SetupProperties( const Importer* pImp ); - - /// Overwritten, @see BaseProcess - virtual void Execute( aiScene* pScene ); - -private: - void traverseNodes( aiNode *currentNode, unsigned int nested_node_id = 0 ); - void applyScaling( aiNode *currentNode ); - -private: - ai_real mScale; -}; - -} // Namespace Assimp - - -#endif // SCALE_PROCESS_H_
\ No newline at end of file diff --git a/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.cpp b/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.cpp deleted file mode 100644 index be8405a17b..0000000000 --- a/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.cpp +++ /dev/null @@ -1,403 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file Implementation of the DeterminePTypeHelperProcess and - * SortByPTypeProcess post-process steps. -*/ - - - -// internal headers -#include "ProcessHelper.h" -#include "SortByPTypeProcess.h" -#include <assimp/Exceptional.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -SortByPTypeProcess::SortByPTypeProcess() -: mConfigRemoveMeshes( 0 ) { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -SortByPTypeProcess::~SortByPTypeProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool SortByPTypeProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_SortByPType) != 0; -} - -// ------------------------------------------------------------------------------------------------ -void SortByPTypeProcess::SetupProperties(const Importer* pImp) -{ - mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,0); -} - -// ------------------------------------------------------------------------------------------------ -// Update changed meshes in all nodes -void UpdateNodes(const std::vector<unsigned int>& replaceMeshIndex, aiNode* node) -{ - if (node->mNumMeshes) - { - unsigned int newSize = 0; - for (unsigned int m = 0; m< node->mNumMeshes; ++m) - { - unsigned int add = node->mMeshes[m]<<2; - for (unsigned int i = 0; i < 4;++i) - { - if (UINT_MAX != replaceMeshIndex[add+i])++newSize; - } - } - if (!newSize) - { - delete[] node->mMeshes; - node->mNumMeshes = 0; - node->mMeshes = NULL; - } - else - { - // Try to reuse the old array if possible - unsigned int* newMeshes = (newSize > node->mNumMeshes - ? new unsigned int[newSize] : node->mMeshes); - - for (unsigned int m = 0; m< node->mNumMeshes; ++m) - { - unsigned int add = node->mMeshes[m]<<2; - for (unsigned int i = 0; i < 4;++i) - { - if (UINT_MAX != replaceMeshIndex[add+i]) - *newMeshes++ = replaceMeshIndex[add+i]; - } - } - if (newSize > node->mNumMeshes) - delete[] node->mMeshes; - - node->mMeshes = newMeshes-(node->mNumMeshes = newSize); - } - } - - // call all subnodes recursively - for (unsigned int m = 0; m < node->mNumChildren; ++m) - UpdateNodes(replaceMeshIndex,node->mChildren[m]); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SortByPTypeProcess::Execute( aiScene* pScene) { - if ( 0 == pScene->mNumMeshes) { - ASSIMP_LOG_DEBUG("SortByPTypeProcess skipped, there are no meshes"); - return; - } - - ASSIMP_LOG_DEBUG("SortByPTypeProcess begin"); - - unsigned int aiNumMeshesPerPType[4] = {0,0,0,0}; - - std::vector<aiMesh*> outMeshes; - outMeshes.reserve(pScene->mNumMeshes<<1u); - - bool bAnyChanges = false; - - std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes*4,UINT_MAX); - std::vector<unsigned int>::iterator meshIdx = replaceMeshIndex.begin(); - for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { - aiMesh* const mesh = pScene->mMeshes[i]; - ai_assert(0 != mesh->mPrimitiveTypes); - - // if there's just one primitive type in the mesh there's nothing to do for us - unsigned int num = 0; - if (mesh->mPrimitiveTypes & aiPrimitiveType_POINT) { - ++aiNumMeshesPerPType[0]; - ++num; - } - if (mesh->mPrimitiveTypes & aiPrimitiveType_LINE) { - ++aiNumMeshesPerPType[1]; - ++num; - } - if (mesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE) { - ++aiNumMeshesPerPType[2]; - ++num; - } - if (mesh->mPrimitiveTypes & aiPrimitiveType_POLYGON) { - ++aiNumMeshesPerPType[3]; - ++num; - } - - if (1 == num) { - if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) { - *meshIdx = static_cast<unsigned int>( outMeshes.size() ); - outMeshes.push_back(mesh); - } else { - delete mesh; - pScene->mMeshes[ i ] = nullptr; - bAnyChanges = true; - } - - meshIdx += 4; - continue; - } - bAnyChanges = true; - - // reuse our current mesh arrays for the submesh - // with the largest number of primitives - unsigned int aiNumPerPType[4] = {0,0,0,0}; - aiFace* pFirstFace = mesh->mFaces; - aiFace* const pLastFace = pFirstFace + mesh->mNumFaces; - - unsigned int numPolyVerts = 0; - for (;pFirstFace != pLastFace; ++pFirstFace) { - if (pFirstFace->mNumIndices <= 3) - ++aiNumPerPType[pFirstFace->mNumIndices-1]; - else - { - ++aiNumPerPType[3]; - numPolyVerts += pFirstFace-> mNumIndices; - } - } - - VertexWeightTable* avw = ComputeVertexBoneWeightTable(mesh); - for (unsigned int real = 0; real < 4; ++real,++meshIdx) - { - if ( !aiNumPerPType[real] || mConfigRemoveMeshes & (1u << real)) - { - continue; - } - - *meshIdx = (unsigned int) outMeshes.size(); - outMeshes.push_back(new aiMesh()); - aiMesh* out = outMeshes.back(); - - // the name carries the adjacency information between the meshes - out->mName = mesh->mName; - - // copy data members - out->mPrimitiveTypes = 1u << real; - out->mMaterialIndex = mesh->mMaterialIndex; - - // allocate output storage - out->mNumFaces = aiNumPerPType[real]; - aiFace* outFaces = out->mFaces = new aiFace[out->mNumFaces]; - - out->mNumVertices = (3 == real ? numPolyVerts : out->mNumFaces * (real+1)); - - aiVector3D *vert(nullptr), *nor(nullptr), *tan(nullptr), *bit(nullptr); - aiVector3D *uv [AI_MAX_NUMBER_OF_TEXTURECOORDS]; - aiColor4D *cols [AI_MAX_NUMBER_OF_COLOR_SETS]; - - if (mesh->mVertices) { - vert = out->mVertices = new aiVector3D[out->mNumVertices]; - } - - if (mesh->mNormals) { - nor = out->mNormals = new aiVector3D[out->mNumVertices]; - } - - if (mesh->mTangents) { - tan = out->mTangents = new aiVector3D[out->mNumVertices]; - bit = out->mBitangents = new aiVector3D[out->mNumVertices]; - } - - for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_TEXTURECOORDS;++j) { - uv[j] = nullptr; - if (mesh->mTextureCoords[j]) { - uv[j] = out->mTextureCoords[j] = new aiVector3D[out->mNumVertices]; - } - - out->mNumUVComponents[j] = mesh->mNumUVComponents[j]; - } - - for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_COLOR_SETS;++j) { - cols[j] = nullptr; - if (mesh->mColors[j]) { - cols[j] = out->mColors[j] = new aiColor4D[out->mNumVertices]; - } - } - - typedef std::vector< aiVertexWeight > TempBoneInfo; - std::vector< TempBoneInfo > tempBones(mesh->mNumBones); - - // try to guess how much storage we'll need - for (unsigned int q = 0; q < mesh->mNumBones;++q) - { - tempBones[q].reserve(mesh->mBones[q]->mNumWeights / (num-1)); - } - - unsigned int outIdx = 0; - for (unsigned int m = 0; m < mesh->mNumFaces; ++m) - { - aiFace& in = mesh->mFaces[m]; - if ((real == 3 && in.mNumIndices <= 3) || (real != 3 && in.mNumIndices != real+1)) - { - continue; - } - - outFaces->mNumIndices = in.mNumIndices; - outFaces->mIndices = in.mIndices; - - for (unsigned int q = 0; q < in.mNumIndices; ++q) - { - unsigned int idx = in.mIndices[q]; - - // process all bones of this index - if (avw) - { - VertexWeightTable& tbl = avw[idx]; - for (VertexWeightTable::const_iterator it = tbl.begin(), end = tbl.end(); - it != end; ++it) - { - tempBones[ (*it).first ].push_back( aiVertexWeight(outIdx, (*it).second) ); - } - } - - if (vert) - { - *vert++ = mesh->mVertices[idx]; - //mesh->mVertices[idx].x = get_qnan(); - } - if (nor )*nor++ = mesh->mNormals[idx]; - if (tan ) - { - *tan++ = mesh->mTangents[idx]; - *bit++ = mesh->mBitangents[idx]; - } - - for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp) - { - if (!uv[pp])break; - *uv[pp]++ = mesh->mTextureCoords[pp][idx]; - } - - for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp) - { - if (!cols[pp])break; - *cols[pp]++ = mesh->mColors[pp][idx]; - } - - in.mIndices[q] = outIdx++; - } - - in.mIndices = nullptr; - ++outFaces; - } - ai_assert(outFaces == out->mFaces + out->mNumFaces); - - // now generate output bones - for (unsigned int q = 0; q < mesh->mNumBones;++q) - if (!tempBones[q].empty())++out->mNumBones; - - if (out->mNumBones) - { - out->mBones = new aiBone*[out->mNumBones]; - for (unsigned int q = 0, real = 0; q < mesh->mNumBones;++q) - { - TempBoneInfo& in = tempBones[q]; - if (in.empty())continue; - - aiBone* srcBone = mesh->mBones[q]; - aiBone* bone = out->mBones[real] = new aiBone(); - - bone->mName = srcBone->mName; - bone->mOffsetMatrix = srcBone->mOffsetMatrix; - - bone->mNumWeights = (unsigned int)in.size(); - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - - ::memcpy(bone->mWeights,&in[0],bone->mNumWeights*sizeof(aiVertexWeight)); - - ++real; - } - } - } - - // delete the per-vertex bone weights table - delete[] avw; - - // delete the input mesh - delete mesh; - - // avoid invalid pointer - pScene->mMeshes[i] = NULL; - } - - if (outMeshes.empty()) - { - // This should not occur - throw DeadlyImportError("No meshes remaining"); - } - - // If we added at least one mesh process all nodes in the node - // graph and update their respective mesh indices. - if (bAnyChanges) - { - UpdateNodes(replaceMeshIndex,pScene->mRootNode); - } - - if (outMeshes.size() != pScene->mNumMeshes) - { - delete[] pScene->mMeshes; - pScene->mNumMeshes = (unsigned int)outMeshes.size(); - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - } - ::memcpy(pScene->mMeshes,&outMeshes[0],pScene->mNumMeshes*sizeof(void*)); - - if (!DefaultLogger::isNullLogger()) - { - char buffer[1024]; - ::ai_snprintf(buffer,1024,"Points: %u%s, Lines: %u%s, Triangles: %u%s, Polygons: %u%s (Meshes, X = removed)", - aiNumMeshesPerPType[0], ((mConfigRemoveMeshes & aiPrimitiveType_POINT) ? "X" : ""), - aiNumMeshesPerPType[1], ((mConfigRemoveMeshes & aiPrimitiveType_LINE) ? "X" : ""), - aiNumMeshesPerPType[2], ((mConfigRemoveMeshes & aiPrimitiveType_TRIANGLE) ? "X" : ""), - aiNumMeshesPerPType[3], ((mConfigRemoveMeshes & aiPrimitiveType_POLYGON) ? "X" : "")); - ASSIMP_LOG_INFO(buffer); - ASSIMP_LOG_DEBUG("SortByPTypeProcess finished"); - } -} - diff --git a/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.h b/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.h deleted file mode 100644 index 1d7ccfc152..0000000000 --- a/thirdparty/assimp/code/PostProcessing/SortByPTypeProcess.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to sort meshes by the types - of primitives they contain */ -#ifndef AI_SORTBYPTYPEPROCESS_H_INC -#define AI_SORTBYPTYPEPROCESS_H_INC - -#include "Common/BaseProcess.h" -#include <assimp/mesh.h> - -class SortByPTypeProcessTest; - -namespace Assimp { - - -// --------------------------------------------------------------------------- -/** SortByPTypeProcess: Sorts meshes by the types of primitives they contain. - * A mesh with 5 lines, 3 points and 145 triangles would be split in 3 - * submeshes. -*/ -class ASSIMP_API SortByPTypeProcess : public BaseProcess { -public: - SortByPTypeProcess(); - ~SortByPTypeProcess(); - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - -private: - int mConfigRemoveMeshes; -}; - - -} // end of namespace Assimp - -#endif // !!AI_SORTBYPTYPEPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.cpp b/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.cpp deleted file mode 100644 index 1797b28d5a..0000000000 --- a/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** - * @file Implementation of the SplitLargeMeshes postprocessing step - */ - -// internal headers of the post-processing framework -#include "SplitLargeMeshes.h" -#include "ProcessHelper.h" - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Triangle::SplitLargeMeshesProcess_Triangle() { - LIMIT = AI_SLM_DEFAULT_MAX_TRIANGLES; -} - -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Triangle::~SplitLargeMeshesProcess_Triangle() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool SplitLargeMeshesProcess_Triangle::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_SplitLargeMeshes) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitLargeMeshesProcess_Triangle::Execute( aiScene* pScene) { - if (0xffffffff == this->LIMIT || nullptr == pScene ) { - return; - } - - ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle begin"); - std::vector<std::pair<aiMesh*, unsigned int> > avList; - - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) { - this->SplitMesh(a, pScene->mMeshes[a],avList); - } - - if (avList.size() != pScene->mNumMeshes) { - // it seems something has been split. rebuild the mesh list - delete[] pScene->mMeshes; - pScene->mNumMeshes = (unsigned int)avList.size(); - pScene->mMeshes = new aiMesh*[avList.size()]; - - for (unsigned int i = 0; i < avList.size();++i) { - pScene->mMeshes[i] = avList[i].first; - } - - // now we need to update all nodes - this->UpdateNode(pScene->mRootNode,avList); - ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Triangle finished. Meshes have been split"); - } else { - ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Triangle finished. There was nothing to do"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties -void SplitLargeMeshesProcess_Triangle::SetupProperties( const Importer* pImp) { - // get the current value of the split property - this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_TRIANGLE_LIMIT,AI_SLM_DEFAULT_MAX_TRIANGLES); -} - -// ------------------------------------------------------------------------------------------------ -// Update a node after some meshes have been split -void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode, - const std::vector<std::pair<aiMesh*, unsigned int> >& avList) { - // for every index in out list build a new entry - std::vector<unsigned int> aiEntries; - aiEntries.reserve(pcNode->mNumMeshes + 1); - for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) { - for (unsigned int a = 0; a < avList.size();++a) { - if (avList[a].second == pcNode->mMeshes[i]) { - aiEntries.push_back(a); - } - } - } - - // now build the new list - delete[] pcNode->mMeshes; - pcNode->mNumMeshes = (unsigned int)aiEntries.size(); - pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes]; - - for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) { - pcNode->mMeshes[b] = aiEntries[b]; - } - - // recusively update all other nodes - for (unsigned int i = 0; i < pcNode->mNumChildren;++i) { - UpdateNode ( pcNode->mChildren[i], avList ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitLargeMeshesProcess_Triangle::SplitMesh( - unsigned int a, - aiMesh* pMesh, - std::vector<std::pair<aiMesh*, unsigned int> >& avList) { - if (pMesh->mNumFaces > SplitLargeMeshesProcess_Triangle::LIMIT) { - ASSIMP_LOG_INFO("Mesh exceeds the triangle limit. It will be split ..."); - - // we need to split this mesh into sub meshes - // determine the size of a submesh - const unsigned int iSubMeshes = (pMesh->mNumFaces / LIMIT) + 1; - - const unsigned int iOutFaceNum = pMesh->mNumFaces / iSubMeshes; - const unsigned int iOutVertexNum = iOutFaceNum * 3; - - // now generate all submeshes - for (unsigned int i = 0; i < iSubMeshes;++i) { - aiMesh* pcMesh = new aiMesh; - pcMesh->mNumFaces = iOutFaceNum; - pcMesh->mMaterialIndex = pMesh->mMaterialIndex; - - // the name carries the adjacency information between the meshes - pcMesh->mName = pMesh->mName; - - if (i == iSubMeshes-1) { - pcMesh->mNumFaces = iOutFaceNum + ( - pMesh->mNumFaces - iOutFaceNum * iSubMeshes); - } - // copy the list of faces - pcMesh->mFaces = new aiFace[pcMesh->mNumFaces]; - - const unsigned int iBase = iOutFaceNum * i; - - // get the total number of indices - unsigned int iCnt = 0; - for (unsigned int p = iBase; p < pcMesh->mNumFaces + iBase;++p) { - iCnt += pMesh->mFaces[p].mNumIndices; - } - pcMesh->mNumVertices = iCnt; - - // allocate storage - if (pMesh->mVertices != nullptr) { - pcMesh->mVertices = new aiVector3D[iCnt]; - } - - if (pMesh->HasNormals()) { - pcMesh->mNormals = new aiVector3D[iCnt]; - } - - if (pMesh->HasTangentsAndBitangents()) { - pcMesh->mTangents = new aiVector3D[iCnt]; - pcMesh->mBitangents = new aiVector3D[iCnt]; - } - - // texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c]; - if (pMesh->HasTextureCoords( c)) { - pcMesh->mTextureCoords[c] = new aiVector3D[iCnt]; - } - } - - // vertex colors - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) { - if (pMesh->HasVertexColors( c)) { - pcMesh->mColors[c] = new aiColor4D[iCnt]; - } - } - - if (pMesh->HasBones()) { - // assume the number of bones won't change in most cases - pcMesh->mBones = new aiBone*[pMesh->mNumBones]; - - // iterate through all bones of the mesh and find those which - // need to be copied to the split mesh - std::vector<aiVertexWeight> avTempWeights; - for (unsigned int p = 0; p < pcMesh->mNumBones;++p) { - aiBone* const bone = pcMesh->mBones[p]; - avTempWeights.clear(); - avTempWeights.reserve(bone->mNumWeights / iSubMeshes); - - for (unsigned int q = 0; q < bone->mNumWeights;++q) { - aiVertexWeight& weight = bone->mWeights[q]; - if(weight.mVertexId >= iBase && weight.mVertexId < iBase + iOutVertexNum) { - avTempWeights.push_back(weight); - weight = avTempWeights.back(); - weight.mVertexId -= iBase; - } - } - - if (!avTempWeights.empty()) { - // we'll need this bone. Copy it ... - aiBone* pc = new aiBone(); - pcMesh->mBones[pcMesh->mNumBones++] = pc; - pc->mName = aiString(bone->mName); - pc->mNumWeights = (unsigned int)avTempWeights.size(); - pc->mOffsetMatrix = bone->mOffsetMatrix; - - // no need to reallocate the array for the last submesh. - // Here we can reuse the (large) source array, although - // we'll waste some memory - if (iSubMeshes-1 == i) { - pc->mWeights = bone->mWeights; - bone->mWeights = nullptr; - } else { - pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - } - - // copy the weights - ::memcpy(pc->mWeights,&avTempWeights[0],sizeof(aiVertexWeight)*pc->mNumWeights); - } - } - } - - // (we will also need to copy the array of indices) - unsigned int iCurrent = 0; - for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) { - pcMesh->mFaces[p].mNumIndices = 3; - // allocate a new array - const unsigned int iTemp = p + iBase; - const unsigned int iNumIndices = pMesh->mFaces[iTemp].mNumIndices; - - // setup face type and number of indices - pcMesh->mFaces[p].mNumIndices = iNumIndices; - unsigned int* pi = pMesh->mFaces[iTemp].mIndices; - unsigned int* piOut = pcMesh->mFaces[p].mIndices = new unsigned int[iNumIndices]; - - // need to update the output primitive types - switch (iNumIndices) { - case 1: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - } - - // and copy the contents of the old array, offset by current base - for (unsigned int v = 0; v < iNumIndices;++v) { - unsigned int iIndex = pi[v]; - unsigned int iIndexOut = iCurrent++; - piOut[v] = iIndexOut; - - // copy positions - if (pMesh->mVertices != nullptr) { - pcMesh->mVertices[iIndexOut] = pMesh->mVertices[iIndex]; - } - - // copy normals - if (pMesh->HasNormals()) { - pcMesh->mNormals[iIndexOut] = pMesh->mNormals[iIndex]; - } - - // copy tangents/bitangents - if (pMesh->HasTangentsAndBitangents()) { - pcMesh->mTangents[iIndexOut] = pMesh->mTangents[iIndex]; - pcMesh->mBitangents[iIndexOut] = pMesh->mBitangents[iIndex]; - } - - // texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (pMesh->HasTextureCoords( c ) ) { - pcMesh->mTextureCoords[c][iIndexOut] = pMesh->mTextureCoords[c][iIndex]; - } - } - // vertex colors - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) { - if (pMesh->HasVertexColors( c)) { - pcMesh->mColors[c][iIndexOut] = pMesh->mColors[c][iIndex]; - } - } - } - } - - // add the newly created mesh to the list - avList.push_back(std::pair<aiMesh*, unsigned int>(pcMesh,a)); - } - - // now delete the old mesh data - delete pMesh; - } else { - avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a)); - } -} - -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Vertex::SplitLargeMeshesProcess_Vertex() { - LIMIT = AI_SLM_DEFAULT_MAX_VERTICES; -} - -// ------------------------------------------------------------------------------------------------ -SplitLargeMeshesProcess_Vertex::~SplitLargeMeshesProcess_Vertex() { - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool SplitLargeMeshesProcess_Vertex::IsActive( unsigned int pFlags) const { - return (pFlags & aiProcess_SplitLargeMeshes) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) { - if (0xffffffff == this->LIMIT || nullptr == pScene ) { - return; - } - - ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex begin"); - - std::vector<std::pair<aiMesh*, unsigned int> > avList; - - //Check for point cloud first, - //Do not process point cloud, splitMesh works only with faces data - for (unsigned int a = 0; a < pScene->mNumMeshes; a++) { - if ( pScene->mMeshes[a]->mPrimitiveTypes == aiPrimitiveType_POINT ) { - return; - } - } - - for( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) { - this->SplitMesh(a, pScene->mMeshes[a], avList); - } - - if (avList.size() != pScene->mNumMeshes) { - // it seems something has been split. rebuild the mesh list - delete[] pScene->mMeshes; - pScene->mNumMeshes = (unsigned int)avList.size(); - pScene->mMeshes = new aiMesh*[avList.size()]; - - for (unsigned int i = 0; i < avList.size();++i) { - pScene->mMeshes[i] = avList[i].first; - } - - // now we need to update all nodes - SplitLargeMeshesProcess_Triangle::UpdateNode(pScene->mRootNode,avList); - ASSIMP_LOG_INFO("SplitLargeMeshesProcess_Vertex finished. Meshes have been split"); - } else { - ASSIMP_LOG_DEBUG("SplitLargeMeshesProcess_Vertex finished. There was nothing to do"); - } -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties -void SplitLargeMeshesProcess_Vertex::SetupProperties( const Importer* pImp) { - this->LIMIT = pImp->GetPropertyInteger(AI_CONFIG_PP_SLM_VERTEX_LIMIT,AI_SLM_DEFAULT_MAX_VERTICES); -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void SplitLargeMeshesProcess_Vertex::SplitMesh( - unsigned int a, - aiMesh* pMesh, - std::vector<std::pair<aiMesh*, unsigned int> >& avList) { - if (pMesh->mNumVertices > SplitLargeMeshesProcess_Vertex::LIMIT) { - typedef std::vector< std::pair<unsigned int,float> > VertexWeightTable; - - // build a per-vertex weight list if necessary - VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(pMesh); - - // we need to split this mesh into sub meshes - // determine the estimated size of a submesh - // (this could be too large. Max waste is a single digit percentage) - const unsigned int iSubMeshes = (pMesh->mNumVertices / SplitLargeMeshesProcess_Vertex::LIMIT) + 1; - - // create a std::vector<unsigned int> to indicate which vertices - // have already been copied - std::vector<unsigned int> avWasCopied; - avWasCopied.resize(pMesh->mNumVertices,0xFFFFFFFF); - - // try to find a good estimate for the number of output faces - // per mesh. Add 12.5% as buffer - unsigned int iEstimatedSize = pMesh->mNumFaces / iSubMeshes; - iEstimatedSize += iEstimatedSize >> 3; - - // now generate all submeshes - unsigned int iBase( 0 ); - while (true) { - const unsigned int iOutVertexNum = SplitLargeMeshesProcess_Vertex::LIMIT; - aiMesh* pcMesh = new aiMesh; - pcMesh->mNumVertices = 0; - pcMesh->mMaterialIndex = pMesh->mMaterialIndex; - - // the name carries the adjacency information between the meshes - pcMesh->mName = pMesh->mName; - - typedef std::vector<aiVertexWeight> BoneWeightList; - if (pMesh->HasBones()) { - pcMesh->mBones = new aiBone*[pMesh->mNumBones]; - ::memset(pcMesh->mBones,0,sizeof(void*)*pMesh->mNumBones); - } - - // clear the temporary helper array - if (iBase) { - // we can't use memset here we unsigned int needn' be 32 bits - for (auto &elem : avWasCopied) { - elem = 0xffffffff; - } - } - - // output vectors - std::vector<aiFace> vFaces; - - // reserve enough storage for most cases - if (pMesh->HasPositions()) { - pcMesh->mVertices = new aiVector3D[iOutVertexNum]; - } - if (pMesh->HasNormals()) { - pcMesh->mNormals = new aiVector3D[iOutVertexNum]; - } - if (pMesh->HasTangentsAndBitangents()) { - pcMesh->mTangents = new aiVector3D[iOutVertexNum]; - pcMesh->mBitangents = new aiVector3D[iOutVertexNum]; - } - for (unsigned int c = 0; pMesh->HasVertexColors(c);++c) { - pcMesh->mColors[c] = new aiColor4D[iOutVertexNum]; - } - for (unsigned int c = 0; pMesh->HasTextureCoords(c);++c) { - pcMesh->mNumUVComponents[c] = pMesh->mNumUVComponents[c]; - pcMesh->mTextureCoords[c] = new aiVector3D[iOutVertexNum]; - } - vFaces.reserve(iEstimatedSize); - - // (we will also need to copy the array of indices) - while (iBase < pMesh->mNumFaces) { - // allocate a new array - const unsigned int iNumIndices = pMesh->mFaces[iBase].mNumIndices; - - // doesn't catch degenerates but is quite fast - unsigned int iNeed = 0; - for (unsigned int v = 0; v < iNumIndices;++v) { - unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v]; - - // check whether we do already have this vertex - if (0xFFFFFFFF == avWasCopied[iIndex]) { - iNeed++; - } - } - if (pcMesh->mNumVertices + iNeed > iOutVertexNum) { - // don't use this face - break; - } - - vFaces.push_back(aiFace()); - aiFace& rFace = vFaces.back(); - - // setup face type and number of indices - rFace.mNumIndices = iNumIndices; - rFace.mIndices = new unsigned int[iNumIndices]; - - // need to update the output primitive types - switch (rFace.mNumIndices) { - case 1: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - pcMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - } - - // and copy the contents of the old array, offset by current base - for (unsigned int v = 0; v < iNumIndices;++v) { - unsigned int iIndex = pMesh->mFaces[iBase].mIndices[v]; - - // check whether we do already have this vertex - if (0xFFFFFFFF != avWasCopied[iIndex]) { - rFace.mIndices[v] = avWasCopied[iIndex]; - continue; - } - - // copy positions - pcMesh->mVertices[pcMesh->mNumVertices] = (pMesh->mVertices[iIndex]); - - // copy normals - if (pMesh->HasNormals()) { - pcMesh->mNormals[pcMesh->mNumVertices] = (pMesh->mNormals[iIndex]); - } - - // copy tangents/bitangents - if (pMesh->HasTangentsAndBitangents()) { - pcMesh->mTangents[pcMesh->mNumVertices] = (pMesh->mTangents[iIndex]); - pcMesh->mBitangents[pcMesh->mNumVertices] = (pMesh->mBitangents[iIndex]); - } - - // texture coordinates - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { - if (pMesh->HasTextureCoords( c)) { - pcMesh->mTextureCoords[c][pcMesh->mNumVertices] = pMesh->mTextureCoords[c][iIndex]; - } - } - // vertex colors - for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) { - if (pMesh->HasVertexColors( c)) { - pcMesh->mColors[c][pcMesh->mNumVertices] = pMesh->mColors[c][iIndex]; - } - } - // check whether we have bone weights assigned to this vertex - rFace.mIndices[v] = pcMesh->mNumVertices; - if (avPerVertexWeights) { - VertexWeightTable& table = avPerVertexWeights[ pcMesh->mNumVertices ]; - if( !table.empty() ) { - for (VertexWeightTable::const_iterator iter = table.begin(); - iter != table.end();++iter) { - // allocate the bone weight array if necessary - BoneWeightList* pcWeightList = (BoneWeightList*)pcMesh->mBones[(*iter).first]; - if (nullptr == pcWeightList) { - pcMesh->mBones[(*iter).first] = (aiBone*)(pcWeightList = new BoneWeightList()); - } - pcWeightList->push_back(aiVertexWeight(pcMesh->mNumVertices,(*iter).second)); - } - } - } - - avWasCopied[iIndex] = pcMesh->mNumVertices; - pcMesh->mNumVertices++; - } - ++iBase; - if(pcMesh->mNumVertices == iOutVertexNum) { - // break here. The face is only added if it was complete - break; - } - } - - // check which bones we'll need to create for this submesh - if (pMesh->HasBones()) { - aiBone** ppCurrent = pcMesh->mBones; - for (unsigned int k = 0; k < pMesh->mNumBones;++k) { - // check whether the bone is existing - BoneWeightList* pcWeightList; - if ((pcWeightList = (BoneWeightList*)pcMesh->mBones[k])) { - aiBone* pcOldBone = pMesh->mBones[k]; - aiBone* pcOut( nullptr ); - *ppCurrent++ = pcOut = new aiBone(); - pcOut->mName = aiString(pcOldBone->mName); - pcOut->mOffsetMatrix = pcOldBone->mOffsetMatrix; - pcOut->mNumWeights = (unsigned int)pcWeightList->size(); - pcOut->mWeights = new aiVertexWeight[pcOut->mNumWeights]; - - // copy the vertex weights - ::memcpy(pcOut->mWeights,&pcWeightList->operator[](0), - pcOut->mNumWeights * sizeof(aiVertexWeight)); - - // delete the temporary bone weight list - delete pcWeightList; - pcMesh->mNumBones++; - } - } - } - - // copy the face list to the mesh - pcMesh->mFaces = new aiFace[vFaces.size()]; - pcMesh->mNumFaces = (unsigned int)vFaces.size(); - - for (unsigned int p = 0; p < pcMesh->mNumFaces;++p) { - pcMesh->mFaces[p] = vFaces[p]; - } - - // add the newly created mesh to the list - avList.push_back(std::pair<aiMesh*, unsigned int>(pcMesh,a)); - - if (iBase == pMesh->mNumFaces) { - // have all faces ... finish the outer loop, too - break; - } - } - - // delete the per-vertex weight list again - delete[] avPerVertexWeights; - - // now delete the old mesh data - delete pMesh; - return; - } - avList.push_back(std::pair<aiMesh*, unsigned int>(pMesh,a)); -} diff --git a/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.h b/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.h deleted file mode 100644 index 3f90576ea9..0000000000 --- a/thirdparty/assimp/code/PostProcessing/SplitLargeMeshes.h +++ /dev/null @@ -1,209 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to split large meshes into sub-meshes - */ -#ifndef AI_SPLITLARGEMESHES_H_INC -#define AI_SPLITLARGEMESHES_H_INC - -#include <vector> -#include "Common/BaseProcess.h" - -#include <assimp/mesh.h> -#include <assimp/scene.h> - -// Forward declarations -class SplitLargeMeshesTest; - -namespace Assimp { - -class SplitLargeMeshesProcess_Triangle; -class SplitLargeMeshesProcess_Vertex; - -// NOTE: If you change these limits, don't forget to change the -// corresponding values in all Assimp ports - -// ********************************************************** -// Java: ConfigProperty.java, -// ConfigProperty.DEFAULT_VERTEX_SPLIT_LIMIT -// ConfigProperty.DEFAULT_TRIANGLE_SPLIT_LIMIT -// ********************************************************** - -// default limit for vertices -#if (!defined AI_SLM_DEFAULT_MAX_VERTICES) -# define AI_SLM_DEFAULT_MAX_VERTICES 1000000 -#endif - -// default limit for triangles -#if (!defined AI_SLM_DEFAULT_MAX_TRIANGLES) -# define AI_SLM_DEFAULT_MAX_TRIANGLES 1000000 -#endif - -// --------------------------------------------------------------------------- -/** Post-processing filter to split large meshes into sub-meshes - * - * Applied BEFORE the JoinVertices-Step occurs. - * Returns NON-UNIQUE vertices, splits by triangle number. -*/ -class ASSIMP_API SplitLargeMeshesProcess_Triangle : public BaseProcess -{ - friend class SplitLargeMeshesProcess_Vertex; - -public: - - SplitLargeMeshesProcess_Triangle(); - ~SplitLargeMeshesProcess_Triangle(); - -public: - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag. - * @param pFlags The processing flags the importer was called with. A - * bitwise combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, - * false if not. - */ - bool IsActive( unsigned int pFlags) const; - - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - - - //! Set the split limit - needed for unit testing - inline void SetLimit(unsigned int l) - {LIMIT = l;} - - //! Get the split limit - inline unsigned int GetLimit() const - {return LIMIT;} - -public: - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - //! Apply the algorithm to a given mesh - void SplitMesh (unsigned int a, aiMesh* pcMesh, - std::vector<std::pair<aiMesh*, unsigned int> >& avList); - - // ------------------------------------------------------------------- - //! Update a node in the asset after a few of its meshes - //! have been split - static void UpdateNode(aiNode* pcNode, - const std::vector<std::pair<aiMesh*, unsigned int> >& avList); - -public: - //! Triangle limit - unsigned int LIMIT; -}; - - -// --------------------------------------------------------------------------- -/** Post-processing filter to split large meshes into sub-meshes - * - * Applied AFTER the JoinVertices-Step occurs. - * Returns UNIQUE vertices, splits by vertex number. -*/ -class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess -{ -public: - - SplitLargeMeshesProcess_Vertex(); - ~SplitLargeMeshesProcess_Vertex(); - -public: - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Called prior to ExecuteOnScene(). - * The function is a request to the process to update its configuration - * basing on the Importer's configuration property list. - */ - virtual void SetupProperties(const Importer* pImp); - - - //! Set the split limit - needed for unit testing - inline void SetLimit(unsigned int l) - {LIMIT = l;} - - //! Get the split limit - inline unsigned int GetLimit() const - {return LIMIT;} - -public: - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - //! Apply the algorithm to a given mesh - void SplitMesh (unsigned int a, aiMesh* pcMesh, - std::vector<std::pair<aiMesh*, unsigned int> >& avList); - - // NOTE: Reuse SplitLargeMeshesProcess_Triangle::UpdateNode() - -public: - //! Triangle limit - unsigned int LIMIT; -}; - -} // end of namespace Assimp - -#endif // !!AI_SPLITLARGEMESHES_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/TextureTransform.cpp b/thirdparty/assimp/code/PostProcessing/TextureTransform.cpp deleted file mode 100644 index 8ae2ba7218..0000000000 --- a/thirdparty/assimp/code/PostProcessing/TextureTransform.cpp +++ /dev/null @@ -1,566 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file A helper class that processes texture transformations */ - - - -#include <assimp/Importer.hpp> -#include <assimp/postprocess.h> -#include <assimp/DefaultLogger.hpp> -#include <assimp/scene.h> - -#include "TextureTransform.h" -#include <assimp/StringUtils.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -TextureTransformStep::TextureTransformStep() : - configFlags() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -TextureTransformStep::~TextureTransformStep() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool TextureTransformStep::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_TransformUVCoords) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Setup properties -void TextureTransformStep::SetupProperties(const Importer* pImp) -{ - configFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_TUV_EVALUATE,AI_UVTRAFO_ALL); -} - -// ------------------------------------------------------------------------------------------------ -void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info) -{ - /* This function tries to simplify the input UV transformation. - * That's very important as it allows us to reduce the number - * of output UV channels. The order in which the transformations - * are applied is - as always - scaling, rotation, translation. - */ - - char szTemp[512]; - int rounded = 0; - - - /* Optimize the rotation angle. That's slightly difficult as - * we have an inprecise floating-point number (when comparing - * UV transformations we'll take that into account by using - * an epsilon of 5 degrees). If there is a rotation value, we can't - * perform any further optimizations. - */ - if (info.mRotation) - { - float out = info.mRotation; - if ((rounded = static_cast<int>((info.mRotation / static_cast<float>(AI_MATH_TWO_PI))))) - { - out -= rounded * static_cast<float>(AI_MATH_PI); - ASSIMP_LOG_INFO_F("Texture coordinate rotation ", info.mRotation, " can be simplified to ", out); - } - - // Next step - convert negative rotation angles to positives - if (out < 0.f) - out = (float)AI_MATH_TWO_PI * 2 + out; - - info.mRotation = out; - return; - } - - - /* Optimize UV translation in the U direction. To determine whether - * or not we can optimize we need to look at the requested mapping - * type (e.g. if mirroring is active there IS a difference between - * offset 2 and 3) - */ - if ((rounded = (int)info.mTranslation.x)) { - float out = 0.0f; - szTemp[0] = 0; - if (aiTextureMapMode_Wrap == info.mapU) { - // Wrap - simple take the fraction of the field - out = info.mTranslation.x-(float)rounded; - ai_snprintf(szTemp, 512, "[w] UV U offset %f can be simplified to %f", info.mTranslation.x, out); - } - else if (aiTextureMapMode_Mirror == info.mapU && 1 != rounded) { - // Mirror - if (rounded % 2) - rounded--; - out = info.mTranslation.x-(float)rounded; - - ai_snprintf(szTemp,512,"[m/d] UV U offset %f can be simplified to %f",info.mTranslation.x,out); - } - else if (aiTextureMapMode_Clamp == info.mapU || aiTextureMapMode_Decal == info.mapU) { - // Clamp - translations beyond 1,1 are senseless - ai_snprintf(szTemp,512,"[c] UV U offset %f can be clamped to 1.0f",info.mTranslation.x); - - out = 1.f; - } - if (szTemp[0]) { - ASSIMP_LOG_INFO(szTemp); - info.mTranslation.x = out; - } - } - - /* Optimize UV translation in the V direction. To determine whether - * or not we can optimize we need to look at the requested mapping - * type (e.g. if mirroring is active there IS a difference between - * offset 2 and 3) - */ - if ((rounded = (int)info.mTranslation.y)) { - float out = 0.0f; - szTemp[0] = 0; - if (aiTextureMapMode_Wrap == info.mapV) { - // Wrap - simple take the fraction of the field - out = info.mTranslation.y-(float)rounded; - ::ai_snprintf(szTemp,512,"[w] UV V offset %f can be simplified to %f",info.mTranslation.y,out); - } - else if (aiTextureMapMode_Mirror == info.mapV && 1 != rounded) { - // Mirror - if (rounded % 2) - rounded--; - out = info.mTranslation.x-(float)rounded; - - ::ai_snprintf(szTemp,512,"[m/d] UV V offset %f can be simplified to %f",info.mTranslation.y,out); - } - else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV) { - // Clamp - translations beyond 1,1 are senseless - ::ai_snprintf(szTemp,512,"[c] UV V offset %f canbe clamped to 1.0f",info.mTranslation.y); - - out = 1.f; - } - if (szTemp[0]) { - ASSIMP_LOG_INFO(szTemp); - info.mTranslation.y = out; - } - } - return; -} - -// ------------------------------------------------------------------------------------------------ -void UpdateUVIndex(const std::list<TTUpdateInfo>& l, unsigned int n) -{ - // Don't set if == 0 && wasn't set before - for (std::list<TTUpdateInfo>::const_iterator it = l.begin();it != l.end(); ++it) { - const TTUpdateInfo& info = *it; - - if (info.directShortcut) - *info.directShortcut = n; - else if (!n) - { - info.mat->AddProperty<int>((int*)&n,1,AI_MATKEY_UVWSRC(info.semantic,info.index)); - } - } -} - -// ------------------------------------------------------------------------------------------------ -inline const char* MappingModeToChar(aiTextureMapMode map) -{ - if (aiTextureMapMode_Wrap == map) - return "-w"; - - if (aiTextureMapMode_Mirror == map) - return "-m"; - - return "-c"; -} - -// ------------------------------------------------------------------------------------------------ -void TextureTransformStep::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("TransformUVCoordsProcess begin"); - - - /* We build a per-mesh list of texture transformations we'll need - * to apply. To achieve this, we iterate through all materials, - * find all textures and get their transformations and UV indices. - * Then we search for all meshes using this material. - */ - typedef std::list<STransformVecInfo> MeshTrafoList; - std::vector<MeshTrafoList> meshLists(pScene->mNumMeshes); - - for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { - - aiMaterial* mat = pScene->mMaterials[i]; - for (unsigned int a = 0; a < mat->mNumProperties;++a) { - - aiMaterialProperty* prop = mat->mProperties[a]; - if (!::strcmp( prop->mKey.data, "$tex.file")) { - STransformVecInfo info; - - // Setup a shortcut structure to allow for a fast updating - // of the UV index later - TTUpdateInfo update; - update.mat = (aiMaterial*) mat; - update.semantic = prop->mSemantic; - update.index = prop->mIndex; - - // Get textured properties and transform - for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) { - aiMaterialProperty* prop2 = mat->mProperties[a2]; - if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) { - continue; - } - - if ( !::strcmp( prop2->mKey.data, "$tex.uvwsrc")) { - info.uvIndex = *((int*)prop2->mData); - - // Store a direct pointer for later use - update.directShortcut = (unsigned int*) prop2->mData; - } - - else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodeu")) { - info.mapU = *((aiTextureMapMode*)prop2->mData); - } - else if ( !::strcmp( prop2->mKey.data, "$tex.mapmodev")) { - info.mapV = *((aiTextureMapMode*)prop2->mData); - } - else if ( !::strcmp( prop2->mKey.data, "$tex.uvtrafo")) { - // ValidateDS should check this - ai_assert(prop2->mDataLength >= 20); - ::memcpy(&info.mTranslation.x,prop2->mData,sizeof(float)*5); - - // Directly remove this property from the list - mat->mNumProperties--; - for (unsigned int a3 = a2; a3 < mat->mNumProperties;++a3) { - mat->mProperties[a3] = mat->mProperties[a3+1]; - } - - delete prop2; - - // Warn: could be an underflow, but this does not invoke undefined behaviour - --a2; - } - } - - // Find out which transformations are to be evaluated - if (!(configFlags & AI_UVTRAFO_ROTATION)) { - info.mRotation = 0.f; - } - if (!(configFlags & AI_UVTRAFO_SCALING)) { - info.mScaling = aiVector2D(1.f,1.f); - } - if (!(configFlags & AI_UVTRAFO_TRANSLATION)) { - info.mTranslation = aiVector2D(0.f,0.f); - } - - // Do some preprocessing - PreProcessUVTransform(info); - info.uvIndex = std::min(info.uvIndex,AI_MAX_NUMBER_OF_TEXTURECOORDS -1u); - - // Find out whether this material is used by more than - // one mesh. This will make our task much, much more difficult! - unsigned int cnt = 0; - for (unsigned int n = 0; n < pScene->mNumMeshes;++n) { - if (pScene->mMeshes[n]->mMaterialIndex == i) - ++cnt; - } - - if (!cnt) - continue; - else if (1 != cnt) { - // This material is referenced by more than one mesh! - // So we need to make sure the UV index for the texture - // is identical for each of it ... - info.lockedPos = AI_TT_UV_IDX_LOCK_TBD; - } - - // Get all corresponding meshes - for (unsigned int n = 0; n < pScene->mNumMeshes;++n) { - aiMesh* mesh = pScene->mMeshes[n]; - if (mesh->mMaterialIndex != i || !mesh->mTextureCoords[0]) - continue; - - unsigned int uv = info.uvIndex; - if (!mesh->mTextureCoords[uv]) { - // If the requested UV index is not available, take the first one instead. - uv = 0; - } - - if (mesh->mNumUVComponents[info.uvIndex] >= 3){ - ASSIMP_LOG_WARN("UV transformations on 3D mapping channels are not supported"); - continue; - } - - MeshTrafoList::iterator it; - - // Check whether we have this transform setup already - for (it = meshLists[n].begin();it != meshLists[n].end(); ++it) { - - if ((*it) == info && (*it).uvIndex == uv) { - (*it).updateList.push_back(update); - break; - } - } - - if (it == meshLists[n].end()) { - meshLists[n].push_back(info); - meshLists[n].back().uvIndex = uv; - meshLists[n].back().updateList.push_back(update); - } - } - } - } - } - - char buffer[1024]; // should be sufficiently large - unsigned int outChannels = 0, inChannels = 0, transformedChannels = 0; - - // Now process all meshes. Important: we don't remove unreferenced UV channels. - // This is a job for the RemoveUnreferencedData-Step. - for (unsigned int q = 0; q < pScene->mNumMeshes;++q) { - - aiMesh* mesh = pScene->mMeshes[q]; - MeshTrafoList& trafo = meshLists[q]; - - inChannels += mesh->GetNumUVChannels(); - - if (!mesh->mTextureCoords[0] || trafo.empty() || (trafo.size() == 1 && trafo.begin()->IsUntransformed())) { - outChannels += mesh->GetNumUVChannels(); - continue; - } - - // Move untransformed UV channels to the first position in the list .... - // except if we need a new locked index which should be as small as possible - bool veto = false, need = false; - unsigned int cnt = 0; - unsigned int untransformed = 0; - - MeshTrafoList::iterator it,it2; - for (it = trafo.begin();it != trafo.end(); ++it,++cnt) { - - if (!(*it).IsUntransformed()) { - need = true; - } - - if ((*it).lockedPos == AI_TT_UV_IDX_LOCK_TBD) { - // Lock this index and make sure it won't be changed - (*it).lockedPos = cnt; - veto = true; - continue; - } - - if (!veto && it != trafo.begin() && (*it).IsUntransformed()) { - for (it2 = trafo.begin();it2 != it; ++it2) { - if (!(*it2).IsUntransformed()) - break; - } - trafo.insert(it2,*it); - trafo.erase(it); - break; - } - } - if (!need) - continue; - - // Find all that are not at their 'locked' position and move them to it. - // Conflicts are possible but quite unlikely. - cnt = 0; - for (it = trafo.begin();it != trafo.end(); ++it,++cnt) { - if ((*it).lockedPos != AI_TT_UV_IDX_LOCK_NONE && (*it).lockedPos != cnt) { - it2 = trafo.begin();unsigned int t = 0; - while (t != (*it).lockedPos) - ++it2; - - if ((*it2).lockedPos != AI_TT_UV_IDX_LOCK_NONE) { - ASSIMP_LOG_ERROR("Channel mismatch, can't compute all transformations properly [design bug]"); - continue; - } - - std::swap(*it2,*it); - if ((*it).lockedPos == untransformed) - untransformed = cnt; - } - } - - // ... and add dummies for all unreferenced channels - // at the end of the list - bool ref[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) - ref[n] = (!mesh->mTextureCoords[n] ? true : false); - - for (it = trafo.begin();it != trafo.end(); ++it) - ref[(*it).uvIndex] = true; - - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) { - if (ref[n]) - continue; - trafo.push_back(STransformVecInfo()); - trafo.back().uvIndex = n; - } - - // Then check whether this list breaks the channel limit. - // The unimportant ones are at the end of the list, so - // it shouldn't be too worse if we remove them. - unsigned int size = (unsigned int)trafo.size(); - if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) { - - if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_ERROR_F(static_cast<unsigned int>(trafo.size()), " UV channels required but just ", - AI_MAX_NUMBER_OF_TEXTURECOORDS, " available"); - } - size = AI_MAX_NUMBER_OF_TEXTURECOORDS; - } - - - aiVector3D* old[AI_MAX_NUMBER_OF_TEXTURECOORDS]; - for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n) - old[n] = mesh->mTextureCoords[n]; - - // Now continue and generate the output channels. Channels - // that we're not going to need later can be overridden. - it = trafo.begin(); - for (unsigned int n = 0; n < trafo.size();++n,++it) { - - if (n >= size) { - // Try to use an untransformed channel for all channels we threw over board - UpdateUVIndex((*it).updateList,untransformed); - continue; - } - - outChannels++; - - // Write to the log - if (!DefaultLogger::isNullLogger()) { - ::ai_snprintf(buffer,1024,"Mesh %u, channel %u: t(%.3f,%.3f), s(%.3f,%.3f), r(%.3f), %s%s", - q,n, - (*it).mTranslation.x, - (*it).mTranslation.y, - (*it).mScaling.x, - (*it).mScaling.y, - AI_RAD_TO_DEG( (*it).mRotation), - MappingModeToChar ((*it).mapU), - MappingModeToChar ((*it).mapV)); - - ASSIMP_LOG_INFO(buffer); - } - - // Check whether we need a new buffer here - if (mesh->mTextureCoords[n]) { - - it2 = it;++it2; - for (unsigned int m = n+1; m < size;++m, ++it2) { - - if ((*it2).uvIndex == n){ - it2 = trafo.begin(); - break; - } - } - if (it2 == trafo.begin()){ - mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; - } - } - else mesh->mTextureCoords[n] = new aiVector3D[mesh->mNumVertices]; - - aiVector3D* src = old[(*it).uvIndex]; - aiVector3D* dest, *end; - dest = mesh->mTextureCoords[n]; - - ai_assert(NULL != src); - - // Copy the data to the destination array - if (dest != src) - ::memcpy(dest,src,sizeof(aiVector3D)*mesh->mNumVertices); - - end = dest + mesh->mNumVertices; - - // Build a transformation matrix and transform all UV coords with it - if (!(*it).IsUntransformed()) { - const aiVector2D& trl = (*it).mTranslation; - const aiVector2D& scl = (*it).mScaling; - - // fixme: simplify .. - ++transformedChannels; - aiMatrix3x3 matrix; - - aiMatrix3x3 m2,m3,m4,m5; - - m4.a1 = scl.x; - m4.b2 = scl.y; - - m2.a3 = m2.b3 = 0.5f; - m3.a3 = m3.b3 = -0.5f; - - if ((*it).mRotation > AI_TT_ROTATION_EPSILON ) - aiMatrix3x3::RotationZ((*it).mRotation,matrix); - - m5.a3 += trl.x; m5.b3 += trl.y; - matrix = m2 * m4 * matrix * m3 * m5; - - for (src = dest; src != end; ++src) { /* manual homogenious divide */ - src->z = 1.f; - *src = matrix * *src; - src->x /= src->z; - src->y /= src->z; - src->z = 0.f; - } - } - - // Update all UV indices - UpdateUVIndex((*it).updateList,n); - } - } - - // Print some detailed statistics into the log - if (!DefaultLogger::isNullLogger()) { - - if (transformedChannels) { - ASSIMP_LOG_INFO_F("TransformUVCoordsProcess end: ", outChannels, " output channels (in: ", inChannels, ", modified: ", transformedChannels,")"); - } else { - ASSIMP_LOG_DEBUG("TransformUVCoordsProcess finished"); - } - } -} - - diff --git a/thirdparty/assimp/code/PostProcessing/TextureTransform.h b/thirdparty/assimp/code/PostProcessing/TextureTransform.h deleted file mode 100644 index 2a5d623d7f..0000000000 --- a/thirdparty/assimp/code/PostProcessing/TextureTransform.h +++ /dev/null @@ -1,232 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Definition of a helper step that processes texture transformations */ -#ifndef AI_TEXTURE_TRANSFORM_H_INCLUDED -#define AI_TEXTURE_TRANSFORM_H_INCLUDED - -#include <assimp/BaseImporter.h> -#include "Common/BaseProcess.h" - -#include <assimp/material.h> -#include <list> - -struct aiNode; -struct aiMaterial; - -namespace Assimp { - -#define AI_TT_UV_IDX_LOCK_TBD 0xffffffff -#define AI_TT_UV_IDX_LOCK_NONE 0xeeeeeeee - - -#define AI_TT_ROTATION_EPSILON ((float)AI_DEG_TO_RAD(0.5)) - -// --------------------------------------------------------------------------- -/** Small helper structure representing a shortcut into the material list - * to be able to update some values quickly. -*/ -struct TTUpdateInfo { - TTUpdateInfo() AI_NO_EXCEPT - : directShortcut(nullptr) - , mat(nullptr) - , semantic(0) - , index(0) { - // empty - } - - //! Direct shortcut, if available - unsigned int* directShortcut; - - //! Material - aiMaterial *mat; - - //! Texture type and index - unsigned int semantic, index; -}; - - -// --------------------------------------------------------------------------- -/** Helper class representing texture coordinate transformations -*/ -struct STransformVecInfo : public aiUVTransform { - STransformVecInfo() AI_NO_EXCEPT - : uvIndex(0) - , mapU(aiTextureMapMode_Wrap) - , mapV(aiTextureMapMode_Wrap) - , lockedPos(AI_TT_UV_IDX_LOCK_NONE) { - // empty - } - - //! Source texture coordinate index - unsigned int uvIndex; - - //! Texture mapping mode in the u, v direction - aiTextureMapMode mapU,mapV; - - //! Locked destination UV index - //! AI_TT_UV_IDX_LOCK_TBD - to be determined - //! AI_TT_UV_IDX_LOCK_NONE - none (default) - unsigned int lockedPos; - - //! Update info - shortcuts into all materials - //! that are referencing this transform setup - std::list<TTUpdateInfo> updateList; - - - // ------------------------------------------------------------------- - /** Compare two transform setups - */ - inline bool operator== (const STransformVecInfo& other) const - { - // We use a small epsilon here - const static float epsilon = 0.05f; - - if (std::fabs( mTranslation.x - other.mTranslation.x ) > epsilon || - std::fabs( mTranslation.y - other.mTranslation.y ) > epsilon) - { - return false; - } - - if (std::fabs( mScaling.x - other.mScaling.x ) > epsilon || - std::fabs( mScaling.y - other.mScaling.y ) > epsilon) - { - return false; - } - - if (std::fabs( mRotation - other.mRotation) > epsilon) - { - return false; - } - return true; - } - - inline bool operator!= (const STransformVecInfo& other) const - { - return !(*this == other); - } - - - // ------------------------------------------------------------------- - /** Returns whether this is an untransformed texture coordinate set - */ - inline bool IsUntransformed() const - { - return (1.0f == mScaling.x && 1.f == mScaling.y && - !mTranslation.x && !mTranslation.y && - mRotation < AI_TT_ROTATION_EPSILON); - } - - // ------------------------------------------------------------------- - /** Build a 3x3 matrix from the transformations - */ - inline void GetMatrix(aiMatrix3x3& mOut) - { - mOut = aiMatrix3x3(); - - if (1.0f != mScaling.x || 1.0f != mScaling.y) - { - aiMatrix3x3 mScale; - mScale.a1 = mScaling.x; - mScale.b2 = mScaling.y; - mOut = mScale; - } - if (mRotation) - { - aiMatrix3x3 mRot; - mRot.a1 = mRot.b2 = std::cos(mRotation); - mRot.a2 = mRot.b1 = std::sin(mRotation); - mRot.a2 = -mRot.a2; - mOut *= mRot; - } - if (mTranslation.x || mTranslation.y) - { - aiMatrix3x3 mTrans; - mTrans.a3 = mTranslation.x; - mTrans.b3 = mTranslation.y; - mOut *= mTrans; - } - } -}; - - -// --------------------------------------------------------------------------- -/** Helper step to compute final UV coordinate sets if there are scalings - * or rotations in the original data read from the file. -*/ -class TextureTransformStep : public BaseProcess -{ -public: - - TextureTransformStep(); - ~TextureTransformStep(); - -public: - - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - void SetupProperties(const Importer* pImp); - - -protected: - - - // ------------------------------------------------------------------- - /** Preprocess a specific UV transformation setup - * - * @param info Transformation setup to be preprocessed. - */ - void PreProcessUVTransform(STransformVecInfo& info); - -private: - - unsigned int configFlags; -}; - -} - -#endif //! AI_TEXTURE_TRANSFORM_H_INCLUDED diff --git a/thirdparty/assimp/code/PostProcessing/TriangulateProcess.cpp b/thirdparty/assimp/code/PostProcessing/TriangulateProcess.cpp deleted file mode 100644 index 1040836bbe..0000000000 --- a/thirdparty/assimp/code/PostProcessing/TriangulateProcess.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file TriangulateProcess.cpp - * @brief Implementation of the post processing step to split up - * all faces with more than three indices into triangles. - * - * - * The triangulation algorithm will handle concave or convex polygons. - * Self-intersecting or non-planar polygons are not rejected, but - * they're probably not triangulated correctly. - * - * DEBUG SWITCHES - do not enable any of them in release builds: - * - * AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING - * - generates vertex colors to represent the face winding order. - * the first vertex of a polygon becomes red, the last blue. - * AI_BUILD_TRIANGULATE_DEBUG_POLYS - * - dump all polygons and their triangulation sequences to - * a file - */ -#ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS - -#include "PostProcessing/TriangulateProcess.h" -#include "PostProcessing/ProcessHelper.h" -#include "Common/PolyTools.h" - -#include <memory> - -//#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING -//#define AI_BUILD_TRIANGULATE_DEBUG_POLYS - -#define POLY_GRID_Y 40 -#define POLY_GRID_X 70 -#define POLY_GRID_XPAD 20 -#define POLY_OUTPUT_FILE "assimp_polygons_debug.txt" - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -TriangulateProcess::TriangulateProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -TriangulateProcess::~TriangulateProcess() -{ - // nothing to do here -} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool TriangulateProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_Triangulate) != 0; -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void TriangulateProcess::Execute( aiScene* pScene) -{ - ASSIMP_LOG_DEBUG("TriangulateProcess begin"); - - bool bHas = false; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++) - { - if (pScene->mMeshes[ a ]) { - if ( TriangulateMesh( pScene->mMeshes[ a ] ) ) { - bHas = true; - } - } - } - if ( bHas ) { - ASSIMP_LOG_INFO( "TriangulateProcess finished. All polygons have been triangulated." ); - } else { - ASSIMP_LOG_DEBUG( "TriangulateProcess finished. There was nothing to be done." ); - } -} - -// ------------------------------------------------------------------------------------------------ -// Triangulates the given mesh. -bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh) -{ - // Now we have aiMesh::mPrimitiveTypes, so this is only here for test cases - if (!pMesh->mPrimitiveTypes) { - bool bNeed = false; - - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { - const aiFace& face = pMesh->mFaces[a]; - - if( face.mNumIndices != 3) { - bNeed = true; - } - } - if (!bNeed) - return false; - } - else if (!(pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) { - return false; - } - - // Find out how many output faces we'll get - unsigned int numOut = 0, max_out = 0; - bool get_normals = true; - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { - aiFace& face = pMesh->mFaces[a]; - if (face.mNumIndices <= 4) { - get_normals = false; - } - if( face.mNumIndices <= 3) { - numOut++; - - } - else { - numOut += face.mNumIndices-2; - max_out = std::max(max_out,face.mNumIndices); - } - } - - // Just another check whether aiMesh::mPrimitiveTypes is correct - ai_assert(numOut != pMesh->mNumFaces); - - aiVector3D* nor_out = NULL; - - // if we don't have normals yet, but expect them to be a cheap side - // product of triangulation anyway, allocate storage for them. - if (!pMesh->mNormals && get_normals) { - // XXX need a mechanism to inform the GenVertexNormals process to treat these normals as preprocessed per-face normals - // nor_out = pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; - } - - // the output mesh will contain triangles, but no polys anymore - pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON; - - aiFace* out = new aiFace[numOut](), *curOut = out; - std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */ - std::vector<aiVector2D> temp_verts(max_out+2); - - // Apply vertex colors to represent the face winding? -#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING - if (!pMesh->mColors[0]) - pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices]; - else - new(pMesh->mColors[0]) aiColor4D[pMesh->mNumVertices]; - - aiColor4D* clr = pMesh->mColors[0]; -#endif - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - FILE* fout = fopen(POLY_OUTPUT_FILE,"a"); -#endif - - const aiVector3D* verts = pMesh->mVertices; - - // use std::unique_ptr to avoid slow std::vector<bool> specialiations - std::unique_ptr<bool[]> done(new bool[max_out]); - for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { - aiFace& face = pMesh->mFaces[a]; - - unsigned int* idx = face.mIndices; - int num = (int)face.mNumIndices, ear = 0, tmp, prev = num-1, next = 0, max = num; - - // Apply vertex colors to represent the face winding? -#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING - for (unsigned int i = 0; i < face.mNumIndices; ++i) { - aiColor4D& c = clr[idx[i]]; - c.r = (i+1) / (float)max; - c.b = 1.f - c.r; - } -#endif - - aiFace* const last_face = curOut; - - // if it's a simple point,line or triangle: just copy it - if( face.mNumIndices <= 3) - { - aiFace& nface = *curOut++; - nface.mNumIndices = face.mNumIndices; - nface.mIndices = face.mIndices; - - face.mIndices = NULL; - continue; - } - // optimized code for quadrilaterals - else if ( face.mNumIndices == 4) { - - // quads can have at maximum one concave vertex. Determine - // this vertex (if it exists) and start tri-fanning from - // it. - unsigned int start_vertex = 0; - for (unsigned int i = 0; i < 4; ++i) { - const aiVector3D& v0 = verts[face.mIndices[(i+3) % 4]]; - const aiVector3D& v1 = verts[face.mIndices[(i+2) % 4]]; - const aiVector3D& v2 = verts[face.mIndices[(i+1) % 4]]; - - const aiVector3D& v = verts[face.mIndices[i]]; - - aiVector3D left = (v0-v); - aiVector3D diag = (v1-v); - aiVector3D right = (v2-v); - - left.Normalize(); - diag.Normalize(); - right.Normalize(); - - const float angle = std::acos(left*diag) + std::acos(right*diag); - if (angle > AI_MATH_PI_F) { - // this is the concave point - start_vertex = i; - break; - } - } - - const unsigned int temp[] = {face.mIndices[0], face.mIndices[1], face.mIndices[2], face.mIndices[3]}; - - aiFace& nface = *curOut++; - nface.mNumIndices = 3; - nface.mIndices = face.mIndices; - - nface.mIndices[0] = temp[start_vertex]; - nface.mIndices[1] = temp[(start_vertex + 1) % 4]; - nface.mIndices[2] = temp[(start_vertex + 2) % 4]; - - aiFace& sface = *curOut++; - sface.mNumIndices = 3; - sface.mIndices = new unsigned int[3]; - - sface.mIndices[0] = temp[start_vertex]; - sface.mIndices[1] = temp[(start_vertex + 2) % 4]; - sface.mIndices[2] = temp[(start_vertex + 3) % 4]; - - // prevent double deletion of the indices field - face.mIndices = NULL; - continue; - } - else - { - // A polygon with more than 3 vertices can be either concave or convex. - // Usually everything we're getting is convex and we could easily - // triangulate by tri-fanning. However, LightWave is probably the only - // modeling suite to make extensive use of highly concave, monster polygons ... - // so we need to apply the full 'ear cutting' algorithm to get it right. - - // RERQUIREMENT: polygon is expected to be simple and *nearly* planar. - // We project it onto a plane to get a 2d triangle. - - // Collect all vertices of of the polygon. - for (tmp = 0; tmp < max; ++tmp) { - temp_verts3d[tmp] = verts[idx[tmp]]; - } - - // Get newell normal of the polygon. Store it for future use if it's a polygon-only mesh - aiVector3D n; - NewellNormal<3,3,3>(n,max,&temp_verts3d.front().x,&temp_verts3d.front().y,&temp_verts3d.front().z); - if (nor_out) { - for (tmp = 0; tmp < max; ++tmp) - nor_out[idx[tmp]] = n; - } - - // Select largest normal coordinate to ignore for projection - const float ax = (n.x>0 ? n.x : -n.x); - const float ay = (n.y>0 ? n.y : -n.y); - const float az = (n.z>0 ? n.z : -n.z); - - unsigned int ac = 0, bc = 1; /* no z coord. projection to xy */ - float inv = n.z; - if (ax > ay) { - if (ax > az) { /* no x coord. projection to yz */ - ac = 1; bc = 2; - inv = n.x; - } - } - else if (ay > az) { /* no y coord. projection to zy */ - ac = 2; bc = 0; - inv = n.y; - } - - // Swap projection axes to take the negated projection vector into account - if (inv < 0.f) { - std::swap(ac,bc); - } - - for (tmp =0; tmp < max; ++tmp) { - temp_verts[tmp].x = verts[idx[tmp]][ac]; - temp_verts[tmp].y = verts[idx[tmp]][bc]; - done[tmp] = false; - } - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - // plot the plane onto which we mapped the polygon to a 2D ASCII pic - aiVector2D bmin,bmax; - ArrayBounds(&temp_verts[0],max,bmin,bmax); - - char grid[POLY_GRID_Y][POLY_GRID_X+POLY_GRID_XPAD]; - std::fill_n((char*)grid,POLY_GRID_Y*(POLY_GRID_X+POLY_GRID_XPAD),' '); - - for (int i =0; i < max; ++i) { - const aiVector2D& v = (temp_verts[i] - bmin) / (bmax-bmin); - const size_t x = static_cast<size_t>(v.x*(POLY_GRID_X-1)), y = static_cast<size_t>(v.y*(POLY_GRID_Y-1)); - char* loc = grid[y]+x; - if (grid[y][x] != ' ') { - for(;*loc != ' '; ++loc); - *loc++ = '_'; - } - *(loc+::ai_snprintf(loc, POLY_GRID_XPAD,"%i",i)) = ' '; - } - - - for(size_t y = 0; y < POLY_GRID_Y; ++y) { - grid[y][POLY_GRID_X+POLY_GRID_XPAD-1] = '\0'; - fprintf(fout,"%s\n",grid[y]); - } - - fprintf(fout,"\ntriangulation sequence: "); -#endif - - // - // FIXME: currently this is the slow O(kn) variant with a worst case - // complexity of O(n^2) (I think). Can be done in O(n). - while (num > 3) { - - // Find the next ear of the polygon - int num_found = 0; - for (ear = next;;prev = ear,ear = next) { - - // break after we looped two times without a positive match - for (next=ear+1;done[(next>=max?next=0:next)];++next); - if (next < ear) { - if (++num_found == 2) { - break; - } - } - const aiVector2D* pnt1 = &temp_verts[ear], - *pnt0 = &temp_verts[prev], - *pnt2 = &temp_verts[next]; - - // Must be a convex point. Assuming ccw winding, it must be on the right of the line between p-1 and p+1. - if (OnLeftSideOfLine2D(*pnt0,*pnt2,*pnt1)) { - continue; - } - - // and no other point may be contained in this triangle - for ( tmp = 0; tmp < max; ++tmp) { - - // We need to compare the actual values because it's possible that multiple indexes in - // the polygon are referring to the same position. concave_polygon.obj is a sample - // - // FIXME: Use 'epsiloned' comparisons instead? Due to numeric inaccuracies in - // PointInTriangle() I'm guessing that it's actually possible to construct - // input data that would cause us to end up with no ears. The problem is, - // which epsilon? If we chose a too large value, we'd get wrong results - const aiVector2D& vtmp = temp_verts[tmp]; - if ( vtmp != *pnt1 && vtmp != *pnt2 && vtmp != *pnt0 && PointInTriangle2D(*pnt0,*pnt1,*pnt2,vtmp)) { - break; - } - } - if (tmp != max) { - continue; - } - - // this vertex is an ear - break; - } - if (num_found == 2) { - - // Due to the 'two ear theorem', every simple polygon with more than three points must - // have 2 'ears'. Here's definitely something wrong ... but we don't give up yet. - // - - // Instead we're continuing with the standard tri-fanning algorithm which we'd - // use if we had only convex polygons. That's life. - ASSIMP_LOG_ERROR("Failed to triangulate polygon (no ear found). Probably not a simple polygon?"); - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - fprintf(fout,"critical error here, no ear found! "); -#endif - num = 0; - break; - - curOut -= (max-num); /* undo all previous work */ - for (tmp = 0; tmp < max-2; ++tmp) { - aiFace& nface = *curOut++; - - nface.mNumIndices = 3; - if (!nface.mIndices) - nface.mIndices = new unsigned int[3]; - - nface.mIndices[0] = 0; - nface.mIndices[1] = tmp+1; - nface.mIndices[2] = tmp+2; - - } - num = 0; - break; - } - - aiFace& nface = *curOut++; - nface.mNumIndices = 3; - - if (!nface.mIndices) { - nface.mIndices = new unsigned int[3]; - } - - // setup indices for the new triangle ... - nface.mIndices[0] = prev; - nface.mIndices[1] = ear; - nface.mIndices[2] = next; - - // exclude the ear from most further processing - done[ear] = true; - --num; - } - if (num > 0) { - // We have three indices forming the last 'ear' remaining. Collect them. - aiFace& nface = *curOut++; - nface.mNumIndices = 3; - if (!nface.mIndices) { - nface.mIndices = new unsigned int[3]; - } - - for (tmp = 0; done[tmp]; ++tmp); - nface.mIndices[0] = tmp; - - for (++tmp; done[tmp]; ++tmp); - nface.mIndices[1] = tmp; - - for (++tmp; done[tmp]; ++tmp); - nface.mIndices[2] = tmp; - - } - } - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - - for(aiFace* f = last_face; f != curOut; ++f) { - unsigned int* i = f->mIndices; - fprintf(fout," (%i %i %i)",i[0],i[1],i[2]); - } - - fprintf(fout,"\n*********************************************************************\n"); - fflush(fout); - -#endif - - for(aiFace* f = last_face; f != curOut; ) { - unsigned int* i = f->mIndices; - - // drop dumb 0-area triangles - deactivated for now: - //FindDegenerates post processing step can do the same thing - //if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) { - // ASSIMP_LOG_DEBUG("Dropping triangle with area 0"); - // --curOut; - - // delete[] f->mIndices; - // f->mIndices = nullptr; - - // for(aiFace* ff = f; ff != curOut; ++ff) { - // ff->mNumIndices = (ff+1)->mNumIndices; - // ff->mIndices = (ff+1)->mIndices; - // (ff+1)->mIndices = nullptr; - // } - // continue; - //} - - i[0] = idx[i[0]]; - i[1] = idx[i[1]]; - i[2] = idx[i[2]]; - ++f; - } - - delete[] face.mIndices; - face.mIndices = NULL; - } - -#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS - fclose(fout); -#endif - - // kill the old faces - delete [] pMesh->mFaces; - - // ... and store the new ones - pMesh->mFaces = out; - pMesh->mNumFaces = (unsigned int)(curOut-out); /* not necessarily equal to numOut */ - return true; -} - -#endif // !! ASSIMP_BUILD_NO_TRIANGULATE_PROCESS diff --git a/thirdparty/assimp/code/PostProcessing/TriangulateProcess.h b/thirdparty/assimp/code/PostProcessing/TriangulateProcess.h deleted file mode 100644 index 916b5103dd..0000000000 --- a/thirdparty/assimp/code/PostProcessing/TriangulateProcess.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a post processing step to triangulate all faces - with more than three vertices. - */ -#ifndef AI_TRIANGULATEPROCESS_H_INC -#define AI_TRIANGULATEPROCESS_H_INC - -#include "Common/BaseProcess.h" - -struct aiMesh; - -class TriangulateProcessTest; - -namespace Assimp { - -// --------------------------------------------------------------------------- -/** The TriangulateProcess splits up all faces with more than three indices - * into triangles. You usually want this to happen because the graphics cards - * need their data as triangles. - */ -class ASSIMP_API TriangulateProcess : public BaseProcess { -public: - TriangulateProcess(); - ~TriangulateProcess(); - - // ------------------------------------------------------------------- - /** Returns whether the processing step is present in the given flag field. - * @param pFlags The processing flags the importer was called with. A bitwise - * combination of #aiPostProcessSteps. - * @return true if the process is present in this flag fields, false if not. - */ - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - /** Executes the post processing step on the given imported data. - * At the moment a process is not supposed to fail. - * @param pScene The imported data to work at. - */ - void Execute( aiScene* pScene); - - // ------------------------------------------------------------------- - /** Triangulates the given mesh. - * @param pMesh The mesh to triangulate. - */ - bool TriangulateMesh( aiMesh* pMesh); -}; - -} // end of namespace Assimp - -#endif // AI_TRIANGULATEPROCESS_H_INC diff --git a/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.cpp b/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.cpp deleted file mode 100644 index 75d1b6ef78..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.cpp +++ /dev/null @@ -1,1034 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -/** @file ValidateDataStructure.cpp - * @brief Implementation of the post processing step to validate - * the data structure returned by Assimp. - */ - -// internal headers -#include "ValidateDataStructure.h" -#include <assimp/BaseImporter.h> -#include <assimp/fast_atof.h> -#include "ProcessHelper.h" -#include <memory> - -// CRT headers -#include <stdarg.h> - -using namespace Assimp; - -// ------------------------------------------------------------------------------------------------ -// Constructor to be privately used by Importer -ValidateDSProcess::ValidateDSProcess() : - mScene() -{} - -// ------------------------------------------------------------------------------------------------ -// Destructor, private as well -ValidateDSProcess::~ValidateDSProcess() -{} - -// ------------------------------------------------------------------------------------------------ -// Returns whether the processing step is present in the given flag field. -bool ValidateDSProcess::IsActive( unsigned int pFlags) const -{ - return (pFlags & aiProcess_ValidateDataStructure) != 0; -} -// ------------------------------------------------------------------------------------------------ -AI_WONT_RETURN void ValidateDSProcess::ReportError(const char* msg,...) -{ - ai_assert(NULL != msg); - - va_list args; - va_start(args,msg); - - char szBuffer[3000]; - const int iLen = vsprintf(szBuffer,msg,args); - ai_assert(iLen > 0); - - va_end(args); - - throw DeadlyImportError("Validation failed: " + std::string(szBuffer,iLen)); -} -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::ReportWarning(const char* msg,...) -{ - ai_assert(NULL != msg); - - va_list args; - va_start(args,msg); - - char szBuffer[3000]; - const int iLen = vsprintf(szBuffer,msg,args); - ai_assert(iLen > 0); - - va_end(args); - ASSIMP_LOG_WARN("Validation warning: " + std::string(szBuffer,iLen)); -} - -// ------------------------------------------------------------------------------------------------ -inline -int HasNameMatch(const aiString& in, aiNode* node) { - int result = (node->mName == in ? 1 : 0 ); - for (unsigned int i = 0; i < node->mNumChildren;++i) { - result += HasNameMatch(in,node->mChildren[i]); - } - return result; -} - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline -void ValidateDSProcess::DoValidation(T** parray, unsigned int size, const char* firstName, const char* secondName) { - // validate all entries - if (size) - { - if (!parray) - { - ReportError("aiScene::%s is NULL (aiScene::%s is %i)", - firstName, secondName, size); - } - for (unsigned int i = 0; i < size;++i) - { - if (!parray[i]) - { - ReportError("aiScene::%s[%i] is NULL (aiScene::%s is %i)", - firstName,i,secondName,size); - } - Validate(parray[i]); - } - } -} - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline void ValidateDSProcess::DoValidationEx(T** parray, unsigned int size, - const char* firstName, const char* secondName) -{ - // validate all entries - if (size) - { - if (!parray) { - ReportError("aiScene::%s is NULL (aiScene::%s is %i)", - firstName, secondName, size); - } - for (unsigned int i = 0; i < size;++i) - { - if (!parray[i]) - { - ReportError("aiScene::%s[%u] is NULL (aiScene::%s is %u)", - firstName,i,secondName,size); - } - Validate(parray[i]); - - // check whether there are duplicate names - for (unsigned int a = i+1; a < size;++a) - { - if (parray[i]->mName == parray[a]->mName) - { - ReportError("aiScene::%s[%u] has the same name as " - "aiScene::%s[%u]",firstName, i,secondName, a); - } - } - } - } -} - -// ------------------------------------------------------------------------------------------------ -template <typename T> -inline -void ValidateDSProcess::DoValidationWithNameCheck(T** array, unsigned int size, const char* firstName, - const char* secondName) { - // validate all entries - DoValidationEx(array,size,firstName,secondName); - - for (unsigned int i = 0; i < size;++i) { - int res = HasNameMatch(array[i]->mName,mScene->mRootNode); - if (0 == res) { - const std::string name = static_cast<char*>(array[i]->mName.data); - ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)", - firstName,i, name.c_str()); - } else if (1 != res) { - const std::string name = static_cast<char*>(array[i]->mName.data); - ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name", - firstName,i, name.c_str()); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Executes the post processing step on the given imported data. -void ValidateDSProcess::Execute( aiScene* pScene) { - mScene = pScene; - ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin"); - - // validate the node graph of the scene - Validate(pScene->mRootNode); - - // validate all meshes - if (pScene->mNumMeshes) { - DoValidation(pScene->mMeshes,pScene->mNumMeshes,"mMeshes","mNumMeshes"); - } - else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) { - ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there"); - } - else if (pScene->mMeshes) { - ReportError("aiScene::mMeshes is non-null although there are no meshes"); - } - - // validate all animations - if (pScene->mNumAnimations) { - DoValidation(pScene->mAnimations,pScene->mNumAnimations, - "mAnimations","mNumAnimations"); - } - else if (pScene->mAnimations) { - ReportError("aiScene::mAnimations is non-null although there are no animations"); - } - - // validate all cameras - if (pScene->mNumCameras) { - DoValidationWithNameCheck(pScene->mCameras,pScene->mNumCameras, - "mCameras","mNumCameras"); - } - else if (pScene->mCameras) { - ReportError("aiScene::mCameras is non-null although there are no cameras"); - } - - // validate all lights - if (pScene->mNumLights) { - DoValidationWithNameCheck(pScene->mLights,pScene->mNumLights, - "mLights","mNumLights"); - } - else if (pScene->mLights) { - ReportError("aiScene::mLights is non-null although there are no lights"); - } - - // validate all textures - if (pScene->mNumTextures) { - DoValidation(pScene->mTextures,pScene->mNumTextures, - "mTextures","mNumTextures"); - } - else if (pScene->mTextures) { - ReportError("aiScene::mTextures is non-null although there are no textures"); - } - - // validate all materials - if (pScene->mNumMaterials) { - DoValidation(pScene->mMaterials,pScene->mNumMaterials,"mMaterials","mNumMaterials"); - } -#if 0 - // NOTE: ScenePreprocessor generates a default material if none is there - else if (!(mScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)) { - ReportError("aiScene::mNumMaterials is 0. At least one material must be there"); - } -#endif - else if (pScene->mMaterials) { - ReportError("aiScene::mMaterials is non-null although there are no materials"); - } - -// if (!has)ReportError("The aiScene data structure is empty"); - ASSIMP_LOG_DEBUG("ValidateDataStructureProcess end"); -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiLight* pLight) -{ - if (pLight->mType == aiLightSource_UNDEFINED) - ReportWarning("aiLight::mType is aiLightSource_UNDEFINED"); - - if (!pLight->mAttenuationConstant && - !pLight->mAttenuationLinear && - !pLight->mAttenuationQuadratic) { - ReportWarning("aiLight::mAttenuationXXX - all are zero"); - } - - if (pLight->mAngleInnerCone > pLight->mAngleOuterCone) - ReportError("aiLight::mAngleInnerCone is larger than aiLight::mAngleOuterCone"); - - if (pLight->mColorDiffuse.IsBlack() && pLight->mColorAmbient.IsBlack() - && pLight->mColorSpecular.IsBlack()) - { - ReportWarning("aiLight::mColorXXX - all are black and won't have any influence"); - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiCamera* pCamera) -{ - if (pCamera->mClipPlaneFar <= pCamera->mClipPlaneNear) - ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear"); - - // FIX: there are many 3ds files with invalid FOVs. No reason to - // reject them at all ... a warning is appropriate. - if (!pCamera->mHorizontalFOV || pCamera->mHorizontalFOV >= (float)AI_MATH_PI) - ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV",pCamera->mHorizontalFOV); -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiMesh* pMesh) -{ - // validate the material index of the mesh - if (mScene->mNumMaterials && pMesh->mMaterialIndex >= mScene->mNumMaterials) - { - ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)", - pMesh->mMaterialIndex,mScene->mNumMaterials-1); - } - - Validate(&pMesh->mName); - - for (unsigned int i = 0; i < pMesh->mNumFaces; ++i) - { - aiFace& face = pMesh->mFaces[i]; - - if (pMesh->mPrimitiveTypes) - { - switch (face.mNumIndices) - { - case 0: - ReportError("aiMesh::mFaces[%i].mNumIndices is 0",i); - break; - case 1: - if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT)) - { - ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimitiveTypes " - "does not report the POINT flag",i); - } - break; - case 2: - if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_LINE)) - { - ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimitiveTypes " - "does not report the LINE flag",i); - } - break; - case 3: - if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_TRIANGLE)) - { - ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimitiveTypes " - "does not report the TRIANGLE flag",i); - } - break; - default: - if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POLYGON)) - { - this->ReportError("aiMesh::mFaces[%i] is a POLYGON but aiMesh::mPrimitiveTypes " - "does not report the POLYGON flag",i); - } - break; - }; - } - - if (!face.mIndices) - ReportError("aiMesh::mFaces[%i].mIndices is NULL",i); - } - - // positions must always be there ... - if (!pMesh->mNumVertices || (!pMesh->mVertices && !mScene->mFlags)) { - ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str()); - } - - if (pMesh->mNumVertices > AI_MAX_VERTICES) { - ReportError("Mesh has too many vertices: %u, but the limit is %u",pMesh->mNumVertices,AI_MAX_VERTICES); - } - if (pMesh->mNumFaces > AI_MAX_FACES) { - ReportError("Mesh has too many faces: %u, but the limit is %u",pMesh->mNumFaces,AI_MAX_FACES); - } - - // if tangents are there there must also be bitangent vectors ... - if ((pMesh->mTangents != NULL) != (pMesh->mBitangents != NULL)) { - ReportError("If there are tangents, bitangent vectors must be present as well"); - } - - // faces, too - if (!pMesh->mNumFaces || (!pMesh->mFaces && !mScene->mFlags)) { - ReportError("Mesh %s contains no faces", pMesh->mName.C_Str()); - } - - // now check whether the face indexing layout is correct: - // unique vertices, pseudo-indexed. - std::vector<bool> abRefList; - abRefList.resize(pMesh->mNumVertices,false); - for (unsigned int i = 0; i < pMesh->mNumFaces;++i) - { - aiFace& face = pMesh->mFaces[i]; - if (face.mNumIndices > AI_MAX_FACE_INDICES) { - ReportError("Face %u has too many faces: %u, but the limit is %u",i,face.mNumIndices,AI_MAX_FACE_INDICES); - } - - for (unsigned int a = 0; a < face.mNumIndices;++a) - { - if (face.mIndices[a] >= pMesh->mNumVertices) { - ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a); - } - // the MSB flag is temporarily used by the extra verbose - // mode to tell us that the JoinVerticesProcess might have - // been executed already. - /*if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && !(this->mScene->mFlags & AI_SCENE_FLAGS_ALLOW_SHARED) && - abRefList[face.mIndices[a]]) - { - ReportError("aiMesh::mVertices[%i] is referenced twice - second " - "time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a); - }*/ - abRefList[face.mIndices[a]] = true; - } - } - - // check whether there are vertices that aren't referenced by a face - bool b = false; - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) { - if (!abRefList[i])b = true; - } - abRefList.clear(); - if (b) { - ReportWarning("There are unreferenced vertices"); - } - - // texture channel 2 may not be set if channel 1 is zero ... - { - unsigned int i = 0; - for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - { - if (!pMesh->HasTextureCoords(i))break; - } - for (;i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - if (pMesh->HasTextureCoords(i)) - { - ReportError("Texture coordinate channel %i exists " - "although the previous channel was NULL.",i); - } - } - // the same for the vertex colors - { - unsigned int i = 0; - for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i) - { - if (!pMesh->HasVertexColors(i))break; - } - for (;i < AI_MAX_NUMBER_OF_COLOR_SETS;++i) - if (pMesh->HasVertexColors(i)) - { - ReportError("Vertex color channel %i is exists " - "although the previous channel was NULL.",i); - } - } - - - // now validate all bones - if (pMesh->mNumBones) - { - if (!pMesh->mBones) - { - ReportError("aiMesh::mBones is NULL (aiMesh::mNumBones is %i)", - pMesh->mNumBones); - } - std::unique_ptr<float[]> afSum(nullptr); - if (pMesh->mNumVertices) - { - afSum.reset(new float[pMesh->mNumVertices]); - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) - afSum[i] = 0.0f; - } - - // check whether there are duplicate bone names - for (unsigned int i = 0; i < pMesh->mNumBones;++i) - { - const aiBone* bone = pMesh->mBones[i]; - if (bone->mNumWeights > AI_MAX_BONE_WEIGHTS) { - ReportError("Bone %u has too many weights: %u, but the limit is %u",i,bone->mNumWeights,AI_MAX_BONE_WEIGHTS); - } - - if (!pMesh->mBones[i]) - { - ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)", - i,pMesh->mNumBones); - } - Validate(pMesh,pMesh->mBones[i],afSum.get()); - - for (unsigned int a = i+1; a < pMesh->mNumBones;++a) - { - if (pMesh->mBones[i]->mName == pMesh->mBones[a]->mName) - { - const char *name = "unknown"; - if (nullptr != pMesh->mBones[ i ]->mName.C_Str()) { - name = pMesh->mBones[ i ]->mName.C_Str(); - } - ReportError("aiMesh::mBones[%i], name = \"%s\" has the same name as " - "aiMesh::mBones[%i]", i, name, a ); - } - } - } - // check whether all bone weights for a vertex sum to 1.0 ... - for (unsigned int i = 0; i < pMesh->mNumVertices;++i) - { - if (afSum[i] && (afSum[i] <= 0.94 || afSum[i] >= 1.05)) { - ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)",i,afSum[i]); - } - } - } - else if (pMesh->mBones) - { - ReportError("aiMesh::mBones is non-null although there are no bones"); - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiMesh* pMesh, const aiBone* pBone,float* afSum) { - this->Validate(&pBone->mName); - - if (!pBone->mNumWeights) { - //ReportError("aiBone::mNumWeights is zero"); - } - - // check whether all vertices affected by this bone are valid - for (unsigned int i = 0; i < pBone->mNumWeights;++i) - { - if (pBone->mWeights[i].mVertexId >= pMesh->mNumVertices) { - ReportError("aiBone::mWeights[%i].mVertexId is out of range",i); - } - else if (!pBone->mWeights[i].mWeight || pBone->mWeights[i].mWeight > 1.0f) { - ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value",i); - } - afSum[pBone->mWeights[i].mVertexId] += pBone->mWeights[i].mWeight; - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiAnimation* pAnimation) -{ - Validate(&pAnimation->mName); - - // validate all animations - if (pAnimation->mNumChannels || pAnimation->mNumMorphMeshChannels) - { - if (!pAnimation->mChannels && pAnimation->mNumChannels) { - ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)", - pAnimation->mNumChannels); - } - if (!pAnimation->mMorphMeshChannels && pAnimation->mNumMorphMeshChannels) { - ReportError("aiAnimation::mMorphMeshChannels is NULL (aiAnimation::mNumMorphMeshChannels is %i)", - pAnimation->mNumMorphMeshChannels); - } - for (unsigned int i = 0; i < pAnimation->mNumChannels;++i) - { - if (!pAnimation->mChannels[i]) - { - ReportError("aiAnimation::mChannels[%i] is NULL (aiAnimation::mNumChannels is %i)", - i, pAnimation->mNumChannels); - } - Validate(pAnimation, pAnimation->mChannels[i]); - } - for (unsigned int i = 0; i < pAnimation->mNumMorphMeshChannels;++i) - { - if (!pAnimation->mMorphMeshChannels[i]) - { - ReportError("aiAnimation::mMorphMeshChannels[%i] is NULL (aiAnimation::mNumMorphMeshChannels is %i)", - i, pAnimation->mNumMorphMeshChannels); - } - Validate(pAnimation, pAnimation->mMorphMeshChannels[i]); - } - } - else { - ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial, - aiTextureType type) -{ - const char* szType = TextureTypeToString(type); - - // **************************************************************************** - // Search all keys of the material ... - // textures must be specified with ascending indices - // (e.g. diffuse #2 may not be specified if diffuse #1 is not there ...) - // **************************************************************************** - - int iNumIndices = 0; - int iIndex = -1; - for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) { - aiMaterialProperty* prop = pMaterial->mProperties[ i ]; - ai_assert(nullptr != prop); - if ( !::strcmp(prop->mKey.data,"$tex.file") && prop->mSemantic == static_cast<unsigned int>(type)) { - iIndex = std::max(iIndex, (int) prop->mIndex); - ++iNumIndices; - - if (aiPTI_String != prop->mType) { - ReportError("Material property %s is expected to be a string", prop->mKey.data); - } - } - } - if (iIndex +1 != iNumIndices) { - ReportError("%s #%i is set, but there are only %i %s textures", - szType,iIndex,iNumIndices,szType); - } - if (!iNumIndices)return; - std::vector<aiTextureMapping> mappings(iNumIndices); - - // Now check whether all UV indices are valid ... - bool bNoSpecified = true; - for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) - { - aiMaterialProperty* prop = pMaterial->mProperties[i]; - if (prop->mSemantic != type)continue; - - if ((int)prop->mIndex >= iNumIndices) - { - ReportError("Found texture property with index %i, although there " - "are only %i textures of type %s", - prop->mIndex, iNumIndices, szType); - } - - if (!::strcmp(prop->mKey.data,"$tex.mapping")) { - if (aiPTI_Integer != prop->mType || prop->mDataLength < sizeof(aiTextureMapping)) - { - ReportError("Material property %s%i is expected to be an integer (size is %i)", - prop->mKey.data,prop->mIndex,prop->mDataLength); - } - mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData); - } - else if (!::strcmp(prop->mKey.data,"$tex.uvtrafo")) { - if (aiPTI_Float != prop->mType || prop->mDataLength < sizeof(aiUVTransform)) - { - ReportError("Material property %s%i is expected to be 5 floats large (size is %i)", - prop->mKey.data,prop->mIndex, prop->mDataLength); - } - mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData); - } - else if (!::strcmp(prop->mKey.data,"$tex.uvwsrc")) { - if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength) - { - ReportError("Material property %s%i is expected to be an integer (size is %i)", - prop->mKey.data,prop->mIndex,prop->mDataLength); - } - bNoSpecified = false; - - // Ignore UV indices for texture channels that are not there ... - - // Get the value - iIndex = *((unsigned int*)prop->mData); - - // Check whether there is a mesh using this material - // which has not enough UV channels ... - for (unsigned int a = 0; a < mScene->mNumMeshes;++a) - { - aiMesh* mesh = this->mScene->mMeshes[a]; - if(mesh->mMaterialIndex == (unsigned int)i) - { - int iChannels = 0; - while (mesh->HasTextureCoords(iChannels))++iChannels; - if (iIndex >= iChannels) - { - ReportWarning("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels", - iIndex,prop->mKey.data,a,iChannels); - } - } - } - } - } - if (bNoSpecified) - { - // Assume that all textures are using the first UV channel - for (unsigned int a = 0; a < mScene->mNumMeshes;++a) - { - aiMesh* mesh = mScene->mMeshes[a]; - if(mesh->mMaterialIndex == (unsigned int)iIndex && mappings[0] == aiTextureMapping_UV) - { - if (!mesh->mTextureCoords[0]) - { - // This is a special case ... it could be that the - // original mesh format intended the use of a special - // mapping here. - ReportWarning("UV-mapped texture, but there are no UV coords"); - } - } - } - } -} -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiMaterial* pMaterial) -{ - // check whether there are material keys that are obviously not legal - for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) - { - const aiMaterialProperty* prop = pMaterial->mProperties[i]; - if (!prop) { - ReportError("aiMaterial::mProperties[%i] is NULL (aiMaterial::mNumProperties is %i)", - i,pMaterial->mNumProperties); - } - if (!prop->mDataLength || !prop->mData) { - ReportError("aiMaterial::mProperties[%i].mDataLength or " - "aiMaterial::mProperties[%i].mData is 0",i,i); - } - // check all predefined types - if (aiPTI_String == prop->mType) { - // FIX: strings are now stored in a less expensive way, but we can't use the - // validation routine for 'normal' aiStrings - if (prop->mDataLength < 5 || prop->mDataLength < 4 + (*reinterpret_cast<uint32_t*>(prop->mData)) + 1) { - ReportError("aiMaterial::mProperties[%i].mDataLength is " - "too small to contain a string (%i, needed: %i)", - i,prop->mDataLength,static_cast<int>(sizeof(aiString))); - } - if(prop->mData[prop->mDataLength-1]) { - ReportError("Missing null-terminator in string material property"); - } - // Validate((const aiString*)prop->mData); - } - else if (aiPTI_Float == prop->mType) { - if (prop->mDataLength < sizeof(float)) { - ReportError("aiMaterial::mProperties[%i].mDataLength is " - "too small to contain a float (%i, needed: %i)", - i,prop->mDataLength, static_cast<int>(sizeof(float))); - } - } - else if (aiPTI_Integer == prop->mType) { - if (prop->mDataLength < sizeof(int)) { - ReportError("aiMaterial::mProperties[%i].mDataLength is " - "too small to contain an integer (%i, needed: %i)", - i,prop->mDataLength, static_cast<int>(sizeof(int))); - } - } - // TODO: check whether there is a key with an unknown name ... - } - - // make some more specific tests - ai_real fTemp; - int iShading; - if (AI_SUCCESS == aiGetMaterialInteger( pMaterial,AI_MATKEY_SHADING_MODEL,&iShading)) { - switch ((aiShadingMode)iShading) - { - case aiShadingMode_Blinn: - case aiShadingMode_CookTorrance: - case aiShadingMode_Phong: - - if (AI_SUCCESS != aiGetMaterialFloat(pMaterial,AI_MATKEY_SHININESS,&fTemp)) { - ReportWarning("A specular shading model is specified but there is no " - "AI_MATKEY_SHININESS key"); - } - if (AI_SUCCESS == aiGetMaterialFloat(pMaterial,AI_MATKEY_SHININESS_STRENGTH,&fTemp) && !fTemp) { - ReportWarning("A specular shading model is specified but the value of the " - "AI_MATKEY_SHININESS_STRENGTH key is 0.0"); - } - break; - default: - break; - } - } - - if (AI_SUCCESS == aiGetMaterialFloat( pMaterial,AI_MATKEY_OPACITY,&fTemp) && (!fTemp || fTemp > 1.01)) { - ReportWarning("Invalid opacity value (must be 0 < opacity < 1.0)"); - } - - // Check whether there are invalid texture keys - // TODO: that's a relict of the past, where texture type and index were baked - // into the material string ... we could do that in one single pass. - SearchForInvalidTextures(pMaterial,aiTextureType_DIFFUSE); - SearchForInvalidTextures(pMaterial,aiTextureType_SPECULAR); - SearchForInvalidTextures(pMaterial,aiTextureType_AMBIENT); - SearchForInvalidTextures(pMaterial,aiTextureType_EMISSIVE); - SearchForInvalidTextures(pMaterial,aiTextureType_OPACITY); - SearchForInvalidTextures(pMaterial,aiTextureType_SHININESS); - SearchForInvalidTextures(pMaterial,aiTextureType_HEIGHT); - SearchForInvalidTextures(pMaterial,aiTextureType_NORMALS); - SearchForInvalidTextures(pMaterial,aiTextureType_DISPLACEMENT); - SearchForInvalidTextures(pMaterial,aiTextureType_LIGHTMAP); - SearchForInvalidTextures(pMaterial,aiTextureType_REFLECTION); -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiTexture* pTexture) -{ - // the data section may NEVER be NULL - if (!pTexture->pcData) { - ReportError("aiTexture::pcData is NULL"); - } - if (pTexture->mHeight) - { - if (!pTexture->mWidth){ - ReportError("aiTexture::mWidth is zero (aiTexture::mHeight is %i, uncompressed texture)", - pTexture->mHeight); - } - } - else - { - if (!pTexture->mWidth) { - ReportError("aiTexture::mWidth is zero (compressed texture)"); - } - if ('\0' != pTexture->achFormatHint[3]) { - ReportWarning("aiTexture::achFormatHint must be zero-terminated"); - } - else if ('.' == pTexture->achFormatHint[0]) { - ReportWarning("aiTexture::achFormatHint should contain a file extension " - "without a leading dot (format hint: %s).",pTexture->achFormatHint); - } - } - - const char* sz = pTexture->achFormatHint; - if ((sz[0] >= 'A' && sz[0] <= 'Z') || - (sz[1] >= 'A' && sz[1] <= 'Z') || - (sz[2] >= 'A' && sz[2] <= 'Z') || - (sz[3] >= 'A' && sz[3] <= 'Z')) { - ReportError("aiTexture::achFormatHint contains non-lowercase letters"); - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiAnimation* pAnimation, - const aiNodeAnim* pNodeAnim) -{ - Validate(&pNodeAnim->mNodeName); - - if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mScalingKeys && !pNodeAnim->mNumRotationKeys) { - ReportError("Empty node animation channel"); - } - // otherwise check whether one of the keys exceeds the total duration of the animation - if (pNodeAnim->mNumPositionKeys) - { - if (!pNodeAnim->mPositionKeys) - { - ReportError("aiNodeAnim::mPositionKeys is NULL (aiNodeAnim::mNumPositionKeys is %i)", - pNodeAnim->mNumPositionKeys); - } - double dLast = -10e10; - for (unsigned int i = 0; i < pNodeAnim->mNumPositionKeys;++i) - { - // ScenePreprocessor will compute the duration if still the default value - // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration, - // seems to be due the compilers register usage/width. - if (pAnimation->mDuration > 0. && pNodeAnim->mPositionKeys[i].mTime > pAnimation->mDuration+0.001) - { - ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger " - "than aiAnimation::mDuration (which is %.5f)",i, - (float)pNodeAnim->mPositionKeys[i].mTime, - (float)pAnimation->mDuration); - } - if (i && pNodeAnim->mPositionKeys[i].mTime <= dLast) - { - ReportWarning("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is smaller " - "than aiAnimation::mPositionKeys[%i] (which is %.5f)",i, - (float)pNodeAnim->mPositionKeys[i].mTime, - i-1, (float)dLast); - } - dLast = pNodeAnim->mPositionKeys[i].mTime; - } - } - // rotation keys - if (pNodeAnim->mNumRotationKeys) - { - if (!pNodeAnim->mRotationKeys) - { - ReportError("aiNodeAnim::mRotationKeys is NULL (aiNodeAnim::mNumRotationKeys is %i)", - pNodeAnim->mNumRotationKeys); - } - double dLast = -10e10; - for (unsigned int i = 0; i < pNodeAnim->mNumRotationKeys;++i) - { - if (pAnimation->mDuration > 0. && pNodeAnim->mRotationKeys[i].mTime > pAnimation->mDuration+0.001) - { - ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger " - "than aiAnimation::mDuration (which is %.5f)",i, - (float)pNodeAnim->mRotationKeys[i].mTime, - (float)pAnimation->mDuration); - } - if (i && pNodeAnim->mRotationKeys[i].mTime <= dLast) - { - ReportWarning("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is smaller " - "than aiAnimation::mRotationKeys[%i] (which is %.5f)",i, - (float)pNodeAnim->mRotationKeys[i].mTime, - i-1, (float)dLast); - } - dLast = pNodeAnim->mRotationKeys[i].mTime; - } - } - // scaling keys - if (pNodeAnim->mNumScalingKeys) - { - if (!pNodeAnim->mScalingKeys) { - ReportError("aiNodeAnim::mScalingKeys is NULL (aiNodeAnim::mNumScalingKeys is %i)", - pNodeAnim->mNumScalingKeys); - } - double dLast = -10e10; - for (unsigned int i = 0; i < pNodeAnim->mNumScalingKeys;++i) - { - if (pAnimation->mDuration > 0. && pNodeAnim->mScalingKeys[i].mTime > pAnimation->mDuration+0.001) - { - ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger " - "than aiAnimation::mDuration (which is %.5f)",i, - (float)pNodeAnim->mScalingKeys[i].mTime, - (float)pAnimation->mDuration); - } - if (i && pNodeAnim->mScalingKeys[i].mTime <= dLast) - { - ReportWarning("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is smaller " - "than aiAnimation::mScalingKeys[%i] (which is %.5f)",i, - (float)pNodeAnim->mScalingKeys[i].mTime, - i-1, (float)dLast); - } - dLast = pNodeAnim->mScalingKeys[i].mTime; - } - } - - if (!pNodeAnim->mNumScalingKeys && !pNodeAnim->mNumRotationKeys && - !pNodeAnim->mNumPositionKeys) - { - ReportError("A node animation channel must have at least one subtrack"); - } -} - -void ValidateDSProcess::Validate( const aiAnimation* pAnimation, - const aiMeshMorphAnim* pMeshMorphAnim) -{ - Validate(&pMeshMorphAnim->mName); - - if (!pMeshMorphAnim->mNumKeys) { - ReportError("Empty mesh morph animation channel"); - } - - // otherwise check whether one of the keys exceeds the total duration of the animation - if (pMeshMorphAnim->mNumKeys) - { - if (!pMeshMorphAnim->mKeys) - { - ReportError("aiMeshMorphAnim::mKeys is NULL (aiMeshMorphAnim::mNumKeys is %i)", - pMeshMorphAnim->mNumKeys); - } - double dLast = -10e10; - for (unsigned int i = 0; i < pMeshMorphAnim->mNumKeys;++i) - { - // ScenePreprocessor will compute the duration if still the default value - // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration, - // seems to be due the compilers register usage/width. - if (pAnimation->mDuration > 0. && pMeshMorphAnim->mKeys[i].mTime > pAnimation->mDuration+0.001) - { - ReportError("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is larger " - "than aiAnimation::mDuration (which is %.5f)",i, - (float)pMeshMorphAnim->mKeys[i].mTime, - (float)pAnimation->mDuration); - } - if (i && pMeshMorphAnim->mKeys[i].mTime <= dLast) - { - ReportWarning("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is smaller " - "than aiMeshMorphAnim::mKeys[%i] (which is %.5f)",i, - (float)pMeshMorphAnim->mKeys[i].mTime, - i-1, (float)dLast); - } - dLast = pMeshMorphAnim->mKeys[i].mTime; - } - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiNode* pNode) -{ - if (!pNode) { - ReportError("A node of the scenegraph is NULL"); - } - // Validate node name string first so that it's safe to use in below expressions - this->Validate(&pNode->mName); - const char* nodeName = (&pNode->mName)->C_Str(); - if (pNode != mScene->mRootNode && !pNode->mParent){ - ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is NULL) ", nodeName); - } - - // validate all meshes - if (pNode->mNumMeshes) - { - if (!pNode->mMeshes) - { - ReportError("aiNode::mMeshes is NULL for node %s (aiNode::mNumMeshes is %i)", - nodeName, pNode->mNumMeshes); - } - std::vector<bool> abHadMesh; - abHadMesh.resize(mScene->mNumMeshes,false); - for (unsigned int i = 0; i < pNode->mNumMeshes;++i) - { - if (pNode->mMeshes[i] >= mScene->mNumMeshes) - { - ReportError("aiNode::mMeshes[%i] is out of range for node %s (maximum is %i)", - pNode->mMeshes[i], nodeName, mScene->mNumMeshes-1); - } - if (abHadMesh[pNode->mMeshes[i]]) - { - ReportError("aiNode::mMeshes[%i] is already referenced by this node %s (value: %i)", - i, nodeName, pNode->mMeshes[i]); - } - abHadMesh[pNode->mMeshes[i]] = true; - } - } - if (pNode->mNumChildren) - { - if (!pNode->mChildren) { - ReportError("aiNode::mChildren is NULL for node %s (aiNode::mNumChildren is %i)", - nodeName, pNode->mNumChildren); - } - for (unsigned int i = 0; i < pNode->mNumChildren;++i) { - Validate(pNode->mChildren[i]); - } - } -} - -// ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiString* pString) -{ - if (pString->length > MAXLEN) - { - ReportError("aiString::length is too large (%u, maximum is %lu)", - pString->length,MAXLEN); - } - const char* sz = pString->data; - while (true) - { - if ('\0' == *sz) - { - if (pString->length != (unsigned int)(sz-pString->data)) { - ReportError("aiString::data is invalid: the terminal zero is at a wrong offset"); - } - break; - } - else if (sz >= &pString->data[MAXLEN]) { - ReportError("aiString::data is invalid. There is no terminal character"); - } - ++sz; - } -} diff --git a/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.h b/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.h deleted file mode 100644 index 7b309c9251..0000000000 --- a/thirdparty/assimp/code/PostProcessing/ValidateDataStructure.h +++ /dev/null @@ -1,197 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2019, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file Defines a (dummy) post processing step to validate the loader's - * output data structure (for debugging) - */ -#ifndef AI_VALIDATEPROCESS_H_INC -#define AI_VALIDATEPROCESS_H_INC - -#include <assimp/types.h> -#include <assimp/material.h> - -#include "Common/BaseProcess.h" - -struct aiBone; -struct aiMesh; -struct aiAnimation; -struct aiNodeAnim; -struct aiMeshMorphAnim; -struct aiTexture; -struct aiMaterial; -struct aiNode; -struct aiString; -struct aiCamera; -struct aiLight; - -namespace Assimp { - -// -------------------------------------------------------------------------------------- -/** Validates the whole ASSIMP scene data structure for correctness. - * ImportErrorException is thrown of the scene is corrupt.*/ -// -------------------------------------------------------------------------------------- -class ValidateDSProcess : public BaseProcess -{ -public: - - ValidateDSProcess(); - ~ValidateDSProcess(); - -public: - // ------------------------------------------------------------------- - bool IsActive( unsigned int pFlags) const; - - // ------------------------------------------------------------------- - void Execute( aiScene* pScene); - -protected: - - // ------------------------------------------------------------------- - /** Report a validation error. This will throw an exception, - * control won't return. - * @param msg Format string for sprintf().*/ - AI_WONT_RETURN void ReportError(const char* msg,...) AI_WONT_RETURN_SUFFIX; - - - // ------------------------------------------------------------------- - /** Report a validation warning. This won't throw an exception, - * control will return to the caller. - * @param msg Format string for sprintf().*/ - void ReportWarning(const char* msg,...); - - - // ------------------------------------------------------------------- - /** Validates a mesh - * @param pMesh Input mesh*/ - void Validate( const aiMesh* pMesh); - - // ------------------------------------------------------------------- - /** Validates a bone - * @param pMesh Input mesh - * @param pBone Input bone*/ - void Validate( const aiMesh* pMesh,const aiBone* pBone,float* afSum); - - // ------------------------------------------------------------------- - /** Validates an animation - * @param pAnimation Input animation*/ - void Validate( const aiAnimation* pAnimation); - - // ------------------------------------------------------------------- - /** Validates a material - * @param pMaterial Input material*/ - void Validate( const aiMaterial* pMaterial); - - // ------------------------------------------------------------------- - /** Search the material data structure for invalid or corrupt - * texture keys. - * @param pMaterial Input material - * @param type Type of the texture*/ - void SearchForInvalidTextures(const aiMaterial* pMaterial, - aiTextureType type); - - // ------------------------------------------------------------------- - /** Validates a texture - * @param pTexture Input texture*/ - void Validate( const aiTexture* pTexture); - - // ------------------------------------------------------------------- - /** Validates a light source - * @param pLight Input light - */ - void Validate( const aiLight* pLight); - - // ------------------------------------------------------------------- - /** Validates a camera - * @param pCamera Input camera*/ - void Validate( const aiCamera* pCamera); - - // ------------------------------------------------------------------- - /** Validates a bone animation channel - * @param pAnimation Animation channel. - * @param pBoneAnim Input bone animation */ - void Validate( const aiAnimation* pAnimation, - const aiNodeAnim* pBoneAnim); - - /** Validates a mesh morph animation channel. - * @param pAnimation Input animation. - * @param pMeshMorphAnim Mesh morph animation channel. - * */ - void Validate( const aiAnimation* pAnimation, - const aiMeshMorphAnim* pMeshMorphAnim); - - // ------------------------------------------------------------------- - /** Validates a node and all of its subnodes - * @param Node Input node*/ - void Validate( const aiNode* pNode); - - // ------------------------------------------------------------------- - /** Validates a string - * @param pString Input string*/ - void Validate( const aiString* pString); - -private: - - // template to validate one of the aiScene::mXXX arrays - template <typename T> - inline void DoValidation(T** array, unsigned int size, - const char* firstName, const char* secondName); - - // extended version: checks whether T::mName occurs twice - template <typename T> - inline void DoValidationEx(T** array, unsigned int size, - const char* firstName, const char* secondName); - - // extension to the first template which does also search - // the nodegraph for an item with the same name - template <typename T> - inline void DoValidationWithNameCheck(T** array, unsigned int size, - const char* firstName, const char* secondName); - - aiScene* mScene; -}; - - - - -} // end of namespace Assimp - -#endif // AI_VALIDATEPROCESS_H_INC |