///////////////////////////////////////////////////////////////////////////////
/// @file deAnimatedMesh.cpp
///
/// @brief Animated mesh loading code
///
/// @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 Jun 2002
/// @author Assassin
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

//A feeble attempt at an actor class
#include "deList.hpp"
#include "deAnimatedMesh_priv.hpp"
#include "MD2.h"
#include "deMath.hpp"
#include "deDriver.hpp"
#include "deRenderStates.hpp"
#include "deBitmap.hpp"
#include "deFileSystem.hpp"
#include "deFile.hpp"

long deAnimatedMesh::s_AnimatedMeshInterfaceID = 0;

static IdeResourceBase*
deAnimatedMesh_LoadMD2(const char *filename, IdeFile *file, deBoolean /*isThreaded*/)
{
#pragma todo(make this function actually use the arguments properly)
	deAnimatedMesh				*act;

	return new deAnimatedMesh((const char *)filename);
}

ACTOR_API void IdeAnimatedMesh_Initialize()
{
	IdeResourceManager * Manager = IdeResourceManager_GetManager();
	Manager->RegisterResourceType("md2", deAnimatedMesh_LoadMD2);
	deAnimatedMesh::s_AnimatedMeshInterfaceID = Manager->GetUniqueInterfaceID();
}

ACTOR_API long IdeAnimatedMesh_GetRscInterfaceID()
{
	return deAnimatedMesh::s_AnimatedMeshInterfaceID;
}


