///////////////////////////////////////////////////////////////////////////////
/// @file deMesh.cpp
///
/// @brief mesh class interface
///
/// @author Assassin 
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Aug 2003
/// @author Assassin
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

#if 1
#	undef deConsoleOut
//#	include <windows.h>
#	include "deConsole.hpp"
#else
static inline void thunk_ConsoleOut(char *, ...) {}
#	define deConsoleOut thunk_ConsoleOut
#endif

#include "deMesh_priv.hpp"
#include "deSurface.hpp"
#include "deMath.hpp"
#include "deDriver.hpp"

WorldObjectClassImp(deMesh);
static long s_deMeshWOInterfaceID = -1;

deBoolean IdeMesh_Initialize()
{
	IdeWorldManager * manager = IdeWorld_GetManager();
	s_deMeshWOInterfaceID = manager->GetUniqueWOInterfaceID();
	
	if (!WorldObjectRegister(deMesh))
		return deFALSE;

	return deTRUE;
}

long IdeMesh_GetWOInterfaceID()
{
	return s_deMeshWOInterfaceID;
}

IdeMesh* IdeMesh_CreateMesh()
{
	return new deMesh;
}

deMesh::deMesh()
:	m_MainVertexBuffer(NULL),
	m_MainIndexBuffer(NULL),
	m_BoundRadius(0)
{
	m_BBox.Min = deZeroVec;
	m_BBox.Max = deZeroVec;
}

deMesh::~deMesh()
{
	ClearGeometry();
}

void deMesh::ClearGeometry()
{
	size_t i;
	// release all the vertex buffers and surfaces
	for (i = 0; i < m_SubMeshes.Length(); ++i)
	{
		if (m_SubMeshes[i].IBuffer)
		{
			m_SubMeshes[i].IBuffer->Release();
			m_SubMeshes[i].IBuffer = NULL;
		}
		if (m_SubMeshes[i].VBuffer)
		{
			m_SubMeshes[i].VBuffer->Release();
			m_SubMeshes[i].VBuffer = NULL;
		}
		if (m_SubMeshes[i].Surface)
		{
			m_SubMeshes[i].Surface->Release();
			m_SubMeshes[i].Surface = NULL;
		}
	}
	// eliminate all geometry that was stored here
	m_SubMeshes.Resize(0);
	m_VertexDataList.Resize(0);
	m_IndexDataList.Resize(0);
	if (m_MainVertexBuffer)
		m_MainVertexBuffer->Release();
	m_MainVertexBuffer = NULL;
	if (m_MainIndexBuffer)
		m_MainIndexBuffer->Release();
	m_MainIndexBuffer = NULL;
}

deBoolean deMesh::BuildFromBrushGeometry(IdeBrush* brush)
{
#pragma todo(test deMesh::BuildFromBrushGeometry)

	if (!brush)
		return deFALSE;

	long numsurfaces, k;

	ClearGeometry();

	numsurfaces = brush->GetNumVBs();
	m_SubMeshes.Resize(numsurfaces);

	if (numsurfaces == 0)
		return deTRUE;

	for (k = 0; k < numsurfaces; ++k)
	{
		IdeVertexBuffer* pVB;
		pVB = brush->GetVertexBuffer(k);
		if (!pVB)
			continue;
		long IndexOffset;
		{
			// vertex data
			deMeshVertexData VertexData;
			VertexData.numpoints = pVB->GetVertexCount();
			VertexData.positions = (deVertex*)(pVB->GetBuffer(IdeVertexBuffer::BUFFER_POSITION));
			VertexData.normals = (deVertex*)(pVB->GetBuffer(IdeVertexBuffer::BUFFER_NORMAL));
			VertexData.colors = (deARGB*)(pVB->GetBuffer(IdeVertexBuffer::BUFFER_DIFFUSE));
			VertexData.uvcoords = (deTexCoord*)(pVB->GetBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0));
			VertexData.numtexstages = (VertexData.uvcoords) ? 1 : 0;
			AddVertices(VertexData, IndexOffset);
		}
		{
			// index data
			deMeshIndexData IndexData;
			IdeRenderTexture* pRT;
			pRT = brush->GetTexture(k);
			IndexData.surface = IdeSurface_CreateSurface();
			if (!IndexData.surface)
				return deFALSE;
			IndexData.surface->SetRenderTexture(pRT);
			IndexData.numindices = pVB->GetIndexCount();
			// only one of these should be valid
			IndexData.indices16 = (u16*)(pVB->GetBuffer(IdeVertexBuffer::BUFFER_INDICES16));
			IndexData.indices32 = (u32*)(pVB->GetBuffer(IdeVertexBuffer::BUFFER_INDICES32));
			IndexData.indexoffset = IndexOffset;
			AddIndices(IndexData);
		}
	}
	return BuildFromVertices();
}

