Browse Source

Merge branch 'master' into patch-1

JeffH-BMG 7 years ago
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 ####
 #### Supported file formats ####
 
 
-A full list [is here](http://assimp.org/main_features_formats.html).
 __Importers__:
 __Importers__:
+
 - 3D
 - 3D
 - 3DS
 - 3DS
 - 3MF
 - 3MF
@@ -109,6 +109,8 @@ __Exporters__:
 - STEP
 - STEP
 - glTF 1.0 (partial)
 - glTF 1.0 (partial)
 - glTF 2.0 (partial)
 - glTF 2.0 (partial)
+- 3MF ( experimental )
+- FBX ( experimental )
 
 
 ### Building ###
 ### 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.
 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 );
     unsigned int idx( NotSet );
     for (unsigned int i = 0; i < mScene->mMaterials.size();++i)
     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 ) {
         for ( std::string::iterator it = s.begin(); it != s.end(); ++it ) {
             *it = static_cast< char >( ::tolower( *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;
 	TextureConverted_Index = 0;
 	for(const SPP_Texture& tex_convd: mTexture_Converted)
 	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)
                 // at the file extension (ASE, ASK, ASC)
                 // *************************************************************
                 // *************************************************************
 
 
-                if (fmt)iFileFormat = fmt;
+                if ( fmt ) {
+                    iFileFormat = fmt;
+                }
                 continue;
                 continue;
             }
             }
             // main scene information
             // main scene information
@@ -427,28 +429,25 @@ void Parser::ParseLV1SoftSkinBlock()
                         // Reserve enough storage
                         // Reserve enough storage
                         vert.mBoneWeights.reserve(numWeights);
                         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");
                             ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
 
 
                             // Find the bone in the mesh's list
                             // Find the bone in the mesh's list
                             std::pair<int,ai_real> me;
                             std::pair<int,ai_real> me;
                             me.first = -1;
                             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;
                                     me.first = n;
                                     break;
                                     break;
                                 }
                                 }
                             }
                             }