bool deAnimatedMesh::LoadMD2(const char *filename)
{
	IdeFSReal			*filesys;
	IdeFile				*file;
	MD2Header			header;
	int					i, j;
	bool				foundanim;

//	MessageBox(NULL, "Entered the LoadMD2() function!!", "Test", 48);
	//Create a deFSReal object and open the file
	filesys = IdeFileSystem_CreateFSReal();
	if (!filesys)
	{
		DEBUGRETURN(false, "Could not create file object!!");
	}

	file = filesys->Open(filename, deFile_Open_Existing | deFile_Open_Read);
	if (!file)
	{
		filesys->Release();
		DEBUGRETURN(false, "Could not open MD2 file!!");
	}

	//Make sure we are at the beginning of the file
	file->SetPosition(0, deFile_Seek_Start);

	//Read in the MD2 header
	file->Read((void*)&header, sizeof(MD2Header));

	//Set up the values
	this->m_NumFrames = header.numFrames;
	this->m_NumSkins = header.numSkins;
	this->m_NumTexCoords = header.numST;
	this->m_NumTriangles = header.numTris;
	this->m_NumVertices = header.numXYZ;

	//Prepare the arrays
	this->m_pFrames = new MD2Frame[this->m_NumFrames];
	if (!this->m_pFrames)
	{
//		MessageBox(NULL, "Could not create the frame array!!", "Test", 48);
		file->Close();
		file->Release();
		filesys->Release();
		return false;
	}

	this->m_pSkins = new MD2Skin[this->m_NumSkins];
	if (!this->m_pSkins)
	{
//		MessageBox(NULL, "Could not create skin array!!", "Test", 48);
		DE3D_SAFE_DELETE_ARRAY(this->m_pFrames);
		file->Close();
		file->Release();
		filesys->Release();
		return false;
	}

	this->m_pTexCoords = new MD2TexCoord[this->m_NumTexCoords];
	if (!this->m_pTexCoords)
	{
//		MessageBox(NULL, "Could not create the texture coordinate array!!", "Test", 48);
		DE3D_SAFE_DELETE_ARRAY(this->m_pSkins);
		DE3D_SAFE_DELETE_ARRAY(this->m_pFrames);
		file->Close();
		file->Release();
		filesys->Release();
		return false;
	}

	this->m_pTriangles = new MD2Face[this->m_NumTriangles];
	if (!this->m_pTriangles)
	{
//		MessageBox(NULL, "Could not create the face array!!", "Test", 48);
		DE3D_SAFE_DELETE_ARRAY(this->m_pTexCoords);
		DE3D_SAFE_DELETE_ARRAY(this->m_pSkins);
		DE3D_SAFE_DELETE_ARRAY(this->m_pFrames);
		file->Close();
		file->Release();
		filesys->Release();
		return false;
	}

	//Read in the skin information
	if (this->m_NumSkins > 0)
	{
		file->SetPosition(header.offsetSkins, deFile_Seek_Start);
		for (i = 0; i < this->m_NumSkins; i++)
			file->Read((void*)&this->m_pSkins[i], sizeof(MD2Skin));
	}
	
	//Read in the texture coordinates
	if (this->m_NumTexCoords > 0)
	{
		file->SetPosition(header.offsetST, deFile_Seek_Start);
		for (i = 0; i < this->m_NumTexCoords; i++)
		{
			file->Read((void*)&this->m_pTexCoords[i], sizeof(MD2TexCoord));
		}
	}

	//Read in the triangle info
	if (this->m_NumTriangles > 0)
	{
		file->SetPosition(header.offsetTris, deFile_Seek_Start);
		for (i = 0; i < this->m_NumTriangles; i++)
			file->Read((void*)&this->m_pTriangles[i], sizeof(MD2Face));
	}

	//Read in the frames
	if (this->m_NumFrames > 0)
	{
		MD2FrameData			data;
		char					buffer[20];
		
		file->SetPosition(header.offsetFrames, deFile_Seek_Start);
		for (i = 0; i < this->m_NumFrames; i++)
		{
			this->m_pFrames[i].vertices = new MD2Triangle[this->m_NumVertices];
			if (!this->m_pFrames[i].vertices)
				break;
		
			file->Read((void*)&data, sizeof(float)*6+16);
			{
				j = strlen (data.name);
				strcpy(this->m_pFrames[i].name, data.name);
				memcpy(buffer, data.name, j-3);
				buffer[j-3] = '\0';
			}
			foundanim = false;
			for (j = 0; j < m_Anims.Length(); ++j)
			{
				if (m_Anims[j].AnimName == buffer)
				{
					foundanim = true;
					break;
				}
			}
			if (!foundanim)
			{
				deTArray<MD2Anim>::iterator it = m_Anims.IncrementSize();
				it->AnimName = buffer;
				it->Start = i;
			}
			m_Anims[j].Stop = i;
			
			data.vertices = new MD2TriangleVertex[this->m_NumVertices];

			file->Read((void*)data.vertices, sizeof(MD2TriangleVertex) * this->m_NumVertices);

			for (j = 0; j < this->m_NumVertices; j++)
			{
				this->m_pFrames[i].vertices[j].vert.x = data.vertices[j].vertex[0] * data.scale[0] + data.translation[0];
				this->m_pFrames[i].vertices[j].vert.y = data.vertices[j].vertex[2] * data.scale[2] + data.translation[2];
				this->m_pFrames[i].vertices[j].vert.z = data.vertices[j].vertex[1] * data.scale[1] + data.translation[1];
			}

			DE3D_SAFE_DELETE_ARRAY(data.vertices);
		}
	}

	file->Close();
	file->Release();
	filesys->Release();
	return true;
}

void deAnimatedMesh::InitVars()
{
	m_CurrentFrame = 0;
	m_CurrentAnim = 0;
	m_AnimSpeed = 5.0f;
	m_Interpolation = 0.0f;
	m_NextFrame = 0;
	m_NumFrames = 0;
	m_NumSkins = 0;
	m_NumTexCoords = 0;
	m_NumTriangles = 0;
	m_NumVertices = 0;
	
	m_pFrames = NULL;
	m_pSkins = NULL;
	m_pTriangles = NULL;
	m_pTexCoords = NULL;
	m_pVertices = NULL;
	m_pNormals = NULL;
	
	m_pTexture = NULL;
	m_pBitmap = NULL;
	m_pVBuffer = NULL;
}

deAnimatedMesh::deAnimatedMesh()
 : deResourceBase()
{
	InitVars();
}