deBoolean deMesh::BuildFromVertices()
{
	size_t k, j, n;
	size_t num_verts, num_indices;
	IdeVertexBuffer::BufferType Counter;
	deBoolean BufferMade[IdeVertexBuffer::BUFFER_COUNT] = {0};
	deBoolean Indices32Bit;
	deTexCoord* TexBuffer;
	deTArray<IdeSurface*> SurfacesFound;
	deTArray<int> SurfaceIndices;

	deConsoleOut("deMesh::BuildFromVertices - creating vertex buffers\n");

	// create vertex storage
	if (!m_MainVertexBuffer)
		m_MainVertexBuffer = IdeVertexBuffer_CreateVBuffer();
	if (!m_MainVertexBuffer)
		DEBUGRETURN(deFALSE, "BuildFromVertices - error creating m_MainVertexBuffer");
	// create index storage
	if (!m_MainIndexBuffer)
		m_MainIndexBuffer = IdeVertexBuffer_CreateVBuffer();
	if (!m_MainIndexBuffer)
		DEBUGRETURN(deFALSE, "BuildFromVertices - error creating m_MainIndexBuffer");
	// prepare to set values
	m_MainVertexBuffer->Lock();
	m_MainIndexBuffer->Lock();

	deConsoleOut("deMesh::BuildFromVertices - vertex buffers locked, counting streams\n");
	
	num_verts = 0;
	num_indices = 0;
	Indices32Bit = deFALSE;
	for (k = 0; k < m_VertexDataList.Length(); ++k)
	{
		num_verts += m_VertexDataList[k].numpoints;
		if (m_VertexDataList[k].positions)
			BufferMade[IdeVertexBuffer::BUFFER_POSITION] = deTRUE;
		if (m_VertexDataList[k].normals)
			BufferMade[IdeVertexBuffer::BUFFER_NORMAL] = deTRUE;
		if (m_VertexDataList[k].colors)
			BufferMade[IdeVertexBuffer::BUFFER_DIFFUSE] = deTRUE;
		for (j = 0; j < m_VertexDataList[k].numtexstages; ++j)
		{
			BufferMade[IdeVertexBuffer::BUFFER_TEXTURECOORDS0 + j] = deTRUE;
		}
		if (num_verts > 65535)
			Indices32Bit = deTRUE;
	}

	deConsoleOut("deMesh::BuildFromVertices - streams made, vertex count: %d\n", num_verts);

	for (k = 0; k < m_IndexDataList.Length(); ++k)
	{
		if (m_IndexDataList[k].numindices)
		{
			num_indices += m_IndexDataList[k].numindices;
			if (m_IndexDataList[k].indices32)
				Indices32Bit = deTRUE;
			for (j = 0; j < SurfacesFound.Length(); ++j)
			{
				if (SurfacesFound[j] == m_IndexDataList[k].surface)
				{
					SurfaceIndices[j] += m_IndexDataList[k].numindices;
					break;
				}
			}
			if (j >= SurfacesFound.Length())
			{
				SurfacesFound.ResizeQuick(j+1);
				SurfaceIndices.ResizeQuick(j+1);
				SurfacesFound[j] = m_IndexDataList[k].surface;
				SurfaceIndices[j] = m_IndexDataList[k].numindices;
			}
		}
	}
	
	deConsoleOut("deMesh::BuildFromVertices - indices counted, surface count: %d\n", SurfacesFound.Length());
	
	m_SubMeshes.ResizeQuick(SurfacesFound.Length(), deTRUE);
	for (k = 0; k < SurfacesFound.Length(); ++k)
	{
		IdeSurface* currentsurface = SurfacesFound[k];
		m_SubMeshes[k].Surface = currentsurface;
		if (currentsurface)
			currentsurface->Claim();
		m_SubMeshes[k].VBuffer = NULL;
#pragma fixme(bug in sub-VB regarding resizing after already having data)
//		m_SubMeshes[k].IBuffer = IdeVertexBuffer_CreateSubVBuffer(m_MainIndexBuffer);
		m_SubMeshes[k].IBuffer = IdeVertexBuffer_CreateVBuffer();
		if (!m_SubMeshes[k].IBuffer)
			DEBUGRETURN(deFALSE, "BuildFromVertices - error creating m_SubMeshes[k].IBuffer");
		m_SubMeshes[k].IBuffer->Lock();
		if (Indices32Bit)
		{
			if (!m_SubMeshes[k].IBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_INDICES32, deTRUE))
				DEBUGRETURN(deFALSE, "BuildFromVertices - failure creating BUFFER_INDICES32");
		}
		else
		{
			if (!m_SubMeshes[k].IBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_INDICES16, deTRUE))
				DEBUGRETURN(deFALSE, "BuildFromVertices - failure creating BUFFER_INDICES16");
		}
		m_SubMeshes[k].IBuffer->Unlock();
	}
	
	deConsoleOut("deMesh::BuildFromVertices - setting VB stream sizes. v=%d, i=%d\n",
		num_verts, num_indices);
	
	// set buffer sizes
	if (!m_MainVertexBuffer->SetBufferSize(num_verts, deFALSE))
	{
		deConsoleOut("failure setting num_verts in m_MainVertexBuffer\n");
		DEBUGRETURN(deFALSE, "BuildFromVertices - failure setting num_verts in m_MainVertexBuffer");
	}
	if (!m_MainIndexBuffer->SetBufferSize(num_indices, deTRUE))
	{
		deConsoleOut("failure setting num_indices in m_MainIndexBuffer\n");
		DEBUGRETURN(deFALSE, "BuildFromVertices - failure setting num_indices in m_MainIndexBuffer");
	}

	deConsoleOut("deMesh::BuildFromVertices - creating VB streams\n");
	
	// create the buffers that the mesh has
	for (Counter = IdeVertexBuffer::BUFFER_POSITION; Counter < IdeVertexBuffer::BUFFER_COUNT; ((int&)Counter)++)
	{
		if (BufferMade[Counter])
			m_MainVertexBuffer->CreateBuffer(Counter, deFALSE);
	}
	if (Indices32Bit)
	{
		if (!m_MainIndexBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_INDICES32, deTRUE))
		{
			deConsoleOut("failure creating BUFFER_INDICES32\n");
			DEBUGRETURN(deFALSE, "BuildFromVertices - failure creating BUFFER_INDICES32");
		}
	}
	else
	{
		DE_ASSERT(num_verts < 65536);
		if (!m_MainIndexBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_INDICES16, deTRUE))
		{
			deConsoleOut("failure creating BUFFER_INDICES16\n");
			DEBUGRETURN(deFALSE, "BuildFromVertices - failure creating BUFFER_INDICES16");
		}
	}
	
	deConsoleOut("deMesh::BuildFromVertices - filling vertices\n");
	
	// time to fill the vertices
	num_verts = 0;
	for (k = 0; k < m_VertexDataList.Length(); ++k)
	{
		// fill positions
		m_MainVertexBuffer->FillBuffer(IdeVertexBuffer::BUFFER_POSITION, m_VertexDataList[k].positions, num_verts, m_VertexDataList[k].numpoints);
		// fill normals
		if (m_VertexDataList[k].normals)
		{
			m_MainVertexBuffer->FillBuffer(IdeVertexBuffer::BUFFER_NORMAL, m_VertexDataList[k].normals, num_verts, m_VertexDataList[k].numpoints);
		}
		// fill diffuse colors
		if (m_VertexDataList[k].colors)
		{
			m_MainVertexBuffer->FillBuffer(IdeVertexBuffer::BUFFER_DIFFUSE, m_VertexDataList[k].colors, num_verts, m_VertexDataList[k].numpoints);
		}
		// fill texture coordinates
		for (j = 0; j < m_VertexDataList[k].numtexstages; ++j)
		{
			Counter = (IdeVertexBuffer::BufferType)(IdeVertexBuffer::BUFFER_TEXTURECOORDS0 + j);
			TexBuffer = m_VertexDataList[k].uvcoords;
			TexBuffer += j*m_VertexDataList[k].numpoints;
			m_MainVertexBuffer->FillBuffer(
				(IdeVertexBuffer::BufferType)(IdeVertexBuffer::BUFFER_TEXTURECOORDS0 + j), 
				TexBuffer, num_verts, m_VertexDataList[k].numpoints);
		}

		// keep track of how many vertices have been filled so far
		num_verts += m_VertexDataList[k].numpoints;
	}
	// generate bounding volumes
	if (m_MainVertexBuffer)
	{
		bool FirstVert = true;
		int k, numVerts = m_MainVertexBuffer->GetVertexCount();
		deVertex* positions = (deVertex*)m_MainVertexBuffer->GetBuffer(IdeVertexBuffer::BUFFER_POSITION);
		for (k = 0; k < numVerts; ++k)
		{
			deVec3d vec = deMake_Vec3d(positions[k]);
			if (FirstVert)
			{
				FirstVert = false;
				m_BBox.Min = vec;
				m_BBox.Max = vec;
				m_BoundRadius = 0;
			}
			deGeometry::AABBAddPoint(m_BBox, vec);
			deDouble rad = Vec3d_Length(vec);
			m_BoundRadius = max(m_BoundRadius, rad);
		}
	}
	// done filling data
	m_MainVertexBuffer->Unlock();
	m_MainIndexBuffer->Unlock();

	deConsoleOut("deMesh::BuildFromVertices - filling indices\n");
	
	// and now to fill in all the index data, consolidating same-surface indices into one submesh
	for (k = 0; k < m_IndexDataList.Length(); ++k)
	{
		// find the matching submesh
		for (j = 0; j < m_SubMeshes.Length(); ++j)
		{
			if (m_SubMeshes[j].Surface == m_IndexDataList[k].surface)
				break;
		}
		if (j >= m_SubMeshes.Length())
			continue; // this shouldnt happen

		IdeVertexBuffer* MeshIBuffer = m_SubMeshes[j].IBuffer;
		// some temporary values for faster processing
		num_indices = m_IndexDataList[k].numindices;
		long Offset = m_IndexDataList[k].indexoffset;
		long prev_num_indices = MeshIBuffer->GetIndexCount();
		deConsoleOut("deMesh::BuildFromVertices - processing submesh %d, with (%d) %d-bit indices\n", 
						j, 
						num_indices, 
						(Indices32Bit?32:16));

		if (!MeshIBuffer->Lock())
		{
			deConsoleOut("failure locking MeshIBuffer\n");
			DEBUGRETURN(deFALSE, "BuildFromVertices - failure locking MeshIBuffer");
		}
//		MeshIBuffer->BindDataBuffer(m_MainVertexBuffer);
		MeshIBuffer->SetRenderType(IdeVertexBuffer::RENDER_TRIANGLELIST);
		if (!MeshIBuffer->SetBufferSize(num_indices + MeshIBuffer->GetIndexCount(), deTRUE))
		{
			deConsoleOut("failure setting num_indices in MeshIBuffer\n");
			DEBUGRETURN(deFALSE, "BuildFromVertices - failure setting num_indices in MeshIBuffer");
		}
		
		u32 MaxIndex = 0;
		if (Indices32Bit)
		{
			// 32-bit indices stored, but not all inputs had to use 32-bit also - might need converting
			u32 * IndexBuffer = (u32*)MeshIBuffer->GetBuffer(IdeVertexBuffer::BUFFER_INDICES32);
			deConsoleOut("deMesh::BuildFromVertices - IndexBuffer32 = 0x%.8x\n", IndexBuffer);
			if (!IndexBuffer)
				DEBUGRETURN(deFALSE, "BuildFromVertices - invalid IndexBuffer");
			IndexBuffer += prev_num_indices;
			if (m_IndexDataList[k].indices16)
			{
				u16* pSource = m_IndexDataList[k].indices16;
				for (n = 0; n < num_indices; ++n)
				{
					IndexBuffer[n] = pSource[n] + Offset;
					MaxIndex = max(MaxIndex, pSource[n]);
				}
			}
			else if (m_IndexDataList[k].indices32)
			{
				u32* pSource = m_IndexDataList[k].indices32;
				for (n = 0; n < num_indices; ++n)
				{
					IndexBuffer[n] = pSource[n] + Offset;
					MaxIndex = max(MaxIndex, pSource[n]);
				}
			}
			else
			{
				DEBUGRETURN(deFALSE, "BuildFromVertices - no vertex data (indices16 & indices32 both NULL)");
			}
		}
		else
		{
			// if it's only 16-bit, then all of them have to use indices16
			u16 * IndexBuffer = (u16*)MeshIBuffer->GetBuffer(IdeVertexBuffer::BUFFER_INDICES16);
			deConsoleOut("deMesh::BuildFromVertices - IndexBuffer16 = 0x%.8x\n", IndexBuffer);
			if (!IndexBuffer)
				DEBUGRETURN(deFALSE, "BuildFromVertices - invalid IndexBuffer");
			IndexBuffer += prev_num_indices;
			u16* pSource = m_IndexDataList[k].indices16;
			for (n = 0; n < num_indices; ++n)
			{
				DE_ASSERT(pSource[n] + Offset < 65536);
				IndexBuffer[n] = (u16)(pSource[n] + Offset);
				MaxIndex = max(MaxIndex, pSource[n]);
			}
		}
		MeshIBuffer->Unlock();
		deConsoleOut("deMesh::BuildFromVertices - maximum index = %d\n", MaxIndex);
	}

	deConsoleOut("deMesh::BuildFromVertices - finished successfully\n");
	
	return deTRUE;
}

