#define		D3D_OVERLOADS
#include	"object3d.h"

HRESULT LoadObject3D( TCHAR* name, LPOBJECT3D object )
{
	FILE*		inFile = fopen( name, "rb" );
	DWORD		i, faceNbr, vertNbr;

	if( !inFile )
		return E_FAIL;	

	fread( &vertNbr, sizeof(DWORD), 1, inFile );	
	object->vert = new D3DVERTEX[vertNbr];

	for( i = 0 ; i<vertNbr ; i++ )
	{
		fread( &object->vert[i].x, sizeof(FLOAT),  1, inFile );
		fread( &object->vert[i].y, sizeof(FLOAT),  1, inFile );
		fread( &object->vert[i].z, sizeof(FLOAT),  1, inFile );
		fread( &object->vert[i].nx, sizeof(FLOAT), 1, inFile );
		fread( &object->vert[i].ny, sizeof(FLOAT), 1, inFile );
		fread( &object->vert[i].nz, sizeof(FLOAT), 1, inFile );
		fread( &object->vert[i].tu, sizeof(FLOAT), 1, inFile );
		fread( &object->vert[i].tv, sizeof(FLOAT), 1, inFile );		
	}

	object->vertNbr = vertNbr;

	fread( &faceNbr, sizeof(DWORD), 1, inFile );
	object->indNbr  = (WORD)(faceNbr*3);	
	object->ind		= new WORD[object->indNbr];

	for( i = 0 ; i<object->indNbr ; i++ )
	{
		fread( &object->ind[i], sizeof(WORD), 1, inFile );
	}

	fclose( inFile );

	return S_OK;
}


VOID TransformObject3D( LPOBJECT3D object, gem_Matrix& mat )
{
	gem_Vector		a;

	for( DWORD i  = 0 ; i<object->vertNbr ; i++ )
	{
		a.x = object->vert[i].x;
		a.y = object->vert[i].y;
		a.z = object->vert[i].z;

		a = a*mat;

		object->vert[i].x = a.x;
		object->vert[i].y = a.y;
		object->vert[i].z = a.z;
		
	}	
}

VOID TransformObject3D( LPOBJECT3D src, LPOBJECT3D dest, gem_Matrix& mat )
{
	gem_Vector		a, b;

	for( DWORD i  = 0 ; i<src->vertNbr ; i++ )
	{
		dest->vert[i] = src->vert[i];

		a.x = src->vert[i].x;
		a.y = src->vert[i].y;
		a.z = src->vert[i].z;

		b = a*mat;

		dest->vert[i].x = b.x;
		dest->vert[i].y = b.y;
		dest->vert[i].z = b.z;
		
	}	
}



void DeleteObject3D( LPOBJECT3D obj )
{
	if( obj->vert ) delete obj->vert;
	if( obj->ind ) delete obj->ind;
}

inline DWORD Find( LPWORD list, DWORD ind, WORD a, WORD b )
{
	for( DWORD i = 0 ; i<ind ; i+=2 )
		if( list[i] == a && list[i+1] == b || list[i] == b && list[i] == a )
			return 1;

	return 0;
}

HRESULT CreateLineList( LPOBJECT3D object, DWORD& indNbr, LPWORD& linelist )
{
	indNbr	 = object->indNbr*2;	
	linelist = new WORD[indNbr];	

	LONG	lCount = object->indNbr/3;

	for( LONG i = 0, j = 0 ; i<lCount ; i++ )
	{
		linelist[j] = object->ind[i*3 + 0];
		linelist[j+1] = object->ind[i*3 + 1];
		if( !Find( linelist, j, linelist[j], linelist[j+1] ) )
			j+=2;

		linelist[j] = object->ind[i*3 + 1];
		linelist[j+1] = object->ind[i*3 + 2];
		if( !Find( linelist, j, linelist[j], linelist[j+1] ) )
			j+=2;		

		linelist[j] = object->ind[i*3 + 2];
		linelist[j+1] = object->ind[i*3 + 0];
		if( !Find( linelist, j, linelist[j], linelist[j+1] ) )
			j+=2;
	}

	indNbr = j;
	
	return S_OK;
}


