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

Merge branch 'master' into patch-1

JeffH-BMG 7 жил өмнө
parent
commit
376586b164

+ 3 - 1
Readme.md

@@ -32,8 +32,8 @@ Please check our Wiki as well: https://github.com/assimp/assimp/wiki
 
 #### Supported file formats ####
 
-A full list [is here](http://assimp.org/main_features_formats.html).
 __Importers__:
+
 - 3D
 - 3DS
 - 3MF
@@ -109,6 +109,8 @@ __Exporters__:
 - STEP
 - glTF 1.0 (partial)
 - glTF 2.0 (partial)
+- 3MF ( experimental )
+- FBX ( experimental )
 
 ### Building ###
 Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do.

+ 1 - 1
code/3DSConverter.cpp

@@ -72,7 +72,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
     unsigned int idx( NotSet );
     for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
     {
-        std::string s = mScene->mMaterials[i].mName;
+        std::string &s = mScene->mMaterials[i].mName;
         for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) {
             *it = static_cast< char >( ::tolower( *it ) );
         }

+ 5 - 4
code/AMFImporter_Postprocess.cpp

@@ -156,10 +156,11 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string&
 	TextureConverted_Index = 0;
 	for(const SPP_Texture& tex_convd: mTexture_Converted)
 	{
-		if(tex_convd.ID == TextureConverted_ID)
-			return TextureConverted_Index;
-		else
-			TextureConverted_Index++;
+        if ( tex_convd.ID == TextureConverted_ID ) {
+            return TextureConverted_Index;
+        } else {
+            ++TextureConverted_Index;
+        }
 	}
 
 	//

+ 13 - 13
code/ASEParser.cpp

@@ -267,7 +267,9 @@ void Parser::Parse()
                 // at the file extension (ASE, ASK, ASC)
                 // *************************************************************
 
-                if (fmt)iFileFormat = fmt;
+                if ( fmt ) {
+                    iFileFormat = fmt;
+                }
                 continue;
             }
             // main scene information
@@ -427,28 +429,25 @@ void Parser::ParseLV1SoftSkinBlock()
                         // Reserve enough storage
                         vert.mBoneWeights.reserve(numWeights);
 