deAnimatedMesh::deAnimatedMesh(const char *filename)
 : deResourceBase((char*)filename)
{
	InitVars();
	
	//AttachDriver(drv);
	if (!LoadFromFile(filename))
		throw;
//		MessageBox(NULL, "Could not load MD2!!", "Test", 48);
}

deAnimatedMesh::~deAnimatedMesh()
{
	Destroy();
}

void * deAnimatedMesh::GetRscInterface(long interface_id)
{
	if (interface_id == s_AnimatedMeshInterfaceID)
	{
		return (IdeAnimatedMesh*)(this);
	}
	if (interface_id == 0)
	{
		return (IdeResourceBase*)(this);
	}
	return NULL;
}

struct index_container
{
	index_container * next;
	int index;
};
struct index_pair
{
	int tex;
	index_container *verts;
};

deBoolean deAnimatedMesh::LoadFromFile(const char *filename)
{
	if (!LoadMD2(filename))
	{
//		MessageBox(NULL, "Could not load MD2!!", "Test", 48);
		return deFALSE;
	}

	deVertex	**OldVertices;
	deVertex	**OldNormals;
	deTexCoord*	OldTexCoords;
	deTexCoord*	NewTexCoords;
	void *		ptr;
	short *		VertIndices;
	short *		TexIndices;
	short *		Indices;
	int i, j, x, NumIndices;

	NumIndices = m_NumTriangles * 3;

	if (m_pVBuffer)
		m_pVBuffer->Release();
	m_pVBuffer = IdeVertexBuffer_CreateVBuffer();

	// lock the vbuffer so we can fill in texture coords and indices
	m_pVBuffer->Lock();

	m_pVBuffer->SetDynamicStatus(deTRUE, deFALSE);

	// create the 2 buffers we'll be dealing with
	if (!m_pVBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0, deFALSE))
		return deFALSE;
	if (!m_pVBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_INDICES16, deFALSE))
		return deFALSE;

	// set our buffer sizes
	m_pVBuffer->SetBufferSize(NumIndices, deTRUE);
	m_pVBuffer->SetBufferSize(NumIndices, deFALSE);
	
	// grab pointers to the memory
	NewTexCoords = (deTexCoord*)m_pVBuffer->GetBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0);
	Indices = (short*)m_pVBuffer->GetBuffer(IdeVertexBuffer::BUFFER_INDICES16);


	// grab some memory to work with
	OldVertices =	new deVertex*[m_NumFrames];
	OldNormals =	new deVertex*[m_NumFrames];
	m_pVertices	=	new deVertex*[m_NumFrames];
	m_pNormals =	new deVertex*[m_NumFrames];
	OldTexCoords =	new deTexCoord[m_NumTexCoords];
	VertIndices	=	new short[NumIndices];
	TexIndices =	new short[NumIndices];
	for (i = 0; i < m_NumFrames; i++)
	{
		// make a buffer for each frame
		OldVertices[i] = new deVertex[m_NumVertices];
		OldNormals[i]  = new deVertex[m_NumVertices];
		m_pVertices[i] = new deVertex[NumIndices];
		m_pNormals[i]  = new deVertex[NumIndices];
	}

	// initialize some values
	for (j = 0; j < m_NumFrames; j++)
	{
		for (i = 0; i < m_NumVertices; i++)
		{
			OldVertices[j][i] = m_pFrames[j].vertices[i].vert;
			m_pFrames[j].vertices[i].normal = deMake_Vertex(0,0,0);
		}
	}

	// format the texture coordinates properly
	for (i = 0; i < m_NumTexCoords; i++)
	{
		OldTexCoords[i].u = m_pTexCoords[i].s / 256.0f;
		OldTexCoords[i].v = m_pTexCoords[i].t / 256.0f;
	}

	// copy the faces' vertex indices
	for (i = 0; i < m_NumTriangles; i++)
	{
		VertIndices[i*3+0] = m_pTriangles[i].vertexIndices[0];
		VertIndices[i*3+1] = m_pTriangles[i].vertexIndices[2];
		VertIndices[i*3+2] = m_pTriangles[i].vertexIndices[1];
		TexIndices[i*3+0] = m_pTriangles[i].textureIndices[0];
		TexIndices[i*3+1] = m_pTriangles[i].textureIndices[2];
		TexIndices[i*3+2] = m_pTriangles[i].textureIndices[1];
	}

	// find normals for all the faces
	deVec3d Norm, vec1, vec2, vec3;
	deVertex TempVert;
	for (j = 0; j < m_NumFrames; j++)
	{
		for (i = 0; i < m_NumTriangles; i++)
		{
			vec1 = deMake_Vec3d(OldVertices[j][VertIndices[i*3+0]]);
			vec2 = deMake_Vec3d(OldVertices[j][VertIndices[i*3+1]]);
			vec3 = deMake_Vec3d(OldVertices[j][VertIndices[i*3+2]]);
			vec3 = (vec3-vec1);
			vec2 = (vec2-vec1);
			Norm = Vec3d_Cross(vec2, vec3);
			vec1 = deMake_Vec3d(m_pFrames[j].vertices[m_pTriangles[i].vertexIndices[0]].normal);
			vec2 = deMake_Vec3d(m_pFrames[j].vertices[m_pTriangles[i].vertexIndices[1]].normal);
			vec3 = deMake_Vec3d(m_pFrames[j].vertices[m_pTriangles[i].vertexIndices[2]].normal);
			// composite the normals onto each vertex
			vec1 += Norm;
			TempVert = deMake_Vertex(vec1);
			m_pFrames[j].vertices[m_pTriangles[i].vertexIndices[0]].normal = TempVert;
			vec2 += Norm;
			TempVert = deMake_Vertex(vec2);
			m_pFrames[j].vertices[m_pTriangles[i].vertexIndices[1]].normal = TempVert;
			vec3 += Norm;
			TempVert = deMake_Vertex(vec3);
			m_pFrames[j].vertices[m_pTriangles[i].vertexIndices[2]].normal = TempVert;
		}
		for (i = 0; i < m_NumVertices; i++)
		{
			Norm = deMake_Vec3d(m_pFrames[j].vertices[i].normal);
			Vec3d_Normalize(Norm);
			OldNormals[j][i] = deMake_Vertex(Norm);
		}
	}

	// the following code is used to create a properly textured index buffer for the mesh
	x = 0;
	index_container * container = NULL, *next_cont = NULL;
	bool found;
	index_pair temp_pair, *temp_pair2;
	// we keep a list of all the VertIndex-TexIndex pairs so that each vertex can be copied
	// only 1 time for each combination of the two is found
	deTList <index_pair> TexCoordList;
	// cycle through all the vertices, finding all needed copies of each vertex
	for (i = 0; i < m_NumVertices; i++)
	{
		// start with 0 found combinations
		TexCoordList.EmptyList();
		for (j = 0; j < NumIndices; j++)
		{
			// cycle through the index list, looking for references to current vertex
			if (VertIndices[j] == i)
			{
				// we found one, record the texture coord index for the same face-vertex
				temp_pair.tex = TexIndices[j];
				// see if we've already stored a copy of this particular combination
				found = false;
				ptr = TexCoordList.GetNext(NULL, temp_pair2);
				while (!found && ptr)
				{
					if (temp_pair2->tex == temp_pair.tex)
					{
						// we found an existing copy of this combination
						// but the index buffer still needs to record where this vertex is
						found = true;
						container = new index_container;
						container->index = j;
						container->next = temp_pair2->verts;
						temp_pair2->verts = container;
					}
					ptr = TexCoordList.GetNext(ptr, temp_pair2);
				}
				if (!found)
				{
					// didn't find a copy, so make one and store it in the list
					temp_pair.verts = new index_container;
					temp_pair.verts->next = NULL;
					temp_pair.verts->index = j;
					TexCoordList.AddElement(temp_pair);
				}
			}
		}
		// cycle through all the combinations found
		ptr = TexCoordList.RemoveElementGetNext(NULL, temp_pair2);
		while (ptr)
		{
			// gotta modify the vertex data for all the frames
			for (j = 0; j < m_NumFrames; j++)
			{
				m_pVertices[j][x] = OldVertices[j][i];
				m_pNormals [j][x] = OldNormals [j][i];
			}
			// copy the texcoords from their place in the texcoord array into our vertex buffer
			NewTexCoords[x] = OldTexCoords[temp_pair2->tex];
			container = temp_pair2->verts;
			while (container)
			{
				// for each instance of the combination, a different element
				// in the index buffer needs to be recorded
				next_cont = container->next;
				Indices[container->index] = (short)x;
				delete container;
				container = next_cont;
			}
			x++;
			ptr = TexCoordList.RemoveElementGetNext(ptr, temp_pair2);
		}
	}

	m_NumVertices = x;

	m_pVBuffer->SetRenderType(IdeVertexBuffer::RENDER_TRIANGLELIST);
	m_pVBuffer->DirtyBuffer(IdeVertexBuffer::BUFFER_TEXTURECOORDS0);
	m_pVBuffer->DirtyBuffer(IdeVertexBuffer::BUFFER_INDICES16);
	m_pVBuffer->SetBufferSize(m_NumVertices, deFALSE);
	m_pVBuffer->Unlock();

	delete[] OldTexCoords;
	for (i = 0; i < m_NumFrames; i++)
	{
		delete[] OldVertices[i];
		delete[] OldNormals[i];
	}
	delete[] OldVertices;
	delete[] OldNormals;
	delete[] TexIndices;
	delete[] VertIndices;

	return deTRUE;
}

