#include <xtl.h>

#include <stdio.h>
#include <io.h>
#include <conio.h>

#include <string.h>
#include <search.h>

#include <pshpack4.h>
#include <xgraphics.h>
#include <D3D8Perf.h>
#include <xonline.h>
#include <xkbd.h>
#include <xfont.h>

#include "callbacks.h"

//xapilibd.lib d3dx8.lib d3d8.lib xgraphics.lib xonline.lib xboxkrnl.lib
//xapilibd.lib d3dx8.lib d3d8.lib xgraphics.lib dsoundd.lib dmusicd.lib xboxkrnl.lib xnetd.lib xkbdd.lib xbdm.lib xvoiced.lib 


int nr_poly=0;
LPDIRECT3DVERTEXBUFFER8 g_pVB=0;

char *LoadFile( char *filename, DWORD *size )
{
	char *buffer;
	DWORD filelength;
	FILE *fp;

	fp = fopen( filename, "rb" );
	if( fp )
	{
		fseek( fp, 0, SEEK_END);
		filelength = ftell(fp);
		if( size )
			*size = filelength;
		fseek( fp, 0, SEEK_SET);

		buffer = (char*)malloc( filelength+2 );
		buffer[filelength] = 0;
		buffer[filelength+1] = 0;
		fread( buffer, filelength, 1, fp );
		fclose( fp );
		return buffer;
	}
	return 0;
}


struct CUSTOMVERTEX2
{
	float x,y,z;
	float xn,yn,zn;
	DWORD color;
    FLOAT       tu, tv;   // The texture coordinates
};

#define D3DFVF_CUSTOMVERTEX2 (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1)

int ASE_GetIntValue( char *meshdata, char *keyword, int index )
{
	char work[256];

	if( index < 0 )
		strcpy( work, keyword);
	else
		sprintf(work, "%s%%5u", keyword, index );
	char *temp = strstr(meshdata, work );

	if( temp )
	{	
		temp += strlen(work)+1;
		return atoi(temp );
	}
	return -1;
}


struct vertex3d
{
	float x,y,z;
};

struct face
{
	int a,b,c;
};

int ASE_GetVertexValue( CUSTOMVERTEX2 *p, char *meshdata, char *keyword, int index )
{
	char work[256];

	sprintf(work, "%s%5u", keyword, index );
	char *temp = strstr(meshdata, work );

	if( temp )
	{	
		temp += strlen(work)+1;
		sscanf(temp,"%f\t%f\t%f",&p->x,&p->y,&p->z);
		return 1;
	}
	return -1;
}

int ASE_GetVertexNormalValue( CUSTOMVERTEX2 *p, char *meshdata, char *keyword, int index )
{
	char work[256];

	sprintf(work, "%s %u", keyword, index );
	char *temp = strstr(meshdata, work );

	if( temp )
	{	
		temp += strlen(work)+1;
		sscanf(temp,"%f\t%f\t%f",&p->xn,&p->yn,&p->zn);
		p->tu=0;
		p->tv=0;
		return 1;
	}
	return -1;
}

int ASE_GetFaceValue( struct face *f, char *meshdata, char *keyword, int index )
{
	char work[256];

	if( index < 0 )
		strcpy( work, keyword);
	else
		sprintf(work, "%s%5u", keyword, index );
	char *temp = strstr(meshdata, work );

	if( temp )
	{	
		temp = strstr( temp, "A:");
		temp += 2;
		f->a = atoi(temp);
 
		temp = strstr( temp, "B:");
		temp += 2;
		f->b = atoi(temp);

		temp = strstr( temp, "C:");
		temp += 2;
		f->c = atoi(temp);

		return 1;
	}
	return -1;
}

extern LPDIRECT3DDEVICE8 g_pd3dDevice ; // Our rendering device
float xrot=0, yrot=0, zrot=0;