deBoolean deMesh::AddVertices(const deMeshVertexData & vertexdata, long & indexoffset)
{
	size_t k;
	indexoffset = 0;
	if (!vertexdata.positions)
	{
		deConsoleOut("deMesh::AddVertices - no positions\n");
		return deFALSE;
	}
	for (k = 0; k < m_VertexDataList.Length(); ++k)
	{
		indexoffset += m_VertexDataList[k].numpoints;
	}
	if (!m_VertexDataList.PushBack(vertexdata))
		return deFALSE;
	return deTRUE;
}

deBoolean deMesh::AddIndices(const deMeshIndexData & indexdata)
{
	if (indexdata.numindices == 0)
		return deTRUE;
	if (!(indexdata.indices16 || indexdata.indices32))
		return deFALSE;
	return m_IndexDataList.PushBack(indexdata);
}

long deMesh::GetNumSubMeshes()
{
	return m_SubMeshes.Length();
}

#pragma todo (test the manual-build routines)
void deMesh::SetNumSubMeshes(u32 NumSubs, deBoolean Dynamic)
{
	// destroy existing meshes
	ClearGeometry();
	m_MainVertexBuffer = IdeVertexBuffer_CreateVBuffer();
	m_MainVertexBuffer->Lock();
	m_MainVertexBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_POSITION, deFALSE);
	m_MainVertexBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_DIFFUSE, deFALSE);
	m_MainVertexBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0, deFALSE);
	m_MainVertexBuffer->SetDynamicStatus(Dynamic, deFALSE);
	m_MainVertexBuffer->Unlock();
	m_SubMeshes.ResizeQuick(NumSubs, deTRUE);
}