-                        for (unsigned int w = 0; w < numWeights;++w)
-                        {
-                            std::string bone;
+                        std::string bone;
+                        for (unsigned int w = 0; w < numWeights;++w) {
+                            bone.clear();
                             ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
 
                             // Find the bone in the mesh's list
                             std::pair<int,ai_real> me;
                             me.first = -1;
 
-                            for (unsigned int n = 0; n < curMesh->mBones.size();++n)
-                            {
-                                if (curMesh->mBones[n].mName == bone)
-                                {
+                            for (unsigned int n = 0; n < curMesh->mBones.size();++n) {
+                                if (curMesh->mBones[n].mName == bone) {
                                     me.first = n;
                                     break;
                                 }
                             }
-                            if (-1 == me.first)
-                            {
+                            if (-1 == me.first) {
                                 // We don't have this bone yet, so add it to the list
-                                me.first = (int)curMesh->mBones.size();
-                                curMesh->mBones.push_back(ASE::Bone(bone));
+                                me.first = static_cast<int>( curMesh->mBones.size() );
+                                curMesh->mBones.push_back( ASE::Bone( bone ) );
                             }
                             ParseLV4MeshFloat( me.second );
 
@@ -745,6 +744,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
     // empty the texture won't be used later.
     // ***********************************************************
     bool parsePath = true;
+    std::string temp;
     while (true)
     {
         if ('*' == *filePtr)
@@ -753,7 +753,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
             // type of map
             if (TokenMatch(filePtr,"MAP_CLASS" ,9))
             {
-                std::string temp;
+                temp.clear();
                 if(!ParseString(temp,"*MAP_CLASS"))
                     SkipToNextToken();
                 if (temp != "Bitmap" && temp != "Normal Bump")

+ 14 - 13
code/BVHLoader.cpp

@@ -199,6 +199,7 @@ aiNode* BVHLoader::ReadNode()
     Node& internNode = mNodes.back();
 
     // now read the node's contents
+    std::string siteToken;
     while( 1)
     {
         std::string token = GetNextToken();
@@ -218,7 +219,8 @@ aiNode* BVHLoader::ReadNode()
         else if( token == "End")
         {
             // The real symbol is "End Site". Second part comes in a separate token
-            std::string siteToken = GetNextToken();
+            siteToken.clear();
+            siteToken = GetNextToken();
             if( siteToken != "Site")
                 ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
 
@@ -262,21 +264,18 @@ aiNode* BVHLoader::ReadEndSite( const std::string& pParentName)
     aiNode* node = new aiNode( "EndSite_" + pParentName);
 
     // now read the node's contents. Only possible entry is "OFFSET"
-    while( 1)
-    {
-        std::string token = GetNextToken();
+    std::string token;
+    while( 1) {
+        token.clear();
+        token = GetNextToken();
 
         // end node's offset
-        if( token == "OFFSET")
-        {
+        if( token == "OFFSET") {
             ReadNodeOffset( node);
-        }
-        else if( token == "}")
-        {
+        } else if( token == "}") {
             // we're done with the end node
             break;
-        } else
-        {
+        } else {
             // everything else is a parse error
             ThrowException( format() << "Unknown keyword \"" << token << "\"." );
         }
@@ -296,8 +295,10 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
     offset.z = GetNextTokenAsFloat();
 
     // build a transformation matrix from it
-    pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y,
-        0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f);
+    pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x,
+                                          0.0f, 1.0f, 0.0f, offset.y,
+                                          0.0f, 0.0f, 1.0f, offset.z,
+                                          0.0f, 0.0f, 0.0f, 1.0f);
 }
 
 // ------------------------------------------------------------------------------------------------

+ 2 - 1
code/BaseImporter.cpp

@@ -251,7 +251,8 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions) {
 /* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
     const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
 {
-    ai_assert(size <= 16 && _magic);
+    ai_assert( size <= 16 );
+    ai_assert( _magic );
 
     if (!pIOHandler) {
         return false;

+ 9 - 5
code/ColladaExporter.cpp

@@ -1269,7 +1269,8 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
 	
 	mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr;
 	PushTag();
-	
+
+    std::string node_idstr;
 	for (size_t a = 0; a < anim->mNumChannels; ++a) {
 		const aiNodeAnim * nodeAnim = anim->mChannels[a];
 		
@@ -1277,7 +1278,9 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
 		if ( nodeAnim->mNumPositionKeys != nodeAnim->mNumScalingKeys ||  nodeAnim->mNumPositionKeys != nodeAnim->mNumRotationKeys ) continue;
 		
 		{
-			const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-input");
+            node_idstr.clear();
+            node_idstr += nodeAnim->mNodeName.data;
+            node_idstr += std::string( "_matrix-input" );
 
 			std::vector<ai_real> frames;
 			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
@@ -1289,12 +1292,14 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
 		}
 		
 		{
-			const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-output");
+            node_idstr.clear();
+
+            node_idstr += nodeAnim->mNodeName.data;
+            node_idstr += std::string("_matrix-output");
 			
 			std::vector<ai_real> keyframes;
 			keyframes.reserve(nodeAnim->mNumPositionKeys * 16);
 			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
-				
 				aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue;
 				aiMatrix4x4 ScalingM;  // identity
 				ScalingM[0][0] = Scaling.x; ScalingM[1][1] = Scaling.y; ScalingM[2][2] = Scaling.z;
@@ -1361,7 +1366,6 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
 			PopTag();
 			mOutput << startstr << "</source>" << endstr;
 		}
-		
 	}
 	
 	for (size_t a = 0; a < anim->mNumChannels; ++a) {

+ 8 - 4
code/ColladaLoader.cpp

@@ -1121,6 +1121,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
             continue;
 
         // now check all channels if they affect the current node
+        std::string targetID, subElement;
         for( std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
             cit != pSrcAnim->mChannels.end(); ++cit)
         {
@@ -1147,7 +1148,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
             }
             if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos)
                 continue;
-            std::string targetID = srcChannel.mTarget.substr( 0, slashPos);
+
+            targetID.clear();
+            targetID = srcChannel.mTarget.substr( 0, slashPos);
             if( targetID != srcNode->mID)
                 continue;
 
@@ -1160,7 +1163,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
 
                 entry.mTransformId = srcChannel.mTarget.substr( slashPos+1, dotPos - slashPos - 1);
 
-                std::string subElement = srcChannel.mTarget.substr( dotPos+1);
+                subElement.clear();
+                subElement = srcChannel.mTarget.substr( dotPos+1);
                 if( subElement == "ANGLE")
                     entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle
                 else if( subElement == "X")
@@ -1181,7 +1185,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
             if (bracketPos != std::string::npos)
             {
                 entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
-                std::string subElement = srcChannel.mTarget.substr(bracketPos);
+                subElement.clear();
+                subElement = srcChannel.mTarget.substr(bracketPos);
 
                 if (subElement == "(0)(0)")
                     entry.mSubElement = 0;
@@ -1215,7 +1220,6 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
                     entry.mSubElement = 14;
                 else if (subElement == "(3)(3)")
                     entry.mSubElement = 15;
-
             }
 
             // determine which transform step is affected by this channel

+ 29 - 3
code/D3MFExporter.cpp

@@ -117,6 +117,7 @@ bool D3MFExporter::exportArchive( const char *file ) {
     if ( nullptr == m_zipArchive ) {
         return false;
     }
+
     ok |= exportContentTypes();
     ok |= export3DModel();
     ok |= exportRelations();
@@ -181,6 +182,8 @@ bool D3MFExporter::export3DModel() {
     mModelOutput << "<" << XmlTag::resources << ">";
     mModelOutput << std::endl;
 
+    writeMetaData();
+
     writeBaseMaterials();
 
     writeObjects();
@@ -209,22 +212,45 @@ void D3MFExporter::writeHeader() {
     mModelOutput << std::endl;
 }
 
+void D3MFExporter::writeMetaData() {
+    if ( nullptr == mScene->mMetaData ) {
+        return;
+    }
+
+    const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
+    if ( 0 == numMetaEntries ) {
+        return;
+    }
+
+    const aiString *key;
+    const aiMetadataEntry *entry(nullptr);
+    for ( size_t i = 0; i < numMetaEntries; ++i ) {
+        mScene->mMetaData->Get( i, key, entry );
+        std::string k( key->C_Str() );
+        aiString value;
+        mScene->mMetaData->Get(  k, value );
+        mModelOutput << "<" << XmlTag::meta << " " << XmlTag::meta_name << "=\"" << key->C_Str() << "\">";
+        mModelOutput << value.C_Str();
+        mModelOutput << "</" << XmlTag::meta << ">" << std::endl;
+    }
+}
+
 void D3MFExporter::writeBaseMaterials() {
     mModelOutput << "<basematerials id=\"1\">\n";
+    std::string strName, hexDiffuseColor , tmp;
     for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
         aiMaterial *mat = mScene->mMaterials[ i ];
-        std::string strName;
         aiString name;
         if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
             strName = "basemat_" + to_string( i );
         } else {
             strName = name.C_Str();
         }
-        std::string hexDiffuseColor;
         aiColor4D color;
         if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
+            hexDiffuseColor.clear();
+            tmp.clear();
             hexDiffuseColor = "#";
-            std::string tmp;
             
             tmp = DecimalToHexa( color.r );
             hexDiffuseColor += tmp;

+ 1 - 0
code/D3MFExporter.h

@@ -76,6 +76,7 @@ public:
 
 protected:
     void writeHeader();
+    void writeMetaData();
     void writeBaseMaterials();
     void writeObjects();
     void writeMesh( aiMesh *mesh );

+ 39 - 5
code/D3MFImporter.cpp

@@ -94,14 +94,17 @@ public:
         scene->mRootNode = new aiNode();
         std::vector<aiNode*> children;
 
+        std::string nodeName;
         while(ReadToEndElement(D3MF::XmlTag::model)) {
-            const std::string nodeName( xmlReader->getNodeName() );
+            nodeName = xmlReader->getNodeName();
             if( nodeName == D3MF::XmlTag::object) {
                 children.push_back(ReadObject(scene));
             } else if( nodeName == D3MF::XmlTag::build) {
                 // 
             } else if ( nodeName == D3MF::XmlTag::basematerials ) {
                 ReadBaseMaterials();
+            } else if ( nodeName == D3MF::XmlTag::meta ) {
+                ReadMetadata();
             }
         }
 
@@ -109,19 +112,31 @@ public:
             scene->mRootNode->mName.Set( "3MF" );
         }
 
+        // import the metadata
+        if ( !mMetaData.empty() ) {
+            const size_t numMeta( mMetaData.size() );
+            scene->mMetaData = aiMetadata::Alloc( numMeta );
+            for ( size_t i = 0; i < numMeta; ++i ) {
+                aiString val( mMetaData[ i ].value );
+                scene->mMetaData->Set( i, mMetaData[ i ].name, val );
+            }
+        }
+
+        // import the meshes
         scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
         scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
-
         std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
 
+        // import the materials
         scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
         if ( 0 != scene->mNumMaterials ) {
             scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
             std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
         }
+
+        // create the scenegraph
         scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
         scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
-
         std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
     }
 
@@ -180,6 +195,21 @@ private:
         return mesh;
     }
 
+    void ReadMetadata() {
+        const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
+        xmlReader->read();
+        const std::string value = xmlReader->getNodeData();
+
+        if ( name.empty() ) {
+            return;
+        }
+
+        MetaEntry entry;
+        entry.name = name;
+        entry.value = value;
+        mMetaData.push_back( entry );
+    }
+
     void ImportVertices(aiMesh* mesh) {
         std::vector<aiVector3D> vertices;
         while(ReadToEndElement(D3MF::XmlTag::vertices)) {
@@ -253,7 +283,7 @@ private:
                     MatIdArray = it->second;
                 }
             }
-            MatIdArray.push_back( newMatIdx );
+            MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
             mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
         }
 
@@ -371,8 +401,12 @@ private:
         return false;
     }
 
-
 private:
+    struct MetaEntry {
+        std::string name;
+        std::string value;
+    };
+    std::vector<MetaEntry> mMetaData;
     std::vector<aiMesh*> mMeshes;
     MatArray mMatArray;
     unsigned int mActiveMatGroup;

+ 2 - 2
code/D3MFOpcPackage.cpp

@@ -288,8 +288,8 @@ bool D3MFZipArchive::Exists(const char* pFile) const {
         return false;
     }
 
-    std::string rFile(pFile);
-    std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile);
+    std::string filename(pFile);
+    std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(filename);
     bool exist( false );
     if(it != m_ArchiveMap.end()) {
         exist = true;

+ 0 - 1
code/DXFHelper.h

@@ -169,7 +169,6 @@ public:
     }
 
 private:
-
     LineSplitter splitter;
     int groupcode;
     std::string value;

+ 3 - 3
code/DefaultIOSystem.cpp

@@ -76,7 +76,7 @@ bool DefaultIOSystem::Exists( const char* pFile) const
 #ifdef _WIN32
     wchar_t fileName16[PATHLIMIT];
 
-    bool isUnicode = IsTextUnicode(pFile, strlen(pFile), NULL);
+    bool isUnicode = IsTextUnicode(pFile, static_cast<int>(strlen(pFile)), NULL);
     if (isUnicode) {
 
         MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
@@ -110,7 +110,7 @@ IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode)
     FILE* file;
 #ifdef _WIN32
     wchar_t fileName16[PATHLIMIT];
-    bool isUnicode = IsTextUnicode(strFile, strlen(strFile), NULL );
+    bool isUnicode = IsTextUnicode(strFile, static_cast<int>(strlen(strFile)), NULL );
     if (isUnicode) {
         MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT);
         std::string mode8(strMode);
@@ -158,7 +158,7 @@ inline static void MakeAbsolutePath (const char* in, char* _out)
 {
     ai_assert(in && _out);
 #if defined( _MSC_VER ) || defined( __MINGW32__ )
-    bool isUnicode = IsTextUnicode(in, strlen(in), NULL);
+    bool isUnicode = IsTextUnicode(in, static_cast<int>(strlen(in)), NULL);
     if (isUnicode) {
         wchar_t out16[PATHLIMIT];
         wchar_t in16[PATHLIMIT];

+ 56 - 68
code/DefaultLogger.cpp

@@ -45,7 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *  @brief Implementation of DefaultLogger (and Logger)
  */
 
-
 // Default log streams
 #include "Win32DebugLogStream.h"
 #include "StdOStreamLogStream.h"
@@ -62,8 +61,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_SINGLETHREADED
 #   include <thread>
 #   include <mutex>
-
-std::mutex loggerMutex;
+    std::mutex loggerMutex;
 #endif
 
 namespace Assimp    {
@@ -76,22 +74,19 @@ static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::War
 
 // ----------------------------------------------------------------------------------
 // Represents a log-stream + its error severity
-struct LogStreamInfo
-{
-    unsigned int m_uiErrorSeverity;
-    LogStream *m_pStream;
+struct LogStreamInfo {
+    unsigned int  m_uiErrorSeverity;
+    LogStream    *m_pStream;
 
     // Constructor
     LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
         m_uiErrorSeverity( uiErrorSev ),
-        m_pStream( pStream )
-    {
+        m_pStream( pStream ) {
         // empty
     }
 
     // Destructor
-    ~LogStreamInfo()
-    {
+    ~LogStreamInfo() {
         delete m_pStream;
     }
 };
@@ -109,7 +104,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream    streams,
 #ifdef WIN32
         return new Win32DebugLogStream();
 #else
-        return NULL;
+        return nullptr;
 #endif
 
         // Platform-independent default streams
@@ -118,7 +113,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream    streams,
     case aiDefaultLogStream_STDOUT:
         return new StdOStreamLogStream(std::cout);
     case aiDefaultLogStream_FILE:
-        return (name && *name ? new FileLogStream(name,io) : NULL);
+        return (name && *name ? new FileLogStream(name,io) : nullptr );
     default:
         // We don't know this default log stream, so raise an assertion
         ai_assert(false);
@@ -134,34 +129,38 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream    streams,
 Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
     LogSeverity severity                       /*= NORMAL*/,
     unsigned int defStreams                    /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
-    IOSystem* io                               /*= NULL*/)
-{
+    IOSystem* io                               /*= NULL*/) {
     // enter the mutex here to avoid concurrency problems
 #ifndef ASSIMP_BUILD_SINGLETHREADED
     std::lock_guard<std::mutex> lock(loggerMutex);
 #endif
 
-    if (m_pLogger && !isNullLogger() )
+    if ( m_pLogger && !isNullLogger() ) {
         delete m_pLogger;
+    }
 
     m_pLogger = new DefaultLogger( severity );
 
     // Attach default log streams
     // Stream the log to the MSVC debugger?
-    if (defStreams & aiDefaultLogStream_DEBUGGER)
-        m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_DEBUGGER));
+    if ( defStreams & aiDefaultLogStream_DEBUGGER ) {
+        m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_DEBUGGER ) );
+    }
 
     // Stream the log to COUT?
-    if (defStreams & aiDefaultLogStream_STDOUT)
-        m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDOUT));
+    if ( defStreams & aiDefaultLogStream_STDOUT ) {
+        m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDOUT ) );
+    }
 
     // Stream the log to CERR?
-    if (defStreams & aiDefaultLogStream_STDERR)
-         m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_STDERR));
+    if ( defStreams & aiDefaultLogStream_STDERR ) {
+        m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_STDERR ) );
+    }
 
     // Stream the log to a file
-    if (defStreams & aiDefaultLogStream_FILE && name && *name)
-        m_pLogger->attachStream( LogStream::createDefaultStream(aiDefaultLogStream_FILE,name,io));
+    if ( defStreams & aiDefaultLogStream_FILE && name && *name ) {
+        m_pLogger->attachStream( LogStream::createDefaultStream( aiDefaultLogStream_FILE, name, io ) );
+    }
 
     return m_pLogger;
 }
