Explorar o código

OgreImporter: Implement Ogre binary mesh support (.mesh). All Ogre3D SDK media samples tested to work. Assimp repo does not yet have binary versions of Ogre meshes.

Jonne Nauha %!s(int64=11) %!d(string=hai) anos
pai
achega
4b16b182be

+ 6 - 0
code/CMakeLists.txt

@@ -322,8 +322,14 @@ SOURCE_GROUP( Obj FILES ${Obj_SRCS})
 
 SET( Ogre_SRCS
 	OgreImporter.h
+	OgreStructs.h
 	OgreParsingUtils.h
+	OgreBinarySerializer.h
+	OgreXmlSerializer.h
 	OgreImporter.cpp
+	OgreStructs.cpp
+	OgreBinarySerializer.cpp
+	OgreXmlSerializer.cpp
 	OgreMaterial.cpp
 	OgreMesh.cpp
 	OgreSkeleton.cpp

+ 759 - 0
code/OgreBinarySerializer.cpp

@@ -0,0 +1,759 @@
+/*
+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 "OgreBinarySerializer.h"
+#include "TinyFormatter.h"
+
+#ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
+
+namespace Assimp
+{
+namespace Ogre
+{
+
+const std::string		VERSION_1_8				= "[MeshSerializer_v1.8]";
+const unsigned short	HEADER_CHUNK_ID			= 0x1000;
+const long				MSTREAM_OVERHEAD_SIZE	= sizeof(uint16_t) + sizeof(uint32_t);
+
+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);
+}
+
+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 (id != HEADER_CHUNK_ID)
+	//	DefaultLogger::get()->debug(Formatter::format() << MeshHeaderToString(static_cast<MeshChunkId>(id)));
+	return id;
+}
+
+void OgreBinarySerializer::RollbackHeader()
+{
+	m_reader->IncPtr(-MSTREAM_OVERHEAD_SIZE);
+}
+
+void OgreBinarySerializer::SkipBytes(size_t num)
+{
+	m_reader->IncPtr(num);
+}
+
+Mesh *OgreBinarySerializer::ImportMesh(MemoryStreamReader *stream)
+{
+	OgreBinarySerializer serializer(stream);
+	
+	uint16_t id = serializer.ReadHeader(false);
+	if (id != HEADER_CHUNK_ID)
+		throw DeadlyExportError("Invalid Mesh file header");
+	
+	/// @todo Check what we can actually support.
+	std::string version = serializer.ReadLine();
+	if (version != VERSION_1_8)
+		throw DeadlyExportError("Mesh version " + version + " not supported by this importer. Run OgreMeshUpgrader tool on the file and try again.");
+
+	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(Formatter::format() << "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, mesh->sharedVertexData);
+					break;
+				}
+				case M_SUBMESH:
+					ReadSubMesh(mesh);
+					break;
+				case M_MESH_SKELETON_LINK:
+					ReadMeshSkeletonLink(mesh);
+					break;
+				case M_MESH_BONE_ASSIGNMENT:
+					ReadBoneAssignment(mesh);
+					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();
+	}
+}
+
+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(Mesh *dest)
+{
+	VertexBoneAssignment ba;
+	ba.vertexIndex = Read<uint32_t>();
+	ba.boneIndex = Read<uint16_t>();
+	ba.weight = Read<float>();
+
+	dest->boneAssignments.push_back(ba);
+}
+
+void OgreBinarySerializer::ReadBoneAssignment(SubMesh2 *dest)
+{
+	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;
+	
+	SubMesh2 *submesh = new SubMesh2();
+	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(mesh, 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);
+					break;
+				}
+				case M_SUBMESH_TEXTURE_ALIAS:
+				{
+					ReadSubMeshTextureAlias(submesh);
+					break;
+				}
+			}
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+	
+	submesh->index = mesh->subMeshes.size();
+	mesh->subMeshes.push_back(submesh);
+}
+
+void OgreBinarySerializer::ReadSubMeshOperation(SubMesh2 *submesh)
+{
+	submesh->operationType = static_cast<SubMesh2::OperationType>(Read<uint16_t>());
+}
+
+void OgreBinarySerializer::ReadSubMeshTextureAlias(SubMesh2 *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)
+		{
+			SubMesh2 *submesh = mesh->SubMesh(Read<uint16_t>());
+			if (submesh)
+			{
+				submesh->name = ReadLine();
+				DefaultLogger::get()->debug(Formatter::format() << "  - SubMesh " << submesh->index << " name '" << submesh->name << "'");
+			}
+			else
+				ReadLine();
+			
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadGeometry(Mesh *mesh, 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(mesh, dest);
+					break;
+				}
+				case M_GEOMETRY_VERTEX_BUFFER:
+				{
+					ReadGeometryVertexBuffer(mesh, dest);
+					break;
+				}
+			}
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadGeometryVertexDeclaration(Mesh *mesh, VertexData *dest)
+{
+	if (!AtEnd())
+	{
+		uint16_t id = ReadHeader();
+		while (!AtEnd() && id == M_GEOMETRY_VERTEX_ELEMENT)
+		{
+			ReadGeometryVertexElement(mesh, dest);
+
+			if (!AtEnd())
+				id = ReadHeader();
+		}
+		if (!AtEnd())
+			RollbackHeader();
+	}
+}
+
+void OgreBinarySerializer::ReadGeometryVertexElement(Mesh *mesh, 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(Mesh *mesh, 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)
+		{
+			Animation2 *anim = new Animation2(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(Animation2 *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(Animation2 *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();
+	}
+}
+
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER

+ 312 - 0
code/OgreBinarySerializer.h

@@ -0,0 +1,312 @@
+/*
+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
+{
+	class OgreBinarySerializer
+	{
+	public:	
+		static Mesh *ImportMesh(MemoryStreamReader *reader);
+
+	private:
+		OgreBinarySerializer(MemoryStreamReader *reader) :
+			m_reader(reader),
+			m_currentLen(0)
+		{
+		}
+
+		bool AtEnd() const;
+
+		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(SubMesh2 *submesh);
+		void ReadSubMeshTextureAlias(SubMesh2 *submesh);
+		
+		void ReadBoneAssignment(Mesh *dest);
+		void ReadBoneAssignment(SubMesh2 *dest);
+
+		void ReadGeometry(Mesh *mesh, VertexData *dest);
+		void ReadGeometryVertexDeclaration(Mesh *mesh, VertexData *dest);
+		void ReadGeometryVertexElement(Mesh *mesh, VertexData *dest);
+		void ReadGeometryVertexBuffer(Mesh *mesh, VertexData *dest);
+
+		void ReadEdgeList(Mesh *mesh);
+		void ReadPoses(Mesh *mesh);
+		void ReadPoseVertices(Pose *pose);
+		
+		void ReadAnimations(Mesh *mesh);
+		void ReadAnimation(Animation2 *anim);
+		void ReadAnimationKeyFrames(Animation2 *anim, VertexAnimationTrack *track);
+
+		uint16_t ReadHeader(bool readLen = true);
+		void RollbackHeader();
+
+		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);
+
+		std::string ReadString(size_t len);
+		std::string ReadLine();
+
+		void SkipBytes(size_t num);
+
+		uint32_t m_currentLen;
+		MemoryStreamReader *m_reader;
+	};
+
+	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 "Uknown_MeshChunkId";
+	}
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
+#endif // AI_OGREBINARYSERIALIZER_H_INC

+ 51 - 20
code/OgreImporter.cpp

@@ -38,28 +38,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ----------------------------------------------------------------------
 */
 
-#include "AssimpPCH.h"
-
 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
 
+#include "AssimpPCH.h"
+
 #include <vector>
 #include <sstream>
+#include <istream>
 
 #include "OgreImporter.h"
+#include "OgreBinarySerializer.h"
+
 #include "TinyFormatter.h"
 #include "irrXMLWrapper.h"
 
 static const aiImporterDesc desc = {
-	"Ogre XML Mesh Importer",
+	"Ogre3D Mesh Importer",
 	"",
 	"",
 	"",
-	aiImporterFlags_SupportTextFlavour,
+	aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour,
 	0,
 	0,
 	0,
 	0,
-	"mesh.xml"
+	"mesh mesh.xml"
 };
 
 using namespace std;
@@ -83,11 +86,18 @@ void OgreImporter::SetupProperties(const Importer* pImp)
 bool OgreImporter::CanRead(const std::string &pFile, Assimp::IOSystem *pIOHandler, bool checkSig) const
 {
 	if (!checkSig) {
-		return EndsWith(pFile, ".mesh.xml", false);
+		return EndsWith(pFile, ".mesh.xml", false) || EndsWith(pFile, ".mesh", false);
 	}
 
-	const char* tokens[] = { "<mesh>" };
-	return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+	if (EndsWith(pFile, ".mesh.xml", false))
+	{
+		const char* tokens[] = { "<mesh>" };
+		return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
+	}
+	else
+	{
+		return EndsWith(pFile, ".mesh", false);
+	}
 }
 
 void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Assimp::IOSystem *pIOHandler)