deBoolean deMesh::SetSurface(u32 SubNum, IdeSurface* Surface)
{
	u32 len = m_SubMeshes.size();
	if (SubNum < 0 || SubNum >= len)
		DEBUGRETURN(deFALSE, "SetSurface - invalid array index");

	if (Surface)
		Surface->Claim();
	if (m_SubMeshes[SubNum].Surface)
		m_SubMeshes[SubNum].Surface->Release();
	m_SubMeshes[SubNum].Surface = Surface;

	return deTRUE;
}

IdeSurface* deMesh::GetSurface(u32 SubNum)
{
	u32 len = m_SubMeshes.size();
	if (SubNum < 0 || SubNum >= len)
		DEBUGRETURN(NULL, "SetSurface - invalid array index");
	
	return m_SubMeshes[SubNum].Surface;
}

deBoolean deMesh::SetNumFaces(u32 SubNum, u32 NumFaces)
{
	u32 len = m_SubMeshes.size();
	if (SubNum < 0 || SubNum >= len)
		DEBUGRETURN(deFALSE, "SetSurface - invalid array index");

	IdeVertexBuffer* VB = m_SubMeshes[SubNum].VBuffer;
	if (!VB)
	{
		m_SubMeshes[SubNum].VBuffer = IdeVertexBuffer_CreateSubVBuffer(m_MainVertexBuffer);
		VB = m_SubMeshes[SubNum].VBuffer;
		if (!VB)
			DEBUGRETURN(deFALSE, "SetNumFaces - error creating sub-VB");
	}
	if (!VB->Lock())
		return deFALSE;
	if (!VB->SetBufferSize(NumFaces*3, deFALSE))
		return deFALSE;
	VB->SetRenderType(IdeVertexBuffer::RENDER_TRIANGLELIST);
	VB->Unlock();
	return deTRUE;
}