void SetupMatrices( float x, float y, float distance, D3DXVECTOR3 *target)
{
    D3DXMATRIX matWorld;
    D3DXMATRIX matWorldt;

	D3DXMatrixRotationY( &matWorld, yrot );
    D3DXMatrixRotationX( &matWorldt, xrot );
	D3DXMatrixMultiply(&matWorld, &matWorld, &matWorldt);
    D3DXMatrixRotationZ( &matWorldt, zrot );
	D3DXMatrixMultiply(&matWorld, &matWorld, &matWorldt);

    g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );


    D3DXMATRIX matView;
    D3DXMatrixLookAtLH( &matView, &D3DXVECTOR3( 0.0f, 3.0f, distance*(float)5.14 ),
                                  &D3DXVECTOR3( x, y, 0.0f ) ,
									//&m_vObjectCenter,
                                  &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

    D3DXMATRIX matProj;
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/8, 640.0f/480.0f,0.1f, 100000.0f );
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

}

void SetupLights( float distance, char lighting )
{
    // Set up a material. The material here just has the diffuse and ambient
    // colors set to yellow. Note that only one material can be used at a time.
    D3DMATERIAL8 mtrl;

	ZeroMemory( &mtrl, sizeof(D3DMATERIAL8) );
    mtrl.Diffuse.r = mtrl.Ambient.r = 1.0f;
    mtrl.Diffuse.g = mtrl.Ambient.g = 1.0f;
    mtrl.Diffuse.b = mtrl.Ambient.b = 1.0f;
    mtrl.Diffuse.a = mtrl.Ambient.a = 1.0f;
    g_pd3dDevice->SetMaterial( &mtrl );

    // Set up a white, directional light, with an oscillating direction.
    // Note that many lights may be active at a time (but each one slows down
    // the rendering of our scene). However, here we are just using one.

    // Direction vector for the light
    FLOAT       fAngle = 0.0f ;
	
	D3DXVECTOR3 vDirection( 0, 0, 1.0 );

/*	vDirection.x = -0.5;
	vDirection.y = 0.5;
	vDirection.z = -1.0;*/

//    D3DXVec3Normalize( &vDirection, &vDirection );

    // The light structure
    D3DLIGHT8 light;
    ZeroMemory( &light, sizeof(D3DLIGHT8) );
    light.Type       = D3DLIGHT_DIRECTIONAL;
	light.Diffuse.r  = 0.1f;
	light.Diffuse.g  = 1.0f;
	light.Diffuse.b  = 0.1f;

	light.Direction  = vDirection;
    light.Range      = 100000.0f;
    g_pd3dDevice->SetLight( 0, &light );
    g_pd3dDevice->LightEnable( 0, TRUE );
    
    // When using lights, we must turn lighting on
    g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );

    // Finally, turn on some ambient light.
    g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xff555555 );

}

#include "3DOBJ.H"

