Browse Source

Update assimp to newest git revision.

Lasse Öörni 11 years ago
parent
commit
dd657eab8d
100 changed files with 7573 additions and 1516 deletions
  1. 10 4
      Source/ThirdParty/Assimp/CMakeLists.txt
  2. 12 6
      Source/ThirdParty/Assimp/CREDITS
  3. 46 26
      Source/ThirdParty/Assimp/code/3DSConverter.cpp
  4. 7 0
      Source/ThirdParty/Assimp/code/3DSHelper.h
  5. 12 4
      Source/ThirdParty/Assimp/code/3DSLoader.cpp
  6. 22 6
      Source/ThirdParty/Assimp/code/Assimp.cpp
  7. 22 19
      Source/ThirdParty/Assimp/code/AssimpPCH.cpp
  8. 2 2
      Source/ThirdParty/Assimp/code/AssimpPCH.h
  9. 39 1
      Source/ThirdParty/Assimp/code/BaseImporter.cpp
  10. 10 1
      Source/ThirdParty/Assimp/code/BaseImporter.h
  11. 145 0
      Source/ThirdParty/Assimp/code/Bitmap.cpp
  12. 139 0
      Source/ThirdParty/Assimp/code/Bitmap.h
  13. 2 2
      Source/ThirdParty/Assimp/code/BlenderBMesh.cpp
  14. 1 1
      Source/ThirdParty/Assimp/code/BlenderDNA.h
  15. 9 0
      Source/ThirdParty/Assimp/code/BlenderModifier.cpp
  16. 1 8
      Source/ThirdParty/Assimp/code/BlenderScene.cpp
  17. 3 3
      Source/ThirdParty/Assimp/code/BlenderTessellator.cpp
  18. 1 1
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/shared_array.hpp
  19. 2 2
      Source/ThirdParty/Assimp/code/BoostWorkaround/boost/shared_ptr.hpp
  20. 40 14
      Source/ThirdParty/Assimp/code/CalcTangentsProcess.cpp
  21. 263 55
      Source/ThirdParty/Assimp/code/ColladaExporter.cpp
  22. 36 7
      Source/ThirdParty/Assimp/code/ColladaExporter.h
  23. 1 1
      Source/ThirdParty/Assimp/code/ComputeUVMappingProcess.cpp
  24. 4 4
      Source/ThirdParty/Assimp/code/DefaultLogger.cpp
  25. 3 1
      Source/ThirdParty/Assimp/code/Exporter.cpp
  26. 282 54
      Source/ThirdParty/Assimp/code/FBXConverter.cpp
  27. 4 1
      Source/ThirdParty/Assimp/code/FBXDocument.cpp
  28. 70 2
      Source/ThirdParty/Assimp/code/FBXDocument.h
  29. 1 1
      Source/ThirdParty/Assimp/code/FBXImportSettings.h
  30. 66 7
      Source/ThirdParty/Assimp/code/FBXMaterial.cpp
  31. 17 7
      Source/ThirdParty/Assimp/code/FBXParser.cpp
  32. 27 0
      Source/ThirdParty/Assimp/code/FBXProperties.cpp
  33. 3 0
      Source/ThirdParty/Assimp/code/FBXProperties.h
  34. 1 1
      Source/ThirdParty/Assimp/code/FindDegenerates.h
  35. 2 3
      Source/ThirdParty/Assimp/code/FindInvalidDataProcess.h
  36. 7 6
      Source/ThirdParty/Assimp/code/GenVertexNormalsProcess.cpp
  37. 2 2
      Source/ThirdParty/Assimp/code/IFCBoolean.cpp
  38. 1 1
      Source/ThirdParty/Assimp/code/IFCCurve.cpp
  39. 0 2
      Source/ThirdParty/Assimp/code/IFCGeometry.cpp
  40. 10 28
      Source/ThirdParty/Assimp/code/IFCLoader.cpp
  41. 2 2
      Source/ThirdParty/Assimp/code/IFCOpenings.cpp
  42. 1 1
      Source/ThirdParty/Assimp/code/IFCUtil.cpp
  43. 1 1
      Source/ThirdParty/Assimp/code/IFCUtil.h
  44. 26 7
      Source/ThirdParty/Assimp/code/Importer.cpp
  45. 8 3
      Source/ThirdParty/Assimp/code/Importer.h
  46. 1 1
      Source/ThirdParty/Assimp/code/ImporterRegistry.cpp
  47. 1 1
      Source/ThirdParty/Assimp/code/LWOLoader.cpp
  48. 2 1
      Source/ThirdParty/Assimp/code/LimitBoneWeightsProcess.h
  49. 238 242
      Source/ThirdParty/Assimp/code/LineSplitter.h
  50. 12 0
      Source/ThirdParty/Assimp/code/MaterialSystem.cpp
  51. 3 0
      Source/ThirdParty/Assimp/code/ObjExporter.cpp
  52. 3 1
      Source/ThirdParty/Assimp/code/ObjFileData.h
  53. 25 24
      Source/ThirdParty/Assimp/code/ObjFileImporter.cpp
  54. 5 0
      Source/ThirdParty/Assimp/code/ObjFileMtlImporter.cpp
  55. 45 19
      Source/ThirdParty/Assimp/code/ObjFileParser.cpp
  56. 8 7
      Source/ThirdParty/Assimp/code/ObjFileParser.h
  57. 1 1
      Source/ThirdParty/Assimp/code/ObjTools.h
  58. 1112 0
      Source/ThirdParty/Assimp/code/OgreBinarySerializer.cpp
  59. 416 0
      Source/ThirdParty/Assimp/code/OgreBinarySerializer.h
  60. 60 176
      Source/ThirdParty/Assimp/code/OgreImporter.cpp
  61. 98 0
      Source/ThirdParty/Assimp/code/OgreImporter.h
  62. 450 311
      Source/ThirdParty/Assimp/code/OgreMaterial.cpp
  63. 139 0
      Source/ThirdParty/Assimp/code/OgreParsingUtils.h
  64. 1195 0
      Source/ThirdParty/Assimp/code/OgreStructs.cpp
  65. 681 0
      Source/ThirdParty/Assimp/code/OgreStructs.h
  66. 1005 0
      Source/ThirdParty/Assimp/code/OgreXmlSerializer.cpp
  67. 116 0
      Source/ThirdParty/Assimp/code/OgreXmlSerializer.h
  68. 1 1
      Source/ThirdParty/Assimp/code/OptimizeMeshes.cpp
  69. 5 5
      Source/ThirdParty/Assimp/code/ParsingUtils.h
  70. 7 4
      Source/ThirdParty/Assimp/code/PlyParser.cpp
  71. 1 1
      Source/ThirdParty/Assimp/code/PlyParser.h
  72. 12 12
      Source/ThirdParty/Assimp/code/PostStepRegistry.cpp
  73. 12 2
      Source/ThirdParty/Assimp/code/PretransformVertices.cpp
  74. 6 4
      Source/ThirdParty/Assimp/code/PretransformVertices.h
  75. 44 57
      Source/ThirdParty/Assimp/code/Q3BSPFileData.h
  76. 33 47
      Source/ThirdParty/Assimp/code/Q3BSPFileImporter.cpp
  77. 213 97
      Source/ThirdParty/Assimp/code/Q3BSPZipArchive.cpp
  78. 89 108
      Source/ThirdParty/Assimp/code/Q3BSPZipArchive.h
  79. 1 1
      Source/ThirdParty/Assimp/code/RemoveComments.h
  80. 23 15
      Source/ThirdParty/Assimp/code/RemoveRedundantMaterials.cpp
  81. 5 3
      Source/ThirdParty/Assimp/code/RemoveRedundantMaterials.h
  82. 9 4
      Source/ThirdParty/Assimp/code/RemoveVCProcess.h
  83. 13 13
      Source/ThirdParty/Assimp/code/STEPFile.h
  84. 4 18
      Source/ThirdParty/Assimp/code/STEPFileReader.cpp
  85. 0 4
      Source/ThirdParty/Assimp/code/STEPFileReader.h
  86. 57 0
      Source/ThirdParty/Assimp/code/SceneCombiner.cpp
  87. 14 0
      Source/ThirdParty/Assimp/code/SceneCombiner.h
  88. 1 1
      Source/ThirdParty/Assimp/code/ScenePreprocessor.cpp
  89. 1 1
      Source/ThirdParty/Assimp/code/ScenePreprocessor.h
  90. 1 1
      Source/ThirdParty/Assimp/code/SmoothingGroups.h
  91. 1 1
      Source/ThirdParty/Assimp/code/SortByPTypeProcess.h
  92. 1 1
      Source/ThirdParty/Assimp/code/SpatialSort.cpp
  93. 4 4
      Source/ThirdParty/Assimp/code/SplitLargeMeshes.h
  94. 3 3
      Source/ThirdParty/Assimp/code/Subdivision.cpp
  95. 3 3
      Source/ThirdParty/Assimp/code/TriangulateProcess.h
  96. 1 1
      Source/ThirdParty/Assimp/code/ValidateDataStructure.cpp
  97. 1 1
      Source/ThirdParty/Assimp/code/VertexTriangleAdjacency.h
  98. 3 0
      Source/ThirdParty/Assimp/code/XFileParser.cpp
  99. 1 1
      Source/ThirdParty/Assimp/code/XFileParser.h
  100. 24 21
      Source/ThirdParty/Assimp/code/fast_atof.h

+ 10 - 4
Source/ThirdParty/Assimp/CMakeLists.txt

@@ -157,6 +157,8 @@ SET( Common_SRCS
 	code/TinyFormatter.h
 	code/TinyFormatter.h
 	code/Profiler.h
 	code/Profiler.h
 	code/LogAux.h
 	code/LogAux.h
+	code/Bitmap.cpp
+	code/Bitmap.h
 )
 )
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 SOURCE_GROUP(Common FILES ${Common_SRCS})
 
 
@@ -338,12 +340,16 @@ SET( Obj_SRCS
 SOURCE_GROUP( Obj FILES ${Obj_SRCS})
 SOURCE_GROUP( Obj FILES ${Obj_SRCS})
 
 
 SET( Ogre_SRCS
 SET( Ogre_SRCS
-	code/OgreImporter.hpp
-	code/OgreXmlHelper.hpp
+	code/OgreImporter.h
+	code/OgreStructs.h
+	code/OgreParsingUtils.h
+	code/OgreBinarySerializer.h
+	code/OgreXmlSerializer.h
 	code/OgreImporter.cpp
 	code/OgreImporter.cpp
+	code/OgreStructs.cpp
+	code/OgreBinarySerializer.cpp
+	code/OgreXmlSerializer.cpp
 	code/OgreMaterial.cpp
 	code/OgreMaterial.cpp
-	code/OgreMesh.cpp
-	code/OgreSkeleton.cpp
 )
 )
 SOURCE_GROUP( Ogre FILES ${Ogre_SRCS})
 SOURCE_GROUP( Ogre FILES ${Ogre_SRCS})
 
 

+ 12 - 6
Source/ThirdParty/Assimp/CREDITS

@@ -3,8 +3,8 @@ Open Asset Import Library (Assimp)
 Developers and Contributors
 Developers and Contributors
 ===============================================================
 ===============================================================
 
 
-The following is the list of all constributors.  
-Thanks for your help!
+The following is a non-exhaustive list of all constributors over the years.
+If you think your name should be listed here, drop us a line and we'll add you.
 
 
 - Alexander Gessler,
 - Alexander Gessler,
 3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Admin and Design).
 3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Admin and Design).
@@ -41,7 +41,7 @@ Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 w
 - Andreas Nagel
 - Andreas Nagel
 First Assimp testing & verification under Windows Vista 64 Bit.
 First Assimp testing & verification under Windows Vista 64 Bit.
 
 
-- Marius Schröder
+- Marius Schr�der
 Allowed us to use many of his models for screenshots and testing.
 Allowed us to use many of his models for screenshots and testing.
 
 
 - Christian Schubert
 - Christian Schubert
@@ -92,7 +92,7 @@ Contributed the 'SimpleTexturedOpenGl' sample.
 - Matthias Fauconneau
 - Matthias Fauconneau
 Contributed a fix for the Q3-BSP loader.
 Contributed a fix for the Q3-BSP loader.
 
 
-- Jørgen P. Tjernø
+- J�rgen P. Tjern�
 Contributed updated and improved xcode workspaces
 Contributed updated and improved xcode workspaces
 
 
 - drparallax
 - drparallax
@@ -137,8 +137,14 @@ GCC/Linux fixes for the SimpleOpenGL sample.
 - Brian Miller
 - Brian Miller
 Bugfix for a compiler fix for iOS on arm.
 Bugfix for a compiler fix for iOS on arm.
 
 
-- Séverin Lemaignan
+- S�verin Lemaignan
 Rewrite of PyAssimp, distutils and Python3 support
 Rewrite of PyAssimp, distutils and Python3 support
 
 
 - albert-wang
 - albert-wang
-Bugfixes for the collada parser
+Bugfixes for the collada parser
+
+- Ya ping Jin
+Bugfixes for uv-tanget calculation.
+
+- Jonne Nauha
+Ogre Binary format support

+ 46 - 26
Source/ThirdParty/Assimp/code/3DSConverter.cpp

@@ -467,34 +467,41 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
 			const unsigned int iIndex = iArray[i];
 			const unsigned int iIndex = iArray[i];
 			aiMesh* const mesh = pcSOut->mMeshes[iIndex];
 			aiMesh* const mesh = pcSOut->mMeshes[iIndex];
 
 
-			// Transform the vertices back into their local space
-			// fixme: consider computing normals after this, so we don't need to transform them
-			const aiVector3D* const pvEnd = mesh->mVertices+mesh->mNumVertices;
-			aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
-
-			for (;pvCurrent != pvEnd;++pvCurrent,++t2) {
-				*pvCurrent = mInv * (*pvCurrent);
-				*t2 = mInvTransposed * (*t2);
-			}
-
-			// Handle negative transformation matrix determinant -> invert vertex x
-			if (imesh->mMat.Determinant() < 0.0f)
+			if (mesh->mColors[1] == NULL)
 			{
 			{
-				/* we *must* have normals */
-				for (pvCurrent = mesh->mVertices,t2 = mesh->mNormals;pvCurrent != pvEnd;++pvCurrent,++t2) {
-					pvCurrent->x *= -1.f;
-					t2->x *= -1.f;
+				// Transform the vertices back into their local space
+				// fixme: consider computing normals after this, so we don't need to transform them
+				const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices;
+				aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals;
+
+				for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
+					*pvCurrent = mInv * (*pvCurrent);
+					*t2 = mInvTransposed * (*t2);
 				}
 				}
-				DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
-			}
 
 
-			// Handle pivot point
-			if(pivot.x || pivot.y || pivot.z)
-			{
-				for (pvCurrent = mesh->mVertices;pvCurrent != pvEnd;++pvCurrent)	{
-					*pvCurrent -= pivot;	
+				// Handle negative transformation matrix determinant -> invert vertex x
+				if (imesh->mMat.Determinant() < 0.0f)
+				{
+					/* we *must* have normals */
+					for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) {
+						pvCurrent->x *= -1.f;
+						t2->x *= -1.f;
+					}
+					DefaultLogger::get()->info("3DS: Flipping mesh X-Axis");
+				}
+
+				// Handle pivot point
+				if (pivot.x || pivot.y || pivot.z)
+				{
+					for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent)	{
+						*pvCurrent -= pivot;
+					}
 				}
 				}
+
+				mesh->mColors[1] = (aiColor4D*)1;
 			}
 			}
+			else
+				mesh->mColors[1] = (aiColor4D*)1;
 
 
 			// Setup the mesh index
 			// Setup the mesh index
 			pcOut->mMeshes[i] = iIndex;
 			pcOut->mMeshes[i] = iIndex;
@@ -502,7 +509,17 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
 	}
 	}
 
 
 	// Setup the name of the node
 	// Setup the name of the node
-	pcOut->mName.Set(pcIn->mName);
+	// First instance keeps its name otherwise something might break, all others will be postfixed with their instance number
+	if (pcIn->mInstanceNumber > 1)
+	{
+		char tmp[12];
+		ASSIMP_itoa10(tmp, pcIn->mInstanceNumber);
+		std::string tempStr = pcIn->mName + "_inst_";
+		tempStr += tmp;
+		pcOut->mName.Set(tempStr);
+	}
+	else
+		pcOut->mName.Set(pcIn->mName);
 
 
 	// Now build the transformation matrix of the node
 	// Now build the transformation matrix of the node
 	// ROTATION
 	// ROTATION
@@ -784,9 +801,12 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
 		AddNodeToGraph(pcOut,  pcOut->mRootNode, mRootNode,m);
 		AddNodeToGraph(pcOut,  pcOut->mRootNode, mRootNode,m);
 	}
 	}
 
 
-	// We used the first vertex color set to store some emporary values so we need to cleanup here
-	for (unsigned int a = 0; a < pcOut->mNumMeshes;++a)
+	// We used the first and second vertex color set to store some temporary values so we need to cleanup here
+	for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a)
+	{
 		pcOut->mMeshes[a]->mColors[0] = NULL;
 		pcOut->mMeshes[a]->mColors[0] = NULL;
+		pcOut->mMeshes[a]->mColors[1] = NULL;
+	}
 
 
 	pcOut->mRootNode->mTransformation = aiMatrix4x4(
 	pcOut->mRootNode->mTransformation = aiMatrix4x4(
 		1.f,0.f,0.f,0.f,
 		1.f,0.f,0.f,0.f,

+ 7 - 0
Source/ThirdParty/Assimp/code/3DSHelper.h

@@ -481,6 +481,7 @@ struct Node
 
 
 		:	mHierarchyPos		(0)
 		:	mHierarchyPos		(0)
 		,	mHierarchyIndex		(0)
 		,	mHierarchyIndex		(0)
+		,	mInstanceCount		(1)
 
 
 	{
 	{
 		static int iCnt = 0;
 		static int iCnt = 0;
@@ -510,6 +511,9 @@ struct Node
 	//! Name of the node
 	//! Name of the node
 	std::string mName;
 	std::string mName;
 
 
+	//! InstanceNumber of the node
+	int32_t mInstanceNumber;
+
 	//! Dummy nodes: real name to be combined with the $$$DUMMY 
 	//! Dummy nodes: real name to be combined with the $$$DUMMY 
 	std::string mDummyName;
 	std::string mDummyName;
 
 
@@ -539,6 +543,9 @@ struct Node
 	//! Pivot position loaded from the file
 	//! Pivot position loaded from the file
 	aiVector3D vPivot;
 	aiVector3D vPivot;
 
 
+	//instance count, will be kept only for the first node
+	int32_t mInstanceCount;
+
 	//! Add a child node, setup the right parent node for it
 	//! Add a child node, setup the right parent node for it
 	//! \param pc Node to be 'adopted'
 	//! \param pc Node to be 'adopted'
 	inline Node& push_back(Node* pc)
 	inline Node& push_back(Node* pc)

+ 12 - 4
Source/ThirdParty/Assimp/code/3DSLoader.cpp

@@ -659,14 +659,22 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
 		// Now find out whether we have this node already (target animation channels 
 		// Now find out whether we have this node already (target animation channels 
 		// are stored with a separate object ID)
 		// are stored with a separate object ID)
 		D3DS::Node* pcNode = FindNode(mRootNode,name);
 		D3DS::Node* pcNode = FindNode(mRootNode,name);
-		if (pcNode)
+		int instanceNumber = 1;
+
+		if ( pcNode)
 		{
 		{
-			// Make this node the current node
-			mCurrentNode = pcNode;
-			break;	
+			// if the source is not a CHUNK_TRACKINFO block it wont be an object instance
+			if (parent != Discreet3DS::CHUNK_TRACKINFO)
+			{
+				mCurrentNode = pcNode;
+				break;
+			}
+			pcNode->mInstanceCount++;
+			instanceNumber = pcNode->mInstanceCount;
 		}
 		}
 		pcNode = new D3DS::Node();
 		pcNode = new D3DS::Node();
 		pcNode->mName = name;
 		pcNode->mName = name;
+		pcNode->mInstanceNumber = instanceNumber;
 
 
 		// There are two unknown values which we can safely ignore
 		// There are two unknown values which we can safely ignore
 		stream->IncPtr(4);
 		stream->IncPtr(4);

+ 22 - 6
Source/ThirdParty/Assimp/code/Assimp.cpp

@@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "Importer.h"
 #include "Importer.h"
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 #	include <boost/thread/thread.hpp>
 #	include <boost/thread/thread.hpp>
 #	include <boost/thread/mutex.hpp>
 #	include <boost/thread/mutex.hpp>
 #endif
 #endif
@@ -87,7 +87,7 @@ namespace Assimp
 }
 }
 
 
 
 
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 /** Global mutex to manage the access to the logstream map */
 /** Global mutex to manage the access to the logstream map */
 static boost::mutex gLogStreamMutex;
 static boost::mutex gLogStreamMutex;
 #endif
 #endif
@@ -104,7 +104,7 @@ public:
 	}
 	}
 
 
 	~LogToCallbackRedirector()	{
 	~LogToCallbackRedirector()	{
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 		boost::mutex::scoped_lock lock(gLogStreamMutex);
 		boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 #endif
 		// (HACK) Check whether the 'stream.user' pointer points to a
 		// (HACK) Check whether the 'stream.user' pointer points to a
@@ -172,6 +172,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl
 		pimpl->mIntProperties = pp->ints;
 		pimpl->mIntProperties = pp->ints;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mStringProperties = pp->strings;
 		pimpl->mStringProperties = pp->strings;
+		pimpl->mMatrixProperties = pp->matrices;
 	}
 	}
 	// setup a custom IO system if necessary
 	// setup a custom IO system if necessary
 	if (pFS)	{
 	if (pFS)	{
@@ -230,6 +231,7 @@ const aiScene* aiImportFileFromMemoryWithProperties(
 		pimpl->mIntProperties = pp->ints;
 		pimpl->mIntProperties = pp->ints;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mFloatProperties = pp->floats;
 		pimpl->mStringProperties = pp->strings;
 		pimpl->mStringProperties = pp->strings;
+		pimpl->mMatrixProperties = pp->matrices;
 	}
 	}
 
 
 	// and have it read the file from the memory buffer
 	// and have it read the file from the memory buffer
@@ -337,7 +339,7 @@ ASSIMP_API void aiAttachLogStream( const aiLogStream* stream )
 {
 {
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 #endif
 
 
@@ -356,7 +358,7 @@ ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
 {
 {
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 
 
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 #endif
 	// find the logstream associated with this data
 	// find the logstream associated with this data
@@ -381,7 +383,7 @@ ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream)
 ASSIMP_API void aiDetachAllLogStreams(void)
 ASSIMP_API void aiDetachAllLogStreams(void)
 {
 {
 	ASSIMP_BEGIN_EXCEPTION_REGION();
 	ASSIMP_BEGIN_EXCEPTION_REGION();
-#ifdef AI_C_THREADSAFE
+#ifndef ASSIMP_BUILD_SINGLETHREADED
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 	boost::mutex::scoped_lock lock(gLogStreamMutex);
 #endif
 #endif
 	for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
 	for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) {
@@ -504,6 +506,20 @@ ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName
 	ASSIMP_END_EXCEPTION_REGION(void);
 	ASSIMP_END_EXCEPTION_REGION(void);
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Importer::SetPropertyMatrix
+ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName,
+	const C_STRUCT aiMatrix4x4* mat)
+{
+	if (!mat) {
+		return;
+	}
+	ASSIMP_BEGIN_EXCEPTION_REGION();
+	PropertyMap* pp = reinterpret_cast<PropertyMap*>(p);
+	SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat,NULL);
+	ASSIMP_END_EXCEPTION_REGION(void);
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Rotation matrix to quaternion
 // Rotation matrix to quaternion
 ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)
 ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat)

+ 22 - 19
Source/ThirdParty/Assimp/code/AssimpPCH.cpp

@@ -4,6 +4,9 @@
 #include "AssimpPCH.h"
 #include "AssimpPCH.h"
 #include "./../include/assimp/version.h"
 #include "./../include/assimp/version.h"
 
 
+static const unsigned int MajorVersion = 3;
+static const unsigned int MinorVersion = 1;
+
 // --------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------
 // Legal information string - dont't remove this.
 // Legal information string - dont't remove this.
 static const char* LEGAL_INFORMATION =
 static const char* LEGAL_INFORMATION =
@@ -25,13 +28,13 @@ ASSIMP_API const char*  aiGetLegalString  ()	{
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get Assimp minor version
 // Get Assimp minor version
 ASSIMP_API unsigned int aiGetVersionMinor ()	{
 ASSIMP_API unsigned int aiGetVersionMinor ()	{
-	return 0;
+    return MinorVersion;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get Assimp major version
 // Get Assimp major version
 ASSIMP_API unsigned int aiGetVersionMajor ()	{
 ASSIMP_API unsigned int aiGetVersionMajor ()	{
-	return 3;
+    return MajorVersion;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -65,31 +68,31 @@ ASSIMP_API unsigned int aiGetCompileFlags ()	{
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 ASSIMP_API unsigned int aiGetVersionRevision ()
 ASSIMP_API unsigned int aiGetVersionRevision ()
 {
 {
-	return SVNRevision;
+    return GitVersion;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-aiScene::aiScene()
-	: mFlags()
-	, mRootNode()
-	, mNumMeshes()
-	, mMeshes()
-	, mNumMaterials()
-	, mMaterials()
-	, mNumAnimations()
-	, mAnimations()
-	, mNumTextures()
-	, mTextures()
-	, mNumLights()
-	, mLights()
-	, mNumCameras()
-	, mCameras()
+ASSIMP_API aiScene::aiScene()
+	: mFlags(0)
+	, mRootNode(NULL)
+	, mNumMeshes(0)
+	, mMeshes(NULL)
+	, mNumMaterials(0)
+	, mMaterials(NULL)
+	, mNumAnimations(0)
+	, mAnimations(NULL)
+	, mNumTextures(0)
+	, mTextures(NULL)
+	, mNumLights(0)
+	, mLights(NULL)
+	, mNumCameras(0)
+	, mCameras(NULL)
 	, mPrivate(new Assimp::ScenePrivateData())
 	, mPrivate(new Assimp::ScenePrivateData())
 	{
 	{
 	}
 	}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-aiScene::~aiScene()
+ASSIMP_API aiScene::~aiScene()
 {
 {
 	// delete all sub-objects recursively
 	// delete all sub-objects recursively
 	delete mRootNode;
 	delete mRootNode;

+ 2 - 2
Source/ThirdParty/Assimp/code/AssimpPCH.h

@@ -56,7 +56,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 // Include our stdint.h replacement header for MSVC, take the global header for gcc/mingw
 // Include our stdint.h replacement header for MSVC, take the global header for gcc/mingw
 #if defined( _MSC_VER) && (_MSC_VER < 1600)
 #if defined( _MSC_VER) && (_MSC_VER < 1600)
-#	include "pstdint.h"
+#	include "../include/assimp/Compiler/pstdint.h"
 #else
 #else
 #	include <stdint.h>
 #	include <stdint.h>
 #endif
 #endif
@@ -74,7 +74,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 /* Helper macro to set a pointer to NULL in debug builds
 /* Helper macro to set a pointer to NULL in debug builds
  */
  */
-#if (defined _DEBUG)
+#if (defined ASSIMP_BUILD_DEBUG)
 #	define AI_DEBUG_INVALIDATE_PTR(x) x = NULL;
 #	define AI_DEBUG_INVALIDATE_PTR(x) x = NULL;
 #else
 #else
 #	define AI_DEBUG_INVALIDATE_PTR(x)
 #	define AI_DEBUG_INVALIDATE_PTR(x)

+ 39 - 1
Source/ThirdParty/Assimp/code/BaseImporter.cpp

@@ -379,6 +379,43 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
 	}
 	}
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Convert to UTF8 data to ISO-8859-1
+void BaseImporter::ConvertUTF8toISO8859_1(std::string& data)
+{
+	unsigned int size = data.size();
+	unsigned int i = 0, j = 0;
+
+	while(i < size) {
+		if((unsigned char) data[i] < 0x80) {
+			data[j] = data[i];
+		} else if(i < size - 1) {
+			if((unsigned char) data[i] == 0xC2) {
+				data[j] = data[++i];
+			} else if((unsigned char) data[i] == 0xC3) {
+				data[j] = ((unsigned char) data[++i] + 0x40);
+			} else {
+				std::stringstream stream;
+
+				stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
+
+				DefaultLogger::get()->error(stream.str());
+
+				data[j++] = data[i++];
+				data[j] = data[i];
+			}
+		} else {
+			DefaultLogger::get()->error("UTF8 code but only one character remaining");
+
+			data[j] = data[i];
+		}
+
+		i++; j++;
+	}
+
+	data.resize(j);
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void BaseImporter::TextFileToBuffer(IOStream* stream,
 void BaseImporter::TextFileToBuffer(IOStream* stream,
 	std::vector<char>& data)
 	std::vector<char>& data)
@@ -533,7 +570,7 @@ void BatchLoader::LoadAll()
 	for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it)	{
 	for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it)	{
 		// force validation in debug builds
 		// force validation in debug builds
 		unsigned int pp = (*it).flags;
 		unsigned int pp = (*it).flags;
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		pp |= aiProcess_ValidateDataStructure;
 		pp |= aiProcess_ValidateDataStructure;
 #endif
 #endif
 		// setup config properties if necessary
 		// setup config properties if necessary
@@ -541,6 +578,7 @@ void BatchLoader::LoadAll()
 		pimpl->mFloatProperties  = (*it).map.floats;
 		pimpl->mFloatProperties  = (*it).map.floats;
 		pimpl->mIntProperties    = (*it).map.ints;
 		pimpl->mIntProperties    = (*it).map.ints;
 		pimpl->mStringProperties = (*it).map.strings;
 		pimpl->mStringProperties = (*it).map.strings;
+		pimpl->mMatrixProperties = (*it).map.matrices;
 
 
 		if (!DefaultLogger::isNullLogger())
 		if (!DefaultLogger::isNullLogger())
 		{
 		{

+ 10 - 1
Source/ThirdParty/Assimp/code/BaseImporter.h

@@ -106,7 +106,7 @@ private:
  * imports the given file. ReadFile is not overridable, it just calls 
  * imports the given file. ReadFile is not overridable, it just calls 
  * InternReadFile() and catches any ImportErrorException that might occur.
  * InternReadFile() and catches any ImportErrorException that might occur.
  */
  */
-class BaseImporter
+class ASSIMP_API BaseImporter
 {
 {
 	friend class Importer;
 	friend class Importer;
 
 
@@ -331,6 +331,15 @@ public: // static utilities
 	static void ConvertToUTF8(
 	static void ConvertToUTF8(
 		std::vector<char>& data);
 		std::vector<char>& data);
 
 
+	// -------------------------------------------------------------------
+	/** An utility for all text file loaders. It converts a file from our
+	 *   UTF8 character set back to ISO-8859-1. Errors are reported, but ignored.
+	 *
+	 *  @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer
+	 *  is resized as appropriate. */
+	static void ConvertUTF8toISO8859_1(
+		std::string& data);
+
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Utility for text file loaders which copies the contents of the
 	/** Utility for text file loaders which copies the contents of the
 	 *  file into a memory buffer and converts it to our UTF8
 	 *  file into a memory buffer and converts it to our UTF8

+ 145 - 0
Source/ThirdParty/Assimp/code/Bitmap.cpp

@@ -0,0 +1,145 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+/** @file Bitmap.cpp
+ *  @brief Defines bitmap format helper for textures
+ *
+ * Used for file formats which embed their textures into the model file.
+ */
+
+#include "AssimpPCH.h"
+
+#include "Bitmap.h"
+
+namespace Assimp {
+
+	void Bitmap::Save(aiTexture* texture, IOStream* file) {
+		if(file != NULL) {
+			Header header;
+			DIB dib;
+
+			dib.size = DIB::dib_size;
+			dib.width = texture->mWidth;
+			dib.height = texture->mHeight;
+			dib.planes = 1;
+			dib.bits_per_pixel = 8 * mBytesPerPixel;
+			dib.compression = 0;
+			dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height;
+			dib.x_resolution = 0;
+			dib.y_resolution = 0;
+			dib.nb_colors = 0;
+			dib.nb_important_colors = 0;
+
+			header.type = 0x4D42; // 'BM'
+			header.offset = Header::header_size + DIB::dib_size;
+			header.size = header.offset + dib.image_size;
+			header.reserved1 = 0;
+			header.reserved2 = 0;
+
+			WriteHeader(header, file);
+			WriteDIB(dib, file);
+			WriteData(texture, file);
+		}
+	}
+
+	template<typename T>
+	inline std::size_t Copy(uint8_t* data, T& field) {
+		std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field);
+	}
+
+	void Bitmap::WriteHeader(Header& header, IOStream* file) {
+		uint8_t data[Header::header_size];
+
+		std::size_t offset = 0;
+
+		offset += Copy(&data[offset], header.type);
+		offset += Copy(&data[offset], header.size);
+		offset += Copy(&data[offset], header.reserved1);
+		offset += Copy(&data[offset], header.reserved2);
+		offset += Copy(&data[offset], header.offset);
+
+		file->Write(data, Header::header_size, 1);
+	}
+
+	void Bitmap::WriteDIB(DIB& dib, IOStream* file) {
+		uint8_t data[DIB::dib_size];
+
+		std::size_t offset = 0;
+
+		offset += Copy(&data[offset], dib.size);
+		offset += Copy(&data[offset], dib.width);
+		offset += Copy(&data[offset], dib.height);
+		offset += Copy(&data[offset], dib.planes);
+		offset += Copy(&data[offset], dib.bits_per_pixel);
+		offset += Copy(&data[offset], dib.compression);
+		offset += Copy(&data[offset], dib.image_size);
+		offset += Copy(&data[offset], dib.x_resolution);
+		offset += Copy(&data[offset], dib.y_resolution);
+		offset += Copy(&data[offset], dib.nb_colors);
+		offset += Copy(&data[offset], dib.nb_important_colors);
+
+		file->Write(data, DIB::dib_size, 1);
+	}
+
+	void Bitmap::WriteData(aiTexture* texture, IOStream* file) {
+		static const std::size_t padding_offset = 4;
+		static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0};
+
+		unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset;
+		uint8_t pixel[mBytesPerPixel];
+
+		for(std::size_t i = 0; i < texture->mHeight; ++i) {
+			for(std::size_t j = 0; j < texture->mWidth; ++j) {
+				const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format
+
+				pixel[0] = texel.r;
+				pixel[1] = texel.g;
+				pixel[2] = texel.b;
+				pixel[3] = texel.a;
+
+				file->Write(pixel, mBytesPerPixel, 1);
+			}
+
+			file->Write(padding_data, padding, 1);
+		}
+	}
+
+}

+ 139 - 0
Source/ThirdParty/Assimp/code/Bitmap.h

@@ -0,0 +1,139 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+/** @file Bitmap.h
+ *  @brief Defines bitmap format helper for textures
+ *
+ * Used for file formats which embed their textures into the model file.
+ */
+
+#ifndef AI_BITMAP_H_INC
+#define AI_BITMAP_H_INC
+
+namespace Assimp {
+
+class Bitmap {
+
+	protected:
+
+		struct Header {
+
+			uint16_t type;
+
+			uint32_t size;
+
+			uint16_t reserved1;
+
+			uint16_t reserved2;
+
+			uint32_t offset;
+
+			// We define the struct size because sizeof(Header) might return a wrong result because of structure padding.
+			// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
+			static const std::size_t header_size =
+				sizeof(uint16_t) + // type
+				sizeof(uint32_t) + // size
+				sizeof(uint16_t) + // reserved1
+				sizeof(uint16_t) + // reserved2
+				sizeof(uint32_t);  // offset
+
+		};
+
+		struct DIB {
+
+			uint32_t size;
+
+			int32_t width;
+
+			int32_t height;
+
+			uint16_t planes;
+
+			uint16_t bits_per_pixel;
+
+			uint32_t compression;
+
+			uint32_t image_size;
+
+			int32_t x_resolution;
+
+			int32_t y_resolution;
+
+			uint32_t nb_colors;
+
+			uint32_t nb_important_colors;
+
+			// We define the struct size because sizeof(DIB) might return a wrong result because of structure padding.
+			// Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field).
+			static const std::size_t dib_size =
+				sizeof(uint32_t) + // size
+				sizeof(int32_t) +  // width
+				sizeof(int32_t) +  // height
+				sizeof(uint16_t) + // planes
+				sizeof(uint16_t) + // bits_per_pixel
+				sizeof(uint32_t) + // compression
+				sizeof(uint32_t) + // image_size
+				sizeof(int32_t) +  // x_resolution
+				sizeof(int32_t) +  // y_resolution
+				sizeof(uint32_t) + // nb_colors
+				sizeof(uint32_t);  // nb_important_colors
+
+		};
+
+		static const std::size_t mBytesPerPixel = 4;
+
+	public:
+
+		static void Save(aiTexture* texture, IOStream* file);
+
+	protected:
+
+		static void WriteHeader(Header& header, IOStream* file);
+
+		static void WriteDIB(DIB& dib, IOStream* file);
+
+		static void WriteData(aiTexture* texture, IOStream* file);
+
+};
+
+}
+
+#endif // AI_BITMAP_H_INC

+ 2 - 2
Source/ThirdParty/Assimp/code/BlenderBMesh.cpp

@@ -109,11 +109,11 @@ void BlenderBMeshConverter::AssertValidMesh( )
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 void BlenderBMeshConverter::AssertValidSizes( )
 void BlenderBMeshConverter::AssertValidSizes( )
 {
 {
-	if ( BMesh->totpoly != BMesh->mpoly.size( ) )
+	if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) )
 	{
 	{
 		ThrowException( "BMesh poly array has incorrect size" );
 		ThrowException( "BMesh poly array has incorrect size" );
 	}
 	}
-	if ( BMesh->totloop != BMesh->mloop.size( ) )
+	if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) )
 	{
 	{
 		ThrowException( "BMesh loop array has incorrect size" );
 		ThrowException( "BMesh loop array has incorrect size" );
 	}
 	}

+ 1 - 1
Source/ThirdParty/Assimp/code/BlenderDNA.h

@@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "TinyFormatter.h"
 #include "TinyFormatter.h"
 
 
 // enable verbose log output. really verbose, so be careful.
 // enable verbose log output. really verbose, so be careful.
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 #	define ASSIMP_BUILD_BLENDER_DEBUG
 #	define ASSIMP_BUILD_BLENDER_DEBUG
 #endif
 #endif
 
 

+ 9 - 0
Source/ThirdParty/Assimp/code/BlenderModifier.cpp

@@ -248,6 +248,15 @@ void  BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data,  co
 			}
 			}
 		}
 		}
 
 
+		// Only reverse the winding order if an odd number of axes were mirrored.
+		if (xs * ys * zs < 0) {
+			for( unsigned int i = 0; i < mesh->mNumFaces; i++) {
+				aiFace& face = mesh->mFaces[i];
+				for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi)
+					std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]);
+			}
+		}
+
 		conv_data.meshes->push_back(mesh);
 		conv_data.meshes->push_back(mesh);
 	}
 	}
 	unsigned int* nind = new unsigned int[out.mNumMeshes*2];
 	unsigned int* nind = new unsigned int[out.mNumMeshes*2];

+ 1 - 8
Source/ThirdParty/Assimp/code/BlenderScene.cpp

@@ -251,10 +251,7 @@ template <> void Structure :: Convert<Base> (
 	const int initial_pos = db.reader->GetCurrentPos();
 	const int initial_pos = db.reader->GetCurrentPos();
 
 
 	std::pair<Base*, int> todo = std::make_pair(&dest, initial_pos);
 	std::pair<Base*, int> todo = std::make_pair(&dest, initial_pos);
-
-	Base* saved_prev = NULL;
-
-	while(true) {
+	for ( ;; ) {
 	
 	
 		Base& cur_dest = *todo.first;
 		Base& cur_dest = *todo.first;
 		db.reader->SetCurrentPos(todo.second);
 		db.reader->SetCurrentPos(todo.second);
@@ -265,10 +262,6 @@ template <> void Structure :: Convert<Base> (
 
 
 		ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object,"*object",db);
 		ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object,"*object",db);
 
 
-		// just record the offset of the blob data and allocate storage.
-		// Does _not_ invoke Convert() recursively.
-		const int old = db.reader->GetCurrentPos();
-
 		// the return value of ReadFieldPtr indicates whether the object 
 		// the return value of ReadFieldPtr indicates whether the object 
 		// was already cached. In this case, we don't need to resolve
 		// was already cached. In this case, we don't need to resolve
 		// it again.
 		// it again.

+ 3 - 3
Source/ThirdParty/Assimp/code/BlenderTessellator.cpp

@@ -51,11 +51,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BlenderBMesh.h"
 #include "BlenderBMesh.h"
 #include "BlenderTessellator.h"
 #include "BlenderTessellator.h"
 
 
-#define BLEND_TESS_MAGIC ( 0x83ed9ac3 )
+static const unsigned int BLEND_TESS_MAGIC = 0x83ed9ac3;
 
 
 #if ASSIMP_BLEND_WITH_GLU_TESSELLATE
 #if ASSIMP_BLEND_WITH_GLU_TESSELLATE
 
 
-namespace Assimp
+namspace Assimp
 {
 {
 	template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
 	template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: ";
 }
 }
@@ -382,7 +382,7 @@ inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& poi
 {
 {
 	unsigned int pointOffset = OffsetOf( PointP2T, point2D );
 	unsigned int pointOffset = OffsetOf( PointP2T, point2D );
 	PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
 	PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset );
-	if ( pointStruct.magic != BLEND_TESS_MAGIC )
+	if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) )
 	{
 	{
 		ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" );
 		ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" );
 	}
 	}

+ 1 - 1
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/shared_array.hpp

@@ -2,7 +2,7 @@
 #ifndef INCLUDED_AI_BOOST_SHARED_ARRAY
 #ifndef INCLUDED_AI_BOOST_SHARED_ARRAY
 #define INCLUDED_AI_BOOST_SHARED_ARRAY
 #define INCLUDED_AI_BOOST_SHARED_ARRAY
 
 
-#ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED
+#ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED
 
 
 // ------------------------------
 // ------------------------------
 // Internal stub
 // Internal stub

+ 2 - 2
Source/ThirdParty/Assimp/code/BoostWorkaround/boost/shared_ptr.hpp

@@ -2,7 +2,7 @@
 #ifndef INCLUDED_AI_BOOST_SHARED_PTR
 #ifndef INCLUDED_AI_BOOST_SHARED_PTR
 #define INCLUDED_AI_BOOST_SHARED_PTR
 #define INCLUDED_AI_BOOST_SHARED_PTR
 
 
-#ifndef BOOST_SCOPED_PTR_HPP_INCLUDED
+#ifndef BOOST_SHARED_PTR_HPP_INCLUDED
 
 
 // ------------------------------
 // ------------------------------
 // Internal stub
 // Internal stub
@@ -254,4 +254,4 @@ inline shared_ptr<T> const_pointer_cast( shared_ptr<U> ptr)
 #else
 #else
 #	error "shared_ptr.h was already included"
 #	error "shared_ptr.h was already included"
 #endif
 #endif
-#endif // INCLUDED_AI_BOOST_SCOPED_PTR
+#endif // INCLUDED_AI_BOOST_SHARED_PTR

+ 40 - 14
Source/ThirdParty/Assimp/code/CalcTangentsProcess.cpp

@@ -55,8 +55,9 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 CalcTangentsProcess::CalcTangentsProcess()
 CalcTangentsProcess::CalcTangentsProcess()
-{
-	this->configMaxAngle = AI_DEG_TO_RAD(45.f);
+: configMaxAngle( AI_DEG_TO_RAD(45.f) )
+, configSourceUV( 0 ) {
+	// nothing to do here
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -77,6 +78,8 @@ bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
 // Executes the post processing step on the given imported data.
 // Executes the post processing step on the given imported data.
 void CalcTangentsProcess::SetupProperties(const Importer* pImp)
 void CalcTangentsProcess::SetupProperties(const Importer* pImp)
 {
 {
+    ai_assert( NULL != pImp );
+
 	// get the current value of the property
 	// get the current value of the property
 	configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
 	configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
 	configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f);
 	configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f);
@@ -89,14 +92,20 @@ void CalcTangentsProcess::SetupProperties(const Importer* pImp)
 // Executes the post processing step on the given imported data.
 // Executes the post processing step on the given imported data.
 void CalcTangentsProcess::Execute( aiScene* pScene)
 void CalcTangentsProcess::Execute( aiScene* pScene)
 {
 {
-	DefaultLogger::get()->debug("CalcTangentsProcess begin");
+    ai_assert( NULL != pScene );
+
+    DefaultLogger::get()->debug("CalcTangentsProcess begin");
 
 
 	bool bHas = false;
 	bool bHas = false;
-	for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
+	for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
 		if(ProcessMesh( pScene->mMeshes[a],a))bHas = true;
 		if(ProcessMesh( pScene->mMeshes[a],a))bHas = true;
+    }
 
 
-	if (bHas)DefaultLogger::get()->info("CalcTangentsProcess finished. Tangents have been calculated");
-	else DefaultLogger::get()->debug("CalcTangentsProcess finished");
+	if ( bHas ) {
+        DefaultLogger::get()->info("CalcTangentsProcess finished. Tangents have been calculated");
+    } else {
+        DefaultLogger::get()->debug("CalcTangentsProcess finished");
+    }
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -179,9 +188,14 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
 		float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
 		float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y;
         float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
         float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
 		float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
 		float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
-
-		// tangent points in the direction where to positive X axis of the texture coords would point in model space
-		// bitangents points along the positive Y axis of the texture coords, respectively
+        // when t1, t2, t3 in same position in UV space, just use default UV direction.
+        if ( 0 == sx && 0 ==sy && 0 == tx && 0 == ty ) {
+            sx = 0.0; sy = 1.0;
+            tx = 1.0; ty = 0.0;
+        }
+
+		// tangent points in the direction where to positive X axis of the texture coord's would point in model space
+		// bitangent's points along the positive Y axis of the texture coord's, respectively
 		aiVector3D tangent, bitangent;
 		aiVector3D tangent, bitangent;
 		tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
 		tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
         tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
         tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
@@ -191,8 +205,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
         bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
         bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
 
 
 		// store for every vertex of that face
 		// store for every vertex of that face
-		for( unsigned int b = 0; b < face.mNumIndices; b++)
-		{
+		for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
 			unsigned int p = face.mIndices[b];
 			unsigned int p = face.mIndices[b];
 
 
 			// project tangent and bitangent into the plane formed by the vertex' normal
 			// project tangent and bitangent into the plane formed by the vertex' normal
@@ -200,9 +213,22 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
 			aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
 			aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
 			localTangent.Normalize(); localBitangent.Normalize();
 			localTangent.Normalize(); localBitangent.Normalize();
 
 
-			// and write it into the mesh.
-			meshTang[p] = localTangent;
-			meshBitang[p] = localBitangent;
+            // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
+            bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z);
+            bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z);
+            if (invalid_tangent != invalid_bitangent) {
+                if (invalid_tangent) {
+                    localTangent = meshNorm[p] ^ localBitangent;
+                    localTangent.Normalize();
+                } else {
+                    localBitangent = localTangent ^ meshNorm[p]; 
+                    localBitangent.Normalize();
+                }
+            }
+
+            // and write it into the mesh.
+			meshTang[ p ]   = localTangent;
+			meshBitang[ p ] = localBitangent;
 		}
 		}
     }
     }
 
 

+ 263 - 55
Source/ThirdParty/Assimp/code/ColladaExporter.cpp

@@ -44,6 +44,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
 #include "ColladaExporter.h"
 #include "ColladaExporter.h"
 
 
+#include "Bitmap.h"
+#include "fast_atof.h"
+#include "SceneCombiner.h" 
+
+#include <ctime>
+#include <set>
+
 using namespace Assimp;
 using namespace Assimp;
 
 
 namespace Assimp
 namespace Assimp
@@ -53,8 +60,25 @@ namespace Assimp
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
 // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp
 void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
 void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene)
 {
 {
+	std::string path = "";
+	std::string file = pFile;
+
+	// We need to test both types of folder separators because pIOSystem->getOsSeparator() is not reliable.
+	// Moreover, the path given by some applications is not even consistent with the OS specific type of separator.
+	const char* end_path = std::max(strrchr(pFile, '\\'), strrchr(pFile, '/'));
+
+	if(end_path != NULL) {
+		path = std::string(pFile, end_path + 1 - pFile);
+		file = file.substr(end_path + 1 - pFile, file.npos);
+
+		std::size_t pos = file.find_last_of('.');
+		if(pos != file.npos) {
+			file = file.substr(0, pos);
+		}
+	}
+
 	// invoke the exporter 
 	// invoke the exporter 
-	ColladaExporter iDoTheExportThing( pScene);
+	ColladaExporter iDoTheExportThing( pScene, pIOSystem, path, file);
 
 
 	// we're still here - export successfully completed. Write result to the given IOSYstem
 	// we're still here - export successfully completed. Write result to the given IOSYstem
 	boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
 	boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt"));
@@ -71,12 +95,13 @@ void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pS
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor for a specific scene to export
 // Constructor for a specific scene to export
-ColladaExporter::ColladaExporter( const aiScene* pScene)
+ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file)
 {
 {
 	// make sure that all formatting happens using the standard, C locale and not the user's current locale
 	// make sure that all formatting happens using the standard, C locale and not the user's current locale
 	mOutput.imbue( std::locale("C") );
 	mOutput.imbue( std::locale("C") );
 
 
 	mScene = pScene;
 	mScene = pScene;
+	mSceneOwned = false;
 
 
 	// set up strings
 	// set up strings
 	endstr = "\n"; 
 	endstr = "\n"; 
@@ -85,6 +110,15 @@ ColladaExporter::ColladaExporter( const aiScene* pScene)
 	WriteFile();
 	WriteFile();
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Destructor
+ColladaExporter::~ColladaExporter()
+{
+	if(mSceneOwned) {
+		delete mScene;
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Starts writing the contents
 // Starts writing the contents
 void ColladaExporter::WriteFile()
 void ColladaExporter::WriteFile()
@@ -95,9 +129,10 @@ void ColladaExporter::WriteFile()
 	mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
 	mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr;
 	PushTag();
 	PushTag();
 
 
+	WriteTextures();
 	WriteHeader();
 	WriteHeader();
 
 
-  WriteMaterials();
+	WriteMaterials();
 	WriteGeometryLibrary();
 	WriteGeometryLibrary();
 
 
 	WriteSceneLibrary();
 	WriteSceneLibrary();
@@ -105,7 +140,7 @@ void ColladaExporter::WriteFile()
 	// useless Collada fu at the end, just in case we haven't had enough indirections, yet. 
 	// useless Collada fu at the end, just in case we haven't had enough indirections, yet. 
 	mOutput << startstr << "<scene>" << endstr;
 	mOutput << startstr << "<scene>" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<instance_visual_scene url=\"#myScene\" />" << endstr;
+	mOutput << startstr << "<instance_visual_scene url=\"#" + std::string(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr;
 	PopTag();
 	PopTag();
 	mOutput << startstr << "</scene>" << endstr;
 	mOutput << startstr << "</scene>" << endstr;
 	PopTag();
 	PopTag();
@@ -116,23 +151,131 @@ void ColladaExporter::WriteFile()
 // Writes the asset header
 // Writes the asset header
 void ColladaExporter::WriteHeader()
 void ColladaExporter::WriteHeader()
 {
 {
-	// Dummy stuff. Nobody actually cares for it anyways
+	static const float epsilon = 0.000001f;
+	static const aiQuaternion x_rot(aiMatrix3x3( 
+		0, -1,  0,
+		1,  0,  0,
+		0,  0,  1));
+	static const aiQuaternion y_rot(aiMatrix3x3(
+		1,  0,  0,
+		0,  1,  0,
+		0,  0,  1));
+	static const aiQuaternion z_rot(aiMatrix3x3(
+		1,  0,  0,
+		0,  0,  1,
+		0, -1,  0));
+
+	static const unsigned int date_nb_chars = 20;
+	char date_str[date_nb_chars];
+	std::time_t date = std::time(NULL);
+	std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date));
+
+	std::string scene_name = mScene->mRootNode->mName.C_Str();
+
+	aiVector3D scaling;
+	aiQuaternion rotation;
+	aiVector3D position;
+	mScene->mRootNode->mTransformation.Decompose(scaling, rotation, position);
+
+	bool add_root_node = false;
+
+	float scale = 1.0;
+	if(std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) {
+		scale = (float) ((((double) scaling.x) + ((double) scaling.y) + ((double) scaling.z)) / 3.0);
+	} else {
+		add_root_node = true;
+	}
+
+	std::string up_axis = "Y_UP";
+	if(rotation.Equal(x_rot, epsilon)) {
+		up_axis = "X_UP";
+	} else if(rotation.Equal(y_rot, epsilon)) {
+		up_axis = "Y_UP";
+	} else if(rotation.Equal(z_rot, epsilon)) {
+		up_axis = "Z_UP";
+	} else {
+		add_root_node = true;
+	}
+
+	if(! position.Equal(aiVector3D(0, 0, 0))) {
+		add_root_node = true;
+	}
+
+	if(mScene->mRootNode->mNumChildren == 0) {
+		add_root_node = true;
+	}
+
+	if(add_root_node) {
+		aiScene* scene;
+		SceneCombiner::CopyScene(&scene, mScene);
+
+		aiNode* root = new aiNode("Scene");
+
+		root->mNumChildren = 1;
+		root->mChildren = new aiNode*[root->mNumChildren];
+
+		root->mChildren[0] = scene->mRootNode;
+		scene->mRootNode->mParent = root;
+		scene->mRootNode = root;
+
+		mScene = scene;
+		mSceneOwned = true;
+
+		up_axis = "Y_UP";
+		scale = 1.0;
+	}
+
 	mOutput << startstr << "<asset>" << endstr;
 	mOutput << startstr << "<asset>" << endstr;
 	PushTag();
 	PushTag();
 	mOutput << startstr << "<contributor>" << endstr;
 	mOutput << startstr << "<contributor>" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<author>Someone</author>" << endstr;
+	mOutput << startstr << "<author>Assimp</author>" << endstr;
 	mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr;
 	mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr;
 	PopTag();
 	PopTag();
 	mOutput << startstr << "</contributor>" << endstr;
 	mOutput << startstr << "</contributor>" << endstr;
-  mOutput << startstr << "<created>2000-01-01T23:59:59</created>" << endstr;
-  mOutput << startstr << "<modified>2000-01-01T23:59:59</modified>" << endstr;
-	mOutput << startstr << "<unit name=\"centimeter\" meter=\"0.01\" />" << endstr;
-	mOutput << startstr << "<up_axis>Y_UP</up_axis>" << endstr;
+	mOutput << startstr << "<created>" << date_str << "</created>" << endstr;
+	mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr;
+	mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr;
+	mOutput << startstr << "<up_axis>" << up_axis << "</up_axis>" << endstr;
 	PopTag();
 	PopTag();
 	mOutput << startstr << "</asset>" << endstr;
 	mOutput << startstr << "</asset>" << endstr;
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Write the embedded textures
+void ColladaExporter::WriteTextures() {
+	static const unsigned int buffer_size = 1024;
+	char str[buffer_size];
+
+	if(mScene->HasTextures()) {
+		for(unsigned int i = 0; i < mScene->mNumTextures; i++) {
+			// It would be great to be able to create a directory in portable standard C++, but it's not the case,
+			// so we just write the textures in the current directory.
+
+			aiTexture* texture = mScene->mTextures[i];
+
+			ASSIMP_itoa10(str, buffer_size, i + 1);
+
+			std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint);
+
+			boost::scoped_ptr<IOStream> outfile(mIOSystem->Open(mPath + name, "wb"));
+			if(outfile == NULL) {
+				throw DeadlyExportError("could not open output texture file: " + mPath + name);
+			}
+
+			if(texture->mHeight == 0) {
+				outfile->Write((void*) texture->pcData, texture->mWidth, 1);
+			} else {
+				Bitmap::Save(texture, outfile.get());
+			}
+
+			outfile->Flush();
+
+			textures.insert(std::make_pair(i, name));
+		}
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Reads a single surface entry from the given material keys
 // Reads a single surface entry from the given material keys
 void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex)
 void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex)
@@ -142,12 +285,39 @@ void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial*
     aiString texfile;
     aiString texfile;
     unsigned int uvChannel = 0;
     unsigned int uvChannel = 0;
     pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel);
     pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel);
-    poSurface.texture = texfile.C_Str();
+
+    std::string index_str(texfile.C_Str());
+
+    if(index_str.size() != 0 && index_str[0] == '*')
+    {
+		unsigned int index;
+
+    	index_str = index_str.substr(1, std::string::npos);
+
+    	try {
+    		index = (unsigned int) strtoul10_64(index_str.c_str());
+    	} catch(std::exception& error) {
+    		throw DeadlyExportError(error.what());
+    	}
+
+    	std::map<unsigned int, std::string>::const_iterator name = textures.find(index);
+
+    	if(name != textures.end()) {
+    		poSurface.texture = name->second;
+    	} else {
+    		throw DeadlyExportError("could not find embedded texture at index " + index_str);
+    	}
+    } else
+    {
+		poSurface.texture = texfile.C_Str();
+    }
+
     poSurface.channel = uvChannel;
     poSurface.channel = uvChannel;
+	poSurface.exist = true;
   } else
   } else
   {
   {
     if( pKey )
     if( pKey )
-      pSrcMat->Get( pKey, pType, pIndex, poSurface.color);
+      poSurface.exist = pSrcMat->Get( pKey, pType, pIndex, poSurface.color) == aiReturn_SUCCESS;
   }
   }
 }
 }
 
 
@@ -177,17 +347,19 @@ void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::strin
 // Writes a color-or-texture entry into an effect definition
 // Writes a color-or-texture entry into an effect definition
 void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName)
 void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName)
 {
 {
-  mOutput << startstr << "<" << pTypeName << ">" << endstr;
-  PushTag();
-  if( pSurface.texture.empty() )
-  {
-    mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
-  } else
-  {
-    mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
+  if(pSurface.exist) {
+    mOutput << startstr << "<" << pTypeName << ">" << endstr;
+    PushTag();
+    if( pSurface.texture.empty() )
+    {
+      mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << "   " << pSurface.color.g << "   " << pSurface.color.b << "   " << pSurface.color.a << "</color>" << endstr;
+    } else
+    {
+      mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
+    }
+    PopTag();
+    mOutput << startstr << "</" << pTypeName << ">" << endstr;
   }
   }
-  PopTag();
-  mOutput << startstr << "</" << pTypeName << ">" << endstr;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -219,12 +391,27 @@ void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std
   }
   }
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Writes a scalar property
+void ColladaExporter::WriteFloatEntry( const Property& pProperty, const std::string& pTypeName)
+{
+	if(pProperty.exist) {
+		mOutput << startstr << "<" << pTypeName << ">" << endstr;
+		PushTag();
+		mOutput << startstr << "<float sid=\"" << pTypeName << "\">" << pProperty.value << "</float>" << endstr;
+		PopTag();
+		mOutput << startstr << "</" << pTypeName << ">" << endstr;
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Writes the material setup
 // Writes the material setup
 void ColladaExporter::WriteMaterials()
 void ColladaExporter::WriteMaterials()
 {
 {
   materials.resize( mScene->mNumMaterials);
   materials.resize( mScene->mNumMaterials);
 
 
+  std::set<std::string> material_names;
+
   /// collect all materials from the scene
   /// collect all materials from the scene
   size_t numTextures = 0;
   size_t numTextures = 0;
   for( size_t a = 0; a < mScene->mNumMaterials; ++a )
   for( size_t a = 0; a < mScene->mNumMaterials; ++a )
@@ -233,16 +420,30 @@ void ColladaExporter::WriteMaterials()
 
 
     aiString name;
     aiString name;
     if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS )
     if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS )
-      name = "mat";
+      name = "mat";
     materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str();
     materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str();
     for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) {
     for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) {
 		// isalnum on MSVC asserts for code points in [0,255]. Thus prevent unwanted promotion
 		// isalnum on MSVC asserts for code points in [0,255]. Thus prevent unwanted promotion
 		// of char to signed int and take the unsigned char value.
 		// of char to signed int and take the unsigned char value.
-      if( !isalnum( static_cast<uint8_t>(*it) ) ) {
+      if( !isalnum( static_cast<uint8_t>(*it) ) ) {
         *it = '_';
         *it = '_';
 	  }
 	  }
 	}
 	}
 
 
+	aiShadingMode shading;
+	materials[a].shading_model = "phong";
+	if(mat->Get( AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) {
+		if(shading == aiShadingMode_Phong) {
+			materials[a].shading_model = "phong";
+		} else if(shading == aiShadingMode_Blinn) {
+			materials[a].shading_model = "blinn";
+		} else if(shading == aiShadingMode_NoShading) {
+			materials[a].shading_model = "constant";
+		} else if(shading == aiShadingMode_Gouraud) {
+			materials[a].shading_model = "lambert";
+		}
+	}
+
     ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
     ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT);
     if( !materials[a].ambient.texture.empty() ) numTextures++;
     if( !materials[a].ambient.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
     ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE);
@@ -253,10 +454,15 @@ void ColladaExporter::WriteMaterials()
     if( !materials[a].emissive.texture.empty() ) numTextures++;
     if( !materials[a].emissive.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE);
     ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE);
     if( !materials[a].reflective.texture.empty() ) numTextures++;
     if( !materials[a].reflective.texture.empty() ) numTextures++;
+	ReadMaterialSurface( materials[a].transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT);
+    if( !materials[a].transparent.texture.empty() ) numTextures++;
     ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0);
     ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0);
     if( !materials[a].normal.texture.empty() ) numTextures++;
     if( !materials[a].normal.texture.empty() ) numTextures++;
 
 
-    mat->Get( AI_MATKEY_SHININESS, materials[a].shininess);
+	materials[a].shininess.exist = mat->Get( AI_MATKEY_SHININESS, materials[a].shininess.value) == aiReturn_SUCCESS;
+	materials[a].transparency.exist = mat->Get( AI_MATKEY_OPACITY, materials[a].transparency.value) == aiReturn_SUCCESS;
+	materials[a].transparency.value = 1 - materials[a].transparency.value;
+	materials[a].index_refraction.exist = mat->Get( AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS;
   }
   }
 
 
   // output textures if present
   // output textures if present
@@ -270,8 +476,9 @@ void ColladaExporter::WriteMaterials()
       WriteImageEntry( mat.ambient, mat.name + "-ambient-image");
       WriteImageEntry( mat.ambient, mat.name + "-ambient-image");
       WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image");
       WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image");
       WriteImageEntry( mat.specular, mat.name + "-specular-image");
       WriteImageEntry( mat.specular, mat.name + "-specular-image");
-      WriteImageEntry( mat.emissive, mat.name + "-emissive-image");
+      WriteImageEntry( mat.emissive, mat.name + "-emission-image");
       WriteImageEntry( mat.reflective, mat.name + "-reflective-image");
       WriteImageEntry( mat.reflective, mat.name + "-reflective-image");
+	  WriteImageEntry( mat.transparent, mat.name + "-transparent-image");
       WriteImageEntry( mat.normal, mat.name + "-normal-image");
       WriteImageEntry( mat.normal, mat.name + "-normal-image");
     }
     }
     PopTag();
     PopTag();
@@ -293,37 +500,35 @@ void ColladaExporter::WriteMaterials()
       PushTag();
       PushTag();
 
 
       // write sampler- and surface params for the texture entries
       // write sampler- and surface params for the texture entries
-      WriteTextureParamEntry( mat.emissive, "emissive", mat.name);
+      WriteTextureParamEntry( mat.emissive, "emission", mat.name);
       WriteTextureParamEntry( mat.ambient, "ambient", mat.name);
       WriteTextureParamEntry( mat.ambient, "ambient", mat.name);
       WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name);
       WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name);
       WriteTextureParamEntry( mat.specular, "specular", mat.name);
       WriteTextureParamEntry( mat.specular, "specular", mat.name);
       WriteTextureParamEntry( mat.reflective, "reflective", mat.name);
       WriteTextureParamEntry( mat.reflective, "reflective", mat.name);
+	  WriteTextureParamEntry( mat.transparent, "transparent", mat.name);
+	  WriteTextureParamEntry( mat.normal, "normal", mat.name);
 
 
       mOutput << startstr << "<technique sid=\"standard\">" << endstr;
       mOutput << startstr << "<technique sid=\"standard\">" << endstr;
       PushTag();
       PushTag();
-      mOutput << startstr << "<phong>" << endstr;
+	  mOutput << startstr << "<" << mat.shading_model << ">" << endstr;
       PushTag();
       PushTag();
 
 
-      WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emissive-sampler");
+      WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emission-sampler");
       WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "-ambient-sampler");
       WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "-ambient-sampler");
       WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler");
       WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler");
       WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-sampler");
       WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-sampler");
-
-      mOutput << startstr << "<shininess>" << endstr;
-      PushTag();
-      mOutput << startstr << "<float sid=\"shininess\">" << mat.shininess << "</float>" << endstr;
-      PopTag();
-      mOutput << startstr << "</shininess>" << endstr;
-
+	  WriteFloatEntry(mat.shininess, "shininess");
       WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "-reflective-sampler");
       WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "-reflective-sampler");
+	  WriteTextureColorEntry( mat.transparent, "transparent", mat.name + "-transparent-sampler");
+	  WriteFloatEntry(mat.transparency, "transparency");
+	  WriteFloatEntry(mat.index_refraction, "index_of_refraction");
 
 
-  // deactivated because the Collada spec PHONG model does not allow other textures.
-  //    if( !mat.normal.texture.empty() )
-  //      WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler");
-
+	  if(! mat.normal.texture.empty()) {
+		WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler");
+	  }
 
 
       PopTag();
       PopTag();
-      mOutput << startstr << "</phong>" << endstr;
+      mOutput << startstr << "</" << mat.shading_model << ">" << endstr;
       PopTag();
       PopTag();
       mOutput << startstr << "</technique>" << endstr;
       mOutput << startstr << "</technique>" << endstr;
       PopTag();
       PopTag();
@@ -546,13 +751,16 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
 // Writes the scene library
 // Writes the scene library
 void ColladaExporter::WriteSceneLibrary()
 void ColladaExporter::WriteSceneLibrary()
 {
 {
+	std::string scene_name = mScene->mRootNode->mName.C_Str();
+
 	mOutput << startstr << "<library_visual_scenes>" << endstr;
 	mOutput << startstr << "<library_visual_scenes>" << endstr;
 	PushTag();
 	PushTag();
-	mOutput << startstr << "<visual_scene id=\"myScene\" name=\"myScene\">" << endstr;
+	mOutput << startstr << "<visual_scene id=\"" + scene_name + "\" name=\"" + scene_name + "\">" << endstr;
 	PushTag();
 	PushTag();
 
 
 	// start recursive write at the root node
 	// start recursive write at the root node
-	WriteNode( mScene->mRootNode);
+	for( size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a )
+		WriteNode( mScene->mRootNode->mChildren[a]);
 
 
 	PopTag();
 	PopTag();
 	mOutput << startstr << "</visual_scene>" << endstr;
 	mOutput << startstr << "</visual_scene>" << endstr;
@@ -581,22 +789,22 @@ void ColladaExporter::WriteNode( const aiNode* pNode)
 	for( size_t a = 0; a < pNode->mNumMeshes; ++a )
 	for( size_t a = 0; a < pNode->mNumMeshes; ++a )
 	{
 	{
 		const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]];
 		const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]];
-    // do not instanciate mesh if empty. I wonder how this could happen
-    if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
-      continue;
+	// do not instanciate mesh if empty. I wonder how this could happen
+	if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
+		continue;
 
 
 		mOutput << startstr << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr;
 		mOutput << startstr << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr;
 		PushTag();
 		PushTag();
-    mOutput << startstr << "<bind_material>" << endstr;
-    PushTag();
-    mOutput << startstr << "<technique_common>" << endstr;
-    PushTag();
-    mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr;
+	mOutput << startstr << "<bind_material>" << endstr;
+	PushTag();
+	mOutput << startstr << "<technique_common>" << endstr;
+	PushTag();
+	mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr;
 		PopTag();
 		PopTag();
-    mOutput << startstr << "</technique_common>" << endstr;
-    PopTag();
-    mOutput << startstr << "</bind_material>" << endstr;
-    PopTag();
+	mOutput << startstr << "</technique_common>" << endstr;
+	PopTag();
+	mOutput << startstr << "</bind_material>" << endstr;
+	PopTag();
 		mOutput << startstr << "</instance_geometry>" << endstr;
 		mOutput << startstr << "</instance_geometry>" << endstr;
 	}
 	}
 
 

+ 36 - 7
Source/ThirdParty/Assimp/code/ColladaExporter.h

@@ -59,7 +59,10 @@ class ColladaExporter
 {
 {
 public:
 public:
 	/// Constructor for a specific scene to export
 	/// Constructor for a specific scene to export
-	ColladaExporter( const aiScene* pScene);
+	ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file);
+
+	/// Destructor
+	virtual ~ColladaExporter();
 
 
 protected:
 protected:
 	/// Starts writing the contents
 	/// Starts writing the contents
@@ -68,8 +71,11 @@ protected:
 	/// Writes the asset header
 	/// Writes the asset header
 	void WriteHeader();
 	void WriteHeader();
 
 
-  /// Writes the material setup
-  void WriteMaterials();
+	/// Writes the embedded textures
+	void WriteTextures();
+
+	/// Writes the material setup
+	void WriteMaterials();
 
 
 	/// Writes the geometry library
 	/// Writes the geometry library
 	void WriteGeometryLibrary();
 	void WriteGeometryLibrary();
@@ -101,8 +107,18 @@ public:
 	std::stringstream mOutput;
 	std::stringstream mOutput;
 
 
 protected:
 protected:
+	/// The IOSystem for output
+	IOSystem* mIOSystem;
+
+	/// Path of the directory where the scene will be exported
+	const std::string mPath;
+
+	/// Name of the file (without extension) where the scene will be exported
+	const std::string mFile;
+
 	/// The scene to be written
 	/// The scene to be written
 	const aiScene* mScene;
 	const aiScene* mScene;
+	bool mSceneOwned;
 
 
 	/// current line start string, contains the current indentation for simple stream insertion
 	/// current line start string, contains the current indentation for simple stream insertion
 	std::string startstr;
 	std::string startstr;
@@ -112,24 +128,35 @@ protected:
   // pair of color and texture - texture precedences color
   // pair of color and texture - texture precedences color
   struct Surface 
   struct Surface 
   { 
   { 
+    bool exist;
     aiColor4D color; 
     aiColor4D color; 
     std::string texture; 
     std::string texture; 
     size_t channel; 
     size_t channel; 
-    Surface() { channel = 0; }
+    Surface() { exist = false; channel = 0; }
+  };
+
+  struct Property
+  {
+    bool exist;
+	float value;
+	Property() { exist = false; }
   };
   };
 
 
   // summarize a material in an convinient way. 
   // summarize a material in an convinient way. 
   struct Material
   struct Material
   {
   {
     std::string name;
     std::string name;
-    Surface ambient, diffuse, specular, emissive, reflective, normal;
-    float shininess; /// specular exponent
+    std::string shading_model;
+    Surface ambient, diffuse, specular, emissive, reflective, transparent, normal;
+   	Property shininess, transparency, index_refraction;
 
 
-    Material() { shininess = 16.0f; }
+    Material() {}
   };
   };
 
 
   std::vector<Material> materials;
   std::vector<Material> materials;
 
 
+  std::map<unsigned int, std::string> textures;
+
 protected:
 protected:
   /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
   /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions
   /// Reads a single surface entry from the given material keys
   /// Reads a single surface entry from the given material keys
@@ -140,6 +167,8 @@ protected:
   void WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName);
   void WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName);
   /// Writes a color-or-texture entry into an effect definition
   /// Writes a color-or-texture entry into an effect definition
   void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName);
   void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName);
+  /// Writes a scalar property
+  void WriteFloatEntry( const Property& pProperty, const std::string& pTypeName);
 };
 };
 
 
 }
 }

+ 1 - 1
Source/ThirdParty/Assimp/code/ComputeUVMappingProcess.cpp

@@ -380,7 +380,7 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-void ComputeUVMappingProcess::ComputeBoxMapping(aiMesh* /*mesh*/, aiVector3D* /*out*/)
+void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* )
 {
 {
 	DefaultLogger::get()->error("Mapping type currently not implemented");
 	DefaultLogger::get()->error("Mapping type currently not implemented");
 }
 }

+ 4 - 4
Source/ThirdParty/Assimp/code/DefaultLogger.cpp

@@ -253,7 +253,7 @@ void DefaultLogger::OnDebug( const char* message )
 	if ( m_Severity == Logger::NORMAL )
 	if ( m_Severity == Logger::NORMAL )
 		return;
 		return;
 
 
-	char msg[MAX_LOG_MESSAGE_LENGTH*2];
+	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
 	::sprintf(msg,"Debug, T%i: %s", GetThreadID(), message );
 	::sprintf(msg,"Debug, T%i: %s", GetThreadID(), message );
 
 
 	WriteToStreams( msg, Logger::Debugging );
 	WriteToStreams( msg, Logger::Debugging );
@@ -263,7 +263,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 )
 {
 {
-	char msg[MAX_LOG_MESSAGE_LENGTH*2];
+	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
 	::sprintf(msg,"Info,  T%i: %s", GetThreadID(), message );
 	::sprintf(msg,"Info,  T%i: %s", GetThreadID(), message );
 
 
 	WriteToStreams( msg , Logger::Info );
 	WriteToStreams( msg , Logger::Info );
@@ -273,7 +273,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 )
 {
 {
-	char msg[MAX_LOG_MESSAGE_LENGTH*2];
+	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
 	::sprintf(msg,"Warn,  T%i: %s", GetThreadID(), message );
 	::sprintf(msg,"Warn,  T%i: %s", GetThreadID(), message );
 
 
 	WriteToStreams( msg, Logger::Warn );
 	WriteToStreams( msg, Logger::Warn );
@@ -283,7 +283,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 )
 {
 {
-	char msg[MAX_LOG_MESSAGE_LENGTH*2];
+	char msg[MAX_LOG_MESSAGE_LENGTH + 16];
 	::sprintf(msg,"Error, T%i: %s", GetThreadID(), message );
 	::sprintf(msg,"Error, T%i: %s", GetThreadID(), message );
 
 
 	WriteToStreams( msg, Logger::Err );
 	WriteToStreams( msg, Logger::Err );

+ 3 - 1
Source/ThirdParty/Assimp/code/Exporter.cpp

@@ -95,7 +95,7 @@ Exporter::ExportFormatEntry gExporters[] =
 	Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL, 
 	Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL, 
 		aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
 		aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
 	),
 	),
-	Exporter::ExportFormatEntry( "stlb", "Stereolithography(binary)", "stlb" , &ExportSceneSTLBinary, 
+	Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary, 
 		aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
 		aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
 	),
 	),
 #endif
 #endif
@@ -176,6 +176,8 @@ Exporter :: Exporter()
 Exporter :: ~Exporter()
 Exporter :: ~Exporter()
 {
 {
 	FreeBlob();
 	FreeBlob();
+
+	delete pimpl;
 }
 }
 
 
 
 

+ 282 - 54
Source/ThirdParty/Assimp/code/FBXConverter.cpp

@@ -23,7 +23,7 @@ following conditions are met:
   derived from this software without specific prior
   derived from this software without specific prior
   written permission of the assimp team.
   written permission of the assimp team.
 
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
@@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
 #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER
 
 
 #include <iterator>
 #include <iterator>
+#include <sstream>
 #include <boost/tuple/tuple.hpp>
 #include <boost/tuple/tuple.hpp>
 
 
 #include "FBXParser.h"
 #include "FBXParser.h"
@@ -62,7 +63,6 @@ namespace FBX {
 
 
 
 
 #define MAGIC_NODE_TAG "_$AssimpFbx$"
 #define MAGIC_NODE_TAG "_$AssimpFbx$"
-#define MAGIC_NULL_TAG "_$AssimpFbxNull$"
 
 
 #define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000L
 #define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000L
 
 
@@ -88,12 +88,13 @@ public:
 		TransformationComp_ScalingPivot,
 		TransformationComp_ScalingPivot,
 		TransformationComp_Scaling,
 		TransformationComp_Scaling,
 		TransformationComp_ScalingPivotInverse,
 		TransformationComp_ScalingPivotInverse,
+		TransformationComp_GeometricTranslation,
+		TransformationComp_GeometricRotation,
+		TransformationComp_GeometricScaling,
 
 
 		TransformationComp_MAXIMUM
 		TransformationComp_MAXIMUM
 	};
 	};
 
 
-
-
 public:
 public:
 
 
 	Converter(aiScene* out, const Document& doc)
 	Converter(aiScene* out, const Document& doc)
@@ -120,7 +121,7 @@ public:
 				if(mat) {
 				if(mat) {
 
 
 					if (materials_converted.find(mat) == materials_converted.end()) {
 					if (materials_converted.find(mat) == materials_converted.end()) {
-						ConvertMaterial(*mat);
+						ConvertMaterial(*mat, 0);
 					}
 					}
 				}
 				}
 			}
 			}
@@ -220,6 +221,9 @@ private:
 						name_carrier = nodes_chain.back();
 						name_carrier = nodes_chain.back();
 					}
 					}
 
 
+					//setup metadata on newest node
+					SetupNodeMetadata(*model, *nodes_chain.back());
+
 					// link all nodes in a row
 					// link all nodes in a row
 					aiNode* last_parent = &parent;
 					aiNode* last_parent = &parent;
 					BOOST_FOREACH(aiNode* prenode, nodes_chain) {
 					BOOST_FOREACH(aiNode* prenode, nodes_chain) {
@@ -251,14 +255,6 @@ private:
 						ConvertCameras(*model);
 						ConvertCameras(*model);
 					}
 					}
 
 
-					// preserve the info that a node was marked as Null node
-					// in the original file.
-					if(model->IsNull()) {
-						const std::string& new_name = original_name + MAGIC_NULL_TAG;
-						RenameNode(original_name, new_name);
-						name_carrier->mName.Set( new_name.c_str() );
-					}
-
 					nodes.push_back(nodes_chain.front());	
 					nodes.push_back(nodes_chain.front());	
 					nodes_chain.clear();
 					nodes_chain.clear();
 				}
 				}
@@ -382,10 +378,11 @@ private:
 
 
 		out_camera->mName.Set(FixNodeName(model.Name()));
 		out_camera->mName.Set(FixNodeName(model.Name()));
 
 
-		out_camera->mAspect = cam.AspectWidth();
+		out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight();
 		out_camera->mPosition = cam.Position();
 		out_camera->mPosition = cam.Position();
 		out_camera->mLookAt = cam.InterestPosition() - out_camera->mPosition;
 		out_camera->mLookAt = cam.InterestPosition() - out_camera->mPosition;
 
 
+		// BUG HERE cam.FieldOfView() returns 1.0f every time.  1.0f is default value.
 		out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
 		out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView());
 	}
 	}
 
 
@@ -419,6 +416,12 @@ private:
 			return "Scaling";
 			return "Scaling";
 		case TransformationComp_ScalingPivotInverse:
 		case TransformationComp_ScalingPivotInverse:
 			return "ScalingPivotInverse";
 			return "ScalingPivotInverse";
+		case TransformationComp_GeometricScaling:
+			return "GeometricScaling";
+		case TransformationComp_GeometricRotation:
+			return "GeometricRotation";
+		case TransformationComp_GeometricTranslation:
+			return "GeometricTranslation";
 		case TransformationComp_MAXIMUM: // this is to silence compiler warnings
 		case TransformationComp_MAXIMUM: // this is to silence compiler warnings
 			break;
 			break;
 		}
 		}
@@ -456,6 +459,12 @@ private:
 			return "Lcl Scaling";
 			return "Lcl Scaling";
 		case TransformationComp_ScalingPivotInverse:
 		case TransformationComp_ScalingPivotInverse:
 			return "ScalingPivotInverse";
 			return "ScalingPivotInverse";
+		case TransformationComp_GeometricScaling:
+			return "GeometricScaling";
+		case TransformationComp_GeometricRotation:
+			return "GeometricRotation";
+		case TransformationComp_GeometricTranslation:
+			return "GeometricTranslation";
 		case TransformationComp_MAXIMUM: // this is to silence compiler warnings
 		case TransformationComp_MAXIMUM: // this is to silence compiler warnings
 			break;
 			break;
 		}
 		}
@@ -577,9 +586,8 @@ private:
 		for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
 		for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) {
 			const TransformationComp comp = static_cast<TransformationComp>(i);
 			const TransformationComp comp = static_cast<TransformationComp>(i);
 
 
-			if(comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || 
-				comp == TransformationComp_Translation) {
-
+			if( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ||
+				comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) { 
 				continue;
 				continue;
 			}
 			}
 
 
@@ -676,6 +684,21 @@ private:
 		if(ok && Rotation.SquareLength() > zero_epsilon) {
 		if(ok && Rotation.SquareLength() > zero_epsilon) {
 			GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]);
 			GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]);
 		}
 		}
+		
+		const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok);
+		if (ok && fabs(GeometricScaling.SquareLength() - 1.0f) > zero_epsilon) {
+			aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]);
+		}
+		
+		const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>(props, "GeometricRotation", ok);
+		if (ok && GeometricRotation.SquareLength() > zero_epsilon) {
+			GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]);
+		}
+
+		const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>(props, "GeometricTranslation", ok);
+		if (ok && GeometricTranslation.SquareLength() > zero_epsilon){
+			aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]);
+		}
 
 
 		// is_complex needs to be consistent with NeedsComplexTransformationChain()
 		// is_complex needs to be consistent with NeedsComplexTransformationChain()
 		// or the interplay between this code and the animation converter would
 		// or the interplay between this code and the animation converter would
@@ -725,7 +748,49 @@ private:
 			nd->mTransformation = nd->mTransformation * chain[i];
 			nd->mTransformation = nd->mTransformation * chain[i];
 		}
 		}
 	}
 	}
+	
+	// ------------------------------------------------------------------------------------------------
 
 
+	void SetupNodeMetadata(const Model& model, aiNode& nd)
+	{
+		const PropertyTable& props = model.Props();
+		DirectPropertyMap unparsedProperties = props.GetUnparsedProperties();
+
+		// create metadata on node
+		std::size_t numStaticMetaData = 2;
+		aiMetadata* data = new aiMetadata();
+		data->mNumProperties = unparsedProperties.size() + numStaticMetaData;
+		data->mKeys = new aiString[data->mNumProperties]();
+		data->mValues = new aiMetadataEntry[data->mNumProperties]();
+		nd.mMetaData = data;
+		int index = 0;
+
+		// find user defined properties (3ds Max)
+		data->Set(index++, "UserProperties", aiString(PropertyGet<std::string>(props, "UDP3DSMAX", "")));
+		unparsedProperties.erase("UDP3DSMAX");
+		// preserve the info that a node was marked as Null node in the original file.
+		data->Set(index++, "IsNull", model.IsNull() ? true : false);
+
+		// add unparsed properties to the node's metadata
+		BOOST_FOREACH(const DirectPropertyMap::value_type& prop, unparsedProperties) {
+
+			// Interpret the property as a concrete type
+			if (const TypedProperty<bool>* interpreted = prop.second->As<TypedProperty<bool> >())
+				data->Set(index++, prop.first, interpreted->Value());
+			else if (const TypedProperty<int>* interpreted = prop.second->As<TypedProperty<int> >())
+				data->Set(index++, prop.first, interpreted->Value());
+			else if (const TypedProperty<uint64_t>* interpreted = prop.second->As<TypedProperty<uint64_t> >())
+				data->Set(index++, prop.first, interpreted->Value());
+			else if (const TypedProperty<float>* interpreted = prop.second->As<TypedProperty<float> >())
+				data->Set(index++, prop.first, interpreted->Value());
+			else if (const TypedProperty<std::string>* interpreted = prop.second->As<TypedProperty<std::string> >())
+				data->Set(index++, prop.first, aiString(interpreted->Value()));
+			else if (const TypedProperty<aiVector3D>* interpreted = prop.second->As<TypedProperty<aiVector3D> >())
+				data->Set(index++, prop.first, interpreted->Value());
+			else
+				assert(false);
+		}
+	}
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
 	void ConvertModel(const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform)
 	void ConvertModel(const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform)
@@ -1316,7 +1381,7 @@ private:
 			return;
 			return;
 		}
 		}
 
 
-		out->mMaterialIndex = ConvertMaterial(*mat);	
+		out->mMaterialIndex = ConvertMaterial(*mat, &geo);	
 		materials_converted[mat] = out->mMaterialIndex;
 		materials_converted[mat] = out->mMaterialIndex;
 	}
 	}
 
 
@@ -1346,7 +1411,7 @@ private:
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
 	// Material -> aiMaterial
 	// Material -> aiMaterial
-	unsigned int ConvertMaterial(const Material& material)
+	unsigned int ConvertMaterial(const Material& material, const MeshGeometry* const mesh)
 	{
 	{
 		const PropertyTable& props = material.Props();
 		const PropertyTable& props = material.Props();
 
 
@@ -1375,7 +1440,8 @@ private:
 		SetShadingPropertiesCommon(out_mat,props);
 		SetShadingPropertiesCommon(out_mat,props);
 	
 	
 		// texture assignments
 		// texture assignments
-		SetTextureProperties(out_mat,material.Textures());
+		SetTextureProperties(out_mat,material.Textures(), mesh);
+		SetTextureProperties(out_mat,material.LayeredTextures(), mesh);
 
 
 		return static_cast<unsigned int>(materials.size() - 1);
 		return static_cast<unsigned int>(materials.size() - 1);
 	}
 	}
@@ -1384,7 +1450,7 @@ private:
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
 	void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, 
 	void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, 
 		const std::string& propName, 
 		const std::string& propName, 
-		aiTextureType target)
+		aiTextureType target, const MeshGeometry* const mesh)
 	{
 	{
 		TextureMap::const_iterator it = textures.find(propName);
 		TextureMap::const_iterator it = textures.find(propName);
 		if(it == textures.end()) {
 		if(it == textures.end()) {
@@ -1392,7 +1458,128 @@ private:
 		}
 		}
 
 
 		const Texture* const tex = (*it).second;
 		const Texture* const tex = (*it).second;
-		
+		if(tex !=0 )
+		{
+			aiString path;
+			path.Set(tex->RelativeFilename());
+
+			out_mat->AddProperty(&path,_AI_MATKEY_TEXTURE_BASE,target,0);
+
+			aiUVTransform uvTrafo;
+			// XXX handle all kinds of UV transformations
+			uvTrafo.mScaling = tex->UVScaling();
+			uvTrafo.mTranslation = tex->UVTranslation();
+			out_mat->AddProperty(&uvTrafo,1,_AI_MATKEY_UVTRANSFORM_BASE,target,0);
+
+			const PropertyTable& props = tex->Props();
+
+			int uvIndex = 0;
+
+			bool ok;
+			const std::string& uvSet = PropertyGet<std::string>(props,"UVSet",ok);
+			if(ok) {
+				// "default" is the name which usually appears in the FbxFileTexture template
+				if(uvSet != "default" && uvSet.length()) {
+					// this is a bit awkward - we need to find a mesh that uses this
+					// material and scan its UV channels for the given UV name because
+					// assimp references UV channels by index, not by name.
+
+					// XXX: the case that UV channels may appear in different orders
+					// in meshes is unhandled. A possible solution would be to sort
+					// the UV channels alphabetically, but this would have the side
+					// effect that the primary (first) UV channel would sometimes
+					// be moved, causing trouble when users read only the first
+					// UV channel and ignore UV channel assignments altogether.
+
+					const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), 
+						std::find(materials.begin(),materials.end(),out_mat)
+					));
+
+
+          uvIndex = -1;
+          if (!mesh)
+          {					
+					  BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) {
+						  const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first);
+						  if(!mesh) {
+							  continue;
+						  }
+
+						  const MatIndexArray& mats = mesh->GetMaterialIndices();
+						  if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) {
+							  continue;
+						  }
+
+						  int index = -1;
+						  for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+							  if(mesh->GetTextureCoords(i).empty()) {
+								  break;
+							  }
+							  const std::string& name = mesh->GetTextureCoordChannelName(i);
+							  if(name == uvSet) {
+								  index = static_cast<int>(i);
+								  break;
+							  }
+						  }
+						  if(index == -1) {
+							  FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
+							  continue;
+						  }
+
+						  if(uvIndex == -1) {
+							  uvIndex = index;
+						  }
+						  else {
+							  FBXImporter::LogWarn("the UV channel named " + uvSet + 
+								  " appears at different positions in meshes, results will be wrong");
+						  }
+					  }
+          }
+          else
+          {
+						int index = -1;
+						for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+							if(mesh->GetTextureCoords(i).empty()) {
+								break;
+							}
+							const std::string& name = mesh->GetTextureCoordChannelName(i);
+							if(name == uvSet) {
+								index = static_cast<int>(i);
+								break;
+							}
+						}
+						if(index == -1) {
+							FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
+						}
+
+						if(uvIndex == -1) {
+							uvIndex = index;
+						}
+          }
+
+					if(uvIndex == -1) {
+						FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel");
+						uvIndex = 0;
+					}
+				}
+			}
+
+			out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0);
+		}
+	}
+
+	// ------------------------------------------------------------------------------------------------
+	void TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, 
+		const std::string& propName, 
+		aiTextureType target, const MeshGeometry* const mesh)
+	{
+		LayeredTextureMap::const_iterator it = layeredTextures.find(propName);
+		if(it == layeredTextures.end()) {
+			return;
+		}
+
+		const Texture* const tex = (*it).second->getTexture();
+
 		aiString path;
 		aiString path;
 		path.Set(tex->RelativeFilename());
 		path.Set(tex->RelativeFilename());
 
 
@@ -1426,20 +1613,49 @@ private:
 
 
 				const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), 
 				const unsigned int matIndex = static_cast<unsigned int>(std::distance(materials.begin(), 
 					std::find(materials.begin(),materials.end(),out_mat)
 					std::find(materials.begin(),materials.end(),out_mat)
-				));
+					));
+
+			  uvIndex = -1;
+        if (!mesh)
+        {					
+					BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) {
+						const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first);
+						if(!mesh) {
+							continue;
+						}
 
 
-				uvIndex = -1;
-				BOOST_FOREACH(const MeshMap::value_type& v,meshes_converted) {
-					const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*> (v.first);
-					if(!mesh) {
-						continue;
-					}
+						const MatIndexArray& mats = mesh->GetMaterialIndices();
+						if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) {
+							continue;
+						}
 
 
-					const MatIndexArray& mats = mesh->GetMaterialIndices();
-					if(std::find(mats.begin(),mats.end(),matIndex) == mats.end()) {
-						continue;
-					}
+						int index = -1;
+						for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
+							if(mesh->GetTextureCoords(i).empty()) {
+								break;
+							}
+							const std::string& name = mesh->GetTextureCoordChannelName(i);
+							if(name == uvSet) {
+								index = static_cast<int>(i);
+								break;
+							}
+						}
+						if(index == -1) {
+							FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
+							continue;
+						}
 
 
+						if(uvIndex == -1) {
+							uvIndex = index;
+						}
+						else {
+							FBXImporter::LogWarn("the UV channel named " + uvSet + 
+								" appears at different positions in meshes, results will be wrong");
+						}
+					}
+        }
+        else
+        {
 					int index = -1;
 					int index = -1;
 					for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
 					for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
 						if(mesh->GetTextureCoords(i).empty()) {
 						if(mesh->GetTextureCoords(i).empty()) {
@@ -1453,17 +1669,12 @@ private:
 					}
 					}
 					if(index == -1) {
 					if(index == -1) {
 						FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
 						FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material");
-						continue;
 					}
 					}
 
 
 					if(uvIndex == -1) {
 					if(uvIndex == -1) {
 						uvIndex = index;
 						uvIndex = index;
 					}
 					}
-					else {
-						FBXImporter::LogWarn("the UV channel named " + uvSet + 
-							" appears at different positions in meshes, results will be wrong");
-					}
-				}
+        }
 
 
 				if(uvIndex == -1) {
 				if(uvIndex == -1) {
 					FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel");
 					FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel");
@@ -1475,21 +1686,35 @@ private:
 		out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0);
 		out_mat->AddProperty(&uvIndex,1,_AI_MATKEY_UVWSRC_BASE,target,0);
 	}
 	}
 
 
-
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
-	void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures)
+	void SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh)
 	{
 	{
-		TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE);
-		TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT);
-		TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE);
-		TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR);
-		TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY);
-		TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION);
-		TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT);
-		TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS);
-		TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT);
+		TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
+		TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh);
+		TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
+		TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh);
+		TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh);
+		TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
+		TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
+		TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS, mesh);
+		TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT, mesh);
+		TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh);
 	}
 	}
 
 
+	// ------------------------------------------------------------------------------------------------
+	void SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh)
+	{
+		TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh);
+		TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh);
+		TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh);
+		TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh);
+		TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh);
+		TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh);
+		TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh);
+		TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh);
+		TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh);
+		TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh);
+	}
 
 
 
 
 	// ------------------------------------------------------------------------------------------------
 	// ------------------------------------------------------------------------------------------------
@@ -1838,7 +2063,7 @@ private:
 		ai_assert(curves.size());
 		ai_assert(curves.size());
 
 
 		// sanity check whether the input is ok
 		// sanity check whether the input is ok
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		{ const Object* target = NULL;
 		{ const Object* target = NULL;
 		BOOST_FOREACH(const AnimationCurveNode* node, curves) {
 		BOOST_FOREACH(const AnimationCurveNode* node, curves) {
 			if(!target) {
 			if(!target) {
@@ -1900,9 +2125,9 @@ private:
 
 
 				has_any = true;
 				has_any = true;
 
 
-				if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling &&
-					comp != TransformationComp_Translation) {
-
+				if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation &&
+					comp != TransformationComp_GeometricScaling && comp != TransformationComp_GeometricRotation && comp != TransformationComp_GeometricTranslation )
+				{
 					has_complex = true;
 					has_complex = true;
 				}
 				}
 			}
 			}
@@ -1955,6 +2180,7 @@ private:
 				case TransformationComp_Rotation:
 				case TransformationComp_Rotation:
 				case TransformationComp_PreRotation:
 				case TransformationComp_PreRotation:
 				case TransformationComp_PostRotation:
 				case TransformationComp_PostRotation:
+				case TransformationComp_GeometricRotation:
 					na = GenerateRotationNodeAnim(chain_name, 
 					na = GenerateRotationNodeAnim(chain_name, 
 						target, 
 						target, 
 						(*chain[i]).second,
 						(*chain[i]).second,
@@ -1969,6 +2195,7 @@ private:
 				case TransformationComp_ScalingOffset:
 				case TransformationComp_ScalingOffset:
 				case TransformationComp_ScalingPivot:
 				case TransformationComp_ScalingPivot:
 				case TransformationComp_Translation:
 				case TransformationComp_Translation:
+				case TransformationComp_GeometricTranslation:
 					na = GenerateTranslationNodeAnim(chain_name, 
 					na = GenerateTranslationNodeAnim(chain_name, 
 						target, 
 						target, 
 						(*chain[i]).second,
 						(*chain[i]).second,
@@ -2017,6 +2244,7 @@ private:
 					break;
 					break;
 
 
 				case TransformationComp_Scaling:
 				case TransformationComp_Scaling:
+				case TransformationComp_GeometricScaling:
 					na = GenerateScalingNodeAnim(chain_name, 
 					na = GenerateScalingNodeAnim(chain_name, 
 						target, 
 						target, 
 						(*chain[i]).second,
 						(*chain[i]).second,

+ 4 - 1
Source/ThirdParty/Assimp/code/FBXDocument.cpp

@@ -14,7 +14,7 @@ following conditions are met:
   following disclaimer.
   following disclaimer.
 
 
 * Redistributions in binary form must reproduce the above
 * Redistributions in binary form must reproduce the above
-  copyright notice, this list of conditions and the
+  copyright notice, this list of conditions and the*
   following disclaimer in the documentation and/or other
   following disclaimer in the documentation and/or other
   materials provided with the distribution.
   materials provided with the distribution.
 
 
@@ -176,6 +176,9 @@ const Object* LazyObject::Get(bool dieOnError)
 		else if (!strncmp(obtype,"Texture",length)) {
 		else if (!strncmp(obtype,"Texture",length)) {
 			object.reset(new Texture(id,element,doc,name));
 			object.reset(new Texture(id,element,doc,name));
 		}
 		}
+		else if (!strncmp(obtype,"LayeredTexture",length)) {
+			object.reset(new LayeredTexture(id,element,doc,name));
+		}
 		else if (!strncmp(obtype,"AnimationStack",length)) {
 		else if (!strncmp(obtype,"AnimationStack",length)) {
 			object.reset(new AnimationStack(id,element,name,doc));
 			object.reset(new AnimationStack(id,element,name,doc));
 		}
 		}

+ 70 - 2
Source/ThirdParty/Assimp/code/FBXDocument.h

@@ -516,8 +516,6 @@ private:
 	boost::shared_ptr<const PropertyTable> props;
 	boost::shared_ptr<const PropertyTable> props;
 };
 };
 
 
-
-
 /** DOM class for generic FBX textures */
 /** DOM class for generic FBX textures */
 class Texture : public Object
 class Texture : public Object
 {
 {
@@ -576,8 +574,73 @@ private:
 	unsigned int crop[4];
 	unsigned int crop[4];
 };
 };
 
 
+/** DOM class for layered FBX textures */
+class LayeredTexture : public Object
+{
+public:
+
+	LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name);
+	~LayeredTexture();
+
+	//Can only be called after construction of the layered texture object due to construction flag.
+	void fillTexture(const Document& doc);
+
+	enum BlendMode
+	{
+		BlendMode_Translucent,
+		BlendMode_Additive,
+		BlendMode_Modulate,
+		BlendMode_Modulate2,
+		BlendMode_Over,
+		BlendMode_Normal,
+		BlendMode_Dissolve,
+		BlendMode_Darken,
+		BlendMode_ColorBurn,
+		BlendMode_LinearBurn,
+		BlendMode_DarkerColor,
+		BlendMode_Lighten,
+		BlendMode_Screen,
+		BlendMode_ColorDodge,
+		BlendMode_LinearDodge,
+		BlendMode_LighterColor,
+		BlendMode_SoftLight,
+		BlendMode_HardLight,
+		BlendMode_VividLight,
+		BlendMode_LinearLight,
+		BlendMode_PinLight,
+		BlendMode_HardMix,
+		BlendMode_Difference,
+		BlendMode_Exclusion,
+		BlendMode_Subtract,
+		BlendMode_Divide,
+		BlendMode_Hue,
+		BlendMode_Saturation,
+		BlendMode_Color,
+		BlendMode_Luminosity,
+		BlendMode_Overlay,
+		BlendMode_BlendModeCount
+	};
+
+	const Texture* getTexture() const
+	{
+		return texture;
+	}
+	BlendMode GetBlendMode()
+	{
+		return blendMode;
+	}
+	float Alpha()
+	{
+		return alpha;
+	}
+private:
+	const Texture* texture;
+	BlendMode blendMode;
+	float alpha;
+};
 
 
 typedef std::fbx_unordered_map<std::string, const Texture*> TextureMap;
 typedef std::fbx_unordered_map<std::string, const Texture*> TextureMap;
+typedef std::fbx_unordered_map<std::string, const LayeredTexture*> LayeredTextureMap;
 
 
 
 
 /** DOM class for generic FBX materials */
 /** DOM class for generic FBX materials */
@@ -607,6 +670,10 @@ public:
 		return textures;
 		return textures;
 	}
 	}
 
 
+	const LayeredTextureMap& LayeredTextures() const {
+		return layeredTextures;
+	}
+
 private:
 private:
 
 
 	std::string shading;
 	std::string shading;
@@ -614,6 +681,7 @@ private:
 	boost::shared_ptr<const PropertyTable> props;
 	boost::shared_ptr<const PropertyTable> props;
 
 
 	TextureMap textures;
 	TextureMap textures;
+	LayeredTextureMap layeredTextures;
 };
 };
 
 
 
 

+ 1 - 1
Source/ThirdParty/Assimp/code/FBXImportSettings.h

@@ -53,7 +53,7 @@ struct ImportSettings
 	ImportSettings()
 	ImportSettings()
 		: strictMode(true)
 		: strictMode(true)
 		, readAllLayers(true)
 		, readAllLayers(true)
-		, readAllMaterials()
+		, readAllMaterials(false)
 		, readMaterials(true)
 		, readMaterials(true)
 		, readCameras(true)
 		, readCameras(true)
 		, readLights(true)
 		, readLights(true)

+ 66 - 7
Source/ThirdParty/Assimp/code/FBXMaterial.cpp

@@ -110,16 +110,29 @@ Material::Material(uint64_t id, const Element& element, const Document& doc, con
 
 
 		const Texture* const tex = dynamic_cast<const Texture*>(ob);
 		const Texture* const tex = dynamic_cast<const Texture*>(ob);
 		if(!tex) {
 		if(!tex) {
-			DOMWarning("source object for texture link is not a texture, ignoring",&element);
-			continue;
+			const LayeredTexture* const layeredTexture = dynamic_cast<const LayeredTexture*>(ob);
+			if(!layeredTexture) {
+				DOMWarning("source object for texture link is not a texture or layered texture, ignoring",&element);
+				continue;
+			}
+			const std::string& prop = con->PropertyName();
+			if (layeredTextures.find(prop) != layeredTextures.end()) {
+				DOMWarning("duplicate layered texture link: " + prop,&element);
+			}
+
+			layeredTextures[prop] = layeredTexture;
+			((LayeredTexture*)layeredTexture)->fillTexture(doc);
 		}
 		}
-
-		const std::string& prop = con->PropertyName();
-		if (textures.find(prop) != textures.end()) {
-			DOMWarning("duplicate texture link: " + prop,&element);
+		else
+		{
+			const std::string& prop = con->PropertyName();
+			if (textures.find(prop) != textures.end()) {
+				DOMWarning("duplicate texture link: " + prop,&element);
+			}
+
+			textures[prop] = tex;
 		}
 		}
 
 
-		textures[prop] = tex;
 	}
 	}
 }
 }
 
 
@@ -194,6 +207,52 @@ Texture::~Texture()
 
 
 }
 }
 
 
+LayeredTexture::LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name)
+: Object(id,element,name)
+,texture(0)
+,blendMode(BlendMode_Modulate)
+,alpha(1)
+{
+	const Scope& sc = GetRequiredScope(element);
+
+	const Element* const BlendModes = sc["BlendModes"];
+	const Element* const Alphas = sc["Alphas"];
+
+	
+	if(BlendModes!=0)
+	{
+		blendMode = (BlendMode)ParseTokenAsInt(GetRequiredToken(*BlendModes,0));
+	}
+	if(Alphas!=0)
+	{
+		alpha = ParseTokenAsFloat(GetRequiredToken(*Alphas,0));
+	}
+}
+
+LayeredTexture::~LayeredTexture()
+{
+
+}
+
+void LayeredTexture::fillTexture(const Document& doc)
+{
+	const std::vector<const Connection*>& conns = doc.GetConnectionsByDestinationSequenced(ID());
+	for(size_t i = 0; i < conns.size();++i)
+	{
+		const Connection* con = conns.at(i);
+
+		const Object* const ob = con->SourceObject();
+		if(!ob) {
+			DOMWarning("failed to read source object for texture link, ignoring",&element);
+			continue;
+		}
+
+		const Texture* const tex = dynamic_cast<const Texture*>(ob);
+
+		texture = tex;
+	}
+}
+
 } //!FBX
 } //!FBX
 } //!Assimp
 } //!Assimp
 
 

+ 17 - 7
Source/ThirdParty/Assimp/code/FBXParser.cpp

@@ -364,14 +364,24 @@ float ParseTokenAsFloat(const Token& t, const char*& err_out)
 		}
 		}
 
 
 		if (data[0] == 'F') {
 		if (data[0] == 'F') {
-			ai_assert(t.end() - data == 5);
-			// no byte swapping needed for ieee floats
-			return *reinterpret_cast<const float*>(data+1);
+			// Actual size validation happens during Tokenization so
+			// this is valid as an assertion.
+			ai_assert(t.end() - data == sizeof(float) + 1);
+			// Initially, we did reinterpret_cast, breaking strict aliasing rules.
+			// This actually caused trouble on Android, so let's be safe this time.
+			// https://github.com/assimp/assimp/issues/24
+			
+			float out_float;
+			::memcpy(&out_float, data+1, sizeof(float));
+			return out_float;
 		}
 		}
 		else {
 		else {
-			ai_assert(t.end() - data == 9);
-			// no byte swapping needed for ieee floats
-			return static_cast<float>(*reinterpret_cast<const double*>(data+1));
+			ai_assert(t.end() - data == sizeof(double) + 1);
+			
+			// Same
+			double out_double;
+			::memcpy(&out_double, data+1, sizeof(double));
+			return static_cast<float>(out_double);
 		}
 		}
 	}
 	}
 
 
@@ -565,7 +575,7 @@ void ReadBinaryDataArray(char type, uint32_t count, const char*& data, const cha
 		// terminate zlib
 		// terminate zlib
 		inflateEnd(&zstream);
 		inflateEnd(&zstream);
 	}
 	}
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	else {
 	else {
 		// runtime check for this happens at tokenization stage
 		// runtime check for this happens at tokenization stage
 		ai_assert(false);
 		ai_assert(false);

+ 27 - 0
Source/ThirdParty/Assimp/code/FBXProperties.cpp

@@ -201,6 +201,33 @@ const Property* PropertyTable::Get(const std::string& name) const
 	return (*it).second;
 	return (*it).second;
 }
 }
 
 
+DirectPropertyMap PropertyTable::GetUnparsedProperties() const
+{
+	DirectPropertyMap result;
+
+	// Loop through all the lazy properties (which is all the properties)
+	BOOST_FOREACH(const LazyPropertyMap::value_type& element, lazyProps) {
+
+		// Skip parsed properties
+		if (props.end() != props.find(element.first)) continue;
+
+		// Read the element's value.
+		// Wrap the naked pointer (since the call site is required to acquire ownership)
+		// std::unique_ptr from C++11 would be preferred both as a wrapper and a return value.
+		boost::shared_ptr<Property> prop = boost::shared_ptr<Property>(ReadTypedProperty(*element.second));
+			
+		// Element could not be read. Skip it.
+		if (!prop) continue;
+
+		// Add to result
+		result[element.first] = prop;
+	}
+
+	return result;
+}
+
+
+
 } //! FBX
 } //! FBX
 } //! Assimp
 } //! Assimp
 
 

+ 3 - 0
Source/ThirdParty/Assimp/code/FBXProperties.h

@@ -101,6 +101,7 @@ private:
 };
 };
 
 
 
 
+typedef std::fbx_unordered_map<std::string,boost::shared_ptr<Property> > DirectPropertyMap;
 typedef std::fbx_unordered_map<std::string,const Property*> PropertyMap;
 typedef std::fbx_unordered_map<std::string,const Property*> PropertyMap;
 typedef std::fbx_unordered_map<std::string,const Element*> LazyPropertyMap;
 typedef std::fbx_unordered_map<std::string,const Element*> LazyPropertyMap;
 
 
@@ -128,6 +129,8 @@ public:
 		return templateProps.get();
 		return templateProps.get();
 	}
 	}
 
 
+	DirectPropertyMap GetUnparsedProperties() const;
+
 private:
 private:
 
 
 	LazyPropertyMap lazyProps;
 	LazyPropertyMap lazyProps;

+ 1 - 1
Source/ThirdParty/Assimp/code/FindDegenerates.h

@@ -53,7 +53,7 @@ namespace Assimp	{
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** FindDegeneratesProcess: Searches a mesh for degenerated triangles.
 /** FindDegeneratesProcess: Searches a mesh for degenerated triangles.
 */
 */
-class FindDegeneratesProcess : public BaseProcess
+class ASSIMP_API FindDegeneratesProcess : public BaseProcess
 {
 {
 public:
 public:
 
 

+ 2 - 3
Source/ThirdParty/Assimp/code/FindInvalidDataProcess.h

@@ -51,13 +51,12 @@ class FindInvalidDataProcessTest;
 namespace Assimp	{
 namespace Assimp	{
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
-/** The FindInvalidData postprocessing step. It searches the mesh data
+/** The FindInvalidData post-processing step. It searches the mesh data
  *  for parts that are obviously invalid and removes them.
  *  for parts that are obviously invalid and removes them.
  *
  *
  *  Originally this was a workaround for some models written by Blender
  *  Originally this was a workaround for some models written by Blender
  *  which have zero normal vectors. */
  *  which have zero normal vectors. */
-class FindInvalidDataProcess 
-	: public BaseProcess
+class ASSIMP_API FindInvalidDataProcess : public BaseProcess
 {
 {
 public:
 public:
 
 

+ 7 - 6
Source/ThirdParty/Assimp/code/GenVertexNormalsProcess.cpp

@@ -142,7 +142,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
 		const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
 		const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
 		const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
 		const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
 		const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
 		const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
-		const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).Normalize();
+		const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1));
 
 
 		for (unsigned int i = 0;i < face.mNumIndices;++i) {
 		for (unsigned int i = 0;i < face.mNumIndices;++i) {
 			pMesh->mNormals[face.mIndices[i]] = vNor;
 			pMesh->mNormals[face.mIndices[i]] = vNor;
@@ -209,18 +209,19 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
 			// Get all vertices that share this one ...
 			// Get all vertices that share this one ...
 			vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound);
 			vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound);
 
 
+			aiVector3D vr = pMesh->mNormals[i];
+			float vrlen = vr.Length();
+
 			aiVector3D pcNor; 
 			aiVector3D pcNor; 
 			for (unsigned int a = 0; a < verticesFound.size(); ++a)	{
 			for (unsigned int a = 0; a < verticesFound.size(); ++a)	{
-				const aiVector3D& v = pMesh->mNormals[verticesFound[a]];
+				aiVector3D v = pMesh->mNormals[verticesFound[a]];
 
 
 				// check whether the angle between the two normals is not too large
 				// check whether the angle between the two normals is not too large
 				// HACK: if v.x is qnan the dot product will become qnan, too
 				// HACK: if v.x is qnan the dot product will become qnan, too
 				//   therefore the comparison against fLimit should be false
 				//   therefore the comparison against fLimit should be false
 				//   in every case. 
 				//   in every case. 
-				if (v * pMesh->mNormals[i] < fLimit)
-					continue;
-
-				pcNor += v;
+				if (v * vr >= fLimit * vrlen * v.Length())
+					pcNor += v;
 			}
 			}
 			pcNew[i] = pcNor.Normalize();
 			pcNew[i] = pcNor.Normalize();
 		}
 		}

+ 2 - 2
Source/ThirdParty/Assimp/code/IFCBoolean.cpp

@@ -221,7 +221,7 @@ bool IntersectsBoundaryProfile( const IfcVector3& e0, const IfcVector3& e1, cons
 		const IfcFloat s = (x*e.y - e.x*y)/det;
 		const IfcFloat s = (x*e.y - e.x*y)/det;
 		const IfcFloat t = (x*b.y - b.x*y)/det;
 		const IfcFloat t = (x*b.y - b.x*y)/det;
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		const IfcVector3 check = b0 + b*s  - (e0 + e*t);
 		const IfcVector3 check = b0 + b*s  - (e0 + e*t);
 		ai_assert((IfcVector2(check.x,check.y)).SquareLength() < 1e-5);
 		ai_assert((IfcVector2(check.x,check.y)).SquareLength() < 1e-5);
 #endif
 #endif
@@ -417,7 +417,7 @@ void ProcessPolygonalBoundedBooleanHalfSpaceDifference(const IfcPolygonalBounded
 			IfcVector3 isectpos;
 			IfcVector3 isectpos;
 			const Intersect isect =  extra_point_flag ? Intersect_No : IntersectSegmentPlane(p,n,e0,e1,isectpos);
 			const Intersect isect =  extra_point_flag ? Intersect_No : IntersectSegmentPlane(p,n,e0,e1,isectpos);
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 			if (isect == Intersect_Yes) {
 			if (isect == Intersect_Yes) {
 				const IfcFloat f = fabs((isectpos - p)*n);
 				const IfcFloat f = fabs((isectpos - p)*n);
 				ai_assert(f < 1e-5);
 				ai_assert(f < 1e-5);

+ 1 - 1
Source/ThirdParty/Assimp/code/IFCCurve.cpp

@@ -550,7 +550,7 @@ Curve* Curve :: Convert(const IFC::IfcCurve& curve,ConversionData& conv)
 	return NULL;
 	return NULL;
 }
 }
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 bool Curve :: InRange(IfcFloat u) const 
 bool Curve :: InRange(IfcFloat u) const 
 {
 {

+ 0 - 2
Source/ThirdParty/Assimp/code/IFCGeometry.cpp

@@ -325,8 +325,6 @@ void ProcessSweptDiskSolid(const IfcSweptDiskSolid solid, TempMesh& result, Conv
 		IFCImporter::LogError("failed to convert Directrix curve (IfcSweptDiskSolid)");
 		IFCImporter::LogError("failed to convert Directrix curve (IfcSweptDiskSolid)");
 		return;
 		return;
 	}
 	}
-
-	const std::vector<IfcVector3>& in = result.verts;
 	
 	
 	const unsigned int cnt_segments = 16;
 	const unsigned int cnt_segments = 16;
 	const IfcFloat deltaAngle = AI_MATH_TWO_PI/cnt_segments;
 	const IfcFloat deltaAngle = AI_MATH_TWO_PI/cnt_segments;

+ 10 - 28
Source/ThirdParty/Assimp/code/IFCLoader.cpp

@@ -192,24 +192,17 @@ void IFCImporter::InternReadFile( const std::string& pFile,
 		}
 		}
 
 
 		// search file (same name as the IFCZIP except for the file extension) and place file pointer there
 		// search file (same name as the IFCZIP except for the file extension) and place file pointer there
-		
 		if(UNZ_OK == unzGoToFirstFile(zip)) {
 		if(UNZ_OK == unzGoToFirstFile(zip)) {
 			do {
 			do {
-				//
-
 				// get file size, etc.
 				// get file size, etc.
 				unz_file_info fileInfo;
 				unz_file_info fileInfo;
 				char filename[256];
 				char filename[256];
 				unzGetCurrentFileInfo( zip , &fileInfo, filename, sizeof(filename), 0, 0, 0, 0 );
 				unzGetCurrentFileInfo( zip , &fileInfo, filename, sizeof(filename), 0, 0, 0, 0 );
-				
 				if (GetExtension(filename) != "ifc") {
 				if (GetExtension(filename) != "ifc") {
 					continue;
 					continue;
 				}
 				}
-
 				uint8_t* buff = new uint8_t[fileInfo.uncompressed_size];
 				uint8_t* buff = new uint8_t[fileInfo.uncompressed_size];
-
 				LogInfo("Decompressing IFCZIP file");
 				LogInfo("Decompressing IFCZIP file");
-
 				unzOpenCurrentFile( zip  );
 				unzOpenCurrentFile( zip  );
 				const int ret = unzReadCurrentFile( zip, buff, fileInfo.uncompressed_size);
 				const int ret = unzReadCurrentFile( zip, buff, fileInfo.uncompressed_size);
 				size_t filesize = fileInfo.uncompressed_size;
 				size_t filesize = fileInfo.uncompressed_size;
@@ -271,7 +264,6 @@ void IFCImporter::InternReadFile( const std::string& pFile,
 
 
 	// feed the IFC schema into the reader and pre-parse all lines
 	// feed the IFC schema into the reader and pre-parse all lines
 	STEP::ReadFile(*db, schema, types_to_track, inverse_indices_to_track);
 	STEP::ReadFile(*db, schema, types_to_track, inverse_indices_to_track);
-
 	const STEP::LazyObject* proj =  db->GetObject("ifcproject");
 	const STEP::LazyObject* proj =  db->GetObject("ifcproject");
 	if (!proj) {
 	if (!proj) {
 		ThrowException("missing IfcProject entity");
 		ThrowException("missing IfcProject entity");
@@ -287,9 +279,9 @@ void IFCImporter::InternReadFile( const std::string& pFile,
 	// in a build with no entities disabled. See 
 	// in a build with no entities disabled. See 
 	//     scripts/IFCImporter/CPPGenerator.py
 	//     scripts/IFCImporter/CPPGenerator.py
 	// for more information.
 	// for more information.
-#ifdef ASSIMP_IFC_TEST
-	db->EvaluateAll();
-#endif
+	#ifdef ASSIMP_IFC_TEST
+		db->EvaluateAll();
+	#endif
 
 
 	// do final data copying
 	// do final data copying
 	if (conv.meshes.size()) {
 	if (conv.meshes.size()) {
@@ -565,21 +557,16 @@ void ProcessProductRepresentation(const IfcProduct& el, aiNode* nd, std::vector<
 	if(!el.Representation) {
 	if(!el.Representation) {
 		return;
 		return;
 	}
 	}
-
-
 	std::vector<unsigned int> meshes;
 	std::vector<unsigned int> meshes;
-	
 	// we want only one representation type, so bring them in a suitable order (i.e try those
 	// we want only one representation type, so bring them in a suitable order (i.e try those
 	// that look as if we could read them quickly at first). This way of reading
 	// that look as if we could read them quickly at first). This way of reading
 	// representation is relatively generic and allows the concrete implementations
 	// representation is relatively generic and allows the concrete implementations
 	// for the different representation types to make some sensible choices what
 	// for the different representation types to make some sensible choices what
 	// to load and what not to load.
 	// to load and what not to load.
 	const STEP::ListOf< STEP::Lazy< IfcRepresentation >, 1, 0 >& src = el.Representation.Get()->Representations;
 	const STEP::ListOf< STEP::Lazy< IfcRepresentation >, 1, 0 >& src = el.Representation.Get()->Representations;
-
 	std::vector<const IfcRepresentation*> repr_ordered(src.size());
 	std::vector<const IfcRepresentation*> repr_ordered(src.size());
 	std::copy(src.begin(),src.end(),repr_ordered.begin());
 	std::copy(src.begin(),src.end(),repr_ordered.begin());
 	std::sort(repr_ordered.begin(),repr_ordered.end(),RateRepresentationPredicate());
 	std::sort(repr_ordered.begin(),repr_ordered.end(),RateRepresentationPredicate());
-
 	BOOST_FOREACH(const IfcRepresentation* repr, repr_ordered) {
 	BOOST_FOREACH(const IfcRepresentation* repr, repr_ordered) {
 		bool res = false;
 		bool res = false;
 		BOOST_FOREACH(const IfcRepresentationItem& item, repr->Items) {
 		BOOST_FOREACH(const IfcRepresentationItem& item, repr->Items) {
@@ -595,7 +582,6 @@ void ProcessProductRepresentation(const IfcProduct& el, aiNode* nd, std::vector<
 			break;
 			break;
 		}
 		}
 	}
 	}
-
 	AssignAddedMeshes(meshes,nd,conv);
 	AssignAddedMeshes(meshes,nd,conv);
 }
 }
 
 
@@ -725,17 +711,13 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const IfcProduct& el, Conversion
 		if (!properties.empty()) {
 		if (!properties.empty()) {
 			aiMetadata* data = new aiMetadata();
 			aiMetadata* data = new aiMetadata();
 			data->mNumProperties = properties.size();
 			data->mNumProperties = properties.size();
-			data->mKeys = new aiString*[data->mNumProperties]();
-			data->mValues = new aiString*[data->mNumProperties]();
-
-			unsigned int i = 0;
-			BOOST_FOREACH(const Metadata::value_type& kv, properties) {
-				data->mKeys[i] = new aiString(kv.first);
-				if (kv.second.length() > 0) {
-					data->mValues[i] = new aiString(kv.second);
-				}				
-				++i;
-			}
+			data->mKeys = new aiString[data->mNumProperties]();
+			data->mValues = new aiMetadataEntry[data->mNumProperties]();
+
+			unsigned int index = 0;
+			BOOST_FOREACH(const Metadata::value_type& kv, properties)
+				data->Set(index++, kv.first, aiString(kv.second));
+
 			nd->mMetaData = data;
 			nd->mMetaData = data;
 		}
 		}
 	}
 	}

+ 2 - 2
Source/ThirdParty/Assimp/code/IFCOpenings.cpp

@@ -1063,7 +1063,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
 	if(!ok) {
 	if(!ok) {
 		return IfcMatrix4();
 		return IfcMatrix4();
 	}
 	}
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	const IfcFloat det = m.Determinant();
 	const IfcFloat det = m.Determinant();
 	ai_assert(fabs(det-1) < 1e-5);
 	ai_assert(fabs(det-1) < 1e-5);
 #endif
 #endif
@@ -1119,7 +1119,7 @@ IfcMatrix4 ProjectOntoPlane(std::vector<IfcVector2>& out_contour, const TempMesh
 	m = mult * m;
 	m = mult * m;
 
 
 	// debug code to verify correctness
 	// debug code to verify correctness
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	std::vector<IfcVector2> out_contour2;
 	std::vector<IfcVector2> out_contour2;
 	BOOST_FOREACH(const IfcVector3& x, in_verts) {
 	BOOST_FOREACH(const IfcVector3& x, in_verts) {
 		const IfcVector3& vv = m * x;
 		const IfcVector3& vv = m * x;

+ 1 - 1
Source/ThirdParty/Assimp/code/IFCUtil.cpp

@@ -193,7 +193,7 @@ void TempMesh::ComputePolygonNormals(std::vector<IfcVector3>& normals,
 			temp[cnt++] = v.x;
 			temp[cnt++] = v.x;
 			temp[cnt++] = v.y;
 			temp[cnt++] = v.y;
 			temp[cnt++] = v.z;
 			temp[cnt++] = v.z;
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 			temp[cnt] = std::numeric_limits<IfcFloat>::quiet_NaN();
 			temp[cnt] = std::numeric_limits<IfcFloat>::quiet_NaN();
 #endif
 #endif
 			++cnt;
 			++cnt;

+ 1 - 1
Source/ThirdParty/Assimp/code/IFCUtil.h

@@ -365,7 +365,7 @@ public:
 	// and append the result to the mesh
 	// and append the result to the mesh
 	virtual void SampleDiscrete(TempMesh& out,IfcFloat start,IfcFloat end) const;
 	virtual void SampleDiscrete(TempMesh& out,IfcFloat start,IfcFloat end) const;
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	// check if a particular parameter value lies within the well-defined range
 	// check if a particular parameter value lies within the well-defined range
 	bool InRange(IfcFloat) const;
 	bool InRange(IfcFloat) const;
 #endif 
 #endif 

+ 26 - 7
Source/ThirdParty/Assimp/code/Importer.cpp

@@ -197,6 +197,7 @@ Importer::Importer(const Importer &other)
 	pimpl->mIntProperties    = other.pimpl->mIntProperties;
 	pimpl->mIntProperties    = other.pimpl->mIntProperties;
 	pimpl->mFloatProperties  = other.pimpl->mFloatProperties;
 	pimpl->mFloatProperties  = other.pimpl->mFloatProperties;
 	pimpl->mStringProperties = other.pimpl->mStringProperties;
 	pimpl->mStringProperties = other.pimpl->mStringProperties;
+	pimpl->mMatrixProperties = other.pimpl->mMatrixProperties;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -232,7 +233,7 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
 
 
 	for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
 	for(std::set<std::string>::const_iterator it = st.begin(); it != st.end(); ++it) {
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		if (IsExtensionSupported(*it)) {
 		if (IsExtensionSupported(*it)) {
 			DefaultLogger::get()->warn("The file extension " + *it + " is already in use");
 			DefaultLogger::get()->warn("The file extension " + *it + " is already in use");
 		}
 		}
@@ -558,7 +559,7 @@ void WriteLogOpening(const std::string& file)
 		<< "<unknown compiler>"
 		<< "<unknown compiler>"
 #endif
 #endif
 
 
-#ifndef NDEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		<< " debug"
 		<< " debug"
 #endif
 #endif
 
 
@@ -749,10 +750,10 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 		}
 		}
 	}
 	}
 #endif // no validation
 #endif // no validation
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	if (pimpl->bExtraVerbose)
 	if (pimpl->bExtraVerbose)
 	{
 	{
-#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
+#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
 		DefaultLogger::get()->error("Verbose Import is not available due to build settings");
 		DefaultLogger::get()->error("Verbose Import is not available due to build settings");
 #endif  // no validation
 #endif  // no validation
 		pFlags |= aiProcess_ValidateDataStructure;
 		pFlags |= aiProcess_ValidateDataStructure;
@@ -783,9 +784,9 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
 		if( !pimpl->mScene) {
 		if( !pimpl->mScene) {
 			break; 
 			break; 
 		}
 		}
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 
 
-#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
+#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
 		continue;
 		continue;
 #endif  // no validation
 #endif  // no validation
 
 
@@ -937,6 +938,16 @@ void Importer::SetPropertyString(const char* szName, const std::string& value,
 	ASSIMP_END_EXCEPTION_REGION(void);
 	ASSIMP_END_EXCEPTION_REGION(void);
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Set a configuration property
+void Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value, 
+	bool* bWasExisting /*= NULL*/)
+{
+	ASSIMP_BEGIN_EXCEPTION_REGION();
+	SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value,bWasExisting);	
+	ASSIMP_END_EXCEPTION_REGION(void);
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 // Get a configuration property
 int Importer::GetPropertyInteger(const char* szName, 
 int Importer::GetPropertyInteger(const char* szName, 
@@ -955,12 +966,20 @@ float Importer::GetPropertyFloat(const char* szName,
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get a configuration property
 // Get a configuration property
-const std::string& Importer::GetPropertyString(const char* szName, 
+const std::string Importer::GetPropertyString(const char* szName, 
 	const std::string& iErrorReturn /*= ""*/) const
 	const std::string& iErrorReturn /*= ""*/) const
 {
 {
 	return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
 	return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Get a configuration property
+const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, 
+	const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
+{
+	return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get the memory requirements of a single node
 // Get the memory requirements of a single node
 inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
 inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)

+ 8 - 3
Source/ThirdParty/Assimp/code/Importer.h

@@ -63,11 +63,12 @@ public:
 	// Data type to store the key hash
 	// Data type to store the key hash
 	typedef unsigned int KeyType;
 	typedef unsigned int KeyType;
 	
 	
-	// typedefs for our three configuration maps.
+	// typedefs for our four configuration maps.
 	// We don't need more, so there is no need for a generic solution
 	// We don't need more, so there is no need for a generic solution
 	typedef std::map<KeyType, int> IntPropertyMap;
 	typedef std::map<KeyType, int> IntPropertyMap;
 	typedef std::map<KeyType, float> FloatPropertyMap;
 	typedef std::map<KeyType, float> FloatPropertyMap;
 	typedef std::map<KeyType, std::string> StringPropertyMap;
 	typedef std::map<KeyType, std::string> StringPropertyMap;
+	typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
 
 
 public:
 public:
 
 
@@ -100,6 +101,9 @@ public:
 	/** List of string properties */
 	/** List of string properties */
 	StringPropertyMap mStringProperties;
 	StringPropertyMap mStringProperties;
 
 
+	/** List of Matrix properties */
+	MatrixPropertyMap mMatrixProperties;
+
 	/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
 	/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
 	 *  to be executed before and after every single postprocess step */
 	 *  to be executed before and after every single postprocess step */
 	bool bExtraVerbose;
 	bool bExtraVerbose;
@@ -135,14 +139,15 @@ public:
 		ImporterPimpl::IntPropertyMap     ints;
 		ImporterPimpl::IntPropertyMap     ints;
 		ImporterPimpl::FloatPropertyMap   floats;
 		ImporterPimpl::FloatPropertyMap   floats;
 		ImporterPimpl::StringPropertyMap  strings;
 		ImporterPimpl::StringPropertyMap  strings;
+		ImporterPimpl::MatrixPropertyMap  matrices;
 
 
 		bool operator == (const PropertyMap& prop) const {
 		bool operator == (const PropertyMap& prop) const {
 			// fixme: really isocpp? gcc complains
 			// fixme: really isocpp? gcc complains
-			return ints == prop.ints && floats == prop.floats && strings == prop.strings; 
+			return ints == prop.ints && floats == prop.floats && strings == prop.strings && matrices == prop.matrices; 
 		}
 		}
 
 
 		bool empty () const {
 		bool empty () const {
-			return ints.empty() && floats.empty() && strings.empty();
+			return ints.empty() && floats.empty() && strings.empty() && matrices.empty();
 		}
 		}
 	};
 	};
 	//! @endcond
 	//! @endcond

+ 1 - 1
Source/ThirdParty/Assimp/code/ImporterRegistry.cpp

@@ -140,7 +140,7 @@ corresponding preprocessor flag to selectively disable formats.
 #	include "LWSLoader.h"
 #	include "LWSLoader.h"
 #endif
 #endif
 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
-#	include "OgreImporter.hpp"
+#	include "OgreImporter.h"
 #endif
 #endif
 #ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER
 #ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER
 #	include "MS3DLoader.h"
 #	include "MS3DLoader.h"

+ 1 - 1
Source/ThirdParty/Assimp/code/LWOLoader.cpp

@@ -294,7 +294,7 @@ void LWOImporter::InternReadFile( const std::string& pFile,
 				unsigned int vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 				unsigned int vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS];
 				unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS];
 				unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS];
 
 
-#if _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 				for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
 				for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
 					vUVChannelIndices[mui] = UINT_MAX;
 					vUVChannelIndices[mui] = UINT_MAX;
 				}
 				}

+ 2 - 1
Source/ThirdParty/Assimp/code/LimitBoneWeightsProcess.h

@@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "BaseProcess.h"
 #include "BaseProcess.h"
 
 
 struct aiMesh;
 struct aiMesh;
+
 class LimitBoneWeightsTest;
 class LimitBoneWeightsTest;
 
 
 namespace Assimp
 namespace Assimp
@@ -69,7 +70,7 @@ namespace Assimp
 * The other weights on this bone are then renormalized to assure the sum weight
 * The other weights on this bone are then renormalized to assure the sum weight
 * to be 1.
 * to be 1.
 */
 */
-class LimitBoneWeightsProcess : public BaseProcess
+class ASSIMP_API LimitBoneWeightsProcess : public BaseProcess
 {
 {
 public:
 public:
 
 

+ 238 - 242
Source/ThirdParty/Assimp/code/LineSplitter.h

@@ -1,242 +1,238 @@
-/*
-Open Asset Import Library (assimp)
-----------------------------------------------------------------------
-
-Copyright (c) 2006-2012, assimp team
-All rights reserved.
-
-Redistribution and use of this software in source and binary forms, 
-with or without modification, are permitted provided that the 
-following conditions are met:
-
-* Redistributions of source code must retain the above
-  copyright notice, this list of conditions and the
-  following disclaimer.
-
-* Redistributions in binary form must reproduce the above
-  copyright notice, this list of conditions and the
-  following disclaimer in the documentation and/or other
-  materials provided with the distribution.
-
-* Neither the name of the assimp team, nor the names of its
-  contributors may be used to endorse or promote products
-  derived from this software without specific prior
-  written permission of the assimp team.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----------------------------------------------------------------------
-*/
-
-/** @file  LineSplitter.h
- *  @brief LineSplitter, a helper class to iterate through all lines
- *    of a file easily. Works with StreamReader.
- */
-#ifndef INCLUDED_LINE_SPLITTER_H
-#define INCLUDED_LINE_SPLITTER_H
-
-#include <stdexcept>
-
-#include "StreamReader.h"
-#include "ParsingUtils.h"
-
-namespace Assimp {
-
-// ------------------------------------------------------------------------------------------------
-/** Usage:
-@code
-for(LineSplitter splitter(stream);splitter;++splitter) {
-
-	if (*splitter == "hi!") {
-	   ...
-	}
-    else if (splitter->substr(0,5) == "hello") {
-	   ...
-	   // access the third token in the line (tokens are space-separated)
-	   if (strtol(splitter[2]) > 5) { .. }
-	}
-
-	std::cout << "Current line is: " << splitter.get_index() << std::endl;
-}
-@endcode */
-// ------------------------------------------------------------------------------------------------
-class LineSplitter
-{
-public:
-
-	typedef size_t line_idx;
-
-public:
-
-	// -----------------------------------------
-	/** construct from existing stream reader 
-	note: trim is *always* assumed true if skyp_empty_lines==true
-	*/
-	LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true)
-		: stream(stream)
-		, swallow()
-		, skip_empty_lines(skip_empty_lines)
-		, trim(trim)
-	{
-		cur.reserve(1024);
-		operator++();
-
-		idx = 0;
-	}
-
-public:
-
-	// -----------------------------------------
-	/** pseudo-iterator increment */
-	LineSplitter& operator++() {
-		if(swallow) {
-			swallow = false;
-			return *this;
-		}
-		
-		if (!*this) {
-			throw std::logic_error("End of file, no more lines to be retrieved.");
-		}
-
-		char s;
-
-		cur.clear();
-		while(stream.GetRemainingSize() && (s = stream.GetI1(),1)) {
-			if (s == '\n' || s == '\r') {
-				if (skip_empty_lines) {
-					while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\r' || s == '\n'));
-					if (stream.GetRemainingSize()) {
-						stream.IncPtr(-1);
-					}
-				}
-				else {
-					// skip both potential line terminators but don't read past this line.
-					if (stream.GetRemainingSize() && (s == '\r' && stream.GetI1() != '\n')) {
-						stream.IncPtr(-1);
-					}
-
-					if (trim) {
-						while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\t'));
-						if (stream.GetRemainingSize()) {
-							stream.IncPtr(-1);
-						}
-					}
-				}
-				
-				break;
-			}
-			cur += s;
-		}
-
-		++idx;
-		return *this;
-	}
-
-	// -----------------------------------------
-	LineSplitter& operator++(int) {
-		return ++(*this);
-	}
-
-	// -----------------------------------------
-	/** get a pointer to the beginning of a particular token */
-	const char* operator[] (size_t idx) const {
-		const char* s = operator->()->c_str();
-
-		SkipSpaces(&s);
-		for(size_t i = 0; i < idx; ++i) {
-
-			for(;!IsSpace(*s); ++s) {
-				if(IsLineEnd(*s)) {
-					throw std::range_error("Token index out of range, EOL reached");
-				}
-			}
-			SkipSpaces(&s);
-		}
-		return s;
-	}
-
-	// -----------------------------------------
-	/** extract the start positions of N tokens from the current line*/
-	template <size_t N>
-	void get_tokens(const char* (&tokens)[N]) const {
-		const char* s = operator->()->c_str();
-
-		SkipSpaces(&s);
-		for(size_t i = 0; i < N; ++i) {
-			if(IsLineEnd(*s)) {
-				throw std::range_error("Token count out of range, EOL reached");
-			}
-			tokens[i] = s;
-
-			for(;*s && !IsSpace(*s); ++s);
-			SkipSpaces(&s);
-		}
-	}
-
-	// -----------------------------------------
-	/** member access */
-	const std::string* operator -> () const {
-		return &cur;
-	}
-
-	std::string operator* () const {
-		return cur;
-	}
-
-	// -----------------------------------------
-	/** boolean context */
-	operator bool() const {
-		return stream.GetRemainingSize()>0;
-	}
-
-	// -----------------------------------------
-	/** line indices are zero-based, empty lines are included */
-	operator line_idx() const {
-		return idx;
-	}
-
-	line_idx get_index() const {
-		return idx;
-	}
-
-	// -----------------------------------------
-	/** access the underlying stream object */
-	StreamReaderLE& get_stream() {
-		return stream;
-	}
-
-	// -----------------------------------------
-	/** !strcmp((*this)->substr(0,strlen(check)),check) */
-	bool match_start(const char* check) {
-		const size_t len = strlen(check);
-		
-		return len <= cur.length() && std::equal(check,check+len,cur.begin());
-	}
-
-
-	// -----------------------------------------
-	/** swallow the next call to ++, return the previous value. */
-	void swallow_next_increment() {
-		swallow = true;
-	}
-
-private:
-
-	line_idx idx;
-	std::string cur;
-	StreamReaderLE& stream;
-	bool swallow, skip_empty_lines, trim;
-};
-
-}
-#endif // INCLUDED_LINE_SPLITTER_H
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+/** @file  LineSplitter.h
+ *  @brief LineSplitter, a helper class to iterate through all lines
+ *    of a file easily. Works with StreamReader.
+ */
+#ifndef INCLUDED_LINE_SPLITTER_H
+#define INCLUDED_LINE_SPLITTER_H
+
+#include <stdexcept>
+
+#include "StreamReader.h"
+#include "ParsingUtils.h"
+
+namespace Assimp {
+
+// ------------------------------------------------------------------------------------------------
+/** Usage:
+@code
+for(LineSplitter splitter(stream);splitter;++splitter) {
+
+	if (*splitter == "hi!") {
+	   ...
+	}
+    else if (splitter->substr(0,5) == "hello") {
+	   ...
+	   // access the third token in the line (tokens are space-separated)
+	   if (strtol(splitter[2]) > 5) { .. }
+	}
+
+	std::cout << "Current line is: " << splitter.get_index() << std::endl;
+}
+@endcode */
+// ------------------------------------------------------------------------------------------------
+class LineSplitter
+{
+public:
+
+	typedef size_t line_idx;
+
+public:
+
+	// -----------------------------------------
+	/** construct from existing stream reader 
+	note: trim is *always* assumed true if skyp_empty_lines==true
+	*/
+	LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true)
+		: stream(stream)
+		, swallow()
+		, skip_empty_lines(skip_empty_lines)
+		, trim(trim)
+	{
+		cur.reserve(1024);
+		operator++();
+
+		idx = 0;
+	}
+
+public:
+
+	// -----------------------------------------
+	/** pseudo-iterator increment */
+	LineSplitter& operator++() {
+		if(swallow) {
+			swallow = false;
+			return *this;
+		}
+		if (!*this) {
+			throw std::logic_error("End of file, no more lines to be retrieved.");
+		}
+		char s;
+		cur.clear();
+		while(stream.GetRemainingSize() && (s = stream.GetI1(),1)) {
+			if (s == '\n' || s == '\r') {
+				if (skip_empty_lines) {
+					while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\r' || s == '\n'));
+					if (stream.GetRemainingSize()) {
+						stream.IncPtr(-1);
+					}
+				}
+				else {
+					// skip both potential line terminators but don't read past this line.
+					if (stream.GetRemainingSize() && (s == '\r' && stream.GetI1() != '\n')) {
+						stream.IncPtr(-1);
+					}
+					if (trim) {
+						while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\t'));
+						if (stream.GetRemainingSize()) {
+							stream.IncPtr(-1);
+						}
+					}
+				}
+				break;
+			}
+			cur += s;
+		}
+		++idx;
+		return *this;
+	}
+
+	// -----------------------------------------
+	LineSplitter& operator++(int) {
+		return ++(*this);
+	}
+
+	// -----------------------------------------
+	/** get a pointer to the beginning of a particular token */
+	const char* operator[] (size_t idx) const {
+		const char* s = operator->()->c_str();
+
+		SkipSpaces(&s);
+		for(size_t i = 0; i < idx; ++i) {
+
+			for(;!IsSpace(*s); ++s) {
+				if(IsLineEnd(*s)) {
+					throw std::range_error("Token index out of range, EOL reached");
+				}
+			}
+			SkipSpaces(&s);
+		}
+		return s;
+	}
+
+	// -----------------------------------------
+	/** extract the start positions of N tokens from the current line*/
+	template <size_t N>
+	void get_tokens(const char* (&tokens)[N]) const {
+		const char* s = operator->()->c_str();
+
+		SkipSpaces(&s);
+		for(size_t i = 0; i < N; ++i) {
+			if(IsLineEnd(*s)) {
+
+				throw std::range_error("Token count out of range, EOL reached");
+
+			}
+			tokens[i] = s;
+
+			for(;*s && !IsSpace(*s); ++s);
+			SkipSpaces(&s);
+		}
+	}
+
+	// -----------------------------------------
+	/** member access */
+	const std::string* operator -> () const {
+		return &cur;
+	}
+
+	std::string operator* () const {
+		return cur;
+	}
+
+	// -----------------------------------------
+	/** boolean context */
+	operator bool() const {
+		return stream.GetRemainingSize()>0;
+	}
+
+	// -----------------------------------------
+	/** line indices are zero-based, empty lines are included */
+	operator line_idx() const {
+		return idx;
+	}
+
+	line_idx get_index() const {
+		return idx;
+	}
+
+	// -----------------------------------------
+	/** access the underlying stream object */
+	StreamReaderLE& get_stream() {
+		return stream;
+	}
+
+	// -----------------------------------------
+	/** !strcmp((*this)->substr(0,strlen(check)),check) */
+	bool match_start(const char* check) {
+		const size_t len = strlen(check);
+		
+		return len <= cur.length() && std::equal(check,check+len,cur.begin());
+	}
+
+
+	// -----------------------------------------
+	/** swallow the next call to ++, return the previous value. */
+	void swallow_next_increment() {
+		swallow = true;
+	}
+
+private:
+
+	line_idx idx;
+	std::string cur;
+	StreamReaderLE& stream;
+	bool swallow, skip_empty_lines, trim;
+};
+
+}
+#endif // INCLUDED_LINE_SPLITTER_H

+ 12 - 0
Source/ThirdParty/Assimp/code/MaterialSystem.cpp

@@ -247,6 +247,18 @@ aiReturn aiGetMaterialColor(const aiMaterial* pMat,
 	return eRet;
 	return eRet;
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+// Get a aiUVTransform (4 floats) from the material
+aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat, 
+	const char* pKey,
+	unsigned int type,
+	unsigned int index,
+	aiUVTransform* pOut)
+{
+	unsigned int iMax = 4;
+	return  aiGetMaterialFloatArray(pMat,pKey,type,index,(float*)pOut,&iMax);
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Get a string from the material
 // Get a string from the material
 aiReturn aiGetMaterialString(const aiMaterial* pMat, 
 aiReturn aiGetMaterialString(const aiMaterial* pMat, 

+ 3 - 0
Source/ThirdParty/Assimp/code/ObjExporter.cpp

@@ -152,6 +152,9 @@ void ObjExporter :: WriteMaterialFile()
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_SPECULAR,c)) {
 			mOutputMat << "ks " << c.r << " " << c.g << " " << c.b << endl;
 			mOutputMat << "ks " << c.r << " " << c.g << " " << c.b << endl;
 		}
 		}
+		if(AI_SUCCESS == mat->Get(AI_MATKEY_COLOR_EMISSIVE,c)) {
+			mOutputMat << "ke " << c.r << " " << c.g << " " << c.b << endl;
+		}
 
 
 		float o;
 		float o;
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {
 		if(AI_SUCCESS == mat->Get(AI_MATKEY_OPACITY,o)) {

+ 3 - 1
Source/ThirdParty/Assimp/code/ObjFileData.h

@@ -183,6 +183,8 @@ struct Material
 	aiColor3D diffuse;
 	aiColor3D diffuse;
 	//!	Specular color
 	//!	Specular color
 	aiColor3D specular;
 	aiColor3D specular;
+	//!	Emissive color
+	aiColor3D emissive;
 	//!	Alpha value
 	//!	Alpha value
 	float alpha;
 	float alpha;
 	//!	Shineness factor
 	//!	Shineness factor
@@ -288,7 +290,7 @@ struct Model
 	//!	Active group
 	//!	Active group
 	std::string m_strActiveGroup;
 	std::string m_strActiveGroup;
 	//!	Vector with generated texture coordinates
 	//!	Vector with generated texture coordinates
-	std::vector<aiVector2D> m_TextureCoord;
+	std::vector<aiVector3D> m_TextureCoord;
 	//!	Current mesh instance
 	//!	Current mesh instance
 	Mesh *m_pCurrentMesh;
 	Mesh *m_pCurrentMesh;
 	//!	Vector with stored meshes
 	//!	Vector with stored meshes

+ 25 - 24
Source/ThirdParty/Assimp/code/ObjFileImporter.cpp

@@ -60,6 +60,7 @@ static const aiImporterDesc desc = {
 	"obj"
 	"obj"
 };
 };
 
 
+static const unsigned int ObjMinSize = 16;
 
 
 namespace Assimp	{
 namespace Assimp	{
 
 
@@ -80,12 +81,8 @@ ObjFileImporter::ObjFileImporter() :
 //	Destructor.
 //	Destructor.
 ObjFileImporter::~ObjFileImporter()
 ObjFileImporter::~ObjFileImporter()
 {
 {
-	// Release root object instance
-	if (NULL != m_pRootObject)
-	{
-		delete m_pRootObject;
-		m_pRootObject = NULL;
-	}
+	delete m_pRootObject;
+	m_pRootObject = NULL;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -118,12 +115,13 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
 	// Read file into memory
 	// Read file into memory
 	const std::string mode = "rb";
 	const std::string mode = "rb";
 	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode));
 	boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, mode));
-	if (NULL == file.get())
-		throw DeadlyImportError( "Failed to open file " + pFile + ".");
+    if( !file.get() ) {
+        throw DeadlyImportError( "Failed to open file " + pFile + "." );
+    }
 
 
 	// Get the file-size and validate it, throwing an exception when fails
 	// Get the file-size and validate it, throwing an exception when fails
 	size_t fileSize = file->FileSize();
 	size_t fileSize = file->FileSize();
-	if( fileSize < 16) {
+    if( fileSize < ObjMinSize ) {
 		throw DeadlyImportError( "OBJ-file is too small.");
 		throw DeadlyImportError( "OBJ-file is too small.");
     }
     }
 
 
@@ -154,10 +152,10 @@ void ObjFileImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Create the data from parsed obj-file
 //	Create the data from parsed obj-file
-void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene* pScene)
-{
-	if (0L == pModel)
-		return;
+void ObjFileImporter::CreateDataFromImport(const ObjFile::Model* pModel, aiScene* pScene) {
+    if( 0L == pModel ) {
+        return;
+    }
 		
 		
 	// Create the root node of the scene
 	// Create the root node of the scene
 	pScene->mRootNode = new aiNode;
 	pScene->mRootNode = new aiNode;
@@ -200,8 +198,9 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
 									 std::vector<aiMesh*> &MeshArray )
 									 std::vector<aiMesh*> &MeshArray )
 {
 {
 	ai_assert( NULL != pModel );
 	ai_assert( NULL != pModel );
-	if ( NULL == pObject )
-		return NULL;
+    if( NULL == pObject ) {
+        return NULL;
+    }
 	
 	
 	// Store older mesh size to be able to computes mesh offsets for new mesh instances
 	// Store older mesh size to be able to computes mesh offsets for new mesh instances
 	const size_t oldMeshSize = MeshArray.size();
 	const size_t oldMeshSize = MeshArray.size();
@@ -210,8 +209,9 @@ aiNode *ObjFileImporter::createNodes(const ObjFile::Model* pModel, const ObjFile
 	pNode->mName = pObject->m_strObjName;
 	pNode->mName = pObject->m_strObjName;
 	
 	
 	// If we have a parent node, store it
 	// If we have a parent node, store it
-	if (pParent != NULL)
-		appendChildToParentNode(pParent, pNode);
+    if( pParent != NULL ) {
+        appendChildToParentNode( pParent, pNode );
+    }
 
 
 	for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ )
 	for ( unsigned int i=0; i< pObject->m_Meshes.size(); i++ )
 	{
 	{
@@ -265,8 +265,9 @@ void ObjFileImporter::createTopology(const ObjFile::Model* pModel,
 {
 {
 	// Checking preconditions
 	// Checking preconditions
 	ai_assert( NULL != pModel );
 	ai_assert( NULL != pModel );
-	if (NULL == pData)
-		return;
+    if( NULL == pData ) {
+        return;
+    }
 
 
 	// Create faces
 	// Create faces
 	ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
 	ObjFile::Mesh *pObjMesh = pModel->m_Meshes[ uiMeshIndex ];
@@ -284,8 +285,7 @@ void ObjFileImporter::createTopology(const ObjFile::Model* pModel,
 		else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
 		else if (inp->m_PrimitiveType == aiPrimitiveType_POINT) {
 			pMesh->mNumFaces += inp->m_pVertices->size();
 			pMesh->mNumFaces += inp->m_pVertices->size();
 			pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
 			pMesh->mPrimitiveTypes |= aiPrimitiveType_POINT;
-		}
-		else {
+		} else {
 			++pMesh->mNumFaces;
 			++pMesh->mNumFaces;
 			if (inp->m_pVertices->size() > 3) {
 			if (inp->m_pVertices->size() > 3) {
 				pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
 				pMesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON;
@@ -409,10 +409,10 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel,
 				ai_assert( tex < pModel->m_TextureCoord.size() );
 				ai_assert( tex < pModel->m_TextureCoord.size() );
 					
 					
 				if ( tex >= pModel->m_TextureCoord.size() )
 				if ( tex >= pModel->m_TextureCoord.size() )
-					throw DeadlyImportError("OBJ: texture coord index out of range");
+					throw DeadlyImportError("OBJ: texture coordinate index out of range");
 
 
-				aiVector2D coord2d = pModel->m_TextureCoord[ tex ];
-				pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord2d.x, coord2d.y, 0.0 );
+				const aiVector3D &coord3d = pModel->m_TextureCoord[ tex ];
+                pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord3d.x, coord3d.y, coord3d.z );
 			}
 			}
 
 
 			ai_assert( pMesh->mNumVertices > newIndex );
 			ai_assert( pMesh->mNumVertices > newIndex );
@@ -550,6 +550,7 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc
 		mat->AddProperty( &pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT );
 		mat->AddProperty( &pCurrentMaterial->ambient, 1, AI_MATKEY_COLOR_AMBIENT );
 		mat->AddProperty( &pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
 		mat->AddProperty( &pCurrentMaterial->diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
 		mat->AddProperty( &pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR );
 		mat->AddProperty( &pCurrentMaterial->specular, 1, AI_MATKEY_COLOR_SPECULAR );
+		mat->AddProperty( &pCurrentMaterial->emissive, 1, AI_MATKEY_COLOR_EMISSIVE );
 		mat->AddProperty( &pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS );
 		mat->AddProperty( &pCurrentMaterial->shineness, 1, AI_MATKEY_SHININESS );
 		mat->AddProperty( &pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY );
 		mat->AddProperty( &pCurrentMaterial->alpha, 1, AI_MATKEY_OPACITY );
 
 

+ 5 - 0
Source/ThirdParty/Assimp/code/ObjFileMtlImporter.cpp

@@ -146,6 +146,11 @@ void ObjFileMtlImporter::load()
 					++m_DataIt;
 					++m_DataIt;
 					getColorRGBA( &m_pModel->m_pCurrentMaterial->specular );
 					getColorRGBA( &m_pModel->m_pCurrentMaterial->specular );
 				}
 				}
+				else if (*m_DataIt == 'e')
+				{
+					++m_DataIt;
+					getColorRGBA( &m_pModel->m_pCurrentMaterial->emissive );
+				}
 				m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 				m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 			}
 			}
 			break;
 			break;

+ 45 - 19
Source/ThirdParty/Assimp/code/ObjFileParser.cpp

@@ -108,19 +108,14 @@ void ObjFileParser::parseFile()
 		case 'v': // Parse a vertex texture coordinate
 		case 'v': // Parse a vertex texture coordinate
 			{
 			{
 				++m_DataIt;
 				++m_DataIt;
-				if (*m_DataIt == ' ' || *m_DataIt == '\t')
-				{
-					// Read in vertex definition
+				if (*m_DataIt == ' ' || *m_DataIt == '\t') {
+					// read in vertex definition
 					getVector3(m_pModel->m_Vertices);
 					getVector3(m_pModel->m_Vertices);
-				}
-				else if (*m_DataIt == 't')
-				{
-					// Read in texture coordinate (2D)
-					++m_DataIt;
-					getVector2(m_pModel->m_TextureCoord);
-				}
-				else if (*m_DataIt == 'n')
-				{
+				} else if (*m_DataIt == 't') {
+					// read in texture coordinate ( 2D or 3D )
+                    ++m_DataIt;
+                    getVector( m_pModel->m_TextureCoord );
+				} else if (*m_DataIt == 'n') {
 					// Read in normal vector definition
 					// Read in normal vector definition
 					++m_DataIt;
 					++m_DataIt;
 					getVector3( m_pModel->m_Normals );
 					getVector3( m_pModel->m_Normals );
@@ -235,10 +230,43 @@ void ObjFileParser::copyNextLine(char *pBuffer, size_t length)
 	pBuffer[ index ] = '\0';
 	pBuffer[ index ] = '\0';
 }
 }
 
 
+// -------------------------------------------------------------------
+void ObjFileParser::getVector( std::vector<aiVector3D> &point3d_array ) {
+    size_t numComponents( 0 );
+    DataArrayIt tmp( m_DataIt );
+    while( !IsLineEnd( *tmp ) ) {
+        if( *tmp == ' ' ) {
+            ++numComponents;
+        }
+        tmp++;
+    }
+    float x, y, z;
+    if( 2 == numComponents ) {
+        copyNextWord( m_buffer, BUFFERSIZE );
+        x = ( float ) fast_atof( m_buffer );
+
+        copyNextWord( m_buffer, BUFFERSIZE );
+        y = ( float ) fast_atof( m_buffer );
+        z = 0.0;
+    } else if( 3 == numComponents ) {
+        copyNextWord( m_buffer, BUFFERSIZE );
+        x = ( float ) fast_atof( m_buffer );
+
+        copyNextWord( m_buffer, BUFFERSIZE );
+        y = ( float ) fast_atof( m_buffer );
+
+        copyNextWord( m_buffer, BUFFERSIZE );
+        z = ( float ) fast_atof( m_buffer );
+    } else {
+        ai_assert( !"Invalid number of components" );
+    }
+    point3d_array.push_back( aiVector3D( x, y, z ) );
+    m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
+}
+
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
 //	Get values for a new 3D vector instance
 //	Get values for a new 3D vector instance
-void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array)
-{
+void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array) {
 	float x, y, z;
 	float x, y, z;
 	copyNextWord(m_buffer, BUFFERSIZE);
 	copyNextWord(m_buffer, BUFFERSIZE);
 	x = (float) fast_atof(m_buffer);	
 	x = (float) fast_atof(m_buffer);	
@@ -246,18 +274,16 @@ void ObjFileParser::getVector3(std::vector<aiVector3D> &point3d_array)
 	copyNextWord(m_buffer, BUFFERSIZE);
 	copyNextWord(m_buffer, BUFFERSIZE);
 	y = (float) fast_atof(m_buffer);
 	y = (float) fast_atof(m_buffer);
 
 
-	copyNextWord(m_buffer, BUFFERSIZE);
-	z = (float) fast_atof(m_buffer);
+    copyNextWord( m_buffer, BUFFERSIZE );
+    z = ( float ) fast_atof( m_buffer );
 
 
 	point3d_array.push_back( aiVector3D( x, y, z ) );
 	point3d_array.push_back( aiVector3D( x, y, z ) );
-	//skipLine();
 	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 	m_DataIt = skipLine<DataArrayIt>( m_DataIt, m_DataItEnd, m_uiLine );
 }
 }
 
 
 // -------------------------------------------------------------------
 // -------------------------------------------------------------------
 //	Get values for a new 2D vector instance
 //	Get values for a new 2D vector instance
-void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array )
-{
+void ObjFileParser::getVector2( std::vector<aiVector2D> &point2d_array ) {
 	float x, y;
 	float x, y;
 	copyNextWord(m_buffer, BUFFERSIZE);
 	copyNextWord(m_buffer, BUFFERSIZE);
 	x = (float) fast_atof(m_buffer);	
 	x = (float) fast_atof(m_buffer);	

+ 8 - 7
Source/ThirdParty/Assimp/code/ObjFileParser.h

@@ -37,8 +37,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
-
-
 #ifndef OBJ_FILEPARSER_H_INC
 #ifndef OBJ_FILEPARSER_H_INC
 #define OBJ_FILEPARSER_H_INC
 #define OBJ_FILEPARSER_H_INC
 
 
@@ -79,26 +77,29 @@ public:
 	ObjFile::Model *GetModel() const;
 	ObjFile::Model *GetModel() const;
 
 
 private:
 private:
-	///	Parse the loadedfile
+	///	Parse the loaded file
 	void parseFile();
 	void parseFile();
 	///	Method to copy the new delimited word in the current line.
 	///	Method to copy the new delimited word in the current line.
 	void copyNextWord(char *pBuffer, size_t length);
 	void copyNextWord(char *pBuffer, size_t length);
 	///	Method to copy the new line.
 	///	Method to copy the new line.
 	void copyNextLine(char *pBuffer, size_t length);
 	void copyNextLine(char *pBuffer, size_t length);
-	///	Stores the following 3d vector.
+    /// Stores the vector 
+    void getVector( std::vector<aiVector3D> &point3d_array );
+    ///	Stores the following 3d vector.
 	void getVector3( std::vector<aiVector3D> &point3d_array );
 	void getVector3( std::vector<aiVector3D> &point3d_array );
 	///	Stores the following 3d vector.
 	///	Stores the following 3d vector.
 	void getVector2(std::vector<aiVector2D> &point2d_array);
 	void getVector2(std::vector<aiVector2D> &point2d_array);
-	///	Stores the following face.
+    ///	Stores the following face.
 	void getFace(aiPrimitiveType type);
 	void getFace(aiPrimitiveType type);
-	void getMaterialDesc();
+	/// Reads the material description.
+    void getMaterialDesc();
 	///	Gets a comment.
 	///	Gets a comment.
 	void getComment();
 	void getComment();
 	/// Gets a a material library.
 	/// Gets a a material library.
 	void getMaterialLib();
 	void getMaterialLib();
 	/// Creates a new material.
 	/// Creates a new material.
 	void getNewMaterial();
 	void getNewMaterial();
-	/// Gets the groupname from file.
+	/// Gets the group name from file.
 	void getGroupName();
 	void getGroupName();
 	/// Gets the group number from file.
 	/// Gets the group number from file.
 	void getGroupNumber();
 	void getGroupNumber();

+ 1 - 1
Source/ThirdParty/Assimp/code/ObjTools.h

@@ -107,7 +107,7 @@ inline Char_T getNextWord( Char_T pBuffer, Char_T pEnd )
 	return pBuffer;
 	return pBuffer;
 }
 }
 
 
-/**	@brief	Returns ponter a next token
+/**	@brief	Returns pointer a next token
  *	@param	pBuffer	Pointer to data buffer
  *	@param	pBuffer	Pointer to data buffer
  *	@param	pEnd	Pointer to end of buffer
  *	@param	pEnd	Pointer to end of buffer
  *	@return	Pointer to next token
  *	@return	Pointer to next token

+ 1112 - 0
Source/ThirdParty/Assimp/code/OgreBinarySerializer.cpp

@@ -0,0 +1,1112 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#include "AssimpPCH.h"
+
+#include "OgreBinarySerializer.h"
+#include "OgreXmlSerializer.h"
+#include "OgreParsingUtils.h"
+
+#include "TinyFormatter.h"
+
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
+
+// Define as 1 to get verbose logging.
+#define OGRE_BINARY_SERIALIZER_DEBUG 0
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+const std::string       MESH_VERSION_1_8        = "[MeshSerializer_v1.8]";
+const std::string       SKELETON_VERSION_1_8    = "[Serializer_v1.80]";
+const std::string       SKELETON_VERSION_1_1    = "[Serializer_v1.10]";
+
+const unsigned short    HEADER_CHUNK_ID         = 0x1000;
+
+const long              MSTREAM_OVERHEAD_SIZE               = sizeof(uint16_t) + sizeof(uint32_t);
+const long              MSTREAM_BONE_SIZE_WITHOUT_SCALE     = MSTREAM_OVERHEAD_SIZE + sizeof(unsigned short) + (sizeof(float) * 7);
+const long              MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE = MSTREAM_OVERHEAD_SIZE + (sizeof(float) * 8);
+
+template<> 
+inline bool OgreBinarySerializer::Read<bool>()
+{
+	return (m_reader->GetU1() > 0);
+}
+
+template<> 
+inline char OgreBinarySerializer::Read<char>()
+{
+	return static_cast<char>(m_reader->GetU1());
+}
+
+template<> 
+inline uint8_t OgreBinarySerializer::Read<uint8_t>()
+{
+	return m_reader->GetU1();
+}
+
+template<> 
+inline uint16_t OgreBinarySerializer::Read<uint16_t>()
+{
+	return m_reader->GetU2();
+}
+
+template<> 
+inline uint32_t OgreBinarySerializer::Read<uint32_t>()
+{
+	return m_reader->GetU4();
+}
+
+template<> 
+inline float OgreBinarySerializer::Read<float>()
+{
+	return m_reader->GetF4();
+}
+
+void OgreBinarySerializer::ReadBytes(char *dest, size_t numBytes)
+{
+	ReadBytes(static_cast<void*>(dest), numBytes);
+}
+
+void OgreBinarySerializer::ReadBytes(uint8_t *dest, size_t numBytes)
+{
+	ReadBytes(static_cast<void*>(dest), numBytes);
+}
+
+void OgreBinarySerializer::ReadBytes(void *dest, size_t numBytes)
+{
+	m_reader->CopyAndAdvance(dest, numBytes);
+}
+
+uint8_t *OgreBinarySerializer::ReadBytes(size_t numBytes)
+{
+	uint8_t *bytes = new uint8_t[numBytes];
+	ReadBytes(bytes, numBytes);
+	return bytes;
+}
+
+void OgreBinarySerializer::ReadVector(aiVector3D &vec)
+{
+	m_reader->CopyAndAdvance(&vec.x, sizeof(float)*3);
+}
+
+void OgreBinarySerializer::ReadQuaternion(aiQuaternion &quat)
+{
+	float temp[4];
+	m_reader->CopyAndAdvance(temp, sizeof(float)*4);
+	quat.x = temp[0];
+	quat.y = temp[1];
+	quat.z = temp[2];
+	quat.w = temp[3];
+}
+
+bool OgreBinarySerializer::AtEnd() const
+{
+	return (m_reader->GetRemainingSize() == 0);
+}
+
+std::string OgreBinarySerializer::ReadString(size_t len)
+{
+	std::string str;
+	str.resize(len);
+	ReadBytes(&str[0], len);
+	return str;
+}
+
+std::string OgreBinarySerializer::ReadLine()
+{
+	std::string str;
+	while(!AtEnd())
+	{
+		char c = Read<char>();
+		if (c == '\n')
+			break;
+		str += c;
+	}
+	return str;
+}
+
+uint16_t OgreBinarySerializer::ReadHeader(bool readLen)
+{
+	uint16_t id = Read<uint16_t>();
+	if (readLen)
+		m_currentLen = Read<uint32_t>();
+
+#if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
+	if (id != HEADER_CHUNK_ID)
+	{
+		DefaultLogger::get()->debug(Formatter::format() << (assetMode == AM_Mesh 
+			? MeshHeaderToString(static_cast<MeshChunkId>(id)) : SkeletonHeaderToString(static_cast<SkeletonChunkId>(id))));
+	}
+#endif
+
+	return id;
+}
+
+void OgreBinarySerializer::RollbackHeader()
+{
+	m_reader->IncPtr(-MSTREAM_OVERHEAD_SIZE);
+}
+
+void OgreBinarySerializer::SkipBytes(size_t numBytes)
+{
+#if (OGRE_BINARY_SERIALIZER_DEBUG == 1)
+	DefaultLogger::get()->debug(Formatter::format() << "Skipping " << numBytes << " bytes");
+#endif
+
+	m_reader->IncPtr(numBytes);
+}
+
+// Mesh
+
+Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream)
+{
+	OgreBinarySerializer serializer(stream, OgreBinarySerializer::AM_Mesh);
+	
+	uint16_t id = serializer.ReadHeader(false);
+	if (id != HEADER_CHUNK_ID) {
+		throw DeadlyExportError("Invalid Ogre Mesh file header.");
+	}
+
+	/// @todo Check what we can actually support.
+	std::string version = serializer.ReadLine();
+	if (version != MESH_VERSION_1_8)
+	{
+		throw DeadlyExportError(Formatter::format() << "Mesh version " << version << " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again."
+			<< " Supported versions: " << MESH_VERSION_1_8);
+	}
+
+	Mesh *mesh = new Mesh();
+	while (!serializer.AtEnd())
+	{
+		id = serializer.ReadHeader();
+		switch(id)
+		{
+			case M_MESH:
+			{
+				serializer.ReadMesh(mesh);
+				break;
+			}
+		}
+	}
+	return mesh;
+}
+
+void OgreBinarySerializer::ReadMesh(Mesh *mesh)
+{
+	mesh->hasSkeletalAnimations = Read<bool>();
+
+	DefaultLogger::get()->debug("Reading Mesh");
+	DefaultLogger::get()->debug(Formatter::format() << "  - Skeletal animations: " << (mesh->hasSkeletalAnimations ? "true" : "false"));
+	
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		while (!AtEnd() &&
+			(id == M_GEOMETRY ||
+			 id == M_SUBMESH ||
+			 id == M_MESH_SKELETON_LINK ||
+			 id == M_MESH_BONE_ASSIGNMENT ||
+			 id == M_MESH_LOD ||
+			 id == M_MESH_BOUNDS ||
+			 id == M_SUBMESH_NAME_TABLE ||
+			 id == M_EDGE_LISTS ||
+			 id == M_POSES ||
+			 id == M_ANIMATIONS ||
+			 id == M_TABLE_EXTREMES))
+		{
+			switch(id)
+			{
+				case M_GEOMETRY:
+				{
+					mesh->sharedVertexData = new VertexData();
+					ReadGeometry(mesh->sharedVertexData);
+					break;
+				}
+				case M_SUBMESH:
+				{
+					ReadSubMesh(mesh);
+					break;
+				}
+				case M_MESH_SKELETON_LINK:
+				{
+					ReadMeshSkeletonLink(mesh);
+					break;
+				}
+				case M_MESH_BONE_ASSIGNMENT:
+				{
+					ReadBoneAssignment(mesh->sharedVertexData);
+					break;
+				}
+				case M_MESH_LOD:
+				{
+					ReadMeshLodInfo(mesh);
+					break;
+				}
+				case M_MESH_BOUNDS:
+				{
+					ReadMeshBounds(mesh);
+					break;
+				}
+				case M_SUBMESH_NAME_TABLE:
+				{
+					ReadSubMeshNames(mesh);
+					break;
+				}
+				case M_EDGE_LISTS:
+				{
+					ReadEdgeList(mesh);
+					break;
+				}
+				case M_POSES:
+				{
+					ReadPoses(mesh);
+					break;
+				}
+				case M_ANIMATIONS:
+				{
+					ReadAnimations(mesh);
+					break;
+				}
+				case M_TABLE_EXTREMES:
+				{
+					ReadMeshExtremes(mesh);
+					break;
+				}
+			}
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+
+	NormalizeBoneWeights(mesh->sharedVertexData);
+}
+
+void OgreBinarySerializer::ReadMeshLodInfo(Mesh *mesh)
+{
+	// Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
+	// @todo Put this stuff to scene/mesh custom properties. If manual mesh the app can use the information.
+	ReadLine(); // strategy name
+	uint16_t numLods = Read<uint16_t>();
+	bool manual = Read<bool>();
+	
+	/// @note Main mesh is considered as LOD 0, start from index 1.
+	for (size_t i=1; i<numLods; ++i)
+	{
+		uint16_t id = ReadHeader();
+		if (id != M_MESH_LOD_USAGE) {
+			throw DeadlyImportError("M_MESH_LOD does not contain a M_MESH_LOD_USAGE for each LOD level");
+		}
+
+		m_reader->IncPtr(sizeof(float)); // user value
+
+		if (manual)
+		{
+			id = ReadHeader();
+			if (id != M_MESH_LOD_MANUAL) {
+				throw DeadlyImportError("Manual M_MESH_LOD_USAGE does not contain M_MESH_LOD_MANUAL");
+			}
+				
+			ReadLine(); // manual mesh name (ref to another mesh)
+		}
+		else
+		{
+			for(size_t si=0, silen=mesh->NumSubMeshes(); si<silen; ++si)
+			{
+				id = ReadHeader();
+				if (id != M_MESH_LOD_GENERATED) {
+					throw DeadlyImportError("Generated M_MESH_LOD_USAGE does not contain M_MESH_LOD_GENERATED");
+				}
+
+				uint32_t indexCount = Read<uint32_t>();
+				bool is32bit = Read<bool>();
+
+				if (indexCount > 0)
+				{
+					uint32_t len = indexCount * (is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
+					m_reader->IncPtr(len);
+				}
+			}
+		}
+	}
+}
+
+void OgreBinarySerializer::ReadMeshSkeletonLink(Mesh *mesh)
+{
+	mesh->skeletonRef = ReadLine();
+}
+
+void OgreBinarySerializer::ReadMeshBounds(Mesh *mesh)
+{
+	// Skip bounds, not compatible with Assimp.
+	// 2x float vec3 + 1x float sphere radius
+	SkipBytes(sizeof(float) * 7);
+}
+
+void OgreBinarySerializer::ReadMeshExtremes(Mesh *mesh)
+{
+	// Skip extremes, not compatible with Assimp.
+	size_t numBytes = m_currentLen - MSTREAM_OVERHEAD_SIZE; 
+	SkipBytes(numBytes);
+}
+
+void OgreBinarySerializer::ReadBoneAssignment(VertexData *dest)
+{
+	if (!dest) {
+		throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
+	}
+		
+	VertexBoneAssignment ba;
+	ba.vertexIndex = Read<uint32_t>();
+	ba.boneIndex = Read<uint16_t>();
+	ba.weight = Read<float>();
+
+	dest->boneAssignments.push_back(ba);
+}
+
+void OgreBinarySerializer::ReadSubMesh(Mesh *mesh)
+{
+	uint16_t id = 0;
+	
+	SubMesh *submesh = new SubMesh();
+	submesh->materialRef = ReadLine();
+	submesh->usesSharedVertexData = Read<bool>();
+
+	submesh->indexData->count = Read<uint32_t>();
+	submesh->indexData->faceCount = static_cast<uint32_t>(submesh->indexData->count / 3);
+	submesh->indexData->is32bit = Read<bool>();
+
+	DefaultLogger::get()->debug(Formatter::format() << "Reading SubMesh " << mesh->subMeshes.size());
+	DefaultLogger::get()->debug(Formatter::format() << "  - Material: '" << submesh->materialRef << "'");
+	DefaultLogger::get()->debug(Formatter::format() << "  - Uses shared geometry: " << (submesh->usesSharedVertexData ? "true" : "false"));
+
+	// Index buffer
+	if (submesh->indexData->count > 0)
+	{
+		uint32_t numBytes = submesh->indexData->count * (submesh->indexData->is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
+		uint8_t *indexBuffer = ReadBytes(numBytes);
+		submesh->indexData->buffer = MemoryStreamPtr(new Assimp::MemoryIOStream(indexBuffer, numBytes, true));
+
+		DefaultLogger::get()->debug(Formatter::format() << "  - " << submesh->indexData->faceCount 
+			<< " faces from " << submesh->indexData->count << (submesh->indexData->is32bit ? " 32bit" : " 16bit") 
+			<< " indexes of " << numBytes << " bytes");
+	}
+	
+	// Vertex buffer if not referencing the shared geometry
+	if (!submesh->usesSharedVertexData)
+	{
+		id = ReadHeader();
+		if (id != M_GEOMETRY) {
+			throw DeadlyImportError("M_SUBMESH does not contain M_GEOMETRY, but shader geometry is set to false");
+		}
+
+		submesh->vertexData = new VertexData();
+		ReadGeometry(submesh->vertexData);
+	}
+	
+	// Bone assignment, submesh operation and texture aliases
+	if (!AtEnd())
+	{
+		id = ReadHeader();
+		while (!AtEnd() &&
+			(id == M_SUBMESH_OPERATION ||
+			 id == M_SUBMESH_BONE_ASSIGNMENT ||
+			 id == M_SUBMESH_TEXTURE_ALIAS))
+		{
+			switch(id)
+			{
+				case M_SUBMESH_OPERATION:
+				{
+					ReadSubMeshOperation(submesh);
+					break;
+				}
+				case M_SUBMESH_BONE_ASSIGNMENT:
+				{
+					ReadBoneAssignment(submesh->vertexData);
+					break;
+				}
+				case M_SUBMESH_TEXTURE_ALIAS:
+				{
+					ReadSubMeshTextureAlias(submesh);
+					break;
+				}
+			}
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+
+	NormalizeBoneWeights(submesh->vertexData);
+
+	submesh->index = mesh->subMeshes.size();
+	mesh->subMeshes.push_back(submesh);
+}
+
+void OgreBinarySerializer::NormalizeBoneWeights(VertexData *vertexData) const
+{
+	if (!vertexData || vertexData->boneAssignments.empty())
+		return;
+
+	std::set<uint32_t> influencedVertices;
+	for (VertexBoneAssignmentList::const_iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter) {
+		influencedVertices.insert(baIter->vertexIndex);
+	}
+
+	/** Normalize bone weights.
+		Some exporters wont care if the sum of all bone weights
+		for a single vertex equals 1 or not, so validate here. */
+	const float epsilon = 0.05f;
+	for(std::set<uint32_t>::const_iterator iter=influencedVertices.begin(), end=influencedVertices.end(); iter != end; ++iter)
+	{
+		const uint32_t vertexIndex = (*iter);
+
+		float sum = 0.0f;
+		for (VertexBoneAssignmentList::const_iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter)
+		{
+			if (baIter->vertexIndex == vertexIndex)
+				sum += baIter->weight;
+		}
+		if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon)))
+		{
+			for (VertexBoneAssignmentList::iterator baIter=vertexData->boneAssignments.begin(), baEnd=vertexData->boneAssignments.end(); baIter != baEnd; ++baIter)
+			{
+				if (baIter->vertexIndex == vertexIndex)
+					baIter->weight /= sum;
+			}
+		}
+	}
+}
+
+void OgreBinarySerializer::ReadSubMeshOperation(SubMesh *submesh)
+{
+	submesh->operationType = static_cast<SubMesh::OperationType>(Read<uint16_t>());
+}
+
+void OgreBinarySerializer::ReadSubMeshTextureAlias(SubMesh *submesh)
+{
+	submesh->textureAliasName = ReadLine();
+	submesh->textureAliasRef = ReadLine();
+}
+
+void OgreBinarySerializer::ReadSubMeshNames(Mesh *mesh)
+{
+	uint16_t id = 0;
+	uint16_t submeshIndex = 0;
+
+	if (!AtEnd())
+	{
+		id = ReadHeader();
+		while (!AtEnd() && id == M_SUBMESH_NAME_TABLE_ELEMENT)
+		{
+			uint16_t submeshIndex = Read<uint16_t>();
+			SubMesh *submesh = mesh->GetSubMesh(submeshIndex);
+			if (!submesh) {
+				throw DeadlyImportError(Formatter::format() << "Ogre Mesh does not include submesh " << submeshIndex << " referenced in M_SUBMESH_NAME_TABLE_ELEMENT. Invalid mesh file.");
+			}
+
+			submesh->name = ReadLine();
+			DefaultLogger::get()->debug(Formatter::format() << "  - SubMesh " << submesh->index << " name '" << submesh->name << "'");
+			
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadGeometry(VertexData *dest)
+{
+	dest->count = Read<uint32_t>();
+	
+	DefaultLogger::get()->debug(Formatter::format() << "  - Reading geometry of " << dest->count << " vertices");
+	
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		while (!AtEnd() &&
+			(id == M_GEOMETRY_VERTEX_DECLARATION ||
+			 id == M_GEOMETRY_VERTEX_BUFFER))
+		{
+			switch(id)
+			{
+				case M_GEOMETRY_VERTEX_DECLARATION:
+				{
+					ReadGeometryVertexDeclaration(dest);
+					break;
+				}
+				case M_GEOMETRY_VERTEX_BUFFER:
+				{
+					ReadGeometryVertexBuffer(dest);
+					break;
+				}
+			}
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadGeometryVertexDeclaration(VertexData *dest)
+{
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		while (!AtEnd() && id == M_GEOMETRY_VERTEX_ELEMENT)
+		{
+			ReadGeometryVertexElement(dest);
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadGeometryVertexElement(VertexData *dest)
+{
+	VertexElement element;
+	element.source = Read<uint16_t>();
+	element.type = static_cast<VertexElement::Type>(Read<uint16_t>());
+	element.semantic = static_cast<VertexElement::Semantic>(Read<uint16_t>());
+	element.offset = Read<uint16_t>();
+	element.index = Read<uint16_t>();
+
+	DefaultLogger::get()->debug(Formatter::format() << "    - Vertex element " << element.SemanticToString() << " of type " 
+		<< element.TypeToString() << " index=" << element.index << " source=" << element.source);
+
+	dest->vertexElements.push_back(element);
+}
+
+void OgreBinarySerializer::ReadGeometryVertexBuffer(VertexData *dest)
+{
+	uint16_t bindIndex = Read<uint16_t>();
+	uint16_t vertexSize = Read<uint16_t>();
+	
+	uint16_t id = ReadHeader();
+	if (id != M_GEOMETRY_VERTEX_BUFFER_DATA)
+		throw DeadlyImportError("M_GEOMETRY_VERTEX_BUFFER_DATA not found in M_GEOMETRY_VERTEX_BUFFER");
+
+	if (dest->VertexSize(bindIndex) != vertexSize)
+		throw DeadlyImportError("Vertex buffer size does not agree with vertex declaration in M_GEOMETRY_VERTEX_BUFFER");
+
+	size_t numBytes = dest->count * vertexSize;
+	uint8_t *vertexBuffer = ReadBytes(numBytes);
+	dest->vertexBindings[bindIndex] = MemoryStreamPtr(new Assimp::MemoryIOStream(vertexBuffer, numBytes, true));
+	
+	DefaultLogger::get()->debug(Formatter::format() << "    - Read vertex buffer for source " << bindIndex << " of " << numBytes << " bytes");
+}
+
+void OgreBinarySerializer::ReadEdgeList(Mesh *mesh)
+{
+	// Assimp does not acknowledge LOD levels as far as I can see it. This info is just skipped.
+
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		while (!AtEnd() && id == M_EDGE_LIST_LOD)
+		{
+			m_reader->IncPtr(sizeof(uint16_t)); // lod index
+			bool manual = Read<bool>();
+
+			if (!manual)
+			{
+				m_reader->IncPtr(sizeof(uint8_t));
+				uint32_t numTriangles = Read<uint32_t>();
+				uint32_t numEdgeGroups = Read<uint32_t>();
+				
+				size_t skipBytes = (sizeof(uint32_t) * 8 + sizeof(float) * 4) * numTriangles;
+				m_reader->IncPtr(skipBytes);
+
+				for (size_t i=0; i<numEdgeGroups; ++i)
+				{
+					uint16_t id = ReadHeader();
+					if (id != M_EDGE_GROUP)
+						throw DeadlyImportError("M_EDGE_GROUP not found in M_EDGE_LIST_LOD");
+						
+					m_reader->IncPtr(sizeof(uint32_t) * 3);
+					uint32_t numEdges = Read<uint32_t>();
+					for (size_t j=0; j<numEdges; ++j)
+					{
+						m_reader->IncPtr(sizeof(uint32_t) * 6 + sizeof(uint8_t));
+					}
+				}
+			}
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadPoses(Mesh *mesh)
+{
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		while (!AtEnd() && id == M_POSE)
+		{
+			Pose *pose = new Pose();
+			pose->name = ReadLine();
+			pose->target = Read<uint16_t>();
+			pose->hasNormals = Read<bool>();
+
+			ReadPoseVertices(pose);
+			
+			mesh->poses.push_back(pose);
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadPoseVertices(Pose *pose)
+{
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		while (!AtEnd() && id == M_POSE_VERTEX)
+		{
+			Pose::Vertex v;
+			v.index = Read<uint32_t>();
+			ReadVector(v.offset);
+			if (pose->hasNormals)
+				ReadVector(v.normal);
+
+			pose->vertices[v.index] = v;
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadAnimations(Mesh *mesh)
+{
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		while (!AtEnd() && id == M_ANIMATION)
+		{
+			Animation *anim = new Animation(mesh);
+			anim->name = ReadLine();
+			anim->length = Read<float>();
+			
+			ReadAnimation(anim);
+
+			mesh->animations.push_back(anim);
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadAnimation(Animation *anim)
+{	
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		if (id == M_ANIMATION_BASEINFO)
+		{
+			anim->baseName = ReadLine();
+			anim->baseTime = Read<float>();
+
+			// Advance to first track
+			id = ReadHeader();
+		}
+		
+		while (!AtEnd() && id == M_ANIMATION_TRACK)
+		{
+			VertexAnimationTrack track;
+			track.type = static_cast<VertexAnimationTrack::Type>(Read<uint16_t>());
+			track.target = Read<uint16_t>();
+
+			ReadAnimationKeyFrames(anim, &track);
+			
+			anim->tracks.push_back(track);
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *track)
+{
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		while (!AtEnd() && 
+			(id == M_ANIMATION_MORPH_KEYFRAME ||
+			 id == M_ANIMATION_POSE_KEYFRAME))
+		{
+			if (id == M_ANIMATION_MORPH_KEYFRAME)
+			{
+				MorphKeyFrame kf;
+				kf.timePos = Read<float>();
+				bool hasNormals = Read<bool>();
+				
+				size_t vertexCount = anim->AssociatedVertexData(track)->count;
+				size_t vertexSize = sizeof(float) * (hasNormals ? 6 : 3);
+				size_t numBytes = vertexCount * vertexSize;
+
+				uint8_t *morphBuffer = ReadBytes(numBytes);
+				kf.buffer = MemoryStreamPtr(new Assimp::MemoryIOStream(morphBuffer, numBytes, true));
+
+				track->morphKeyFrames.push_back(kf);
+			}
+			else if (id == M_ANIMATION_POSE_KEYFRAME)
+			{
+				PoseKeyFrame kf;
+				kf.timePos = Read<float>();
+				
+				if (!AtEnd())
+				{
+					id = ReadHeader();
+					while (!AtEnd() && id == M_ANIMATION_POSE_REF)
+					{
+						PoseRef pr;
+						pr.index = Read<uint16_t>();
+						pr.influence = Read<float>();
+						kf.references.push_back(pr);
+						
+						if (!AtEnd())
+							id = ReadHeader();
+					}
+					if (!AtEnd())
+						RollbackHeader();
+				}
+				
+				track->poseKeyFrames.push_back(kf);
+			}
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+// Skeleton
+
+bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh)
+{
+	if (!mesh || mesh->skeletonRef.empty())
+		return false;
+
+	// Highly unusual to see in read world cases but support
+	// binary mesh referencing a XML skeleton file.
+	if (EndsWith(mesh->skeletonRef, ".skeleton.xml", false))
+	{
+		OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh);
+		return false;
+	}
+	
+	MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
+		
+	Skeleton *skeleton = new Skeleton();
+	OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
+	serializer.ReadSkeleton(skeleton);
+	mesh->skeleton = skeleton;
+	return true;
+}
+
+bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh)
+{
+	if (!mesh || mesh->skeletonRef.empty())
+		return false;
+
+	MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
+	if (!reader.get())
+		return false;
+
+	Skeleton *skeleton = new Skeleton();
+	OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton);
+	serializer.ReadSkeleton(skeleton);
+	mesh->skeleton = skeleton;
+	return true;
+}
+
+MemoryStreamReaderPtr OgreBinarySerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename)
+{
+	if (!EndsWith(filename, ".skeleton", false))
+	{
+		DefaultLogger::get()->error("Imported Mesh is referencing to unsupported '" + filename + "' skeleton file.");
+		return MemoryStreamReaderPtr();
+	}
+
+	if (!pIOHandler->Exists(filename))
+	{
+		DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "' that is referenced by imported Mesh.");
+		return MemoryStreamReaderPtr();
+	}
+
+	IOStream *f = pIOHandler->Open(filename, "rb");
+	if (!f) {
+		throw DeadlyImportError("Failed to open skeleton file " + filename);
+	}
+
+	return MemoryStreamReaderPtr(new MemoryStreamReader(f));
+}
+
+void OgreBinarySerializer::ReadSkeleton(Skeleton *skeleton)
+{
+	uint16_t id = ReadHeader(false);
+	if (id != HEADER_CHUNK_ID) {
+		throw DeadlyExportError("Invalid Ogre Skeleton file header.");
+	}
+
+	// This deserialization supports both versions of the skeleton spec
+	std::string version = ReadLine();
+	if (version != SKELETON_VERSION_1_8 && version != SKELETON_VERSION_1_1)
+	{
+		throw DeadlyExportError(Formatter::format() << "Skeleton version " << version << " not supported by this importer."
+			<< " Supported versions: " << SKELETON_VERSION_1_8 << " and " << SKELETON_VERSION_1_1);
+	}
+	
+	DefaultLogger::get()->debug("Reading Skeleton");
+	
+	bool firstBone = true;
+	bool firstAnim = true;
+
+	while (!AtEnd())
+	{
+		id = ReadHeader();
+		switch(id)
+		{
+			case SKELETON_BLENDMODE:
+			{
+				skeleton->blendMode = static_cast<Skeleton::BlendMode>(Read<uint16_t>());
+				break;
+			}
+			case SKELETON_BONE:
+			{
+				if (firstBone)
+				{
+					DefaultLogger::get()->debug("  - Bones");
+					firstBone = false;
+				}
+
+				ReadBone(skeleton);
+				break;
+			}
+			case SKELETON_BONE_PARENT:
+			{
+				ReadBoneParent(skeleton);
+				break;
+			}
+			case SKELETON_ANIMATION:
+			{
+				if (firstAnim)
+				{
+					DefaultLogger::get()->debug("  - Animations");
+					firstAnim = false;
+				}
+
+				ReadSkeletonAnimation(skeleton);
+				break;
+			}
+			case SKELETON_ANIMATION_LINK:
+			{
+				ReadSkeletonAnimationLink(skeleton);
+				break;
+			}
+		}
+	}
+	
+	// Calculate bone matrices for root bones. Recursively calculates their children.
+	for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
+	{
+		Bone *bone = skeleton->bones[i];
+		if (!bone->IsParented())
+			bone->CalculateWorldMatrixAndDefaultPose(skeleton);
+	}
+}
+
+void OgreBinarySerializer::ReadBone(Skeleton *skeleton)
+{
+	Bone *bone = new Bone();
+	bone->name = ReadLine();
+	bone->id = Read<uint16_t>();
+
+	// Pos and rot
+	ReadVector(bone->position);
+	ReadQuaternion(bone->rotation);
+
+	// Scale (optional)
+	if (m_currentLen > MSTREAM_BONE_SIZE_WITHOUT_SCALE)
+		ReadVector(bone->scale);
+
+	// Bone indexes need to start from 0 and be contiguous
+	if (bone->id != skeleton->bones.size()) {
+		throw DeadlyImportError(Formatter::format() << "Ogre Skeleton bone indexes not contiguous. Error at bone index " << bone->id);
+	}
+
+	DefaultLogger::get()->debug(Formatter::format() << "    " << bone->id << " " << bone->name);
+
+	skeleton->bones.push_back(bone);
+}
+
+void OgreBinarySerializer::ReadBoneParent(Skeleton *skeleton)
+{
+	uint16_t childId = Read<uint16_t>();
+	uint16_t parentId = Read<uint16_t>();
+	
+	Bone *child = skeleton->BoneById(childId);
+	Bone *parent = skeleton->BoneById(parentId);
+	
+	if (child && parent)
+		parent->AddChild(child);
+	else
+		throw DeadlyImportError(Formatter::format() << "Failed to find bones for parenting: Child id " << childId << " for parent id " << parentId);
+}
+
+void OgreBinarySerializer::ReadSkeletonAnimation(Skeleton *skeleton)
+{
+	Animation *anim = new Animation(skeleton);
+	anim->name = ReadLine();
+	anim->length = Read<float>();
+	
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		if (id == SKELETON_ANIMATION_BASEINFO)
+		{
+			anim->baseName = ReadLine();
+			anim->baseTime = Read<float>();
+
+			// Advance to first track
+			id = ReadHeader();
+		}
+
+		while (!AtEnd() && id == SKELETON_ANIMATION_TRACK)
+		{
+			ReadSkeletonAnimationTrack(skeleton, anim);
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+	
+	skeleton->animations.push_back(anim);
+	
+	DefaultLogger::get()->debug(Formatter::format() << "    " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)");	
+}
+
+void OgreBinarySerializer::ReadSkeletonAnimationTrack(Skeleton *skeleton, Animation *dest)
+{
+	uint16_t boneId = Read<uint16_t>();
+	Bone *bone = dest->parentSkeleton->BoneById(boneId);
+	if (!bone) {
+		throw DeadlyImportError(Formatter::format() << "Cannot read animation track, target bone " << boneId << " not in target Skeleton");
+	}
+	
+	VertexAnimationTrack track;
+	track.type = VertexAnimationTrack::VAT_TRANSFORM;
+	track.boneName = bone->name;
+	
+	uint16_t id = ReadHeader();
+	while (!AtEnd() && id == SKELETON_ANIMATION_TRACK_KEYFRAME)
+	{
+		ReadSkeletonAnimationKeyFrame(&track);
+
+		if (!AtEnd())
+			id = ReadHeader();
+	}
+	if (!AtEnd())
+		RollbackHeader();
+
+	dest->tracks.push_back(track);
+}
+
+void OgreBinarySerializer::ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest)
+{
+	TransformKeyFrame keyframe;
+	keyframe.timePos = Read<float>();
+	
+	// Rot and pos
+	ReadQuaternion(keyframe.rotation);
+	ReadVector(keyframe.position);
+	
+	// Scale (optional)
+	if (m_currentLen > MSTREAM_KEYFRAME_SIZE_WITHOUT_SCALE)
+		ReadVector(keyframe.scale);
+		
+	dest->transformKeyFrames.push_back(keyframe);
+}
+
+void OgreBinarySerializer::ReadSkeletonAnimationLink(Skeleton *skeleton)
+{
+	// Skip bounds, not compatible with Assimp.
+	ReadLine(); // skeleton name
+	SkipBytes(sizeof(float) * 3); // scale
+}
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER

+ 416 - 0
Source/ThirdParty/Assimp/code/OgreBinarySerializer.h

@@ -0,0 +1,416 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef AI_OGREBINARYSERIALIZER_H_INC
+#define AI_OGREBINARYSERIALIZER_H_INC
+
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
+
+#include "OgreStructs.h"
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+typedef Assimp::StreamReaderLE MemoryStreamReader;
+typedef boost::shared_ptr<MemoryStreamReader> MemoryStreamReaderPtr;
+
+class OgreBinarySerializer
+{
+public:
+	/// Imports mesh and returns the result.
+	/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
+	static Mesh *ImportMesh(MemoryStreamReader *reader);
+
+	/// Imports skeleton to @c mesh into Mesh::skeleton.
+	/** If mesh does not have a skeleton reference or the skeleton file
+		cannot be found it is not a fatal DeadlyImportError.
+		@return If skeleton import was successful. */
+	static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
+	static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
+
+private:
+	enum AssetMode
+	{
+		AM_Mesh,
+		AM_Skeleton
+	};
+	
+	OgreBinarySerializer(MemoryStreamReader *reader, AssetMode mode) :
+		m_reader(reader),
+		m_currentLen(0),
+		assetMode(mode)
+	{
+	}
+	
+	static MemoryStreamReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename);
+
+	// Header
+
+	uint16_t ReadHeader(bool readLen = true);
+	void RollbackHeader();
+
+	// Mesh
+
+	void ReadMesh(Mesh *mesh);
+	void ReadMeshLodInfo(Mesh *mesh);
+	void ReadMeshSkeletonLink(Mesh *mesh);
+	void ReadMeshBounds(Mesh *mesh);
+	void ReadMeshExtremes(Mesh *mesh);
+
+	void ReadSubMesh(Mesh *mesh);
+	void ReadSubMeshNames(Mesh *mesh);
+	void ReadSubMeshOperation(SubMesh *submesh);
+	void ReadSubMeshTextureAlias(SubMesh *submesh);
+
+	void ReadBoneAssignment(VertexData *dest);
+
+	void ReadGeometry(VertexData *dest);
+	void ReadGeometryVertexDeclaration(VertexData *dest);
+	void ReadGeometryVertexElement(VertexData *dest);
+	void ReadGeometryVertexBuffer(VertexData *dest);
+
+	void ReadEdgeList(Mesh *mesh);
+	void ReadPoses(Mesh *mesh);
+	void ReadPoseVertices(Pose *pose);
+	
+	void ReadAnimations(Mesh *mesh);
+	void ReadAnimation(Animation *anim);
+	void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *track);
+
+	void NormalizeBoneWeights(VertexData *vertexData) const;
+
+	// Skeleton
+	
+	void ReadSkeleton(Skeleton *skeleton);
+	
+	void ReadBone(Skeleton *skeleton);
+	void ReadBoneParent(Skeleton *skeleton);
+	
+	void ReadSkeletonAnimation(Skeleton *skeleton);
+	void ReadSkeletonAnimationTrack(Skeleton *skeleton, Animation *dest);
+	void ReadSkeletonAnimationKeyFrame(VertexAnimationTrack *dest);
+	void ReadSkeletonAnimationLink(Skeleton *skeleton);
+
+	// Reader utils
+	bool AtEnd() const;
+	
+	template<typename T> 
+	inline T Read();
+
+	void ReadBytes(char *dest, size_t numBytes);
+	void ReadBytes(uint8_t *dest, size_t numBytes);
+	void ReadBytes(void *dest, size_t numBytes);
+	uint8_t *ReadBytes(size_t numBytes);
+	
+	void ReadVector(aiVector3D &vec);
+	void ReadQuaternion(aiQuaternion &quat);
+
+	std::string ReadString(size_t len);
+	std::string ReadLine();
+
+	void SkipBytes(size_t numBytes);
+
+	uint32_t m_currentLen;
+	MemoryStreamReader *m_reader;
+
+	AssetMode assetMode;
+};
+
+enum MeshChunkId
+{
+	M_HEADER = 0x1000,
+		// char*		  version		   : Version number check
+	M_MESH   = 0x3000,
+		// bool skeletallyAnimated   // important flag which affects h/w buffer policies
+		// Optional M_GEOMETRY chunk
+		M_SUBMESH			 = 0x4000, 
+			// char* materialName
+			// bool useSharedVertices
+			// unsigned int indexCount
+			// bool indexes32Bit
+			// unsigned int* faceVertexIndices (indexCount)
+			// OR
+			// unsigned short* faceVertexIndices (indexCount)
+			// M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
+			M_SUBMESH_OPERATION = 0x4010, // optional, trilist assumed if missing
+				// unsigned short operationType
+			M_SUBMESH_BONE_ASSIGNMENT = 0x4100,
+				// Optional bone weights (repeating section)
+				// unsigned int vertexIndex;
+				// unsigned short boneIndex;
+				// float weight;
+			// Optional chunk that matches a texture name to an alias
+			// a texture alias is sent to the submesh material to use this texture name
+			// instead of the one in the texture unit with a matching alias name
+			M_SUBMESH_TEXTURE_ALIAS = 0x4200, // Repeating section
+				// char* aliasName;
+				// char* textureName;
+
+		M_GEOMETRY		  = 0x5000, // NB this chunk is embedded within M_MESH and M_SUBMESH
+			// unsigned int vertexCount
+			M_GEOMETRY_VERTEX_DECLARATION = 0x5100,
+				M_GEOMETRY_VERTEX_ELEMENT = 0x5110, // Repeating section
+					// unsigned short source;  	// buffer bind source
+					// unsigned short type;		// VertexElementType
+					// unsigned short semantic; // VertexElementSemantic
+					// unsigned short offset;	// start offset in buffer in bytes
+					// unsigned short index;	// index of the semantic (for colours and texture coords)
+			M_GEOMETRY_VERTEX_BUFFER = 0x5200, // Repeating section
+				// unsigned short bindIndex;	// Index to bind this buffer to
+				// unsigned short vertexSize;	// Per-vertex size, must agree with declaration at this index
+				M_GEOMETRY_VERTEX_BUFFER_DATA = 0x5210,
+					// raw buffer data
+		M_MESH_SKELETON_LINK = 0x6000,
+			// Optional link to skeleton
+			// char* skeletonName		   : name of .skeleton to use
+		M_MESH_BONE_ASSIGNMENT = 0x7000,
+			// Optional bone weights (repeating section)
+			// unsigned int vertexIndex;
+			// unsigned short boneIndex;
+			// float weight;
+		M_MESH_LOD = 0x8000,
+			// Optional LOD information
+			// string strategyName;
+			// unsigned short numLevels;
+			// bool manual;  (true for manual alternate meshes, false for generated)
+			M_MESH_LOD_USAGE = 0x8100,
+			// Repeating section, ordered in increasing depth
+			// NB LOD 0 (full detail from 0 depth) is omitted
+			// LOD value - this is a distance, a pixel count etc, based on strategy
+			// float lodValue;
+				M_MESH_LOD_MANUAL = 0x8110,
+				// Required if M_MESH_LOD section manual = true
+				// String manualMeshName;
+				M_MESH_LOD_GENERATED = 0x8120,
+				// Required if M_MESH_LOD section manual = false
+				// Repeating section (1 per submesh)
+				// unsigned int indexCount;
+				// bool indexes32Bit
+				// unsigned short* faceIndexes;  (indexCount)
+				// OR
+				// unsigned int* faceIndexes;  (indexCount)
+		M_MESH_BOUNDS = 0x9000,
+			// float minx, miny, minz
+			// float maxx, maxy, maxz
+			// float radius
+				
+		// Added By DrEvil
+		// optional chunk that contains a table of submesh indexes and the names of
+		// the sub-meshes.
+		M_SUBMESH_NAME_TABLE = 0xA000,
+			// Subchunks of the name table. Each chunk contains an index & string
+			M_SUBMESH_NAME_TABLE_ELEMENT = 0xA100,
+				// short index
+				// char* name
+		// Optional chunk which stores precomputed edge data					 
+		M_EDGE_LISTS = 0xB000,
+			// Each LOD has a separate edge list
+			M_EDGE_LIST_LOD = 0xB100,
+				// unsigned short lodIndex
+				// bool isManual			// If manual, no edge data here, loaded from manual mesh
+					// bool isClosed
+					// unsigned long numTriangles
+					// unsigned long numEdgeGroups
+					// Triangle* triangleList
+						// unsigned long indexSet
+						// unsigned long vertexSet
+						// unsigned long vertIndex[3]
+						// unsigned long sharedVertIndex[3] 
+						// float normal[4] 
+
+					M_EDGE_GROUP = 0xB110,
+						// unsigned long vertexSet
+						// unsigned long triStart
+						// unsigned long triCount
+						// unsigned long numEdges
+						// Edge* edgeList
+							// unsigned long  triIndex[2]
+							// unsigned long  vertIndex[2]
+							// unsigned long  sharedVertIndex[2]
+							// bool degenerate
+		// Optional poses section, referred to by pose keyframes
+		M_POSES = 0xC000,
+			M_POSE = 0xC100,
+				// char* name (may be blank)
+				// unsigned short target	// 0 for shared geometry, 
+											// 1+ for submesh index + 1
+				// bool includesNormals [1.8+]
+				M_POSE_VERTEX = 0xC111,
+					// unsigned long vertexIndex
+					// float xoffset, yoffset, zoffset
+					// float xnormal, ynormal, znormal (optional, 1.8+)
+		// Optional vertex animation chunk
+		M_ANIMATIONS = 0xD000, 
+			M_ANIMATION = 0xD100,
+			// char* name
+			// float length
+			M_ANIMATION_BASEINFO = 0xD105,
+			// [Optional] base keyframe information (pose animation only)
+			// char* baseAnimationName (blank for self)
+			// float baseKeyFrameTime
+			M_ANIMATION_TRACK = 0xD110,
+				// unsigned short type			// 1 == morph, 2 == pose
+				// unsigned short target		// 0 for shared geometry, 
+												// 1+ for submesh index + 1
+				M_ANIMATION_MORPH_KEYFRAME = 0xD111,
+					// float time
+					// bool includesNormals [1.8+]
+					// float x,y,z			// repeat by number of vertices in original geometry
+				M_ANIMATION_POSE_KEYFRAME = 0xD112,
+					// float time
+					M_ANIMATION_POSE_REF = 0xD113, // repeat for number of referenced poses
+						// unsigned short poseIndex 
+						// float influence
+		// Optional submesh extreme vertex list chink
+		M_TABLE_EXTREMES = 0xE000,
+		// unsigned short submesh_index;
+		// float extremes [n_extremes][3];
+};
+
+static std::string MeshHeaderToString(MeshChunkId id)
+{
+	switch(id)
+	{
+		case M_HEADER:						return "HEADER";
+		case M_MESH:						return "MESH";
+		case M_SUBMESH:						return "SUBMESH";
+		case M_SUBMESH_OPERATION:			return "SUBMESH_OPERATION";
+		case M_SUBMESH_BONE_ASSIGNMENT:		return "SUBMESH_BONE_ASSIGNMENT";
+		case M_SUBMESH_TEXTURE_ALIAS:		return "SUBMESH_TEXTURE_ALIAS";
+		case M_GEOMETRY:					return "GEOMETRY";
+		case M_GEOMETRY_VERTEX_DECLARATION: return "GEOMETRY_VERTEX_DECLARATION";
+		case M_GEOMETRY_VERTEX_ELEMENT:		return "GEOMETRY_VERTEX_ELEMENT";
+		case M_GEOMETRY_VERTEX_BUFFER:		return "GEOMETRY_VERTEX_BUFFER";
+		case M_GEOMETRY_VERTEX_BUFFER_DATA: return "GEOMETRY_VERTEX_BUFFER_DATA";
+		case M_MESH_SKELETON_LINK:			return "MESH_SKELETON_LINK";
+		case M_MESH_BONE_ASSIGNMENT:		return "MESH_BONE_ASSIGNMENT";
+		case M_MESH_LOD:					return "MESH_LOD";
+		case M_MESH_LOD_USAGE:				return "MESH_LOD_USAGE";
+		case M_MESH_LOD_MANUAL:				return "MESH_LOD_MANUAL";
+		case M_MESH_LOD_GENERATED:			return "MESH_LOD_GENERATED";
+		case M_MESH_BOUNDS:					return "MESH_BOUNDS";
+		case M_SUBMESH_NAME_TABLE:			return "SUBMESH_NAME_TABLE";
+		case M_SUBMESH_NAME_TABLE_ELEMENT:	return "SUBMESH_NAME_TABLE_ELEMENT";
+		case M_EDGE_LISTS:					return "EDGE_LISTS";
+		case M_EDGE_LIST_LOD:				return "EDGE_LIST_LOD";
+		case M_EDGE_GROUP:					return "EDGE_GROUP";
+		case M_POSES:						return "POSES";
+		case M_POSE:						return "POSE";
+		case M_POSE_VERTEX:					return "POSE_VERTEX";
+		case M_ANIMATIONS:					return "ANIMATIONS";
+		case M_ANIMATION:					return "ANIMATION";
+		case M_ANIMATION_BASEINFO:			return "ANIMATION_BASEINFO";
+		case M_ANIMATION_TRACK:				return "ANIMATION_TRACK";
+		case M_ANIMATION_MORPH_KEYFRAME:	return "ANIMATION_MORPH_KEYFRAME";
+		case M_ANIMATION_POSE_KEYFRAME:		return "ANIMATION_POSE_KEYFRAME";
+		case M_ANIMATION_POSE_REF:			return "ANIMATION_POSE_REF";
+		case M_TABLE_EXTREMES:				return "TABLE_EXTREMES";
+	}
+	return "Unknown_MeshChunkId";
+}
+
+enum SkeletonChunkId
+{
+	SKELETON_HEADER				= 0x1000,
+		// char* version		   : Version number check
+		SKELETON_BLENDMODE		= 0x1010, // optional
+			// unsigned short blendmode		: SkeletonAnimationBlendMode
+	SKELETON_BONE				= 0x2000,
+	// Repeating section defining each bone in the system. 
+	// Bones are assigned indexes automatically based on their order of declaration
+	// starting with 0.
+		// char* name					   : name of the bone
+		// unsigned short handle			: handle of the bone, should be contiguous & start at 0
+		// Vector3 position				 : position of this bone relative to parent 
+		// Quaternion orientation		   : orientation of this bone relative to parent 
+		// Vector3 scale					: scale of this bone relative to parent 
+	SKELETON_BONE_PARENT		= 0x3000,
+	// Record of the parent of a single bone, used to build the node tree
+	// Repeating section, listed in Bone Index order, one per Bone
+		// unsigned short handle			 : child bone
+		// unsigned short parentHandle   : parent bone
+	SKELETON_ANIMATION			= 0x4000,
+	// A single animation for this skeleton
+		// char* name					   : Name of the animation
+		// float length					  : Length of the animation in seconds
+		SKELETON_ANIMATION_BASEINFO = 0x4010,
+		// [Optional] base keyframe information
+		// char* baseAnimationName (blank for self)
+		// float baseKeyFrameTime
+		SKELETON_ANIMATION_TRACK	= 0x4100,
+		// A single animation track (relates to a single bone)
+		// Repeating section (within SKELETON_ANIMATION)
+			// unsigned short boneIndex	 : Index of bone to apply to
+			SKELETON_ANIMATION_TRACK_KEYFRAME = 0x4110,
+			// A single keyframe within the track
+			// Repeating section
+				// float time					: The time position (seconds)
+				// Quaternion rotate			: Rotation to apply at this keyframe
+				// Vector3 translate			: Translation to apply at this keyframe
+				// Vector3 scale				: Scale to apply at this keyframe
+	SKELETON_ANIMATION_LINK		= 0x5000
+	// Link to another skeleton, to re-use its animations
+		// char* skeletonName					: name of skeleton to get animations from
+		// float scale							: scale to apply to trans/scale keys
+};
+
+static std::string SkeletonHeaderToString(SkeletonChunkId id)
+{
+	switch(id)
+	{
+		case SKELETON_HEADER:					return "HEADER";
+		case SKELETON_BLENDMODE:				return "BLENDMODE";
+		case SKELETON_BONE:						return "BONE";
+		case SKELETON_BONE_PARENT:				return "BONE_PARENT";
+		case SKELETON_ANIMATION:				return "ANIMATION";
+		case SKELETON_ANIMATION_BASEINFO:		return "ANIMATION_BASEINFO";
+		case SKELETON_ANIMATION_TRACK:			return "ANIMATION_TRACK";
+		case SKELETON_ANIMATION_TRACK_KEYFRAME: return "ANIMATION_TRACK_KEYFRAME";
+		case SKELETON_ANIMATION_LINK:			return "ANIMATION_LINK";
+	}
+	return "Unknown_SkeletonChunkId";
+}
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
+#endif // AI_OGREBINARYSERIALIZER_H_INC

+ 60 - 176
Source/ThirdParty/Assimp/code/OgreImporter.cpp

@@ -38,31 +38,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
-/** @file  OgreImporter.cpp
- *  @brief Implementation of the Ogre XML (.mesh.xml) loader.
- */
 #include "AssimpPCH.h"
 #include "AssimpPCH.h"
-#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
 
 
-#include <vector>
-#include <sstream>
-using namespace std;
+#include "OgreImporter.h"
+#include "OgreBinarySerializer.h"
+#include "OgreXmlSerializer.h"
 
 
-#include "OgreImporter.hpp"
-#include "TinyFormatter.h"
-#include "irrXMLWrapper.h"
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
 
 
 static const aiImporterDesc desc = {
 static const aiImporterDesc desc = {
-	"Ogre XML Mesh Importer",
+	"Ogre3D Mesh Importer",
 	"",
 	"",
 	"",
 	"",
 	"",
 	"",
-	aiImporterFlags_SupportTextFlavour,
+	aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour,
 	0,
 	0,
 	0,
 	0,
 	0,
 	0,
 	0,
 	0,
-	"mesh.xml"
+	"mesh mesh.xml"
 };
 };
 
 
 namespace Assimp
 namespace Assimp
@@ -70,194 +64,84 @@ namespace Assimp
 namespace Ogre
 namespace Ogre
 {
 {
 
 
-
-bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const
+const aiImporterDesc* OgreImporter::GetInfo() const
 {
 {
-	if(!checkSig)//Check File Extension
-	{
-		std::string extension("mesh.xml");
-		int l=extension.length();
-		return pFile.substr(pFile.length()-l, l)==extension;
-	}
-	else//Check file Header
-	{
-		const char* tokens[] = {"<mesh>"};
-		return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
-	}
+	return &desc;
 }
 }
 
 
-
-void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler)
+void OgreImporter::SetupProperties(const Importer* pImp)
 {
 {
-	m_CurrentFilename=pFile;
-	m_CurrentIOHandler=pIOHandler;
-	m_CurrentScene=pScene;
-
-	//Open the File:
-	boost::scoped_ptr<IOStream> file(pIOHandler->Open(pFile));
-	if( file.get() == NULL)
-		throw DeadlyImportError("Failed to open file "+pFile+".");
-
-	//Read the Mesh File:
-	boost::scoped_ptr<CIrrXML_IOStreamReader> mIOWrapper( new CIrrXML_IOStreamReader( file.get()));
-	boost::scoped_ptr<XmlReader> MeshFile(irr::io::createIrrXMLReader(mIOWrapper.get()));
-	if(!MeshFile)//parse the xml file
-		throw DeadlyImportError("Failed to create XML Reader for "+pFile);
-
+	m_userDefinedMaterialLibFile = pImp->GetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "Scene.material");
+	m_detectTextureTypeFromFilename = pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false);
+}
 
 
-	DefaultLogger::get()->debug("Mesh File opened");
-	
-	//Read root Node:
-	if(!(XmlRead(MeshFile.get()) && string(MeshFile->getNodeName())=="mesh"))
-	{
-		throw DeadlyImportError("Root Node is not <mesh>! "+pFile+"  "+MeshFile->getNodeName());
+bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const
+{
+	if (!checkSig) {
+		return EndsWith(pFile, ".mesh.xml", false) || EndsWith(pFile, ".mesh", false);
 	}
 	}
 
 
-	//eventually load shared geometry
-	XmlRead(MeshFile.get());//shared geometry is optional, so we need a reed for the next two if's
-	if(MeshFile->getNodeName()==string("sharedgeometry"))
+	if (EndsWith(pFile, ".mesh.xml", false))
 	{
 	{
-		unsigned int NumVertices=GetAttribute<int>(MeshFile.get(), "vertexcount");;
-
-		XmlRead(MeshFile.get());
-		while(MeshFile->getNodeName()==string("vertexbuffer"))
-		{
-			ReadVertexBuffer(m_SharedGeometry, MeshFile.get(), NumVertices);
-		}
+		const char* tokens[] = { "<mesh>" };
+		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
 	}
 	}
-
-	//Go to the submeshs:
-	if(MeshFile->getNodeName()!=string("submeshes"))
+	else
 	{
 	{
-		throw DeadlyImportError("No <submeshes> node in <mesh> node! "+pFile);
+		/// @todo Read and validate first header chunk?
+		return EndsWith(pFile, ".mesh", false);
 	}
 	}
+}
 
 
-
-	//-------------------Read the submeshs and materials:-----------------------
-	std::list<boost::shared_ptr<SubMesh> > SubMeshes;
-	vector<aiMaterial*> Materials;
-	XmlRead(MeshFile.get());
-	while(MeshFile->getNodeName()==string("submesh"))
-	{
-		SubMesh* theSubMesh=new SubMesh();
-		theSubMesh->MaterialName=GetAttribute<string>(MeshFile.get(), "material");
-		DefaultLogger::get()->debug("Loading Submehs with Material: "+theSubMesh->MaterialName);
-		ReadSubMesh(*theSubMesh, MeshFile.get());
-
-		//just a index in a array, we add a mesh in each loop cycle, so we get indicies like 0, 1, 2 ... n;
-		//so it is important to do this before pushing the mesh in the vector!
-		theSubMesh->MaterialIndex=SubMeshes.size();
-
-		SubMeshes.push_back(boost::shared_ptr<SubMesh>(theSubMesh));
-
-		//Load the Material:
-		aiMaterial* MeshMat=LoadMaterial(theSubMesh->MaterialName);
-		
-		//Set the Material:
-		Materials.push_back(MeshMat);
+void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler)
+{
+	// Open source file
+	IOStream *f = pIOHandler->Open(pFile, "rb");
+	if (!f) {
+		throw DeadlyImportError("Failed to open file " + pFile);
 	}
 	}
 
 
-	if(SubMeshes.empty())
-		throw DeadlyImportError("no submesh loaded!");
-	if(SubMeshes.size()!=Materials.size())
-		throw DeadlyImportError("materialcount doesn't match mesh count!");
-
-	//____________________________________________________________
-
-
-	//skip submeshnames (stupid irrxml)
-	if(MeshFile->getNodeName()==string("submeshnames"))
+	// Binary .mesh import
+	if (EndsWith(pFile, ".mesh", false))
 	{
 	{
-		XmlRead(MeshFile.get());
-		while(MeshFile->getNodeName()==string("submesh"))
-			XmlRead(MeshFile.get());
-	}
+		/// @note MemoryStreamReader takes ownership of f.
+		MemoryStreamReader reader(f);
 
 
+		// Import mesh
+		boost::scoped_ptr<Mesh> mesh = OgreBinarySerializer::ImportMesh(&reader);
 
 
-	//----------------Load the skeleton: -------------------------------
-	vector<Bone> Bones;
-	vector<Animation> Animations;
-	if(MeshFile->getNodeName()==string("skeletonlink"))
-	{
-		string SkeletonFile=GetAttribute<string>(MeshFile.get(), "name");
-		LoadSkeleton(SkeletonFile, Bones, Animations);
-		XmlRead(MeshFile.get());
-	}
-	else
-	{
-		DefaultLogger::get()->debug("No skeleton file will be loaded");
-		DefaultLogger::get()->debug(MeshFile->getNodeName());
-	}
-	//__________________________________________________________________
+		// Import skeleton
+		OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh);
 
 
+		// Import mesh referenced materials
+		ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
 
 
-	//now there might be boneassignments for the shared geometry:
-	if(MeshFile->getNodeName()==string("boneassignments"))
-	{
-		ReadBoneWeights(m_SharedGeometry, MeshFile.get());
+		// Convert to Assimp
+		mesh->ConvertToAssimpScene(pScene);
 	}
 	}
-
-
-	//----------------- Process Meshs -----------------------
-	BOOST_FOREACH(boost::shared_ptr<SubMesh> theSubMesh, SubMeshes)
+	// XML .mesh.xml import
+	else
 	{
 	{
-		ProcessSubMesh(*theSubMesh, m_SharedGeometry);
-	}
-	//_______________________________________________________
-
+		/// @note XmlReader does not take ownership of f, hence the scoped ptr.
+		boost::scoped_ptr<IOStream> scopedFile(f);
+		boost::scoped_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(scopedFile.get()));
+		boost::scoped_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get()));
 
 
+		// Import mesh
+		boost::scoped_ptr<MeshXml> mesh = OgreXmlSerializer::ImportMesh(reader.get());
+		
+		// Import skeleton
+		OgreXmlSerializer::ImportSkeleton(pIOHandler, mesh);
 
 
-	
-	//----------------- Now fill the Assimp scene ---------------------------
-	
-	//put the aiMaterials in the scene:
-	m_CurrentScene->mMaterials=new aiMaterial*[Materials.size()];
-	m_CurrentScene->mNumMaterials=Materials.size();
-	for(unsigned int i=0; i<Materials.size(); ++i)
-		m_CurrentScene->mMaterials[i]=Materials[i];
+		// Import mesh referenced materials
+		ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
 
 
-	//create the aiMehs... 
-	vector<aiMesh*> aiMeshes;
-	BOOST_FOREACH(boost::shared_ptr<SubMesh> theSubMesh, SubMeshes)
-	{
-		aiMeshes.push_back(CreateAssimpSubMesh(*theSubMesh, Bones));
+		// Convert to Assimp
+		mesh->ConvertToAssimpScene(pScene);
 	}
 	}
-	//... and put them in the scene:
-	m_CurrentScene->mNumMeshes=aiMeshes.size();
-	m_CurrentScene->mMeshes=new aiMesh*[aiMeshes.size()];
-	memcpy(m_CurrentScene->mMeshes, &(aiMeshes[0]), sizeof(aiMeshes[0])*aiMeshes.size());
-
-	//Create the root node
-	m_CurrentScene->mRootNode=new aiNode("root");
-
-	//link the meshs with the root node:
-	m_CurrentScene->mRootNode->mMeshes=new unsigned int[SubMeshes.size()];
-	m_CurrentScene->mRootNode->mNumMeshes=SubMeshes.size();
-	for(unsigned int i=0; i<SubMeshes.size(); ++i)
-		m_CurrentScene->mRootNode->mMeshes[i]=i;
-
-	
-
-	CreateAssimpSkeleton(Bones, Animations);
-	PutAnimationsInScene(Bones, Animations);
-	//___________________________________________________________
 }
 }
 
 
+} // Ogre
+} // Assimp
 
 
-const aiImporterDesc* OgreImporter::GetInfo () const
-{
-	return &desc;
-}
-
-
-void OgreImporter::SetupProperties(const Importer* pImp)
-{
-	m_MaterialLibFilename=pImp->GetPropertyString(AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE, "Scene.material");
-	m_TextureTypeFromFilename=pImp->GetPropertyBool(AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME, false);
-}
-
-
-}//namespace Ogre
-}//namespace Assimp
-
-#endif  // !! ASSIMP_BUILD_NO_OGRE_IMPORTER
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER

+ 98 - 0
Source/ThirdParty/Assimp/code/OgreImporter.h

@@ -0,0 +1,98 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef AI_OGREIMPORTER_H_INC
+#define AI_OGREIMPORTER_H_INC
+
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
+
+#include "BaseImporter.h"
+
+#include "OgreStructs.h"
+#include "OgreParsingUtils.h"
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+/**	Importer for Ogre mesh, skeleton and material formats.
+	@todo Support vertex colors.
+	@todo Support poses/animations from the mesh file. 
+	Currently only skeleton file animations are supported. */
+class OgreImporter : public BaseImporter
+{
+public:
+	/// BaseImporter override.
+	virtual bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const;
+	
+	/// BaseImporter override.
+	virtual void InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler);
+	
+	/// BaseImporter override.
+	virtual const aiImporterDesc *GetInfo() const;
+	
+	/// BaseImporter override.
+	virtual void SetupProperties(const Importer *pImp);
+
+private:
+	/// Read materials referenced by the @c mesh to @c pScene.
+	void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh);
+	void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh);
+	void AssignMaterials(aiScene *pScene, std::vector<aiMaterial*> &materials);
+	
+	/// Reads material
+	aiMaterial* ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string MaterialName);
+
+	// These functions parse blocks from a material file from @c ss. Starting parsing from "{" and ending it to "}".
+	bool ReadTechnique(const std::string &techniqueName, std::stringstream &ss, aiMaterial *material);
+	bool ReadPass(const std::string &passName, std::stringstream &ss, aiMaterial *material);	
+	bool ReadTextureUnit(const std::string &textureUnitName, std::stringstream &ss, aiMaterial *material);
+
+	std::string m_userDefinedMaterialLibFile;
+	bool m_detectTextureTypeFromFilename;
+	
+	std::map<aiTextureType, unsigned int> m_textures;
+};
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
+#endif // AI_OGREIMPORTER_H_INC

+ 450 - 311
Source/ThirdParty/Assimp/code/OgreMaterial.cpp

@@ -38,56 +38,93 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 */
 */
 
 
-/**
-This file contains material related code. This is
-spilitted up from the main file OgreImporter.cpp
-to make it shorter easier to maintain.
-*/
 #include "AssimpPCH.h"
 #include "AssimpPCH.h"
 
 
 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
 
 
+#include "OgreImporter.h"
+#include "TinyFormatter.h"
+
+#include "fast_atof.h"
+
 #include <vector>
 #include <vector>
 #include <sstream>
 #include <sstream>
-using namespace std;
 
 
-#include "OgreImporter.hpp"
-#include "irrXMLWrapper.h"
-#include "TinyFormatter.h"
+using namespace std;
 
 
 namespace Assimp
 namespace Assimp
 {
 {
 namespace Ogre
 namespace Ogre
 {
 {
 
 
+static const string partComment    = "//";
+static const string partBlockStart = "{";
+static const string partBlockEnd   = "}";
+
+void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh)
+{
+	std::vector<aiMaterial*> materials;
+
+	// Create materials that can be found and parsed via the IOSystem.
+	for (size_t i=0, len=mesh->NumSubMeshes(); i<len; ++i)
+	{
+		SubMesh *submesh = mesh->GetSubMesh(i);
+		if (submesh && !submesh->materialRef.empty())
+		{
+			aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);
+			if (material)
+			{
+				submesh->materialIndex = materials.size();
+				materials.push_back(material);
+			}
+		}
+	}
 
 
+	AssignMaterials(pScene, materials);
+}
 
 
-aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const
+void OgreImporter::ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, MeshXml *mesh)
 {
 {
-	/*For better understanding of the material parser, here is a material example file:
+	std::vector<aiMaterial*> materials;
 
 
-	material Sarg
+	// Create materials that can be found and parsed via the IOSystem.
+	for (size_t i=0, len=mesh->NumSubMeshes(); i<len; ++i)
 	{
 	{
-		receive_shadows on
-		technique
+		SubMeshXml *submesh = mesh->GetSubMesh(i);
+		if (submesh && !submesh->materialRef.empty())
 		{
 		{
-			pass
+			aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);
+			if (material)
 			{
 			{
-				ambient 0.500000 0.500000 0.500000 1.000000
-				diffuse 0.640000 0.640000 0.640000 1.000000
-				specular 0.500000 0.500000 0.500000 1.000000 12.500000
-				emissive 0.000000 0.000000 0.000000 1.000000
-				texture_unit
-				{
-					texture SargTextur.tga
-					tex_address_mode wrap
-					filtering linear linear none
-				}
+				submesh->materialIndex = materials.size();
+				materials.push_back(material);
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	*/
+	AssignMaterials(pScene, materials);
+}
+
+void OgreImporter::AssignMaterials(aiScene *pScene, std::vector<aiMaterial*> &materials)
+{
+	pScene->mNumMaterials = materials.size();
+	if (pScene->mNumMaterials > 0)
+	{
+		pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
+		for(size_t i=0;i<pScene->mNumMaterials; ++i) {
+			pScene->mMaterials[i] = materials[i];
+		}
+	}
+}
+
+aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string materialName)
+{
+	if (materialName.empty()) {
+		return 0;
+	}
+
+	// Full reference and examples of Ogre Material Script 
+	// can be found from http://www.ogre3d.org/docs/manual/manual_14.html
 
 
 	/*and here is another one:
 	/*and here is another one:
 
 
@@ -112,342 +149,444 @@ aiMaterial* OgreImporter::LoadMaterial(const std::string MaterialName) const
 	}
 	}
 	*/
 	*/
 
 
-	//Read the file into memory and put it in a stringstream
 	stringstream ss;
 	stringstream ss;
-	{// after this block, the temporarly loaded data will be released
-
-		/*
-		We have 3 guesses for the Material filename:
-		- the Material Name
-		- the Name of the mesh file
-		- the DefaultMaterialLib (which you can set before importing)
-		*/
+
+	// Scope for scopre_ptr auto release
+	{	
+		/* There are three .material options in priority order:
+			1) File with the material name (materialName)
+			2) File with the mesh files base name (pFile)
+			3) Optional user defined material library file (m_userDefinedMaterialLibFile) */
+		std::vector<string> potentialFiles;
+		potentialFiles.push_back(materialName + ".material");
+		potentialFiles.push_back(pFile.substr(0, pFile.rfind(".mesh")) + ".material");
+		if (!m_userDefinedMaterialLibFile.empty())
+			potentialFiles.push_back(m_userDefinedMaterialLibFile);
 		
 		
-		IOStream* MatFilePtr=m_CurrentIOHandler->Open(MaterialName+".material");
-		if(NULL==MatFilePtr)
+		IOStream *materialFile = 0;
+		for(size_t i=0; i<potentialFiles.size(); ++i)
 		{
 		{
-			//the filename typically ends with .mesh or .mesh.xml
-			const string MaterialFileName=m_CurrentFilename.substr(0, m_CurrentFilename.rfind(".mesh"))+".material";
-
-			MatFilePtr=m_CurrentIOHandler->Open(MaterialFileName);
-			if(NULL==MatFilePtr)
-			{
-				//try the default mat Library
-				if(NULL==MatFilePtr)
-				{
-				
-					MatFilePtr=m_CurrentIOHandler->Open(m_MaterialLibFilename);
-					if(NULL==MatFilePtr)
-					{
-						DefaultLogger::get()->error(m_MaterialLibFilename+" and "+MaterialFileName + " could not be opened, Material will not be loaded!");
-						return new aiMaterial();
-					}
-				}
+			materialFile = pIOHandler->Open(potentialFiles[i]);
+			if (materialFile) {
+				break;
 			}
 			}
+			DefaultLogger::get()->debug(Formatter::format() << "Source file for material '" << materialName << "' " << potentialFiles[i] << " does not exist");
 		}
 		}
-		//Fill the stream
-		boost::scoped_ptr<IOStream> MaterialFile(MatFilePtr);
-		if(MaterialFile->FileSize()>0)
+		if (!materialFile)
 		{
 		{
-			vector<char> FileData(MaterialFile->FileSize());
-			MaterialFile->Read(&FileData[0], MaterialFile->FileSize(), 1);
-			BaseImporter::ConvertToUTF8(FileData);
-
-			FileData.push_back('\0');//terminate the string with zero, so that the ss can parse it correctly
-			ss << &FileData[0];
+			DefaultLogger::get()->error(Formatter::format() << "Failed to find source file for material '" << materialName << "'");
+			return 0;
 		}
 		}
-		else
+
+		boost::scoped_ptr<IOStream> stream(materialFile);
+		if (stream->FileSize() == 0)
 		{
 		{
-			DefaultLogger::get()->warn("Material " + MaterialName + " seams to be empty");
-			return NULL;
+			DefaultLogger::get()->warn(Formatter::format() << "Source file for material '" << materialName << "' is empty (size is 0 bytes)");
+			return 0;
 		}
 		}
+
+		// Read bytes
+		vector<char> data(stream->FileSize());
+		stream->Read(&data[0], stream->FileSize(), 1);
+		
+		// Convert to UTF-8 and terminate the string for ss
+		BaseImporter::ConvertToUTF8(data);
+		data.push_back('\0');
+		
+		ss << &data[0];
 	}
 	}
+	
+	DefaultLogger::get()->debug("Reading material '" + materialName + "'");
 
 
-	//create the material
-	aiMaterial *NewMaterial=new aiMaterial();
+	aiMaterial *material = new aiMaterial();
+	m_textures.clear();
+	
+	aiString ts(materialName);
+	material->AddProperty(&ts, AI_MATKEY_NAME);
 
 
-	aiString ts(MaterialName.c_str());
-	NewMaterial->AddProperty(&ts, AI_MATKEY_NAME);
+	// The stringstream will push words from a line until newline.
+	// It will also trim whitespace from line start and between words.
+	string linePart;
+	ss >> linePart;
+	
+	const string partMaterial   = "material";
+	const string partTechnique  = "technique";
 
 
-	string Line;
-	ss >> Line;
-//	unsigned int Level=0;//Hierarchielevels in the material file, like { } blocks into another
 	while(!ss.eof())
 	while(!ss.eof())
 	{
 	{
-		if(Line=="material")
+		// Skip commented lines
+		if (linePart == partComment)
+		{
+			NextAfterNewLine(ss, linePart);
+			continue;
+		}
+		if (linePart != partMaterial)
+		{
+			ss >> linePart;
+			continue;
+		}
+
+		ss >> linePart;
+		if (linePart != materialName)
+		{
+			//DefaultLogger::get()->debug(Formatter::format() << "Found material '" << linePart << "' that does not match at index " << ss.tellg());
+			ss >> linePart;
+			continue;
+		}
+
+		NextAfterNewLine(ss, linePart);
+		if (linePart != partBlockStart)
 		{
 		{
-			ss >> Line;
-			if(Line==MaterialName)//Load the next material
+			DefaultLogger::get()->error(Formatter::format() << "Invalid material: block start missing near index " << ss.tellg());
+			return material;
+		}
+		
+		DefaultLogger::get()->debug("material '" + materialName + "'");
+
+		while(linePart != partBlockEnd)
+		{
+			// Proceed to the first technique
+			ss >> linePart;
+					
+			if (linePart == partTechnique)
 			{
 			{
-				string RestOfLine;
-				getline(ss, RestOfLine);//ignore the rest of the line
-				ss >> Line;
+				string techniqueName = SkipLine(ss);
+				ReadTechnique(Trim(techniqueName), ss, material);
+			}
 
 
-				if(Line!="{")
+			// Read informations from a custom material
+			/** @todo This "set $x y" does not seem to be a official Ogre material system feature.
+				Materials can inherit other materials and override texture units by using the (unique)
+				parent texture unit name in your cloned material.
+				This is not yet supported and below code is probably some hack from the original
+				author of this Ogre importer. Should be removed? */
+			if (linePart=="set")
+			{
+				ss >> linePart;
+				if (linePart=="$specular")//todo load this values:
 				{
 				{
-					DefaultLogger::get()->warn("empyt material!");
-					return NULL;
 				}
 				}
-
-				while(Line!="}")//read until the end of the material
+				else if (linePart=="$diffuse")
 				{
 				{
-					//Proceed to the first technique
-					ss >> Line;
-					if(Line=="technique")
-					{
-						ReadTechnique(ss, NewMaterial);
+				}
+				else if (linePart=="$ambient")
+				{
+				}
+				else if (linePart=="$colormap")
+				{
+					ss >> linePart;
+					aiString ts(linePart);
+					material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
+				}
+				else if (linePart=="$normalmap")
+				{
+					ss >> linePart;
+					aiString ts(linePart);
+					material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
+				}
+				else if (linePart=="$shininess_strength")
+				{
+					ss >> linePart;
+					float Shininess = fast_atof(linePart.c_str());
+					material->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS_STRENGTH);
+				}
+				else if (linePart=="$shininess_exponent")
+				{
+					ss >> linePart;
+					float Shininess = fast_atof(linePart.c_str());
+					material->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS);
+				}
+				//Properties from Venetica:
+				else if (linePart=="$diffuse_map")
+				{
+					ss >> linePart;
+					if (linePart[0] == '"')// "file" -> file
+						linePart = linePart.substr(1, linePart.size()-2);
+					aiString ts(linePart);
+					material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
+				}
+				else if (linePart=="$specular_map")
+				{
+					ss >> linePart;
+					if (linePart[0] == '"')// "file" -> file
+						linePart = linePart.substr(1, linePart.size()-2);
+					aiString ts(linePart);
+					material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_SHININESS, 0));
+				}
+				else if (linePart=="$normal_map")
+				{
+					ss >> linePart;
+					if (linePart[0]=='"')// "file" -> file
+						linePart = linePart.substr(1, linePart.size()-2);
+					aiString ts(linePart);
+					material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
+				}
+				else if (linePart=="$light_map")
+				{
+					ss >> linePart;
+					if (linePart[0]=='"') {
+						linePart = linePart.substr(1, linePart.size() - 2);
 					}
 					}
-
-					DefaultLogger::get()->info(Line);
-					//read informations from a custom material:
-					if(Line=="set")
-					{
-						ss >> Line;
-						if(Line=="$specular")//todo load this values:
-						{
-						}
-						if(Line=="$diffuse")
-						{
-						}
-						if(Line=="$ambient")
-						{
-						}
-						if(Line=="$colormap")
-						{
-							ss >> Line;
-							aiString ts(Line.c_str());
-							NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
-						}
-						if(Line=="$normalmap")
-						{
-							ss >> Line;
-							aiString ts(Line.c_str());
-							NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
-						}
-						
-						if(Line=="$shininess_strength")
-						{
-							ss >> Line;
-							float Shininess=fast_atof(Line.c_str());
-							NewMaterial->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS_STRENGTH);
-						}
-
-						if(Line=="$shininess_exponent")
-						{
-							ss >> Line;
-							float Shininess=fast_atof(Line.c_str());
-							NewMaterial->AddProperty(&Shininess, 1, AI_MATKEY_SHININESS);
-						}
-
-						//Properties from Venetica:
-						if(Line=="$diffuse_map")
-						{
-							ss >> Line;
-							if(Line[0]=='"')// "file" -> file
-								Line=Line.substr(1, Line.size()-2);
-							aiString ts(Line.c_str());
-							NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0));
-						}
-						if(Line=="$specular_map")
-						{
-							ss >> Line;
-							if(Line[0]=='"')// "file" -> file
-								Line=Line.substr(1, Line.size()-2);
-							aiString ts(Line.c_str());
-							NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_SHININESS, 0));
-						}
-						if(Line=="$normal_map")
-						{
-							ss >> Line;
-							if(Line[0]=='"')// "file" -> file
-								Line=Line.substr(1, Line.size()-2);
-							aiString ts(Line.c_str());
-							NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, 0));
-						}
-						if(Line=="$light_map")
-						{
-							ss >> Line;
-							if(Line[0]=='"')// "file" -> file
-								Line=Line.substr(1, Line.size()-2);
-							aiString ts(Line.c_str());
-							NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, 0));
-						}
-					}					
-				}//end of material
-			}
-			else {} //this is the wrong material, proceed the file until we reach the next material
+					aiString ts(linePart);
+					material->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, 0));
+				}
+			}					
 		}
 		}
-		ss >> Line;
+		ss >> linePart;
+	}
+
+	return material;
+}
+
+bool OgreImporter::ReadTechnique(const std::string &techniqueName, stringstream &ss, aiMaterial *material)
+{
+	string linePart;
+	ss >> linePart;
+
+	if (linePart != partBlockStart)
+	{
+		DefaultLogger::get()->error(Formatter::format() << "Invalid material: Technique block start missing near index " << ss.tellg());
+		return false;
 	}
 	}
 
 
-	return NewMaterial;
+	DefaultLogger::get()->debug(" technique '" + techniqueName + "'");
+
+	const string partPass  = "pass";
+
+	while(linePart != partBlockEnd)
+	{
+		ss >> linePart;
+		
+		// Skip commented lines
+		if (linePart == partComment)
+		{
+			SkipLine(ss);
+			continue;
+		}
+
+		/// @todo Techniques have other attributes than just passes.		
+		if (linePart == partPass)
+		{
+			string passName = SkipLine(ss);
+			ReadPass(Trim(passName), ss, material);
+		}
+	}
+	return true;
 }
 }
 
 
-void OgreImporter::ReadTechnique(stringstream &ss, aiMaterial* NewMaterial) const
+bool OgreImporter::ReadPass(const std::string &passName, stringstream &ss, aiMaterial *material)
 {
 {
-	unsigned int CurrentDiffuseTextureId=0;
-	unsigned int CurrentSpecularTextureId=0;
-	unsigned int CurrentNormalTextureId=0;
-	unsigned int CurrentLightTextureId=0;
+	string linePart;
+	ss >> linePart;
+
+	if (linePart != partBlockStart)
+	{
+		DefaultLogger::get()->error(Formatter::format() << "Invalid material: Pass block start missing near index " << ss.tellg());
+		return false;
+	}
+
+	DefaultLogger::get()->debug("  pass '" + passName + "'");
+
+	const string partAmbient     = "ambient";
+	const string partDiffuse     = "diffuse";
+	const string partSpecular    = "specular";
+	const string partEmissive    = "emissive";
+	const string partTextureUnit = "texture_unit";
+
+	while(linePart != partBlockEnd)
+	{
+		ss >> linePart;
+		
+		// Skip commented lines
+		if (linePart == partComment)
+		{
+			SkipLine(ss);
+			continue;
+		}
 
 
+		// Colors
+		/// @todo Support alpha via aiColor4D.
+		if (linePart == partAmbient || linePart == partDiffuse || linePart == partSpecular || linePart == partEmissive)
+		{
+			float r, g, b;
+			ss >> r >> g >> b;
+			const aiColor3D color(r, g, b);
+			
+			DefaultLogger::get()->debug(Formatter::format() << "   " << linePart << " " << r << " " << g << " " << b);
+			
+			if (linePart == partAmbient)
+			{
+				material->AddProperty(&color, 1, AI_MATKEY_COLOR_AMBIENT);
+			}
+			else if (linePart == partDiffuse)
+			{
+				material->AddProperty(&color, 1, AI_MATKEY_COLOR_DIFFUSE);
+			}
+			else if (linePart == partSpecular)
+			{
+				material->AddProperty(&color, 1, AI_MATKEY_COLOR_SPECULAR);
+			}
+			else if (linePart == partEmissive)
+			{
+				material->AddProperty(&color, 1, AI_MATKEY_COLOR_EMISSIVE);
+			}
+		}
+		else if (linePart == partTextureUnit)
+		{
+			string textureUnitName = SkipLine(ss);
+			ReadTextureUnit(Trim(textureUnitName), ss, material);
+		}
+	}
+	return true;
+}
 
 
-	string RestOfLine;
-	getline(ss, RestOfLine);//ignore the rest of the line
+bool OgreImporter::ReadTextureUnit(const std::string &textureUnitName, stringstream &ss, aiMaterial *material)
+{
+	string linePart;
+	ss >> linePart;
 
 
-	string Line;
-	ss >> Line;
-	if(Line!="{")
+	if (linePart != partBlockStart)
 	{
 	{
-		DefaultLogger::get()->warn("empty technique!");
-		return;
+		DefaultLogger::get()->error(Formatter::format() << "Invalid material: Texture unit block start missing near index " << ss.tellg());
+		return false;
 	}
 	}
-	while(Line!="}")//read until the end of the technique
+
+	DefaultLogger::get()->debug("   texture_unit '" + textureUnitName + "'");
+
+	const string partTexture      = "texture";
+	const string partTextCoordSet = "tex_coord_set";
+	const string partColorOp      = "colour_op";
+
+	aiTextureType textureType = aiTextureType_NONE;
+	std::string textureRef;
+	int uvCoord = 0;
+
+	while(linePart != partBlockEnd)
 	{
 	{
-		ss >> Line;
-		if(Line=="pass")
+		ss >> linePart;
+
+		// Skip commented lines
+		if (linePart == partComment)
+		{
+			SkipLine(ss);
+			continue;
+		}
+
+		if (linePart == partTexture)
 		{
 		{
-			getline(ss, RestOfLine);//ignore the rest of the line
+			ss >> linePart;
+			textureRef = linePart;
 
 
-			ss >> Line;
-			if(Line!="{")
+			// User defined Assimp config property to detect texture type from filename.	
+			if (m_detectTextureTypeFromFilename)
 			{
 			{
-				DefaultLogger::get()->warn("empty pass!");
-				return;
+				size_t posSuffix = textureRef.find_last_of(".");
+				size_t posUnderscore = textureRef.find_last_of("_");
+				
+				if (posSuffix != string::npos && posUnderscore != string::npos && posSuffix > posUnderscore)
+				{
+					string identifier = Ogre::ToLower(textureRef.substr(posUnderscore, posSuffix - posUnderscore));
+					DefaultLogger::get()->debug(Formatter::format() << "Detecting texture type from filename postfix '" << identifier << "'");
+
+					if (identifier == "_n" || identifier == "_nrm" || identifier == "_nrml" || identifier == "_normal" || identifier == "_normals" || identifier == "_normalmap")
+					{
+						textureType = aiTextureType_NORMALS;
+					}
+					else if (identifier == "_s" || identifier == "_spec" || identifier == "_specular" || identifier == "_specularmap")
+					{
+						textureType = aiTextureType_SPECULAR;
+					}
+					else if (identifier == "_l" || identifier == "_light" || identifier == "_lightmap" || identifier == "_occ" || identifier == "_occlusion")
+					{
+						textureType = aiTextureType_LIGHTMAP;
+					}
+					else if (identifier == "_disp" || identifier == "_displacement")
+					{
+						textureType = aiTextureType_DISPLACEMENT;
+					}
+					else
+					{
+						textureType = aiTextureType_DIFFUSE;
+					}
+				}
+				else
+				{
+					textureType = aiTextureType_DIFFUSE;
+				}
 			}
 			}
-			while(Line!="}")//read until the end of the pass
+			// Detect from texture unit name. This cannot be too broad as 
+			// authors might give names like "LightSaber" or "NormalNinja".
+			else
 			{
 			{
-				ss >> Line;
-				if(Line=="ambient")
+				string unitNameLower = Ogre::ToLower(textureUnitName);
+				if (unitNameLower.find("normalmap") != string::npos)
 				{
 				{
-					float r,g,b;
-					ss >> r >> g >> b;
-					const aiColor3D Color(r,g,b);
-					NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_AMBIENT);
+					textureType = aiTextureType_NORMALS;
 				}
 				}
-				else if(Line=="diffuse")
+				else if (unitNameLower.find("specularmap") != string::npos)
 				{
 				{
-					float r,g,b;
-					ss >> r >> g >> b;
-					const aiColor3D Color(r,g,b);
-					NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_DIFFUSE);
+					textureType = aiTextureType_SPECULAR;
 				}
 				}
-				else if(Line=="specular")
+				else if (unitNameLower.find("lightmap") != string::npos)
 				{
 				{
-					float r,g,b;
-					ss >> r >> g >> b;
-					const aiColor3D Color(r,g,b);
-					NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_SPECULAR);
+					textureType = aiTextureType_LIGHTMAP;
 				}
 				}
-				else if(Line=="emmisive")
+				else if (unitNameLower.find("displacementmap") != string::npos)
 				{
 				{
-					float r,g,b;
-					ss >> r >> g >> b;
-					const aiColor3D Color(r,g,b);
-					NewMaterial->AddProperty(&Color, 1, AI_MATKEY_COLOR_EMISSIVE);
+					textureType = aiTextureType_DISPLACEMENT;
 				}
 				}
-				else if(Line=="texture_unit")
+				else
 				{
 				{
-					getline(ss, RestOfLine);//ignore the rest of the line
-
-					std::string TextureName;
-					int TextureType=-1;
-					int UvSet=0;
-
-					ss >> Line;
-					if(Line!="{")
-						throw DeadlyImportError("empty texture unit!");
-					while(Line!="}")//read until the end of the texture_unit
-					{
-						ss >> Line;
-						if(Line=="texture")
-						{
-							ss >> Line;
-							TextureName=Line;
-
-							if(m_TextureTypeFromFilename)
-							{
-								if(Line.find("_n.")!=string::npos)// Normalmap
-								{
-									TextureType=aiTextureType_NORMALS;
-								}
-								else if(Line.find("_s.")!=string::npos)// Specularmap
-								{
-									TextureType=aiTextureType_SPECULAR;
-								}
-								else if(Line.find("_l.")!=string::npos)// Lightmap
-								{
-									TextureType=aiTextureType_LIGHTMAP;
-								}
-								else// colormap
-								{
-									TextureType=aiTextureType_DIFFUSE;
-								}
-							}
-							else
-							{
-								TextureType=aiTextureType_DIFFUSE;
-							}
-						}
-						else if(Line=="tex_coord_set")
-						{
-							ss >> UvSet;
-						}
-						else if(Line=="colour_op")//TODO implement this
-						{
-							/*
-							ss >> Line;
-							if("replace"==Line)//I don't think, assimp has something for this...
-							{
-							}
-							else if("modulate"==Line)
-							{
-								//TODO: set value
-								//NewMaterial->AddProperty(aiTextureOp_Multiply)
-							}
-							*/
-						}
-						
-					}//end of texture unit
-					Line="";//clear the } that would end the outer loop
-
-					//give the texture to assimp:
-					
-					aiString ts(TextureName.c_str());
-					switch(TextureType)
-					{
-					case aiTextureType_DIFFUSE:
-						NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, CurrentDiffuseTextureId));
-						NewMaterial->AddProperty(&UvSet, 1, AI_MATKEY_UVWSRC(0, CurrentDiffuseTextureId));
-						CurrentDiffuseTextureId++;
-						break;
-					case aiTextureType_NORMALS:
-						NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_NORMALS, CurrentNormalTextureId));
-						NewMaterial->AddProperty(&UvSet, 1, AI_MATKEY_UVWSRC(0, CurrentNormalTextureId));
-						CurrentNormalTextureId++;
-						break;
-					case aiTextureType_SPECULAR:
-						NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_SPECULAR, CurrentSpecularTextureId));
-						NewMaterial->AddProperty(&UvSet, 1, AI_MATKEY_UVWSRC(0, CurrentSpecularTextureId));
-						CurrentSpecularTextureId++;
-						break;
-					case aiTextureType_LIGHTMAP:
-						NewMaterial->AddProperty(&ts, AI_MATKEY_TEXTURE(aiTextureType_LIGHTMAP, CurrentLightTextureId));
-						NewMaterial->AddProperty(&UvSet, 1, AI_MATKEY_UVWSRC(0, CurrentLightTextureId));
-						CurrentLightTextureId++;
-						break;
-					default:
-						DefaultLogger::get()->warn("Invalid Texture Type!");
-						break;
-					}
+					textureType = aiTextureType_DIFFUSE;
 				}
 				}
 			}
 			}
-			Line="";//clear the } that would end the outer loop
 		}
 		}
-	}//end of technique
-}
+		else if (linePart == partTextCoordSet)
+		{
+			ss >> uvCoord;
+		}
+		/// @todo Implement
+		else if(linePart == partColorOp)
+		{
+			/*
+			ss >> linePart;
+			if("replace"==linePart)//I don't think, assimp has something for this...
+			{
+			}
+			else if("modulate"==linePart)
+			{
+				//TODO: set value
+				//material->AddProperty(aiTextureOp_Multiply)
+			}
+			*/
+		}	
+	}
+	
+	if (textureRef.empty())
+	{
+		DefaultLogger::get()->warn("Texture reference is empty, ignoring texture_unit.");
+		return false;
+	}
+	if (textureType == aiTextureType_NONE)
+	{
+		DefaultLogger::get()->warn("Failed to detect texture type for '" + textureRef  + "', ignoring texture_unit.");
+		return false;
+	}
 
 
+	unsigned int textureTypeIndex = m_textures[textureType];
+	m_textures[textureType]++;
+	
+	DefaultLogger::get()->debug(Formatter::format() << "    texture '" << textureRef << "' type " << textureType 
+		<< " index " << textureTypeIndex << " UV " << uvCoord);
+	
+	aiString assimpTextureRef(textureRef);
+	material->AddProperty(&assimpTextureRef, AI_MATKEY_TEXTURE(textureType, textureTypeIndex));
+	material->AddProperty(&uvCoord, 1, AI_MATKEY_UVWSRC(textureType, textureTypeIndex));
+	
+	return true;
+}
 
 
-}//namespace Ogre
-}//namespace Assimp
+} // Ogre
+} // Assimp
 
 
-#endif  // !! ASSIMP_BUILD_NO_OGRE_IMPORTER
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER

+ 139 - 0
Source/ThirdParty/Assimp/code/OgreParsingUtils.h

@@ -0,0 +1,139 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef AI_OGREPARSINGUTILS_H_INC
+#define AI_OGREPARSINGUTILS_H_INC
+
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
+
+#include "ParsingUtils.h"
+#include <functional>
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+/// Returns a lower cased copy of @s.
+static inline std::string ToLower(std::string s)
+{
+	std::transform(s.begin(), s.end(), s.begin(), ::tolower);
+	return s;
+}
+
+/// Returns if @c s ends with @c suffix. If @c caseSensitive is false, both strings will be lower cased before matching.
+static inline bool EndsWith(const std::string &s, const std::string &suffix, bool caseSensitive = true)
+{
+	if (s.empty() || suffix.empty())
+	{
+		return false;
+	}
+	else if (s.length() < suffix.length())
+	{
+		return false;
+	}
+
+	if (!caseSensitive) {
+		return EndsWith(ToLower(s), ToLower(suffix), true);
+	}
+
+	size_t len = suffix.length();
+	std::string sSuffix = s.substr(s.length()-len, len);
+	return (ASSIMP_stricmp(sSuffix, suffix) == 0);
+}
+
+// Below trim functions adapted from http://stackoverflow.com/questions/216823/whats-the-best-way-to-trim-stdstring
+
+/// Trim from start
+static inline std::string &TrimLeft(std::string &s, bool newlines = true)
+{
+	if (!newlines)
+	{
+		s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpace<char>))));
+	}
+	else
+	{
+		s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine<char>))));
+	}
+	return s;
+}
+
+/// Trim from end
+static inline std::string &TrimRight(std::string &s, bool newlines = true)
+{
+	if (!newlines)
+	{
+		s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(Assimp::IsSpace<char>))).base(),s.end());
+	}
+	else
+	{
+		s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine<char>))));
+	}
+	return s;
+}
+
+/// Trim from both ends
+static inline std::string &Trim(std::string &s, bool newlines = true)
+{
+	return TrimLeft(TrimRight(s, newlines), newlines);
+}
+
+/// Skips a line from current @ss position until a newline. Returns the skipped part.
+static inline std::string SkipLine(std::stringstream &ss)
+{
+	std::string skipped;
+	getline(ss, skipped);
+	return skipped;
+}
+
+/// Skips a line and reads next element from @c ss to @c nextElement.
+/** @return Skipped line content until newline. */
+static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &nextElement)
+{
+	std::string skipped = SkipLine(ss);
+	ss >> nextElement;
+	return skipped;
+}
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
+#endif // AI_OGREPARSINGUTILS_H_INC

+ 1195 - 0
Source/ThirdParty/Assimp/code/OgreStructs.cpp

@@ -0,0 +1,1195 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#include "AssimpPCH.h"
+
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
+
+#include "OgreStructs.h"
+#include "TinyFormatter.h"
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+// VertexElement
+
+VertexElement::VertexElement() : 
+	index(0),
+	source(0),
+	offset(0),
+	type(VET_FLOAT1),
+	semantic(VES_POSITION)
+{
+}
+
+size_t VertexElement::Size() const
+{
+	return TypeSize(type);
+}
+
+size_t VertexElement::ComponentCount() const
+{
+	return ComponentCount(type);
+}
+
+size_t VertexElement::ComponentCount(Type type)
+{
+	switch(type)
+	{
+		case VET_COLOUR:
+		case VET_COLOUR_ABGR:
+		case VET_COLOUR_ARGB:
+		case VET_FLOAT1:
+		case VET_DOUBLE1:
+		case VET_SHORT1:
+		case VET_USHORT1:
+		case VET_INT1:
+		case VET_UINT1:
+			return 1;
+		case VET_FLOAT2:
+		case VET_DOUBLE2:
+		case VET_SHORT2:
+		case VET_USHORT2:
+		case VET_INT2:
+		case VET_UINT2:
+			return 2;
+		case VET_FLOAT3:
+		case VET_DOUBLE3:
+		case VET_SHORT3:
+		case VET_USHORT3:
+		case VET_INT3:
+		case VET_UINT3:
+			return 3;
+		case VET_FLOAT4:
+		case VET_DOUBLE4:
+		case VET_SHORT4:
+		case VET_USHORT4:
+		case VET_INT4:
+		case VET_UINT4:
+		case VET_UBYTE4:
+			return 4;
+	}
+	return 0;
+}
+
+size_t VertexElement::TypeSize(Type type)
+{
+	switch(type)
+	{
+		case VET_COLOUR:
+		case VET_COLOUR_ABGR:
+		case VET_COLOUR_ARGB:
+			return sizeof(unsigned int);
+		case VET_FLOAT1:
+			return sizeof(float);
+		case VET_FLOAT2:
+			return sizeof(float)*2;
+		case VET_FLOAT3:
+			return sizeof(float)*3;
+		case VET_FLOAT4:
+			return sizeof(float)*4;
+		case VET_DOUBLE1:
+			return sizeof(double);
+		case VET_DOUBLE2:
+			return sizeof(double)*2;
+		case VET_DOUBLE3:
+			return sizeof(double)*3;
+		case VET_DOUBLE4:
+			return sizeof(double)*4;
+		case VET_SHORT1:
+			return sizeof(short);
+		case VET_SHORT2:
+			return sizeof(short)*2;
+		case VET_SHORT3:
+			return sizeof(short)*3;
+		case VET_SHORT4:
+			return sizeof(short)*4;
+		case VET_USHORT1:
+			return sizeof(unsigned short);
+		case VET_USHORT2:
+			return sizeof(unsigned short)*2;
+		case VET_USHORT3:
+			return sizeof(unsigned short)*3;
+		case VET_USHORT4:
+			return sizeof(unsigned short)*4;
+		case VET_INT1:
+			return sizeof(int);
+		case VET_INT2:
+			return sizeof(int)*2;
+		case VET_INT3:
+			return sizeof(int)*3;
+		case VET_INT4:
+			return sizeof(int)*4;
+		case VET_UINT1:
+			return sizeof(unsigned int);
+		case VET_UINT2:
+			return sizeof(unsigned int)*2;
+		case VET_UINT3:
+			return sizeof(unsigned int)*3;
+		case VET_UINT4:
+			return sizeof(unsigned int)*4;
+		case VET_UBYTE4:
+			return sizeof(unsigned char)*4;
+	}
+	return 0;
+}
+
+std::string VertexElement::TypeToString()
+{
+	return TypeToString(type);
+}
+
+std::string VertexElement::TypeToString(Type type)
+{
+	switch(type)
+	{
+		case VET_COLOUR:		return "COLOUR";
+		case VET_COLOUR_ABGR:	return "COLOUR_ABGR";
+		case VET_COLOUR_ARGB:	return "COLOUR_ARGB";
+		case VET_FLOAT1:		return "FLOAT1";
+		case VET_FLOAT2:		return "FLOAT2";
+		case VET_FLOAT3:		return "FLOAT3";
+		case VET_FLOAT4:		return "FLOAT4";
+		case VET_DOUBLE1:		return "DOUBLE1";
+		case VET_DOUBLE2:		return "DOUBLE2";
+		case VET_DOUBLE3:		return "DOUBLE3";
+		case VET_DOUBLE4:		return "DOUBLE4";
+		case VET_SHORT1:		return "SHORT1";
+		case VET_SHORT2:		return "SHORT2";
+		case VET_SHORT3:		return "SHORT3";
+		case VET_SHORT4:		return "SHORT4";
+		case VET_USHORT1:		return "USHORT1";
+		case VET_USHORT2:		return "USHORT2";
+		case VET_USHORT3:		return "USHORT3";
+		case VET_USHORT4:		return "USHORT4";
+		case VET_INT1:			return "INT1";
+		case VET_INT2:			return "INT2";
+		case VET_INT3:			return "INT3";
+		case VET_INT4:			return "INT4";
+		case VET_UINT1:			return "UINT1";
+		case VET_UINT2:			return "UINT2";
+		case VET_UINT3:			return "UINT3";
+		case VET_UINT4:			return "UINT4";
+		case VET_UBYTE4:		return "UBYTE4";
+	}
+	return "Uknown_VertexElement::Type";
+}
+
+std::string VertexElement::SemanticToString()
+{
+	return SemanticToString(semantic);
+}
+
+std::string VertexElement::SemanticToString(Semantic semantic)
+{
+	switch(semantic)
+	{
+		case VES_POSITION:				return "POSITION";
+		case VES_BLEND_WEIGHTS:			return "BLEND_WEIGHTS";
+		case VES_BLEND_INDICES:			return "BLEND_INDICES";
+		case VES_NORMAL:				return "NORMAL";
+		case VES_DIFFUSE:				return "DIFFUSE";
+		case VES_SPECULAR:				return "SPECULAR";
+		case VES_TEXTURE_COORDINATES:	return "TEXTURE_COORDINATES";
+		case VES_BINORMAL:				return "BINORMAL";
+		case VES_TANGENT:				return "TANGENT";
+	}
+	return "Uknown_VertexElement::Semantic";
+}
+
+// IVertexData
+
+IVertexData::IVertexData() :
+	count(0)
+{
+}
+
+bool IVertexData::HasBoneAssignments() const
+{
+	return !boneAssignments.empty();
+}
+
+void IVertexData::AddVertexMapping(uint32_t oldIndex, uint32_t newIndex)
+{
+	BoneAssignmentsForVertex(oldIndex, newIndex, boneAssignmentsMap[newIndex]);
+	vertexIndexMapping[oldIndex].push_back(newIndex);
+}
+
+void IVertexData::BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const
+{
+	for (VertexBoneAssignmentList::const_iterator iter=boneAssignments.begin(), end=boneAssignments.end();
+		iter!=end; ++iter)
+	{
+		if (iter->vertexIndex == currentIndex)
+		{
+			VertexBoneAssignment a = (*iter);
+			a.vertexIndex = newIndex;
+			dest.push_back(a);
+		}
+	}
+}
+
+AssimpVertexBoneWeightList IVertexData::AssimpBoneWeights(size_t vertices)
+{
+	AssimpVertexBoneWeightList weights;	
+	for(size_t vi=0; vi<vertices; ++vi)
+	{
+		VertexBoneAssignmentList &vertexWeights = boneAssignmentsMap[vi];
+		for (VertexBoneAssignmentList::const_iterator iter=vertexWeights.begin(), end=vertexWeights.end();
+			iter!=end; ++iter)
+		{
+			std::vector<aiVertexWeight> &boneWeights = weights[iter->boneIndex];
+			boneWeights.push_back(aiVertexWeight(vi, iter->weight));
+		}
+	}
+	return weights;
+}
+
+std::set<uint16_t> IVertexData::ReferencedBonesByWeights() const
+{
+	std::set<uint16_t> referenced;
+	for (VertexBoneAssignmentList::const_iterator iter=boneAssignments.begin(), end=boneAssignments.end();
+		iter!=end; ++iter)
+	{
+		referenced.insert(iter->boneIndex);
+	}
+	return referenced;
+}
+
+// VertexData
+
+VertexData::VertexData()
+{
+}
+
+VertexData::~VertexData()
+{
+	Reset();
+}
+
+void VertexData::Reset()
+{
+	// Releases shared ptr memory streams.
+	vertexBindings.clear();
+	vertexElements.clear();
+}
+
+uint32_t VertexData::VertexSize(uint16_t source) const
+{
+	uint32_t size = 0;
+	for(VertexElementList::const_iterator iter=vertexElements.begin(), end=vertexElements.end(); iter != end; ++iter)
+	{
+		if (iter->source == source)
+			size += iter->Size();
+	}
+	return size;
+}
+
+MemoryStream *VertexData::VertexBuffer(uint16_t source)
+{
+	if (vertexBindings.find(source) != vertexBindings.end())
+		return vertexBindings[source];
+	return 0;
+}
+
+VertexElement *VertexData::GetVertexElement(VertexElement::Semantic semantic, uint16_t index)
+{
+	for(VertexElementList::iterator iter=vertexElements.begin(), end=vertexElements.end(); iter != end; ++iter)
+	{
+		VertexElement &element = (*iter);
+		if (element.semantic == semantic && element.index == index)
+			return &element;
+	}
+	return 0;
+}
+
+// VertexDataXml
+
+VertexDataXml::VertexDataXml()
+{
+}
+
+bool VertexDataXml::HasPositions() const
+{
+	return !positions.empty();
+}
+
+bool VertexDataXml::HasNormals() const
+{
+	return !normals.empty();
+}
+
+bool VertexDataXml::HasTangents() const
+{
+	return !tangents.empty();
+}
+
+bool VertexDataXml::HasUvs() const
+{
+	return !uvs.empty();
+}
+
+size_t VertexDataXml::NumUvs() const
+{
+	return uvs.size();
+}
+
+// IndexData
+
+IndexData::IndexData() :
+	count(0),
+	faceCount(0),
+	is32bit(false)
+{
+}
+
+IndexData::~IndexData()
+{
+	Reset();	
+}
+
+void IndexData::Reset()
+{
+	// Release shared ptr memory stream.
+	buffer.reset();
+}
+
+size_t IndexData::IndexSize() const
+{
+	return (is32bit ? sizeof(uint32_t) : sizeof(uint16_t));
+}
+
+size_t IndexData::FaceSize() const
+{
+	return IndexSize() * 3;
+}
+
+// Mesh
+
+Mesh::Mesh() :
+	sharedVertexData(0),
+	skeleton(0),
+	hasSkeletalAnimations(false)
+{
+}
+
+Mesh::~Mesh()
+{
+	Reset();
+}
+
+void Mesh::Reset()
+{
+	OGRE_SAFE_DELETE(skeleton)
+	OGRE_SAFE_DELETE(sharedVertexData)
+
+	for(size_t i=0, len=subMeshes.size(); i<len; ++i) {
+		OGRE_SAFE_DELETE(subMeshes[i])
+	}
+	subMeshes.clear();
+	for(size_t i=0, len=animations.size(); i<len; ++i) {
+		OGRE_SAFE_DELETE(animations[i])
+	}
+	animations.clear();
+	for(size_t i=0, len=poses.size(); i<len; ++i) {
+		OGRE_SAFE_DELETE(poses[i])
+	}
+	poses.clear();
+}
+
+size_t Mesh::NumSubMeshes() const
+{
+	return subMeshes.size();
+}
+
+SubMesh *Mesh::GetSubMesh(uint16_t index) const
+{
+	for(size_t i=0; i<subMeshes.size(); ++i)
+		if (subMeshes[i]->index == index)
+			return subMeshes[i];
+	return 0;
+}
+
+void Mesh::ConvertToAssimpScene(aiScene* dest)
+{
+	// Setup
+	dest->mNumMeshes = NumSubMeshes();
+	dest->mMeshes = new aiMesh*[dest->mNumMeshes];
+
+	// Create root node
+	dest->mRootNode = new aiNode();
+	dest->mRootNode->mNumMeshes = dest->mNumMeshes;
+	dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes];
+
+	// Export meshes
+	for(size_t i=0; i<dest->mNumMeshes; ++i)
+	{
+		dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
+		dest->mRootNode->mMeshes[i] = i;
+	}
+
+	// Export skeleton
+	if (skeleton)
+	{
+		// Bones
+		if (!skeleton->bones.empty())
+		{
+			BoneList rootBones = skeleton->RootBones();
+			dest->mRootNode->mNumChildren = rootBones.size();
+			dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren];
+
+			for(size_t i=0, len=rootBones.size(); i<len; ++i)
+			{
+				dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode);
+			}
+		}
+
+		// Animations
+		if (!skeleton->animations.empty())
+		{
+			dest->mNumAnimations = skeleton->animations.size();
+			dest->mAnimations = new aiAnimation*[dest->mNumAnimations];
+
+			for(size_t i=0, len=skeleton->animations.size(); i<len; ++i)
+			{
+				dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation();
+			}
+		}
+	}
+}
+
+// ISubMesh
+
+ISubMesh::ISubMesh() :
+	index(0),
+	materialIndex(-1),
+	usesSharedVertexData(false),
+	operationType(OT_POINT_LIST)
+{
+}
+
+// SubMesh
+
+SubMesh::SubMesh() :
+	vertexData(0),
+	indexData(new IndexData())
+{
+}
+
+SubMesh::~SubMesh()
+{
+	Reset();
+}
+
+void SubMesh::Reset()
+{
+	OGRE_SAFE_DELETE(vertexData)
+	OGRE_SAFE_DELETE(indexData)
+}
+
+aiMesh *SubMesh::ConvertToAssimpMesh(Mesh *parent)
+{
+	if (operationType != OT_TRIANGLE_LIST) {
+		throw DeadlyImportError(Formatter::format() << "Only mesh operation type OT_TRIANGLE_LIST is supported. Found " << operationType);
+	}
+		
+	aiMesh *dest = new aiMesh();
+	dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+
+	if (!name.empty())
+		dest->mName = name;
+
+	// Material index	
+	if (materialIndex != -1)
+		dest->mMaterialIndex = materialIndex;
+
+	// Pick source vertex data from shader geometry or from internal geometry.
+	VertexData *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData);
+
+	VertexElement *positionsElement = src->GetVertexElement(VertexElement::VES_POSITION);
+	VertexElement *normalsElement   = src->GetVertexElement(VertexElement::VES_NORMAL);
+	VertexElement *uv1Element       = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 0);
+	VertexElement *uv2Element       = src->GetVertexElement(VertexElement::VES_TEXTURE_COORDINATES, 1);
+
+	// Sanity checks
+	if (!positionsElement) {
+		throw DeadlyImportError("Failed to import Ogre VertexElement::VES_POSITION. Mesh does not have vertex positions!");
+	} else if (positionsElement->type != VertexElement::VET_FLOAT3) {
+		throw DeadlyImportError("Ogre Mesh position vertex element type != VertexElement::VET_FLOAT3. This is not supported.");
+	} else if (normalsElement && normalsElement->type != VertexElement::VET_FLOAT3) {
+		throw DeadlyImportError("Ogre Mesh normal vertex element type != VertexElement::VET_FLOAT3. This is not supported.");
+	}
+
+	// Faces
+	dest->mNumFaces = indexData->faceCount;
+	dest->mFaces = new aiFace[dest->mNumFaces];
+
+	// Assimp required unique vertices, we need to convert from Ogres shared indexing.
+	size_t uniqueVertexCount = dest->mNumFaces * 3;
+	dest->mNumVertices = uniqueVertexCount;
+	dest->mVertices = new aiVector3D[dest->mNumVertices];
+
+	// Source streams
+	MemoryStream *positions      = src->VertexBuffer(positionsElement->source);
+	MemoryStream *normals        = (normalsElement ? src->VertexBuffer(normalsElement->source) : 0);
+	MemoryStream *uv1            = (uv1Element ? src->VertexBuffer(uv1Element->source) : 0);
+	MemoryStream *uv2            = (uv2Element ? src->VertexBuffer(uv2Element->source) : 0);
+
+	// Element size
+	const size_t sizePosition    = positionsElement->Size();
+	const size_t sizeNormal      = (normalsElement ? normalsElement->Size() : 0);
+	const size_t sizeUv1         = (uv1Element ? uv1Element->Size() : 0);
+	const size_t sizeUv2         = (uv2Element ? uv2Element->Size() : 0);
+
+	// Vertex width
+	const size_t vWidthPosition  = src->VertexSize(positionsElement->source);
+	const size_t vWidthNormal    = (normalsElement ? src->VertexSize(normalsElement->source) : 0);
+	const size_t vWidthUv1       = (uv1Element ? src->VertexSize(uv1Element->source) : 0);
+	const size_t vWidthUv2       = (uv2Element ? src->VertexSize(uv2Element->source) : 0);
+	
+	bool boneAssignments = src->HasBoneAssignments();
+	
+	// Prepare normals
+	if (normals) 
+		dest->mNormals = new aiVector3D[dest->mNumVertices];
+
+	// Prepare UVs, ignoring incompatible UVs.
+	if (uv1)
+	{
+		if (uv1Element->type == VertexElement::VET_FLOAT2 || uv1Element->type == VertexElement::VET_FLOAT3)
+		{
+			dest->mNumUVComponents[0] = uv1Element->ComponentCount();
+			dest->mTextureCoords[0] = new aiVector3D[dest->mNumVertices];	
+		}
+		else
+		{
+			DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv1Element->TypeToString() << " is not compatible with Assimp. Ignoring UV.");
+			uv1 = 0;
+		}
+	}
+	if (uv2)
+	{
+		if (uv2Element->type == VertexElement::VET_FLOAT2 || uv2Element->type == VertexElement::VET_FLOAT3)
+		{
+			dest->mNumUVComponents[1] = uv2Element->ComponentCount();
+			dest->mTextureCoords[1] = new aiVector3D[dest->mNumVertices];	
+		}
+		else
+		{
+			DefaultLogger::get()->warn(Formatter::format() << "Ogre imported UV0 type " << uv2Element->TypeToString() << " is not compatible with Assimp. Ignoring UV.");
+			uv2 = 0;
+		}
+	}
+
+	aiVector3D *uv1Dest = (uv1 ? dest->mTextureCoords[0] : 0);
+	aiVector3D *uv2Dest = (uv2 ? dest->mTextureCoords[1] : 0);
+
+	MemoryStream *faces = indexData->buffer.get();
+	for (size_t fi=0, isize=indexData->IndexSize(), fsize=indexData->FaceSize(); 
+		 fi<dest->mNumFaces; ++fi)
+	{
+		// Source Ogre face
+		aiFace ogreFace;
+		ogreFace.mNumIndices = 3;
+		ogreFace.mIndices = new unsigned int[3];
+
+		faces->Seek(fi * fsize, aiOrigin_SET);
+		if (indexData->is32bit)
+		{
+			faces->Read(&ogreFace.mIndices[0], isize, 3);
+		}
+		else
+		{
+			uint16_t iout = 0;
+			for (size_t ii=0; ii<3; ++ii)
+			{
+				faces->Read(&iout, isize, 1);
+				ogreFace.mIndices[ii] = static_cast<unsigned int>(iout);
+			}
+		}
+
+		// Destination Assimp face
+		aiFace &face = dest->mFaces[fi];
+		face.mNumIndices = 3;
+		face.mIndices = new unsigned int[3];
+
+		const size_t pos = fi * 3;
+		for (size_t v=0; v<3; ++v)
+		{
+			const size_t newIndex = pos + v;
+
+			// Write face index
+			face.mIndices[v] = newIndex;
+
+			// Ogres vertex index to ref into the source buffers.
+			const size_t ogreVertexIndex = ogreFace.mIndices[v];
+			src->AddVertexMapping(ogreVertexIndex, newIndex);
+			
+			// Position
+			positions->Seek((vWidthPosition * ogreVertexIndex) + positionsElement->offset, aiOrigin_SET);
+			positions->Read(&dest->mVertices[newIndex], sizePosition, 1);
+
+			// Normal
+			if (normals)
+			{
+				normals->Seek((vWidthNormal * ogreVertexIndex) + normalsElement->offset, aiOrigin_SET);
+				normals->Read(&dest->mNormals[newIndex], sizeNormal, 1);
+			}
+			// UV0
+			if (uv1 && uv1Dest)
+			{
+				uv1->Seek((vWidthUv1 * ogreVertexIndex) + uv1Element->offset, aiOrigin_SET);
+				uv1->Read(&uv1Dest[newIndex], sizeUv1, 1);
+				uv1Dest[newIndex].y = (uv1Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form
+			}
+			// UV1
+			if (uv2 && uv2Dest)
+			{
+				uv2->Seek((vWidthUv2 * ogreVertexIndex) + uv2Element->offset, aiOrigin_SET);
+				uv2->Read(&uv2Dest[newIndex], sizeUv2, 1);
+				uv2Dest[newIndex].y = (uv2Dest[newIndex].y * -1) + 1; // Flip UV from Ogre to Assimp form
+			}
+		}
+	}
+
+	// Bones and bone weights
+	if (parent->skeleton && boneAssignments)
+	{
+		AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices);
+		std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights();
+
+		dest->mNumBones = referencedBones.size();
+		dest->mBones = new aiBone*[dest->mNumBones];
+
+		size_t assimpBoneIndex = 0;
+		for(std::set<uint16_t>::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex)
+		{
+			Bone *bone = parent->skeleton->BoneById((*rbIter));
+			dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]);
+		}
+	}
+
+	return dest;
+}
+
+// MeshXml
+
+MeshXml::MeshXml() :
+	sharedVertexData(0),
+	skeleton(0)
+{
+}
+
+MeshXml::~MeshXml()
+{
+	Reset();
+}
+
+void MeshXml::Reset()
+{
+	OGRE_SAFE_DELETE(skeleton)
+	OGRE_SAFE_DELETE(sharedVertexData)
+
+	for(size_t i=0, len=subMeshes.size(); i<len; ++i) {
+		OGRE_SAFE_DELETE(subMeshes[i])
+	}
+	subMeshes.clear();
+}
+
+size_t MeshXml::NumSubMeshes() const
+{
+	return subMeshes.size();
+}
+
+SubMeshXml *MeshXml::GetSubMesh(uint16_t index) const
+{
+	for(size_t i=0; i<subMeshes.size(); ++i)
+		if (subMeshes[i]->index == index)
+			return subMeshes[i];
+	return 0;
+}
+
+void MeshXml::ConvertToAssimpScene(aiScene* dest)
+{
+	// Setup
+	dest->mNumMeshes = NumSubMeshes();
+	dest->mMeshes = new aiMesh*[dest->mNumMeshes];
+
+	// Create root node
+	dest->mRootNode = new aiNode();
+	dest->mRootNode->mNumMeshes = dest->mNumMeshes;
+	dest->mRootNode->mMeshes = new unsigned int[dest->mRootNode->mNumMeshes];
+
+	// Export meshes
+	for(size_t i=0; i<dest->mNumMeshes; ++i)
+	{
+		dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
+		dest->mRootNode->mMeshes[i] = i;
+	}
+	
+	// Export skeleton
+	if (skeleton)
+	{
+		// Bones
+		if (!skeleton->bones.empty())
+		{
+			BoneList rootBones = skeleton->RootBones();
+			dest->mRootNode->mNumChildren = rootBones.size();
+			dest->mRootNode->mChildren = new aiNode*[dest->mRootNode->mNumChildren];
+			
+			for(size_t i=0, len=rootBones.size(); i<len; ++i)
+			{
+				dest->mRootNode->mChildren[i] = rootBones[i]->ConvertToAssimpNode(skeleton, dest->mRootNode);
+			}
+		}
+
+		// Animations
+		if (!skeleton->animations.empty())
+		{
+			dest->mNumAnimations = skeleton->animations.size();
+			dest->mAnimations = new aiAnimation*[dest->mNumAnimations];
+			
+			for(size_t i=0, len=skeleton->animations.size(); i<len; ++i)
+			{
+				dest->mAnimations[i] = skeleton->animations[i]->ConvertToAssimpAnimation();
+			}
+		}
+	}
+}
+
+// SubMeshXml
+
+SubMeshXml::SubMeshXml() :
+	vertexData(0),
+	indexData(new IndexDataXml())
+{
+}
+
+SubMeshXml::~SubMeshXml()
+{
+	Reset();
+}
+
+void SubMeshXml::Reset()
+{
+	OGRE_SAFE_DELETE(indexData)
+	OGRE_SAFE_DELETE(vertexData)
+}
+
+aiMesh *SubMeshXml::ConvertToAssimpMesh(MeshXml *parent)
+{
+	aiMesh *dest = new aiMesh();
+	dest->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
+
+	if (!name.empty())
+		dest->mName = name;
+
+	// Material index	
+	if (materialIndex != -1)
+		dest->mMaterialIndex = materialIndex;
+
+	// Faces
+	dest->mNumFaces = indexData->faceCount;
+	dest->mFaces = new aiFace[dest->mNumFaces];
+
+	// Assimp required unique vertices, we need to convert from Ogres shared indexing.
+	size_t uniqueVertexCount = dest->mNumFaces * 3;
+	dest->mNumVertices = uniqueVertexCount;
+	dest->mVertices = new aiVector3D[dest->mNumVertices];
+
+	VertexDataXml *src = (!usesSharedVertexData ? vertexData : parent->sharedVertexData);
+	bool boneAssignments = src->HasBoneAssignments();
+	bool normals = src->HasNormals();
+	size_t uvs = src->NumUvs();
+	
+	// Prepare normals
+	if (normals) 
+		dest->mNormals = new aiVector3D[dest->mNumVertices];
+
+	// Prepare UVs
+	for(size_t uvi=0; uvi<uvs; ++uvi)
+	{
+		dest->mNumUVComponents[uvi] = 2;
+		dest->mTextureCoords[uvi] = new aiVector3D[dest->mNumVertices];
+	}
+
+	for (size_t fi=0; fi<dest->mNumFaces; ++fi)
+	{
+		// Source Ogre face
+		aiFace &ogreFace = indexData->faces[fi];
+
+		// Destination Assimp face
+		aiFace &face = dest->mFaces[fi];
+		face.mNumIndices = 3;
+		face.mIndices = new unsigned int[3];
+
+		const size_t pos = fi * 3;
+		for (size_t v=0; v<3; ++v)
+		{
+			const size_t newIndex = pos + v;
+
+			// Write face index
+			face.mIndices[v] = newIndex;
+
+			// Ogres vertex index to ref into the source buffers.
+			const size_t ogreVertexIndex = ogreFace.mIndices[v];
+			src->AddVertexMapping(ogreVertexIndex, newIndex);
+			
+			// Position
+			dest->mVertices[newIndex] = src->positions[ogreVertexIndex];
+
+			// Normal
+			if (normals)
+				dest->mNormals[newIndex] = src->normals[ogreVertexIndex];
+				
+			// UVs
+			for(size_t uvi=0; uvi<uvs; ++uvi)
+			{
+				aiVector3D *uvDest = dest->mTextureCoords[uvi];
+				std::vector<aiVector3D> &uvSrc = src->uvs[uvi];
+				uvDest[newIndex] = uvSrc[ogreVertexIndex];
+			}
+		}
+	}
+	
+	// Bones and bone weights
+	if (parent->skeleton && boneAssignments)
+	{
+		AssimpVertexBoneWeightList weights = src->AssimpBoneWeights(dest->mNumVertices);
+		std::set<uint16_t> referencedBones = src->ReferencedBonesByWeights();
+
+		dest->mNumBones = referencedBones.size();
+		dest->mBones = new aiBone*[dest->mNumBones];
+		
+		size_t assimpBoneIndex = 0;
+		for(std::set<uint16_t>::const_iterator rbIter=referencedBones.begin(), rbEnd=referencedBones.end(); rbIter != rbEnd; ++rbIter, ++assimpBoneIndex)
+		{
+			Bone *bone = parent->skeleton->BoneById((*rbIter));
+			dest->mBones[assimpBoneIndex] = bone->ConvertToAssimpBone(parent->skeleton, weights[bone->id]);
+		}
+	}
+
+	return dest;
+}
+
+// Animation
+
+Animation::Animation(Skeleton *parent) :
+	parentSkeleton(parent),
+	parentMesh(0),
+	length(0.0f),
+	baseTime(-1.0f)
+{
+}
+
+Animation::Animation(Mesh *parent) : 
+	parentMesh(parent),
+	parentSkeleton(0),
+	length(0.0f),
+	baseTime(-1.0f)
+{
+}
+
+VertexData *Animation::AssociatedVertexData(VertexAnimationTrack *track) const
+{
+	if (!parentMesh)
+		return 0;
+
+	bool sharedGeom = (track->target == 0);
+	if (sharedGeom)
+		return parentMesh->sharedVertexData;
+	else
+		return parentMesh->GetSubMesh(track->target-1)->vertexData;
+}
+
+aiAnimation *Animation::ConvertToAssimpAnimation()
+{
+	aiAnimation *anim = new aiAnimation();
+	anim->mName = name;
+	anim->mDuration = static_cast<double>(length);
+	anim->mTicksPerSecond = 1.0;
+
+	// Tracks
+	if (!tracks.empty())
+	{
+		anim->mNumChannels = tracks.size();
+		anim->mChannels = new aiNodeAnim*[anim->mNumChannels];
+		
+		for(size_t i=0, len=tracks.size(); i<len; ++i)
+		{
+			anim->mChannels[i] = tracks[i].ConvertToAssimpAnimationNode(parentSkeleton);
+		}
+	}
+	return anim;
+}
+
+// Skeleton
+
+Skeleton::Skeleton() :
+	blendMode(ANIMBLEND_AVERAGE)
+{
+}
+
+Skeleton::~Skeleton()
+{
+	Reset();
+}
+
+void Skeleton::Reset()
+{
+	for(size_t i=0, len=bones.size(); i<len; ++i) {
+		OGRE_SAFE_DELETE(bones[i])
+	}
+	bones.clear();
+	for(size_t i=0, len=animations.size(); i<len; ++i) {
+		OGRE_SAFE_DELETE(animations[i])
+	}
+	animations.clear();
+}
+
+BoneList Skeleton::RootBones() const
+{
+	BoneList rootBones;
+	for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter)
+	{
+		if (!(*iter)->IsParented())
+			rootBones.push_back((*iter));
+	}
+	return rootBones;
+}
+
+size_t Skeleton::NumRootBones() const
+{
+	size_t num = 0;
+	for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter)
+	{
+		if (!(*iter)->IsParented())
+			num++;
+	}
+	return num;
+}
+
+Bone *Skeleton::BoneByName(const std::string &name) const
+{
+	for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter)
+	{
+		if ((*iter)->name == name)
+			return (*iter);
+	}
+	return 0;
+}
+
+Bone *Skeleton::BoneById(uint16_t id) const
+{
+	for(BoneList::const_iterator iter = bones.begin(); iter != bones.end(); ++iter)
+	{
+		if ((*iter)->id == id)
+			return (*iter);
+	}
+	return 0;
+}
+
+// Bone
+
+Bone::Bone() :
+	id(0),
+	parent(0),
+	parentId(-1),
+	scale(1.0f, 1.0f, 1.0f)
+{
+}
+
+bool Bone::IsParented() const
+{
+	return (parentId != -1 && parent != 0);
+}
+
+uint16_t Bone::ParentId() const
+{
+	return static_cast<uint16_t>(parentId);
+}
+
+void Bone::AddChild(Bone *bone)
+{
+	if (!bone)
+		return;
+	if (bone->IsParented())
+		throw DeadlyImportError("Attaching child Bone that is already parented: " + bone->name);
+		
+	bone->parent = this;
+	bone->parentId = id;
+	children.push_back(bone->id);
+}
+
+void Bone::CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton)
+{
+	if (!IsParented())
+		worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse();
+	else
+		worldMatrix = aiMatrix4x4(scale, rotation, position).Inverse() * parent->worldMatrix;
+
+	defaultPose = aiMatrix4x4(scale, rotation, position);
+
+	// Recursively for all children now that the parent matrix has been calculated.
+	for (size_t i=0, len=children.size(); i<len; ++i)
+	{
+		Bone *child = skeleton->BoneById(children[i]);
+		if (!child) {
+			throw DeadlyImportError(Formatter::format() << "CalculateWorldMatrixAndDefaultPose: Failed to find child bone " << children[i] << " for parent " << id << " " << name);
+		}
+		child->CalculateWorldMatrixAndDefaultPose(skeleton);
+	}
+}
+
+aiNode *Bone::ConvertToAssimpNode(Skeleton *skeleton, aiNode *parentNode)
+{
+	// Bone node
+	aiNode* node = new aiNode(name);
+	node->mParent = parentNode;
+	node->mTransformation = defaultPose;
+
+	// Children
+	if (!children.empty())
+	{
+		node->mNumChildren = children.size();
+		node->mChildren = new aiNode*[node->mNumChildren];
+
+		for(size_t i=0, len=children.size(); i<len; ++i)
+		{
+			Bone *child = skeleton->BoneById(children[i]);
+			if (!child) {
+				throw DeadlyImportError(Formatter::format() << "ConvertToAssimpNode: Failed to find child bone " << children[i] << " for parent " << id << " " << name);
+			}
+			node->mChildren[i] = child->ConvertToAssimpNode(skeleton, node);
+		}
+	}
+	return node;
+}
+
+aiBone *Bone::ConvertToAssimpBone(Skeleton *parent, const std::vector<aiVertexWeight> &boneWeights)
+{
+	aiBone *bone = new aiBone();
+	bone->mName = name;
+	bone->mOffsetMatrix = worldMatrix;
+	
+	if (!boneWeights.empty())
+	{
+		bone->mNumWeights = boneWeights.size();
+		bone->mWeights = new aiVertexWeight[boneWeights.size()];
+		memcpy(bone->mWeights, &boneWeights[0], boneWeights.size() * sizeof(aiVertexWeight));
+	}
+
+	return bone;
+}
+
+// VertexAnimationTrack
+
+VertexAnimationTrack::VertexAnimationTrack() :
+	target(0),
+	type(VAT_NONE)
+{
+}
+
+aiNodeAnim *VertexAnimationTrack::ConvertToAssimpAnimationNode(Skeleton *skeleton)
+{
+	if (boneName.empty() || type != VAT_TRANSFORM) {
+		throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Cannot convert track that has no target bone name or is not type of VAT_TRANSFORM");
+	}
+
+	aiNodeAnim *nodeAnim = new aiNodeAnim();
+	nodeAnim->mNodeName = boneName;
+	
+	Bone *bone = skeleton->BoneByName(boneName);
+	if (!bone) {
+		throw DeadlyImportError("VertexAnimationTrack::ConvertToAssimpAnimationNode: Failed to find bone " + boneName + " from parent Skeleton");
+	}
+
+	// Keyframes
+	size_t numKeyframes = transformKeyFrames.size();
+
+	nodeAnim->mPositionKeys = new aiVectorKey[numKeyframes];				
+	nodeAnim->mRotationKeys = new aiQuatKey[numKeyframes];
+	nodeAnim->mScalingKeys = new aiVectorKey[numKeyframes];
+	nodeAnim->mNumPositionKeys = numKeyframes;
+	nodeAnim->mNumRotationKeys = numKeyframes;
+	nodeAnim->mNumScalingKeys  = numKeyframes;
+
+	for(size_t kfi=0; kfi<numKeyframes; ++kfi)
+	{
+		TransformKeyFrame &kfSource = transformKeyFrames[kfi];
+
+		// Calculate the complete transformation from world space to bone space
+		aiVector3D pos; aiQuaternion rot; aiVector3D scale;
+
+		aiMatrix4x4 finalTransform = bone->defaultPose * kfSource.Transform();		
+		finalTransform.Decompose(scale, rot, pos);
+
+		double t = static_cast<double>(kfSource.timePos);
+		nodeAnim->mPositionKeys[kfi].mTime = t;
+		nodeAnim->mRotationKeys[kfi].mTime = t;
+		nodeAnim->mScalingKeys[kfi].mTime = t;
+
+		nodeAnim->mPositionKeys[kfi].mValue = pos;					
+		nodeAnim->mRotationKeys[kfi].mValue = rot;
+		nodeAnim->mScalingKeys[kfi].mValue = scale;
+	}
+
+	return nodeAnim;
+}
+
+// TransformKeyFrame
+
+TransformKeyFrame::TransformKeyFrame() : 
+	timePos(0.0f),
+	scale(1.0f, 1.0f, 1.0f)
+{
+}
+
+aiMatrix4x4 TransformKeyFrame::Transform()
+{
+	return aiMatrix4x4(scale, rotation, position);
+}
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER

+ 681 - 0
Source/ThirdParty/Assimp/code/OgreStructs.h

@@ -0,0 +1,681 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef AI_OGRESTRUCTS_H_INC
+#define AI_OGRESTRUCTS_H_INC
+
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
+
+#include "AssimpPCH.h"
+#include "MemoryIOWrapper.h"
+
+/** @note Parts of this implementation, for example enums, deserialization constants and logic
+	has been copied directly with minor modifications from the MIT licensed Ogre3D code base.
+	See more from https://bitbucket.org/sinbad/ogre. */
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+// Forward decl
+class Mesh;
+class MeshXml;
+class SubMesh;
+class SubMeshXml;
+class Skeleton;
+
+#define OGRE_SAFE_DELETE(p) delete p; p=0;
+
+// Typedefs
+typedef Assimp::MemoryIOStream MemoryStream;
+typedef boost::shared_ptr<MemoryStream> MemoryStreamPtr;
+typedef std::map<uint16_t, MemoryStreamPtr> VertexBufferBindings;
+
+// Ogre Vertex Element
+class VertexElement
+{
+public:
+	/// Vertex element semantics, used to identify the meaning of vertex buffer contents
+	enum Semantic {
+		/// Position, 3 reals per vertex
+		VES_POSITION = 1,
+		/// Blending weights
+		VES_BLEND_WEIGHTS = 2,
+		/// Blending indices
+		VES_BLEND_INDICES = 3,
+		/// Normal, 3 reals per vertex
+		VES_NORMAL = 4,
+		/// Diffuse colours
+		VES_DIFFUSE = 5,
+		/// Specular colours
+		VES_SPECULAR = 6,
+		/// Texture coordinates
+		VES_TEXTURE_COORDINATES = 7,
+		/// Binormal (Y axis if normal is Z)
+		VES_BINORMAL = 8,
+		/// Tangent (X axis if normal is Z)
+		VES_TANGENT = 9,
+		/// The  number of VertexElementSemantic elements (note - the first value VES_POSITION is 1) 
+		VES_COUNT = 9
+	};
+
+	/// Vertex element type, used to identify the base types of the vertex contents
+	enum Type
+	{
+		VET_FLOAT1 = 0,
+		VET_FLOAT2 = 1,
+		VET_FLOAT3 = 2,
+		VET_FLOAT4 = 3,
+		/// alias to more specific colour type - use the current rendersystem's colour packing
+		VET_COLOUR = 4,
+		VET_SHORT1 = 5,
+		VET_SHORT2 = 6,
+		VET_SHORT3 = 7,
+		VET_SHORT4 = 8,
+		VET_UBYTE4 = 9,
+		/// D3D style compact colour
+		VET_COLOUR_ARGB = 10,
+		/// GL style compact colour
+		VET_COLOUR_ABGR = 11,
+		VET_DOUBLE1 = 12,
+		VET_DOUBLE2 = 13,
+		VET_DOUBLE3 = 14,
+		VET_DOUBLE4 = 15,
+		VET_USHORT1 = 16,
+		VET_USHORT2 = 17,
+		VET_USHORT3 = 18,
+		VET_USHORT4 = 19,      
+		VET_INT1 = 20,
+		VET_INT2 = 21,
+		VET_INT3 = 22,
+		VET_INT4 = 23,
+		VET_UINT1 = 24,
+		VET_UINT2 = 25,
+		VET_UINT3 = 26,
+		VET_UINT4 = 27
+	};
+
+	VertexElement();
+
+	/// Size of the vertex element in bytes.
+	size_t Size() const;
+	
+	/// Count of components in this element, eg. VET_FLOAT3 return 3.
+	size_t ComponentCount() const;
+	
+	/// Type as string.
+	std::string TypeToString();
+	
+	/// Semantic as string.
+	std::string SemanticToString();
+	
+	static size_t TypeSize(Type type);
+	static size_t ComponentCount(Type type);
+	static std::string TypeToString(Type type);
+	static std::string SemanticToString(Semantic semantic);
+
+	uint16_t index;
+	uint16_t source;
+	uint16_t offset;
+	Type type;
+	Semantic semantic;
+};
+typedef std::vector<VertexElement> VertexElementList;
+
+/// Ogre Vertex Bone Assignment
+struct VertexBoneAssignment
+{
+	uint32_t vertexIndex;
+	uint16_t boneIndex;
+	float weight;
+};
+typedef std::vector<VertexBoneAssignment> VertexBoneAssignmentList;
+typedef std::map<uint32_t, VertexBoneAssignmentList > VertexBoneAssignmentsMap;
+typedef std::map<uint16_t, std::vector<aiVertexWeight> > AssimpVertexBoneWeightList;
+
+// Ogre Vertex Data interface, inherited by the binary and XML implementations.
+class IVertexData
+{
+public:
+	IVertexData();
+	
+	/// Returns if bone assignments are available.
+	bool HasBoneAssignments() const;
+	
+	/// Add vertex mapping from old to new index.
+	void AddVertexMapping(uint32_t oldIndex, uint32_t newIndex);
+
+	/// Returns re-mapped bone assignments.
+	/** @note Uses mappings added via AddVertexMapping. */
+	AssimpVertexBoneWeightList AssimpBoneWeights(size_t vertices);
+
+	/// Returns a set of bone indexes that are referenced by bone assignments (weights).
+	std::set<uint16_t> ReferencedBonesByWeights() const;
+
+	/// Vertex count.
+	uint32_t count;
+	
+	/// Bone assignments.
+	VertexBoneAssignmentList boneAssignments;
+	
+private:
+	void BoneAssignmentsForVertex(uint32_t currentIndex, uint32_t newIndex, VertexBoneAssignmentList &dest) const;
+	
+	std::map<uint32_t, std::vector<uint32_t> > vertexIndexMapping;
+	VertexBoneAssignmentsMap boneAssignmentsMap;
+};
+
+// Ogre Vertex Data
+class VertexData : public IVertexData
+{
+public:
+	VertexData();
+	~VertexData();
+
+	/// Releases all memory that this data structure owns.
+	void Reset();
+
+	/// Get vertex size for @c source.
+	uint32_t VertexSize(uint16_t source) const;
+
+	/// Get vertex buffer for @c source.
+	MemoryStream *VertexBuffer(uint16_t source);
+
+	/// Get vertex element for @c semantic for @c index.
+	VertexElement *GetVertexElement(VertexElement::Semantic semantic, uint16_t index = 0);
+
+	/// Vertex elements.
+	VertexElementList vertexElements;
+
+	/// Vertex buffers mapped to bind index.
+	VertexBufferBindings vertexBindings;
+};
+
+// Ogre Index Data
+class IndexData
+{
+public:
+	IndexData();
+	~IndexData();
+
+	/// Releases all memory that this data structure owns.
+	void Reset();
+
+	/// Index size in bytes.
+	size_t IndexSize() const;
+
+	/// Face size in bytes.
+	size_t FaceSize() const;
+
+	/// Index count.
+	uint32_t count;
+	
+	/// Face count.
+	uint32_t faceCount;
+
+	/// If has 32-bit indexes.
+	bool is32bit;
+
+	/// Index buffer.
+	MemoryStreamPtr buffer;
+};
+
+/// Ogre Pose
+class Pose
+{
+public:
+	struct Vertex
+	{
+		uint32_t index;
+		aiVector3D offset;
+		aiVector3D normal;
+	};
+	typedef std::map<uint32_t, Vertex> PoseVertexMap;
+
+	Pose() : target(0), hasNormals(false) {}
+
+	/// Name.
+	std::string name;
+	
+	/// Target.
+	uint16_t target;
+	
+	/// Does vertices map have normals.
+	bool hasNormals;
+	
+	/// Vertex offset and normals.
+	PoseVertexMap vertices;
+};
+typedef std::vector<Pose*> PoseList;
+
+/// Ogre Pose Key Frame Ref
+struct PoseRef
+{
+	uint16_t index;
+	float influence;
+};
+typedef std::vector<PoseRef> PoseRefList;
+
+/// Ogre Pose Key Frame
+struct PoseKeyFrame
+{
+	/// Time position in the animation.
+	float timePos;
+
+	PoseRefList references;
+};
+typedef std::vector<PoseKeyFrame> PoseKeyFrameList;
+
+/// Ogre Morph Key Frame
+struct MorphKeyFrame
+{
+	/// Time position in the animation.
+	float timePos;
+
+	MemoryStreamPtr buffer;
+};
+typedef std::vector<MorphKeyFrame> MorphKeyFrameList;
+
+/// Ogre animation key frame
+struct TransformKeyFrame
+{
+	TransformKeyFrame();
+	
+	aiMatrix4x4 Transform();
+
+	float timePos;
+	
+	aiQuaternion rotation;
+	aiVector3D position;
+	aiVector3D scale;
+};
+typedef std::vector<TransformKeyFrame> TransformKeyFrameList;
+
+/// Ogre Animation Track
+struct VertexAnimationTrack
+{
+	enum Type
+	{
+		/// No animation
+		VAT_NONE = 0,
+		/// Morph animation is made up of many interpolated snapshot keyframes
+		VAT_MORPH = 1,
+		/// Pose animation is made up of a single delta pose keyframe
+		VAT_POSE = 2,
+		/// Keyframe that has its on pos, rot and scale for a time position
+		VAT_TRANSFORM = 3
+	};
+
+	VertexAnimationTrack();
+	
+	/// Convert to Assimp node animation.
+	aiNodeAnim *ConvertToAssimpAnimationNode(Skeleton *skeleton);
+
+	// Animation type.
+	Type type;
+	
+	/// Vertex data target.
+	/**  0 == shared geometry
+		>0 == submesh index + 1 */
+	uint16_t target;
+	
+	/// Only valid for VAT_TRANSFORM.
+	std::string boneName;
+
+	/// Only one of these will contain key frames, depending on the type enum.
+	PoseKeyFrameList poseKeyFrames;
+	MorphKeyFrameList morphKeyFrames;
+	TransformKeyFrameList transformKeyFrames;
+};
+typedef std::vector<VertexAnimationTrack> VertexAnimationTrackList;
+
+/// Ogre Animation
+class Animation
+{
+public:
+	Animation(Skeleton *parent);
+	Animation(Mesh *parent);
+
+	/// Returns the associated vertex data for a track in this animation.
+	/** @note Only valid to call when parent Mesh is set. */
+	VertexData *AssociatedVertexData(VertexAnimationTrack *track) const;
+
+	/// Convert to Assimp animation.
+	aiAnimation *ConvertToAssimpAnimation();
+
+	/// Parent mesh.
+	/** @note Set only when animation is read from a mesh. */
+	Mesh *parentMesh;
+
+	/// Parent skeleton.
+	/** @note Set only when animation is read from a skeleton. */
+	Skeleton *parentSkeleton;
+
+	/// Animation name.
+	std::string name;
+
+	/// Base animation name.
+	std::string baseName;
+
+	/// Length in seconds.
+	float length;
+
+	/// Base animation key time.
+	float baseTime;
+
+	/// Animation tracks.
+	VertexAnimationTrackList tracks;
+};
+typedef std::vector<Animation*> AnimationList;
+
+/// Ogre Bone
+class Bone
+{
+public:
+	Bone();
+
+	/// Returns if this bone is parented.
+	bool IsParented() const;
+
+	/// Parent index as uint16_t. Internally int32_t as -1 means unparented.
+	uint16_t ParentId() const;
+
+	/// Add child bone.
+	void AddChild(Bone *bone);
+	
+	/// Calculates the world matrix for bone and its children.
+	void CalculateWorldMatrixAndDefaultPose(Skeleton *skeleton);
+	
+	/// Convert to Assimp node (animation nodes).
+	aiNode *ConvertToAssimpNode(Skeleton *parent, aiNode *parentNode = 0);
+	
+	/// Convert to Assimp bone (mesh bones).
+	aiBone *ConvertToAssimpBone(Skeleton *parent, const std::vector<aiVertexWeight> &boneWeights);
+
+	uint16_t id;
+	std::string name;
+
+	Bone *parent;
+	int32_t parentId;
+	std::vector<uint16_t> children;
+
+	aiVector3D position;
+	aiQuaternion rotation;
+	aiVector3D scale;
+	
+	aiMatrix4x4 worldMatrix;
+	aiMatrix4x4 defaultPose;
+};
+typedef std::vector<Bone*> BoneList;
+
+/// Ogre Skeleton
+class Skeleton
+{
+public:
+	enum BlendMode
+	{
+		/// Animations are applied by calculating a weighted average of all animations
+		ANIMBLEND_AVERAGE = 0,
+		/// Animations are applied by calculating a weighted cumulative total
+		ANIMBLEND_CUMULATIVE = 1
+	};
+
+	Skeleton();
+	~Skeleton();
+
+	/// Releases all memory that this data structure owns.
+	void Reset();
+	
+	/// Returns unparented root bones.
+	BoneList RootBones() const;
+	
+	/// Returns number of unparented root bones.
+	size_t NumRootBones() const;
+	
+	/// Get bone by name.
+	Bone *BoneByName(const std::string &name) const;
+	
+	/// Get bone by id.
+	Bone *BoneById(uint16_t id) const;
+	
+	BoneList bones;
+	AnimationList animations;
+	
+	/// @todo Take blend mode into account, but where?
+	BlendMode blendMode;
+};
+
+/// Ogre Sub Mesh interface, inherited by the binary and XML implementations.
+class ISubMesh
+{
+public:
+	/// @note Full list of Ogre types, not all of them are supported and exposed to Assimp.
+	enum OperationType
+	{
+		/// A list of points, 1 vertex per point
+		OT_POINT_LIST = 1,
+		/// A list of lines, 2 vertices per line
+		OT_LINE_LIST = 2,
+		/// A strip of connected lines, 1 vertex per line plus 1 start vertex
+		OT_LINE_STRIP = 3,
+		/// A list of triangles, 3 vertices per triangle
+		OT_TRIANGLE_LIST = 4,
+		/// A strip of triangles, 3 vertices for the first triangle, and 1 per triangle after that 
+		OT_TRIANGLE_STRIP = 5,
+		/// A fan of triangles, 3 vertices for the first triangle, and 1 per triangle after that
+		OT_TRIANGLE_FAN = 6
+	};
+
+	ISubMesh();
+
+	/// SubMesh index.
+	unsigned int index;
+
+	/// SubMesh name.
+	std::string name;
+
+	/// Material used by this submesh.
+	std::string materialRef;
+
+	/// Texture alias information.
+	std::string textureAliasName;
+	std::string textureAliasRef;
+
+	/// Assimp scene material index used by this submesh.
+	/** -1 if no material or material could not be imported. */
+	int materialIndex;
+	
+	/// If submesh uses shared geometry from parent mesh.
+	bool usesSharedVertexData;
+
+	/// Operation type.
+	OperationType operationType;
+};
+
+/// Ogre SubMesh
+class SubMesh : public ISubMesh
+{
+public:
+	SubMesh();
+	~SubMesh();
+	
+	/// Releases all memory that this data structure owns.
+	/** @note Vertex and index data contains shared ptrs
+		that are freed automatically. In practice the ref count
+		should be 0 after this reset. */
+	void Reset();
+	
+	/// Covert to Assimp mesh.
+	aiMesh *ConvertToAssimpMesh(Mesh *parent);
+
+	/// Vertex data.
+	VertexData *vertexData;
+
+	/// Index data.
+	IndexData *indexData;
+};
+typedef std::vector<SubMesh*> SubMeshList;
+
+/// Ogre Mesh
+class Mesh
+{
+public:
+	Mesh();
+	~Mesh();
+
+	/// Releases all memory that this data structure owns.
+	void Reset();
+
+	/// Returns number of subMeshes.
+	size_t NumSubMeshes() const;
+
+	/// Returns submesh for @c index.
+	SubMesh *GetSubMesh(uint16_t index) const;
+
+	/// Convert mesh to Assimp scene.
+	void ConvertToAssimpScene(aiScene* dest);
+
+	/// Mesh has skeletal animations.
+	bool hasSkeletalAnimations;
+	
+	/// Skeleton reference.
+	std::string skeletonRef;
+
+	/// Skeleton.
+	Skeleton *skeleton;
+
+	/// Vertex data
+	VertexData *sharedVertexData;
+
+	/// Sub meshes.
+	SubMeshList subMeshes;
+
+	/// Animations
+	AnimationList animations;
+
+	/// Poses
+	PoseList poses;
+};
+
+/// Ogre XML Vertex Data
+class VertexDataXml : public IVertexData
+{
+public:
+	VertexDataXml();
+	
+	bool HasPositions() const;
+	bool HasNormals() const;
+	bool HasTangents() const;
+	bool HasUvs() const;
+	size_t NumUvs() const;
+
+	std::vector<aiVector3D> positions;
+	std::vector<aiVector3D> normals;
+	std::vector<aiVector3D> tangents;
+	std::vector<std::vector<aiVector3D> > uvs;
+};
+
+/// Ogre XML Index Data
+class IndexDataXml
+{
+public:
+	IndexDataXml() : faceCount(0) {}
+
+	/// Face count.
+	uint32_t faceCount;
+
+	std::vector<aiFace> faces;
+};
+
+/// Ogre XML SubMesh
+class SubMeshXml : public ISubMesh
+{
+public:
+	SubMeshXml();
+	~SubMeshXml();
+	
+	/// Releases all memory that this data structure owns.
+	void Reset();
+	
+	aiMesh *ConvertToAssimpMesh(MeshXml *parent);
+
+	IndexDataXml *indexData;
+	VertexDataXml *vertexData;
+};
+typedef std::vector<SubMeshXml*> SubMeshXmlList;
+
+/// Ogre XML Mesh
+class MeshXml
+{
+public:
+	MeshXml();
+	~MeshXml();
+
+	/// Releases all memory that this data structure owns.
+	void Reset();
+
+	/// Returns number of subMeshes.
+	size_t NumSubMeshes() const;
+
+	/// Returns submesh for @c index.
+	SubMeshXml *GetSubMesh(uint16_t index) const;
+
+	/// Convert mesh to Assimp scene.
+	void ConvertToAssimpScene(aiScene* dest);
+
+	/// Skeleton reference.
+	std::string skeletonRef;
+
+	/// Skeleton.
+	Skeleton *skeleton;
+
+	/// Vertex data
+	VertexDataXml *sharedVertexData;
+
+	/// Sub meshes.
+	SubMeshXmlList subMeshes;
+};
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
+#endif // AI_OGRESTRUCTS_H_INC

+ 1005 - 0
Source/ThirdParty/Assimp/code/OgreXmlSerializer.cpp

@@ -0,0 +1,1005 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#include "AssimpPCH.h"
+
+#include "OgreXmlSerializer.h"
+#include "OgreBinarySerializer.h"
+#include "OgreParsingUtils.h"
+
+#include "TinyFormatter.h"
+
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
+
+// Define as 1 to get verbose logging.
+#define OGRE_XML_SERIALIZER_DEBUG 0
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error = "")
+{
+	if (!error.empty())
+	{
+		throw DeadlyImportError(error + " in node '" + std::string(reader->getNodeName()) + "' and attribute '" + name + "'");
+	}
+	else
+	{
+		throw DeadlyImportError("Attribute '" + name + "' does not exist in node '" + std::string(reader->getNodeName()) + "'");
+	}
+}
+
+template<> 
+int32_t OgreXmlSerializer::ReadAttribute<int32_t>(const std::string &name) const
+{
+	if (HasAttribute(name.c_str()))
+	{
+		return static_cast<int32_t>(m_reader->getAttributeValueAsInt(name.c_str()));
+	}
+	else
+	{
+		ThrowAttibuteError(m_reader, name);
+		return 0;
+	}
+}
+
+template<> 
+uint32_t OgreXmlSerializer::ReadAttribute<uint32_t>(const std::string &name) const
+{
+	if (HasAttribute(name.c_str()))
+	{
+		/** @note This is hackish. But we are never expecting unsigned values that go outside the
+			int32_t range. Just monitor for negative numbers and kill the import. */	
+		int32_t temp = ReadAttribute<int32_t>(name);
+		if (temp >= 0)
+		{
+			return static_cast<uint32_t>(temp);
+		}
+		else
+		{
+			ThrowAttibuteError(m_reader, name, "Found a negative number value where expecting a uint32_t value");
+		}
+	}
+	else
+	{
+		ThrowAttibuteError(m_reader, name);		
+	}
+	return 0;
+}
+
+template<> 
+uint16_t OgreXmlSerializer::ReadAttribute<uint16_t>(const std::string &name) const
+{
+	if (HasAttribute(name.c_str()))
+	{
+		return static_cast<uint16_t>(ReadAttribute<uint32_t>(name));
+	}
+	else
+	{
+		ThrowAttibuteError(m_reader, name);		
+	}
+	return 0;
+}
+
+template<> 
+float OgreXmlSerializer::ReadAttribute<float>(const std::string &name) const
+{
+	if (HasAttribute(name.c_str()))
+	{
+		return m_reader->getAttributeValueAsFloat(name.c_str());
+	}
+	else
+	{
+		ThrowAttibuteError(m_reader, name);
+		return 0;
+	}
+}
+
+template<> 
+std::string OgreXmlSerializer::ReadAttribute<std::string>(const std::string &name) const
+{
+	const char* value = m_reader->getAttributeValue(name.c_str());
+	if (value)
+	{
+		return std::string(value);
+	}
+	else
+	{
+		ThrowAttibuteError(m_reader, name);
+		return "";
+	}
+}
+
+template<> 
+bool OgreXmlSerializer::ReadAttribute<bool>(const std::string &name) const
+{
+	std::string value = Ogre::ToLower(ReadAttribute<std::string>(name));
+	if (ASSIMP_stricmp(value, "true") == 0)
+	{
+		return true;
+	}
+	else if (ASSIMP_stricmp(value, "false") == 0)
+	{
+		return false;
+	}
+	else
+	{
+		ThrowAttibuteError(m_reader, name, "Boolean value is expected to be 'true' or 'false', encountered '" + value + "'");
+		return false;
+	}
+}
+
+bool OgreXmlSerializer::HasAttribute(const std::string &name) const
+{
+	return (m_reader->getAttributeValue(name.c_str()) != 0);
+}
+
+std::string &OgreXmlSerializer::NextNode()
+{
+	do
+	{
+		if (!m_reader->read())
+		{
+			m_currentNodeName = "";
+			return m_currentNodeName;
+		}
+	}
+	while(m_reader->getNodeType() != irr::io::EXN_ELEMENT);
+
+	CurrentNodeName(true);
+#if (OGRE_XML_SERIALIZER_DEBUG == 1)
+	DefaultLogger::get()->debug("<" + m_currentNodeName + ">");
+#endif
+	return m_currentNodeName;
+}
+
+bool OgreXmlSerializer::CurrentNodeNameEquals(const std::string &name) const
+{
+	return (ASSIMP_stricmp(m_currentNodeName, name) == 0);
+}
+
+std::string OgreXmlSerializer::CurrentNodeName(bool forceRead)
+{
+	if (forceRead)
+		m_currentNodeName = std::string(m_reader->getNodeName());
+	return m_currentNodeName;
+}
+
+std::string &OgreXmlSerializer::SkipCurrentNode()
+{
+#if (OGRE_XML_SERIALIZER_DEBUG == 1)
+	DefaultLogger::get()->debug("Skipping node <" + m_currentNodeName + ">");
+#endif
+
+	for(;;)
+	{
+		if (!m_reader->read())
+		{
+			m_currentNodeName = "";
+			return m_currentNodeName;
+		}
+		if (m_reader->getNodeType() != irr::io::EXN_ELEMENT_END)
+			continue;
+		else if (std::string(m_reader->getNodeName()) == m_currentNodeName)
+			break;
+	}
+	return NextNode();
+}
+
+// Mesh XML constants
+
+// <mesh>
+const std::string nnMesh                = "mesh";
+const std::string nnSharedGeometry      = "sharedgeometry";
+const std::string nnSubMeshes           = "submeshes";
+const std::string nnSubMesh             = "submesh";
+const std::string nnSubMeshNames        = "submeshnames";
+const std::string nnSkeletonLink        = "skeletonlink";
+const std::string nnLOD                 = "levelofdetail";
+const std::string nnExtremes            = "extremes";
+const std::string nnPoses               = "poses";
+const std::string nnAnimations          = "animations";
+
+// <submesh>
+const std::string nnFaces               = "faces";
+const std::string nnFace                = "face";
+const std::string nnGeometry            = "geometry";
+const std::string nnTextures            = "textures";
+
+// <mesh/submesh>
+const std::string nnBoneAssignments     = "boneassignments";
+
+// <sharedgeometry/geometry>
+const std::string nnVertexBuffer        = "vertexbuffer";
+
+// <vertexbuffer>
+const std::string nnVertex              = "vertex";
+const std::string nnPosition            = "position";
+const std::string nnNormal              = "normal";
+const std::string nnTangent             = "tangent";
+const std::string nnBinormal            = "binormal";
+const std::string nnTexCoord            = "texcoord";
+const std::string nnColorDiffuse        = "colour_diffuse";
+const std::string nnColorSpecular       = "colour_specular";
+
+// <boneassignments>
+const std::string nnVertexBoneAssignment = "vertexboneassignment";
+
+// Skeleton XML constants
+
+// <skeleton>
+const std::string nnSkeleton            = "skeleton";
+const std::string nnBones               = "bones";
+const std::string nnBoneHierarchy       = "bonehierarchy";
+const std::string nnAnimationLinks      = "animationlinks";
+
+// <bones>
+const std::string nnBone                = "bone";
+const std::string nnRotation            = "rotation";
+const std::string nnAxis                = "axis";
+const std::string nnScale               = "scale";
+
+// <bonehierarchy>
+const std::string nnBoneParent          = "boneparent";
+
+// <animations>
+const std::string nnAnimation           = "animation";
+const std::string nnTracks              = "tracks";
+
+// <tracks>
+const std::string nnTrack               = "track";
+const std::string nnKeyFrames           = "keyframes";
+const std::string nnKeyFrame            = "keyframe";
+const std::string nnTranslate           = "translate";
+const std::string nnRotate              = "rotate";
+
+// Common XML constants
+
+const std::string anX = "x";
+const std::string anY = "y";
+const std::string anZ = "z";
+
+// Mesh
+
+MeshXml *OgreXmlSerializer::ImportMesh(XmlReader *reader)
+{
+	OgreXmlSerializer serializer(reader);
+
+	MeshXml *mesh = new MeshXml();
+	serializer.ReadMesh(mesh);
+	return mesh;
+}
+
+void OgreXmlSerializer::ReadMesh(MeshXml *mesh)
+{
+	if (NextNode() != nnMesh) {
+		throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <mesh>");
+	}
+
+	DefaultLogger::get()->debug("Reading Mesh");
+
+	NextNode();
+	
+	// Root level nodes
+	while(m_currentNodeName == nnSharedGeometry  ||
+		  m_currentNodeName == nnSubMeshes       ||
+		  m_currentNodeName == nnSkeletonLink    ||
+		  m_currentNodeName == nnBoneAssignments ||
+		  m_currentNodeName == nnLOD             ||
+		  m_currentNodeName == nnSubMeshNames    ||
+		  m_currentNodeName == nnExtremes        ||
+		  m_currentNodeName == nnPoses           ||
+		  m_currentNodeName == nnAnimations)
+	{
+		if (m_currentNodeName == nnSharedGeometry)
+		{
+			mesh->sharedVertexData = new VertexDataXml();
+			ReadGeometry(mesh->sharedVertexData);
+		}
+		else if (m_currentNodeName == nnSubMeshes)
+		{
+			NextNode();
+			while(m_currentNodeName == nnSubMesh) {
+				ReadSubMesh(mesh);
+			}
+		}
+		else if (m_currentNodeName == nnBoneAssignments)
+		{
+			ReadBoneAssignments(mesh->sharedVertexData);
+		}
+		else if (m_currentNodeName == nnSkeletonLink)
+		{
+			mesh->skeletonRef = ReadAttribute<std::string>("name");
+			DefaultLogger::get()->debug("Read skeleton link " + mesh->skeletonRef);
+			NextNode();
+		}
+		// Assimp incompatible/ignored nodes
+		else
+			SkipCurrentNode();
+	}
+}
+
+void OgreXmlSerializer::ReadGeometry(VertexDataXml *dest)
+{
+	dest->count = ReadAttribute<uint32_t>("vertexcount");
+	DefaultLogger::get()->debug(Formatter::format() << "  - Reading geometry of " << dest->count << " vertices");
+
+	NextNode();
+	while(m_currentNodeName == nnVertexBuffer) {
+		ReadGeometryVertexBuffer(dest);
+	}
+}
+
+void OgreXmlSerializer::ReadGeometryVertexBuffer(VertexDataXml *dest)
+{
+	bool positions = (HasAttribute("positions") && ReadAttribute<bool>("positions"));
+	bool normals   = (HasAttribute("normals") && ReadAttribute<bool>("normals"));
+	bool tangents  = (HasAttribute("tangents") && ReadAttribute<bool>("tangents"));
+	uint32_t uvs   = (HasAttribute("texture_coords") ? ReadAttribute<uint32_t>("texture_coords") : 0);
+	
+	// Not having positions is a error only if a previous vertex buffer did not have them.
+	if (!positions && !dest->HasPositions()) {
+		throw DeadlyImportError("Vertex buffer does not contain positions!");
+	}
+
+	if (positions)
+	{
+		DefaultLogger::get()->debug("    - Contains positions");
+		dest->positions.reserve(dest->count);
+	}
+	if (normals)
+	{
+		DefaultLogger::get()->debug("    - Contains normals");
+		dest->normals.reserve(dest->count);
+	}
+	if (tangents)
+	{
+		DefaultLogger::get()->debug("    - Contains tangents");
+		dest->tangents.reserve(dest->count);
+	}
+	if (uvs > 0)
+	{
+		DefaultLogger::get()->debug(Formatter::format() << "    - Contains " << uvs << " texture coords");
+		dest->uvs.resize(uvs);
+		for(size_t i=0, len=dest->uvs.size(); i<len; ++i) {
+			dest->uvs[i].reserve(dest->count);
+		}
+	}
+
+	bool warnBinormal = true;
+	bool warnColorDiffuse = true;
+	bool warnColorSpecular = true;
+
+	NextNode();
+
+	while(m_currentNodeName == nnVertex       ||
+		  m_currentNodeName == nnPosition     ||
+		  m_currentNodeName == nnNormal       ||
+		  m_currentNodeName == nnTangent      ||
+		  m_currentNodeName == nnBinormal     ||
+		  m_currentNodeName == nnTexCoord     ||
+		  m_currentNodeName == nnColorDiffuse ||
+		  m_currentNodeName == nnColorSpecular)
+	{
+		if (m_currentNodeName == nnVertex) {
+			NextNode();
+		}
+
+		/// @todo Implement nnBinormal, nnColorDiffuse and nnColorSpecular
+
+		if (positions && m_currentNodeName == nnPosition)
+		{
+			aiVector3D pos;
+			pos.x = ReadAttribute<float>(anX);
+			pos.y = ReadAttribute<float>(anY);
+			pos.z = ReadAttribute<float>(anZ);
+			dest->positions.push_back(pos);
+		}
+		else if (normals && m_currentNodeName == nnNormal)
+		{
+			aiVector3D normal;
+			normal.x = ReadAttribute<float>(anX);
+			normal.y = ReadAttribute<float>(anY);
+			normal.z = ReadAttribute<float>(anZ);
+			dest->normals.push_back(normal);
+		}
+		else if (tangents && m_currentNodeName == nnTangent)
+		{
+			aiVector3D tangent;
+			tangent.x = ReadAttribute<float>(anX);
+			tangent.y = ReadAttribute<float>(anY);
+			tangent.z = ReadAttribute<float>(anZ);
+			dest->tangents.push_back(tangent);
+		}
+		else if (uvs > 0 && m_currentNodeName == nnTexCoord)
+		{
+			for(size_t i=0, len=dest->uvs.size(); i<len; ++i)
+			{
+				if (m_currentNodeName != nnTexCoord) {
+					throw DeadlyImportError("Vertex buffer declared more UVs than can be found in a vertex");
+				}
+
+				aiVector3D uv;
+				uv.x = ReadAttribute<float>("u");
+				uv.y = (ReadAttribute<float>("v") * -1) + 1; // Flip UV from Ogre to Assimp form
+				dest->uvs[i].push_back(uv);
+
+				NextNode();
+			}
+			// Continue main loop as above already read next node
+			continue;
+		}
+		else
+		{
+			/// @todo Remove this stuff once implemented. We only want to log warnings once per element.
+			bool warn = true;
+			if (m_currentNodeName == nnBinormal)
+			{
+				if (warnBinormal)
+				{
+					warnBinormal = false;
+				}
+				else
+				{
+					warn = false;
+				}
+			}
+			else if (m_currentNodeName == nnColorDiffuse)
+			{
+				if (warnColorDiffuse)
+				{
+					warnColorDiffuse = false;
+				}
+				else
+				{
+					warn = false;
+				}
+			}
+			else if (m_currentNodeName == nnColorSpecular)
+			{
+				if (warnColorSpecular)
+				{
+					warnColorSpecular = false;
+				}
+				else
+				{
+					warn = false;
+				}
+			}
+			if (warn) {
+				DefaultLogger::get()->warn("Vertex buffer attribute read not implemented for element: " + m_currentNodeName);
+			}
+		}
+
+		// Advance
+		NextNode();
+	}
+
+	// Sanity checks
+	if (dest->positions.size() != dest->count) {
+	  throw DeadlyImportError(Formatter::format() << "Read only " << dest->positions.size() << " positions when should have read " << dest->count);
+	}
+	if (normals && dest->normals.size() != dest->count) {
+		throw DeadlyImportError(Formatter::format() << "Read only " << dest->normals.size() << " normals when should have read " << dest->count);
+	}
+	if (tangents && dest->tangents.size() != dest->count) {
+		throw DeadlyImportError(Formatter::format() << "Read only " << dest->tangents.size() << " tangents when should have read " << dest->count);
+	}
+	for(unsigned int i=0; i<dest->uvs.size(); ++i)
+	{
+		if (dest->uvs[i].size() != dest->count) {
+			throw DeadlyImportError(Formatter::format() << "Read only " << dest->uvs[i].size() 
+				<< " uvs for uv index " << i << " when should have read " << dest->count);
+		}
+	}
+}
+
+void OgreXmlSerializer::ReadSubMesh(MeshXml *mesh)
+{
+	static const std::string anMaterial          = "material";
+	static const std::string anUseSharedVertices = "usesharedvertices";
+	static const std::string anCount             = "count";
+	static const std::string anV1                = "v1";
+	static const std::string anV2                = "v2";
+	static const std::string anV3                = "v3";
+	static const std::string anV4                = "v4";
+	
+	SubMeshXml* submesh = new SubMeshXml();
+	
+	if (HasAttribute(anMaterial)) {
+		submesh->materialRef = ReadAttribute<std::string>(anMaterial);
+	}
+	if (HasAttribute(anUseSharedVertices)) {
+		submesh->usesSharedVertexData = ReadAttribute<bool>(anUseSharedVertices);
+	}
+
+	DefaultLogger::get()->debug(Formatter::format() << "Reading SubMesh " << mesh->subMeshes.size());
+	DefaultLogger::get()->debug(Formatter::format() << "  - Material: '" << submesh->materialRef << "'");
+	DefaultLogger::get()->debug(Formatter::format() << "  - Uses shared geometry: " << (submesh->usesSharedVertexData ? "true" : "false"));
+
+	// TODO: maybe we have always just 1 faces and 1 geometry and always in this order. this loop will only work correct, when the order
+	// of faces and geometry changed, and not if we have more than one of one
+	/// @todo Fix above comment with better read logic below
+
+	bool quadWarned = false;
+
+	NextNode();
+	while(m_currentNodeName == nnFaces     ||
+		  m_currentNodeName == nnGeometry  ||
+		  m_currentNodeName == nnTextures  ||
+		  m_currentNodeName == nnBoneAssignments)
+	{
+		if (m_currentNodeName == nnFaces)
+		{
+			submesh->indexData->faceCount = ReadAttribute<uint32_t>(anCount);
+			submesh->indexData->faces.reserve(submesh->indexData->faceCount);
+
+			NextNode();
+			while(m_currentNodeName == nnFace)
+			{
+				aiFace face;
+				face.mNumIndices = 3;
+				face.mIndices = new unsigned int[3];
+				face.mIndices[0] = ReadAttribute<uint32_t>(anV1);
+				face.mIndices[1] = ReadAttribute<uint32_t>(anV2);
+				face.mIndices[2] = ReadAttribute<uint32_t>(anV3);
+
+				/// @todo Support quads if Ogre even supports them in XML (I'm not sure but I doubt it)
+				if (!quadWarned && HasAttribute(anV4)) {
+					DefaultLogger::get()->warn("Submesh <face> has quads with <v4>, only triangles are supported at the moment!");
+					quadWarned = true;
+				}
+
+				submesh->indexData->faces.push_back(face);
+
+				// Advance
+				NextNode();
+			}
+
+			if (submesh->indexData->faces.size() == submesh->indexData->faceCount)
+			{
+				DefaultLogger::get()->debug(Formatter::format() << "  - Faces " << submesh->indexData->faceCount);
+			}
+			else
+			{
+				throw DeadlyImportError(Formatter::format() << "Read only " << submesh->indexData->faces.size() << " faces when should have read " << submesh->indexData->faceCount);
+			}
+		}
+		else if (m_currentNodeName == nnGeometry)
+		{
+			if (submesh->usesSharedVertexData) {
+				throw DeadlyImportError("Found <geometry> in <submesh> when use shared geometry is true. Invalid mesh file.");
+			}
+			
+			submesh->vertexData = new VertexDataXml();
+			ReadGeometry(submesh->vertexData);
+		}
+		else if (m_currentNodeName == nnBoneAssignments)
+		{
+			ReadBoneAssignments(submesh->vertexData);
+		}
+		// Assimp incompatible/ignored nodes
+		else
+			SkipCurrentNode();
+	}
+	
+	submesh->index = mesh->subMeshes.size();
+	mesh->subMeshes.push_back(submesh);
+}
+
+void OgreXmlSerializer::ReadBoneAssignments(VertexDataXml *dest)
+{
+	if (!dest) {
+		throw DeadlyImportError("Cannot read bone assignments, vertex data is null.");
+	}
+
+	static const std::string anVertexIndex = "vertexindex";
+	static const std::string anBoneIndex   = "boneindex";
+	static const std::string anWeight      = "weight";
+
+	std::set<uint32_t> influencedVertices;
+
+	NextNode();
+	while(m_currentNodeName == nnVertexBoneAssignment)
+	{
+		VertexBoneAssignment ba;
+		ba.vertexIndex = ReadAttribute<uint32_t>(anVertexIndex);
+		ba.boneIndex = ReadAttribute<uint16_t>(anBoneIndex);
+		ba.weight = ReadAttribute<float>(anWeight);
+
+		dest->boneAssignments.push_back(ba);
+		influencedVertices.insert(ba.vertexIndex);
+
+		NextNode();
+	}
+
+	/** Normalize bone weights.
+		Some exporters wont care if the sum of all bone weights
+		for a single vertex equals 1 or not, so validate here. */
+	const float epsilon = 0.05f;
+	for(std::set<uint32_t>::const_iterator iter=influencedVertices.begin(), end=influencedVertices.end(); iter != end; ++iter)
+	{
+		const uint32_t vertexIndex = (*iter);
+
+		float sum = 0.0f;
+		for (VertexBoneAssignmentList::const_iterator baIter=dest->boneAssignments.begin(), baEnd=dest->boneAssignments.end(); baIter != baEnd; ++baIter)
+		{
+			if (baIter->vertexIndex == vertexIndex)
+				sum += baIter->weight;
+		}
+		if ((sum < (1.0f - epsilon)) || (sum > (1.0f + epsilon)))
+		{
+			for (VertexBoneAssignmentList::iterator baIter=dest->boneAssignments.begin(), baEnd=dest->boneAssignments.end(); baIter != baEnd; ++baIter)
+			{
+				if (baIter->vertexIndex == vertexIndex)
+					baIter->weight /= sum;
+			}
+		}
+	}
+	
+	DefaultLogger::get()->debug(Formatter::format() << "  - " << dest->boneAssignments.size() << " bone assignments");
+}
+
+// Skeleton
+
+bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh)
+{
+	if (!mesh || mesh->skeletonRef.empty())
+		return false;
+
+	// Highly unusual to see in read world cases but support
+	// XML mesh referencing a binary skeleton file.
+	if (EndsWith(mesh->skeletonRef, ".skeleton", false))
+	{
+		if (OgreBinarySerializer::ImportSkeleton(pIOHandler, mesh))
+			return true;
+
+		/** Last fallback if .skeleton failed to be read. Try reading from
+			.skeleton.xml even if the XML file referenced a binary skeleton.
+			@note This logic was in the previous version and I don't want to break
+			old code that might depends on it. */
+		mesh->skeletonRef = mesh->skeletonRef + ".xml";
+	}
+
+	XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
+	if (!reader.get())
+		return false;
+
+	Skeleton *skeleton = new Skeleton();
+	OgreXmlSerializer serializer(reader.get());
+	serializer.ReadSkeleton(skeleton);
+	mesh->skeleton = skeleton;
+	return true;
+}
+
+bool OgreXmlSerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh)
+{
+	if (!mesh || mesh->skeletonRef.empty())
+		return false;
+
+	XmlReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef);
+	if (!reader.get())
+		return false;
+
+	Skeleton *skeleton = new Skeleton();
+	OgreXmlSerializer serializer(reader.get());
+	serializer.ReadSkeleton(skeleton);
+	mesh->skeleton = skeleton;
+	return true;
+}
+
+XmlReaderPtr OgreXmlSerializer::OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename)
+{
+	if (!EndsWith(filename, ".skeleton.xml", false))
+	{
+		DefaultLogger::get()->error("Imported Mesh is referencing to unsupported '" + filename + "' skeleton file.");
+		return XmlReaderPtr();
+	}
+
+	if (!pIOHandler->Exists(filename))
+	{
+		DefaultLogger::get()->error("Failed to find skeleton file '" + filename + "' that is referenced by imported Mesh.");
+		return XmlReaderPtr();
+	}
+
+	boost::scoped_ptr<IOStream> file(pIOHandler->Open(filename));
+	if (!file.get()) {
+		throw DeadlyImportError("Failed to open skeleton file " + filename);
+	}
+
+	boost::scoped_ptr<CIrrXML_IOStreamReader> stream(new CIrrXML_IOStreamReader(file.get()));
+	XmlReaderPtr reader = XmlReaderPtr(irr::io::createIrrXMLReader(stream.get()));
+	if (!reader.get()) {
+		throw DeadlyImportError("Failed to create XML reader for skeleton file " + filename);
+	}
+	return reader;
+}
+
+void OgreXmlSerializer::ReadSkeleton(Skeleton *skeleton)
+{
+	if (NextNode() != nnSkeleton) {
+		throw DeadlyImportError("Root node is <" + m_currentNodeName + "> expecting <skeleton>");
+	}
+	
+	DefaultLogger::get()->debug("Reading Skeleton");
+	
+	// Optional blend mode from root node
+	if (HasAttribute("blendmode")) {
+		skeleton->blendMode = (ToLower(ReadAttribute<std::string>("blendmode")) == "cumulative" 
+			? Skeleton::ANIMBLEND_CUMULATIVE : Skeleton::ANIMBLEND_AVERAGE);
+	}
+
+	NextNode();
+
+	// Root level nodes
+	while(m_currentNodeName == nnBones         ||
+		  m_currentNodeName == nnBoneHierarchy ||
+		  m_currentNodeName == nnAnimations    ||
+		  m_currentNodeName == nnAnimationLinks)
+	{
+		if (m_currentNodeName == nnBones)
+			ReadBones(skeleton);
+		else if (m_currentNodeName == nnBoneHierarchy)
+			ReadBoneHierarchy(skeleton);
+		else if (m_currentNodeName == nnAnimations)
+			ReadAnimations(skeleton);
+		else
+			SkipCurrentNode();
+	}
+}
+
+void OgreXmlSerializer::ReadAnimations(Skeleton *skeleton)
+{
+	if (skeleton->bones.empty()) {
+		throw DeadlyImportError("Cannot read <animations> for a Skeleton without bones");
+	}
+
+	DefaultLogger::get()->debug("  - Animations");
+	
+	NextNode();
+	while(m_currentNodeName == nnAnimation)
+	{
+		Animation *anim = new Animation(skeleton);
+		anim->name = ReadAttribute<std::string>("name");
+		anim->length = ReadAttribute<float>("length");
+		
+		if (NextNode() != nnTracks) {
+			throw DeadlyImportError(Formatter::format() << "No <tracks> found in <animation> " << anim->name);
+		}
+
+		ReadAnimationTracks(anim);
+		skeleton->animations.push_back(anim);
+
+		DefaultLogger::get()->debug(Formatter::format() << "    " << anim->name << " (" << anim->length << " sec, " << anim->tracks.size() << " tracks)");	
+	}
+}
+
+void OgreXmlSerializer::ReadAnimationTracks(Animation *dest)
+{
+	NextNode();
+	while(m_currentNodeName == nnTrack)
+	{
+		VertexAnimationTrack track;
+		track.type = VertexAnimationTrack::VAT_TRANSFORM;
+		track.boneName = ReadAttribute<std::string>("bone");
+
+		if (NextNode() != nnKeyFrames) {
+			throw DeadlyImportError(Formatter::format() << "No <keyframes> found in <track> " << dest->name);
+		}
+
+		ReadAnimationKeyFrames(dest, &track);
+
+		dest->tracks.push_back(track);
+	}
+}
+
+void OgreXmlSerializer::ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest)
+{
+	const aiVector3D zeroVec(0.f, 0.f, 0.f);
+	
+	NextNode();
+	while(m_currentNodeName == nnKeyFrame)
+	{
+		TransformKeyFrame keyframe;
+		keyframe.timePos = ReadAttribute<float>("time");
+		
+		NextNode();
+		while(m_currentNodeName == nnTranslate || m_currentNodeName == nnRotate || m_currentNodeName == nnScale)
+		{
+			if (m_currentNodeName == nnTranslate)
+			{
+				keyframe.position.x = ReadAttribute<float>(anX);
+				keyframe.position.y = ReadAttribute<float>(anY);
+				keyframe.position.z = ReadAttribute<float>(anZ);
+			}
+			else if (m_currentNodeName == nnRotate)
+			{
+				float angle = ReadAttribute<float>("angle");
+
+				if (NextNode() != nnAxis) {
+					throw DeadlyImportError("No axis specified for keyframe rotation in animation " + anim->name);
+				}
+
+				aiVector3D axis;
+				axis.x = ReadAttribute<float>(anX);
+				axis.y = ReadAttribute<float>(anY);
+				axis.z = ReadAttribute<float>(anZ);
+				if (axis.Equal(zeroVec))
+				{
+					axis.x = 1.0f;
+					if (angle != 0) {
+						DefaultLogger::get()->warn("Found invalid a key frame with a zero rotation axis in animation: " + anim->name);
+					}
+				}
+				keyframe.rotation = aiQuaternion(axis, angle);
+			}
+			else if (m_currentNodeName == nnScale)
+			{
+				keyframe.scale.x = ReadAttribute<float>(anX);
+				keyframe.scale.y = ReadAttribute<float>(anY);
+				keyframe.scale.z = ReadAttribute<float>(anZ);
+			}
+
+			NextNode();
+		}
+
+		dest->transformKeyFrames.push_back(keyframe);
+	}
+}
+
+void OgreXmlSerializer::ReadBoneHierarchy(Skeleton *skeleton)
+{
+	if (skeleton->bones.empty()) {
+		throw DeadlyImportError("Cannot read <bonehierarchy> for a Skeleton without bones");
+	}
+	
+	while(NextNode() == nnBoneParent)
+	{
+		const std::string name = ReadAttribute<std::string>("bone");
+		const std::string parentName = ReadAttribute<std::string>("parent");
+
+		Bone *bone = skeleton->BoneByName(name);
+		Bone *parent = skeleton->BoneByName(parentName);
+
+		if (bone && parent)
+			parent->AddChild(bone);
+		else
+			throw DeadlyImportError("Failed to find bones for parenting: Child " + name + " for parent " + parentName);
+	}
+	
+	// Calculate bone matrices for root bones. Recursively calculates their children.
+	for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
+	{
+		Bone *bone = skeleton->bones[i];
+		if (!bone->IsParented())
+			bone->CalculateWorldMatrixAndDefaultPose(skeleton);
+	}
+}
+
+bool BoneCompare(Bone *a, Bone *b)
+{
+	return (a->id < b->id);
+}
+
+void OgreXmlSerializer::ReadBones(Skeleton *skeleton)
+{
+	DefaultLogger::get()->debug("  - Bones");
+	
+	NextNode();
+	while(m_currentNodeName == nnBone)
+	{
+		Bone *bone = new Bone();
+		bone->id = ReadAttribute<uint16_t>("id");
+		bone->name = ReadAttribute<std::string>("name");
+
+		NextNode();
+		while(m_currentNodeName == nnPosition || 
+			  m_currentNodeName == nnRotation ||
+			  m_currentNodeName == nnScale)
+		{
+			if (m_currentNodeName == nnPosition)
+			{
+				bone->position.x = ReadAttribute<float>(anX);
+				bone->position.y = ReadAttribute<float>(anY);
+				bone->position.z = ReadAttribute<float>(anZ);
+			}
+			else if (m_currentNodeName == nnRotation)
+			{
+				float angle = ReadAttribute<float>("angle");
+
+				if (NextNode() != nnAxis) {
+					throw DeadlyImportError(Formatter::format() << "No axis specified for bone rotation in bone " << bone->id);
+				}
+
+				aiVector3D axis;
+				axis.x = ReadAttribute<float>(anX);
+				axis.y = ReadAttribute<float>(anY);
+				axis.z = ReadAttribute<float>(anZ);
+				
+				bone->rotation = aiQuaternion(axis, angle);
+			}
+			else if (m_currentNodeName == nnScale)
+			{
+				/// @todo Implement taking scale into account in matrix/pose calculations!
+				if (HasAttribute("factor"))
+				{
+					float factor = ReadAttribute<float>("factor");
+					bone->scale.Set(factor, factor, factor);
+				}
+				else
+				{
+					if (HasAttribute(anX))
+						bone->scale.x = ReadAttribute<float>(anX);
+					if (HasAttribute(anY))
+						bone->scale.y = ReadAttribute<float>(anY);
+					if (HasAttribute(anZ))
+						bone->scale.z = ReadAttribute<float>(anZ);
+				}
+			}
+				
+			NextNode();
+		}
+
+		skeleton->bones.push_back(bone);
+	}
+
+	// Order bones by Id
+	std::sort(skeleton->bones.begin(), skeleton->bones.end(), BoneCompare);
+
+	// Validate that bone indexes are not skipped.
+	/** @note Left this from original authors code, but not sure if this is strictly necessary
+		as per the Ogre skeleton spec. It might be more that other (later) code in this imported does not break. */
+	for (size_t i=0, len=skeleton->bones.size(); i<len; ++i)
+	{
+		Bone *b = skeleton->bones[i];
+		DefaultLogger::get()->debug(Formatter::format() << "    " << b->id << " " << b->name);
+
+		if (b->id != static_cast<uint16_t>(i)) {
+			throw DeadlyImportError(Formatter::format() << "Bone ids are not in sequence starting from 0. Missing index " << i);
+		}
+	}
+}
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER

+ 116 - 0
Source/ThirdParty/Assimp/code/OgreXmlSerializer.h

@@ -0,0 +1,116 @@
+/*
+Open Asset Import Library (assimp)
+----------------------------------------------------------------------
+
+Copyright (c) 2006-2012, assimp team
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, 
+with or without modification, are permitted provided that the 
+following conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+*/
+
+#ifndef AI_OGREXMLSERIALIZER_H_INC
+#define AI_OGREXMLSERIALIZER_H_INC
+
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
+
+#include "OgreStructs.h"
+#include "irrXMLWrapper.h"
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+typedef irr::io::IrrXMLReader XmlReader;
+typedef boost::shared_ptr<XmlReader> XmlReaderPtr;
+
+class OgreXmlSerializer
+{
+public:
+	/// Imports mesh and returns the result.
+	/** @note Fatal unrecoverable errors will throw a DeadlyImportError. */
+	static MeshXml *ImportMesh(XmlReader *reader);
+	
+	/// Imports skeleton to @c mesh.
+	/** If mesh does not have a skeleton reference or the skeleton file
+		cannot be found it is not a fatal DeadlyImportError.
+		@return If skeleton import was successful. */
+	static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, MeshXml *mesh);
+	static bool ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *mesh);
+
+private:
+	OgreXmlSerializer(XmlReader *reader) :
+		m_reader(reader)
+	{
+	}
+	
+	static XmlReaderPtr OpenReader(Assimp::IOSystem *pIOHandler, const std::string &filename);
+
+	// Mesh
+	void ReadMesh(MeshXml *mesh);
+	void ReadSubMesh(MeshXml *mesh);
+	
+	void ReadGeometry(VertexDataXml *dest);
+	void ReadGeometryVertexBuffer(VertexDataXml *dest);
+	
+	void ReadBoneAssignments(VertexDataXml *dest);
+	
+	// Skeleton
+	void ReadSkeleton(Skeleton *skeleton);
+	
+	void ReadBones(Skeleton *skeleton);
+	void ReadBoneHierarchy(Skeleton *skeleton);
+	
+	void ReadAnimations(Skeleton *skeleton);
+	void ReadAnimationTracks(Animation *dest);
+	void ReadAnimationKeyFrames(Animation *anim, VertexAnimationTrack *dest);
+
+	template<typename T> 
+	T ReadAttribute(const std::string &name) const;
+	bool HasAttribute(const std::string &name) const;
+	
+	std::string &NextNode();
+	std::string &SkipCurrentNode();
+
+	bool CurrentNodeNameEquals(const std::string &name) const;
+	std::string CurrentNodeName(bool forceRead = false);
+		
+	XmlReader *m_reader;
+	std::string m_currentNodeName;
+};
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
+#endif // AI_OGREXMLSERIALIZER_H_INC

+ 1 - 1
Source/ThirdParty/Assimp/code/OptimizeMeshes.cpp

@@ -74,7 +74,7 @@ bool OptimizeMeshesProcess::IsActive( unsigned int pFlags) const
 	// That's a serious design flaw, consider redesign.
 	// That's a serious design flaw, consider redesign.
 	if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
 	if( 0 != (pFlags & aiProcess_OptimizeMeshes) ) {
 		pts = (0 != (pFlags & aiProcess_SortByPType));
 		pts = (0 != (pFlags & aiProcess_SortByPType));
-		max_verts = (0 != (pFlags & aiProcess_SplitLargeMeshes)) ? 0xdeadbeef : 0;
+		max_verts = (0 != (pFlags & aiProcess_SplitLargeMeshes)) ? 0xdeadbeef : max_verts;
 		return true;
 		return true;
 	}
 	}
 	return false;
 	return false;

+ 5 - 5
Source/ThirdParty/Assimp/code/ParsingUtils.h

@@ -115,7 +115,7 @@ AI_FORCE_INLINE bool SkipSpaces( const char_t** inout)
 }
 }
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-inline bool SkipLine( const char_t* in, const char_t** out)
+AI_FORCE_INLINE bool SkipLine( const char_t* in, const char_t** out)
 {
 {
 	while (*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0')in++;
 	while (*in != (char_t)'\r' && *in != (char_t)'\n' && *in != (char_t)'\0')in++;
 
 
@@ -126,13 +126,13 @@ inline bool SkipLine( const char_t* in, const char_t** out)
 }
 }
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-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>
-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' ||
 	while (*in == (char_t)' ' || *in == (char_t)'\t' ||
 		*in == (char_t)'\r' || *in == (char_t)'\n')in++;
 		*in == (char_t)'\r' || *in == (char_t)'\n')in++;
@@ -141,13 +141,13 @@ inline bool SkipSpacesAndLineEnd( const char_t* in, const char_t** out)
 }
 }
 // ---------------------------------------------------------------------------------
 // ---------------------------------------------------------------------------------
 template <class char_t>
 template <class char_t>
-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>
-inline bool GetNextLine(const char_t*& buffer, char_t out[4096])
+AI_FORCE_INLINE bool GetNextLine(const char_t*& buffer, char_t out[4096])
 {
 {
 	if ((char_t)'\0' == *buffer)return false;
 	if ((char_t)'\0' == *buffer)return false;
 
 

+ 7 - 4
Source/ThirdParty/Assimp/code/PlyParser.cpp

@@ -427,7 +427,7 @@ bool PLY::DOM::SkipComments (const char* pCur,
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut)
+bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut,bool isBinary)
 {
 {
 	ai_assert(NULL != pCur && NULL != pCurOut);
 	ai_assert(NULL != pCur && NULL != pCurOut);
 	DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin");
 	DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin");
@@ -458,7 +458,10 @@ bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut)
 			SkipLine(&pCur);
 			SkipLine(&pCur);
 		}
 		}
 	}
 	}
-	SkipSpacesAndLineEnd(pCur,&pCur);
+	if(!isBinary)
+	{ // it would occur an error, if binary data start with values as space or line end.
+		SkipSpacesAndLineEnd(pCur,&pCur);
+	}
 	*pCurOut = pCur;
 	*pCurOut = pCur;
 
 
 	DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded");
 	DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded");
@@ -527,7 +530,7 @@ bool PLY::DOM::ParseInstanceBinary (const char* pCur,DOM* p_pcOut,bool p_bBE)
 
 
 	DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin");
 	DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin");
 
 
-	if(!p_pcOut->ParseHeader(pCur,&pCur))
+	if(!p_pcOut->ParseHeader(pCur,&pCur,true))
 	{
 	{
 		DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
 		DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure");
 		return false;
 		return false;
@@ -550,7 +553,7 @@ bool PLY::DOM::ParseInstance (const char* pCur,DOM* p_pcOut)
 	DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin");
 	DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin");
 
 
 
 
-	if(!p_pcOut->ParseHeader(pCur,&pCur))
+	if(!p_pcOut->ParseHeader(pCur,&pCur,false))
 	{
 	{
 		DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
 		DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure");
 		return false;
 		return false;

+ 1 - 1
Source/ThirdParty/Assimp/code/PlyParser.h

@@ -434,7 +434,7 @@ private:
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	//! Handle the file header and read all element descriptions
 	//! Handle the file header and read all element descriptions
-	bool ParseHeader (const char* pCur,const char** pCurOut);
+	bool ParseHeader (const char* pCur,const char** pCurOut, bool p_bBE);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	//! Read in all element instance lists
 	//! Read in all element instance lists

+ 12 - 12
Source/ThirdParty/Assimp/code/PostStepRegistry.cpp

@@ -133,6 +133,15 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 	// validated - as RegisterPPStep() does - all dependencies must be given.
 	// validated - as RegisterPPStep() does - all dependencies must be given.
 	// ----------------------------------------------------------------------------
 	// ----------------------------------------------------------------------------
 	out.reserve(25);
 	out.reserve(25);
+#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
+	out.push_back( new MakeLeftHandedProcess());
+#endif
+#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS)
+	out.push_back( new FlipUVsProcess());
+#endif
+#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
+	out.push_back( new FlipWindingOrderProcess());
+#endif
 #if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS)
 #if (!defined ASSIMP_BUILD_NO_REMOVEVC_PROCESS)
 	out.push_back( new RemoveVCProcess());
 	out.push_back( new RemoveVCProcess());
 #endif
 #endif
@@ -145,9 +154,6 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 #if (!defined ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
 #if (!defined ASSIMP_BUILD_NO_OPTIMIZEGRAPH_PROCESS)
 	out.push_back( new OptimizeGraphProcess());
 	out.push_back( new OptimizeGraphProcess());
 #endif
 #endif
-#if (!defined ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS)
-	out.push_back( new OptimizeMeshesProcess());
-#endif
 #if (!defined ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS)
 #if (!defined ASSIMP_BUILD_NO_FINDDEGENERATES_PROCESS)
 	out.push_back( new FindDegeneratesProcess());
 	out.push_back( new FindDegeneratesProcess());
 #endif
 #endif
@@ -169,6 +175,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 #if (!defined ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS)
 #if (!defined ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS)
 	out.push_back( new FindInvalidDataProcess());
 	out.push_back( new FindInvalidDataProcess());
 #endif
 #endif
+#if (!defined ASSIMP_BUILD_NO_OPTIMIZEMESHES_PROCESS)
+	out.push_back( new OptimizeMeshesProcess());
+#endif
 #if (!defined ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
 #if (!defined ASSIMP_BUILD_NO_FIXINFACINGNORMALS_PROCESS)
 	out.push_back( new FixInfacingNormalsProcess());
 	out.push_back( new FixInfacingNormalsProcess());
 #endif
 #endif
@@ -207,15 +216,6 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
 #if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
 #if (!defined ASSIMP_BUILD_NO_SPLITLARGEMESHES_PROCESS)
 	out.push_back( new SplitLargeMeshesProcess_Vertex());
 	out.push_back( new SplitLargeMeshesProcess_Vertex());
 #endif
 #endif
-#if (!defined ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS)
-	out.push_back( new MakeLeftHandedProcess());
-#endif
-#if (!defined ASSIMP_BUILD_NO_FLIPUVS_PROCESS)
-	out.push_back( new FlipUVsProcess());
-#endif
-#if (!defined ASSIMP_BUILD_NO_FLIPWINDINGORDER_PROCESS)
-	out.push_back( new FlipWindingOrderProcess());
-#endif
 #if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS)
 #if (!defined ASSIMP_BUILD_NO_DEBONE_PROCESS)
 	out.push_back( new DeboneProcess());
 	out.push_back( new DeboneProcess());
 #endif
 #endif

+ 12 - 2
Source/ThirdParty/Assimp/code/PretransformVertices.cpp

@@ -57,7 +57,7 @@ using namespace Assimp;
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 // Constructor to be privately used by Importer
 // Constructor to be privately used by Importer
 PretransformVertices::PretransformVertices()
 PretransformVertices::PretransformVertices()
-:	configKeepHierarchy (false)
+:	configKeepHierarchy (false), configNormalize(false), configTransform(false), configTransformation()
 {
 {
 }
 }
 
 
@@ -79,9 +79,13 @@ bool PretransformVertices::IsActive( unsigned int pFlags) const
 // Setup import configuration
 // Setup import configuration
 void PretransformVertices::SetupProperties(const Importer* pImp)
 void PretransformVertices::SetupProperties(const Importer* pImp)
 {
 {
-	// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY and AI_CONFIG_PP_PTV_NORMALIZE
+	// Get the current value of AI_CONFIG_PP_PTV_KEEP_HIERARCHY, AI_CONFIG_PP_PTV_NORMALIZE,
+	// AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION and AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION
 	configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0));
 	configKeepHierarchy = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_KEEP_HIERARCHY,0));
 	configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0));
 	configNormalize = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_NORMALIZE,0));
+	configTransform = (0 != pImp->GetPropertyInteger(AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION,0));
+
+	configTransformation = pImp->GetPropertyMatrix(AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION, aiMatrix4x4());
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -391,6 +395,8 @@ void PretransformVertices::BuildWCSMeshes(std::vector<aiMesh*>& out, aiMesh** in
 				ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
 				ntz->mBones = reinterpret_cast<aiBone**> (&node->mTransformation);
 
 
 				out.push_back(ntz);
 				out.push_back(ntz);
+
+				node->mMeshes[i] = numIn + out.size() - 1;
 			}
 			}
 		}
 		}
 	}
 	}
@@ -437,6 +443,10 @@ void PretransformVertices::Execute( aiScene* pScene)
 	const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
 	const unsigned int iOldAnimationChannels = pScene->mNumAnimations;
 	const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
 	const unsigned int iOldNodes = CountNodes(pScene->mRootNode);
 
 
+	if(configTransform) {
+		pScene->mRootNode->mTransformation = configTransformation;
+	}
+
 	// first compute absolute transformation matrices for all nodes
 	// first compute absolute transformation matrices for all nodes
 	ComputeAbsoluteTransform(pScene->mRootNode);
 	ComputeAbsoluteTransform(pScene->mRootNode);
 
 

+ 6 - 4
Source/ThirdParty/Assimp/code/PretransformVertices.h

@@ -52,11 +52,11 @@ class PretransformVerticesTest;
 namespace Assimp	{
 namespace Assimp	{
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
-/** The PretransformVertices pretransforms all vertices in the nodegraph
+/** The PretransformVertices pre-transforms all vertices in the node tree
  *  and removes the whole graph. The output is a list of meshes, one for
  *  and removes the whole graph. The output is a list of meshes, one for
  *  each material.
  *  each material.
 */
 */
-class PretransformVertices : public BaseProcess
+class ASSIMP_API PretransformVertices : public BaseProcess
 {
 {
 public:
 public:
 
 
@@ -152,8 +152,10 @@ private:
 
 
 
 
 	//! Configuration option: keep scene hierarchy as long as possible
 	//! Configuration option: keep scene hierarchy as long as possible
-	bool configKeepHierarchy, configNormalize;
-
+	bool configKeepHierarchy;
+	bool configNormalize;
+	bool configTransform;
+	aiMatrix4x4 configTransformation;
 };
 };
 
 
 } // end of namespace Assimp
 } // end of namespace Assimp

+ 44 - 57
Source/ThirdParty/Assimp/code/Q3BSPFileData.h

@@ -42,10 +42,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
 #include <vector>
 #include <vector>
 
 
-namespace Assimp
-{
-namespace Q3BSP
-{
+namespace Assimp {
+namespace Q3BSP {
 
 
 static const unsigned int CE_BSP_LIGHTMAPWIDTH = 128;
 static const unsigned int CE_BSP_LIGHTMAPWIDTH = 128;
 static const unsigned int CE_BSP_LIGHTMAPHEIGHT = 128;
 static const unsigned int CE_BSP_LIGHTMAPHEIGHT = 128;
@@ -54,8 +52,7 @@ static const unsigned int CE_BSP_LIGHTMAPSIZE = 128*128*3;	///< = 128( width ) *
 static const int VERION_Q3LEVEL = 46;						///< Supported version.
 static const int VERION_Q3LEVEL = 46;						///< Supported version.
 
 
 ///	Geometric type enumeration
 ///	Geometric type enumeration
-enum Q3BSPGeoType
-{
+enum Q3BSPGeoType {
 	Polygon = 1,
 	Polygon = 1,
 	Patch, 
 	Patch, 
 	TriangleMesh,
 	TriangleMesh,
@@ -63,25 +60,23 @@ enum Q3BSPGeoType
 };
 };
 
 
 ///	Integer vector.
 ///	Integer vector.
-struct ceVec3i 
-{
+struct ceVec3i {
     int x, y, z;
     int x, y, z;
 	ceVec3i(): x( 0 ), y( 0 ), z( 0 ) { /* empty */ }
 	ceVec3i(): x( 0 ), y( 0 ), z( 0 ) { /* empty */ }
 	ceVec3i( int iX, int iY=0, int iZ=0) : x( iX ), y( iY ), z( iZ ) { /* empty */ }
 	ceVec3i( int iX, int iY=0, int iZ=0) : x( iX ), y( iY ), z( iZ ) { /* empty */ }
 };
 };
 
 
-///	Fileheader
-struct sQ3BSPHeader 
-{
-	char strID[ 4 ];	//!< Should be "IBSP"
-	int iVersion;	//!< 46 for standard levels
+///	the file header
+struct sQ3BSPHeader {
+	char strID[ 4 ]; ///< Should be "IBSP"
+    int iVersion;    ///< 46 for standard levels
 };
 };
 
 
-///	Descripes an entry.
+///	Describes an entry.
 struct sQ3BSPLump 
 struct sQ3BSPLump 
 {
 {
-	int iOffset;	///< Offset from startpointer of file
-	int iSize;		///< Size fo part
+	int iOffset;	///< Offset from start pointer of file
+	int iSize;		///< Size of part
 };
 };
 
 
 struct vec2f
 struct vec2f
@@ -108,47 +103,42 @@ struct sQ3BSPVertex
 struct sQ3BSPFace 
 struct sQ3BSPFace 
 {
 {
 	int iTextureID;					///< Index in texture array
 	int iTextureID;					///< Index in texture array
-	int iEffect;					///< Index in effectarray (-1 = no effect)
+	int iEffect;					///< Index in effect array (-1 = no effect)
 	int iType;						///< 1=Polygon, 2=Patch, 3=Mesh, 4=Billboard
 	int iType;						///< 1=Polygon, 2=Patch, 3=Mesh, 4=Billboard
 	int iVertexIndex;				///< Start index of polygon
 	int iVertexIndex;				///< Start index of polygon
 	int iNumOfVerts;				///< Number of vertices
 	int iNumOfVerts;				///< Number of vertices
 	int	iFaceVertexIndex;			///< Index of first mesh vertex
 	int	iFaceVertexIndex;			///< Index of first mesh vertex
-	int iNumOfFaceVerts;			///< Anzahl der Meshvertices
-	int iLightmapID;				///< Index to the lightmap array
-	int iLMapCorner[ 2 ];			///< Die Ecke der Lightmap in der Textur
-	int iLMapSize[ 2 ];				///< Size of the lightmap stored on the texture
-	vec3f vLMapPos;					///< 3D-Ursprung der Lightmap
-	vec3f vLMapVecs[ 2 ];			///< 3D-s-t-Vektoren
-	vec3f vNormal;					///< Polygonnormale
+	int iNumOfFaceVerts;			///< number of mesh vertices
+	int iLightmapID;				///< Index to the light-map array
+	int iLMapCorner[ 2 ];			///< edge of the light-map in texture
+	int iLMapSize[ 2 ];				///< Size of the light-map stored on the texture
+	vec3f vLMapPos;					///< 3D origin of the light-map
+	vec3f vLMapVecs[ 2 ];			///< 3D-s-t-vectors
+	vec3f vNormal;					///< Polygon normals
 	int patchWidth, patchHeight;	///< bezier patch
 	int patchWidth, patchHeight;	///< bezier patch
 };
 };
 
 
 /// A quake3 texture name.
 /// A quake3 texture name.
-struct sQ3BSPTexture 
-{
-	char strName[ 64 ];		///< Name of the texture without extention
+struct sQ3BSPTexture {
+	char strName[ 64 ];		///< Name of the texture without extension
 	int iFlags;				///< Not used
 	int iFlags;				///< Not used
 	int iContents;			///< Not used
 	int iContents;			///< Not used
 };
 };
 
 
-///	A lightmap of the level, size 128 x 128, RGB components.
-struct sQ3BSPLightmap 
-{
+///	A light-map of the level, size 128 x 128, RGB components.
+struct sQ3BSPLightmap {
 	unsigned char bLMapData[ CE_BSP_LIGHTMAPSIZE ];
 	unsigned char bLMapData[ CE_BSP_LIGHTMAPSIZE ];
-	sQ3BSPLightmap() 
-	{	
-		memset(bLMapData, 0, CE_BSP_LIGHTMAPSIZE ); 
+	sQ3BSPLightmap() {	
+		::memset(bLMapData, 0, CE_BSP_LIGHTMAPSIZE ); 
 	}
 	}
 };
 };
 
 
-struct SubPatch
-{
+struct SubPatch {
 	std::vector<size_t> indices;
 	std::vector<size_t> indices;
 	int lightmapID;
 	int lightmapID;
 };
 };
 
 
-enum eLumps 
-{
+enum eLumps {
 	kEntities = 0,
 	kEntities = 0,
 	kTextures,
 	kTextures,
 	kPlanes,
 	kPlanes,
@@ -169,8 +159,7 @@ enum eLumps
 	kMaxLumps
 	kMaxLumps
 };
 };
 
 
-struct Q3BSPModel
-{
+struct Q3BSPModel {
 	std::vector<unsigned char> m_Data;
 	std::vector<unsigned char> m_Data;
 	std::vector<sQ3BSPLump*> m_Lumps;
 	std::vector<sQ3BSPLump*> m_Lumps;
 	std::vector<sQ3BSPVertex*> m_Vertices;
 	std::vector<sQ3BSPVertex*> m_Vertices;
@@ -195,24 +184,22 @@ struct Q3BSPModel
 		// empty
 		// empty
 	}
 	}
 
 
-	~Q3BSPModel()
-	{
-		for ( unsigned int i=0; i<m_Lumps.size(); i++ )
-			if ( NULL != m_Lumps[i] )
-				delete m_Lumps[i];
-		
-		for ( unsigned int i=0; i<m_Vertices.size(); i++ )
-			if ( NULL != m_Vertices[ i ] )
-				delete m_Vertices[ i ];
-		for ( unsigned int i=0; i<m_Faces.size(); i++ )
-			if ( NULL != m_Faces[ i ] )
-				delete m_Faces[ i ];
-		for ( unsigned int i=0; i<m_Textures.size(); i++ )
-			if ( NULL != m_Textures[ i ] )
-				delete m_Textures[ i ];
-		for ( unsigned int i=0; i<m_Lightmaps.size(); i++ )
-			if ( NULL != m_Lightmaps[ i ] )
-				delete m_Lightmaps[ i ];
+	~Q3BSPModel() {
+		for ( unsigned int i=0; i<m_Lumps.size(); i++ ) {
+            delete m_Lumps[ i ];
+        }
+		for ( unsigned int i=0; i<m_Vertices.size(); i++ ) {
+            delete m_Vertices[ i ];
+        }
+		for ( unsigned int i=0; i<m_Faces.size(); i++ ) {
+            delete m_Faces[ i ];
+        }
+		for ( unsigned int i=0; i<m_Textures.size(); i++ ) {
+            delete m_Textures[ i ];
+        }
+		for ( unsigned int i=0; i<m_Lightmaps.size(); i++ ) {
+            delete m_Lightmaps[ i ];
+        }
 
 
 		m_Lumps.clear();
 		m_Lumps.clear();
 		m_Vertices.clear();
 		m_Vertices.clear();

+ 33 - 47
Source/ThirdParty/Assimp/code/Q3BSPFileImporter.cpp

@@ -71,9 +71,14 @@ static const aiImporterDesc desc = {
 	"pk3"
 	"pk3"
 };
 };
 
 
-namespace Assimp
-{
+namespace Assimp {
 
 
+static void getSupportedExtensions(std::vector<std::string> &supportedExtensions) {
+    supportedExtensions.push_back( ".jpg" );
+    supportedExtensions.push_back( ".png" );
+    supportedExtensions.push_back( ".tga" );
+}
+    
 using namespace Q3BSP;
 using namespace Q3BSP;
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -86,7 +91,7 @@ static void createKey( int id1, int id2, std::string &rKey )
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-//	Local function to extract the texture ids from a material keyname.
+//	Local function to extract the texture ids from a material key-name.
 static void extractIds( const std::string &rKey, int &rId1, int &rId2 )
 static void extractIds( const std::string &rKey, int &rId1, int &rId2 )
 {
 {
 	rId1 = -1;
 	rId1 = -1;
@@ -146,24 +151,16 @@ Q3BSPFileImporter::Q3BSPFileImporter() :
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Destructor.
 //	Destructor.
-Q3BSPFileImporter::~Q3BSPFileImporter()
-{
-	// For lint
+Q3BSPFileImporter::~Q3BSPFileImporter() {
 	m_pCurrentMesh = NULL;
 	m_pCurrentMesh = NULL;
 	m_pCurrentFace = NULL;
 	m_pCurrentFace = NULL;
 	
 	
 	// Clear face-to-material map
 	// Clear face-to-material map
-	for ( FaceMap::iterator it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end();
-		++it )
-	{
-		const std::string matName = (*it).first;
-		if ( matName.empty() )
-		{
-			continue;
+    for ( FaceMap::iterator it = m_MaterialLookupMap.begin(); it != m_MaterialLookupMap.end(); ++it ) {
+		const std::string &matName = it->first;
+		if ( !matName.empty() ) {
+            delete it->second;
 		}
 		}
-
-		std::vector<Q3BSP::sQ3BSPFace*> *pCurFaceArray = (*it).second;
-		delete pCurFaceArray;
 	}
 	}
 	m_MaterialLookupMap.clear();
 	m_MaterialLookupMap.clear();
 }
 }
@@ -188,9 +185,9 @@ const aiImporterDesc* Q3BSPFileImporter::GetInfo () const
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Import method.
 //	Import method.
-void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* pScene, IOSystem* /*pIOHandler*/)
+void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* pScene, IOSystem* pIOHandler)
 {
 {
-	Q3BSPZipArchive Archive( rFile );
+	Q3BSPZipArchive Archive( pIOHandler, rFile );
 	if ( !Archive.isOpen() )
 	if ( !Archive.isOpen() )
 	{
 	{
 		throw DeadlyImportError( "Failed to open file " + rFile + "." );
 		throw DeadlyImportError( "Failed to open file " + rFile + "." );
@@ -566,7 +563,7 @@ size_t Q3BSPFileImporter::countFaces( const std::vector<Q3BSP::sQ3BSPFace*> &rAr
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-//	Counts the number of triangles in a Q3-facearray.
+//	Counts the number of triangles in a Q3-face-array.
 size_t Q3BSPFileImporter::countTriangles( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const
 size_t Q3BSPFileImporter::countTriangles( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const
 {
 {
 	size_t numTriangles = 0;
 	size_t numTriangles = 0;
@@ -617,16 +614,11 @@ void Q3BSPFileImporter::createMaterialMap( const Q3BSP::Q3BSPModel *pModel )
 //	Returns the next face.
 //	Returns the next face.
 aiFace *Q3BSPFileImporter::getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx )
 aiFace *Q3BSPFileImporter::getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx )
 {
 {
-	aiFace *pFace = NULL;
-	if ( rFaceIdx < pMesh->mNumFaces )
-	{
+	aiFace *pFace( NULL );
+	if ( rFaceIdx < pMesh->mNumFaces ) {
 		pFace = &pMesh->mFaces[ rFaceIdx ];
 		pFace = &pMesh->mFaces[ rFaceIdx ];
 		rFaceIdx++;
 		rFaceIdx++;
 	}
 	}
-	else
-	{
-		pFace = NULL;
-	}
 
 
 	return pFace;
 	return pFace;
 }
 }
@@ -634,34 +626,30 @@ aiFace *Q3BSPFileImporter::getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx )
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Imports a texture file.
 //	Imports a texture file.
 bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel,
 bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel,
-												 Q3BSP::Q3BSPZipArchive *pArchive, aiScene* /*pScene*/,
-												 aiMaterial *pMatHelper, int textureId )
-{
-	std::vector<std::string> supportedExtensions;
-	supportedExtensions.push_back( ".jpg" );
-	supportedExtensions.push_back( ".png" );
-  supportedExtensions.push_back( ".tga" );
-	if ( NULL == pArchive || NULL == pArchive || NULL == pMatHelper )
-	{
+												 Q3BSP::Q3BSPZipArchive *pArchive, aiScene*,
+												 aiMaterial *pMatHelper, int textureId ) {
+	if ( NULL == pArchive || NULL == pArchive || NULL == pMatHelper ) {
 		return false;
 		return false;
 	}
 	}
 
 
-	if ( textureId < 0 || textureId >= static_cast<int>( pModel->m_Textures.size() ) )
-	{
+	if ( textureId < 0 || textureId >= static_cast<int>( pModel->m_Textures.size() ) ) {
 		return false;
 		return false;
 	}
 	}
 
 
 	bool res = true;
 	bool res = true;
 	sQ3BSPTexture *pTexture = pModel->m_Textures[ textureId ];
 	sQ3BSPTexture *pTexture = pModel->m_Textures[ textureId ];
-	if ( NULL == pTexture )
-		return false;
-
+	if ( !pTexture ) {
+        return false;
+    }
+
+    std::vector<std::string> supportedExtensions;
+    supportedExtensions.push_back( ".jpg" );
+    supportedExtensions.push_back( ".png" );
+    supportedExtensions.push_back( ".tga" );
 	std::string textureName, ext;
 	std::string textureName, ext;
-	if ( expandFile( pArchive, pTexture->strName, supportedExtensions, textureName, ext ) )
-	{
+	if ( expandFile( pArchive, pTexture->strName, supportedExtensions, textureName, ext ) ) {
 		IOStream *pTextureStream = pArchive->Open( textureName.c_str() );
 		IOStream *pTextureStream = pArchive->Open( textureName.c_str() );
-		if ( NULL != pTextureStream )
-		{
+		if ( !pTextureStream ) {
 			size_t texSize = pTextureStream->FileSize();
 			size_t texSize = pTextureStream->FileSize();
 			aiTexture *pTexture = new aiTexture;
 			aiTexture *pTexture = new aiTexture;
 			pTexture->mHeight = 0;
 			pTexture->mHeight = 0;
@@ -685,9 +673,7 @@ bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *pMode
 
 
 			pMatHelper->AddProperty( &name, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
 			pMatHelper->AddProperty( &name, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) );
 			mTextures.push_back( pTexture );
 			mTextures.push_back( pTexture );
-		}
-		else
-		{
+		} else {
 			// If it doesn't exist in the archive, it is probably just a reference to an external file.
 			// If it doesn't exist in the archive, it is probably just a reference to an external file.
 			// We'll leave it up to the user to figure out which extension the file has.
 			// We'll leave it up to the user to figure out which extension the file has.
 			aiString name;
 			aiString name;

+ 213 - 97
Source/ThirdParty/Assimp/code/Q3BSPZipArchive.cpp

@@ -46,23 +46,144 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <algorithm>
 #include <algorithm>
 #include <cassert>
 #include <cassert>
 
 
-namespace Assimp
-{
-namespace Q3BSP
-{
+namespace Assimp {
+namespace Q3BSP {
+
+voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
+	IOSystem* io_system = (IOSystem*) opaque;
+
+	const char* mode_fopen = NULL;
+	if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) {
+		mode_fopen = "rb";
+	} else {
+		if(mode & ZLIB_FILEFUNC_MODE_EXISTING) {
+			mode_fopen = "r+b";
+		} else {
+			if(mode & ZLIB_FILEFUNC_MODE_CREATE) {
+				mode_fopen = "wb";
+			}
+		}
+	}
+
+	return (voidpf) io_system->Open(filename, mode_fopen);
+}
+
+uLong IOSystem2Unzip::read(voidpf opaque, voidpf stream, void* buf, uLong size) {
+	IOStream* io_stream = (IOStream*) stream;
+
+	return io_stream->Read(buf, 1, size);
+}
+
+uLong IOSystem2Unzip::write(voidpf opaque, voidpf stream, const void* buf, uLong size) {
+	IOStream* io_stream = (IOStream*) stream;
+
+	return io_stream->Write(buf, 1, size);
+}
+
+long IOSystem2Unzip::tell(voidpf opaque, voidpf stream) {
+	IOStream* io_stream = (IOStream*) stream;
+
+	return io_stream->Tell();
+}
+
+long IOSystem2Unzip::seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
+	IOStream* io_stream = (IOStream*) stream;
+
+	aiOrigin assimp_origin;
+	switch (origin) {
+		default:
+		case ZLIB_FILEFUNC_SEEK_CUR:
+			assimp_origin = aiOrigin_CUR;
+			break;
+		case ZLIB_FILEFUNC_SEEK_END:
+			assimp_origin = aiOrigin_END;
+			break;
+		case ZLIB_FILEFUNC_SEEK_SET:
+			assimp_origin = aiOrigin_SET;
+			break;
+	}
+
+	return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
+}
+
+int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
+	IOSystem* io_system = (IOSystem*) opaque;
+	IOStream* io_stream = (IOStream*) stream;
+
+	io_system->Close(io_stream);
+
+	return 0;
+}
+
+int IOSystem2Unzip::testerror(voidpf opaque, voidpf stream) {
+	return 0;
+}
+
+zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
+	zlib_filefunc_def mapping;
+
+	mapping.zopen_file = open;
+	mapping.zread_file = read;
+	mapping.zwrite_file = write;
+	mapping.ztell_file = tell;
+	mapping.zseek_file = seek;
+	mapping.zclose_file = close;
+	mapping.zerror_file = testerror;
+	mapping.opaque = (voidpf) pIOHandler;
+
+	return mapping;
+}
+
+// ------------------------------------------------------------------------------------------------
+ZipFile::ZipFile(size_t size) : m_Size(size) {
+	ai_assert(m_Size != 0);
+
+	m_Buffer = std::malloc(m_Size);
+}
+	
+ZipFile::~ZipFile() {
+	std::free(m_Buffer);
+	m_Buffer = NULL;
+}
+
+size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
+	const size_t size = pSize * pCount;
+	assert(size <= m_Size);
+			
+	std::memcpy(pvBuffer, m_Buffer, size);
+
+	return size;
+}
+
+size_t ZipFile::Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
+	return 0;
+}
+
+size_t ZipFile::FileSize() const {
+	return m_Size;
+}
+
+aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
+	return aiReturn_FAILURE;
+}
+
+size_t ZipFile::Tell() const {
+	return 0;
+}
+
+void ZipFile::Flush() {
+	// empty
+}
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Constructor.
 //	Constructor.
-Q3BSPZipArchive::Q3BSPZipArchive( const std::string& rFile ) :
-	m_ZipFileHandle( NULL ),
-	m_FileList(),
-	m_bDirty( true )
-{
-	if ( !rFile.empty() )
-	{
-		m_ZipFileHandle = unzOpen( rFile.c_str() );
-		if ( NULL != m_ZipFileHandle )
-		{
+Q3BSPZipArchive::Q3BSPZipArchive(IOSystem* pIOHandler, const std::string& rFile) : m_ZipFileHandle(NULL), m_ArchiveMap() {
+	if (! rFile.empty()) {
+		zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
+
+		m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
+
+		if(m_ZipFileHandle != NULL) {
 			mapArchive();
 			mapArchive();
 		}
 		}
 	}
 	}
@@ -70,127 +191,122 @@ Q3BSPZipArchive::Q3BSPZipArchive( const std::string& rFile ) :
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Destructor.
 //	Destructor.
-Q3BSPZipArchive::~Q3BSPZipArchive()
-{
-	if ( NULL != m_ZipFileHandle )
-	{
-		unzClose( m_ZipFileHandle );
+Q3BSPZipArchive::~Q3BSPZipArchive() {
+	for( std::map<std::string, ZipFile*>::iterator it(m_ArchiveMap.begin()), end(m_ArchiveMap.end()); it != end; ++it ) {
+		delete it->second;
+	}
+	m_ArchiveMap.clear();
+
+	if(m_ZipFileHandle != NULL) {
+		unzClose(m_ZipFileHandle);
+		m_ZipFileHandle = NULL;
 	}
 	}
-	m_ZipFileHandle = NULL;
-	m_FileList.clear();
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Returns true, if the archive is already open.
 //	Returns true, if the archive is already open.
-bool Q3BSPZipArchive::isOpen() const
-{
-	return ( NULL != m_ZipFileHandle );
+bool Q3BSPZipArchive::isOpen() const {
+	return (m_ZipFileHandle != NULL);
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Returns true, if the filename is part of the archive.
 //	Returns true, if the filename is part of the archive.
-bool Q3BSPZipArchive::Exists( const char* pFile ) const
-{
-	ai_assert( NULL != pFile );
-	if ( NULL == pFile )
-	{
-		return false;
-	}
+bool Q3BSPZipArchive::Exists(const char* pFile) const {
+	ai_assert(pFile != NULL);
+
+	bool exist = false;
+
+	if (pFile != NULL) {
+		std::string rFile(pFile);
+		std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile);
 
 
-	std::string rFile( pFile );
-	std::vector<std::string>::const_iterator it = std::find( m_FileList.begin(), m_FileList.end(), rFile );
-	if ( m_FileList.end() == it )
-	{
-		return false;
+		if(it != m_ArchiveMap.end()) {
+			exist = true;
+		}
 	}
 	}
 
 
-	return true;
+	return exist;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Returns the separator delimiter.
 //	Returns the separator delimiter.
-char Q3BSPZipArchive::getOsSeparator() const
-{
+char Q3BSPZipArchive::getOsSeparator() const {
+#ifndef _WIN32
 	return '/';
 	return '/';
+#else
+	return '\\';
+#endif
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Opens a file, which is part of the archive.
 //	Opens a file, which is part of the archive.
-IOStream *Q3BSPZipArchive::Open( const char* pFile, const char* /*pMode*/ )
-{
-	ai_assert( NULL != pFile );
+IOStream *Q3BSPZipArchive::Open(const char* pFile, const char* /*pMode*/) {
+	ai_assert(pFile != NULL);
+
+	IOStream* result = NULL;
 
 
-	std::string rItem( pFile );
-	std::vector<std::string>::iterator it = std::find( m_FileList.begin(), m_FileList.end(), rItem );
-	if ( m_FileList.end() == it )
-		return NULL;
+	std::map<std::string, ZipFile*>::iterator it = m_ArchiveMap.find(pFile);
 
 
-	ZipFile *pZipFile = new ZipFile( *it, m_ZipFileHandle );
-	m_ArchiveMap[ rItem ] = pZipFile;
+	if(it != m_ArchiveMap.end()) {
+		result = (IOStream*) it->second;
+	}
 
 
-	return pZipFile;
+	return result;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Close a filestream.
 //	Close a filestream.
-void Q3BSPZipArchive::Close( IOStream *pFile )
-{
-	ai_assert( NULL != pFile );
-
-	std::map<std::string, IOStream*>::iterator it;
-	for ( it = m_ArchiveMap.begin(); it != m_ArchiveMap.end(); ++it )
-	{
-		if ( (*it).second == pFile )
-		{
-			ZipFile *pZipFile = reinterpret_cast<ZipFile*>( (*it).second ); 
-			delete pZipFile;
-			m_ArchiveMap.erase( it );
-			break;
-		}
-	}
+void Q3BSPZipArchive::Close(IOStream *pFile) {
+	ai_assert(pFile != NULL);
+
+	// We don't do anything in case the file would be opened again in the future
 }
 }
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Returns the file-list of the archive.
 //	Returns the file-list of the archive.
-void Q3BSPZipArchive::getFileList( std::vector<std::string> &rFileList )
-{
-	rFileList = m_FileList;
+void Q3BSPZipArchive::getFileList(std::vector<std::string> &rFileList) {
+	rFileList.clear();
+
+	for(std::map<std::string, ZipFile*>::iterator it(m_ArchiveMap.begin()), end(m_ArchiveMap.end()); it != end; ++it) {
+		rFileList.push_back(it->first);
+	}
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 //	Maps the archive content.
 //	Maps the archive content.
-bool Q3BSPZipArchive::mapArchive()
-{
-	if ( NULL == m_ZipFileHandle )
-		return false;
-
-	if ( !m_bDirty )
-		return true;
-
-	if ( !m_FileList.empty() )
-		m_FileList.resize( 0 );
-
-	//	At first ensure file is already open
-	if ( UNZ_OK == unzGoToFirstFile( m_ZipFileHandle ) ) 
-	{
-		char filename[ FileNameSize ];
-		unzGetCurrentFileInfo( m_ZipFileHandle, NULL, filename, FileNameSize, NULL, 0, NULL, 0 );
-		m_FileList.push_back( filename );
-		unzCloseCurrentFile( m_ZipFileHandle );
-			
-		// Loop over all files
-		while ( unzGoToNextFile( m_ZipFileHandle ) != UNZ_END_OF_LIST_OF_FILE )  
-		{
-			char filename[ FileNameSize ];
-			unzGetCurrentFileInfo( m_ZipFileHandle, NULL, filename, FileNameSize, NULL, 0, NULL, 0 );
-			m_FileList.push_back( filename );
-			unzCloseCurrentFile( m_ZipFileHandle );
+bool Q3BSPZipArchive::mapArchive() {
+	bool success = false;
+
+	if(m_ZipFileHandle != NULL) {
+		if(m_ArchiveMap.empty()) {
+			//	At first ensure file is already open
+			if(unzGoToFirstFile(m_ZipFileHandle) == UNZ_OK) {	
+				// Loop over all files  
+				do {
+					char filename[FileNameSize];
+					unz_file_info fileInfo;
+
+					if(unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, NULL, 0, NULL, 0) == UNZ_OK) {
+						// The file has EXACTLY the size of uncompressed_size. In C
+						// you need to mark the last character with '\0', so add
+						// another character
+						if(unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) {
+							std::pair<std::map<std::string, ZipFile*>::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size)));
+
+							if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) {
+								if(unzCloseCurrentFile(m_ZipFileHandle) == UNZ_OK) {
+									// Nothing to do anymore...
+								}
+							}
+						}
+					}
+				} while(unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
+			}
 		}
 		}
+
+		success = true;
 	}
 	}
-	
-	std::sort( m_FileList.begin(), m_FileList.end() );
-	m_bDirty = false;
 
 
-	return true;
+	return success;
 }
 }
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 89 - 108
Source/ThirdParty/Assimp/code/Q3BSPZipArchive.h

@@ -48,10 +48,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <map>
 #include <map>
 #include <cassert>
 #include <cassert>
 
 
-namespace Assimp
-{
-namespace Q3BSP
-{
+namespace Assimp {
+namespace Q3BSP {
+
+// ------------------------------------------------------------------------------------------------
+///	\class		IOSystem2Unzip
+///	\ingroup	Assimp::Q3BSP
+///
+///	\brief
+// ------------------------------------------------------------------------------------------------
+class IOSystem2Unzip {
+
+	public:
+
+		static voidpf open(voidpf opaque, const char* filename, int mode);
+
+		static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
+
+		static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
+
+		static long tell(voidpf opaque, voidpf stream);
+
+		static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
+
+		static int close(voidpf opaque, voidpf stream);
+
+		static int testerror(voidpf opaque, voidpf stream);
+
+		static zlib_filefunc_def get(IOSystem* pIOHandler);
+};
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 ///	\class		ZipFile
 ///	\class		ZipFile
@@ -59,88 +84,33 @@ namespace Q3BSP
 ///
 ///
 ///	\brief
 ///	\brief
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-class ZipFile : public IOStream
-{
-public:
-	ZipFile( const std::string &rFileName, unzFile zipFile ) :
-		m_Name( rFileName ),
-		m_zipFile( zipFile )
-	{
-		ai_assert( NULL != m_zipFile );
-	}
+class ZipFile : public IOStream {
+
+	friend class Q3BSPZipArchive;
+
+	public:
+
+		ZipFile(size_t size);
 	
 	
-	~ZipFile()
-	{
-		m_zipFile = NULL;
-	}
-
-	size_t Read(void* pvBuffer, size_t pSize, size_t pCount )
-	{
-		size_t bytes_read = 0;
-		if ( NULL == m_zipFile )
-			return bytes_read;
-		
-		// search file and place file pointer there
-		if ( unzLocateFile( m_zipFile, m_Name.c_str(), 0 ) == UNZ_OK )
-		{
-			// get file size, etc.
-			unz_file_info fileInfo;
-			unzGetCurrentFileInfo( m_zipFile, &fileInfo, 0, 0, 0, 0, 0, 0 );
-			const size_t size = pSize * pCount;
-			assert( size <= fileInfo.uncompressed_size );
-			
-			// The file has EXACTLY the size of uncompressed_size. In C
-			// you need to mark the last character with '\0', so add 
-			// another character
-			unzOpenCurrentFile( m_zipFile );
-			const int ret = unzReadCurrentFile( m_zipFile, pvBuffer, fileInfo.uncompressed_size);
-			size_t filesize = fileInfo.uncompressed_size;
-			if ( ret < 0 || size_t(ret) != filesize )
-			{
-				return 0;
-			}
-			bytes_read = ret;
-			unzCloseCurrentFile( m_zipFile );
-		}
-		return bytes_read;
-	}
-
-	size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/)
-	{
-		return 0;
-	}
-
-	size_t FileSize() const
-	{
-		if ( NULL == m_zipFile )
-			return 0;
-		if ( unzLocateFile( m_zipFile, m_Name.c_str(), 0 ) == UNZ_OK ) 
-		{
-			unz_file_info fileInfo;
-			unzGetCurrentFileInfo( m_zipFile, &fileInfo, 0, 0, 0, 0, 0, 0 );
-			return fileInfo.uncompressed_size;
-		}
-		return 0;
-	}
-
-	aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/)
-	{
-		return aiReturn_FAILURE;
-	}
-
-    size_t Tell() const
-	{
-		return 0;
-	}
-
-	void Flush()
-	{
-		// empty
-	}
-
-private:
-	std::string m_Name;
-	unzFile m_zipFile;
+		~ZipFile();
+
+		size_t Read(void* pvBuffer, size_t pSize, size_t pCount );
+
+		size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/);
+
+		size_t FileSize() const;
+
+		aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/);
+
+		size_t Tell() const;
+
+		void Flush();
+
+	private:
+
+		void* m_Buffer;
+
+		size_t m_Size;
 };
 };
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
@@ -150,29 +120,40 @@ private:
 ///	\brief	IMplements a zip archive like the WinZip archives. Will be also used to import data 
 ///	\brief	IMplements a zip archive like the WinZip archives. Will be also used to import data 
 ///	from a P3K archive ( Quake level format ).
 ///	from a P3K archive ( Quake level format ).
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
-class Q3BSPZipArchive : public Assimp::IOSystem
-{
-public:
-	static const unsigned int FileNameSize = 256;
-
-public:
-	Q3BSPZipArchive( const std::string & rFile );
-	~Q3BSPZipArchive();
-	bool Exists( const char* pFile) const;
-	char getOsSeparator() const;
-	IOStream* Open(const char* pFile, const char* pMode = "rb");
-	void Close( IOStream* pFile);
-	bool isOpen() const;
-	void getFileList( std::vector<std::string> &rFileList );
-
-private:
-	bool mapArchive();
-
-private:
-	unzFile m_ZipFileHandle;
-	std::map<std::string, IOStream*> m_ArchiveMap;
-	std::vector<std::string> m_FileList;
-	bool m_bDirty;
+class Q3BSPZipArchive : public Assimp::IOSystem {
+
+	public:
+
+		static const unsigned int FileNameSize = 256;
+
+	public:
+
+		Q3BSPZipArchive(IOSystem* pIOHandler, const std::string & rFile);
+
+		~Q3BSPZipArchive();
+
+		bool Exists(const char* pFile) const;
+
+		char getOsSeparator() const;
+
+		IOStream* Open(const char* pFile, const char* pMode = "rb");
+
+		void Close(IOStream* pFile);
+
+		bool isOpen() const;
+
+		void getFileList(std::vector<std::string> &rFileList);
+
+	private:
+
+		bool mapArchive();
+
+	private:
+
+		unzFile m_ZipFileHandle;
+
+		std::map<std::string, ZipFile*> m_ArchiveMap;
+
 };
 };
 
 
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------

+ 1 - 1
Source/ThirdParty/Assimp/code/RemoveComments.h

@@ -55,7 +55,7 @@ namespace Assimp	{
  *  to those in C or C++ so this code has been moved to a separate
  *  to those in C or C++ so this code has been moved to a separate
  *  module.
  *  module.
  */
  */
-class CommentRemover
+class ASSIMP_API CommentRemover
 {
 {
 	// class cannot be instanced
 	// class cannot be instanced
 	CommentRemover() {}
 	CommentRemover() {}

+ 23 - 15
Source/ThirdParty/Assimp/code/RemoveRedundantMaterials.cpp

@@ -86,7 +86,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 {
 {
 	DefaultLogger::get()->debug("RemoveRedundantMatsProcess begin");
 	DefaultLogger::get()->debug("RemoveRedundantMatsProcess begin");
 
 
-	unsigned int iCnt = 0, unreferenced = 0;
+	unsigned int redundantRemoved = 0, unreferencedRemoved = 0;
 	if (pScene->mNumMaterials)
 	if (pScene->mNumMaterials)
 	{
 	{
 		// Find out which materials are referenced by meshes
 		// Find out which materials are referenced by meshes
@@ -125,9 +125,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 			}
 			}
 		}
 		}
 
 
-
 		// TODO: reimplement this algorithm to work in-place
 		// TODO: reimplement this algorithm to work in-place
-
 		unsigned int* aiMappingTable = new unsigned int[pScene->mNumMaterials];
 		unsigned int* aiMappingTable = new unsigned int[pScene->mNumMaterials];
 		unsigned int iNewNum = 0;
 		unsigned int iNewNum = 0;
 
 
@@ -139,36 +137,42 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 		aiHashes = new uint32_t[pScene->mNumMaterials];
 		aiHashes = new uint32_t[pScene->mNumMaterials];
 		for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
 		for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
 		{
 		{
-			// if the material is not referenced ... remove it
-			if (!abReferenced[i])	{
-				++unreferenced;
+			// No mesh is referencing this material, remove it.
+			if (!abReferenced[i]) {
+				++unreferencedRemoved;
+				delete pScene->mMaterials[i];
 				continue;
 				continue;
 			}
 			}
 
 
+			// Check all previously mapped materials for a matching hash.
+			// On a match we can delete this material and just make it ref to the same index.
 			uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
 			uint32_t me = aiHashes[i] = ComputeMaterialHash(pScene->mMaterials[i]);
 			for (unsigned int a = 0; a < i;++a)
 			for (unsigned int a = 0; a < i;++a)
 			{
 			{
 				if (abReferenced[a] && me == aiHashes[a]) {
 				if (abReferenced[a] && me == aiHashes[a]) {
-					++iCnt;
+					++redundantRemoved;
 					me = 0;
 					me = 0;
 					aiMappingTable[i] = aiMappingTable[a];
 					aiMappingTable[i] = aiMappingTable[a];
 					delete pScene->mMaterials[i];
 					delete pScene->mMaterials[i];
 					break;
 					break;
 				}
 				}
 			}
 			}
+			// This is a new material that is referenced, add to the map.
 			if (me)	{
 			if (me)	{
 				aiMappingTable[i] = iNewNum++;
 				aiMappingTable[i] = iNewNum++;
 			}
 			}
 		}
 		}
-		if (iCnt)	{
-			// build an output material list
+		// If the new material count differs from the original,
+		// we need to rebuild the material list and remap mesh material indexes.
+		if (iNewNum != pScene->mNumMaterials) {
 			aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
 			aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
 			::memset(ppcMaterials,0,sizeof(void*)*iNewNum); 
 			::memset(ppcMaterials,0,sizeof(void*)*iNewNum); 
 			for (unsigned int p = 0; p < pScene->mNumMaterials;++p)
 			for (unsigned int p = 0; p < pScene->mNumMaterials;++p)
 			{
 			{
 				// if the material is not referenced ... remove it
 				// if the material is not referenced ... remove it
-				if (!abReferenced[p])
+				if (!abReferenced[p]) {
 					continue;
 					continue;
+				}
 
 
 				// generate new names for all modified materials
 				// generate new names for all modified materials
 				const unsigned int idx = aiMappingTable[p]; 
 				const unsigned int idx = aiMappingTable[p]; 
@@ -178,10 +182,11 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 					sz.length = ::sprintf(sz.data,"JoinedMaterial_#%i",p);
 					sz.length = ::sprintf(sz.data,"JoinedMaterial_#%i",p);
 					((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
 					((aiMaterial*)ppcMaterials[idx])->AddProperty(&sz,AI_MATKEY_NAME);
 				}
 				}
-				else ppcMaterials[idx] = pScene->mMaterials[p];
+				else
+					ppcMaterials[idx] = pScene->mMaterials[p];
 			}
 			}
 			// update all material indices
 			// update all material indices
-			for (unsigned int p = 0; p < pScene->mNumMeshes;++p)	{
+			for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
 				aiMesh* mesh = pScene->mMeshes[p];
 				aiMesh* mesh = pScene->mMeshes[p];
 				mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
 				mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
 			}
 			}
@@ -194,12 +199,15 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
 		delete[] aiHashes;
 		delete[] aiHashes;
 		delete[] aiMappingTable;
 		delete[] aiMappingTable;
 	}
 	}
-	if (!iCnt)DefaultLogger::get()->debug("RemoveRedundantMatsProcess finished ");
+	if (redundantRemoved == 0 && unreferencedRemoved == 0)
+	{
+		DefaultLogger::get()->debug("RemoveRedundantMatsProcess finished ");
+	}
 	else 
 	else 
 	{
 	{
 		char szBuffer[128]; // should be sufficiently large
 		char szBuffer[128]; // should be sufficiently large
-		::sprintf(szBuffer,"RemoveRedundantMatsProcess finished. %i redundant and %i unused materials",
-			iCnt,unreferenced);
+		::sprintf(szBuffer,"RemoveRedundantMatsProcess finished. Removed %i redundant and %i unused materials.",
+			redundantRemoved,unreferencedRemoved);
 		DefaultLogger::get()->info(szBuffer);
 		DefaultLogger::get()->info(szBuffer);
 	}
 	}
 }
 }

+ 5 - 3
Source/ThirdParty/Assimp/code/RemoveRedundantMaterials.h

@@ -51,14 +51,16 @@ class RemoveRedundantMatsTest;
 namespace Assimp	{
 namespace Assimp	{
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
-/** RemoveRedundantMatsProcess: Postprocessing steo to remove redundant 
+/** RemoveRedundantMatsProcess: Post-processing step to remove redundant 
  *  materials from the imported scene.
  *  materials from the imported scene.
  */
  */
-class RemoveRedundantMatsProcess : public BaseProcess
+class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess
 {
 {
 public:
 public:
-
+    /// The default class constructor.
 	RemoveRedundantMatsProcess();
 	RemoveRedundantMatsProcess();
+
+    /// The class destructor.
 	~RemoveRedundantMatsProcess();
 	~RemoveRedundantMatsProcess();
 
 
 public:
 public:

+ 9 - 4
Source/ThirdParty/Assimp/code/RemoveVCProcess.h

@@ -46,17 +46,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include "../include/assimp/mesh.h"
 #include "../include/assimp/mesh.h"
 
 
 class RemoveVCProcessTest;
 class RemoveVCProcessTest;
-namespace Assimp	{
+
+namespace Assimp {
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** RemoveVCProcess: Class to exclude specific parts of the data structure
 /** RemoveVCProcess: Class to exclude specific parts of the data structure
  *  from further processing by removing them,
  *  from further processing by removing them,
 */
 */
-class RemoveVCProcess : public BaseProcess
+class ASSIMP_API RemoveVCProcess : public BaseProcess
 {
 {
 public:
 public:
-
+    /// The default class constructor.
 	RemoveVCProcess();
 	RemoveVCProcess();
+
+    /// The class destructor.
 	~RemoveVCProcess();
 	~RemoveVCProcess();
 
 
 public:
 public:
@@ -85,7 +88,7 @@ public:
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Manually setup the configuration flags for the step
 	/** Manually setup the configuration flags for the step
 	 *
 	 *
-	 *  @param Bitwise combintion of the #aiComponent enumerated values.
+	 *  @param Bitwise combination of the #aiComponent enumerated values.
 	*/
 	*/
 	void SetDeleteFlags(unsigned int f)	
 	void SetDeleteFlags(unsigned int f)	
 	{
 	{
@@ -113,6 +116,8 @@ private:
 	aiScene* mScene;
 	aiScene* mScene;
 };
 };
 
 
+// ---------------------------------------------------------------------------
+
 } // end of namespace Assimp
 } // end of namespace Assimp
 
 
 #endif // !!AI_REMOVEVCPROCESS_H_INCLUDED
 #endif // !!AI_REMOVEVCPROCESS_H_INCLUDED

+ 13 - 13
Source/ThirdParty/Assimp/code/STEPFile.h

@@ -192,19 +192,19 @@ namespace STEP {
 			}
 			}
 
 
 			// utilities to deal with SELECT entities, which currently lack automatic
 			// utilities to deal with SELECT entities, which currently lack automatic
-			// conversion support.
-			template <typename T>
-			const T& ResolveSelect(const DB& db) const {
-				return Couple<T>(db).MustGetObject(To<EXPRESS::ENTITY>())->template To<T>();
-			}
-
-			template <typename T>
-			const T* ResolveSelectPtr(const DB& db) const {
-				const EXPRESS::ENTITY* e = ToPtr<EXPRESS::ENTITY>();
-				return e?Couple<T>(db).MustGetObject(*e)->template ToPtr<T>():(const T*)0;
-			}
-
-		public:
+			// conversion support.
+			template <typename T>
+			const T& ResolveSelect(const DB& db) const {
+				return Couple<T>(db).MustGetObject(To<EXPRESS::ENTITY>())->template To<T>();
+			}
+
+			template <typename T>
+			const T* ResolveSelectPtr(const DB& db) const {
+				const EXPRESS::ENTITY* e = ToPtr<EXPRESS::ENTITY>();
+				return e?Couple<T>(db).MustGetObject(*e)->template ToPtr<T>():(const T*)0;
+			}
+
+		public:
 
 
 			/** parse a variable from a string and set 'inout' to the character 
 			/** parse a variable from a string and set 'inout' to the character 
 			 *  behind the last consumed character. An optional schema enables,
 			 *  behind the last consumed character. An optional schema enables,

+ 4 - 18
Source/ThirdParty/Assimp/code/STEPFileReader.cpp

@@ -175,7 +175,7 @@ bool IsEntityDef(const std::string& snext)
 			if (*it == '=') {
 			if (*it == '=') {
 				return true;
 				return true;
 			}
 			}
-			if (*it < '0' || *it > '9') {
+			if ((*it < '0' || *it > '9') && *it != ' ') {
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -197,16 +197,17 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 
 
 	const DB::ObjectMap& map = db.GetObjects();
 	const DB::ObjectMap& map = db.GetObjects();
 	LineSplitter& splitter = db.GetSplitter();
 	LineSplitter& splitter = db.GetSplitter();
+	
 	while (splitter) {
 	while (splitter) {
 		bool has_next = false;
 		bool has_next = false;
 		std::string s = *splitter;
 		std::string s = *splitter;
 		if (s == "ENDSEC;") {
 		if (s == "ENDSEC;") {
 			break;
 			break;
 		}
 		}
+		s.erase(std::remove(s.begin(), s.end(), ' '), s.end());
 
 
 		// want one-based line numbers for human readers, so +1
 		// want one-based line numbers for human readers, so +1
 		const uint64_t line = splitter.get_index()+1;
 		const uint64_t line = splitter.get_index()+1;
-
 		// LineSplitter already ignores empty lines
 		// LineSplitter already ignores empty lines
 		ai_assert(s.length());
 		ai_assert(s.length());
 		if (s[0] != '#') {
 		if (s[0] != '#') {
@@ -214,12 +215,10 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 			++splitter;
 			++splitter;
 			continue;
 			continue;
 		}
 		}
-
 		// ---
 		// ---
 		// extract id, entity class name and argument string,
 		// extract id, entity class name and argument string,
 		// but don't create the actual object yet. 
 		// but don't create the actual object yet. 
 		// ---
 		// ---
-
 		const std::string::size_type n0 = s.find_first_of('=');
 		const std::string::size_type n0 = s.find_first_of('=');
 		if (n0 == std::string::npos) {
 		if (n0 == std::string::npos) {
 			DefaultLogger::get()->warn(AddLineNumber("expected token \'=\'",line));
 			DefaultLogger::get()->warn(AddLineNumber("expected token \'=\'",line));
@@ -233,13 +232,10 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 			++splitter;
 			++splitter;
 			continue;
 			continue;
 		}
 		}
-
 		std::string::size_type n1 = s.find_first_of('(',n0);
 		std::string::size_type n1 = s.find_first_of('(',n0);
 		if (n1 == std::string::npos) {
 		if (n1 == std::string::npos) {
-
 			has_next = true;
 			has_next = true;
 			bool ok = false;
 			bool ok = false;
-
 			for( ++splitter; splitter; ++splitter) {
 			for( ++splitter; splitter; ++splitter) {
 				const std::string& snext = *splitter;
 				const std::string& snext = *splitter;
 				if (snext.empty()) {
 				if (snext.empty()) {
@@ -269,13 +265,11 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 			
 			
 			has_next = true;
 			has_next = true;
 			bool ok = false;
 			bool ok = false;
-
 			for( ++splitter; splitter; ++splitter) {
 			for( ++splitter; splitter; ++splitter) {
 				const std::string& snext = *splitter;
 				const std::string& snext = *splitter;
 				if (snext.empty()) {
 				if (snext.empty()) {
 					continue;
 					continue;
 				}
 				}
-
 				// the next line doesn't start an entity, so maybe it is 
 				// the next line doesn't start an entity, so maybe it is 
 				// just a continuation  for this line, keep going
 				// just a continuation  for this line, keep going
 				if (!IsEntityDef(snext)) {
 				if (!IsEntityDef(snext)) {
@@ -287,7 +281,6 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 					break;
 					break;
 				}
 				}
 			}
 			}
-
 			if(!ok) {
 			if(!ok) {
 				DefaultLogger::get()->warn(AddLineNumber("expected token \')\'",line));
 				DefaultLogger::get()->warn(AddLineNumber("expected token \')\'",line));
 				continue;
 				continue;
@@ -300,24 +293,18 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 
 
 		std::string::size_type ns = n0;
 		std::string::size_type ns = n0;
 		do ++ns; while( IsSpace(s.at(ns)));
 		do ++ns; while( IsSpace(s.at(ns)));
-
 		std::string::size_type ne = n1;
 		std::string::size_type ne = n1;
 		do --ne; while( IsSpace(s.at(ne)));
 		do --ne; while( IsSpace(s.at(ne)));
-
 		std::string type = s.substr(ns,ne-ns+1);
 		std::string type = s.substr(ns,ne-ns+1);
 		std::transform( type.begin(), type.end(), type.begin(), &Assimp::ToLower<char>  );
 		std::transform( type.begin(), type.end(), type.begin(), &Assimp::ToLower<char>  );
-
 		const char* sz = scheme.GetStaticStringForToken(type);
 		const char* sz = scheme.GetStaticStringForToken(type);
 		if(sz) {
 		if(sz) {
-		
 			const std::string::size_type len = n2-n1+1;
 			const std::string::size_type len = n2-n1+1;
 			char* const copysz = new char[len+1];
 			char* const copysz = new char[len+1];
 			std::copy(s.c_str()+n1,s.c_str()+n2+1,copysz);
 			std::copy(s.c_str()+n1,s.c_str()+n2+1,copysz);
 			copysz[len] = '\0';
 			copysz[len] = '\0';
-
 			db.InternInsert(new LazyObject(db,id,line,sz,copysz));
 			db.InternInsert(new LazyObject(db,id,line,sz,copysz));
 		}
 		}
-
 		if(!has_next) {
 		if(!has_next) {
 			++splitter;
 			++splitter;
 		}
 		}
@@ -327,7 +314,7 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme,
 		DefaultLogger::get()->warn("STEP: ignoring unexpected EOF");
 		DefaultLogger::get()->warn("STEP: ignoring unexpected EOF");
 	}
 	}
 
 
-	if ( !DefaultLogger::isNullLogger() ){
+	if ( !DefaultLogger::isNullLogger()){
 		DefaultLogger::get()->debug((Formatter::format(),"STEP: got ",map.size()," object records with ",
 		DefaultLogger::get()->debug((Formatter::format(),"STEP: got ",map.size()," object records with ",
 			db.GetRefs().size()," inverse index entries"));
 			db.GetRefs().size()," inverse index entries"));
 	}
 	}
@@ -338,7 +325,6 @@ boost::shared_ptr<const EXPRESS::DataType> EXPRESS::DataType::Parse(const char*&
 {
 {
 	const char* cur = inout;
 	const char* cur = inout;
 	SkipSpaces(&cur);
 	SkipSpaces(&cur);
-
 	if (*cur == ',' || IsSpaceOrNewLine(*cur)) {
 	if (*cur == ',' || IsSpaceOrNewLine(*cur)) {
 		throw STEP::SyntaxError("unexpected token, expected parameter",line);
 		throw STEP::SyntaxError("unexpected token, expected parameter",line);
 	}
 	}

+ 0 - 4
Source/ThirdParty/Assimp/code/STEPFileReader.h

@@ -47,12 +47,10 @@ namespace Assimp {
 namespace STEP {
 namespace STEP {
 
 
 	// ### Parsing a STEP file is a twofold procedure ###
 	// ### Parsing a STEP file is a twofold procedure ###
-
 	// --------------------------------------------------------------------------
 	// --------------------------------------------------------------------------
 	// 1) read file header and return to caller, who checks if the 
 	// 1) read file header and return to caller, who checks if the 
 	//    file is of a supported schema ..
 	//    file is of a supported schema ..
 	DB* ReadFileHeader(boost::shared_ptr<IOStream> stream);
 	DB* ReadFileHeader(boost::shared_ptr<IOStream> stream);
-
 	// --------------------------------------------------------------------------
 	// --------------------------------------------------------------------------
 	// 2) read the actual file contents using a user-supplied set of
 	// 2) read the actual file contents using a user-supplied set of
 	//    conversion functions to interpret the data.
 	//    conversion functions to interpret the data.
@@ -60,8 +58,6 @@ namespace STEP {
 	template <size_t N, size_t N2> inline void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const (&arr)[N], const char* const (&arr2)[N2]) {
 	template <size_t N, size_t N2> inline void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const (&arr)[N], const char* const (&arr2)[N2]) {
 		return ReadFile(db,scheme,arr,N,arr2,N2);
 		return ReadFile(db,scheme,arr,N,arr2,N2);
 	}
 	}
-	
-
 } // ! STEP
 } // ! STEP
 } // ! Assimp
 } // ! Assimp
 
 

+ 57 - 0
Source/ThirdParty/Assimp/code/SceneCombiner.cpp

@@ -880,6 +880,59 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/,
 		delete *it;
 		delete *it;
 }
 }
 
 
+// ------------------------------------------------------------------------------------------------
+void SceneCombiner::MergeMaterials(aiMaterial** dest,
+		std::vector<aiMaterial*>::const_iterator begin,
+		std::vector<aiMaterial*>::const_iterator end)
+{
+	ai_assert(NULL != dest);
+
+	if (begin == end)	{
+		*dest = NULL; // no materials ...
+		return;
+	}
+
+	// Allocate the output material
+	aiMaterial* out = *dest = new aiMaterial();
+
+	// Get the maximal number of properties
+	unsigned int size = 0;
+	for (std::vector<aiMaterial*>::const_iterator it = begin; it != end; ++it) {
+		size += (*it)->mNumProperties;
+	}
+
+	out->Clear();
+	delete[] out->mProperties;
+
+	out->mNumAllocated = size;
+	out->mNumProperties = 0;
+	out->mProperties = new aiMaterialProperty*[out->mNumAllocated];
+
+	for (std::vector<aiMaterial*>::const_iterator it = begin; it != end; ++it) {
+		for(unsigned int i = 0; i < (*it)->mNumProperties; ++i) {
+			aiMaterialProperty* sprop = (*it)->mProperties[i];
+
+			// Test if we already have a matching property 
+			const aiMaterialProperty* prop_exist;
+			if(aiGetMaterialProperty(out, sprop->mKey.C_Str(), sprop->mType, sprop->mIndex, &prop_exist) != AI_SUCCESS) {
+				// If not, we add it to the new material
+				aiMaterialProperty* prop = out->mProperties[out->mNumProperties] = new aiMaterialProperty();
+
+				prop->mDataLength = sprop->mDataLength;
+				prop->mData = new char[prop->mDataLength];
+				::memcpy(prop->mData, sprop->mData, prop->mDataLength);
+
+				prop->mIndex    = sprop->mIndex;
+				prop->mSemantic = sprop->mSemantic;
+				prop->mKey      = sprop->mKey;
+				prop->mType		= sprop->mType;
+
+				out->mNumProperties++;
+			}
+		}
+	}
+}
+
 // ------------------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------------------
 template <typename Type>
 template <typename Type>
 inline void CopyPtrArray (Type**& dest, const Type* const * src, unsigned int num)
 inline void CopyPtrArray (Type**& dest, const Type* const * src, unsigned int num)
@@ -1012,6 +1065,10 @@ void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src)
 	ai_assert(NULL != _dest && NULL != src);
 	ai_assert(NULL != _dest && NULL != src);
 
 
 	aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() );
 	aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() );
+
+	dest->Clear();
+	delete[] dest->mProperties;
+
 	dest->mNumAllocated  =  src->mNumAllocated;
 	dest->mNumAllocated  =  src->mNumAllocated;
 	dest->mNumProperties =  src->mNumProperties;
 	dest->mNumProperties =  src->mNumProperties;
 	dest->mProperties    =  new aiMaterialProperty* [dest->mNumAllocated];
 	dest->mProperties    =  new aiMaterialProperty* [dest->mNumAllocated];

+ 14 - 0
Source/ThirdParty/Assimp/code/SceneCombiner.h

@@ -248,6 +248,20 @@ public:
 	static void MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
 	static void MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
 		std::vector<aiMesh*>::const_iterator end);
 		std::vector<aiMesh*>::const_iterator end);
 
 
+	// -------------------------------------------------------------------
+	/** Merges two or more materials
+	 *
+	 *  The materials should be complementary as much as possible. In case
+	 *  of a property present in different materials, the first occurence
+	 *  is used.
+	 *
+	 *  @param dest Destination material. Must be empty.
+	 *  @param begin First material to be processed
+	 *  @param end Points to the material after the last material to be processed
+	 */
+	static void MergeMaterials(aiMaterial** dest,
+		std::vector<aiMaterial*>::const_iterator begin,
+		std::vector<aiMaterial*>::const_iterator end);
 
 
 	// -------------------------------------------------------------------
 	// -------------------------------------------------------------------
 	/** Builds a list of uniquely named bones in a mesh list
 	/** Builds a list of uniquely named bones in a mesh list

+ 1 - 1
Source/ThirdParty/Assimp/code/ScenePreprocessor.cpp

@@ -72,7 +72,7 @@ void ScenePreprocessor::ProcessScene ()
 		aiColor3D clr(0.6f,0.6f,0.6f);
 		aiColor3D clr(0.6f,0.6f,0.6f);
 		helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
 		helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
 
 
-		// setup the default name to make this material identifyable
+		// setup the default name to make this material identifiable
 		name.Set(AI_DEFAULT_MATERIAL_NAME);
 		name.Set(AI_DEFAULT_MATERIAL_NAME);
 		helper->AddProperty(&name,AI_MATKEY_NAME);
 		helper->AddProperty(&name,AI_MATKEY_NAME);
 
 

+ 1 - 1
Source/ThirdParty/Assimp/code/ScenePreprocessor.h

@@ -54,7 +54,7 @@ namespace Assimp	{
  *  importer, such as aiMesh::mPrimitiveTypes.
  *  importer, such as aiMesh::mPrimitiveTypes.
 */
 */
 // ----------------------------------------------------------------------------------
 // ----------------------------------------------------------------------------------
-class ScenePreprocessor
+class ASSIMP_API ScenePreprocessor
 {
 {
 	// Make ourselves a friend of the corresponding test unit.
 	// Make ourselves a friend of the corresponding test unit.
 	friend class ::ScenePreprocessorTest;
 	friend class ::ScenePreprocessorTest;

+ 1 - 1
Source/ThirdParty/Assimp/code/SmoothingGroups.h

@@ -52,7 +52,7 @@ struct FaceWithSmoothingGroup
 	{
 	{
 		// let the rest uninitialized for performance - in release builds.
 		// let the rest uninitialized for performance - in release builds.
 		// in debug builds set all indices to a common magic value
 		// in debug builds set all indices to a common magic value
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 		this->mIndices[0] = 0xffffffff;
 		this->mIndices[0] = 0xffffffff;
 		this->mIndices[1] = 0xffffffff;
 		this->mIndices[1] = 0xffffffff;
 		this->mIndices[2] = 0xffffffff;
 		this->mIndices[2] = 0xffffffff;

+ 1 - 1
Source/ThirdParty/Assimp/code/SortByPTypeProcess.h

@@ -55,7 +55,7 @@ namespace Assimp	{
  *  A mesh with 5 lines, 3 points and 145 triangles would be split in 3 
  *  A mesh with 5 lines, 3 points and 145 triangles would be split in 3 
  * submeshes.
  * submeshes.
 */
 */
-class SortByPTypeProcess : public BaseProcess
+class ASSIMP_API SortByPTypeProcess : public BaseProcess
 {
 {
 public:
 public:
 
 

+ 1 - 1
Source/ThirdParty/Assimp/code/SpatialSort.cpp

@@ -329,7 +329,7 @@ unsigned int SpatialSort::GenerateMappingTable(std::vector<unsigned int>& fill,f
 		++t;
 		++t;
 	}
 	}
 
 
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 
 
 	// debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1
 	// debug invariant: mPositions[i].mIndex values must range from 0 to mPositions.size()-1
 	for (size_t i = 0; i < fill.size(); ++i) {
 	for (size_t i = 0; i < fill.size(); ++i) {

+ 4 - 4
Source/ThirdParty/Assimp/code/SplitLargeMeshes.h

@@ -76,12 +76,12 @@ class SplitLargeMeshesProcess_Vertex;
 #endif
 #endif
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
-/** Postprocessing filter to split large meshes into submeshes
+/** Post-processing filter to split large meshes into sub-meshes
  *
  *
  * Applied BEFORE the JoinVertices-Step occurs.
  * Applied BEFORE the JoinVertices-Step occurs.
  * Returns NON-UNIQUE vertices, splits by triangle number.
  * Returns NON-UNIQUE vertices, splits by triangle number.
 */
 */
-class SplitLargeMeshesProcess_Triangle : public BaseProcess
+class ASSIMP_API SplitLargeMeshesProcess_Triangle : public BaseProcess
 {
 {
 	friend class SplitLargeMeshesProcess_Vertex;
 	friend class SplitLargeMeshesProcess_Vertex;
 
 
@@ -144,12 +144,12 @@ public:
 
 
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
-/** Postprocessing filter to split large meshes into submeshes
+/** Post-processing filter to split large meshes into sub-meshes
  *
  *
  * Applied AFTER the JoinVertices-Step occurs.
  * Applied AFTER the JoinVertices-Step occurs.
  * Returns UNIQUE vertices, splits by vertex number.
  * Returns UNIQUE vertices, splits by vertex number.
 */
 */
-class SplitLargeMeshesProcess_Vertex : public BaseProcess
+class ASSIMP_API SplitLargeMeshesProcess_Vertex : public BaseProcess
 {
 {
 public:
 public:
 
 

+ 3 - 3
Source/ThirdParty/Assimp/code/Subdivision.cpp

@@ -383,7 +383,7 @@ void CatmullClarkSubdivider::InternSubdivide (
 	} 
 	} 
 	
 	
 	// check the other way round for consistency
 	// check the other way round for consistency
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 
 
 	for (size_t t = 0; t < ofsadjvec.size()-1; ++t) {
 	for (size_t t = 0; t < ofsadjvec.size()-1; ++t) {
 		for (unsigned int m = 0; m <  cntadjfac[t]; ++m) {
 		for (unsigned int m = 0; m <  cntadjfac[t]; ++m) {
@@ -530,7 +530,7 @@ void CatmullClarkSubdivider::InternSubdivide (
 
 
 							ai_assert(adj[o]-moffsets[nidx].first < mp->mNumFaces);
 							ai_assert(adj[o]-moffsets[nidx].first < mp->mNumFaces);
 							const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first];
 							const aiFace& f = mp->mFaces[adj[o]-moffsets[nidx].first];
-#				ifdef _DEBUG
+#				ifdef ASSIMP_BUILD_DEBUG
 							bool haveit = false;
 							bool haveit = false;
 #				endif
 #				endif
 
 
@@ -553,7 +553,7 @@ void CatmullClarkSubdivider::InternSubdivide (
 									// fixme: replace with mod face.mNumIndices? 
 									// fixme: replace with mod face.mNumIndices? 
 									R += c0.midpoint+c1.midpoint;
 									R += c0.midpoint+c1.midpoint;
 
 
-#						ifdef _DEBUG
+#						ifdef ASSIMP_BUILD_DEBUG
 									haveit = true;
 									haveit = true;
 #						endif
 #						endif
 									break;
 									break;

+ 3 - 3
Source/ThirdParty/Assimp/code/TriangulateProcess.h

@@ -49,15 +49,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 struct aiMesh;
 struct aiMesh;
 
 
 class TriangulateProcessTest;
 class TriangulateProcessTest;
-namespace Assimp
-{
+
+namespace Assimp {
 
 
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 /** The TriangulateProcess splits up all faces with more than three indices
 /** The TriangulateProcess splits up all faces with more than three indices
  * into triangles. You usually want this to happen because the graphics cards
  * into triangles. You usually want this to happen because the graphics cards
  * need their data as triangles.
  * need their data as triangles.
  */
  */
-class TriangulateProcess : public BaseProcess
+class ASSIMP_API TriangulateProcess : public BaseProcess
 {
 {
 public:
 public:
 
 

+ 1 - 1
Source/ThirdParty/Assimp/code/ValidateDataStructure.cpp

@@ -86,7 +86,7 @@ AI_WONT_RETURN void ValidateDSProcess::ReportError(const char* msg,...)
 	ai_assert(iLen > 0);
 	ai_assert(iLen > 0);
 
 
 	va_end(args);
 	va_end(args);
-#ifdef _DEBUG
+#ifdef ASSIMP_BUILD_DEBUG
 	ai_assert( false );
 	ai_assert( false );
 #endif
 #endif
 	throw DeadlyImportError("Validation failed: " + std::string(szBuffer,iLen));
 	throw DeadlyImportError("Validation failed: " + std::string(szBuffer,iLen));

+ 1 - 1
Source/ThirdParty/Assimp/code/VertexTriangleAdjacency.h

@@ -56,7 +56,7 @@ namespace Assimp	{
  *  @note Although it is called #VertexTriangleAdjacency, the current version does also
  *  @note Although it is called #VertexTriangleAdjacency, the current version does also
  *    support arbitrary polygons. */
  *    support arbitrary polygons. */
 // --------------------------------------------------------------------------------------------
 // --------------------------------------------------------------------------------------------
-class VertexTriangleAdjacency
+class ASSIMP_API VertexTriangleAdjacency
 {
 {
 public:
 public:
 
 

+ 3 - 0
Source/ThirdParty/Assimp/code/XFileParser.cpp

@@ -136,6 +136,9 @@ XFileParser::XFileParser( const std::vector<char>& pBuffer)
 		ThrowException( boost::str( boost::format( "Unknown float size %1% specified in xfile header.")
 		ThrowException( boost::str( boost::format( "Unknown float size %1% specified in xfile header.")
 			% mBinaryFloatSize));
 			% mBinaryFloatSize));
 
 
+	// The x format specifies size in bits, but we work in bytes
+	mBinaryFloatSize /= 8;
+
 	P += 16;
 	P += 16;
 
 
 	// If this is a compressed X file, apply the inflate algorithm to it
 	// If this is a compressed X file, apply the inflate algorithm to it

+ 1 - 1
Source/ThirdParty/Assimp/code/XFileParser.h

@@ -144,7 +144,7 @@ protected:
 protected:
 protected:
 	unsigned int mMajorVersion, mMinorVersion; ///< version numbers
 	unsigned int mMajorVersion, mMinorVersion; ///< version numbers
 	bool mIsBinaryFormat; ///< true if the file is in binary, false if it's in text form
 	bool mIsBinaryFormat; ///< true if the file is in binary, false if it's in text form
-	unsigned int mBinaryFloatSize; ///< float size, either 32 or 64 bits
+	unsigned int mBinaryFloatSize; ///< float size in bytes, either 4 or 8
 	// counter for number arrays in binary format
 	// counter for number arrays in binary format
 	unsigned int mBinaryNumCount;
 	unsigned int mBinaryNumCount;
 
 

+ 24 - 21
Source/ThirdParty/Assimp/code/fast_atof.h

@@ -21,23 +21,23 @@
 namespace Assimp
 namespace Assimp
 {
 {
 
 
-const float fast_atof_table[16] =	{  // we write [16] here instead of [] to work around a swig bug
-	0.f,
-	0.1f,
-	0.01f,
-	0.001f,
-	0.0001f,
-	0.00001f,
-	0.000001f,
-	0.0000001f,
-	0.00000001f,
-	0.000000001f,
-	0.0000000001f,
-	0.00000000001f,
-	0.000000000001f,
-	0.0000000000001f,
-	0.00000000000001f,
-	0.000000000000001f
+const double fast_atof_table[16] =	{  // we write [16] here instead of [] to work around a swig bug
+	0.0,
+	0.1,
+	0.01,
+	0.001,
+	0.0001,
+	0.00001,
+	0.000001,
+	0.0000001,
+	0.00000001,
+	0.000000001,
+	0.0000000001,
+	0.00000000001,
+	0.000000000001,
+	0.0000000000001,
+	0.00000000000001,
+	0.000000000000001
 };
 };
 
 
 
 
@@ -179,6 +179,9 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
 	unsigned int cur = 0;
 	unsigned int cur = 0;
 	uint64_t value = 0;
 	uint64_t value = 0;
 
 
+	if ( *in < '0' || *in > '9' )
+			throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value.");
+
 	bool running = true;
 	bool running = true;
 	while ( running )
 	while ( running )
 	{
 	{
@@ -188,7 +191,7 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
 		const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
 		const uint64_t new_value = ( value * 10 ) + ( *in - '0' );
 		
 		
 		if (new_value < value) /* numeric overflow, we rely on you */
 		if (new_value < value) /* numeric overflow, we rely on you */
-			return value;
+			throw std::overflow_error(std::string("Converting the string \"") + in + "\" into a value resulted in overflow.");
 
 
 		value = new_value;
 		value = new_value;
 
 
@@ -224,7 +227,7 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int*
 // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
 // If you find any bugs, please send them to me, niko (at) irrlicht3d.org.
 // ------------------------------------------------------------------------------------
 // ------------------------------------------------------------------------------------
 template <typename Real>
 template <typename Real>
-inline const char* fast_atoreal_move( const char* c, Real& out)
+inline const char* fast_atoreal_move( const char* c, Real& out, bool check_comma = true)
 {
 {
 	Real f;
 	Real f;
 
 
@@ -234,7 +237,7 @@ inline const char* fast_atoreal_move( const char* c, Real& out)
 	}
 	}
 
 
 	f = static_cast<Real>( strtoul10_64 ( c, &c) );
 	f = static_cast<Real>( strtoul10_64 ( c, &c) );
-	if (*c == '.' || (c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too
+	if (*c == '.' || (check_comma && c[0] == ',' && c[1] >= '0' && c[1] <= '9')) // allow for commas, too
 	{
 	{
 		++c;
 		++c;
 
 
@@ -270,7 +273,7 @@ inline const char* fast_atoreal_move( const char* c, Real& out)
 		if (einv) {
 		if (einv) {
 			exp = -exp;
 			exp = -exp;
 		}
 		}
-		f *= pow(static_cast<Real>(10.0f), exp);
+		f *= pow(static_cast<Real>(10.0), exp);
 	}
 	}
 
 
 	if (inv) {
 	if (inv) {

Some files were not shown because too many files changed in this diff