void deAnimatedMesh::Destroy()
{
	//SAFE_DELETE_ARRAY(m_pVertices);

	for (int i = 0; i < m_NumFrames; i++)
	{
		DE3D_SAFE_DELETE_ARRAY(m_pFrames[i].vertices);
		DE3D_SAFE_DELETE_ARRAY(m_pVertices[i]);
		DE3D_SAFE_DELETE_ARRAY(m_pNormals[i]);
	}
	DE3D_SAFE_DELETE_ARRAY(m_pVertices);
	DE3D_SAFE_DELETE_ARRAY(m_pNormals);

	DE3D_SAFE_DELETE_ARRAY(m_pFrames);
	DE3D_SAFE_DELETE_ARRAY(m_pTriangles);
	DE3D_SAFE_DELETE_ARRAY(m_pSkins);
	DE3D_SAFE_DELETE_ARRAY(m_pTexCoords);

	DE3D_SAFE_RELEASE(m_pVBuffer);
	DE3D_SAFE_RELEASE(m_pTexture);
	DE3D_SAFE_RELEASE(m_pBitmap);

	//for (i = 0; i < m_NumSkins; i++)
	//	m_pTextures[i].Cleanup();

}

IdeResourceBase *deAnimatedMesh::MakeCopy()
{
	return NULL;
}