@@ -200,7 +199,6 @@ void Logger::warn(const char* message)  {
 
 // ----------------------------------------------------------------------------------
 void Logger::error(const char* message) {
-
     // SECURITY FIX: see above
     if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
         return;
@@ -209,23 +207,24 @@ void Logger::error(const char* message) {
 }
 
 // ----------------------------------------------------------------------------------
-void DefaultLogger::set( Logger *logger )
-{
+void DefaultLogger::set( Logger *logger ) {
     // enter the mutex here to avoid concurrency problems
 #ifndef ASSIMP_BUILD_SINGLETHREADED
     std::lock_guard<std::mutex> lock(loggerMutex);
 #endif
 
-    if (!logger)logger = &s_pNullLogger;
-    if (m_pLogger && !isNullLogger() )
+    if ( nullptr == logger ) {
+        logger = &s_pNullLogger;
+    }
+    if ( nullptr != m_pLogger && !isNullLogger() ) {
         delete m_pLogger;
+    }
 
     DefaultLogger::m_pLogger = logger;
 }
 
 // ----------------------------------------------------------------------------------
-bool DefaultLogger::isNullLogger()
-{
+bool DefaultLogger::isNullLogger() {
     return m_pLogger == &s_pNullLogger;
 }
 
@@ -236,8 +235,7 @@ Logger *DefaultLogger::get() {
 
 // ----------------------------------------------------------------------------------
 //  Kills the only instance
-void DefaultLogger::kill()
-{
+void DefaultLogger::kill() {
     // enter the mutex here to avoid concurrency problems
 #ifndef ASSIMP_BUILD_SINGLETHREADED
     std::lock_guard<std::mutex> lock(loggerMutex);
@@ -252,10 +250,10 @@ void DefaultLogger::kill()
 
 // ----------------------------------------------------------------------------------
 //  Debug message
-void DefaultLogger::OnDebug( const char* message )
-{
-	if ( m_Severity == Logger::NORMAL )
-		return;
+void DefaultLogger::OnDebug( const char* message ) {
+    if ( m_Severity == Logger::NORMAL ) {
+        return;
+    }
 
 	static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
 	char msg[Size];
@@ -266,8 +264,7 @@ void DefaultLogger::OnDebug( const char* message )
 
 // ----------------------------------------------------------------------------------
 //  Logs an info
-void DefaultLogger::OnInfo( const char* message )
-{
+void DefaultLogger::OnInfo( const char* message ){
 	static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
 	char msg[Size];
     ai_snprintf(msg, Size, "Info,  T%u: %s", GetThreadID(), message );
@@ -277,8 +274,7 @@ void DefaultLogger::OnInfo( const char* message )
 
 // ----------------------------------------------------------------------------------
 //  Logs a warning
-void DefaultLogger::OnWarn( const char* message )
-{
+void DefaultLogger::OnWarn( const char* message ) {
 	static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
 	char msg[Size];
 	ai_snprintf(msg, Size, "Warn,  T%u: %s", GetThreadID(), message );
@@ -288,8 +284,7 @@ void DefaultLogger::OnWarn( const char* message )
 
 // ----------------------------------------------------------------------------------
 //  Logs an error
-void DefaultLogger::OnError( const char* message )
-{
+void DefaultLogger::OnError( const char* message ) {
 	static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
 	char msg[ Size ];
     ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message );
@@ -299,10 +294,10 @@ void DefaultLogger::OnError( const char* message )
 
 // ----------------------------------------------------------------------------------
 //  Will attach a new stream
-bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
-{
-    if (!pStream)
+bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity ) {
+    if ( nullptr == pStream ) {
         return false;
+    }
 
     if (0 == severity)  {
         severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
@@ -312,8 +307,7 @@ bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
         it != m_StreamArray.end();
         ++it )
     {
-        if ( (*it)->m_pStream == pStream )
-        {
+        if ( (*it)->m_pStream == pStream ) {
             (*it)->m_uiErrorSeverity |= severity;
             return true;
         }
@@ -326,34 +320,31 @@ bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
 
 // ----------------------------------------------------------------------------------
 //  Detach a stream
-bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity )
-{
-    if (!pStream)
+bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity ) {
+    if ( nullptr == pStream ) {
         return false;
+    }
 
     if (0 == severity)  {
         severity = SeverityAll;
     }
 
-    for ( StreamIt it = m_StreamArray.begin();
-        it != m_StreamArray.end();
-        ++it )
-    {
-        if ( (*it)->m_pStream == pStream )
-        {
+    bool res( false );
+    for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
+        if ( (*it)->m_pStream == pStream ) {
             (*it)->m_uiErrorSeverity &= ~severity;
-            if ( (*it)->m_uiErrorSeverity == 0 )
-            {
+            if ( (*it)->m_uiErrorSeverity == 0 ) {
                 // don't delete the underlying stream 'cause the caller gains ownership again
-                (**it).m_pStream = NULL;
+                (**it).m_pStream = nullptr;
                 delete *it;
                 m_StreamArray.erase( it );
+                res = true;
                 break;
             }
             return true;
         }
     }
-    return false;
+    return res;
 }
 
 // ----------------------------------------------------------------------------------
@@ -361,15 +352,13 @@ bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity )
 DefaultLogger::DefaultLogger(LogSeverity severity)
     :   Logger  ( severity )
     ,   noRepeatMsg (false)
-    ,   lastLen( 0 )
-{
+    ,   lastLen( 0 ) {
     lastMsg[0] = '\0';
 }
 
 // ----------------------------------------------------------------------------------
 //  Destructor
-DefaultLogger::~DefaultLogger()
-{
+DefaultLogger::~DefaultLogger() {
     for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
         // also frees the underlying stream, we are its owner.
         delete *it;
@@ -378,9 +367,8 @@ DefaultLogger::~DefaultLogger()
 
 // ----------------------------------------------------------------------------------
 //  Writes message to stream
-void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev )
-{
-    ai_assert(NULL != message);
+void DefaultLogger::WriteToStreams(const char *message, ErrorSeverity ErrorSev ) {
+    ai_assert(nullptr != message);
 
     // Check whether this is a repeated message
     if (! ::strncmp( message,lastMsg, lastLen-1))

+ 6 - 6
code/EmbedTexturesProcess.cpp

@@ -99,22 +99,22 @@ void EmbedTexturesProcess::Execute(aiScene* pScene) {
 }
 
 bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
-    uint32_t imageSize = 0;
-    std::string imagePath = path;
+    std::streampos imageSize = 0;
+    std::string    imagePath = path;
 
     // Test path directly
     std::ifstream file(imagePath, std::ios::binary | std::ios::ate);
-    if ((imageSize = file.tellg()) == -1u) {
+    if ((imageSize = file.tellg()) == std::streampos(-1)) {
         DefaultLogger::get()->warn("EmbedTexturesProcess: Cannot find image: " + imagePath + ". Will try to find it in root folder.");
 
         // Test path in root path
         imagePath = mRootPath + path;
         file.open(imagePath, std::ios::binary | std::ios::ate);
-        if ((imageSize = file.tellg()) == -1u) {
+        if ((imageSize = file.tellg()) == std::streampos(-1)) {
             // Test path basename in root path
             imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u);
             file.open(imagePath, std::ios::binary | std::ios::ate);
-            if ((imageSize = file.tellg()) == -1u) {
+            if ((imageSize = file.tellg()) == std::streampos(-1)) {
                 DefaultLogger::get()->error("EmbedTexturesProcess: Unable to embed texture: " + path + ".");
                 return false;
             }
@@ -134,7 +134,7 @@ bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
     // Add the new texture
     auto pTexture = new aiTexture();
     pTexture->mHeight = 0; // Means that this is still compressed
-    pTexture->mWidth = imageSize;
+    pTexture->mWidth = static_cast<uint32_t>(imageSize);
     pTexture->pcData = imageContent;
 
     auto extension = path.substr(path.find_last_of('.') + 1u);

+ 2 - 1
code/Exporter.cpp

@@ -308,7 +308,8 @@ bool IsVerboseFormat(const aiScene* pScene) {
 }
 
 // ------------------------------------------------------------------------------------------------
-aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing, const ExportProperties* pProperties) {
+aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath,
+        unsigned int pPreprocessing, const ExportProperties* pProperties) {
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
     // when they create scenes from scratch, users will likely create them not in verbose

+ 5 - 6
code/FBXConverter.cpp

@@ -704,7 +704,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
         aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
         aiVector3D GeometricScalingInverse = GeometricScaling;
         bool canscale = true;
-        for (size_t i = 0; i < 3; ++i) {
+        for (unsigned int i = 0; i < 3; ++i) {
             if ( std::fabs( GeometricScalingInverse[i] ) > zero_epsilon ) {
                 GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
             } else {
@@ -1642,9 +1642,8 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
 }
 
 void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
-    const std::string& propName,
-    aiTextureType target, const MeshGeometry* const mesh )
-{
+        const std::string& propName,
+        aiTextureType target, const MeshGeometry* const mesh ) {
     LayeredTextureMap::const_iterator it = layeredTextures.find( propName );
     if ( it == layeredTextures.end() ) {
         return;
@@ -1888,11 +1887,11 @@ void Converter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyT
 
     // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
     const aiColor3D& Transparent = GetColorPropertyFactored( props, "TransparentColor", "TransparencyFactor", ok );
-    float CalculatedOpacity = 1.0;
+    float CalculatedOpacity = 1.0f;
     if ( ok ) {
         out_mat->AddProperty( &Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT );
         // as calculated by FBX SDK 2017:
-        CalculatedOpacity = 1.0 - ((Transparent.r + Transparent.g + Transparent.b) / 3.0);
+        CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f);
     }
 
     // use of TransparencyFactor is inconsistent.

+ 8 - 8
code/FBXExportNode.cpp

@@ -182,7 +182,7 @@ void FBX::Node::Begin(Assimp::StreamWriterLE &s)
     s.PutU4(0); // total property section length
 
     // node name
-    s.PutU1(name.size()); // length of node name
+    s.PutU1(uint8_t(name.size())); // length of node name
     s.PutString(name); // node name as raw bytes
 
     // property data comes after here
@@ -217,8 +217,8 @@ void FBX::Node::EndProperties(
     ai_assert(pos > property_start);
     size_t property_section_size = pos - property_start;
     s.Seek(start_pos + 4);
-    s.PutU4(num_properties);
-    s.PutU4(property_section_size);
+    s.PutU4(uint32_t(num_properties));
+    s.PutU4(uint32_t(property_section_size));
     s.Seek(pos);
 }
 
@@ -232,7 +232,7 @@ void FBX::Node::End(
     // now go back and write initial pos
     this->end_pos = s.Tell();
     s.Seek(start_pos);
-    s.PutU4(end_pos);
+    s.PutU4(uint32_t(end_pos));
     s.Seek(end_pos);
 }
 
@@ -251,9 +251,9 @@ void FBX::Node::WritePropertyNode(
     Node node(name);
     node.Begin(s);
     s.PutU1('d');
-    s.PutU4(v.size()); // number of elements
+    s.PutU4(uint32_t(v.size())); // number of elements
     s.PutU4(0); // no encoding (1 would be zip-compressed)
-    s.PutU4(v.size() * 8); // data size
+    s.PutU4(uint32_t(v.size()) * 8); // data size
     for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); }
     node.EndProperties(s, 1);
     node.End(s, false);
@@ -271,9 +271,9 @@ void FBX::Node::WritePropertyNode(
     Node node(name);
     node.Begin(s);
     s.PutU1('i');
-    s.PutU4(v.size()); // number of elements
+    s.PutU4(uint32_t(v.size())); // number of elements
     s.PutU4(0); // no encoding (1 would be zip-compressed)
-    s.PutU4(v.size() * 4); // data size
+    s.PutU4(uint32_t(v.size()) * 4); // data size
     for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); }
     node.EndProperties(s, 1);
     node.End(s, false);

+ 7 - 7
code/FBXExportProperty.cpp

@@ -127,8 +127,8 @@ FBX::Property::Property(const aiMatrix4x4& vm)
     : type('d'), data(8*16)
 {
     double* d = reinterpret_cast<double*>(data.data());
-    for (size_t c = 0; c < 4; ++c) {
-        for (size_t r = 0; r < 4; ++r) {
+    for (unsigned int c = 0; c < 4; ++c) {
+        for (unsigned int r = 0; r < 4; ++r) {
             d[4*c+r] = vm[r][c];
         }
     }
@@ -164,15 +164,15 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s)
     case 'L': s.PutI8(*(reinterpret_cast<int64_t*>(data.data()))); return;
     case 'S':
     case 'R':
-        s.PutU4(data.size());
+        s.PutU4(uint32_t(data.size()));
         for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
         return;
     case 'i':
         N = data.size() / 4;
-        s.PutU4(N); // number of elements
+        s.PutU4(uint32_t(N)); // number of elements
         s.PutU4(0); // no encoding (1 would be zip-compressed)
         // TODO: compress if large?
-        s.PutU4(data.size()); // data size
+        s.PutU4(uint32_t(data.size())); // data size
         d = data.data();
         for (size_t i = 0; i < N; ++i) {
             s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
@@ -180,10 +180,10 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s)
         return;
     case 'd':
         N = data.size() / 8;
-        s.PutU4(N); // number of elements
+        s.PutU4(uint32_t(N)); // number of elements
         s.PutU4(0); // no encoding (1 would be zip-compressed)
         // TODO: compress if large?
-        s.PutU4(data.size()); // data size
+        s.PutU4(uint32_t(data.size())); // data size
         d = data.data();
         for (size_t i = 0; i < N; ++i) {
             s.PutF8((reinterpret_cast<double*>(d))[i]);

+ 25 - 25
code/FBXExporter.cpp

@@ -460,7 +460,7 @@ size_t count_images(const aiScene* scene) {
         ){
             const aiTextureType textype = static_cast<aiTextureType>(tt);
             const size_t texcount = mat->GetTextureCount(textype);
-            for (size_t j = 0; j < texcount; ++j) {
+            for (unsigned int j = 0; j < texcount; ++j) {
                 mat->GetTexture(textype, j, &texpath);
                 images.insert(std::string(texpath.C_Str()));
             }
@@ -593,7 +593,7 @@ void FBXExporter::WriteDefinitions ()
 
     // Model / FbxNode
     // <~~ node heirarchy
-    count = count_nodes(mScene->mRootNode) - 1; // (not counting root node)
+    count = int32_t(count_nodes(mScene->mRootNode)) - 1; // (not counting root node)
     if (count) {
         n = FBX::Node("ObjectType", Property("Model"));
         n.AddChild("Count", count);
@@ -763,7 +763,7 @@ void FBXExporter::WriteDefinitions ()
 
     // Video / FbxVideo
     // one for each image file.
-    count = count_images(mScene);
+    count = int32_t(count_images(mScene));
     if (count) {
         n = FBX::Node("ObjectType", Property("Video"));
         n.AddChild("Count", count);
@@ -792,7 +792,7 @@ void FBXExporter::WriteDefinitions ()
 
     // Texture / FbxFileTexture
     // <~~ aiTexture
-    count = count_textures(mScene);
+    count = int32_t(count_textures(mScene));
     if (count) {
         n = FBX::Node("ObjectType", Property("Texture"));
         n.AddChild("Count", count);
@@ -848,7 +848,7 @@ void FBXExporter::WriteDefinitions ()
     }
 
     // Deformer
-    count = count_deformers(mScene);
+    count = int32_t(count_deformers(mScene));
     if (count) {
         n = FBX::Node("ObjectType", Property("Deformer"));
         n.AddChild("Count", count);
@@ -943,7 +943,7 @@ void FBXExporter::WriteObjects ()
         std::vector<int32_t> vertex_indices;
         // map of vertex value to its index in the data vector
         std::map<aiVector3D,size_t> index_by_vertex_value;
-        size_t index = 0;
+		int32_t index = 0;
         for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
             aiVector3D vtx = m->mVertices[vi];
             auto elem = index_by_vertex_value.find(vtx);
@@ -955,7 +955,7 @@ void FBXExporter::WriteObjects ()
                 flattened_vertices.push_back(vtx[2]);
                 ++index;
             } else {
-                vertex_indices.push_back(elem->second);
+                vertex_indices.push_back(int32_t(elem->second));
             }
         }
         FBX::Node::WritePropertyNode(
@@ -1052,7 +1052,7 @@ void FBXExporter::WriteObjects ()
             std::vector<double> uv_data;
             std::vector<int32_t> uv_indices;
             std::map<aiVector3D,int32_t> index_by_uv;
-            size_t index = 0;
+			int32_t index = 0;
             for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
                 const aiFace &f = m->mFaces[fi];
                 for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
@@ -1062,7 +1062,7 @@ void FBXExporter::WriteObjects ()
                     if (elem == index_by_uv.end()) {
                         index_by_uv[uv] = index;
                         uv_indices.push_back(index);
-                        for (size_t x = 0; x < m->mNumUVComponents[uvi]; ++x) {
+                        for (unsigned int x = 0; x < m->mNumUVComponents[uvi]; ++x) {
                             uv_data.push_back(uv[x]);
                         }
                         ++index;
@@ -1208,13 +1208,13 @@ void FBXExporter::WriteObjects ()
         // and usualy are completely ignored when loading.
         // One notable exception is the "Opacity" property,
         // which Blender uses as (1.0 - alpha).
-        c.r = 0; c.g = 0; c.b = 0;
+        c.r = 0.0f; c.g = 0.0f; c.b = 0.0f;
         m->Get(AI_MATKEY_COLOR_EMISSIVE, c);
         p.AddP70vector("Emissive", c.r, c.g, c.b);
-        c.r = 0.2; c.g = 0.2; c.b = 0.2;
+        c.r = 0.2f; c.g = 0.2f; c.b = 0.2f;
         m->Get(AI_MATKEY_COLOR_AMBIENT, c);
         p.AddP70vector("Ambient", c.r, c.g, c.b);
-        c.r = 0.8; c.g = 0.8; c.b = 0.8;
+        c.r = 0.8f; c.g = 0.8f; c.b = 0.8f;
         m->Get(AI_MATKEY_COLOR_DIFFUSE, c);
         p.AddP70vector("Diffuse", c.r, c.g, c.b);
         // The FBX SDK determines "Opacity" from transparency colour (RGB)
@@ -1223,29 +1223,29 @@ void FBXExporter::WriteObjects ()
         // so we should take it from AI_MATKEY_OPACITY if possible.
         // It might make more sense to use TransparencyFactor,
         // but Blender actually loads "Opacity" correctly, so let's use it.
-        f = 1.0;
+        f = 1.0f;
         if (m->Get(AI_MATKEY_COLOR_TRANSPARENT, c) == aiReturn_SUCCESS) {
-            f = 1.0 - ((c.r + c.g + c.b) / 3);
+            f = 1.0f - ((c.r + c.g + c.b) / 3.0f);
         }
         m->Get(AI_MATKEY_OPACITY, f);
         p.AddP70double("Opacity", f);
         if (phong) {
             // specular color is multiplied by shininess_strength
-            c.r = 0.2; c.g = 0.2; c.b = 0.2;
+            c.r = 0.2f; c.g = 0.2f; c.b = 0.2f;
             m->Get(AI_MATKEY_COLOR_SPECULAR, c);
-            f = 1.0;
+            f = 1.0f;
             m->Get(AI_MATKEY_SHININESS_STRENGTH, f);
             p.AddP70vector("Specular", f*c.r, f*c.g, f*c.b);
-            f = 20.0;
+            f = 20.0f;
             m->Get(AI_MATKEY_SHININESS, f);
             p.AddP70double("Shininess", f);
             // Legacy "Reflectivity" is F*F*((R+G+B)/3),
             // where F is the proportion of light reflected (AKA reflectivity),
             // and RGB is the reflective colour of the material.
             // No idea why, but we might as well set it the same way.
-            f = 0.0;
+            f = 0.0f;
             m->Get(AI_MATKEY_REFLECTIVITY, f);
-            c.r = 1.0, c.g = 1.0, c.b = 1.0;
+            c.r = 1.0f, c.g = 1.0f, c.b = 1.0f;
             m->Get(AI_MATKEY_COLOR_REFLECTIVE, c);
             p.AddP70double("Reflectivity", f*f*((c.r+c.g+c.b)/3.0));
         }
@@ -1269,7 +1269,7 @@ void FBXExporter::WriteObjects ()
             const aiTextureType textype = static_cast<aiTextureType>(tt);
             const size_t texcount = mat->GetTextureCount(textype);
             for (size_t j = 0; j < texcount; ++j) {
-                mat->GetTexture(textype, j, &texpath);
+                mat->GetTexture(textype, (unsigned int)j, &texpath);
                 const std::string texstring = texpath.C_Str();
                 auto elem = uid_by_image.find(texstring);
                 if (elem == uid_by_image.end()) {
@@ -1591,7 +1591,7 @@ void FBXExporter::WriteObjects ()
         std::vector<int32_t> vertex_indices;
         // map of vertex value to its index in the data vector
         std::map<aiVector3D,size_t> index_by_vertex_value;
-        size_t index = 0;
+        int32_t index = 0;
         for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
             aiVector3D vtx = m->mVertices[vi];
             auto elem = index_by_vertex_value.find(vtx);
@@ -1600,7 +1600,7 @@ void FBXExporter::WriteObjects ()
                 index_by_vertex_value[vtx] = index;
                 ++index;
             } else {
-                vertex_indices.push_back(elem->second);
+                vertex_indices.push_back(int32_t(elem->second));
             }
         }
 
@@ -1616,7 +1616,7 @@ void FBXExporter::WriteObjects ()
         // as it can be instanced to many nodes.
         // All we can do is assume no instancing,
         // and take the first node we find that contains the mesh.
-        aiNode* mesh_node = get_node_for_mesh(mi, mScene->mRootNode);
+        aiNode* mesh_node = get_node_for_mesh((unsigned int)mi, mScene->mRootNode);
         aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
 
         // now make a subdeformer for each bone in the skeleton
@@ -1682,7 +1682,7 @@ void FBXExporter::WriteObjects ()
 
             // this should be the same as the bone's mOffsetMatrix.
             // if it's not the same, the skeleton isn't in the bind pose.
-            const float epsilon = 1e-5; // some error is to be expected
+            const float epsilon = 1e-5f; // some error is to be expected
             bool bone_xform_okay = true;
             if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
                 not_in_bind_pose.insert(b);
@@ -2002,7 +2002,7 @@ void FBXExporter::WriteModelNodes(
             transform_chain.emplace_back(elem->first, t);
             break;
         case 'r': // rotation
-            r *= DEG;
+            r *= float(DEG);
             transform_chain.emplace_back(elem->first, r);
             break;
         case 's': // scale

+ 1 - 1
code/Importer.cpp

@@ -622,7 +622,6 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
             if (s != std::string::npos) {
                 DefaultLogger::get()->info("File extension not known, trying signature-based detection");
                 for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
-
                     if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
                         imp = pimpl->mImporter[a];
                         break;
@@ -947,6 +946,7 @@ BaseImporter* Importer::GetImporter (const char* szExtension) const
 size_t Importer::GetImporterIndex (const char* szExtension) const
 {
     ai_assert(szExtension);
+
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
     // skip over wildcard and dot characters at string head --

+ 2 - 3
code/Importer/IFC/IFCLoader.cpp

@@ -583,9 +583,8 @@ typedef std::map<std::string, std::string> Metadata;
 
 // ------------------------------------------------------------------------------------------------
 void ProcessMetadata(const Schema_2x3::ListOf< Schema_2x3::Lazy< Schema_2x3::IfcProperty >, 1, 0 >& set, ConversionData& conv, Metadata& properties,
-    const std::string& prefix = "",
-    unsigned int nest = 0)
-{
+        const std::string& prefix = "",
+        unsigned int nest = 0) {
     for(const Schema_2x3::IfcProperty& property : set) {
         const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name;
         if (const Schema_2x3::IfcPropertySingleValue* const singleValue = property.ToPtr<Schema_2x3::IfcPropertySingleValue>()) {

+ 13 - 14
code/ObjExporter.cpp

@@ -132,18 +132,18 @@ ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMt
     mOutputMat.precision(16);
 
     WriteGeometryFile(noMtl);
-    if (!noMtl)
+    if ( !noMtl ) {
         WriteMaterialFile();
+    }
 }
 
 // ------------------------------------------------------------------------------------------------
 ObjExporter::~ObjExporter() {
-
+    // empty
 }
 
 // ------------------------------------------------------------------------------------------------
-std::string ObjExporter :: GetMaterialLibName()
-{
+std::string ObjExporter::GetMaterialLibName() {
     // within the Obj file, we use just the relative file name with the path stripped
     const std::string& s = GetMaterialLibFileName();
     std::string::size_type il = s.find_last_of("/\\");
@@ -158,8 +158,9 @@ std::string ObjExporter :: GetMaterialLibName()
 std::string ObjExporter::GetMaterialLibFileName() {
     // Remove existing .obj file extension so that the final material file name will be fileName.mtl and not fileName.obj.mtl
     size_t lastdot = filename.find_last_of('.');
-    if (lastdot != std::string::npos)
-        return filename.substr(0, lastdot) + MaterialExt;
+    if ( lastdot != std::string::npos ) {
+        return filename.substr( 0, lastdot ) + MaterialExt;
+    }
 
     return filename + MaterialExt;
 }
@@ -172,8 +173,7 @@ void ObjExporter::WriteHeader(std::ostringstream& out) {
 }
 
 // ------------------------------------------------------------------------------------------------
-std::string ObjExporter::GetMaterialName(unsigned int index)
-{
+std::string ObjExporter::GetMaterialName(unsigned int index) {
     const aiMaterial* const mat = pScene->mMaterials[index];
     if ( nullptr == mat ) {
         static const std::string EmptyStr;
@@ -191,8 +191,7 @@ std::string ObjExporter::GetMaterialName(unsigned int index)
 }
 
 // ------------------------------------------------------------------------------------------------
-void ObjExporter::WriteMaterialFile()
-{
+void ObjExporter::WriteMaterialFile() {
     WriteHeader(mOutputMat);
 
     for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
@@ -310,8 +309,9 @@ void ObjExporter::WriteGeometryFile(bool noMtl) {
         if (!m.name.empty()) {
             mOutput << "g " << m.name << endl;
         }
-        if (!noMtl)
+        if ( !noMtl ) {
             mOutput << "usemtl " << m.matname << endl;
+        }
 
         for(const Face& f : m.faces) {
             mOutput << f.kind << ' ';
@@ -382,7 +382,7 @@ void ObjExporter::colIndexMap::getColors( std::vector<aiColor4D> &colors ) {
 
 // ------------------------------------------------------------------------------------------------
 void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) {
-    mMeshes.push_back(MeshInstance());
+    mMeshes.push_back(MeshInstance() );
     MeshInstance& mesh = mMeshes.back();
 
     mesh.name = std::string( name.data, name.length );
@@ -436,8 +436,7 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4
 }
 
 // ------------------------------------------------------------------------------------------------
-void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent)
-{
+void ObjExporter::AddNode(const aiNode* nd, const aiMatrix4x4& mParent) {
     const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
 
     for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {

+ 10 - 20
code/ObjFileImporter.cpp

@@ -207,30 +207,24 @@ void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene
 
     // Create the root node of the scene
     pScene->mRootNode = new aiNode;
-    if ( !pModel->m_ModelName.empty() )
-    {
+    if ( !pModel->m_ModelName.empty() ) {
         // Set the name of the scene
         pScene->mRootNode->mName.Set(pModel->m_ModelName);
-    }
-    else
-    {
+    } else {
         // This is a fatal error, so break down the application
         ai_assert(false);
     }
 
     // Create nodes for the whole scene
     std::vector<aiMesh*> MeshArray;
-    for (size_t index = 0; index < pModel->m_Objects.size(); index++)
-    {
+    for (size_t index = 0; index < pModel->m_Objects.size(); ++index ) {
         createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray);
     }
 
     // Create mesh pointer buffer for this scene
-    if (pScene->mNumMeshes > 0)
-    {
+    if (pScene->mNumMeshes > 0) {
         pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
-        for (size_t index =0; index < MeshArray.size(); index++)
-        {
+        for (size_t index =0; index < MeshArray.size(); ++index ) {
             pScene->mMeshes[ index ] = MeshArray[ index ];
         }
     }
@@ -261,8 +255,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
         appendChildToParentNode( pParent, pNode );
     }
 
-    for ( size_t i=0; i< pObject->m_Meshes.size(); i++ )
-    {
+    for ( size_t i=0; i< pObject->m_Meshes.size(); ++i ) {
         unsigned int meshId = pObject->m_Meshes[ i ];
         aiMesh *pMesh = createTopology( pModel, pObject, meshId );
         if( pMesh ) {
@@ -275,8 +268,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
     }
 
     // Create all nodes from the sub-objects stored in the current object
-    if ( !pObject->m_SubObjects.empty() )
-    {
+    if ( !pObject->m_SubObjects.empty() ) {
         size_t numChilds = pObject->m_SubObjects.size();
         pNode->mNumChildren = static_cast<unsigned int>( numChilds );
         pNode->mChildren = new aiNode*[ numChilds ];
@@ -286,16 +278,14 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
 
     // Set mesh instances into scene- and node-instances
     const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
-    if ( meshSizeDiff > 0 )
-    {
+    if ( meshSizeDiff > 0 ) {
         pNode->mMeshes = new unsigned int[ meshSizeDiff ];
         pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
         size_t index = 0;
-        for (size_t i = oldMeshSize; i < MeshArray.size(); i++)
-        {
+        for (size_t i = oldMeshSize; i < MeshArray.size(); ++i ) {
             pNode->mMeshes[ index ] = pScene->mNumMeshes;
             pScene->mNumMeshes++;
-            index++;
+            ++index;
         }
     }
 

+ 4 - 3
code/ObjFileParser.cpp

@@ -612,13 +612,14 @@ void ObjFileParser::getMaterialLib() {
         if ( '/' != *path.rbegin() ) {
           path += '/';
         }
-        absName = path + strMatName;
+        absName += path;
+        absName += strMatName;
     } else {
         absName = strMatName;
     }
-    IOStream *pFile = m_pIO->Open( absName );
 
-    if (!pFile ) {
+    IOStream *pFile = m_pIO->Open( absName );
+    if ( nullptr == pFile ) {
         DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName);
         std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl";
         DefaultLogger::get()->info("OBJ: Opening fallback material file " + strMatFallbackName);

+ 23 - 32
code/OgreParsingUtils.h

@@ -52,27 +52,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <sstream>
 #include <cctype>
 
-namespace Assimp
-{
-namespace Ogre
-{
+namespace Assimp {
+namespace Ogre {
 
 /// Returns a lower cased copy of @s.
-static inline std::string ToLower(std::string s)
+static AI_FORCE_INLINE
+std::string ToLower(std::string s)
 {
     std::transform(s.begin(), s.end(), s.begin(), ::tolower);
     return s;
 }
 
 /// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching.
-static inline bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true)
-{
-    if (s.empty() || suffix.empty())
-    {
+static AI_FORCE_INLINE
+bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true) {
+    if (s.empty() || suffix.empty()) {
         return false;
-    }
-    else if (s.length() < suffix.length())
-    {
+    } else if (s.length() < suffix.length()) {
         return false;
     }
 
@@ -82,48 +78,43 @@ static inline bool EndsWith(const std::string &s, const std::string &suffix, boo
 
     size_t len = suffix.length();
     std::string sSuffix = s.substr(s.length()-len, len);
+
     return (ASSIMP_stricmp(sSuffix, suffix) == 0);
 }
 
 // Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
 
 /// Trim from start
-static inline std::string &TrimLeft(std::string &s, bool newlines = true)
-{
-    if (!newlines)
-    {
+static AI_FORCE_INLINE
+std::string &TrimLeft(std::string &s, bool newlines = true) {
+    if (!newlines) {
         s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace<char>(c); }));
-    }
-    else
-    {
+    } else {
         s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
     }
     return s;
 }
 
 /// Trim from end
-static inline std::string &TrimRight(std::string &s, bool newlines = true)
-{
-    if (!newlines)
-    {
+static AI_FORCE_INLINE
+std::string &TrimRight(std::string &s, bool newlines = true) {
+    if (!newlines) {
         s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !Assimp::IsSpace<char>(c); }).base(),s.end());
-    }
-    else
-    {
+    } else {
         s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
     }
     return s;
 }
 
 /// Trim from both ends
-static inline std::string &Trim(std::string &s, bool newlines = true)
-{
+static AI_FORCE_INLINE
+std::string &Trim(std::string &s, bool newlines = true) {
     return TrimLeft(TrimRight(s, newlines), newlines);
 }
 
 /// Skips a line from current @ss position until a newline. Returns the skipped part.
-static inline std::string SkipLine(std::stringstream &ss)
-{
+static AI_FORCE_INLINE
+std::string SkipLine(std::stringstream &ss) {
     std::string skipped;
     getline(ss, skipped);
     return skipped;
@@ -131,8 +122,8 @@ static inline std::string SkipLine(std::stringstream &ss)
 
 /// Skips a line and reads next element from @c ss to @c nextElement.
 /** @return Skipped line content until newline. */
-static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement)
-{
+static AI_FORCE_INLINE
+std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement) {
     std::string skipped = SkipLine(ss);
     ss >> nextElement;
     return skipped;

+ 9 - 10
code/OgreXmlSerializer.cpp

@@ -213,18 +213,18 @@ std::string &OgreXmlSerializer::SkipCurrentNode()
     DefaultLogger::get()->debug("Skipping node <" + m_currentNodeName + ">");
 #endif
 
-    for(;;)
-    {
-        if (!m_reader->read())
-        {
+    for(;;) {
+        if (!m_reader->read()) {
             m_currentNodeName = "";
             return m_currentNodeName;
         }
-        if (m_reader->getNodeType() != irr::io::EXN_ELEMENT_END)
+        if ( m_reader->getNodeType() != irr::io::EXN_ELEMENT_END ) {
             continue;
-        else if (std::string(m_reader->getNodeName()) == m_currentNodeName)
+        } else if ( std::string( m_reader->getNodeName() ) == m_currentNodeName ) {
             break;
+        }
     }
+
     return NextNode();
 }
 
@@ -303,17 +303,16 @@ static const char *anZ = "z";
 
 // Mesh
 
-MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader)
-{
+MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) {
     OgreXmlSerializer serializer(reader);
 
     MeshXml *mesh = new MeshXml();
     serializer.ReadMesh(mesh);
+
     return mesh;
 }
 
-void OgreXmlSerializer::ReadMesh(MeshXml *mesh)
-{
+void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
     if (NextNode() != nnMesh) {
         throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>");
     }

+ 17 - 9
code/SceneCombiner.cpp

@@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <assimp/SceneCombiner.h>
 #include <assimp/StringUtils.h>
 #include <assimp/fast_atof.h>
+#include <assimp/metadata.h>
 #include <assimp/Hash.h>
 #include "time.h"
 #include <assimp/DefaultLogger.hpp>
@@ -806,8 +807,9 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
             for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)   {
                 if ((*it)->mNormals)    {
                     ::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
+                } else {
+                    DefaultLogger::get()->warn( "JoinMeshes: Normals expected but input mesh contains no normals" );
                 }
-                else DefaultLogger::get()->warn("JoinMeshes: Normals expected but input mesh contains no normals");
                 pv2 += (*it)->mNumVertices;
             }
         }
@@ -817,28 +819,29 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
             pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
             aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices];
 
-            for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)   {
+            for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it) {
                 if ((*it)->mTangents)   {
                     ::memcpy(pv2, (*it)->mTangents,  (*it)->mNumVertices*sizeof(aiVector3D));
                     ::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D));
+                } else {
+                    DefaultLogger::get()->warn( "JoinMeshes: Tangents expected but input mesh contains no tangents" );
                 }
-                else DefaultLogger::get()->warn("JoinMeshes: Tangents expected but input mesh contains no tangents");
                 pv2  += (*it)->mNumVertices;
                 pv2b += (*it)->mNumVertices;
             }
         }
         // copy texture coordinates
         unsigned int n = 0;
-        while ((**begin).HasTextureCoords(n))   {
+        while ((**begin).HasTextureCoords(n)) {
             out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
 
             pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
             for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)   {
-
                 if ((*it)->mTextureCoords[n])   {
                     ::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
+                } else {
+                    DefaultLogger::get()->warn( "JoinMeshes: UVs expected but input mesh contains no UVs" );
                 }
-                else DefaultLogger::get()->warn("JoinMeshes: UVs expected but input mesh contains no UVs");
                 pv2 += (*it)->mNumVertices;
             }
             ++n;
@@ -848,11 +851,11 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
         while ((**begin).HasVertexColors(n))    {
             aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
             for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)   {
-
                 if ((*it)->mColors[n])  {
                     ::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
+                } else {
+                    DefaultLogger::get()->warn( "JoinMeshes: VCs expected but input mesh contains no VCs" );
                 }
-                else DefaultLogger::get()->warn("JoinMeshes: VCs expected but input mesh contains no VCs");
                 pv2 += (*it)->mNumVertices;
             }
             ++n;
@@ -1001,7 +1004,12 @@ void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
         *_dest = new aiScene();
     }
     aiScene* dest = *_dest;
-    ai_assert(dest);
+    ai_assert(nullptr != dest);
+
+    // copy metadata
+    if ( nullptr != src->mMetaData ) {
+        dest->mMetaData = new aiMetadata( *src->mMetaData );
+    }
 
     // copy animations
     dest->mNumAnimations = src->mNumAnimations;

+ 2 - 2
code/XFileParser.cpp

@@ -1076,8 +1076,8 @@ std::string XFileParser::GetNextToken() {
                     return s;
                 }
                 len = ReadBinDWord();
-                const int bounds( mEnd - mP );
-                const int iLen( len );
+                const int bounds = int( mEnd - mP );
+                const int iLen   = int( len );
                 if ( iLen < 0 ) {
                     return s;
                 }

+ 29 - 22
doc/dox.h

@@ -667,27 +667,31 @@ need them at all.
 Normally textures used by assets are stored in separate files, however,
 there are file formats embedding their textures directly into the model file.
 Such textures are loaded into an aiTexture structure.
-For embedded textures, the value of `AI_MATKEY_TEXTURE(textureType, index)` will be `*<index>` where
-`<index>` is the index of the texture in aiScene::mTextures.
-<br>
+
+In previous versions, the path from the query for `AI_MATKEY_TEXTURE(textureType, index)` would be
+`*<index>` where `<index>` is the index of the texture in aiScene::mTextures. Now this call will
+return a file path for embedded textures in FBX files. To test if it is an embdedded texture use
+aiScene::GetEmbeddedTexture. If the returned pointer is not null, it is embedded und can be loaded
+from the data structure. If it is null, search for a separate file. Other file types still use the
+old behaviour.<br>
+If your rely on the old behaviour, you can use Assimp::Importer::SetPropertyBool with the key
+#AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING to force the old behaviour.
+
 There are two cases:
-<br>
-<b>1)</b> The texture is NOT compressed. Its color data is directly stored
-in the aiTexture structure as an array of aiTexture::mWidth * aiTexture::mHeight aiTexel structures. Each aiTexel represents a pixel (or "texel") of the texture
-image. The color data is stored in an unsigned RGBA8888 format, which can be easily used for
-both Direct3D and OpenGL (swizzling the order of the color components might be necessary).
-RGBA8888 has been chosen because it is well-known, easy to use and natively
-supported by nearly all graphics APIs.
-<br>
-<b>2)</b> This applies if aiTexture::mHeight == 0 is fulfilled. Then, texture is stored in a
-"compressed" format such as DDS or PNG. The term "compressed" does not mean that the
-texture data must actually be compressed, however the texture was found in the
-model file as if it was stored in a separate file on the harddisk. Appropriate
-decoders (such as libjpeg, libpng, D3DX, DevIL) are required to load theses textures.
-aiTexture::mWidth specifies the size of the texture data in bytes, aiTexture::pcData is
-a pointer to the raw image data and aiTexture::achFormatHint is either zeroed or
-contains the most common file extension of the embedded texture's format. This value is only
-set if assimp is able to determine the file format.
+1. The texture is NOT compressed. Its color data is directly stored in the aiTexture structure as an
+   array of aiTexture::mWidth * aiTexture::mHeight aiTexel structures. Each aiTexel represents a
+   pixel (or "texel") of the texture image. The color data is stored in an unsigned RGBA8888 format,
+   which can be easily used for both Direct3D and OpenGL (swizzling the order of the color
+   components might be necessary).  RGBA8888 has been chosen because it is well-known, easy to use
+   and natively supported by nearly all graphics APIs.
+2. This applies if aiTexture::mHeight == 0 is fulfilled. Then, texture is stored in a "compressed"
+   format such as DDS or PNG. The term "compressed" does not mean that the texture data must
+   actually be compressed, however the texture was found in the model file as if it was stored in a
+   separate file on the harddisk. Appropriate decoders (such as libjpeg, libpng, D3DX, DevIL) are
+   required to load theses textures.  aiTexture::mWidth specifies the size of the texture data in
+   bytes, aiTexture::pcData is a pointer to the raw image data and aiTexture::achFormatHint is
+   either zeroed or contains the most common file extension of the embedded texture's format. This
+   value is only set if assimp is able to determine the file format.
 */
 
 
@@ -871,8 +875,11 @@ All material key constants start with 'AI_MATKEY' (it's an ugly macro for histor
     <td><tt>TEXTURE(t,n)</tt></td>
     <td>aiString</td>
     <td>n/a</td>
-    <td>Defines the path of the n'th texture on the stack 't', where 'n' is any value >= 0 and 't' is one of the #aiTextureType enumerated values. Either a filepath or `*<index>`, where `<index>` is the index of an embedded texture in aiScene::mTextures.</td>
-    <td>See the 'Textures' section above.</td>
+    <td>Defines the path of the n'th texture on the stack 't', where 'n' is any value >= 0 and 't'
+    is one of the #aiTextureType enumerated values. A file path to an external file or an embedded
+    texture. Use aiScene::GetEmbeddedTexture to test if it is embedded for FBX files, in other cases
+    embedded textures start with '*' followed by an index into aiScene::mTextures.</td>
+    <td>See the @ref mat_tex section above. Also see @ref textures for a more information about texture retrieval.</td>
   </tr>
 
   <tr>

+ 0 - 4
include/assimp/DefaultLogger.hpp

@@ -131,9 +131,7 @@ public:
     bool detatchStream(LogStream *pStream,
         unsigned int severity);
 
-
 private:
-
     // ----------------------------------------------------------------------
     /** @briefPrivate construction for internal use by create().
      *  @param severity Logging granularity  */
@@ -143,8 +141,6 @@ private:
     /** @briefDestructor    */
     ~DefaultLogger();
 
-private:
-
     /** @brief  Logs debug infos, only been written when severity level VERBOSE is set */
     void OnDebug(const char* message);
 

+ 30 - 23
include/assimp/ParsingUtils.h

@@ -115,8 +115,8 @@ bool IsSpaceOrNewLine( char_t in) {
 
 // ---------------------------------------------------------------------------------
 template <class char_t>
-AI_FORCE_INLINE bool SkipSpaces( const char_t* in, const char_t** out)
-{
+AI_FORCE_INLINE
+bool SkipSpaces( const char_t* in, const char_t** out) {
     while( *in == ( char_t )' ' || *in == ( char_t )'\t' ) {
         ++in;
     }
@@ -126,15 +126,15 @@ AI_FORCE_INLINE bool SkipSpaces( const char_t* in, const char_t** out)
 
 // ---------------------------------------------------------------------------------
 template <class char_t>
-AI_FORCE_INLINE bool SkipSpaces( const char_t** inout)
-{
+AI_FORCE_INLINE
+bool SkipSpaces( const char_t** inout) {
     return SkipSpaces<char_t>(*inout,inout);
 }
 
 // ---------------------------------------------------------------------------------
 template <class char_t>
-AI_FORCE_INLINE bool SkipLine( const char_t* in, const char_t** out)
-{
+AI_FORCE_INLINE
+bool SkipLine( const char_t* in, const char_t** out) {
     while( *in != ( char_t )'\r' && *in != ( char_t )'\n' && *in != ( char_t )'\0' ) {
         ++in;
     }
@@ -149,15 +149,15 @@ AI_FORCE_INLINE bool SkipLine( const char_t* in, const char_t** out)
 
 // ---------------------------------------------------------------------------------
 template <class char_t>
-AI_FORCE_INLINE bool SkipLine( const char_t** inout)
-{
+AI_FORCE_INLINE
+bool SkipLine( const char_t** inout) {
     return SkipLine<char_t>(*inout,inout);
 }
 
 // ---------------------------------------------------------------------------------
 template <class char_t>
-AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out)
-{
+AI_FORCE_INLINE
+bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out) {
     while( *in == ( char_t )' ' || *in == ( char_t )'\t' || *in == ( char_t )'\r' || *in == ( char_t )'\n' ) {
         ++in;
     }
@@ -167,15 +167,15 @@ AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out)
 
 // ---------------------------------------------------------------------------------
 template <class char_t>
-AI_FORCE_INLINE bool SkipSpacesAndLineEnd( const char_t** inout)
-{
+AI_FORCE_INLINE
+bool SkipSpacesAndLineEnd( const char_t** inout) {
     return SkipSpacesAndLineEnd<char_t>(*inout,inout);
 }
 
 // ---------------------------------------------------------------------------------
 template <class char_t>
-AI_FORCE_INLINE bool GetNextLine( const char_t*& buffer, char_t out[ BufferSize ] )
-{
+AI_FORCE_INLINE
+bool GetNextLine( const char_t*& buffer, char_t out[ BufferSize ] ) {
     if( ( char_t )'\0' == *buffer ) {
         return false;
     }
@@ -203,7 +203,8 @@ AI_FORCE_INLINE bool IsNumeric( char_t in)
 
 // ---------------------------------------------------------------------------------
 template <class char_t>
-AI_FORCE_INLINE bool TokenMatch(char_t*& in, const char* token, unsigned int len)
+AI_FORCE_INLINE
+bool TokenMatch(char_t*& in, const char* token, unsigned int len)
 {
     if (!::strncmp(token,in,len) && IsSpaceOrNewLine(in[len])) {
         if (in[len] != '\0') {
@@ -223,26 +224,32 @@ AI_FORCE_INLINE bool TokenMatch(char_t*& in, const char* token, unsigned int len
  *  @param token Token to check for
  *  @param len Number of characters to check
  */
-AI_FORCE_INLINE bool TokenMatchI(const char*& in, const char* token, unsigned int len)
-{
+AI_FORCE_INLINE
+bool TokenMatchI(const char*& in, const char* token, unsigned int len) {
     if (!ASSIMP_strincmp(token,in,len) && IsSpaceOrNewLine(in[len])) {
         in += len+1;
         return true;
     }
     return false;
 }
+
 // ---------------------------------------------------------------------------------
-AI_FORCE_INLINE void SkipToken(const char*& in)
-{
+AI_FORCE_INLINE
+void SkipToken(const char*& in) {
     SkipSpaces(&in);
-    while (!IsSpaceOrNewLine(*in))++in;
+    while ( !IsSpaceOrNewLine( *in ) ) {
+        ++in;
+    }
 }
+
 // ---------------------------------------------------------------------------------
-AI_FORCE_INLINE std::string GetNextToken(const char*& in)
-{
+AI_FORCE_INLINE
+std::string GetNextToken(const char*& in) {
     SkipSpacesAndLineEnd(&in);
     const char* cur = in;
-    while (!IsSpaceOrNewLine(*in))++in;
+    while ( !IsSpaceOrNewLine( *in ) ) {
+        ++in;
+    }
     return std::string(cur,(size_t)(in-cur));
 }
 

+ 2 - 2
include/assimp/StreamWriter.h

@@ -104,7 +104,7 @@ public:
 
     // ---------------------------------------------------------------------
     ~StreamWriter() {
-        stream->Write(&buffer[0], 1, buffer.size());
+        stream->Write(buffer.data(), 1, buffer.size());
         stream->Flush();
     }
 
@@ -114,7 +114,7 @@ public:
     /** Flush the contents of the internal buffer, and the output IOStream */
     void Flush()
     {
-        stream->Write(&buffer[0], 1, buffer.size());
+        stream->Write(buffer.data(), 1, buffer.size());
         stream->Flush();
         buffer.clear();
         cursor = 0;

+ 24 - 17
include/assimp/StringComparison.h

@@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #define INCLUDED_AI_STRING_WORKERS_H
 
 #include <assimp/ai_assert.h>
+#include <assimp/defs.h>
 #include "StringComparison.h"
 
 #include <string.h>
@@ -72,8 +73,8 @@ namespace Assimp    {
  * @param number Number to be written
  * @return Length of the output string, excluding the '\0'
  */
-inline unsigned int ASSIMP_itoa10( char* out, unsigned int max, int32_t number)
-{
+AI_FORCE_INLINE
+unsigned int ASSIMP_itoa10( char* out, unsigned int max, int32_t number) {
     ai_assert(NULL != out);
 
     // write the unary minus to indicate we have a negative number
@@ -91,7 +92,7 @@ inline unsigned int ASSIMP_itoa10( char* out, unsigned int max, int32_t number)
 
         const unsigned int digit = number / cur;
         if (mustPrint || digit > 0 || 1 == cur) {
-            // print all future zeroes from now
+            // print all future zeroe's from now
             mustPrint = true;
 
             *out++ = '0'+static_cast<char>(digit);
@@ -116,8 +117,8 @@ inline unsigned int ASSIMP_itoa10( char* out, unsigned int max, int32_t number)
  *  size of the array automatically.
  */
 template <size_t length>
-inline unsigned int ASSIMP_itoa10( char(& out)[length], int32_t number)
-{
+AI_FORCE_INLINE
+unsigned int ASSIMP_itoa10( char(& out)[length], int32_t number) {
     return ASSIMP_itoa10(out,length,number);
 }
 
@@ -132,9 +133,10 @@ inline unsigned int ASSIMP_itoa10( char(& out)[length], int32_t number)
  *  @param s2 Second input string
  *  @return 0 if the given strings are identical
  */
-inline int ASSIMP_stricmp(const char *s1, const char *s2)
-{
-    ai_assert(NULL != s1 && NULL != s2);
+AI_FORCE_INLINE
+int ASSIMP_stricmp(const char *s1, const char *s2) {
+    ai_assert( NULL != s1 );
+    ai_assert( NULL != s2 );
 
 #if (defined _MSC_VER)
 
@@ -161,8 +163,8 @@ inline int ASSIMP_stricmp(const char *s1, const char *s2)
  *  @param b Second string
  *  @return 0 if a == b
  */
-inline int ASSIMP_stricmp(const std::string& a, const std::string& b)
-{
+AI_FORCE_INLINE
+int ASSIMP_stricmp(const std::string& a, const std::string& b) {
     int i = (int)b.length()-(int)a.length();
     return (i ? i : ASSIMP_stricmp(a.c_str(),b.c_str()));
 }
@@ -179,10 +181,13 @@ inline int ASSIMP_stricmp(const std::string& a, const std::string& b)
  *  @param n Macimum number of characters to compare
  *  @return 0 if the given strings are identical
  */
-inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n)
-{
-    ai_assert(NULL != s1 && NULL != s2);
-    if (!n)return 0;
+AI_FORCE_INLINE
+int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n) {
+    ai_assert( NULL != s1 );
+    ai_assert( NULL != s2 );
+    if ( !n ) {
+        return 0;
+    }
 
 #if (defined _MSC_VER)
 
@@ -213,14 +218,16 @@ inline int ASSIMP_strincmp(const char *s1, const char *s2, unsigned int n)
  *
  * todo: move somewhere where it fits better in than here
  */
-inline unsigned int integer_pow (unsigned int base, unsigned int power)
-{
+AI_FORCE_INLINE
+unsigned int integer_pow( unsigned int base, unsigned int power ) {
     unsigned int res = 1;
-    for (unsigned int i = 0; i < power;++i)
+    for ( unsigned int i = 0; i < power; ++i ) {
         res *= base;
+    }
 
     return res;
 }
+
 } // end of namespace
 
 #endif // !  AI_STRINGCOMPARISON_H_INC

+ 7 - 5
include/assimp/StringUtils.h

@@ -42,6 +42,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef INCLUDED_AI_STRINGUTILS_H
 #define INCLUDED_AI_STRINGUTILS_H
 
+#include <assimp/defs.h>
+
 #include <sstream>
 #include <stdarg.h>
 #include <cstdlib>
@@ -55,7 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ///	@return	The number of written characters if the buffer size was big enough. If an encoding error occurs, a negative number is returned.
 #if defined(_MSC_VER) && _MSC_VER < 1900
 
-	inline
+    AI_FORCE_INLINE
     int c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
 		int count(-1);
 		if (0 != size) {
@@ -68,7 +70,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 		return count;
 	}
 
-	inline
+    AI_FORCE_INLINE
     int ai_snprintf(char *outBuf, size_t size, const char *format, ...) {
 		int count;
 		va_list ap;
@@ -89,7 +91,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ///	@param	value   The value to write into the std::string.
 ///	@return	The value as a std::string
 template <typename T>
-inline
+AI_FORCE_INLINE
 std::string to_string( T value ) {
     std::ostringstream os;
     os << value;
@@ -102,7 +104,7 @@ std::string to_string( T value ) {
 ///	@param	begin   The first character of the string.
 /// @param  end     The last character
 ///	@return	The float value, 0.0f in cas of an error.
-inline
+AI_FORCE_INLINE
 float ai_strtof( const char *begin, const char *end ) {
     if ( nullptr == begin ) {
         return 0.0f;
@@ -124,7 +126,7 @@ float ai_strtof( const char *begin, const char *end ) {
 ///	@param	toConvert   Value to convert
 ///	@return	The hexadecimal string, is empty in case of an error.
 template<class T>
-inline
+AI_FORCE_INLINE
 std::string DecimalToHexa( T toConvert ) {
     std::string result;
     std::stringstream ss;

+ 81 - 17
include/assimp/metadata.h

@@ -67,6 +67,7 @@ typedef enum aiMetadataType {
     AI_DOUBLE     = 4,
     AI_AISTRING   = 5,
     AI_AIVECTOR3D = 6,
+    AI_META_MAX   = 7,
 
 #ifndef SWIG
     FORCE_32BIT = INT_MAX
@@ -130,42 +131,103 @@ struct aiMetadata {
      */
     aiMetadata()
     : mNumProperties(0)
-    , mKeys(NULL)
-    , mValues(NULL) {
+    , mKeys(nullptr)
+    , mValues(nullptr) {
         // empty
     }
 
+    aiMetadata( const aiMetadata &rhs )
+    : mNumProperties( rhs.mNumProperties )
+    , mKeys( nullptr )
+    , mValues( nullptr ) {
+        mKeys = new aiString[ mNumProperties ];
+        for ( unsigned int i = 0; i < mNumProperties; ++i ) {
+            mKeys[ i ] = rhs.mKeys[ i ];
+        }
+        mValues = new aiMetadataEntry[ mNumProperties ];
+        for ( unsigned int i = 0; i < mNumProperties; ++i ) {
+            mValues[ i ].mType = rhs.mValues[ i ].mType;
+            switch ( rhs.mValues[ i ].mType ) {
+            case AI_BOOL:
+                mValues[ i ].mData = new bool( rhs.mValues[i].mData );
+                break;
+            case AI_INT32: {
+                int32_t v;
+                ::memcpy( &v, rhs.mValues[ i ].mData, sizeof( int32_t ) );
+                mValues[ i ].mData = new int32_t( v );
+                }
+                break;
+            case AI_UINT64: {
+                    uint64_t v;
+                    ::memcpy( &v, rhs.mValues[ i ].mData, sizeof( uint64_t ) );
+                    mValues[ i ].mData = new  uint64_t( v );
+                }
+                break;
+            case AI_FLOAT: {
+                    float v;
+                    ::memcpy( &v, rhs.mValues[ i ].mData, sizeof( float ) );
+                    mValues[ i ].mData = new float( v );
+                }
+                break;
+            case AI_DOUBLE: {
+                    double v;
+                    ::memcpy( &v, rhs.mValues[ i ].mData, sizeof( double ) );
+                    mValues[ i ].mData = new double( v );
+                }
+                break;
+            case AI_AISTRING: {
+                    aiString v;
+                    rhs.Get<aiString>( mKeys[ i ], v );
+                    mValues[ i ].mData = new aiString( v );
+                }
+                break;
+            case AI_AIVECTOR3D: {
+                    aiVector3D v;
+                    rhs.Get<aiVector3D>( mKeys[ i ], v );
+                    mValues[ i ].mData = new aiVector3D( v );
+                }
+                break;
+#ifndef SWIG
+            case FORCE_32BIT:
+#endif
+            default:
+                break;
+            }
+
+        }
+    }
+
     /** 
      *  @brief The destructor.
      */
     ~aiMetadata() {
         delete [] mKeys;
-        mKeys = NULL;
+        mKeys = nullptr;
         if (mValues) {
             // Delete each metadata entry
             for (unsigned i=0; i<mNumProperties; ++i) {
                 void* data = mValues[i].mData;
                 switch (mValues[i].mType) {
                 case AI_BOOL:
-                    delete static_cast<bool*>(data);
+                    delete static_cast< bool* >( data );
                     break;
                 case AI_INT32:
-                    delete static_cast<int32_t*>(data);
+                    delete static_cast< int32_t* >( data );
                     break;
                 case AI_UINT64:
-                    delete static_cast<uint64_t*>(data);
+                    delete static_cast< uint64_t* >( data );
                     break;
                 case AI_FLOAT:
-                    delete static_cast<float*>(data);
+                    delete static_cast< float* >( data );
                     break;
                 case AI_DOUBLE:
-                    delete static_cast<double*>(data);
+                    delete static_cast< double* >( data );
                     break;
                 case AI_AISTRING:
-                    delete static_cast<aiString*>(data);
+                    delete static_cast< aiString* >( data );
                     break;
                 case AI_AIVECTOR3D:
-                    delete static_cast<aiVector3D*>(data);
+                    delete static_cast< aiVector3D* >( data );
                     break;
 #ifndef SWIG
                 case FORCE_32BIT:
@@ -177,7 +239,7 @@ struct aiMetadata {
 
             // Delete the metadata array
             delete [] mValues;
-            mValues = NULL;
+            mValues = nullptr;
         }
     }
 
@@ -208,8 +270,8 @@ struct aiMetadata {
     }
 
 	template<typename T>
-	inline void Add(const std::string& key, const T& value)
-	{
+	inline
+    void Add(const std::string& key, const T& value) {
 		aiString* new_keys = new aiString[mNumProperties + 1];
 		aiMetadataEntry* new_values = new aiMetadataEntry[mNumProperties + 1];
 
@@ -256,7 +318,7 @@ struct aiMetadata {
 
     template<typename T>
     inline 
-    bool Get( unsigned index, T& value ) {
+    bool Get( unsigned index, T& value ) const {
         // In range assertion
         if ( index >= mNumProperties ) {
             return false;
@@ -277,7 +339,7 @@ struct aiMetadata {
 
     template<typename T>
     inline 
-    bool Get( const aiString& key, T& value ) {
+    bool Get( const aiString& key, T& value ) const {
         // Search for the given key
         for ( unsigned int i = 0; i < mNumProperties; ++i ) {
             if ( mKeys[ i ] == key ) {
@@ -288,7 +350,8 @@ struct aiMetadata {
     }
 
     template<typename T>
-    inline bool Get( const std::string& key, T& value ) {
+    inline
+    bool Get( const std::string& key, T& value ) const {
         return Get(aiString(key), value);
     }
 
@@ -297,7 +360,8 @@ struct aiMetadata {
 	/// \param [out] pKey - pointer to the key value.
 	/// \param [out] pEntry - pointer to the entry: type and value.
 	/// \return false - if pIndex is out of range, else - true.
-	inline bool Get(size_t index, const aiString*& key, const aiMetadataEntry*& entry) {
+	inline
+    bool Get(size_t index, const aiString*& key, const aiMetadataEntry*& entry) const {
         if ( index >= mNumProperties ) {
             return false;
         }

+ 71 - 0
test/unit/utMetadata.cpp

@@ -181,3 +181,74 @@ TEST_F( utMetadata, get_set_aiVector3D_Test ) {
     EXPECT_TRUE( success );
 }
 
+TEST_F( utMetadata, copy_test ) {
+    m_data = aiMetadata::Alloc( AI_META_MAX );
+    bool bv = true;
+    m_data->Set( 0, "bool", bv );
+    int32_t i32v = -10;
+    m_data->Set( 1, "int32", i32v );
+    uint64_t ui64v = static_cast<uint64_t>( 10 );
+    m_data->Set( 2, "uint64", ui64v );
+    float fv = 1.0f;
+    m_data->Set( 3, "float", fv );
+    double dv = 2.0;
+    m_data->Set( 4, "double", dv );
+    const aiString strVal( std::string( "test" ) );
+    m_data->Set( 5, "aiString", strVal );
+    aiVector3D vecVal( 1, 2, 3 );
+    m_data->Set( 6, "aiVector3D", vecVal );
+
+    aiMetadata copy( *m_data );
+    EXPECT_EQ( 7, copy.mNumProperties );
+
+    // bool test
+    {
+        bool v;
+        EXPECT_TRUE( copy.Get( "bool", v ) );
+        EXPECT_EQ( bv, v );
+    }
+
+    // int32_t test
+    {
+        int32_t v;
+        bool ok = copy.Get( "int32", v );
+        EXPECT_TRUE( ok );
+        EXPECT_EQ( i32v, v );
+    }
+
+    // uint64_t test
+    {
+        uint64_t v;
+        bool ok = copy.Get( "uint64", v );
+        EXPECT_TRUE( ok );
+        EXPECT_EQ( ui64v, v );
+    }
+
+    // float test
+    {
+        float v;
+        EXPECT_TRUE( copy.Get( "float", v ) );
+        EXPECT_EQ( fv, v );
+    }
+
+    // double test
+    {
+        double v;
+        EXPECT_TRUE( copy.Get( "double", v ) );
+        EXPECT_EQ( dv, v );
+    }
+
+    // bool test
+    {
+        aiString v;
+        EXPECT_TRUE( copy.Get( "aiString", v ) );
+        EXPECT_EQ( strVal, v );
+    }
+
+    // bool test
+    {
+        aiVector3D v;
+        EXPECT_TRUE( copy.Get( "aiVector3D", v ) );
+        EXPECT_EQ( vecVal, v );
+    }
+}