2
0
Эх сурвалжийг харах

Merge branch 'master' into partial-cleanup-m3d

Kim Kulling 5 жил өмнө
parent
commit
747e12465b

+ 1 - 1
CMakeLists.txt

@@ -253,7 +253,7 @@ ELSEIF(MSVC)
   IF(MSVC12)
     ADD_COMPILE_OPTIONS(/wd4351)
   ENDIF()
-  SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /Zi /O0")
+  SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Zi /Od")
 ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
   IF(NOT HUNTER_ENABLED)
     SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")

+ 94 - 93
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<typename T>
-void DeleteAllBarePointers(std::vector<T>& x)
-{
-    for(auto p : x)
-    {
+void DeleteAllBarePointers(std::vector<T>& 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!"<<endl;
-#endif
-
     std::unique_ptr<IOStream> 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: "<<str<<endl;
+    ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
 #endif
     throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
 }
 
 // ------------------------------------------------------------------------------------------------
 int B3DImporter::ReadByte(){
-    if( _pos<_buf.size() ) return _buf[_pos++];
+    if( _pos<_buf.size() ) {
+        return _buf[_pos++];
+    }
+    
     Fail( "EOF" );
     return 0;
 }
@@ -224,7 +217,9 @@ string B3DImporter::ReadString(){
     string str;
     while( _pos<_buf.size() ){
         char c=(char)ReadByte();
-        if( !c ) return str;
+        if( !c ) {
+            return str;
+        }
         str+=c;
     }
     Fail( "EOF" );
@@ -238,7 +233,7 @@ string B3DImporter::ReadChunk(){
         tag+=char( ReadByte() );
     }
 #ifdef DEBUG_B3D
-//	cout<<"ReadChunk:"<<tag<<endl;
+    ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag);
 #endif
     unsigned sz=(unsigned)ReadInt();
     _stack.push_back( _pos+sz );
@@ -269,7 +264,6 @@ T *B3DImporter::to_array( const vector<T> &v ){
     return p;
 }
 
-
 // ------------------------------------------------------------------------------------------------
 template<class T>
 T **unique_to_array( vector<std::unique_ptr<T> > &v ){
@@ -283,7 +277,6 @@ T **unique_to_array( vector<std::unique_ptr<T> > &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="<<matid<<endl;
+		ASSIMP_LOG_ERROR_F("material id=", matid);
 #endif
-        Fail( "Bad material id" );
-    }
+		Fail("Bad material id");
+	}
 
-    std::unique_ptr<aiMesh> mesh(new aiMesh);
+	std::unique_ptr<aiMesh> 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<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() ){
+	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="<<i0<<", i1="<<i1<<", i2="<<i2<<endl;
+			ASSIMP_LOG_ERROR_F("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
 #endif
-            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) );
+			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));
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -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" );
-        }
-
-        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"<<endl;
-        }
-#endif
-    }
+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];
+		for (int i = 0; i < 4; ++i) {
+			if (!v.weights[i]) {
+				v.bones[i] = id;
+				v.weights[i] = weight;
+				break;
+			}
+		}
+	}
 }
 
 // ------------------------------------------------------------------------------------------------
@@ -633,11 +626,15 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
     }
     ExitChunk();
 
-    if( !_nodes.size() ) Fail( "No nodes" );
+    if( !_nodes.size() ) {
+        Fail( "No nodes" );
+    }
 
-    if( !_meshes.size() ) Fail( "No meshes" );
+    if( !_meshes.size() ) {
+        Fail( "No meshes" );
+    }
 
-    //Fix nodes/meshes/bones
+    // Fix nodes/meshes/bones
     for(size_t i=0;i<_nodes.size();++i ){
         aiNode *node=_nodes[i];
 
@@ -648,8 +645,12 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
             int n_verts=mesh->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;
 

+ 157 - 125
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 <assimp/TinyFormatter.h>
 #include <assimp/Exceptional.h>
 #include <assimp/Profiler.h>
+#include <assimp/commonMetaData.h>
+
 #include <set>
 #include <memory>
 #include <cctype>
@@ -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));
 
@@ -498,8 +507,8 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
 }
 
 // ------------------------------------------------------------------------------------------------
-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> 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_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> 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");
             }
@@ -803,24 +816,28 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
         static_cast<int>(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<std::string> str;
     for (std::vector<BaseImporter*>::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<int>(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<ai_real>(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<std::string>(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<aiMatrix4x4>(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<int>(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<ai_real>(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<std::string>(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<aiMatrix4x4>(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;
 

+ 16 - 8
code/FBX/FBXConverter.cpp

@@ -60,6 +60,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/scene.h>
 
 #include <assimp/CreateAnimMesh.h>
+#include <assimp/commonMetaData.h>
+#include <assimp/StringUtils.h>
 
 #include <tuple>
 #include <memory>
@@ -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<const std::string, aiBone *>(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()

+ 2 - 0
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();
 
     // ------------------------------------------------------------------------------------------------

+ 0 - 2
code/LWO/LWOLoader.cpp

@@ -586,7 +586,6 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
     root->mName.Set("<LWORoot>");
 
     //Set parent of all children, inserting pivots
-    //std::cout << "Set parent of all children" << std::endl;
     std::map<uint16_t, aiNode*> mapPivot;
     for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
 
@@ -618,7 +617,6 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& 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;
     }

+ 21 - 1
code/glTF/glTFImporter.cpp

@@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/ai_assert.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/importerdesc.h>
+#include <assimp/commonMetaData.h>
 
 #include <memory>
 
@@ -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;

+ 1 - 1
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

+ 21 - 0
code/glTF2/glTF2Importer.cpp

@@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/scene.h>
 #include <assimp/DefaultLogger.hpp>
 #include <assimp/Importer.hpp>
+#include <assimp/commonMetaData.h>
 
 #include <memory>
 #include <unordered_map>
@@ -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;
 	}

+ 1 - 0
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

+ 1 - 1
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
 */

+ 63 - 0
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

+ 19 - 2
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
 
 };

+ 27 - 0
test/unit/utFBXImporterExporter.cpp

@@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/material.h>
 #include <assimp/scene.h>
 #include <assimp/types.h>
+#include <assimp/commonMetaData.h>
 
 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);
+    }
+}

+ 28 - 0
test/unit/utglTF2ImportExport.cpp

@@ -45,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/Exporter.hpp>
 #include <assimp/postprocess.h>
 #include <assimp/scene.h>
+#include <assimp/commonMetaData.h>
+
 #include <array>
 
 using namespace Assimp;
@@ -436,3 +438,29 @@ TEST_F(utglTF2ImportExport, error_string_preserved) {
 }
 
 #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);
+    }
+}

+ 26 - 0
test/unit/utglTFImportExport.cpp

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/postprocess.h>
 
 #include <assimp/scene.h>
+#include <assimp/commonMetaData.h>
 
 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);
+    }
+}