-                            if (-1 == me.first)
-                            {
+                            if (-1 == me.first) {
                                 // We don't have this bone yet, so add it to the list
                                 // 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 );
                             ParseLV4MeshFloat( me.second );
 
 
@@ -745,6 +744,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
     // empty the texture won't be used later.
     // empty the texture won't be used later.
     // ***********************************************************
     // ***********************************************************
     bool parsePath = true;
     bool parsePath = true;
+    std::string temp;
     while (true)
     while (true)
     {
     {
         if ('*' == *filePtr)
         if ('*' == *filePtr)
@@ -753,7 +753,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
             // type of map
             // type of map
             if (TokenMatch(filePtr,"MAP_CLASS" ,9))
             if (TokenMatch(filePtr,"MAP_CLASS" ,9))
             {
             {
-                std::string temp;
+                temp.clear();
                 if(!ParseString(temp,"*MAP_CLASS"))
                 if(!ParseString(temp,"*MAP_CLASS"))
                     SkipToNextToken();
                     SkipToNextToken();
                 if (temp != "Bitmap" && temp != "Normal Bump")
                 if (temp != "Bitmap" && temp != "Normal Bump")

+ 14 - 13
code/BVHLoader.cpp

@@ -199,6 +199,7 @@ aiNode* BVHLoader::ReadNode()
     Node& internNode = mNodes.back();
     Node& internNode = mNodes.back();
 
 
     // now read the node's contents
     // now read the node's contents
+    std::string siteToken;
     while( 1)
     while( 1)
     {
     {
         std::string token = GetNextToken();
         std::string token = GetNextToken();
@@ -218,7 +219,8 @@ aiNode* BVHLoader::ReadNode()
         else if( token == "End")
         else if( token == "End")
         {
         {
             // The real symbol is "End Site". Second part comes in a separate token
             // The real symbol is "End Site". Second part comes in a separate token
-            std::string siteToken = GetNextToken();
+            siteToken.clear();
+            siteToken = GetNextToken();
             if( siteToken != "Site")
             if( siteToken != "Site")
                 ThrowException( format() << "Expected \"End Site\" keyword, but found \"" << token << " " << siteToken << "\"." );
                 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);
     aiNode* node = new aiNode( "EndSite_" + pParentName);
 
 
     // now read the node's contents. Only possible entry is "OFFSET"
     // 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
         // end node's offset
-        if( token == "OFFSET")
-        {
+        if( token == "OFFSET") {
             ReadNodeOffset( node);
             ReadNodeOffset( node);
-        }
-        else if( token == "}")
-        {
+        } else if( token == "}") {
             // we're done with the end node
             // we're done with the end node
             break;
             break;
-        } else
-        {
+        } else {
             // everything else is a parse error
             // everything else is a parse error
             ThrowException( format() << "Unknown keyword \"" << token << "\"." );
             ThrowException( format() << "Unknown keyword \"" << token << "\"." );
         }
         }
@@ -296,8 +295,10 @@ void BVHLoader::ReadNodeOffset( aiNode* pNode)
     offset.z = GetNextTokenAsFloat();
     offset.z = GetNextTokenAsFloat();
 
 
     // build a transformation matrix from it
     // 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,
 /* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile,
     const void* _magic, unsigned int num, unsigned int offset, unsigned int size)
     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) {
     if (!pIOHandler) {
         return false;
         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;
 	mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr;
 	PushTag();
 	PushTag();
-	
+
+    std::string node_idstr;
 	for (size_t a = 0; a < anim->mNumChannels; ++a) {
 	for (size_t a = 0; a < anim->mNumChannels; ++a) {
 		const aiNodeAnim * nodeAnim = anim->mChannels[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;
 		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;
 			std::vector<ai_real> frames;
 			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
 			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;
 			std::vector<ai_real> keyframes;
 			keyframes.reserve(nodeAnim->mNumPositionKeys * 16);
 			keyframes.reserve(nodeAnim->mNumPositionKeys * 16);
 			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
 			for( size_t i = 0; i < nodeAnim->mNumPositionKeys; ++i) {
-				
 				aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue;
 				aiVector3D Scaling = nodeAnim->mScalingKeys[i].mValue;
 				aiMatrix4x4 ScalingM;  // identity
 				aiMatrix4x4 ScalingM;  // identity
 				ScalingM[0][0] = Scaling.x; ScalingM[1][1] = Scaling.y; ScalingM[2][2] = Scaling.z;
 				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();
 			PopTag();
 			mOutput << startstr << "</source>" << endstr;
 			mOutput << startstr << "</source>" << endstr;
 		}
 		}
-		
 	}
 	}
 	
 	
 	for (size_t a = 0; a < anim->mNumChannels; ++a) {
 	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;
             continue;
 
 
         // now check all channels if they affect the current node
         // 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();
         for( std::vector<Collada::AnimationChannel>::const_iterator cit = pSrcAnim->mChannels.begin();
             cit != pSrcAnim->mChannels.end(); ++cit)
             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)
             if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos)
                 continue;
                 continue;
-            std::string targetID = srcChannel.mTarget.substr( 0, slashPos);
+
+            targetID.clear();
+            targetID = srcChannel.mTarget.substr( 0, slashPos);
             if( targetID != srcNode->mID)
             if( targetID != srcNode->mID)
                 continue;
                 continue;
 
 
@@ -1160,7 +1163,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
 
 
                 entry.mTransformId = srcChannel.mTarget.substr( slashPos+1, dotPos - slashPos - 1);
                 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")
                 if( subElement == "ANGLE")
                     entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle
                     entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle
                 else if( subElement == "X")
                 else if( subElement == "X")
@@ -1181,7 +1185,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
             if (bracketPos != std::string::npos)
             if (bracketPos != std::string::npos)
             {
             {
                 entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, bracketPos - slashPos - 1);
                 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)")
                 if (subElement == "(0)(0)")
                     entry.mSubElement = 0;
                     entry.mSubElement = 0;
@@ -1215,7 +1220,6 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
                     entry.mSubElement = 14;
                     entry.mSubElement = 14;
                 else if (subElement == "(3)(3)")
                 else if (subElement == "(3)(3)")
                     entry.mSubElement = 15;
                     entry.mSubElement = 15;
-
             }
             }
 
 
             // determine which transform step is affected by this channel
             // 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 ) {
     if ( nullptr == m_zipArchive ) {
         return false;
         return false;
     }
     }
+
     ok |= exportContentTypes();
     ok |= exportContentTypes();
     ok |= export3DModel();
     ok |= export3DModel();
     ok |= exportRelations();
     ok |= exportRelations();
@@ -181,6 +182,8 @@ bool D3MFExporter::export3DModel() {
     mModelOutput << "<" << XmlTag::resources << ">";
     mModelOutput << "<" << XmlTag::resources << ">";
     mModelOutput << std::endl;
     mModelOutput << std::endl;
 
 
+    writeMetaData();
+
     writeBaseMaterials();
     writeBaseMaterials();
 
 
     writeObjects();
     writeObjects();
@@ -209,22 +212,45 @@ void D3MFExporter::writeHeader() {
     mModelOutput << std::endl;
     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() {
 void D3MFExporter::writeBaseMaterials() {
     mModelOutput << "<basematerials id=\"1\">\n";
     mModelOutput << "<basematerials id=\"1\">\n";
+    std::string strName, hexDiffuseColor , tmp;
     for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
     for ( size_t i = 0; i < mScene->mNumMaterials; ++i ) {
         aiMaterial *mat = mScene->mMaterials[ i ];
         aiMaterial *mat = mScene->mMaterials[ i ];
-        std::string strName;
         aiString name;
         aiString name;
         if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
         if ( mat->Get( AI_MATKEY_NAME, name ) != aiReturn_SUCCESS ) {
             strName = "basemat_" + to_string( i );
             strName = "basemat_" + to_string( i );
         } else {
         } else {
             strName = name.C_Str();
             strName = name.C_Str();
         }
         }
-        std::string hexDiffuseColor;
         aiColor4D color;
         aiColor4D color;
         if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
         if ( mat->Get( AI_MATKEY_COLOR_DIFFUSE, color ) == aiReturn_SUCCESS ) {
+            hexDiffuseColor.clear();
+            tmp.clear();
             hexDiffuseColor = "#";
             hexDiffuseColor = "#";
-            std::string tmp;
             
             
             tmp = DecimalToHexa( color.r );
             tmp = DecimalToHexa( color.r );
             hexDiffuseColor += tmp;
             hexDiffuseColor += tmp;

+ 1 - 0
code/D3MFExporter.h

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

+ 39 - 5
code/D3MFImporter.cpp

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

+ 2 - 2
code/D3MFOpcPackage.cpp

@@ -288,8 +288,8 @@ bool D3MFZipArchive::Exists(const char* pFile) const {
         return false;
         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 );
     bool exist( false );
     if(it != m_ArchiveMap.end()) {
     if(it != m_ArchiveMap.end()) {
         exist = true;
         exist = true;

+ 0 - 1
code/DXFHelper.h

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

+ 3 - 3
code/DefaultIOSystem.cpp

@@ -76,7 +76,7 @@ bool DefaultIOSystem::Exists( const char* pFile) const
 #ifdef _WIN32
 #ifdef _WIN32
     wchar_t fileName16[PATHLIMIT];
     wchar_t fileName16[PATHLIMIT];
 
 
-    bool isUnicode = IsTextUnicode(pFile, strlen(pFile), NULL);
+    bool isUnicode = IsTextUnicode(pFile, static_cast<int>(strlen(pFile)), NULL);
     if (isUnicode) {
     if (isUnicode) {
 
 
         MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
         MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
@@ -110,7 +110,7 @@ IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode)
     FILE* file;
     FILE* file;
 #ifdef _WIN32
 #ifdef _WIN32
     wchar_t fileName16[PATHLIMIT];
     wchar_t fileName16[PATHLIMIT];
-    bool isUnicode = IsTextUnicode(strFile, strlen(strFile), NULL );
+    bool isUnicode = IsTextUnicode(strFile, static_cast<int>(strlen(strFile)), NULL );
     if (isUnicode) {
     if (isUnicode) {
         MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT);
         MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT);
         std::string mode8(strMode);
         std::string mode8(strMode);
@@ -158,7 +158,7 @@ inline static void MakeAbsolutePath (const char* in, char* _out)
 {
 {
     ai_assert(in && _out);
     ai_assert(in && _out);
 #if defined( _MSC_VER ) || defined( __MINGW32__ )
 #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) {
     if (isUnicode) {
         wchar_t out16[PATHLIMIT];
         wchar_t out16[PATHLIMIT];
         wchar_t in16[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)
  *  @brief Implementation of DefaultLogger (and Logger)
  */
  */
 
 
-
 // Default log streams
 // Default log streams
 #include "Win32DebugLogStream.h"
 #include "Win32DebugLogStream.h"
 #include "StdOStreamLogStream.h"
 #include "StdOStreamLogStream.h"
@@ -62,8 +61,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_SINGLETHREADED
 #ifndef ASSIMP_BUILD_SINGLETHREADED
 #   include <thread>
 #   include <thread>
 #   include <mutex>
 #   include <mutex>
-
-std::mutex loggerMutex;
+    std::mutex loggerMutex;
 #endif
 #endif
 
 
 namespace Assimp    {
 namespace Assimp    {
@@ -76,22 +74,19 @@ static const unsigned int SeverityAll = Logger::Info | Logger::Err | Logger::War
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 // Represents a log-stream + its error severity
 // 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
     // Constructor
     LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
     LogStreamInfo( unsigned int uiErrorSev, LogStream *pStream ) :
         m_uiErrorSeverity( uiErrorSev ),
         m_uiErrorSeverity( uiErrorSev ),
-        m_pStream( pStream )
-    {
+        m_pStream( pStream ) {
         // empty
         // empty
     }
     }
 
 
     // Destructor
     // Destructor
-    ~LogStreamInfo()
-    {
+    ~LogStreamInfo() {
         delete m_pStream;
         delete m_pStream;
     }
     }
 };
 };
@@ -109,7 +104,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream    streams,
 #ifdef WIN32
 #ifdef WIN32
         return new Win32DebugLogStream();
         return new Win32DebugLogStream();
 #else
 #else
-        return NULL;
+        return nullptr;
 #endif
 #endif
 
 
         // Platform-independent default streams
         // Platform-independent default streams
@@ -118,7 +113,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream    streams,
     case aiDefaultLogStream_STDOUT:
     case aiDefaultLogStream_STDOUT:
         return new StdOStreamLogStream(std::cout);
         return new StdOStreamLogStream(std::cout);
     case aiDefaultLogStream_FILE:
     case aiDefaultLogStream_FILE:
-        return (name && *name ? new FileLogStream(name,io) : NULL);
+        return (name && *name ? new FileLogStream(name,io) : nullptr );
     default:
     default:
         // We don't know this default log stream, so raise an assertion
         // We don't know this default log stream, so raise an assertion
         ai_assert(false);
         ai_assert(false);
@@ -134,34 +129,38 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream    streams,
 Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
 Logger *DefaultLogger::create(const char* name /*= "AssimpLog.txt"*/,
     LogSeverity severity                       /*= NORMAL*/,
     LogSeverity severity                       /*= NORMAL*/,
     unsigned int defStreams                    /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
     unsigned int defStreams                    /*= aiDefaultLogStream_DEBUGGER | aiDefaultLogStream_FILE*/,
-    IOSystem* io                               /*= NULL*/)
-{
+    IOSystem* io                               /*= NULL*/) {
     // enter the mutex here to avoid concurrency problems
     // enter the mutex here to avoid concurrency problems
 #ifndef ASSIMP_BUILD_SINGLETHREADED
 #ifndef ASSIMP_BUILD_SINGLETHREADED
     std::lock_guard<std::mutex> lock(loggerMutex);
     std::lock_guard<std::mutex> lock(loggerMutex);
 #endif
 #endif
 
 
-    if (m_pLogger && !isNullLogger() )
+    if ( m_pLogger && !isNullLogger() ) {
         delete m_pLogger;
         delete m_pLogger;
+    }
 
 
     m_pLogger = new DefaultLogger( severity );
     m_pLogger = new DefaultLogger( severity );
 
 
     // Attach default log streams
     // Attach default log streams
     // Stream the log to the MSVC debugger?
     // 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?
     // 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?
     // 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
     // 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;
     return m_pLogger;
 }
 }
@@ -200,7 +199,6 @@ void Logger::warn(const char* message)  {
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 void Logger::error(const char* message) {
 void Logger::error(const char* message) {
-
     // SECURITY FIX: see above
     // SECURITY FIX: see above
     if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
     if (strlen(message)>MAX_LOG_MESSAGE_LENGTH) {
         return;
         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
     // enter the mutex here to avoid concurrency problems
 #ifndef ASSIMP_BUILD_SINGLETHREADED
 #ifndef ASSIMP_BUILD_SINGLETHREADED
     std::lock_guard<std::mutex> lock(loggerMutex);
     std::lock_guard<std::mutex> lock(loggerMutex);
 #endif
 #endif
 
 
-    if (!logger)logger = &s_pNullLogger;
-    if (m_pLogger && !isNullLogger() )
+    if ( nullptr == logger ) {
+        logger = &s_pNullLogger;
+    }
+    if ( nullptr != m_pLogger && !isNullLogger() ) {
         delete m_pLogger;
         delete m_pLogger;
+    }
 
 
     DefaultLogger::m_pLogger = logger;
     DefaultLogger::m_pLogger = logger;
 }
 }
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
-bool DefaultLogger::isNullLogger()
-{
+bool DefaultLogger::isNullLogger() {
     return m_pLogger == &s_pNullLogger;
     return m_pLogger == &s_pNullLogger;
 }
 }
 
 
@@ -236,8 +235,7 @@ Logger *DefaultLogger::get() {
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 //  Kills the only instance
 //  Kills the only instance
-void DefaultLogger::kill()
-{
+void DefaultLogger::kill() {
     // enter the mutex here to avoid concurrency problems
     // enter the mutex here to avoid concurrency problems
 #ifndef ASSIMP_BUILD_SINGLETHREADED
 #ifndef ASSIMP_BUILD_SINGLETHREADED
     std::lock_guard<std::mutex> lock(loggerMutex);
     std::lock_guard<std::mutex> lock(loggerMutex);
@@ -252,10 +250,10 @@ void DefaultLogger::kill()
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 //  Debug message
 //  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;
 	static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
 	char msg[Size];
 	char msg[Size];
@@ -266,8 +264,7 @@ void DefaultLogger::OnDebug( const char* message )
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 //  Logs an info
 //  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;
 	static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
 	char msg[Size];
 	char msg[Size];
     ai_snprintf(msg, Size, "Info,  T%u: %s", GetThreadID(), message );
     ai_snprintf(msg, Size, "Info,  T%u: %s", GetThreadID(), message );
@@ -277,8 +274,7 @@ void DefaultLogger::OnInfo( const char* message )
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 //  Logs a warning
 //  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;
 	static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
 	char msg[Size];
 	char msg[Size];
 	ai_snprintf(msg, Size, "Warn,  T%u: %s", GetThreadID(), message );
 	ai_snprintf(msg, Size, "Warn,  T%u: %s", GetThreadID(), message );
@@ -288,8 +284,7 @@ void DefaultLogger::OnWarn( const char* message )
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 //  Logs an error
 //  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;
 	static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16;
 	char msg[ Size ];
 	char msg[ Size ];
     ai_snprintf(msg, Size, "Error, T%u: %s", GetThreadID(), message );
     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
 //  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;
         return false;
+    }
 
 
     if (0 == severity)  {
     if (0 == severity)  {
         severity = Logger::Info | Logger::Err | Logger::Warn | Logger::Debugging;
         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 != m_StreamArray.end();
         ++it )
         ++it )
     {
     {
-        if ( (*it)->m_pStream == pStream )
-        {
+        if ( (*it)->m_pStream == pStream ) {
             (*it)->m_uiErrorSeverity |= severity;
             (*it)->m_uiErrorSeverity |= severity;
             return true;
             return true;
         }
         }
@@ -326,34 +320,31 @@ bool DefaultLogger::attachStream( LogStream *pStream, unsigned int severity )
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 //  Detach a stream
 //  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;
         return false;
+    }
 
 
     if (0 == severity)  {
     if (0 == severity)  {
         severity = SeverityAll;
         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;
             (*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
                 // don't delete the underlying stream 'cause the caller gains ownership again
-                (**it).m_pStream = NULL;
+                (**it).m_pStream = nullptr;
                 delete *it;
                 delete *it;
                 m_StreamArray.erase( it );
                 m_StreamArray.erase( it );
+                res = true;
                 break;
                 break;
             }
             }
             return true;
             return true;
         }
         }
     }
     }
-    return false;
+    return res;
 }
 }
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
@@ -361,15 +352,13 @@ bool DefaultLogger::detatchStream( LogStream *pStream, unsigned int severity )
 DefaultLogger::DefaultLogger(LogSeverity severity)
 DefaultLogger::DefaultLogger(LogSeverity severity)
     :   Logger  ( severity )
     :   Logger  ( severity )
     ,   noRepeatMsg (false)
     ,   noRepeatMsg (false)
-    ,   lastLen( 0 )
-{
+    ,   lastLen( 0 ) {
     lastMsg[0] = '\0';
     lastMsg[0] = '\0';
 }
 }
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 //  Destructor
 //  Destructor
-DefaultLogger::~DefaultLogger()
-{
+DefaultLogger::~DefaultLogger() {
     for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
     for ( StreamIt it = m_StreamArray.begin(); it != m_StreamArray.end(); ++it ) {
         // also frees the underlying stream, we are its owner.
         // also frees the underlying stream, we are its owner.
         delete *it;
         delete *it;
@@ -378,9 +367,8 @@ DefaultLogger::~DefaultLogger()
 
 
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
 //  Writes message to stream
 //  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
     // Check whether this is a repeated message
     if (! ::strncmp( message,lastMsg, lastLen-1))
     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 {
 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
     // Test path directly
     std::ifstream file(imagePath, std::ios::binary | std::ios::ate);
     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.");
         DefaultLogger::get()->warn("EmbedTexturesProcess: Cannot find image: " + imagePath + ". Will try to find it in root folder.");
 
 
         // Test path in root path
         // Test path in root path
         imagePath = mRootPath + path;
         imagePath = mRootPath + path;
         file.open(imagePath, std::ios::binary | std::ios::ate);
         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
             // Test path basename in root path
             imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u);
             imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u);
             file.open(imagePath, std::ios::binary | std::ios::ate);
             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 + ".");
                 DefaultLogger::get()->error("EmbedTexturesProcess: Unable to embed texture: " + path + ".");
                 return false;
                 return false;
             }
             }
@@ -134,7 +134,7 @@ bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
     // Add the new texture
     // Add the new texture
     auto pTexture = new aiTexture();
     auto pTexture = new aiTexture();
     pTexture->mHeight = 0; // Means that this is still compressed
     pTexture->mHeight = 0; // Means that this is still compressed
-    pTexture->mWidth = imageSize;
+    pTexture->mWidth = static_cast<uint32_t>(imageSize);
     pTexture->pcData = imageContent;
     pTexture->pcData = imageContent;
 
 
     auto extension = path.substr(path.find_last_of('.') + 1u);
     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();
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
     // when they create scenes from scratch, users will likely create them not in verbose
     // 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 ] );
         aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
         aiVector3D GeometricScalingInverse = GeometricScaling;
         aiVector3D GeometricScalingInverse = GeometricScaling;
         bool canscale = true;
         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 ) {
             if ( std::fabs( GeometricScalingInverse[i] ) > zero_epsilon ) {
                 GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
                 GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
             } else {
             } else {
@@ -1642,9 +1642,8 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
 }
 }
 
 
 void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
 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 );
     LayeredTextureMap::const_iterator it = layeredTextures.find( propName );
     if ( it == layeredTextures.end() ) {
     if ( it == layeredTextures.end() ) {
         return;
         return;
@@ -1888,11 +1887,11 @@ void Converter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyT
 
 
     // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
     // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes:
     const aiColor3D& Transparent = GetColorPropertyFactored( props, "TransparentColor", "TransparencyFactor", ok );
     const aiColor3D& Transparent = GetColorPropertyFactored( props, "TransparentColor", "TransparencyFactor", ok );
-    float CalculatedOpacity = 1.0;
+    float CalculatedOpacity = 1.0f;
     if ( ok ) {
     if ( ok ) {
         out_mat->AddProperty( &Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT );
         out_mat->AddProperty( &Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT );
         // as calculated by FBX SDK 2017:
         // 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.
     // 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
     s.PutU4(0); // total property section length
 
 
     // node name
     // 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
     s.PutString(name); // node name as raw bytes
 
 
     // property data comes after here
     // property data comes after here
@@ -217,8 +217,8 @@ void FBX::Node::EndProperties(
     ai_assert(pos > property_start);
     ai_assert(pos > property_start);
     size_t property_section_size = pos - property_start;
     size_t property_section_size = pos - property_start;
     s.Seek(start_pos + 4);
     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);
     s.Seek(pos);
 }
 }
 
 
@@ -232,7 +232,7 @@ void FBX::Node::End(
     // now go back and write initial pos
     // now go back and write initial pos
     this->end_pos = s.Tell();
     this->end_pos = s.Tell();
     s.Seek(start_pos);
     s.Seek(start_pos);
-    s.PutU4(end_pos);
+    s.PutU4(uint32_t(end_pos));
     s.Seek(end_pos);
     s.Seek(end_pos);
 }
 }
 
 
@@ -251,9 +251,9 @@ void FBX::Node::WritePropertyNode(
     Node node(name);
     Node node(name);
     node.Begin(s);
     node.Begin(s);
     s.PutU1('d');
     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(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); }
     for (auto it = v.begin(); it != v.end(); ++it) { s.PutF8(*it); }
     node.EndProperties(s, 1);
     node.EndProperties(s, 1);
     node.End(s, false);
     node.End(s, false);
@@ -271,9 +271,9 @@ void FBX::Node::WritePropertyNode(
     Node node(name);
     Node node(name);
     node.Begin(s);
     node.Begin(s);
     s.PutU1('i');
     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(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); }
     for (auto it = v.begin(); it != v.end(); ++it) { s.PutI4(*it); }
     node.EndProperties(s, 1);
     node.EndProperties(s, 1);
     node.End(s, false);
     node.End(s, false);

+ 7 - 7
code/FBXExportProperty.cpp

@@ -127,8 +127,8 @@ FBX::Property::Property(const aiMatrix4x4& vm)
     : type('d'), data(8*16)
     : type('d'), data(8*16)
 {
 {
     double* d = reinterpret_cast<double*>(data.data());
     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];
             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 'L': s.PutI8(*(reinterpret_cast<int64_t*>(data.data()))); return;
     case 'S':
     case 'S':
     case 'R':
     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]); }
         for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); }
         return;
         return;
     case 'i':
     case 'i':
         N = data.size() / 4;
         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)
         s.PutU4(0); // no encoding (1 would be zip-compressed)
         // TODO: compress if large?
         // TODO: compress if large?
-        s.PutU4(data.size()); // data size
+        s.PutU4(uint32_t(data.size())); // data size
         d = data.data();
         d = data.data();
         for (size_t i = 0; i < N; ++i) {
         for (size_t i = 0; i < N; ++i) {
             s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
             s.PutI4((reinterpret_cast<int32_t*>(d))[i]);
@@ -180,10 +180,10 @@ void FBX::Property::Dump(Assimp::StreamWriterLE &s)
         return;
         return;
     case 'd':
     case 'd':
         N = data.size() / 8;
         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)
         s.PutU4(0); // no encoding (1 would be zip-compressed)
         // TODO: compress if large?
         // TODO: compress if large?
-        s.PutU4(data.size()); // data size
+        s.PutU4(uint32_t(data.size())); // data size
         d = data.data();
         d = data.data();
         for (size_t i = 0; i < N; ++i) {
         for (size_t i = 0; i < N; ++i) {
             s.PutF8((reinterpret_cast<double*>(d))[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 aiTextureType textype = static_cast<aiTextureType>(tt);
             const size_t texcount = mat->GetTextureCount(textype);
             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);
                 mat->GetTexture(textype, j, &texpath);
                 images.insert(std::string(texpath.C_Str()));
                 images.insert(std::string(texpath.C_Str()));
             }
             }
@@ -593,7 +593,7 @@ void FBXExporter::WriteDefinitions ()
 
 
     // Model / FbxNode
     // Model / FbxNode
     // <~~ node heirarchy
     // <~~ 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) {
     if (count) {
         n = FBX::Node("ObjectType", Property("Model"));
         n = FBX::Node("ObjectType", Property("Model"));
         n.AddChild("Count", count);
         n.AddChild("Count", count);
@@ -763,7 +763,7 @@ void FBXExporter::WriteDefinitions ()
 
 
     // Video / FbxVideo
     // Video / FbxVideo
     // one for each image file.
     // one for each image file.
-    count = count_images(mScene);
+    count = int32_t(count_images(mScene));
     if (count) {
     if (count) {
         n = FBX::Node("ObjectType", Property("Video"));
         n = FBX::Node("ObjectType", Property("Video"));
         n.AddChild("Count", count);
         n.AddChild("Count", count);
@@ -792,7 +792,7 @@ void FBXExporter::WriteDefinitions ()
 
 
     // Texture / FbxFileTexture
     // Texture / FbxFileTexture
     // <~~ aiTexture
     // <~~ aiTexture
-    count = count_textures(mScene);
+    count = int32_t(count_textures(mScene));
     if (count) {
     if (count) {
         n = FBX::Node("ObjectType", Property("Texture"));
         n = FBX::Node("ObjectType", Property("Texture"));
         n.AddChild("Count", count);
         n.AddChild("Count", count);
@@ -848,7 +848,7 @@ void FBXExporter::WriteDefinitions ()
     }
     }
 
 
     // Deformer
     // Deformer
-    count = count_deformers(mScene);
+    count = int32_t(count_deformers(mScene));
     if (count) {
     if (count) {
         n = FBX::Node("ObjectType", Property("Deformer"));
         n = FBX::Node("ObjectType", Property("Deformer"));
         n.AddChild("Count", count);
         n.AddChild("Count", count);
@@ -943,7 +943,7 @@ void FBXExporter::WriteObjects ()
         std::vector<int32_t> vertex_indices;
         std::vector<int32_t> vertex_indices;
         // map of vertex value to its index in the data vector
         // map of vertex value to its index in the data vector
         std::map<aiVector3D,size_t> index_by_vertex_value;
         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) {
         for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
             aiVector3D vtx = m->mVertices[vi];
             aiVector3D vtx = m->mVertices[vi];
             auto elem = index_by_vertex_value.find(vtx);
             auto elem = index_by_vertex_value.find(vtx);
@@ -955,7 +955,7 @@ void FBXExporter::WriteObjects ()
                 flattened_vertices.push_back(vtx[2]);
                 flattened_vertices.push_back(vtx[2]);
                 ++index;
                 ++index;
             } else {
             } else {
-                vertex_indices.push_back(elem->second);
+                vertex_indices.push_back(int32_t(elem->second));
             }
             }
         }
         }
         FBX::Node::WritePropertyNode(
         FBX::Node::WritePropertyNode(
@@ -1052,7 +1052,7 @@ void FBXExporter::WriteObjects ()
             std::vector<double> uv_data;
             std::vector<double> uv_data;
             std::vector<int32_t> uv_indices;
             std::vector<int32_t> uv_indices;
             std::map<aiVector3D,int32_t> index_by_uv;
             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) {
             for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
                 const aiFace &f = m->mFaces[fi];
                 const aiFace &f = m->mFaces[fi];
                 for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
                 for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
@@ -1062,7 +1062,7 @@ void FBXExporter::WriteObjects ()
                     if (elem == index_by_uv.end()) {
                     if (elem == index_by_uv.end()) {
                         index_by_uv[uv] = index;
                         index_by_uv[uv] = index;
                         uv_indices.push_back(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]);
                             uv_data.push_back(uv[x]);
                         }
                         }
                         ++index;
                         ++index;
@@ -1208,13 +1208,13 @@ void FBXExporter::WriteObjects ()
         // and usualy are completely ignored when loading.
         // and usualy are completely ignored when loading.
         // One notable exception is the "Opacity" property,
         // One notable exception is the "Opacity" property,
         // which Blender uses as (1.0 - alpha).
         // 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);
         m->Get(AI_MATKEY_COLOR_EMISSIVE, c);
         p.AddP70vector("Emissive", c.r, c.g, c.b);
         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);
         m->Get(AI_MATKEY_COLOR_AMBIENT, c);
         p.AddP70vector("Ambient", c.r, c.g, c.b);
         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);
         m->Get(AI_MATKEY_COLOR_DIFFUSE, c);
         p.AddP70vector("Diffuse", c.r, c.g, c.b);
         p.AddP70vector("Diffuse", c.r, c.g, c.b);
         // The FBX SDK determines "Opacity" from transparency colour (RGB)
         // 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.
         // so we should take it from AI_MATKEY_OPACITY if possible.
         // It might make more sense to use TransparencyFactor,
         // It might make more sense to use TransparencyFactor,
         // but Blender actually loads "Opacity" correctly, so let's use it.
         // 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) {
         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);
         m->Get(AI_MATKEY_OPACITY, f);
         p.AddP70double("Opacity", f);
         p.AddP70double("Opacity", f);
         if (phong) {
         if (phong) {
             // specular color is multiplied by shininess_strength
             // 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);
             m->Get(AI_MATKEY_COLOR_SPECULAR, c);
-            f = 1.0;
+            f = 1.0f;
             m->Get(AI_MATKEY_SHININESS_STRENGTH, f);
             m->Get(AI_MATKEY_SHININESS_STRENGTH, f);
             p.AddP70vector("Specular", f*c.r, f*c.g, f*c.b);
             p.AddP70vector("Specular", f*c.r, f*c.g, f*c.b);
-            f = 20.0;
+            f = 20.0f;
             m->Get(AI_MATKEY_SHININESS, f);
             m->Get(AI_MATKEY_SHININESS, f);
             p.AddP70double("Shininess", f);
             p.AddP70double("Shininess", f);
             // Legacy "Reflectivity" is F*F*((R+G+B)/3),
             // Legacy "Reflectivity" is F*F*((R+G+B)/3),
             // where F is the proportion of light reflected (AKA reflectivity),
             // where F is the proportion of light reflected (AKA reflectivity),
             // and RGB is the reflective colour of the material.
             // and RGB is the reflective colour of the material.
             // No idea why, but we might as well set it the same way.
             // 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);
             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);
             m->Get(AI_MATKEY_COLOR_REFLECTIVE, c);
             p.AddP70double("Reflectivity", f*f*((c.r+c.g+c.b)/3.0));
             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 aiTextureType textype = static_cast<aiTextureType>(tt);
             const size_t texcount = mat->GetTextureCount(textype);
             const size_t texcount = mat->GetTextureCount(textype);
             for (size_t j = 0; j < texcount; ++j) {
             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();
                 const std::string texstring = texpath.C_Str();
                 auto elem = uid_by_image.find(texstring);
                 auto elem = uid_by_image.find(texstring);
                 if (elem == uid_by_image.end()) {
                 if (elem == uid_by_image.end()) {
@@ -1591,7 +1591,7 @@ void FBXExporter::WriteObjects ()
         std::vector<int32_t> vertex_indices;
         std::vector<int32_t> vertex_indices;
         // map of vertex value to its index in the data vector
         // map of vertex value to its index in the data vector
         std::map<aiVector3D,size_t> index_by_vertex_value;
         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) {
         for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
             aiVector3D vtx = m->mVertices[vi];
             aiVector3D vtx = m->mVertices[vi];
             auto elem = index_by_vertex_value.find(vtx);
             auto elem = index_by_vertex_value.find(vtx);
@@ -1600,7 +1600,7 @@ void FBXExporter::WriteObjects ()
                 index_by_vertex_value[vtx] = index;
                 index_by_vertex_value[vtx] = index;
                 ++index;
                 ++index;
             } else {
             } 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.
         // as it can be instanced to many nodes.
         // All we can do is assume no instancing,
         // All we can do is assume no instancing,
         // and take the first node we find that contains the mesh.
         // 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);
         aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene);
 
 
         // now make a subdeformer for each bone in the skeleton
         // 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.
             // this should be the same as the bone's mOffsetMatrix.
             // if it's not the same, the skeleton isn't in the bind pose.
             // 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;
             bool bone_xform_okay = true;
             if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
             if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
                 not_in_bind_pose.insert(b);
                 not_in_bind_pose.insert(b);
@@ -2002,7 +2002,7 @@ void FBXExporter::WriteModelNodes(
             transform_chain.emplace_back(elem->first, t);
             transform_chain.emplace_back(elem->first, t);
             break;
             break;
         case 'r': // rotation
         case 'r': // rotation
-            r *= DEG;
+            r *= float(DEG);
             transform_chain.emplace_back(elem->first, r);
             transform_chain.emplace_back(elem->first, r);
             break;
             break;
         case 's': // scale
         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) {
             if (s != std::string::npos) {
                 DefaultLogger::get()->info("File extension not known, trying signature-based detection");
                 DefaultLogger::get()->info("File extension not known, trying signature-based detection");
                 for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
                 for( unsigned int a = 0; a < pimpl->mImporter.size(); a++)  {
-
                     if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
                     if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) {
                         imp = pimpl->mImporter[a];
                         imp = pimpl->mImporter[a];
                         break;
                         break;
@@ -947,6 +946,7 @@ BaseImporter* Importer::GetImporter (const char* szExtension) const
 size_t Importer::GetImporterIndex (const char* szExtension) const
 size_t Importer::GetImporterIndex (const char* szExtension) const
 {
 {
     ai_assert(szExtension);
     ai_assert(szExtension);
+
     ASSIMP_BEGIN_EXCEPTION_REGION();
     ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
     // skip over wildcard and dot characters at string head --
     // 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,
 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) {
     for(const Schema_2x3::IfcProperty& property : set) {
         const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name;
         const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name;
         if (const Schema_2x3::IfcPropertySingleValue* const singleValue = property.ToPtr<Schema_2x3::IfcPropertySingleValue>()) {
         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);
     mOutputMat.precision(16);
 
 
     WriteGeometryFile(noMtl);
     WriteGeometryFile(noMtl);
-    if (!noMtl)
+    if ( !noMtl ) {
         WriteMaterialFile();
         WriteMaterialFile();
+    }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 ObjExporter::~ObjExporter() {
 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
     // within the Obj file, we use just the relative file name with the path stripped
     const std::string& s = GetMaterialLibFileName();
     const std::string& s = GetMaterialLibFileName();
     std::string::size_type il = s.find_last_of("/\\");
     std::string::size_type il = s.find_last_of("/\\");
@@ -158,8 +158,9 @@ std::string ObjExporter :: GetMaterialLibName()
 std::string ObjExporter::GetMaterialLibFileName() {
 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
     // 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('.');
     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;
     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];
     const aiMaterial* const mat = pScene->mMaterials[index];
     if ( nullptr == mat ) {
     if ( nullptr == mat ) {
         static const std::string EmptyStr;
         static const std::string EmptyStr;
@@ -191,8 +191,7 @@ std::string ObjExporter::GetMaterialName(unsigned int index)
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void ObjExporter::WriteMaterialFile()
-{
+void ObjExporter::WriteMaterialFile() {
     WriteHeader(mOutputMat);
     WriteHeader(mOutputMat);
 
 
     for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
     for(unsigned int i = 0; i < pScene->mNumMaterials; ++i) {
@@ -310,8 +309,9 @@ void ObjExporter::WriteGeometryFile(bool noMtl) {
         if (!m.name.empty()) {
         if (!m.name.empty()) {
             mOutput << "g " << m.name << endl;
             mOutput << "g " << m.name << endl;
         }
         }
-        if (!noMtl)
+        if ( !noMtl ) {
             mOutput << "usemtl " << m.matname << endl;
             mOutput << "usemtl " << m.matname << endl;
+        }
 
 
         for(const Face& f : m.faces) {
         for(const Face& f : m.faces) {
             mOutput << f.kind << ' ';
             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) {
 void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) {
-    mMeshes.push_back(MeshInstance());
+    mMeshes.push_back(MeshInstance() );
     MeshInstance& mesh = mMeshes.back();
     MeshInstance& mesh = mMeshes.back();
 
 
     mesh.name = std::string( name.data, name.length );
     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;
     const aiMatrix4x4& mAbs = mParent * nd->mTransformation;
 
 
     for(unsigned int i = 0; i < nd->mNumMeshes; ++i) {
     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
     // Create the root node of the scene
     pScene->mRootNode = new aiNode;
     pScene->mRootNode = new aiNode;
-    if ( !pModel->m_ModelName.empty() )
-    {
+    if ( !pModel->m_ModelName.empty() ) {
         // Set the name of the scene
         // Set the name of the scene
         pScene->mRootNode->mName.Set(pModel->m_ModelName);
         pScene->mRootNode->mName.Set(pModel->m_ModelName);
-    }
-    else
-    {
+    } else {
         // This is a fatal error, so break down the application
         // This is a fatal error, so break down the application
         ai_assert(false);
         ai_assert(false);
     }
     }
 
 
     // Create nodes for the whole scene
     // Create nodes for the whole scene
     std::vector<aiMesh*> MeshArray;
     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);
         createNodes(pModel, pModel->m_Objects[ index ], pScene->mRootNode, pScene, MeshArray);
     }
     }
 
 
     // Create mesh pointer buffer for this scene
     // Create mesh pointer buffer for this scene
-    if (pScene->mNumMeshes > 0)
-    {
+    if (pScene->mNumMeshes > 0) {
         pScene->mMeshes = new aiMesh*[ MeshArray.size() ];
         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 ];
             pScene->mMeshes[ index ] = MeshArray[ index ];
         }
         }
     }
     }
@@ -261,8 +255,7 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
         appendChildToParentNode( pParent, pNode );
         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 ];
         unsigned int meshId = pObject->m_Meshes[ i ];
         aiMesh *pMesh = createTopology( pModel, pObject, meshId );
         aiMesh *pMesh = createTopology( pModel, pObject, meshId );
         if( pMesh ) {
         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
     // 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();
         size_t numChilds = pObject->m_SubObjects.size();
         pNode->mNumChildren = static_cast<unsigned int>( numChilds );
         pNode->mNumChildren = static_cast<unsigned int>( numChilds );
         pNode->mChildren = new aiNode*[ 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
     // Set mesh instances into scene- and node-instances
     const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
     const size_t meshSizeDiff = MeshArray.size()- oldMeshSize;
-    if ( meshSizeDiff > 0 )
-    {
+    if ( meshSizeDiff > 0 ) {
         pNode->mMeshes = new unsigned int[ meshSizeDiff ];
         pNode->mMeshes = new unsigned int[ meshSizeDiff ];
         pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
         pNode->mNumMeshes = static_cast<unsigned int>( meshSizeDiff );
         size_t index = 0;
         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;
             pNode->mMeshes[ index ] = pScene->mNumMeshes;
             pScene->mNumMeshes++;
             pScene->mNumMeshes++;
-            index++;
+            ++index;
         }
         }
     }
     }
 
 

+ 4 - 3
code/ObjFileParser.cpp

@@ -612,13 +612,14 @@ void ObjFileParser::getMaterialLib() {
         if ( '/' != *path.rbegin() ) {
         if ( '/' != *path.rbegin() ) {
           path += '/';
           path += '/';
         }
         }
-        absName = path + strMatName;
+        absName += path;
+        absName += strMatName;
     } else {
     } else {
         absName = strMatName;
         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);
         DefaultLogger::get()->error("OBJ: Unable to locate material file " + strMatName);
         std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl";
         std::string strMatFallbackName = m_originalObjFileName.substr(0, m_originalObjFileName.length() - 3) + "mtl";
         DefaultLogger::get()->info("OBJ: Opening fallback material file " + strMatFallbackName);
         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 <sstream>
 #include <cctype>
 #include <cctype>
 
 
-namespace Assimp
-{
-namespace Ogre
-{
+namespace Assimp {
+namespace Ogre {
 
 
 /// Returns a lower cased copy of @s.
 /// 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);
     std::transform(s.begin(), s.end(), s.begin(), ::tolower);
     return s;
     return s;
 }
 }
 
 
 /// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching.
 /// 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;
         return false;
-    }
-    else if (s.length() < suffix.length())
-    {
+    } else if (s.length() < suffix.length()) {
         return false;
         return false;
     }
     }
 
 
@@ -82,48 +78,43 @@ static inline bool EndsWith(const std::string &s, const std::string &suffix, boo
 
 
     size_t len = suffix.length();
     size_t len = suffix.length();
     std::string sSuffix = s.substr(s.length()-len, len);
     std::string sSuffix = s.substr(s.length()-len, len);
+
     return (ASSIMP_stricmp(sSuffix, suffix) == 0);
     return (ASSIMP_stricmp(sSuffix, suffix) == 0);
 }
 }
 
 
 // Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
 // Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
 
 
 /// Trim from start
 /// 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); }));
         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); }));
         s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
     }
     }
     return s;
     return s;
 }
 }
 
 
 /// Trim from end
 /// 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());
         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); }));
         s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine<char>(c); }));
     }
     }
     return s;
     return s;
 }
 }
 
 
 /// Trim from both ends
 /// 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);
     return TrimLeft(TrimRight(s, newlines), newlines);
 }
 }
 
 
 /// Skips a line from current @ss position until a newline. Returns the skipped part.
 /// 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;
     std::string skipped;
     getline(ss, skipped);
     getline(ss, skipped);
     return 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.
 /// Skips a line and reads next element from @c ss to @c nextElement.
 /** @return Skipped line content until newline. */
 /** @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);
     std::string skipped = SkipLine(ss);
     ss >> nextElement;
     ss >> nextElement;
     return skipped;
     return skipped;

+ 9 - 10
code/OgreXmlSerializer.cpp

@@ -213,18 +213,18 @@ std::string &OgreXmlSerializer::SkipCurrentNode()
     DefaultLogger::get()->debug("Skipping node <" + m_currentNodeName + ">");
     DefaultLogger::get()->debug("Skipping node <" + m_currentNodeName + ">");
 #endif
 #endif
 
 
-    for(;;)
-    {
-        if (!m_reader->read())
-        {
+    for(;;) {
+        if (!m_reader->read()) {
             m_currentNodeName = "";
             m_currentNodeName = "";
             return m_currentNodeName;
             return m_currentNodeName;
         }
         }
-        if (m_reader->getNodeType() != irr::io::EXN_ELEMENT_END)
+        if ( m_reader->getNodeType() != irr::io::EXN_ELEMENT_END ) {
             continue;
             continue;
-        else if (std::string(m_reader->getNodeName()) == m_currentNodeName)
+        } else if ( std::string( m_reader->getNodeName() ) == m_currentNodeName ) {
             break;
             break;
+        }
     }
     }
+
     return NextNode();
     return NextNode();
 }
 }
 
 
@@ -303,17 +303,16 @@ static const char *anZ = "z";
 
 
 // Mesh
 // Mesh
 
 
-MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader)
-{
+MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader) {
     OgreXmlSerializer serializer(reader);
     OgreXmlSerializer serializer(reader);
 
 
     MeshXml *mesh = new MeshXml();
     MeshXml *mesh = new MeshXml();
     serializer.ReadMesh(mesh);
     serializer.ReadMesh(mesh);
+
     return mesh;
     return mesh;
 }
 }
 
 
-void OgreXmlSerializer::ReadMesh(MeshXml *mesh)
-{
+void OgreXmlSerializer::ReadMesh(MeshXml *mesh) {
     if (NextNode() != nnMesh) {
     if (NextNode() != nnMesh) {
         throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>");
         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/SceneCombiner.h>
 #include <assimp/StringUtils.h>
 #include <assimp/StringUtils.h>
 #include <assimp/fast_atof.h>
 #include <assimp/fast_atof.h>
+#include <assimp/metadata.h>
 #include <assimp/Hash.h>
 #include <assimp/Hash.h>
 #include "time.h"
 #include "time.h"
 #include <assimp/DefaultLogger.hpp>
 #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)   {
             for (std::vector<aiMesh*>::const_iterator it = begin; it != end;++it)   {
                 if ((*it)->mNormals)    {
                 if ((*it)->mNormals)    {
                     ::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D));
                     ::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;
                 pv2 += (*it)->mNumVertices;
             }
             }
         }
         }
@@ -817,28 +819,29 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
             pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
             pv2 = out->mTangents = new aiVector3D[out->mNumVertices];
             aiVector3D* pv2b = out->mBitangents = 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)   {
                 if ((*it)->mTangents)   {
                     ::memcpy(pv2, (*it)->mTangents,  (*it)->mNumVertices*sizeof(aiVector3D));
                     ::memcpy(pv2, (*it)->mTangents,  (*it)->mNumVertices*sizeof(aiVector3D));
                     ::memcpy(pv2b,(*it)->mBitangents,(*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;
                 pv2  += (*it)->mNumVertices;
                 pv2b += (*it)->mNumVertices;
                 pv2b += (*it)->mNumVertices;
             }
             }
         }
         }
         // copy texture coordinates
         // copy texture coordinates
         unsigned int n = 0;
         unsigned int n = 0;
-        while ((**begin).HasTextureCoords(n))   {
+        while ((**begin).HasTextureCoords(n)) {
             out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
             out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n];
 
 
             pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices];
             pv2 = out->mTextureCoords[n] = 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)->mTextureCoords[n])   {
                 if ((*it)->mTextureCoords[n])   {
                     ::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D));
                     ::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;
                 pv2 += (*it)->mNumVertices;
             }
             }
             ++n;
             ++n;
@@ -848,11 +851,11 @@ void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/,
         while ((**begin).HasVertexColors(n))    {
         while ((**begin).HasVertexColors(n))    {
             aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices];
             aiColor4D* pv2 = out->mColors[n] = new aiColor4D[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)->mColors[n])  {
                 if ((*it)->mColors[n])  {
                     ::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D));
                     ::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;
                 pv2 += (*it)->mNumVertices;
             }
             }
             ++n;
             ++n;
@@ -1001,7 +1004,12 @@ void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate)
         *_dest = new aiScene();
         *_dest = new aiScene();
     }
     }
     aiScene* dest = *_dest;
     aiScene* dest = *_dest;
-    ai_assert(dest);
+    ai_assert(nullptr != dest);
+
+    // copy metadata
+    if ( nullptr != src->mMetaData ) {
+        dest->mMetaData = new aiMetadata( *src->mMetaData );
+    }
 
 
     // copy animations
     // copy animations
     dest->mNumAnimations = src->mNumAnimations;
     dest->mNumAnimations = src->mNumAnimations;

+ 2 - 2
code/XFileParser.cpp

@@ -1076,8 +1076,8 @@ std::string XFileParser::GetNextToken() {
                     return s;
                     return s;
                 }
                 }
                 len = ReadBinDWord();
                 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 ) {
                 if ( iLen < 0 ) {
                     return s;
                     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,
 Normally textures used by assets are stored in separate files, however,
 there are file formats embedding their textures directly into the model file.
 there are file formats embedding their textures directly into the model file.
 Such textures are loaded into an aiTexture structure.
 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:
 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><tt>TEXTURE(t,n)</tt></td>
     <td>aiString</td>
     <td>aiString</td>
     <td>n/a</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>
 
 
   <tr>
   <tr>

+ 0 - 4
include/assimp/DefaultLogger.hpp

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

+ 30 - 23
include/assimp/ParsingUtils.h

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

+ 2 - 2
include/assimp/StreamWriter.h

@@ -104,7 +104,7 @@ public:
 
 
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     ~StreamWriter() {
     ~StreamWriter() {
-        stream->Write(&buffer[0], 1, buffer.size());
+        stream->Write(buffer.data(), 1, buffer.size());
         stream->Flush();
         stream->Flush();
     }
     }
 
 
@@ -114,7 +114,7 @@ public:
     /** Flush the contents of the internal buffer, and the output IOStream */
     /** Flush the contents of the internal buffer, and the output IOStream */
     void Flush()
     void Flush()
     {
     {
-        stream->Write(&buffer[0], 1, buffer.size());
+        stream->Write(buffer.data(), 1, buffer.size());
         stream->Flush();
         stream->Flush();
         buffer.clear();
         buffer.clear();
         cursor = 0;
         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
 #define INCLUDED_AI_STRING_WORKERS_H
 
 
 #include <assimp/ai_assert.h>
 #include <assimp/ai_assert.h>
+#include <assimp/defs.h>
 #include "StringComparison.h"
 #include "StringComparison.h"
 
 
 #include <string.h>
 #include <string.h>
@@ -72,8 +73,8 @@ namespace Assimp    {
  * @param number Number to be written
  * @param number Number to be written
  * @return Length of the output string, excluding the '\0'
  * @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);
     ai_assert(NULL != out);
 
 
     // write the unary minus to indicate we have a negative number
     // 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;
         const unsigned int digit = number / cur;
         if (mustPrint || digit > 0 || 1 == cur) {
         if (mustPrint || digit > 0 || 1 == cur) {
-            // print all future zeroes from now
+            // print all future zeroe's from now
             mustPrint = true;
             mustPrint = true;
 
 
             *out++ = '0'+static_cast<char>(digit);
             *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.
  *  size of the array automatically.
  */
  */
 template <size_t length>
 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);
     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
  *  @param s2 Second input string
  *  @return 0 if the given strings are identical
  *  @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)
 #if (defined _MSC_VER)
 
 
@@ -161,8 +163,8 @@ inline int ASSIMP_stricmp(const char *s1, const char *s2)
  *  @param b Second string
  *  @param b Second string
  *  @return 0 if a == b
  *  @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();
     int i = (int)b.length()-(int)a.length();
     return (i ? i : ASSIMP_stricmp(a.c_str(),b.c_str()));
     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
  *  @param n Macimum number of characters to compare
  *  @return 0 if the given strings are identical
  *  @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)
 #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
  * 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;
     unsigned int res = 1;
-    for (unsigned int i = 0; i < power;++i)
+    for ( unsigned int i = 0; i < power; ++i ) {
         res *= base;
         res *= base;
+    }
 
 
     return res;
     return res;
 }
 }