HRESULT RenderObject3D( LPOBJECT3D object, LPDIRECT3DDEVICE7 pd3dDevice )
{
	return pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, D3DFVF_VERTEX, object->vert, 
											 object->vertNbr, object->ind, object->indNbr, NULL );
}

HRESULT RenderFace( LPOBJECT3D object, WORD face, LPDIRECT3DDEVICE7 pd3dDevice )
{
	static	WORD			ind[3];

	ind[0] = object->ind[face*3];
	ind[1] = object->ind[face*3+1];
	ind[2] = object->ind[face*3+2];

	return pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, D3DFVF_VERTEX, object->vert, 
											 object->vertNbr, ind, 3, NULL );
}

HRESULT RenderFaceEdgeWithAlpha( LPOBJECT3D obj, WORD face, DWORD a, LPDIRECT3DDEVICE7 pd3dDevice )
{
	static	D3DLVERTEX		vert[6];

	vert[0].x = obj->vert[obj->ind[face*3]].x;
	vert[0].y = obj->vert[obj->ind[face*3]].y;
	vert[0].z = obj->vert[obj->ind[face*3]].z;
	vert[0].dcColor = a | 0x80ff80;

	vert[1].x = obj->vert[obj->ind[face*3+1]].x;
	vert[1].y = obj->vert[obj->ind[face*3+1]].y;
	vert[1].z = obj->vert[obj->ind[face*3+1]].z;
	vert[1].dcColor = a | 0x80ff80;

	vert[2].x = obj->vert[obj->ind[face*3+1]].x;
	vert[2].y = obj->vert[obj->ind[face*3+1]].y;
	vert[2].z = obj->vert[obj->ind[face*3+1]].z;
	vert[2].dcColor = a | 0x80ff80;

	vert[3].x = obj->vert[obj->ind[face*3+2]].x;
	vert[3].y = obj->vert[obj->ind[face*3+2]].y;
	vert[3].z = obj->vert[obj->ind[face*3+2]].z;
	vert[3].dcColor = a | 0x80ff80;

	vert[4].x = obj->vert[obj->ind[face*3+2]].x;
	vert[4].y = obj->vert[obj->ind[face*3+2]].y;
	vert[4].z = obj->vert[obj->ind[face*3+2]].z;
	vert[4].dcColor = a | 0x80ff80;

	vert[5].x = obj->vert[obj->ind[face*3]].x;
	vert[5].y = obj->vert[obj->ind[face*3]].y;
	vert[5].z = obj->vert[obj->ind[face*3]].z;
	vert[5].dcColor = a | 0x80ff80;

	return pd3dDevice->DrawPrimitive( D3DPT_LINELIST, D3DFVF_LVERTEX, vert, 6, NULL );
}

VOID FlipNormals( LPOBJECT3D object )
{
	for( DWORD i = 0 ; i<object->vertNbr ; i++ )
	{
		object->vert[i].nx = -object->vert[i].nx;
		object->vert[i].ny = -object->vert[i].ny;
		object->vert[i].nz = -object->vert[i].nz;
	}
}

VOID MorphObject( LPOBJECT3D srcObject, LPOBJECT3D destObject, FLOAT factor, LPOBJECT3D morphed )
{	

	for( DWORD i = 0 ; i<srcObject->vertNbr ; i++ )
	{

		morphed->vert[i] = vLERP( srcObject->vert[i], destObject->vert[i], factor );		

	}
}

gem_Vector CalculateCenter( LPOBJECT3D obj )
{
	gem_Vector		center( 0, 0, 0);
	FLOAT			_1nbr = 1.0f/(FLOAT)obj->vertNbr;

	for( DWORD i = 0 ; i<obj->vertNbr ; i++ )
	{
		center.x += obj->vert[i].x;
		center.y += obj->vert[i].y;
		center.z += obj->vert[i].z;
	}

	center.x *= _1nbr;
	center.y *= _1nbr;
	center.z *= _1nbr;

	return center;
}
