/*///////////////////////////////////////////////////////////////////
// this sucks. it needs to be redone.
//////////////////////////////////////////////////////////////////*/
#include "fba.h"

static int VidMemLen=0;
static int VidMemPitch=0;
static int VidWidth=0; 
static int VidHeight=0;
static int VidBpp=0;
static int clipx=0;
static int clipy=0;
static int tLeft=0,tTop=0;
static int VidLeftOver=0;
static int TextureSize=0;
int nScrnWidth=640, nScrnHeight=480;
static RECT rectSource,src, dst;

// stuff that needs to be free'd before exit
static byte*				g_pBlitBuff = NULL;
static unsigned char* VidMem= NULL;
static LPDIRECT3DTEXTURE8	Texture;
static LPD3DXSPRITE			Sprite;

// Compute the scale and transform vectors
static float xAsp = 1.0f;
static float yAsp = 1.0f;

static bool bRotateGame;

// 32-bit pallete calculation used by the burn lib
static unsigned int HighCol24(int r,int g,int b,int i)
{
	unsigned int t; (void)i;
	t =(r<<16)&0xff0000;
	t|=(g<<8 )&0x00ff00;
	t|=(b    )&0x0000ff;
	return t;
}

int IntegerScale(RECT *pRect)
{
	int xm, ym;										// The multiple of nScrnWidth and nScrnHeight we can fit in
	int nWidth, nHeight;
	int nGameHeight=0, nGameWidth=0;
	int nGameAspectX = 4, nGameAspectY = 3;
	int nMonAspectX=4, nMonAspectY=3;
	nWidth = pRect->right - pRect->left;
	nHeight = pRect->bottom - pRect->top;
	
	BurnDrvGetAspect(&nGameAspectX, &nGameAspectY);
	if (bRotateGame)
		{
		BurnDrvGetScreen(&nGameHeight,&nGameWidth);
		}
	else
		{
		BurnDrvGetScreen(&nGameWidth,&nGameHeight);
		}

	xm = nWidth / nGameWidth;
	ym = nHeight / nGameHeight;

	int nWidthScratch;
	nWidthScratch = nHeight * nMonAspectY * nGameAspectX * nScrnWidth / (nScrnHeight * nMonAspectX * nGameAspectY);
	if (nWidthScratch > nWidth) {			
		if (nGameWidth < nGameHeight) {		// Vertical games
			nHeight = nWidth * nMonAspectY * nGameAspectY * nScrnWidth / (nScrnHeight * nMonAspectX * nGameAspectX);
		} else {							// Horizontal games
			nHeight = nWidth * nMonAspectX * nGameAspectY * nScrnHeight / (nScrnWidth * nMonAspectY * nGameAspectX);
		}
	} else {
		nWidth = nWidthScratch;
	}

	pRect->left = (pRect->right + pRect->left) / 2;
	pRect->left -= nWidth / 2;
	pRect->right = pRect->left + nWidth;

	pRect->top = (pRect->top + pRect->bottom) / 2;
	pRect->top -= nHeight / 2;
	pRect->bottom = pRect->top + nHeight;

	return 0;
}

void FixAspect(int newx)
	{
	int xtemp=640-newx;
	int ytemp=(xtemp*3)/4;
	//reduce x 
	src.left = xtemp/2;
	src.right  = 640-(xtemp/2); 
	//reduce y = x *3/4
	src.top=ytemp/2;
	src.bottom = 480-(ytemp/2); 
	IntegerScale(&src);

	if (bRotateGame)		
		{
		tTop=640-480;
		tLeft=0;
		}
	else
		{
		IntegerScale(&src);
		tTop=src.top;
		tLeft=src.left;
		}

	xAsp=((float)src.right-(float)src.left)/(float)clipx;
	yAsp=((float)src.bottom-(float)src.top)/(float)clipy;
		
	}