int deAnimatedMesh::GetCurrentFrame()
{
	return m_CurrentFrame;
}

int deAnimatedMesh::GetFrameSize()
{
	return 0;
}

float deAnimatedMesh::GetInterpolation()
{
	return m_Interpolation;
}

int	deAnimatedMesh::GetNextFrame()
{
	return m_NextFrame;
}

int deAnimatedMesh::GetNumFrames()
{
	return m_NumFrames;
}

int deAnimatedMesh::GetNumSkins()
{
	return m_NumSkins;
}

int deAnimatedMesh::GetNumTriangles()
{
	return m_NumTriangles;
}

int deAnimatedMesh::GetNumVerts()
{
	return m_NumVertices;
}

int deAnimatedMesh::GetNumTexCoords()
{
	return m_NumTexCoords;
}

char *deAnimatedMesh::GetSkinName(int index)
{
	return (char*)m_pSkins[index];
}

void deAnimatedMesh::SetAnimSpeed(float FramesPerSec)
{
	m_AnimSpeed = FramesPerSec;
}

deBoolean deAnimatedMesh::SetCurrentAnim(const char* AnimName)
{
	int j;
	bool foundanim = false;
	
	for (j = 0; j < m_Anims.Length(); ++j)
	{
		if (m_Anims[j].AnimName == AnimName)
		{
			foundanim = true;
			break;
		}
	}
	if (!foundanim)
		return deFALSE;
	
	m_Interpolation = 0;
	m_CurrentAnim = j;
	return deTRUE;
}