+
 } // end of namespace
 } // end of namespace
 
 
 #endif // !  AI_STRINGCOMPARISON_H_INC
 #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
 #ifndef INCLUDED_AI_STRINGUTILS_H
 #define INCLUDED_AI_STRINGUTILS_H
 #define INCLUDED_AI_STRINGUTILS_H
 
 
+#include <assimp/defs.h>
+
 #include <sstream>
 #include <sstream>
 #include <stdarg.h>
 #include <stdarg.h>
 #include <cstdlib>
 #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.
 ///	@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
 #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 c99_ai_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) {
 		int count(-1);
 		int count(-1);
 		if (0 != size) {
 		if (0 != size) {
@@ -68,7 +70,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 		return count;
 		return count;
 	}
 	}
 
 
-	inline
+    AI_FORCE_INLINE
     int ai_snprintf(char *outBuf, size_t size, const char *format, ...) {
     int ai_snprintf(char *outBuf, size_t size, const char *format, ...) {
 		int count;
 		int count;
 		va_list ap;
 		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.
 ///	@param	value   The value to write into the std::string.
 ///	@return	The value as a std::string
 ///	@return	The value as a std::string
 template <typename T>
 template <typename T>
-inline
+AI_FORCE_INLINE
 std::string to_string( T value ) {
 std::string to_string( T value ) {
     std::ostringstream os;
     std::ostringstream os;
     os << value;
     os << value;
@@ -102,7 +104,7 @@ std::string to_string( T value ) {
 ///	@param	begin   The first character of the string.
 ///	@param	begin   The first character of the string.
 /// @param  end     The last character
 /// @param  end     The last character
 ///	@return	The float value, 0.0f in cas of an error.
 ///	@return	The float value, 0.0f in cas of an error.
-inline
+AI_FORCE_INLINE
 float ai_strtof( const char *begin, const char *end ) {
 float ai_strtof( const char *begin, const char *end ) {
     if ( nullptr == begin ) {
     if ( nullptr == begin ) {
         return 0.0f;
         return 0.0f;
@@ -124,7 +126,7 @@ float ai_strtof( const char *begin, const char *end ) {
 ///	@param	toConvert   Value to convert
 ///	@param	toConvert   Value to convert
 ///	@return	The hexadecimal string, is empty in case of an error.
 ///	@return	The hexadecimal string, is empty in case of an error.
 template<class T>
 template<class T>
-inline
+AI_FORCE_INLINE
 std::string DecimalToHexa( T toConvert ) {
 std::string DecimalToHexa( T toConvert ) {
     std::string result;
     std::string result;
     std::stringstream ss;
     std::stringstream ss;

+ 81 - 17
include/assimp/metadata.h

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

+ 71 - 0
test/unit/utMetadata.cpp

@@ -181,3 +181,74 @@ TEST_F( utMetadata, get_set_aiVector3D_Test ) {
     EXPECT_TRUE( success );
     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 );
+    }
+}