u32 deMesh::GetNumFaces(u32 SubNum)
{
	u32 len = m_SubMeshes.size();
	if (SubNum < 0 || SubNum >= len)
		DEBUGRETURN(deFALSE, "SetSurface - invalid array index");

	IdeVertexBuffer* VB = m_SubMeshes[SubNum].VBuffer;
	if (!VB)
		return 0;
	return VB->GetVertexCount() / 3;
}

deBoolean deMesh::Lock(deVertex** &positions, deTexCoord2** &uvcoords, deARGB** &colors)
{
	int i, len = m_SubMeshes.size();
	positions = new deVertex*[len];
	uvcoords = new deTexCoord2*[len];
	colors = new deARGB*[len];
	if (!positions || !uvcoords || !colors)
	{
		delete[] positions;
		delete[] uvcoords;
		delete[] colors;
		positions = NULL;
		uvcoords = NULL;
		colors = NULL;
		DEBUGRETURN(deFALSE, "Lock - error allocating memory");
	}
	memset(positions, 0xff, len*sizeof(deVertex*));
	memset(uvcoords, 0xff, len*sizeof(deTexCoord2*));
	memset(colors, 0xff, len*sizeof(deARGB*));
	for (i = 0; i < len; ++i)
	{
		IdeVertexBuffer* VB = m_SubMeshes[i].VBuffer;
		if (VB)
		{
			if (!VB->Lock())
			{
				for (; i >= 0; --i)
				{
					VB = m_SubMeshes[i].VBuffer;
					if (VB)
						VB->Unlock();
				}
				delete[] positions;
				delete[] uvcoords;
				delete[] colors;
				positions = NULL;
				uvcoords = NULL;
				colors = NULL;
				return deFALSE;
			}
			positions[i] = (deVertex*)(VB->GetBuffer(IdeVertexBuffer::BUFFER_POSITION));
			colors[i] = (deARGB*)(VB->GetBuffer(IdeVertexBuffer::BUFFER_DIFFUSE));
			uvcoords[i] = (deTexCoord2*)(VB->GetBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0));
		}
	}
	return deTRUE;
}

deBoolean deMesh::Unlock(deVertex** &positions, deTexCoord2** &uvcoords, deARGB** &colors)
{
	int i, len = m_SubMeshes.size();
	bool FirstVert = true;
	for (i = 0; i < len; ++i)
	{
		IdeVertexBuffer* VB = m_SubMeshes[i].VBuffer;
		if (VB)
		{
			int k, numVerts = VB->GetVertexCount();
			for (k = 0; k < numVerts; ++k)
			{
				deVec3d vec = deMake_Vec3d(positions[i][k]);
				if (FirstVert)
				{
					FirstVert = false;
					m_BBox.Min = vec;
					m_BBox.Max = vec;
					m_BoundRadius = 0;
				}
				deGeometry::AABBAddPoint(m_BBox, vec);
				deDouble rad = Vec3d_Length(vec);
				m_BoundRadius = max(m_BoundRadius, rad);
			}
			VB->DirtyBuffer(IdeVertexBuffer::BUFFER_POSITION);
			VB->DirtyBuffer(IdeVertexBuffer::BUFFER_DIFFUSE);
			VB->DirtyBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0);
			VB->Unlock();
		}
	}
	delete[] positions;
	delete[] uvcoords;
	delete[] colors;
	positions = NULL;
	uvcoords = NULL;
	colors = NULL;
	return deTRUE;
}

