Просмотр исходного кода

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 11 лет назад
Родитель
Сommit
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. */