deBoolean deAnimatedMesh::SetCurrentAnim(int AnimNum)
{
	if (AnimNum < 0 || AnimNum >= m_Anims.Length())
		return deFALSE;
	m_Interpolation = 0;
	m_CurrentAnim = AnimNum;
	return deTRUE;
}

float deAnimatedMesh::GetAnimSpeed()
{
	return m_AnimSpeed;
}

int deAnimatedMesh::GetCurrentAnim()
{
	return m_CurrentAnim;
}

void deAnimatedMesh::SetCurrentFrame(int frame)
{
	m_CurrentFrame = frame;
}

void deAnimatedMesh::SetNextFrame(int frame)
{
	m_NextFrame = frame;
}

#pragma warning (push)
#pragma warning (disable : 4100)
void deAnimatedMesh::SetTexture(const char* filename)
{
	//m_pTexture = new deBitmap(filename, DEBITMAP_TYPE_BMP);
	//if (!m_pTexture)
	//	m_pTexture = NULL;
}

void deAnimatedMesh::SetTexture(IdeBitmapProxy *tex)
{
	// nuh uh
}
#pragma warning (pop)

IdeVertexBuffer* deAnimatedMesh::GetVBuffer(float Time)
{
	if (!m_pVBuffer)
		DEBUGRETURN(NULL, "GetVBuffer: m_pVBuffer was NULL");
	
	deVertex	*Vertices;
	deVertex	*Normals;
	float		Interpolation;
	int			CurrFrame, NextFrame, i;
	int			StartFrame, StopFrame;

	StartFrame = m_Anims[m_CurrentAnim].Start;
	StopFrame = m_Anims[m_CurrentAnim].Stop;

	CurrFrame = max(StartFrame,(int)m_Interpolation);
	if (CurrFrame > StopFrame)
		CurrFrame = StopFrame;
	NextFrame = CurrFrame+1;
	if (NextFrame > StopFrame)
		NextFrame = StartFrame;
	Interpolation = m_Interpolation - (int)m_Interpolation;
	
	m_pVBuffer->Lock();
	
	if (!m_pVBuffer->BufferExists(IdeVertexBuffer::BUFFER_POSITION))
	{
		if (!m_pVBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_POSITION, deFALSE))
			return NULL;
	}
	if (!m_pVBuffer->BufferExists(IdeVertexBuffer::BUFFER_NORMAL))
	{
		if (!m_pVBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_NORMAL, deFALSE))
			return NULL;
	}
	
	Vertices = (deVertex*)m_pVBuffer->GetBuffer(IdeVertexBuffer::BUFFER_POSITION);
	Normals  = (deVertex*)m_pVBuffer->GetBuffer(IdeVertexBuffer::BUFFER_NORMAL);
	
	if (StartFrame == StopFrame)
	{
		memcpy(Vertices, m_pVertices[CurrFrame], m_NumVertices*sizeof(deVertex));
		memcpy(Normals, m_pNormals[CurrFrame], m_NumVertices*sizeof(deVertex));
	}
	else
	{
		for (i = 0; i < m_NumVertices; i++)
		{
			Vertices[i] = (m_pVertices[NextFrame][i] * Interpolation) + (m_pVertices[CurrFrame][i] * (1-Interpolation));
		#if (1) // change to 0 to not interpolate normals
			Normals[i] = (m_pNormals[NextFrame][i] * Interpolation) + (m_pNormals[CurrFrame][i] * (1-Interpolation));
		#else		
			Normals[i] = m_pNormals[CurrFrame][i];
		#endif
		}
	}
	
	m_pVBuffer->DirtyBuffer(IdeVertexBuffer::BUFFER_POSITION);
	m_pVBuffer->DirtyBuffer(IdeVertexBuffer::BUFFER_NORMAL);
	
	m_pVBuffer->Unlock();
	
	// this is just testing code to step the animation
	{
		int AnimLength = StopFrame - StartFrame;
		if (AnimLength > 0)
		{
			m_Interpolation += m_AnimSpeed * Time;
			while (m_Interpolation > StopFrame+1) // loop to beginning
				m_Interpolation -= (AnimLength+1);
			while (m_Interpolation < StartFrame)// loop to end
				m_Interpolation += AnimLength;
		}
	}
	
	
	return m_pVBuffer;
}