int VidInit()
{
	if (BurnDrvGetFlags() & BDF_ROTATE_GRAPHICS_CCW) {
		bRotateGame = true;
	} else {
		bRotateGame = false;
	}
	

	if (bRotateGame) {
		BurnDrvGetScreen(&clipy,&clipx);
	} else {

		BurnDrvGetScreen(&clipx,&clipy);
	}


//	if (bVidScanRotate && nGameWidth < nGameHeight) {
//			bRotateEffects = true;
//		} else {
//			bRotateEffects = false;
//		}
//	if (bRotateGame) {
//		bRotateEffects = !bRotateEffects;
//	}

// NOTE: To see if you need to *physically* rotate the effects, use this test:
// if (!bRotateGame && bRotateEffects) || (bRotateGame && !bRotateEffects)



	for (VidWidth = 256; VidWidth < clipx; VidWidth <<= 1) {}
	for (VidHeight = 256; VidHeight < clipy; VidHeight <<= 1) {}
	TextureSize=VidWidth*VidHeight*4;

	// Set Burn library Bytes per pixel 
	VidBpp=4;
	nBurnBpp=VidBpp;
	VidMemPitch=clipx*VidBpp;
	VidMemLen=clipy*VidMemPitch;
	VidLeftOver=(VidWidth-clipx)*4;
	
	VidMem = (unsigned char*)malloc(VidMemLen);
	memset(VidMem, 0, VidMemLen);

	BurnHighCol = HighCol24;	 
 	BurnRecalcPal();  

	/////
	if (Texture) 
	{ 
		Texture->Release();
		Texture = NULL;
	}


	D3DXCreateTexture(g_pd3dDevice, VidWidth, VidHeight, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &Texture);
	D3DSURFACE_DESC desc;
    Texture->GetLevelDesc(0, &desc);

	D3DXCreateSprite(g_pd3dDevice, &Sprite);

	//////
	// Figure out how big of a rect to lock in our texture
	
		{
		rectSource.top = 0;
		rectSource.left = 0;
		rectSource.bottom = clipy; 
		rectSource.right  = clipx; 
		}

	FixAspect(640);
	if (g_pBlitBuff != NULL)
	{
		delete [] g_pBlitBuff;
		g_pBlitBuff = NULL;
	}
	
	// Allocate a buffer to blit our frames to

	g_pBlitBuff = new byte[desc.Size];

	return 0;

}


int VidExit()
// Cleanup
{
	if (VidMem)
	{
		free(VidMem);
		VidMem = NULL;
	}


	if (Texture != NULL)
	{
		Texture->Release();
		Texture = NULL;
	}

	if (Sprite != NULL)
	{
		Sprite->Release();
		Sprite = NULL;
	}
	if (g_pBlitBuff != NULL)
	{
		delete [] g_pBlitBuff;
		g_pBlitBuff = NULL;
	}


	VidMemPitch=0;
	VidWidth=0; 
	VidHeight=0;
	return 0;
}

int VidFrame()
//////////////////////////////////////////
// Emulate for one frame. (called 60 times a second for NTSC and 50 for PAL)
// At the end of this function texture should contain the emulated frame
//////////////////////////////////////////
{
	// Get a description of our level 0 texture so we can figure
	// out the pitch of the texture
	pBurnDraw=VidMem;
	nBurnBpp=VidBpp;
	nBurnPitch=VidMemPitch;

	if (bDrvOkay) 
	{
		BurnDrvFrame(); // Run one frame
	}
	// Unlock our texture
	pBurnDraw=NULL;
	nBurnPitch=0;
	return 0;
}


int VidRender()
//////////////////////////////////////////
//now we need to blit VidMem to the screen
//////////////////////////////////////////
{
	unsigned char *pd, *ps;

	D3DSURFACE_DESC desc;
	Texture->GetLevelDesc(0, &desc);
	
	// Lock the rect in our texture
	D3DLOCKED_RECT d3dlr;
	Texture->LockRect(0, &d3dlr,NULL, 0);
	pd = g_pBlitBuff; ps = VidMem;
	for (int y = 0; y < clipy; y++, pd += VidMemPitch, ps += VidMemPitch) {
		memcpy(pd, ps, VidMemPitch);
		pd += VidLeftOver;
	}
    
    XGSwizzleRect( g_pBlitBuff, 0, NULL, d3dlr.pBits, desc.Width, desc.Height,NULL, 4 );

	Texture->UnlockRect(0);

    // Clear the viewport
    g_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL,0x00000000, 1.0f, 0L );
	
	// Begin the Scene
	g_pd3dDevice->BeginScene();

	D3DXCOLOR color(1.0, 1.0, 1.0, 1.0);

	if (bRotateGame)
		{
		D3DXVECTOR2 vecScale(yAsp, xAsp);
		//D3DXVECTOR2 vecTranslate(tLeft, tTop);
		D3DXVECTOR2 vecTranslate(d3dScale.xoffset, d3dScale.yoffset);
		D3DXVECTOR2 vecRotation(clipx/2, clipy/2);
		Sprite->Draw(Texture, &rectSource, &vecScale, &vecRotation, 1.57079, &vecTranslate, color);
		}
	else
		{
		D3DXVECTOR2 vecScale(xAsp, yAsp);
		//D3DXVECTOR2 vecTranslate(tLeft, tTop);
		D3DXVECTOR2 vecTranslate(d3dScale.xoffset, d3dScale.yoffset);
		Sprite->Draw(Texture, &rectSource, &vecScale, NULL, 0, &vecTranslate, color);
		}

	// End the scene.
	g_pd3dDevice->EndScene();
