//============================================================
// Program:		CGFEntity
// Description:	Simple entity class
// Author:		Benjamin Gottemoller
// Website:		http://www.particlefield.com
// Date:		who knows
// Legal:		Licensed under the gnu GPL (see gpl.txt for details)
//============================================================

#include "GameFrameEntity.h"
#include "GameFrame.h"

CGFEntity::CGFEntity()
{
	GFParent = NULL;
	NumLibraryIndices = 0;
	LibraryIndices = NULL;
	ActionFlags = 0;
	RenderFlags = 0;
	Radius = 0;
	Mass = 0;
	Reset();
}

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

void CGFEntity::Initialize(GameFrame *gfparent, list<int> &obj_lib_indices)
{
	list<int>::iterator index = obj_lib_indices.begin();

	Reset();
	GFParent = gfparent;
	Radius = 0;

	NumLibraryIndices = (int) obj_lib_indices.size();
	LibraryIndices = new int[NumLibraryIndices];
	
	for(int i=0; i<NumLibraryIndices; i++)
	{
		LibraryIndices[i] = (*index);
		Radius += GFParent->ObjectLib[LibraryIndices[i]]->Radius;
		index++;
	}
	Radius /= (float)NumLibraryIndices;

	ActionFlags = 0;
	RenderFlags = 0;
}

void CGFEntity::Reset(void)
{
	FrictionDrag = 0;
	X = Y = Z = 0;
	XVec = YVec = ZVec = 0;
	Yaw = Pitch = Roll = 0;
	YawVec = PitchVec = RollVec = 0;
	Up_Vector = D3DXVECTOR3(0,1,0);
	Right_Vector = D3DXVECTOR3(1,0,0);
	Look_Vector = D3DXVECTOR3(0,0,1);
}

void CGFEntity::Destroy(void)
{
	GFParent = NULL;
	NumLibraryIndices = 0;
	SAFE_DELETE_ARRAY(LibraryIndices);
	ActionFlags = 0;
	RenderFlags = 0;
}

void CGFEntity::SetActionFlags(DWORD flags)
{
	ActionFlags = flags;
}

void CGFEntity::SetRenderFlags(DWORD flags)
{
	RenderFlags = flags;
}

void CGFEntity::Move(DWORD type, DWORD direction, float speed)
{
	if(GFParent->IsGamePaused || GFParent->IsGameLocked) return;
	float scalar = speed * GFParent->GetTimeDiff();

	if(type & ENTITY_MOTION_STEADY)
	{
		if(type & ENTITY_FORWARD)
		{
			X += scalar * Look_Vector.x;
			Y += scalar * Look_Vector.y;
			Z += scalar * Look_Vector.z;
		}
		else
		if(type & ENTITY_RIGHT)
		{
			X += scalar * Right_Vector.x;
			Y += scalar * Right_Vector.y;
			Z += scalar * Right_Vector.z;
		}
		else
		if(type & ENTITY_UP)
		{
			X += scalar * Up_Vector.x;
			Y += scalar * Up_Vector.y;
			Z += scalar * Up_Vector.z;
		}
	}
	else
	if(type & ENTITY_MOTION_ACCELERATE)
	{
		if(direction & ENTITY_FORWARD)
		{
			XVec += scalar * Look_Vector.x;
			YVec += scalar * Look_Vector.y;
			ZVec += scalar * Look_Vector.z;
		}
		else
		if(direction & ENTITY_RIGHT)
		{
			XVec += scalar * Right_Vector.x;
			YVec += scalar * Right_Vector.y;
			ZVec += scalar * Right_Vector.z;
		}
		else
		if(direction & ENTITY_UP)
		{
			XVec += scalar * Up_Vector.x;
			YVec += scalar * Up_Vector.y;
			ZVec += scalar * Up_Vector.z;
		}
	}
}

void CGFEntity::Rotate(DWORD type, float speed)
{
	if(GFParent->IsGamePaused || GFParent->IsGameLocked) return;
	float scalar = speed * GFParent->GetTimeDiff();

	if(type & ENTITY_YAW)
	{
		Yaw += scalar;
	}
	else
	if(type & ENTITY_PITCH)
	{
		Pitch += scalar;
	}
	else
	if(type & ENTITY_ROLL)
	{
		Roll += scalar;
	}
}