IdeVertexBuffer* deAnimatedMesh::GetVBuffer()
{
	if (!m_pVBuffer)
		DEBUGRETURN(NULL, "GetVBuffer: m_pVBuffer was NULL");

	deVertex	*Vertices;
	deVertex	*Normals;
	float		interpolation;
	int			CurrFrame, NextFrame, i;

	CurrFrame = min(max(0,(int)m_Interpolation), m_NumFrames-1);
	NextFrame = min(CurrFrame+1, m_NumFrames-1);
	interpolation = m_Interpolation - (int)m_Interpolation;

	m_pVBuffer->Lock();

	if (!m_pVBuffer->BufferExists(IdeVertexBuffer::BUFFER_POSITION))
	{
		if (!m_pVBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_POSITION, deFALSE))
			return NULL;
	}
	if (!m_pVBuffer->BufferExists(IdeVertexBuffer::BUFFER_NORMAL))
	{
		if (!m_pVBuffer->CreateBuffer(IdeVertexBuffer::BUFFER_NORMAL, deFALSE))
			return NULL;
	}

	Vertices = (deVertex*)m_pVBuffer->GetBuffer(IdeVertexBuffer::BUFFER_POSITION);
	Normals  = (deVertex*)m_pVBuffer->GetBuffer(IdeVertexBuffer::BUFFER_NORMAL);

	for (i = 0; i < m_NumVertices; i++)
	{
		Vertices[i] = (m_pVertices[NextFrame][i] * interpolation) + (m_pVertices[CurrFrame][i] * (1-interpolation));
#if (1) // change to 0 to not interpolate normals
		Normals[i] = (m_pNormals[NextFrame][i] * interpolation) + (m_pNormals[CurrFrame][i] * (1-interpolation));
#else		
		Normals[i] = m_pNormals[CurrFrame][i];
#endif
	}

	m_pVBuffer->DirtyBuffer(IdeVertexBuffer::BUFFER_POSITION);
	m_pVBuffer->DirtyBuffer(IdeVertexBuffer::BUFFER_NORMAL);
	
	m_pVBuffer->Unlock();

	// this is just testing code to step the animation
	m_Interpolation += 0.015f;
	if (m_Interpolation >= m_NumFrames)
		m_Interpolation = 0;

	return m_pVBuffer;
}

IdeRenderTexture* deAnimatedMesh::GetTexture(IdeDriver * pDriver)
{
	if (!m_pTexture && !m_pBitmap)
	{
//		if (m_NumSkins > 0)
		{
			IdeResourceBase * resource;
			//void * Texture = NULL;
//			m_pBitmap = (IdeBitmap*)GetIdeResourceManagerInterface()->GetResource(m_pSkins[0], NULL);
			resource = IdeResourceManager_GetManager()->GetResource("players\\alita\\alita.pcx", NULL);
			m_pBitmap = IdeBitmap_CreateProxy(resource);
			if (!m_pBitmap)
				return NULL;
			m_pBitmap->Claim();
			m_pTexture = IdeRenderState_CreateRenderTexture();
			pDriver->AddBitmapProxy(m_pBitmap);
			m_pTexture->Lock();
			m_pTexture->SetBitmap(0,m_pBitmap);
			m_pTexture->SetColorArg(0,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
			m_pTexture->SetColorArg(0,2,IdeRenderTexture::TEXTUREARG_DIFFUSE);
			if (resource)
				m_pTexture->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_MODULATE);
			else
				m_pTexture->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_SELECTARG2);
			m_pTexture->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_DISABLE);
			m_pTexture->Unlock();
		}
	}

	return m_pTexture;
}