IdeVertexBuffer* deMesh::GetMainVertexBuffer()
{
	return m_MainVertexBuffer;
}

IdeVertexBuffer* deMesh::GetSubMeshVertexBuffer(long index)
{
	if (index < 0 || index >= m_SubMeshes.Length())
		return NULL;
	return m_SubMeshes[index].VBuffer;
}

IdeVertexBuffer* deMesh::GetSubMeshIndexBuffer(long index)
{
	if (index < 0 || index >= m_SubMeshes.Length())
		return NULL;
	return m_SubMeshes[index].IBuffer;
}

IdeSurface* deMesh::GetSubMeshSurface(long index)
{
	if (index < 0 || index >= m_SubMeshes.Length())
		return NULL;
	return m_SubMeshes[index].Surface;
}

deDouble deMesh::GetBoundRadius()
{
	return m_BoundRadius;
}

void deMesh::GetBBox(deAABB& outBox)
{
	outBox = m_BBox;
}

void* deMesh::GetWOInterface(long interface_id)
{
	if (interface_id == s_deMeshWOInterfaceID)
		return (IdeMesh*)(this);
	if (interface_id == 0)
		return (IdeWorldObject*)(this);
	return NULL;
}

static deBoolean SerializeVBuffer(IdeVertexBuffer* VB, IdeFile* FS);
static deBoolean DeSerializeVBuffer(IdeVertexBuffer* VB, IdeFile* FS, u32& AmtRead, long DataLength);
struct deMesh_Header_t
{
	short VersionMajor;
	short VersionMinor;
};
static const deMesh_Header_t deMesh_Header = {0,1};
/*
Version 0.1:
December 17, 2003

u16		Version_Major
u16		Version_Minor
u32		NumSubMeshes
foreach(mesh)
	u16			SurfaceWID
	u32			SurfaceOID
	VBuffer		SubMeshIB
VBuffer	MainVB
*/
deBoolean deMesh::Serialize(IdeFile* FS)
{
	deConsoleOut("deMesh::Serialize\n");
	
	if (!FS)
		return deFALSE;

	long length;
	deObjectID	ObjectID;
	deWorldID	WorldID;
	IdeWorld*	pWorld;
	deBoolean TrueVal = deTRUE, FalseVal = deFALSE;

	// header information
	DE3D_STREAM_PUT(FS, deMesh_Header.VersionMajor, u16);
	DE3D_STREAM_PUT(FS, deMesh_Header.VersionMinor, u16);
	
	// number of submeshes
	length = m_SubMeshes.Length();
	DE3D_STREAM_PUT(FS, length, u32);
	// submeshes
	deTArray<deSubMesh>::iterator mesh, mesh_end;
	mesh_end = m_SubMeshes.end();
	for (mesh = m_SubMeshes.begin(); mesh != mesh_end; ++mesh)
	{
		deConsoleOut("deMesh::Serialize - mesh 0x%.8x\n", mesh);
		WorldID = 0;
		ObjectID = 0;
		IdeSurface* surface = mesh->Surface;
		if (surface)
		{
			// convert the world ID
			WorldID = surface->GetWorldID();
			pWorld = IdeWorld_GetManager()->GetWorld(((IdeWorldObject*)this)->GetWorldID());
			if (pWorld)
			{
				WorldID = pWorld->GetLocalIDFromLoadedWorld(WorldID);
				ObjectID = surface->GetObjectID();
			}
			else
				WorldID = 0;
		}
		deConsoleOut("WorldID %d", WorldID);
		deConsoleOut(", ObjectID %d", ObjectID);
		DE3D_STREAM_PUT(FS, WorldID, u16); //sizeof(deWorldID)
		DE3D_STREAM_PUT(FS, ObjectID, int); //sizeof(deObjectID)
		if (!mesh->IBuffer->Lock())
			return deFALSE;
		if (!SerializeVBuffer(mesh->IBuffer, FS))
		{
			mesh->IBuffer->Unlock();
			return deFALSE;
		}
		mesh->IBuffer->Unlock();
		if (mesh->VBuffer)
		{
			if (!FS->Write(&TrueVal, 1))
				return deFALSE;
			if (!mesh->VBuffer->Lock())
				return deFALSE;
			if (!SerializeVBuffer(mesh->VBuffer, FS))
			{
				mesh->VBuffer->Unlock();
				return deFALSE;
			}
			mesh->VBuffer->Unlock();
		}
		else
		{
			if (!FS->Write(&FalseVal, 1))
				return deFALSE;
		}
		deConsoleOut(", IBuffer written\n");
	}
	if (!m_MainVertexBuffer->Lock())
		return deFALSE;
	if (!SerializeVBuffer(m_MainVertexBuffer, FS))
	{
		m_MainVertexBuffer->Unlock();
		return deFALSE;
	}
	m_MainVertexBuffer->Unlock();
	deConsoleOut("VBuffer written\n");
	return deTRUE;
}

