diff --git a/code/B3D/B3DImporter.cpp b/code/B3D/B3DImporter.cpp index ba484ca00..c9eb89ebc 100644 --- a/code/B3D/B3DImporter.cpp +++ b/code/B3D/B3DImporter.cpp @@ -5,8 +5,6 @@ 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, @@ -78,7 +76,6 @@ static const aiImporterDesc desc = { "b3d" }; -// (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings #ifdef _MSC_VER # pragma warning (disable: 4018) #endif @@ -86,10 +83,8 @@ static const aiImporterDesc desc = { //#define DEBUG_B3D template -void DeleteAllBarePointers(std::vector& x) -{ - for(auto p : x) - { +void DeleteAllBarePointers(std::vector& x) { + for(auto p : x) { delete p; } } @@ -102,10 +97,14 @@ B3DImporter::~B3DImporter() bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{ size_t pos=pFile.find_last_of( '.' ); - if( pos==string::npos ) return false; + if( pos==string::npos ) { + return false; + } string ext=pFile.substr( pos+1 ); - if( ext.size()!=3 ) return false; + if( ext.size()!=3 ) { + return false; + } return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D'); } @@ -117,30 +116,21 @@ const aiImporterDesc* B3DImporter::GetInfo () const return &desc; } -#ifdef DEBUG_B3D - extern "C"{ void _stdcall AllocConsole(); } -#endif // ------------------------------------------------------------------------------------------------ void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){ - -#ifdef DEBUG_B3D - AllocConsole(); - freopen( "conin$","r",stdin ); - freopen( "conout$","w",stdout ); - freopen( "conout$","w",stderr ); - cout<<"Hello world from the B3DImporter!"< file( pIOHandler->Open( pFile)); // Check whether we can read from the file - if( file.get() == NULL) + if( file.get() == nullptr) { throw DeadlyImportError( "Failed to open B3D file " + pFile + "."); + } // check whether the .b3d file is large enough to contain // at least one chunk. size_t fileSize = file->FileSize(); - if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small."); + if( fileSize<8 ) { + throw DeadlyImportError( "B3D File is too small."); + } _pos=0; _buf.resize( fileSize ); @@ -158,14 +148,17 @@ AI_WONT_RETURN void B3DImporter::Oops(){ // ------------------------------------------------------------------------------------------------ AI_WONT_RETURN void B3DImporter::Fail( string str ){ #ifdef DEBUG_B3D - cout<<"Error in B3D file data: "< &v ){ return p; } - // ------------------------------------------------------------------------------------------------ template T **unique_to_array( vector > &v ){ @@ -283,7 +277,6 @@ T **unique_to_array( vector > &v ){ return p; } - // ------------------------------------------------------------------------------------------------ void B3DImporter::ReadTEXS(){ while( ChunkSize() ){ @@ -376,9 +369,13 @@ void B3DImporter::ReadVRTS(){ v.vertex=ReadVec3(); - if( _vflags & 1 ) v.normal=ReadVec3(); + if( _vflags & 1 ) { + v.normal=ReadVec3(); + } - if( _vflags & 2 ) ReadQuat(); //skip v 4bytes... + if( _vflags & 2 ) { + ReadQuat(); //skip v 4bytes... + } for( int i=0;i<_tcsets;++i ){ float t[4]={0,0,0,0}; @@ -386,53 +383,55 @@ void B3DImporter::ReadVRTS(){ t[j]=ReadFloat(); } t[1]=1-t[1]; - if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] ); + if( !i ) { + v.texcoords=aiVector3D( t[0],t[1],t[2] ); + } } } } // ------------------------------------------------------------------------------------------------ -void B3DImporter::ReadTRIS( int v0 ){ - int matid=ReadInt(); - if( matid==-1 ){ - matid=0; - }else if( matid<0 || matid>=(int)_materials.size() ){ +void B3DImporter::ReadTRIS(int v0) { + int matid = ReadInt(); + if (matid == -1) { + matid = 0; + } else if (matid < 0 || matid >= (int)_materials.size()) { #ifdef DEBUG_B3D - cout<<"material id="< mesh(new aiMesh); + std::unique_ptr mesh(new aiMesh); - mesh->mMaterialIndex=matid; - mesh->mNumFaces=0; - mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE; + mesh->mMaterialIndex = matid; + mesh->mNumFaces = 0; + mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - int n_tris=ChunkSize()/12; - aiFace *face=mesh->mFaces=new aiFace[n_tris]; + int n_tris = ChunkSize() / 12; + aiFace *face = mesh->mFaces = new aiFace[n_tris]; - for( int i=0;i=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){ + for (int i = 0; i < n_tris; ++i) { + int i0 = ReadInt() + v0; + int i1 = ReadInt() + v0; + int i2 = ReadInt() + v0; + if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) { #ifdef DEBUG_B3D - cout<<"Bad triangle index: i0="<mNumIndices=3; - face->mIndices=new unsigned[3]; - face->mIndices[0]=i0; - face->mIndices[1]=i1; - face->mIndices[2]=i2; - ++mesh->mNumFaces; - ++face; - } + Fail("Bad triangle index"); + continue; + } + face->mNumIndices = 3; + face->mIndices = new unsigned[3]; + face->mIndices[0] = i0; + face->mIndices[1] = i1; + face->mIndices[2] = i2; + ++mesh->mNumFaces; + ++face; + } - _meshes.emplace_back( std::move(mesh) ); + _meshes.emplace_back(std::move(mesh)); } // ------------------------------------------------------------------------------------------------ @@ -453,29 +452,23 @@ void B3DImporter::ReadMESH(){ } // ------------------------------------------------------------------------------------------------ -void B3DImporter::ReadBONE( int id ){ - while( ChunkSize() ){ - int vertex=ReadInt(); - float weight=ReadFloat(); - if( vertex<0 || vertex>=(int)_vertices.size() ){ - Fail( "Bad vertex index" ); - } +void B3DImporter::ReadBONE(int id) { + while (ChunkSize()) { + int vertex = ReadInt(); + float weight = ReadFloat(); + if (vertex < 0 || vertex >= (int)_vertices.size()) { + Fail("Bad vertex index"); + } - Vertex &v=_vertices[vertex]; - int i; - for( i=0;i<4;++i ){ - if( !v.weights[i] ){ - v.bones[i]=id; - v.weights[i]=weight; - break; - } - } -#ifdef DEBUG_B3D - if( i==4 ){ - cout<<"Too many bone weights"<mNumVertices=n_tris * 3; aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0; - if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ]; - if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; + if( _vflags & 1 ) { + mn=mesh->mNormals=new aiVector3D[ n_verts ]; + } + if( _tcsets ) { + mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; + } aiFace *face=mesh->mFaces; diff --git a/code/Common/Exporter.cpp b/code/Common/Exporter.cpp index b9bd0409b..25a78114f 100644 --- a/code/Common/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -445,7 +445,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c 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); + pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices); exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); pimpl->mProgressHandler->UpdateFileWrite(4, 4); diff --git a/code/Common/Importer.cpp b/code/Common/Importer.cpp index 91b50859a..9564f6ab7 100644 --- a/code/Common/Importer.cpp +++ b/code/Common/Importer.cpp @@ -5,8 +5,6 @@ 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, @@ -78,6 +76,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include + #include #include #include @@ -119,7 +119,7 @@ void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothro return AllocateFromAssimpHeap::operator new( num_bytes ); } catch( ... ) { - return NULL; + return nullptr; } } @@ -134,9 +134,8 @@ void* AllocateFromAssimpHeap::operator new[] ( size_t 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; + } catch( ... ) { + return nullptr; } } @@ -148,7 +147,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) { // Importer constructor. Importer::Importer() : pimpl( new ImporterPimpl ) { - pimpl->mScene = NULL; + pimpl->mScene = nullptr; pimpl->mErrorString = ""; // Allocate a default IO handler @@ -174,14 +173,14 @@ Importer::Importer() // ------------------------------------------------------------------------------------------------ // Destructor of Importer -Importer::~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++) + for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) { delete pimpl->mPostProcessingSteps[a]; + } // Delete the assigned IO and progress handler delete pimpl->mIOHandler; @@ -199,9 +198,9 @@ Importer::~Importer() // ------------------------------------------------------------------------------------------------ // Register a custom post-processing step -aiReturn Importer::RegisterPPStep(BaseProcess* pImp) -{ - ai_assert(NULL != pImp); +aiReturn Importer::RegisterPPStep(BaseProcess* pImp) { + ai_assert( nullptr != pImp ); + ASSIMP_BEGIN_EXCEPTION_REGION(); pimpl->mPostProcessingSteps.push_back(pImp); @@ -213,9 +212,9 @@ aiReturn Importer::RegisterPPStep(BaseProcess* pImp) // ------------------------------------------------------------------------------------------------ // Register a custom loader plugin -aiReturn Importer::RegisterLoader(BaseImporter* pImp) -{ - ai_assert(NULL != pImp); +aiReturn Importer::RegisterLoader(BaseImporter* pImp) { + ai_assert(nullptr != pImp); + ASSIMP_BEGIN_EXCEPTION_REGION(); // -------------------------------------------------------------------- @@ -242,13 +241,13 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp) 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) -{ +aiReturn Importer::UnregisterLoader(BaseImporter* pImp) { if(!pImp) { // unregistering a NULL importer is no problem for us ... really! return AI_SUCCESS; @@ -265,13 +264,13 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp) } 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) -{ +aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) { if(!pImp) { // unregistering a NULL ppstep is no problem for us ... really! return AI_SUCCESS; @@ -288,24 +287,22 @@ aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) } 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) -{ +void Importer::SetIOHandler( IOSystem* pIOHandler) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); // If the new handler is zero, allocate a default IO implementation. - if (!pIOHandler) - { + 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) - { + } else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler delete pimpl->mIOHandler; pimpl->mIOHandler = pIOHandler; pimpl->mIsDefaultHandler = false; @@ -316,29 +313,32 @@ void Importer::SetIOHandler( IOSystem* pIOHandler) // ------------------------------------------------------------------------------------------------ // Get the currently set IO handler IOSystem* Importer::GetIOHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mIOHandler; } // ------------------------------------------------------------------------------------------------ // Check whether a custom IO handler is currently set bool Importer::IsDefaultIOHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mIsDefaultHandler; } // ------------------------------------------------------------------------------------------------ // Supplies a custom progress handler to get regular callbacks during importing void Importer::SetProgressHandler ( ProgressHandler* pHandler ) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); + // If the new handler is zero, allocate a default implementation. - if (!pHandler) - { + 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) - { + } else if (pimpl->mProgressHandler != pHandler) { // Otherwise register the custom handler delete pimpl->mProgressHandler; pimpl->mProgressHandler = pHandler; pimpl->mIsDefaultProgressHandler = false; @@ -349,19 +349,22 @@ void Importer::SetProgressHandler ( ProgressHandler* pHandler ) { // ------------------------------------------------------------------------------------------------ // Get the currently set progress handler ProgressHandler* Importer::GetProgressHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mProgressHandler; } // ------------------------------------------------------------------------------------------------ // Check whether a custom progress handler is currently set bool Importer::IsDefaultProgressHandler() const { + ai_assert(nullptr != pimpl); + return pimpl->mIsDefaultProgressHandler; } // ------------------------------------------------------------------------------------------------ // Validate post process step flags -bool _ValidateFlags(unsigned int pFlags) -{ +bool _ValidateFlags(unsigned int pFlags) { if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) { ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible"); return false; @@ -375,12 +378,13 @@ bool _ValidateFlags(unsigned int pFlags) // ------------------------------------------------------------------------------------------------ // Free the current scene -void Importer::FreeScene( ) -{ +void Importer::FreeScene( ) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); delete pimpl->mScene; - pimpl->mScene = NULL; + pimpl->mScene = nullptr; pimpl->mErrorString = ""; ASSIMP_END_EXCEPTION_REGION(void); @@ -388,44 +392,48 @@ void Importer::FreeScene( ) // ------------------------------------------------------------------------------------------------ // Get the current error string, if any -const char* Importer::GetErrorString() const -{ - /* Must remain valid as long as ReadFile() or FreeFile() are not called */ +const char* Importer::GetErrorString() const { + ai_assert(nullptr != pimpl); + + // 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) -{ +void Importer::SetExtraVerbose(bool bDo) { + ai_assert(nullptr != pimpl); + pimpl->bExtraVerbose = bDo; } // ------------------------------------------------------------------------------------------------ // Get the current scene -const aiScene* Importer::GetScene() const -{ +const aiScene* Importer::GetScene() const { + ai_assert(nullptr != pimpl); + return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ // Orphan the current scene and return it. -aiScene* Importer::GetOrphanedScene() -{ +aiScene* Importer::GetOrphanedScene() { + ai_assert(nullptr != pimpl); + aiScene* s = pimpl->mScene; ASSIMP_BEGIN_EXCEPTION_REGION(); - pimpl->mScene = NULL; + pimpl->mScene = nullptr; - pimpl->mErrorString = ""; /* reset error string */ + pimpl->mErrorString = ""; // reset error string ASSIMP_END_EXCEPTION_REGION(aiScene*); + return s; } // ------------------------------------------------------------------------------------------------ // Validate post-processing flags -bool Importer::ValidateFlags(unsigned int pFlags) const -{ +bool Importer::ValidateFlags(unsigned int pFlags) const { ASSIMP_BEGIN_EXCEPTION_REGION(); // run basic checks for mutually exclusive flags if(!_ValidateFlags(pFlags)) { @@ -467,8 +475,9 @@ bool Importer::ValidateFlags(unsigned int pFlags) const const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, size_t pLength, unsigned int pFlags, - const char* pHint /*= ""*/) -{ + const char* pHint /*= ""*/) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); if (!pHint) { pHint = ""; @@ -476,12 +485,12 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) { pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()"; - return NULL; + return nullptr; } // prevent deletion of the previous IOHandler IOSystem* io = pimpl->mIOHandler; - pimpl->mIOHandler = NULL; + pimpl->mIOHandler = nullptr; SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io)); @@ -493,13 +502,13 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, ReadFile(fbuff,pFlags); SetIOHandler(io); - ASSIMP_END_EXCEPTION_REGION(const aiScene*); + ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString); return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ -void WriteLogOpening(const std::string& file) -{ +void WriteLogOpening(const std::string& file) { + ASSIMP_LOG_INFO_F("Load ", file); // print a full version dump. This is nice because we don't @@ -550,8 +559,9 @@ void WriteLogOpening(const std::string& file) // ------------------------------------------------------------------------------------------------ // Reads the given file and returns its contents if successful. -const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) -{ +const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); const std::string pFile(_pFile); @@ -580,7 +590,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) pimpl->mErrorString = "Unable to open file \"" + pFile + "\"."; ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; + return nullptr; } std::unique_ptr profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL); @@ -589,7 +599,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } // Find an worker class which can handle the file - BaseImporter* imp = NULL; + BaseImporter* imp = nullptr; SetPropertyInteger("importerIndex", -1); for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { @@ -617,7 +627,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) if( !imp) { pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; ASSIMP_LOG_ERROR(pimpl->mErrorString); - return NULL; + return nullptr; } } @@ -633,7 +643,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // Dispatch the reading to the worker class for this format const aiImporterDesc *desc( imp->GetInfo() ); std::string ext( "unknown" ); - if ( NULL != desc ) { + if ( nullptr != desc ) { ext = desc->mName; } ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." ); @@ -654,15 +664,20 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // If successful, apply all active post processing steps to the imported data if( pimpl->mScene) { + if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) { + if (!pimpl->mScene->mMetaData) { + pimpl->mScene->mMetaData = new aiMetadata; + } + pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext)); + } #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) - { + if (pFlags & aiProcess_ValidateDataStructure) { ValidateDSProcess ds; ds.ExecuteOnScene (this); if (!pimpl->mScene) { - return NULL; + return nullptr; } } #endif // no validation @@ -695,8 +710,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) } } #ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS - catch (std::exception &e) - { + 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(); @@ -705,24 +719,26 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) #endif ASSIMP_LOG_ERROR(pimpl->mErrorString); - delete pimpl->mScene; pimpl->mScene = NULL; + delete pimpl->mScene; pimpl->mScene = nullptr; } #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS // either successful or failure - the pointer expresses it anyways - ASSIMP_END_EXCEPTION_REGION(const aiScene*); + ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString); + return pimpl->mScene; } // ------------------------------------------------------------------------------------------------ // Apply post-processing to the currently bound scene -const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) -{ +const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); // Return immediately if no scene is active if (!pimpl->mScene) { - return NULL; + return nullptr; } // If no flags are given, return the current scene with no further action @@ -737,12 +753,11 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) #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) - { + if (pFlags & aiProcess_ValidateDataStructure) { ValidateDSProcess ds; ds.ExecuteOnScene (this); if (!pimpl->mScene) { - return NULL; + return nullptr; } } #endif // no validation @@ -762,11 +777,9 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) std::unique_ptr 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(a), static_cast(pimpl->mPostProcessingSteps.size()) ); if( process->IsActive( pFlags)) { - if (profiler) { profiler->BeginRegion("postprocess"); } @@ -803,24 +816,28 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) static_cast(pimpl->mPostProcessingSteps.size()) ); // update private scene flags - if( pimpl->mScene ) + 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 ) { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); // Return immediately if no scene is active - if ( NULL == pimpl->mScene ) { - return NULL; + if ( nullptr == pimpl->mScene ) { + return nullptr; } // If no flags are given, return the current scene with no further action @@ -839,7 +856,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess ValidateDSProcess ds; ds.ExecuteOnScene( this ); if ( !pimpl->mScene ) { - return NULL; + return nullptr; } } #endif // no validation @@ -890,46 +907,50 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess // ------------------------------------------------------------------------------------------------ // Helper function to check whether an extension is supported by ASSIMP -bool Importer::IsExtensionSupported(const char* szExtension) const -{ +bool Importer::IsExtensionSupported(const char* szExtension) const { return nullptr != GetImporter(szExtension); } // ------------------------------------------------------------------------------------------------ -size_t Importer::GetImporterCount() const -{ +size_t Importer::GetImporterCount() const { + ai_assert(nullptr != pimpl); + return pimpl->mImporter.size(); } // ------------------------------------------------------------------------------------------------ -const aiImporterDesc* Importer::GetImporterInfo(size_t index) const -{ +const aiImporterDesc* Importer::GetImporterInfo(size_t index) const { + ai_assert(nullptr != pimpl); + if (index >= pimpl->mImporter.size()) { - return NULL; + return nullptr; } return pimpl->mImporter[index]->GetInfo(); } // ------------------------------------------------------------------------------------------------ -BaseImporter* Importer::GetImporter (size_t index) const -{ +BaseImporter* Importer::GetImporter (size_t index) const { + ai_assert(nullptr != pimpl); + if (index >= pimpl->mImporter.size()) { - return NULL; + return nullptr; } return pimpl->mImporter[index]; } // ------------------------------------------------------------------------------------------------ // Find a loader plugin for a given file extension -BaseImporter* Importer::GetImporter (const char* szExtension) const -{ +BaseImporter* Importer::GetImporter (const char* szExtension) const { + ai_assert(nullptr != pimpl); + return GetImporter(GetImporterIndex(szExtension)); } // ------------------------------------------------------------------------------------------------ // Find a loader plugin for a given file extension size_t Importer::GetImporterIndex (const char* szExtension) const { + ai_assert(nullptr != pimpl); ai_assert(nullptr != szExtension); ASSIMP_BEGIN_EXCEPTION_REGION(); @@ -960,8 +981,9 @@ size_t Importer::GetImporterIndex (const char* szExtension) const { // ------------------------------------------------------------------------------------------------ // Helper function to build a list of all file extensions supported by ASSIMP -void Importer::GetExtensionList(aiString& szOut) const -{ +void Importer::GetExtensionList(aiString& szOut) const { + ai_assert(nullptr != pimpl); + ASSIMP_BEGIN_EXCEPTION_REGION(); std::set str; for (std::vector::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) { @@ -985,8 +1007,9 @@ void Importer::GetExtensionList(aiString& szOut) const // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyInteger(const char* szName, int iValue) -{ +bool Importer::SetPropertyInteger(const char* szName, int iValue) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mIntProperties, szName,iValue); @@ -996,8 +1019,9 @@ bool Importer::SetPropertyInteger(const char* szName, int iValue) // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) -{ +bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mFloatProperties, szName,iValue); @@ -1007,8 +1031,9 @@ bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyString(const char* szName, const std::string& value) -{ +bool Importer::SetPropertyString(const char* szName, const std::string& value) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mStringProperties, szName,value); @@ -1018,8 +1043,9 @@ bool Importer::SetPropertyString(const char* szName, const std::string& value) // ------------------------------------------------------------------------------------------------ // Set a configuration property -bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) -{ +bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) { + ai_assert(nullptr != pimpl); + bool existing; ASSIMP_BEGIN_EXCEPTION_REGION(); existing = SetGenericProperty(pimpl->mMatrixProperties, szName,value); @@ -1029,40 +1055,43 @@ bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) // ------------------------------------------------------------------------------------------------ // Get a configuration property -int Importer::GetPropertyInteger(const char* szName, - int iErrorReturn /*= 0xffffffff*/) const -{ +int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mIntProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get a configuration property -ai_real Importer::GetPropertyFloat(const char* szName, - ai_real iErrorReturn /*= 10e10*/) const -{ +ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mFloatProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get a configuration property -const std::string Importer::GetPropertyString(const char* szName, - const std::string& iErrorReturn /*= ""*/) const -{ +const std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mStringProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get a configuration property -const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, - const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const -{ +const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const { + ai_assert(nullptr != pimpl); + return GetGenericProperty(pimpl->mMatrixProperties,szName,iErrorReturn); } // ------------------------------------------------------------------------------------------------ // Get the memory requirements of a single node -inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) -{ +inline +void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) { + if ( nullptr == pcNode ) { + return; + } iScene += sizeof(aiNode); iScene += sizeof(unsigned int) * pcNode->mNumMeshes; iScene += sizeof(void*) * pcNode->mNumChildren; @@ -1074,8 +1103,9 @@ inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) // ------------------------------------------------------------------------------------------------ // Get the memory requirements of the scene -void Importer::GetMemoryRequirements(aiMemoryInfo& in) const -{ +void Importer::GetMemoryRequirements(aiMemoryInfo& in) const { + ai_assert(nullptr != pimpl); + in = aiMemoryInfo(); aiScene* mScene = pimpl->mScene; @@ -1087,8 +1117,7 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const in.total = sizeof(aiScene); // add all meshes - for (unsigned int i = 0; i < mScene->mNumMeshes;++i) - { + 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; @@ -1105,14 +1134,16 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const 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; } - 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; } - else break; } if (mScene->mMeshes[i]->HasBones()) { in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones; @@ -1131,8 +1162,9 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const in.textures += sizeof(aiTexture); if (pc->mHeight) { in.textures += 4 * pc->mHeight * pc->mWidth; + } else { + in.textures += pc->mWidth; } - else in.textures += pc->mWidth; } in.total += in.textures; diff --git a/code/FBX/FBXConverter.cpp b/code/FBX/FBXConverter.cpp index d8a22d9f7..26a3c4b99 100644 --- a/code/FBX/FBXConverter.cpp +++ b/code/FBX/FBXConverter.cpp @@ -60,6 +60,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include #include #include @@ -1597,12 +1599,11 @@ namespace Assimp { 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(); + ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name); + bone = bone_map[deformer_name]; + } else { + ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name); + bone = new aiBone(); bone->mName = bone_name; // store local transform link for post processing @@ -1648,7 +1649,7 @@ namespace Assimp { bone_map.insert(std::pair(deformer_name, bone)); } - std::cout << "bone research: Indicies size: " << out_indices.size() << std::endl; + ASSIMP_LOG_DEBUG_F("bone research: Indicies size: ", out_indices.size()); // lookup must be populated in case something goes wrong // this also allocates bones to mesh instance outside @@ -3604,7 +3605,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa return; } - out->mMetaData = aiMetadata::Alloc(15); + const bool hasGenerator = !doc.Creator().empty(); + + out->mMetaData = aiMetadata::Alloc(16 + (hasGenerator ? 1 : 0)); out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis()); out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign()); out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis()); @@ -3620,6 +3623,11 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa out->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart()); out->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop()); out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate()); + out->mMetaData->Set(15, AI_METADATA_SOURCE_FORMAT_VERSION, aiString(to_string(doc.FBXVersion()))); + if (hasGenerator) + { + out->mMetaData->Set(16, AI_METADATA_SOURCE_GENERATOR, aiString(doc.Creator())); + } } void FBXConverter::TransferDataToScene() diff --git a/code/FBX/FBXConverter.h b/code/FBX/FBXConverter.h index 46693bdca..d47416223 100644 --- a/code/FBX/FBXConverter.h +++ b/code/FBX/FBXConverter.h @@ -421,6 +421,8 @@ private: double& minTime, Model::RotOrder order); + // ------------------------------------------------------------------------------------------------ + // Copy global geometric data and some information about the source asset into scene metadata. void ConvertGlobalSettings(); // ------------------------------------------------------------------------------------------------ diff --git a/code/FBX/FBXExporter.cpp b/code/FBX/FBXExporter.cpp index 9767f9a0a..413d1d6c8 100644 --- a/code/FBX/FBXExporter.cpp +++ b/code/FBX/FBXExporter.cpp @@ -1860,6 +1860,7 @@ void FBXExporter::WriteObjects () sdnode.AddChild("Version", int32_t(100)); sdnode.AddChild("UserData", "", ""); + std::set setWeightedVertex; // add indices and weights, if any if (b) { std::vector subdef_indices; @@ -1867,7 +1868,8 @@ void FBXExporter::WriteObjects () 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) { + bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end()); + if (vi == last_index || bIsWeightedAlready) { // only for vertices we exported to fbx // TODO, FIXME: this assumes identically-located vertices // will always deform in the same way. @@ -1877,6 +1879,7 @@ void FBXExporter::WriteObjects () // identical vertex. continue; } + setWeightedVertex.insert(vi); subdef_indices.push_back(vi); subdef_weights.push_back(b->mWeights[wi].mWeight); last_index = vi; diff --git a/code/LWO/LWOLoader.cpp b/code/LWO/LWOLoader.cpp index 1e5b92c32..242538056 100644 --- a/code/LWO/LWOLoader.cpp +++ b/code/LWO/LWOLoader.cpp @@ -586,7 +586,6 @@ void LWOImporter::GenerateNodeGraph(std::map& apcNodes) root->mName.Set(""); //Set parent of all children, inserting pivots - //std::cout << "Set parent of all children" << std::endl; std::map mapPivot; for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) { @@ -618,7 +617,6 @@ void LWOImporter::GenerateNodeGraph(std::map& apcNodes) } //Merge pivot map into node map - //std::cout << "Merge pivot map into node map" << std::endl; for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) { apcNodes[itMapPivot->first] = itMapPivot->second; } diff --git a/code/glTF/glTFAsset.h b/code/glTF/glTFAsset.h index ddc7f086e..e7dd9c438 100644 --- a/code/glTF/glTFAsset.h +++ b/code/glTF/glTFAsset.h @@ -362,8 +362,8 @@ namespace glTF ComponentType componentType; //!< The datatype of components in the attribute. (required) unsigned int count; //!< The number of attributes referenced by this accessor. (required) AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required) - std::vector max; //!< Maximum value of each component in this attribute. - std::vector min; //!< Minimum value of each component in this attribute. + std::vector max; //!< Maximum value of each component in this attribute. + std::vector min; //!< Minimum value of each component in this attribute. unsigned int GetNumComponents(); unsigned int GetBytesPerComponent(); diff --git a/code/glTF/glTFAssetWriter.inl b/code/glTF/glTFAssetWriter.inl index 1bbb8fd8c..a3c99a9a8 100644 --- a/code/glTF/glTFAssetWriter.inl +++ b/code/glTF/glTFAssetWriter.inl @@ -54,9 +54,9 @@ namespace glTF { namespace { - template + template inline - Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { + Value& MakeValue(Value& val, T(&r)[N], MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(N, al); for (decltype(N) i = 0; i < N; ++i) { @@ -65,8 +65,9 @@ namespace glTF { return val; } + template inline - Value& MakeValue(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { + Value& MakeValue(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(static_cast(r.size()), al); for (unsigned int i = 0; i < r.size(); ++i) { @@ -75,6 +76,16 @@ namespace glTF { return val; } + template + inline Value& MakeValueCast(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { + val.SetArray(); + val.Reserve(static_cast(r.size()), al); + for (unsigned int i = 0; i < r.size(); ++i) { + val.PushBack(static_cast(r[i]), al); + } + return val; + } + template inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref >& v, MemoryPoolAllocator<>& al) { if (v.empty()) return; @@ -100,8 +111,13 @@ namespace glTF { obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl); Value vTmpMax, vTmpMin; - obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl); - obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl); + if (a.componentType == ComponentType_FLOAT) { + obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl); + obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl); + } else { + obj.AddMember("max", MakeValueCast(vTmpMax, a.max, w.mAl), w.mAl); + obj.AddMember("min", MakeValueCast(vTmpMin, a.min, w.mAl), w.mAl); + } } inline void Write(Value& obj, Animation& a, AssetWriter& w) diff --git a/code/glTF/glTFExporter.cpp b/code/glTF/glTFExporter.cpp index 034f91f3b..3faa1a84b 100644 --- a/code/glTF/glTFExporter.cpp +++ b/code/glTF/glTFExporter.cpp @@ -58,6 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Header files, standard library. #include +#include #include #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC @@ -173,6 +174,62 @@ static void IdentityMatrix4(glTF::mat4& o) o[12] = 0; o[13] = 0; o[14] = 0; o[15] = 1; } +template +void SetAccessorRange(Ref acc, void* data, unsigned int count, + unsigned int numCompsIn, unsigned int numCompsOut) +{ + ai_assert(numCompsOut <= numCompsIn); + + // Allocate and initialize with large values. + for (unsigned int i = 0 ; i < numCompsOut ; i++) { + acc->min.push_back( std::numeric_limits::max()); + acc->max.push_back(-std::numeric_limits::max()); + } + + size_t totalComps = count * numCompsIn; + T* buffer_ptr = static_cast(data); + T* buffer_end = buffer_ptr + totalComps; + + // Search and set extreme values. + for (; buffer_ptr < buffer_end ; buffer_ptr += numCompsIn) { + for (unsigned int j = 0 ; j < numCompsOut ; j++) { + double valueTmp = buffer_ptr[j]; + + if (valueTmp < acc->min[j]) { + acc->min[j] = valueTmp; + } + if (valueTmp > acc->max[j]) { + acc->max[j] = valueTmp; + } + } + } +} + +inline void SetAccessorRange(ComponentType compType, Ref acc, void* data, + unsigned int count, unsigned int numCompsIn, unsigned int numCompsOut) +{ + switch (compType) { + case ComponentType_SHORT: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_UNSIGNED_SHORT: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_UNSIGNED_INT: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_FLOAT: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_BYTE: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_UNSIGNED_BYTE: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + } +} + inline Ref ExportData(Asset& a, std::string& meshName, Ref& buffer, unsigned int count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false) { @@ -206,33 +263,7 @@ inline Ref ExportData(Asset& a, std::string& meshName, Ref& bu acc->type = typeOut; // calculate min and max values - { - // Allocate and initialize with large values. - float float_MAX = 10000000000000.0f; - for (unsigned int i = 0 ; i < numCompsOut ; i++) { - acc->min.push_back( float_MAX); - acc->max.push_back(-float_MAX); - } - - // Search and set extreme values. - float valueTmp; - for (unsigned int i = 0 ; i < count ; i++) { - for (unsigned int j = 0 ; j < numCompsOut ; j++) { - if (numCompsOut == 1) { - valueTmp = static_cast(data)[i]; - } else { - valueTmp = static_cast(data)[i][j]; - } - - if (valueTmp < acc->min[j]) { - acc->min[j] = valueTmp; - } - if (valueTmp > acc->max[j]) { - acc->max[j] = valueTmp; - } - } - } - } + SetAccessorRange(compType, acc, data, count, numCompsIn, numCompsOut); // copy the data acc->WriteData(count, data, numCompsIn*bytesPerComp); diff --git a/code/glTF/glTFImporter.cpp b/code/glTF/glTFImporter.cpp index 9ec13ea69..59e7d9b92 100644 --- a/code/glTF/glTFImporter.cpp +++ b/code/glTF/glTFImporter.cpp @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include @@ -697,6 +698,25 @@ void glTFImporter::ImportEmbeddedTextures(glTF::Asset& r) } } +void glTFImporter::ImportCommonMetadata(glTF::Asset& a) +{ + ai_assert(mScene->mMetaData == nullptr); + const bool hasVersion = !a.asset.version.empty(); + const bool hasGenerator = !a.asset.generator.empty(); + if (hasVersion || hasGenerator) + { + mScene->mMetaData = new aiMetadata; + if (hasVersion) + { + mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT_VERSION, aiString(a.asset.version)); + } + if (hasGenerator) + { + mScene->mMetaData->Add(AI_METADATA_SOURCE_GENERATOR, aiString(a.asset.generator)); + } + } +} + void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { // clean all member arrays @@ -723,7 +743,7 @@ void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOS ImportLights(asset); ImportNodes(asset); - + ImportCommonMetadata(asset); if (pScene->mNumMeshes == 0) { pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; diff --git a/code/glTF/glTFImporter.h b/code/glTF/glTFImporter.h index ce8a000dc..84d74009b 100644 --- a/code/glTF/glTFImporter.h +++ b/code/glTF/glTFImporter.h @@ -83,7 +83,7 @@ private: void ImportCameras(glTF::Asset& a); void ImportLights(glTF::Asset& a); void ImportNodes(glTF::Asset& a); - + void ImportCommonMetadata(glTF::Asset& a); }; } // Namespace assimp diff --git a/code/glTF2/glTF2Asset.h b/code/glTF2/glTF2Asset.h index d13ebfd66..1fcb348bb 100644 --- a/code/glTF2/glTF2Asset.h +++ b/code/glTF2/glTF2Asset.h @@ -387,8 +387,8 @@ namespace glTF2 ComponentType componentType; //!< The datatype of components in the attribute. (required) size_t count; //!< The number of attributes referenced by this accessor. (required) AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required) - std::vector max; //!< Maximum value of each component in this attribute. - std::vector min; //!< Minimum value of each component in this attribute. + std::vector max; //!< Maximum value of each component in this attribute. + std::vector min; //!< Minimum value of each component in this attribute. unsigned int GetNumComponents(); unsigned int GetBytesPerComponent(); diff --git a/code/glTF2/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl index 99f8c876f..55a3e5833 100644 --- a/code/glTF2/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -270,13 +270,14 @@ Ref LazyDict::Retrieve(unsigned int i) throw DeadlyImportError("GLTF: Object at index \"" + to_string(i) + "\" is not a JSON object"); } - T* inst = new T(); + // Unique ptr prevents memory leak in case of Read throws an exception + auto inst = std::unique_ptr(new T()); inst->id = std::string(mDictId) + "_" + to_string(i); inst->oIndex = i; ReadMember(obj, "name", inst->name); inst->Read(obj, mAsset); - return Add(inst); + return Add(inst.release()); } template diff --git a/code/glTF2/glTF2AssetWriter.inl b/code/glTF2/glTF2AssetWriter.inl index 44a1d3e73..8ba4aa10b 100644 --- a/code/glTF2/glTF2AssetWriter.inl +++ b/code/glTF2/glTF2AssetWriter.inl @@ -54,8 +54,8 @@ namespace glTF2 { namespace { - template - inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { + template + inline Value& MakeValue(Value& val, T(&r)[N], MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(N, al); for (decltype(N) i = 0; i < N; ++i) { @@ -64,7 +64,8 @@ namespace glTF2 { return val; } - inline Value& MakeValue(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { + template + inline Value& MakeValue(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(static_cast(r.size()), al); for (unsigned int i = 0; i < r.size(); ++i) { @@ -73,8 +74,19 @@ namespace glTF2 { return val; } - inline Value& MakeValue(Value& val, float r, MemoryPoolAllocator<>& /*al*/) { - val.SetDouble(r); + template + inline Value& MakeValueCast(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { + val.SetArray(); + val.Reserve(static_cast(r.size()), al); + for (unsigned int i = 0; i < r.size(); ++i) { + val.PushBack(static_cast(r[i]), al); + } + return val; + } + + template + inline Value& MakeValue(Value& val, T r, MemoryPoolAllocator<>& /*al*/) { + val.Set(r); return val; } @@ -104,8 +116,13 @@ namespace glTF2 { obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl); Value vTmpMax, vTmpMin; - obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl); - obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl); + if (a.componentType == ComponentType_FLOAT) { + obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl); + obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl); + } else { + obj.AddMember("max", MakeValueCast(vTmpMax, a.max, w.mAl), w.mAl); + obj.AddMember("min", MakeValueCast(vTmpMin, a.min, w.mAl), w.mAl); + } } inline void Write(Value& obj, Animation& a, AssetWriter& w) diff --git a/code/glTF2/glTF2Exporter.cpp b/code/glTF2/glTF2Exporter.cpp index dc0b76443..f85803b52 100644 --- a/code/glTF2/glTF2Exporter.cpp +++ b/code/glTF2/glTF2Exporter.cpp @@ -58,6 +58,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Header files, standard library. #include +#include #include using namespace rapidjson; @@ -152,6 +153,62 @@ static void IdentityMatrix4(mat4& o) { o[12] = 0; o[13] = 0; o[14] = 0; o[15] = 1; } +template +void SetAccessorRange(Ref acc, void* data, size_t count, + unsigned int numCompsIn, unsigned int numCompsOut) +{ + ai_assert(numCompsOut <= numCompsIn); + + // Allocate and initialize with large values. + for (unsigned int i = 0 ; i < numCompsOut ; i++) { + acc->min.push_back( std::numeric_limits::max()); + acc->max.push_back(-std::numeric_limits::max()); + } + + size_t totalComps = count * numCompsIn; + T* buffer_ptr = static_cast(data); + T* buffer_end = buffer_ptr + totalComps; + + // Search and set extreme values. + for (; buffer_ptr < buffer_end ; buffer_ptr += numCompsIn) { + for (unsigned int j = 0 ; j < numCompsOut ; j++) { + double valueTmp = buffer_ptr[j]; + + if (valueTmp < acc->min[j]) { + acc->min[j] = valueTmp; + } + if (valueTmp > acc->max[j]) { + acc->max[j] = valueTmp; + } + } + } +} + +inline void SetAccessorRange(ComponentType compType, Ref acc, void* data, + size_t count, unsigned int numCompsIn, unsigned int numCompsOut) +{ + switch (compType) { + case ComponentType_SHORT: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_UNSIGNED_SHORT: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_UNSIGNED_INT: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_FLOAT: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_BYTE: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + case ComponentType_UNSIGNED_BYTE: + SetAccessorRange(acc, data, count, numCompsIn, numCompsOut); + return; + } +} + inline Ref ExportData(Asset& a, std::string& meshName, Ref& buffer, size_t count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false) { @@ -187,33 +244,7 @@ inline Ref ExportData(Asset& a, std::string& meshName, Ref& bu acc->type = typeOut; // calculate min and max values - { - // Allocate and initialize with large values. - float float_MAX = 10000000000000.0f; - for (unsigned int i = 0 ; i < numCompsOut ; i++) { - acc->min.push_back( float_MAX); - acc->max.push_back(-float_MAX); - } - - // Search and set extreme values. - float valueTmp; - for (unsigned int i = 0 ; i < count ; i++) { - for (unsigned int j = 0 ; j < numCompsOut ; j++) { - if (numCompsOut == 1) { - valueTmp = static_cast(data)[i]; - } else { - valueTmp = static_cast(data)[i][j]; - } - - if (valueTmp < acc->min[j]) { - acc->min[j] = valueTmp; - } - if (valueTmp > acc->max[j]) { - acc->max[j] = valueTmp; - } - } - } - } + SetAccessorRange(compType, acc, data, count, numCompsIn, numCompsOut); // copy the data acc->WriteData(count, data, numCompsIn*bytesPerComp); diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index dd80aeba9..b14d68c27 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include @@ -1301,6 +1302,24 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset &r) { } } +void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) { + ai_assert(mScene->mMetaData == nullptr); + const bool hasVersion = !a.asset.version.empty(); + const bool hasGenerator = !a.asset.generator.empty(); + if (hasVersion || hasGenerator) + { + mScene->mMetaData = new aiMetadata; + if (hasVersion) + { + mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT_VERSION, aiString(a.asset.version)); + } + if (hasGenerator) + { + mScene->mMetaData->Add(AI_METADATA_SOURCE_GENERATOR, aiString(a.asset.generator)); + } + } +} + void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { // clean all member arrays meshOffsets.clear(); @@ -1328,6 +1347,8 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO ImportAnimations(asset); + ImportCommonMetadata(asset); + if (pScene->mNumMeshes == 0) { pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; } diff --git a/code/glTF2/glTF2Importer.h b/code/glTF2/glTF2Importer.h index 091b61ee6..e62c38d21 100644 --- a/code/glTF2/glTF2Importer.h +++ b/code/glTF2/glTF2Importer.h @@ -84,6 +84,7 @@ private: void ImportLights(glTF2::Asset& a); void ImportNodes(glTF2::Asset& a); void ImportAnimations(glTF2::Asset& a); + void ImportCommonMetadata(glTF2::Asset& a); }; } // Namespace assimp diff --git a/include/assimp/Exceptional.h b/include/assimp/Exceptional.h index 6bb6ce1e3..f0d23d0f3 100644 --- a/include/assimp/Exceptional.h +++ b/include/assimp/Exceptional.h @@ -119,6 +119,16 @@ struct ExceptionSwallower { {\ try { +#define ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(type, ASSIMP_END_EXCEPTION_REGION_errorString)\ + } catch(const DeadlyImportError& e) {\ + ASSIMP_END_EXCEPTION_REGION_errorString = e.what();\ + return ExceptionSwallower()();\ + } catch(...) {\ + ASSIMP_END_EXCEPTION_REGION_errorString = "Unknown exception";\ + return ExceptionSwallower()();\ + }\ +} + #define ASSIMP_END_EXCEPTION_REGION(type)\ } catch(...) {\ return ExceptionSwallower()();\ diff --git a/include/assimp/LineSplitter.h b/include/assimp/LineSplitter.h index 6c1097bb6..2fa61cba7 100644 --- a/include/assimp/LineSplitter.h +++ b/include/assimp/LineSplitter.h @@ -72,7 +72,7 @@ for(LineSplitter splitter(stream);splitter;++splitter) { if (strtol(splitter[2]) > 5) { .. } } - std::cout << "Current line is: " << splitter.get_index() << std::endl; + ASSIMP_LOG_DEBUG_F("Current line is: ", splitter.get_index()); } @endcode */ diff --git a/include/assimp/commonMetaData.h b/include/assimp/commonMetaData.h new file mode 100644 index 000000000..1e176725e --- /dev/null +++ b/include/assimp/commonMetaData.h @@ -0,0 +1,63 @@ +/* +--------------------------------------------------------------------------- +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 commonMetaData.h + * @brief Defines a set of common scene metadata keys. + */ +#pragma once +#ifndef AI_COMMONMETADATA_H_INC +#define AI_COMMONMETADATA_H_INC + +/// Scene metadata holding the name of the importer which loaded the source asset. +/// This is always present if the scene was created from an imported asset. +#define AI_METADATA_SOURCE_FORMAT "SourceAsset_Format" + +/// Scene metadata holding the version of the source asset as a string, if available. +/// Not all formats add this metadata. +#define AI_METADATA_SOURCE_FORMAT_VERSION "SourceAsset_FormatVersion" + +/// Scene metadata holding the name of the software which generated the source asset, if available. +/// Not all formats add this metadata. +#define AI_METADATA_SOURCE_GENERATOR "SourceAsset_Generator" + +#endif diff --git a/include/assimp/metadata.h b/include/assimp/metadata.h index 849d90f48..f3a5321d3 100644 --- a/include/assimp/metadata.h +++ b/include/assimp/metadata.h @@ -286,8 +286,8 @@ struct aiMetadata { new_values[i] = mValues[i]; } - delete mKeys; - delete mValues; + delete[] mKeys; + delete[] mValues; mKeys = new_keys; mValues = new_values; @@ -377,6 +377,23 @@ struct aiMetadata { return true; } + /// Check whether there is a metadata entry for the given key. + /// \param [in] Key - the key value value to check for. + inline + bool HasKey(const char* key) { + if ( nullptr == key ) { + return false; + } + + // Search for the given key + for (unsigned int i = 0; i < mNumProperties; ++i) { + if ( 0 == strncmp(mKeys[i].C_Str(), key, mKeys[i].length ) ) { + return true; + } + } + return false; + } + #endif // __cplusplus }; diff --git a/test/models/glTF2/MissingBin/BoxTextured.gltf b/test/models/glTF2/MissingBin/BoxTextured.gltf new file mode 100644 index 000000000..88d65391e --- /dev/null +++ b/test/models/glTF2/MissingBin/BoxTextured.gltf @@ -0,0 +1,181 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "name": "Texture" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "CesiumLogoFlat.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 33648, + "wrapT": 33071 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "BoxTextured0.bin" + } + ] +} diff --git a/test/unit/utFBXImporterExporter.cpp b/test/unit/utFBXImporterExporter.cpp index 43dc40e88..fd350850f 100644 --- a/test/unit/utFBXImporterExporter.cpp +++ b/test/unit/utFBXImporterExporter.cpp @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include using namespace Assimp; @@ -283,3 +284,29 @@ TEST_F(utFBXImporterExporter, importOrphantEmbeddedTextureTest) { ASSERT_TRUE(scene->mTextures[0]->pcData); ASSERT_EQ(9026u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression used for a texture."; } + +TEST_F(utFBXImporterExporter, sceneMetadata) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/global_settings.fbx", + aiProcess_ValidateDataStructure); + ASSERT_NE(scene, nullptr); + ASSERT_NE(scene->mMetaData, nullptr); + { + ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)); + aiString format; + ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, format)); + ASSERT_EQ(strcmp(format.C_Str(), "Autodesk FBX Importer"), 0); + } + { + ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT_VERSION)); + aiString version; + ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, version)); + ASSERT_EQ(strcmp(version.C_Str(), "7400"), 0); + } + { + ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_GENERATOR)); + aiString generator; + ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, generator)); + ASSERT_EQ(strncmp(generator.C_Str(), "Blender", 7), 0); + } +} diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 0df692f0b..6443d740f 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -45,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include + #include using namespace Assimp; @@ -426,4 +428,39 @@ TEST_F( utglTF2ImportExport, crash_in_anim_mesh_destructor ) { ASSERT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube_out.glTF")); } +TEST_F(utglTF2ImportExport, error_string_preserved) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/MissingBin/BoxTextured.gltf", + aiProcess_ValidateDataStructure); + ASSERT_EQ(nullptr, scene); + std::string error = importer.GetErrorString(); + ASSERT_NE(error.find("BoxTextured0.bin"), std::string::npos) << "Error string should contain an error about missing .bin file"; +} + #endif // ASSIMP_BUILD_NO_EXPORT + +TEST_F(utglTF2ImportExport, sceneMetadata) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", + aiProcess_ValidateDataStructure); + ASSERT_NE(scene, nullptr); + ASSERT_NE(scene->mMetaData, nullptr); + { + ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)); + aiString format; + ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, format)); + ASSERT_EQ(strcmp(format.C_Str(), "glTF2 Importer"), 0); + } + { + ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT_VERSION)); + aiString version; + ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, version)); + ASSERT_EQ(strcmp(version.C_Str(), "2.0"), 0); + } + { + ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_GENERATOR)); + aiString generator; + ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, generator)); + ASSERT_EQ(strcmp(generator.C_Str(), "COLLADA2GLTF"), 0); + } +} diff --git a/test/unit/utglTFImportExport.cpp b/test/unit/utglTFImportExport.cpp index 90f0758bb..321d58354 100644 --- a/test/unit/utglTFImportExport.cpp +++ b/test/unit/utglTFImportExport.cpp @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include using namespace Assimp; @@ -85,3 +86,28 @@ TEST_F(utglTFImportExport, incorrect_vertex_arrays) { EXPECT_EQ(scene->mMeshes[7]->mNumVertices, 35u); EXPECT_EQ(scene->mMeshes[7]->mNumFaces, 17u); } + +TEST_F(utglTFImportExport, sceneMetadata) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF/TwoBoxes/TwoBoxes.gltf", aiProcess_ValidateDataStructure); + ASSERT_TRUE(scene); + ASSERT_TRUE(scene->mMetaData); + { + ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)); + aiString format; + ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, format)); + ASSERT_EQ(strcmp(format.C_Str(), "glTF Importer"), 0); + } + { + ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT_VERSION)); + aiString version; + ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, version)); + ASSERT_EQ(strcmp(version.C_Str(), "1.0"), 0); + } + { + ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_GENERATOR)); + aiString generator; + ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, generator)); + ASSERT_EQ(strncmp(generator.C_Str(), "collada2gltf", 12), 0); + } +}