@@ -95,12 +105,30 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
 	// -------------------- Initial file and XML operations --------------------
 	
 	// Open
-	boost::scoped_ptr<IOStream> file(pIOHandler->Open(pFile));
-	if (!file.get()) {
+	IOStream *f = pIOHandler->Open(pFile, "rb");
+	if (!f) {
 		throw DeadlyImportError("Failed to open file " + pFile);
 	}
 
+	// Binary .mesh import
+	if (EndsWith(pFile, ".mesh", false)) {
+		// Read full data from file
+		/// @note MemoryStreamReader takes ownership of f.
+		MemoryStreamReader reader(f);
+		
+		// Import mesh
+		boost::scoped_ptr<Mesh> mesh = OgreBinarySerializer::ImportMesh(&reader);
+		
+		// Import mesh referenced materials
+		ReadMaterials(pFile, pIOHandler, pScene, mesh.get());
+		
+		// Convert to Assimp.
+		mesh->ConvertToAssimpScene(pScene);
+		return;
+	}
+
 	// Read
+	boost::scoped_ptr<IOStream> file(f);
 	boost::scoped_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(file.get()));
 	boost::scoped_ptr<XmlReader> reader(irr::io::createIrrXMLReader(xmlStream.get()));
 	if (!reader) {
@@ -153,18 +181,19 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
 		SubMesh* submesh = new SubMesh();
 		ReadSubMesh(subMeshes.size(), *submesh, reader.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!
-		/// @todo Not sure if this really is needed, refactor out if possible.
-		submesh->MaterialIndex = subMeshes.size();
-
-		subMeshes.push_back(boost::shared_ptr<SubMesh>(submesh));
-
 		/** @todo What is the correct way of handling empty ref here.
 			Does Assimp require there to be a valid material index for each mesh,
 			even if its a dummy material. */
 		aiMaterial* material = ReadMaterial(pFile, pIOHandler, submesh->MaterialName);
-		materials.push_back(material);
+		if (!material)
+			material = new aiMaterial();
+		if (material)
+		{
+			submesh->MaterialIndex = materials.size();
+			materials.push_back(material);
+		}
+
+		subMeshes.push_back(boost::shared_ptr<SubMesh>(submesh));
 	}
 
 	if (subMeshes.empty()) {
@@ -223,10 +252,12 @@ void OgreImporter::InternReadFile(const std::string &pFile, aiScene *pScene, Ass
 	// -------------------- Apply to aiScene --------------------
 
 	// Materials
-	pScene->mMaterials = new aiMaterial*[materials.size()];
 	pScene->mNumMaterials = materials.size();
+	if (pScene->mNumMaterials > 0) {
+		pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials];
+	}
 
-	for(size_t i=0, len=materials.size(); i<len; ++i) {
+	for(size_t i=0; i<pScene->mNumMaterials; ++i) {
 		pScene->mMaterials[i] = materials[i];
 	}
 

+ 44 - 0
code/OgreImporter.h

@@ -1,3 +1,42 @@
+/*
+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
@@ -5,6 +44,8 @@
 #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER
 
 #include "BaseImporter.h"
+
+#include "OgreStructs.h"
 #include "OgreParsingUtils.h"
 
 namespace Assimp
@@ -114,6 +155,9 @@ private:
 
 	//-------------------------------- OgreMaterial.cpp -------------------------------
 
+	/// Read materials referenced by the @c mesh to @c pScene.
+	void ReadMaterials(const std::string &pFile, Assimp::IOSystem *pIOHandler, aiScene *pScene, Mesh *mesh);
+	
 	/// Reads material
 	aiMaterial* ReadMaterial(const std::string &pFile, Assimp::IOSystem *pIOHandler, const std::string MaterialName);
 

+ 33 - 6
code/OgreMaterial.cpp

@@ -59,11 +59,40 @@ 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)
+	{
+		SubMesh2 *submesh = mesh->SubMesh(i);
+		if (submesh && !submesh->materialRef.empty())
+		{
+			aiMaterial *material = ReadMaterial(pFile, pIOHandler, submesh->materialRef);
+			if (material)
+			{
+				submesh->materialIndex = materials.size();
+				materials.push_back(material);
+			}
+		}
+	}
+
+	// Assign material to scene
+	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)
 {
-	/// @todo Should we return null ptr here or a empty material?
 	if (materialName.empty()) {
-		return new aiMaterial();
+		return 0;
 	}
 
 	// Full reference and examples of Ogre Material Script 
@@ -117,17 +146,15 @@ aiMaterial* OgreImporter::ReadMaterial(const std::string &pFile, Assimp::IOSyste
 		}
 		if (!materialFile)
 		{
-			/// @todo Should we return null ptr here or a empty material?
 			DefaultLogger::get()->error(Formatter::format() << "Failed to find source file for material '" << materialName << "'");
-			return new aiMaterial();
+			return 0;
 		}
 
 		boost::scoped_ptr<IOStream> stream(materialFile);
 		if (stream->FileSize() == 0)
 		{
-			/// @todo Should we return null ptr here or a empty material?
 			DefaultLogger::get()->warn(Formatter::format() << "Source file for material '" << materialName << "' is empty (size is 0 bytes)");
-			return new aiMaterial();
+			return 0;
 		}
 
 		// Read bytes

+ 2 - 1
code/OgreMesh.cpp

@@ -469,7 +469,8 @@ aiMesh *OgreImporter::CreateAssimpSubMesh(aiScene *pScene, const SubMesh& submes
 	aiMesh *dest = new aiMesh();
 
 	// Material
-	dest->mMaterialIndex = submesh.MaterialIndex;
+	if (submesh.MaterialIndex != -1)
+		dest->mMaterialIndex = submesh.MaterialIndex;
 
 	// Positions
 	dest->mVertices = new aiVector3D[submesh.Positions.size()];

+ 104 - 65
code/OgreParsingUtils.h

@@ -1,3 +1,42 @@
+/*
+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
@@ -13,6 +52,70 @@ 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);
+}
+
 typedef irr::io::IrrXMLReader XmlReader;
 
 static void ThrowAttibuteError(const XmlReader* reader, const std::string &name, const std::string &error = "")
@@ -93,7 +196,7 @@ inline std::string GetAttribute<std::string>(const XmlReader* reader, const std:
 template<> 
 inline bool GetAttribute<bool>(const XmlReader* reader, const std::string &name)
 {
-	std::string value = GetAttribute<std::string>(reader, name);
+	std::string value = Ogre::ToLower(GetAttribute<std::string>(reader, name));
 	if (ASSIMP_stricmp(value, "true") == 0)
 	{
 		return true;
@@ -143,70 +246,6 @@ static inline std::string NextAfterNewLine(std::stringstream &ss, std::string &n
 	return skipped;
 }
 
-/// 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);
-}
-
 } // Ogre
 } // Assimp
 

+ 2 - 2
code/OgreSkeleton.cpp

@@ -5,11 +5,11 @@ Open Asset Import Library (assimp)
 Copyright (c) 2006-2012, assimp team
 All rights reserved.
 
-Redistribution and use of this software in aSource and binary forms, 
+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 aSource code must retain the above
+* Redistributions of source code must retain the above
   copyright notice, this list of conditions and the
   following disclaimer.
 

+ 583 - 0
code/OgreStructs.cpp

@@ -0,0 +1,583 @@
+/*
+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 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";
+}
+
+// VertexData
+
+VertexData::VertexData() :
+	count(0)
+{
+}
+
+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;
+}
+
+// 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),
+	hasSkeletalAnimations(false)
+{
+}
+
+Mesh::~Mesh()
+{
+	Reset();
+}
+
+void Mesh::Reset()
+{
+	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();
+}
+
+SubMesh2 *Mesh::SubMesh(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)
+{
+	// Export meshes
+	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];
+
+	for(size_t i=0; i<dest->mNumMeshes; ++i) {
+		dest->mMeshes[i] = subMeshes[i]->ConvertToAssimpMesh(this);
+		dest->mRootNode->mMeshes[i] = i;
+	}
+}
+
+// SubMesh2
+
+SubMesh2::SubMesh2() :
+	index(0),
+	vertexData(0),
+	indexData(new IndexData()),
+	usesSharedVertexData(false),
+	operationType(OT_POINT_LIST),
+	materialIndex(-1)
+{
+}
+
+SubMesh2::~SubMesh2()
+{
+	Reset();
+}
+
+void SubMesh2::Reset()
+{
+	OGRE_SAFE_DELETE(vertexData)
+	OGRE_SAFE_DELETE(indexData)
+}
+
+aiMesh *SubMesh2::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);
+	
+	// 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];
+			
+			// 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);
+			}
+			// UV1
+			if (uv2 && uv2Dest)
+			{
+				uv2->Seek((vWidthUv2 * ogreVertexIndex) + uv2Element->offset, aiOrigin_SET);
+				uv2->Read(&uv2Dest[newIndex], sizeUv2, 1);
+			}
+			
+			/// @todo Bones and bone weights.
+		}
+	} 
+	return dest;
+}
+
+// Animation2
+
+Animation2::Animation2(Mesh *_parentMesh) : 
+	parentMesh(_parentMesh),
+	length(0.0f),
+	baseTime(-1.0f)
+{
+}
+
+VertexData *Animation2::AssociatedVertexData(VertexAnimationTrack *track) const
+{
+	bool sharedGeom = (track->target == 0);
+	if (sharedGeom)
+		return parentMesh->sharedVertexData;
+	else
+		return parentMesh->SubMesh(track->target-1)->vertexData;
+}
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER

+ 444 - 0
code/OgreStructs.h

@@ -0,0 +1,444 @@
+/*
+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 SubMesh2;
+
+#define OGRE_SAFE_DELETE(p) delete p; p=0;
+
+// Typedefs
+typedef Assimp::StreamReaderLE MemoryStreamReader;
+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 Data
+class VertexData
+{
+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 count.
+	uint32_t count;
+
+	/// 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;
+};
+
+/// Ogre Pose Key Frame Ref
+struct PoseRef
+{
+	uint16_t index;
+	float influence;
+};
+
+/// Ogre Pose Key Frame
+struct PoseKeyFrame
+{
+	/// Time position in the animation.
+	float timePos;
+
+	std::vector<PoseRef> references;
+};
+
+/// Ogre Morph Key Frame
+struct MorphKeyFrame
+{
+	/// Time position in the animation.
+	float timePos;
+
+	MemoryStreamPtr buffer;
+};
+
+/// 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
+	};
+
+	/// Vertex data target.
+	/**  0 == shared geometry
+		>0 == submesh index + 1 */
+	uint16_t target;
+	Type type;
+	
+	std::vector<PoseKeyFrame> poseKeyFrames;
+	std::vector<MorphKeyFrame> morphKeyFrames;
+};
+
+/// Ogre Animation
+/** @todo Port OgreImporter::Animation to this and rename this to Animation! */
+class Animation2
+{
+public:
+	Animation2(Mesh *_parentMesh);
+
+	/// Returns the associated vertex data for a track in this animation.
+	VertexData *AssociatedVertexData(VertexAnimationTrack *track) const;
+	
+	/// Parent mesh.
+	Mesh *parentMesh;
+	
+	/// Animation name.
+	std::string name;
+	
+	/// Base animation name.
+	std::string baseName;
+	
+	/// Length in seconds.
+	float length;
+	
+	/// Base animation key time.
+	float baseTime;
+
+	/// Animation tracks.
+	std::vector<VertexAnimationTrack> tracks;
+};
+
+/// Ogre Vertex Bone Assignment
+struct VertexBoneAssignment
+{
+	uint32_t vertexIndex;
+	uint16_t boneIndex;
+	float weight;
+};
+
+/// Ogre SubMesh
+/** @todo Port OgreImporter::SubMesh to this and rename this to SubMesh! */
+class SubMesh2
+{
+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
+	};
+
+	SubMesh2();
+	~SubMesh2();
+
+	/// 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);
+
+	/// 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;
+
+	/// Vertex data.
+	VertexData *vertexData;
+
+	/// Index data.
+	IndexData *indexData;
+
+	/// If submesh uses shared geometry from parent mesh.
+	bool usesSharedVertexData;
+
+	/// Operation type.
+	OperationType operationType;
+	
+	/// Bone assignments.
+	std::vector<VertexBoneAssignment> boneAssignments;
+};
+
+/// 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.
+	SubMesh2 *SubMesh(uint16_t index) const;
+
+	/// Convert mesh to Assimp scene.
+	void ConvertToAssimpScene(aiScene* dest);
+
+	/// Mesh has skeletal animations.
+	bool hasSkeletalAnimations;
+	
+	/// Skeleton reference.
+	std::string skeletonRef;
+
+	/// Vertex data
+	VertexData *sharedVertexData;
+
+	/// Sub meshes.
+	std::vector<SubMesh2*> subMeshes;
+
+	/// Animations
+	std::vector<Animation2*> animations;
+
+	/// Bone assignments.
+	std::vector<VertexBoneAssignment> boneAssignments;
+
+	/// Poses
+	std::vector<Pose*> poses;
+};
+
+} // Ogre
+} // Assimp
+
+#endif // ASSIMP_BUILD_NO_OGRE_IMPORTER
+#endif // AI_OGRESTRUCTS_H_INC

+ 42 - 0
code/OgreXmlSerializer.cpp

@@ -0,0 +1,42 @@
+/*
+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.
+
+----------------------------------------------------------------------
+*/
+
+/** @todo Move XML related serialization from OgreImporter.cpp 
+	here in a similar fashion as OgreBinarySerializer. */

+ 42 - 0
code/OgreXmlSerializer.h

@@ -0,0 +1,42 @@
+/*
+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.
+
+----------------------------------------------------------------------
+*/
+
+/** @todo Move XML related serialization from OgreImporter.cpp 
+	here in a similar fashion as OgreBinarySerializer. */