char LoadMesh(char *filename, DWORD col)
{
	struct CUSTOMVERTEX2 *p3d;
	struct face *faces;
	struct CUSTOMVERTEX2 *p;
	int tt=0;
	int flags=0;

    char *meshbuffer = (char*)LOGO_3D;
	if( !meshbuffer )
		return 0;

	int nr_vertex = ASE_GetIntValue(meshbuffer, "*MESH_NUMVERTEX",-1 );
	int nr_face = ASE_GetIntValue(meshbuffer, "*MESH_NUMFACES",-1 );

	nr_poly = nr_face;

	p3d = new CUSTOMVERTEX2[ nr_vertex ];
	faces = new struct face[ nr_face ];

	for( int t=0; t < nr_vertex; ++t )
		ASE_GetVertexValue( &p3d[t],meshbuffer,"*MESH_VERTEX",t );
	for( t=0; t < nr_face; ++t )
		ASE_GetFaceValue( &faces[t],meshbuffer,"*MESH_FACE",t );

	for( int t=0; t < nr_vertex; ++t )
		ASE_GetVertexNormalValue( &p3d[t],meshbuffer,"*MESH_VERTEXNORMAL",t );

	p = (struct CUSTOMVERTEX2*)malloc( (nr_face*3) * sizeof(struct CUSTOMVERTEX2));
	
	for( t =0; t<nr_face; ++t )
	{
/*		p[t*3].x = p3d[ faces[t].a ].x;
		p[t*3].y = p3d[ faces[t].a ].y;
		p[t*3].z = p3d[ faces[t].a ].z;

		p[(t*3)+1].x = p3d[ faces[t].b ].x;
		p[(t*3)+1].y = p3d[ faces[t].b ].y;
		p[(t*3)+1].z = p3d[ faces[t].b ].z;*/

		memcpy(&p[(t*3)], &p3d[ faces[t].a ], sizeof(CUSTOMVERTEX2));
		memcpy(&p[(t*3)+1], &p3d[ faces[t].b ], sizeof(CUSTOMVERTEX2));
		memcpy(&p[(t*3)+2], &p3d[ faces[t].c ], sizeof(CUSTOMVERTEX2));
//		p[(t*3)+2].y = p3d[ faces[t].v ];
//		p[(t*3)+2].z = p3d[ faces[t].c ];
	}

	for( t =0; t<nr_face*3; ++t )
	{
		p[t].color = 0xffffffff;
	}

	if( FAILED( g_pd3dDevice->CreateVertexBuffer( nr_face*3*sizeof(CUSTOMVERTEX2),D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX2,D3DPOOL_DEFAULT, &g_pVB ) ) )
		return (char)E_FAIL;

	CUSTOMVERTEX2* pVertices;

	if( FAILED( g_pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 ) ) )
		return (char)E_FAIL;

	memcpy( pVertices, p, nr_face*3*sizeof(CUSTOMVERTEX2) );
	g_pVB->Unlock();

	delete faces;
	delete p3d;

	return 1;
}

void RenderPolys( float x, float y, float distance, char lighting )
{

	static LPDIRECT3DTEXTURE8 sprite=0;
	static D3DLOCKED_RECT  pLockedRect;
	unsigned char col;

	if( !sprite )
	{
		g_pd3dDevice->CreateTexture(64,64,0,0,D3DFMT_A8R8G8B8,0,&sprite );
		sprite->LockRect(0,&pLockedRect,0,0 );
		DWORD *image = (DWORD*)malloc(64*64*4);

		DWORD pos = 0;
		for( int y=0; y < 64; ++y )
		{
			for( int x=0; x < 64; ++x )
			{
				col = 0x88;
 				image[pos] = 0xff000000 + (col << 16)+ (col << 8)+ (col);
				image[pos]= 0xff555555; 
				pos ++;
			}
		}
		XGSwizzleRect(image, 0,0,pLockedRect.pBits,64,64,0,4);
		sprite->UnlockRect( 0 );
		free( image );
	}

//	if( !sprite )
	{
		xrot += 0.0032f;
		yrot += 0.002f;
		zrot += 0.001f;
	}

    // Clear the backbuffer to a black color

    // Setup the world, view, and projection matrices
    SetupMatrices( x,y,distance, &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );
	SetupLights(distance,lighting);

	D3DXMATRIX mat;
    mat._11 = 0.5f; mat._12 = 0.0f;
    mat._21 = 0.0f; mat._22 =-0.5f;
    mat._31 = 0.0f; mat._32 = 0.0f;
    mat._41 = 0.5f; mat._42 = 0.5f;
    g_pd3dDevice->SetTransform( D3DTS_TEXTURE0, &mat );
    g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2 );/**/
/*	g_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL );/**/
 	g_pd3dDevice->SetTexture( 0, sprite );
	//g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME );
	g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE  );
    g_pd3dDevice->SetStreamSource( 0, g_pVB, sizeof(CUSTOMVERTEX2) );
    g_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX2 );
    g_pd3dDevice->DrawPrimitive ( D3DPT_TRIANGLELIST, 0, nr_poly );
    SetupMatrices( x,y,distance, &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );

}