deBoolean deMesh::DeSerialize(IdeFile* FS, long DataLength)
{
	ClearGeometry();

	int i;
	i = sizeof(unsigned long);
	i = sizeof(unsigned int);
	i = sizeof(u32);
	i = sizeof(s32);
	i = sizeof(deObjectID);

	u32 AmtRead = 0;
	
	u16 VersionMajor, VersionMinor;
	// header information
	DE3D_STREAM_GET(FS, VersionMajor, u16, AmtRead, DataLength);
	DE3D_STREAM_GET(FS, VersionMinor, u16, AmtRead, DataLength);
	
	// check the version
	if (VersionMajor > deMesh_Header.VersionMajor ||
		(VersionMajor == deMesh_Header.VersionMajor && VersionMinor > deMesh_Header.VersionMinor))
		return deFALSE;
	
	if (VersionMajor == 0 && VersionMinor == 1)
	{
		u32 i, k;
		DE3D_STREAM_GET(FS, k, u32, AmtRead, DataLength);
		m_SubMeshes.Resize(k);
		m_TempSubMeshes.Resize(k);
		m_MainIndexBuffer = IdeVertexBuffer_CreateVBuffer();
		for (i = 0; i < k; ++i)
		{
			deSubMesh * mesh = &(m_SubMeshes[i]);
			SubMeshDescriptor * tempmesh = &(m_TempSubMeshes[i]);
			DE3D_STREAM_GET(FS, tempmesh->WorldID, u16, AmtRead, DataLength); //sizeof(deWorldID)
			DE3D_STREAM_GET(FS, tempmesh->ObjectID, u32, AmtRead, DataLength); //sizeof(deObjectID)
			mesh->Surface = NULL;
			mesh->IBuffer = IdeVertexBuffer_CreateSubVBuffer(m_MainIndexBuffer);
			mesh->IBuffer->Lock();
			if (!DeSerializeVBuffer(mesh->IBuffer, FS, AmtRead, DataLength))
			{
				mesh->IBuffer->Unlock();
				return deFALSE;
			}
			mesh->IBuffer->Unlock();
			deBoolean HasVBuffer;
			if (1 != FS->Read(&HasVBuffer, 1))
				return deFALSE;
			if (HasVBuffer)
			{
				mesh->VBuffer = IdeVertexBuffer_CreateSubVBuffer(m_MainVertexBuffer);
				mesh->VBuffer->Lock();
				if (!DeSerializeVBuffer(mesh->VBuffer, FS, AmtRead, DataLength))
				{
					mesh->VBuffer->Unlock();
					return deFALSE;
				}
				mesh->VBuffer->Unlock();
			}
			else
			{
				mesh->VBuffer = NULL;
			}
		}
		m_MainVertexBuffer = IdeVertexBuffer_CreateVBuffer();
		m_MainVertexBuffer->Lock();
		if (!DeSerializeVBuffer(m_MainVertexBuffer, FS, AmtRead, DataLength))
		{
			m_MainVertexBuffer->Unlock();
			return deFALSE;
		}
		m_MainVertexBuffer->Unlock();
		for (i = 0; i < k; ++i)
		{
			m_SubMeshes[i].VBuffer = NULL;
		}

		return deTRUE;
	}
	
	// invalid format here
	return deFALSE;
}

deBoolean deMesh::DeSerializeLoad()
{
	deWorldID wid;
	deObjectID oid;
	u32 i,k;
	IdeWorldManager* manager;
	manager = IdeWorld_GetManager();
	k = m_TempSubMeshes.size();
	for (i = 0; i < k; ++i)
	{
		IdeWorldObject* pObject;
		IdeSurface * surface = NULL;;
		wid = m_TempSubMeshes[i].WorldID;
		if (wid)
		{
			oid = m_TempSubMeshes[i].ObjectID;
			pObject = manager->GetWorldObject(wid, oid);
			if (pObject)
				surface = (IdeSurface*)pObject->GetWOInterface(IdeSurface_GetWOInterfaceID());
			else
				DEBUGMSG2("deMesh::DeSerializeLoad - failure loading object with WID=%d and OID=%d", wid, oid);
		}
		if (surface)
		{
			surface->Claim();
			m_SubMeshes[i].Surface = surface;
		}
	}
	return deTRUE;
}





struct deVBuffer_Header_t
{
	short VersionMajor;
	short VersionMinor;
};
static const deVBuffer_Header_t deVBuffer_Header = {0,1};
/*
Version 0.1:
December 17, 2003

u16		Version_Major
u16		Version_Minor
u32		VertexCount
u32		IndexCount
u32		RenderType
u8		DynamicVertex
u8		DynamicIndex
foreach(buffer)
	u8	BufferExists
	if(BufferExists)
		byte[Count*DataSize]	Buffer;
*/