#if _DEBUG
///////////////////
// debug info
	WCHAR		m_BPP[30];
	WCHAR		m_WIDTH[30];
	WCHAR		m_HEIGHT[30];
	WCHAR		m_PITCH[50];

	swprintf( m_BPP, L"BPP: %d\n",VidBpp);
	swprintf( m_WIDTH, L"Width: %d,%d\n",VidWidth,clipx);
	swprintf( m_HEIGHT, L"Height: %d,%d\n",VidHeight,clipy);
	swprintf( m_PITCH, L"top:%d,left:%d,right:%d,bottom:%d\n",src.top,src.left,src.right,src.bottom);
//	swprintf( m_PITCH, L"x:%f,y:%f\n",xAsp,yAsp);
	m_Font.Begin();
	m_Font.DrawText( 350, 50, 0xffffffff, m_BPP );
	m_Font.DrawText( 350, 70, 0xffffffff, m_WIDTH );
	m_Font.DrawText( 350, 90, 0xffffffff, m_HEIGHT );
	m_Font.DrawText( 300, 110, 0xffffffff, m_PITCH );
	m_Font.End();
#endif

	if (bStretchMode)
	{
		m_Font.Begin();
		m_Font.DrawText( 80, 80, 0xffABCDEF, L"Stretch Mode On");
		m_Font.End();
	}


	return 0;
}

void VidXboxDoStrech(void)
{
    static int nCount = 0;

	if (bStretchMode)
	{

		// translation is integer based and is too fast by default
		// so wait every 20 iterations before moving
		if (nCount == 20)			
		{
			if (g_Gamepads[0].sThumbLX <= -32000)
			{
				if (d3dScale.xoffset > 0)
					d3dScale.xoffset -= 1;
				else
					d3dScale.xoffset = 1;
			}
			else if (g_Gamepads[0].sThumbLX >= 32000)
			{
				if (d3dScale.xoffset > 0)
					d3dScale.xoffset += 1;
				else
					d3dScale.xoffset = 1;
			}

			if (g_Gamepads[0].sThumbLY <= -32000)
			{
				if (d3dScale.yoffset > 0)
					d3dScale.yoffset += 1;
				else
					d3dScale.yoffset = 1;
			}	
			else if (g_Gamepads[0].sThumbLY >= 32000)
			{
				if (d3dScale.yoffset > 0)
					d3dScale.yoffset -= 1;
				else
					d3dScale.yoffset = 1;
			}


			if (g_Gamepads[0].sThumbRY <= -32000 )
			{
				d3dScale.xsize ++;
			}
			else if (g_Gamepads[0].sThumbRY >= 32000)
			{
				d3dScale.xsize--;
			}
			nCount = 0;
		}
		if (g_Gamepads[0].wButtons&&XINPUT_GAMEPAD_RIGHT_THUMB)
			{
			d3dScale.xsize=640;
			FixAspect(d3dScale.xsize);
			d3dScale.xoffset=tLeft;
			d3dScale.yoffset=tTop;	
			}

		if (d3dScale.xsize >= nScrnWidth)
			{
			d3dScale.xsize=nScrnWidth;	
			}
		else if (d3dScale.xsize<=100)
			{
			d3dScale.xsize=100;
			}

		FixAspect(d3dScale.xsize);
		nCount++;
	}

}


void VidXboxLoadScreenData()
{
	struct SScreenScale tempd3dScale;
	char cfgname[42] = "T:\\";
	
	// init stretch code
	FixAspect(640);
	d3dScale.xoffset = tLeft;
	d3dScale.yoffset = tTop;
	d3dScale.xsize = 640;

	memset(&tempd3dScale,0x00, sizeof(tempd3dScale));

	strcat((char *)cfgname, BurnDrvText(0));
	strcat((char *)cfgname, ".cfg");

    FILE *fs = fopen (cfgname, "rb");
    int len = 0;
    
    if (fs)
    {
		fread(&tempd3dScale,sizeof(tempd3dScale),1,fs);

		if (&tempd3dScale)
			memcpy(&d3dScale, &tempd3dScale,sizeof(tempd3dScale));

		fclose(fs);
    }
 
	FixAspect(d3dScale.xsize);
}

void VidXboxSaveScreenData()
{
	char cfgname[42] = "T:\\";
	if (d3dScale.xsize == 640)			// do nothing
		return;

	strcat((char *)cfgname, BurnDrvText(0));
	strcat((char *)cfgname, ".cfg");

    FILE *fs = fopen (cfgname, "wb");
    int len = 0;
    
    if (fs)
    {
		fwrite(&d3dScale, sizeof(d3dScale),1, fs);
		fclose(fs);
    }

	memset(&d3dScale,0x00, sizeof(d3dScale));
}