void CGFEntity::Update(void)
{
	if(GFParent->IsGamePaused || GFParent->IsGameLocked) return;
	float scalar = GFParent->GetTimeDiff();

	X += XVec * scalar;
	Y += YVec * scalar;
	Z += ZVec * scalar;
	Yaw += YawVec * scalar;
	Pitch += PitchVec * scalar;
	Roll += RollVec * scalar;

	if(ActionFlags & ENTITY_ACTION_AUTOLEVEL)
	{
		if(Roll < -.02f) Roll += .01f;
		else
		if(Roll > .02f) Roll -= .01f;
	}
}

void CGFEntity::Render(D3DXMATRIX *modifier)
{
	if((NumLibraryIndices <= 0) || (LibraryIndices == NULL) || (GFParent == NULL)) return;
	if(GFParent->IsGameLocked) return;

	D3DXMATRIX YawMat, PitchMat, RollMat;
	D3DXMATRIX TransMat;
	D3DXMATRIX WorldMat;

	Up_Vector = D3DXVECTOR3(0,1,0);
	Right_Vector = D3DXVECTOR3(1,0,0);
	Look_Vector = D3DXVECTOR3(0,0,1);

	D3DXMatrixRotationAxis(&YawMat, &Up_Vector, Yaw);
	D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &YawMat);
	D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &YawMat);

	D3DXMatrixRotationAxis(&PitchMat, &Right_Vector, Pitch);
	D3DXVec3TransformCoord(&Look_Vector, &Look_Vector, &PitchMat);
	D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &PitchMat);

	D3DXMatrixRotationAxis(&RollMat, &Look_Vector, Roll);
	D3DXVec3TransformCoord(&Up_Vector, &Up_Vector, &RollMat);
	D3DXVec3TransformCoord(&Right_Vector, &Right_Vector, &RollMat);

	D3DXMatrixTranslation(&TransMat, X, Y, Z);
	D3DXMatrixIdentity(&WorldMat);
	D3DXMatrixMultiply(&WorldMat, &RollMat, &TransMat);
	D3DXMatrixMultiply(&WorldMat, &PitchMat, &WorldMat);
	D3DXMatrixMultiply(&WorldMat, &YawMat, &WorldMat);

	if(modifier != NULL) D3DXMatrixMultiply(&WorldMat, &WorldMat, modifier);

	const OBJNODE *tmp_node = GFParent->ObjectLib[LibraryIndices[0]];
	int index = tmp_node->VertexLibraryIndex;
	
	//All objects within the same entity must be in the same VB and have the same FVF
	GFParent->D3DDevice->SetStreamSource(0, GFParent->VertexLib[index], GFParent->VertexLib.GetSize(index));
	GFParent->D3DDevice->SetVertexShader(GFParent->VertexLib.GetFVF(index));
	GFParent->D3DDevice->SetTransform(D3DTS_WORLD, &WorldMat);

	for(int i=0; i<NumLibraryIndices; i++)
	{
		tmp_node = GFParent->ObjectLib[LibraryIndices[i]];

		if(RenderFlags & RENDER_TEXTURED)
		{
			index = tmp_node->TextureLibraryIndex;
			if(index != -1)
			{
				GFParent->D3DDevice->SetTexture(0, GFParent->TextureLib[index]);
			}
		}

		if(RenderFlags & RENDER_LIT)
		{
			index = tmp_node->MaterialLibraryIndex;
			if(index != -1)
			{
				GFParent->D3DDevice->SetMaterial(&(GFParent->MaterialLib[index]));
			}
		}
		
		GFParent->D3DDevice->DrawPrimitive(tmp_node->PrimitiveType, tmp_node->StartVertex, tmp_node->PrimitiveCount);

		if(RenderFlags & RENDER_TEXTURED)
		{
			GFParent->D3DDevice->SetTexture(0, NULL);
		}
	}
}