static deBoolean SerializeVBuffer(IdeVertexBuffer* VB, IdeFile* FS)
{
	//deConsoleOut("SerializeVBuffer\n");
	u32 k;
	int VertexCount, IndexCount;
	
	// header information
	DE3D_STREAM_PUT(FS, deVBuffer_Header.VersionMajor, u16);
	DE3D_STREAM_PUT(FS, deVBuffer_Header.VersionMinor, u16);
	
	// stream sizes
	VertexCount = VB->GetVertexCount();
	DE3D_STREAM_PUT(FS, VertexCount, u32);
	IndexCount = VB->GetIndexCount();
	DE3D_STREAM_PUT(FS, IndexCount, u32);
	k = VB->GetRenderType();
	DE3D_STREAM_PUT(FS, k, u32);
	k = VB->GetDynamicStatusVertex();
	DE3D_STREAM_PUT(FS, k, u8);
	k = VB->GetDynamicStatusIndex();
	DE3D_STREAM_PUT(FS, k, u8);
	
	int i;
	u8 HasBuffer[IdeVertexBuffer::BUFFER_COUNT];
	for (i = 0; i < IdeVertexBuffer::BUFFER_COUNT; ++i)
	{
		HasBuffer[i] = VB->BufferExists((IdeVertexBuffer::BufferType)i);
		DE3D_STREAM_PUT(FS, HasBuffer[i], u8);
	}
	for (i = 0; i < IdeVertexBuffer::BUFFER_COUNT; ++i)
	{
		if (HasBuffer[i])
		{
			long size;
			void * buffer = VB->GetBuffer((IdeVertexBuffer::BufferType)i);
			VB->GetBufferDataType((IdeVertexBuffer::BufferType)i, &size);
			if (i < IdeVertexBuffer::BUFFER_INDICES16)
			{
				DE3D_STREAM_PUTP(FS, buffer, VertexCount*size);
			}
			else
			{
				DE3D_STREAM_PUTP(FS, buffer, IndexCount*size);
			}
		}
	}
	
	return deTRUE;
}

static deBoolean DeSerializeVBuffer(IdeVertexBuffer* VB, IdeFile* FS, u32& AmtRead, long DataLength)
{
	u16 VersionMajor, VersionMinor;
	// header information
	DE3D_STREAM_GET(FS, VersionMajor, u16, AmtRead, DataLength);
	DE3D_STREAM_GET(FS, VersionMinor, u16, AmtRead, DataLength);
	
	// check the version
	if (VersionMajor > deVBuffer_Header.VersionMajor ||
		(VersionMajor == deVBuffer_Header.VersionMajor && VersionMinor > deVBuffer_Header.VersionMinor))
		return deFALSE;
	
	if (VersionMajor == 0 && VersionMinor == 1)
	{
		u32 VertexCount, IndexCount;

		// stream sizes
		DE3D_STREAM_GET(FS, VertexCount, u32, AmtRead, DataLength);
		DE3D_STREAM_GET(FS, IndexCount, u32, AmtRead, DataLength);
		u32 rtype;
		DE3D_STREAM_GET(FS, rtype, u32, AmtRead, DataLength);
		u8 DynVert, DynIdx;
		DE3D_STREAM_GET(FS, DynVert, u8, AmtRead, DataLength);
		DE3D_STREAM_GET(FS, DynIdx, u8, AmtRead, DataLength);

		VB->SetBufferSize(VertexCount, deFALSE);
		VB->SetBufferSize(IndexCount, deTRUE);
		VB->SetRenderType((IdeVertexBuffer::RenderType)rtype);
		VB->SetDynamicStatus(DynVert, DynIdx);
		
		int i;
		u8 HasBuffer[IdeVertexBuffer::BUFFER_COUNT];
		for (i = 0; i < IdeVertexBuffer::BUFFER_COUNT; ++i)
		{
			DE3D_STREAM_GET(FS, HasBuffer[i], u8, AmtRead, DataLength);
		}
		for (i = 0; i < IdeVertexBuffer::BUFFER_COUNT; ++i)
		{
			if (HasBuffer[i])
			{
				VB->CreateBuffer((IdeVertexBuffer::BufferType)i, deFALSE);
				long size;
				void * buffer = VB->GetBuffer((IdeVertexBuffer::BufferType)i);
				VB->GetBufferDataType((IdeVertexBuffer::BufferType)i, &size);
				if (i < IdeVertexBuffer::BUFFER_INDICES16)
				{
					DE3D_STREAM_GETP(FS, buffer, VertexCount*size, AmtRead, DataLength);
				}
				else
				{
					DE3D_STREAM_GETP(FS, buffer, IndexCount*size, AmtRead, DataLength);
				}
				VB->DirtyBuffer((IdeVertexBuffer::BufferType)i);
			}
		}
		VB->SetBufferSize(IndexCount, deTRUE);
		return deTRUE;
	}
	
	// invalid format here
	return deFALSE;
}
