#include <xtl.h>
#include <xboxmath.h>
#include <xui.h>    // XUI Runtime
#include <xuiapp.h> // XUI Class Library
#include <string>
#include <vector>
#include <xaudio2.h>
#include <stdint.h>
#include "Cemulator.h"
#include "Running.h"
#include "xui/select_iso.h"
#include "xbox_stdafx.h"

extern "C" {
	#include "plugins\gpu\draw.h"
	#include "plugins\gpu\swap.h"
	#include "plugins\gpu\GPUXenonStruct.h"
};

//#define _XBOX_PRED
#define printf 
#define XMemSet XMemSet
#define XMemCpy XMemCpy

#ifdef malloc
#undef malloc
#endif

#define RED(x) ((x>>24) & 0xff)
#define BLUE(x) ((x>>8) & 0xff)
#define GREEN(x) ((x>>16) & 0xff)
#define COLOR(x) SWAP32(x & 0xffffff)

#define BACK_BUFFER_SIZE (1024*512)*3 ///2*psxmax vram res

unsigned char * pPsxBackBuffer={0};

#ifdef CC_BUILD
static bool display_xui=true;
#else
static bool display_xui=true;
#endif

//ATG
VOID UnloadFile( VOID* pFileData );
HRESULT LoadFile( const CHAR* strFileName, VOID** ppFileData, DWORD* pdwFileSize );

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D9             g_pD3D = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9       g_pd3dDevice = NULL; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; // Buffer to hold vertices
IDirect3DTexture9 * g_texture = NULL;
IDirect3DTexture9 * g_bg_texture = NULL;
D3DPRESENT_PARAMETERS d3dpp; 

// Rendering surfaces and textures
#ifdef _XBOX_PRED
D3DSurface*                 m_pBackBuffer;
D3DSurface*                 m_pDepthBuffer;
D3DTexture*                 m_pFrontBuffer;
#endif

LPD3DXEFFECT g_effect = NULL;
//-------------------------------------------------------------------------------------
// Shader
//-------------------------------------------------------------------------------------
IDirect3DVertexDeclaration9* g_pVertexDecl;   // Vertex format decl

D3DXMATRIX g_matWorld;
D3DXMATRIX g_matProj;
D3DXMATRIX g_matView;
D3DXMATRIX g_matWorldViewProjection;

//-------------------------------------------------------------------------------------
// Audio
//-------------------------------------------------------------------------------------
IXAudio2* g_pXAudio2 = NULL;
IXAudio2MasteringVoice* g_pMasteringVoice = NULL;
IXAudio2SourceVoice* g_pSourceVoice = NULL;
WAVEFORMATEXTENSIBLE wfx;
XAUDIO2_BUFFER g_SoundBuffer;

//-------------------------------------------------------------------------------------
// Input
//-------------------------------------------------------------------------------------
#define SOUND_SAMPLES_SIZE  2048

float g_pTexelSize[2];

#define D3DFVF_TEXTURED (D3DFVF_XYZ|D3DFVF_TEX1)

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
struct TEXTURED
{
    FLOAT x, y, z;      // The untransformed, 3D position for the vertex
    FLOAT u,v;			// The texture coordonate
};

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
static const D3DVERTEXELEMENT9 g_ElementsTextured[4] =
{
    { 0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
    { 0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
    D3DDECL_END()
};

//-------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------
struct TEXTURED g_VerticesTextured[] =
{
	//square
	{ -1.0f, -1.0f, 0.0f,  0.0f,  1.0f },//1
	{ -1.0f,  1.0f, 0.0f,  0.0f,  0.0f },//2
	{  1.0f, -1.0f, 0.0f,  1.0f,  1.0f },//3
	{  1.0f,  1.0f, 0.0f,  1.0f,  0.0f }//4
};

//msaa
static const D3DRECT g_tiles[3] = 
{
    {             0,              0,  g_dwTileWidth,  g_dwTileHeight },
    {             0, g_dwTileHeight,  g_dwTileWidth, g_dwTileHeight * 2 },
    {             0, g_dwTileHeight * 2,  g_dwTileWidth, g_dwFrameHeight },
};

D3DXHANDLE  g_MaterialAmbientColor;
D3DXHANDLE  g_MaterialDiffuseColor;
D3DXHANDLE  g_mWorldViewProjection;
D3DXHANDLE  g_MeshTexture;
D3DXHANDLE  g_technique_bg;
D3DXHANDLE  g_technique_model;
D3DXHANDLE  g_TexelSize;
D3DXHANDLE  g_fTime;
//FXLTECHNIQUE_DESC techdesc;

LPD3DXBUFFER materialBuffer;
DWORD numMaterials;            // Note: DWORD is a typedef for unsigned long
LPD3DXMESH mesh;


// List of states to save.  We use an enum so that the list can evolve over time
// without worrying about re-ordering, inserting, or removing saved states.
enum SAVEDSTATES
{
    SAVEDSTATE_D3DRS_ALPHABLENDENABLE,
    SAVEDSTATE_D3DRS_SRCBLEND,
    SAVEDSTATE_D3DRS_DESTBLEND,
    SAVEDSTATE_D3DRS_BLENDOP,
    SAVEDSTATE_D3DRS_ALPHATESTENABLE,
    SAVEDSTATE_D3DRS_ALPHAREF,
    SAVEDSTATE_D3DRS_ALPHAFUNC,
    SAVEDSTATE_D3DRS_FILLMODE,
    SAVEDSTATE_D3DRS_CULLMODE,
    SAVEDSTATE_D3DRS_ZENABLE,
    SAVEDSTATE_D3DRS_STENCILENABLE,
    SAVEDSTATE_D3DRS_VIEWPORTENABLE,
    SAVEDSTATE_D3DSAMP_MINFILTER,
    SAVEDSTATE_D3DSAMP_MAGFILTER,
    SAVEDSTATE_D3DSAMP_ADDRESSU,
    SAVEDSTATE_D3DSAMP_ADDRESSV,

    SAVEDSTATE_MAX
};

DWORD m_dwSavedState[ SAVEDSTATE_MAX ];

//proto
void BlitScreen32df(unsigned char *surf, int32_t x, int32_t y);

static unsigned int SelectedRender=RENDER_D3D;

HRESULT Cemulator::InitXui()
{
	//Sauvegarde les states avant xui

	g_pd3dDevice->GetRenderState( D3DRS_ALPHABLENDENABLE,&m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHABLENDENABLE ] );
	g_pd3dDevice->GetRenderState( D3DRS_SRCBLEND, &m_dwSavedState[ SAVEDSTATE_D3DRS_SRCBLEND ] );
	g_pd3dDevice->GetRenderState( D3DRS_DESTBLEND, &m_dwSavedState[ SAVEDSTATE_D3DRS_DESTBLEND ] );
	g_pd3dDevice->GetRenderState( D3DRS_BLENDOP, &m_dwSavedState[ SAVEDSTATE_D3DRS_BLENDOP ] );
	g_pd3dDevice->GetRenderState( D3DRS_ALPHATESTENABLE, &m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHATESTENABLE ] );
	g_pd3dDevice->GetRenderState( D3DRS_ALPHAREF, &m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHAREF ] );
	g_pd3dDevice->GetRenderState( D3DRS_ALPHAFUNC, &m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHAFUNC ] );
	g_pd3dDevice->GetRenderState( D3DRS_FILLMODE, &m_dwSavedState[ SAVEDSTATE_D3DRS_FILLMODE ] );
	g_pd3dDevice->GetRenderState( D3DRS_CULLMODE, &m_dwSavedState[ SAVEDSTATE_D3DRS_CULLMODE ] );
	g_pd3dDevice->GetRenderState( D3DRS_ZENABLE, &m_dwSavedState[ SAVEDSTATE_D3DRS_ZENABLE ] );
	g_pd3dDevice->GetRenderState( D3DRS_STENCILENABLE, &m_dwSavedState[ SAVEDSTATE_D3DRS_STENCILENABLE ] );
	g_pd3dDevice->GetRenderState( D3DRS_VIEWPORTENABLE, &m_dwSavedState[ SAVEDSTATE_D3DRS_VIEWPORTENABLE ] );
	g_pd3dDevice->GetSamplerState( 0, D3DSAMP_MINFILTER, &m_dwSavedState[ SAVEDSTATE_D3DSAMP_MINFILTER ] );
	g_pd3dDevice->GetSamplerState( 0, D3DSAMP_MAGFILTER, &m_dwSavedState[ SAVEDSTATE_D3DSAMP_MAGFILTER ] );
	g_pd3dDevice->GetSamplerState( 0, D3DSAMP_ADDRESSU, &m_dwSavedState[ SAVEDSTATE_D3DSAMP_ADDRESSU ] );
	g_pd3dDevice->GetSamplerState( 0, D3DSAMP_ADDRESSV, &m_dwSavedState[ SAVEDSTATE_D3DSAMP_ADDRESSV ] );


	HRESULT hr;
	hr = InitShared( g_pd3dDevice, &d3dpp, XuiD3DXTextureLoader );
	//Init(XuiD3DXTextureLoader);
	if ( FAILED(hr) )
	{
		OutputDebugStringA( "Failed initializing application." );
		return hr;
	}

	// Load the skin file used for the scene.
	hr=LoadSkin( L"file://game:/media/skin.xzp#xuiskin\\skin.xur" );
	if ( FAILED(hr) )
	{
		OutputDebugStringA( "Failed LoadSkin application." );
	}

	// Register the font. 
	hr=RegisterDefaultTypeface( L"Arial Unicode MS", L"file://game:/media/xarialuni.ttf" ); 
	if ( FAILED(hr) )
	{
		OutputDebugStringA( "Failed RegisterDefaultTypeface application." );
	}
	hr=RegisterTypeface( L"DejaVu Sans", L"file://game:/media/DejaVuSans.ttf" ); 
	if ( FAILED(hr) )
	{
		OutputDebugStringA( "Failed RegisterTypeface application." );
	}

	hr=LoadFirstScene( L"file://game:/media/skin.xzp#xuiskin\\", L"select_iso.xur", NULL );
	if ( FAILED(hr) )
	{
		OutputDebugStringA( "Failed LoadFirstScene application." );
	}
	SelectedRender = RENDER_XUI;
	return S_OK;
};

/**
Test 
**/
void Cemulator::UnInitXui()
{
	Uninit();

	g_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHABLENDENABLE ] );
	g_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, m_dwSavedState[ SAVEDSTATE_D3DRS_SRCBLEND ] );
	g_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, m_dwSavedState[ SAVEDSTATE_D3DRS_DESTBLEND ] );
	g_pd3dDevice->SetRenderState( D3DRS_BLENDOP, m_dwSavedState[ SAVEDSTATE_D3DRS_BLENDOP ] );
	g_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHATESTENABLE ] );
	g_pd3dDevice->SetRenderState( D3DRS_ALPHAREF, m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHAREF ] );
	g_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, m_dwSavedState[ SAVEDSTATE_D3DRS_ALPHAFUNC ] );
	g_pd3dDevice->SetRenderState( D3DRS_FILLMODE, m_dwSavedState[ SAVEDSTATE_D3DRS_FILLMODE ] );
	g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, m_dwSavedState[ SAVEDSTATE_D3DRS_CULLMODE ] );
	g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, m_dwSavedState[ SAVEDSTATE_D3DRS_ZENABLE ] );
	g_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, m_dwSavedState[ SAVEDSTATE_D3DRS_STENCILENABLE ] );
	g_pd3dDevice->SetRenderState( D3DRS_VIEWPORTENABLE, m_dwSavedState[ SAVEDSTATE_D3DRS_VIEWPORTENABLE ] );
	
	m_pFrontBuffer->Release();
//	m_pDepthBuffer->Release();
//	m_pBackBuffer->Release();
	g_pd3dDevice->UnsetAll();

	InitVideo();

};

HRESULT Cemulator::InitVideo(){
//-------------------------------------------------------------------------------------
// Allocate memory for psx+scale stuff
//-------------------------------------------------------------------------------------
	pPsxBackBuffer=(unsigned char *)malloc(BACK_BUFFER_SIZE*sizeof(uint32_t));
	ZeroMemory( pPsxBackBuffer, BACK_BUFFER_SIZE*sizeof(uint32_t) );
//-------------------------------------------------------------------------------------
// Init Os
//-------------------------------------------------------------------------------------
	//InitWindows();

//-------------------------------------------------------------------------------------
// Create d3d device
//-------------------------------------------------------------------------------------
	if(g_pD3D==NULL)
		g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );

    if( !g_pD3D )
        return E_FAIL;

    ZeroMemory( &d3dpp, sizeof(d3dpp) );

	// Set up the structure used to create the D3DDevice.
	XVIDEO_MODE VideoMode;
	ZeroMemory( &VideoMode, sizeof( VideoMode ) );
	XGetVideoMode( &VideoMode );
	BOOL bEnable720p = ( VideoMode.dwDisplayHeight >= 720 ) ? TRUE : FALSE;
	SetSystemWidth(( bEnable720p ) ? 1280 : 640);
	SetSystemHeight(( bEnable720p ) ?  720 : 480);

#ifndef _XBOX_PRED
	d3dpp.BackBufferWidth        = 1280;
    d3dpp.BackBufferHeight       = 720;
	d3dpp.BackBufferFormat = ( D3DFORMAT )MAKESRGBFMT( D3DFMT_X8R8G8B8 );
    d3dpp.BackBufferCount        = 1;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
    d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD;
#else
	d3dpp.BackBufferWidth = GetSystemWidth();
	d3dpp.BackBufferHeight = GetSystemHeight();
    d3dpp.BackBufferFormat = ( D3DFORMAT )MAKESRGBFMT( D3DFMT_A8R8G8B8 );
    d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
    d3dpp.MultiSampleQuality = 0;
    d3dpp.BackBufferCount = 0;
    d3dpp.EnableAutoDepthStencil = FALSE;
    d3dpp.DisableAutoBackBuffer = TRUE;
    d3dpp.DisableAutoFrontBuffer = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
#endif

	d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
	//d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;

#ifdef _XBOX_PRED
	D3DSURFACE_PARAMETERS params = {0};
	g_pd3dDevice->CreateRenderTarget( g_dwTileWidth, g_dwTileHeight, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_4_SAMPLES, 0, 0, &m_pBackBuffer, &params );
	params.Base = m_pBackBuffer->Size / GPU_EDRAM_TILE_SIZE;
	params.HierarchicalZBase = D3DHIZFUNC_GREATER_EQUAL;

	g_pd3dDevice->CreateDepthStencilSurface( g_dwTileWidth, g_dwTileHeight, D3DFMT_D24S8, D3DMULTISAMPLE_4_SAMPLES, 0, 0, &m_pDepthBuffer, &params );
	g_pd3dDevice->CreateTexture( g_dwFrameWidth, g_dwFrameHeight, 1, 0, D3DFMT_LE_X8R8G8B8, 0, &m_pFrontBuffer, NULL );

	if(g_pd3dDevice==NULL)
	if( FAILED( g_pD3D->CreateDevice( 0, D3DDEVTYPE_HAL, NULL, D3DCREATE_BUFFER_2_FRAMES, &d3dpp, &g_pd3dDevice ) ) )
	{
        return E_FAIL;
	}

#else
	if(g_pd3dDevice==NULL)
	if( FAILED( g_pD3D->CreateDevice( 0, D3DDEVTYPE_HAL, NULL,
										D3DCREATE_BUFFER_2_FRAMES,
										&d3dpp, &g_pd3dDevice ) ) )
	{
		printf("CreateDevice failed\n");
        return E_FAIL;
	}
#endif
//-------------------------------------------------------------------------------------
// MSAA surface
//-------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------
// Create the buffer, and load the effect from the file.
//-------------------------------------------------------------------------------------
	HRESULT Result;
	ID3DXEffectCompiler* pCompiler;
	ID3DXBuffer* pCompiledData;

//-------------------------------------------------------------------------------------
// Create a ID3DXEffectCompiler interface for the effect that was just loaded.
//-------------------------------------------------------------------------------------
	Result = D3DXCreateEffectCompilerFromFileA(
         EFFECT_FILE,
         NULL,
         NULL,
         0,
         &pCompiler,
         NULL
	);
	if (FAILED(Result))
    {
		printf( "D3DXCreateEffectCompiler FAILED\n" );
        return Result;
    }

    // Compile the effect by using the ID3DXEffectCompiler interface, and then release the compiler.
    Result = pCompiler->CompileEffect(0, &pCompiledData, NULL);
    pCompiler->Release();
    if (FAILED(Result))
    {
		printf( "CompileEffect FAILED\n" );
        return Result;
    }

    // Create the effect that was just compiled.
    Result = D3DXCreateEffect(g_pd3dDevice, (DWORD*)pCompiledData->GetBufferPointer(), pCompiledData->GetBufferSize(),
                                        NULL, NULL, 0, NULL, &g_effect, NULL);

//-------------------------------------------------------------------------------------
// Create the model
//-------------------------------------------------------------------------------------
	HRESULT hr=D3DXLoadMeshFromXA(X_FILE, D3DXMESH_SYSTEMMEM, 
                             g_pd3dDevice, NULL, 
                             &materialBuffer,NULL, &numMaterials, 
                             &mesh );
//-------------------------------------------------------------------------------------
// Load the bg
//-------------------------------------------------------------------------------------
	D3DXCreateTextureFromFileA(g_pd3dDevice,BG_FILE,&g_bg_texture);

//-------------------------------------------------------------------------------------
// Create SMS RenderTexture
//-------------------------------------------------------------------------------------
#ifdef _XBOX_PRED
	D3DXCreateTexture(
		//g_pd3dDevice, GetWidth(),
		//GetHeight(), D3DX_DEFAULT, 0, D3DFMT_LIN_R5G6B5, D3DPOOL_MANAGED,
		g_pd3dDevice, GetWidth(),
		GetHeight(), D3DX_DEFAULT, 0, D3DFMT_LIN_A8R8G8B8, D3DPOOL_MANAGED,
		&g_texture
	);
#else
	D3DXCreateTexture(
		g_pd3dDevice, GetWidth(),
		GetHeight(), D3DX_DEFAULT, 0, D3DFMT_LIN_X8R8G8B8, D3DPOOL_MANAGED,
		&g_texture
	);
#endif
	

//-------------------------------------------------------------------------------------
// Create VB
//-------------------------------------------------------------------------------------
	g_pd3dDevice->CreateVertexDeclaration( g_ElementsTextured, &g_pVertexDecl );

    if( FAILED( g_pd3dDevice->CreateVertexBuffer( 4*sizeof(TEXTURED),
                                                  D3DUSAGE_WRITEONLY, 
                                                  NULL,
                                                  D3DPOOL_MANAGED, 
                                                  &g_pVB, 
                                                  NULL ) ) )
	{
		printf("CreateVertexBuffer failed\n");
        return E_FAIL;
	}

	TEXTURED* pVertices;

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

    XMemCpy( pVertices, g_VerticesTextured, 4*sizeof(TEXTURED) );
    g_pVB->Unlock();

//-------------------------------------------------------------------------------------
// Param from effectfile
//-------------------------------------------------------------------------------------	
	g_technique_bg = g_effect->GetTechniqueByName("RenderFullScreen");
	g_technique_model = g_effect->GetTechniqueByName("RenderModel");
	g_mWorldViewProjection = g_effect->GetParameterByName(NULL,  "g_mWorldViewProjection" );
	g_MaterialAmbientColor = g_effect->GetParameterByName(NULL,  "g_MaterialAmbientColor" );
	g_MaterialDiffuseColor = g_effect->GetParameterByName(NULL,  "g_MaterialDiffuseColor" );
	g_mWorldViewProjection = g_effect->GetParameterByName(NULL,  "g_mWorldViewProjection" );
	g_MeshTexture = g_effect->GetParameterByName(NULL,  "g_MeshTexture" );
	g_TexelSize = g_effect->GetParameterByName(NULL,  "g_TexelSize" );
	g_fTime = g_effect->GetParameterByName(NULL,  "g_fTime" );

//-------------------------------------------------------------------------------------
// Default Renderstates
//-------------------------------------------------------------------------------------
	g_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
	g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
	g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
	g_pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL);

//-------------------------------------------------------------------------------------
// Initialise view
//-------------------------------------------------------------------------------------
	// Initialize the world matrix
	D3DXMatrixIdentity(&g_matWorld);

	D3DXMATRIX scale;

    // Initialize the projection matrix
    FLOAT fAspect = 16.0f / 9.0f; 
	D3DXMatrixPerspectiveFovLH(&g_matProj, D3DX_PI/4, fAspect, 1.0f, 200.0f );

    // Initialize the view matrix
	D3DXVECTOR3 vEyePt    = D3DXVECTOR3( 0.f, 0.f, -8.f );
    D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.f, 0.f, 0.f );
    D3DXVECTOR3 vUp       = D3DXVECTOR3( 0.f, 1.f, 1.f );
	D3DXMatrixLookAtLH(&g_matView,&vEyePt, &vLookatPt, &vUp );

	g_matWorldViewProjection = g_matWorld * g_matView * g_matProj;

	//donne le droit au thread :D
	//g_pd3dDevice->ReleaseThreadOwnership();

	return S_OK;
};

int SelectedFilter=0;
int FilterMulti=2;

PSXDisplay_t CurDisplay;
PSXDisplay_t OldDisplay;

#define PSXDISP CurDisplay

void BlitPsxScreen(long width, long height, unsigned char * buffer , unsigned char *screen, int pitch);
void Cemulator::SetFilter(int i)
{
SelectedFilter=i;
}
void Cemulator::UpdateVideo()
{

	switch(SelectedFilter)
	{
		case 0://scale2x
			FilterMulti=2;
			break;
		case 1://hq2x
			FilterMulti=2;
			break;
		case 2://hq3x
			FilterMulti=3;
			break;
	}

	int w=PSXDISP.DisplayMode.x;
	int h=PSXDISP.DisplayMode.y;

	if(FilterMulti>1)
	{
		w*=FilterMulti;
		h*=FilterMulti;
	}

	//Créer une surface correspondate à l'affichage
	if(	(w!=GetWidth())	||	(h!=GetHeight())	)
	{
		mScreenWidth=w;
		mScreenHeight=h;

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

		D3DXCreateTexture(
			g_pd3dDevice, GetWidth(),
			GetHeight(), D3DX_DEFAULT, 0, D3DFMT_LIN_X8R8G8B8, D3DPOOL_MANAGED,
			&g_texture
		);
	}

//-------------------------------------------------------------------------------------
// Refresh texture cache
//-------------------------------------------------------------------------------------
	RECT d3dr;

	d3dr.left=0;
	d3dr.top=0;
	d3dr.right=GetWidth();
	d3dr.bottom=GetHeight();

	D3DLOCKED_RECT texture_info;

	g_texture->LockRect( 0,  &texture_info, &d3dr, NULL );

	//copie la texture en vram ici :D
	unsigned char *  screen = (unsigned char *)texture_info.pBits;
	
	if(FilterMulti==1)
	{
		BlitScreen32df((unsigned char *)pPsxBackBuffer,PSXDISP.DisplayPosition.x,PSXDISP.DisplayPosition.y);
		BlitPsxScreen(PSXDISP.DisplayPosition.x,PSXDISP.DisplayPosition.y,(unsigned char *)pPsxBackBuffer,screen,PSXDISP.DisplayMode.x<<2);
	}
	else
	{
		BlitScreen32df((unsigned char *)pPsxBackBuffer,PSXDISP.DisplayPosition.x,PSXDISP.DisplayPosition.y);
		switch(SelectedFilter)
		{
			case 0://scale2x
				Std2xSaI_ex8(pPsxBackBuffer, PSXDISP.DisplayMode.x<<2, screen,PSXDISP.DisplayMode.x,PSXDISP.DisplayMode.y);
				break;
			case 1://hq2x
				hq2x_32(pPsxBackBuffer, PSXDISP.DisplayMode.x<<2, screen,PSXDISP.DisplayMode.x,PSXDISP.DisplayMode.y);
				break;
			case 2://hq3x
				hq3x_32(pPsxBackBuffer, PSXDISP.DisplayMode.x<<2, screen,PSXDISP.DisplayMode.x,PSXDISP.DisplayMode.y);
				break;
		}
	}
	
			
	g_texture->UnlockRect(0);
};

void BlitPsxScreen(long width, long height, unsigned char * buffer , unsigned char *screen, int pitch)
{
	long long int *dst = (long long int *) screen;
	long long int *src1 = (long long int *) buffer;
	long long int *src2 = (long long int *) (buffer + pitch);
	long long int *src3 = (long long int *) (buffer + (pitch * 2));
	long long int *src4 = (long long int *) (buffer + (pitch * 3));
	int rowpitch = (pitch >> 3) * 4  - (width >> 2);

	for (int h = 0; h < height; h += 4)
	{

		for (int w = 0; w < (width >> 2); w++)
		{
			*dst++ = *src1++;
			*dst++ = *src2++;
			*dst++ = *src3++;
			*dst++ = *src4++;
		}
		src1 += rowpitch;
		src2 += rowpitch;
		src3 += rowpitch;
		src4 += rowpitch;
	}
}

HRESULT Cemulator::InitSystem()
{
//-------------------------------------------------------------------------------------
// Set up rendering texture
//-------------------------------------------------------------------------------------
	RECT d3dr;

	d3dr.left=0;
	d3dr.top=0;
	d3dr.right=GetWidth();
	d3dr.bottom=GetHeight();
	
//-------------------------------------------------------------------------------------
// Set up bitmap structure
//-------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------
// Set up sound
//-------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------
// Load roms
//-------------------------------------------------------------------------------------

//-------------------------------------------------------------------------------------
// Start system
//-------------------------------------------------------------------------------------

	return S_OK;
};


HRESULT Cemulator::LoadGame(std::string name, bool restart)
{
//-------------------------------------------------------------------------------------
// Init System + load + start ...
//-------------------------------------------------------------------------------------
	RunPsx();
//-------------------------------------------------------------------------------------
// Start system
//-------------------------------------------------------------------------------------
	
	return S_OK;
};

float ftime=0.f;

//-------------------------------------------------------------------------------------
// Clear screen
//-------------------------------------------------------------------------------------	
void Cemulator::ClearScreen()
{
#ifdef _XBOX_PRED
	const D3DVECTOR4 clearColor = { 0.f, 0.f, 0.f, 1.f };
    g_pd3dDevice->BeginTiling( 0, ARRAYSIZE(g_tiles), g_tiles, &clearColor, 1, 0 );
	g_pd3dDevice->SetPredication( 0 );
#else
	g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_ZBUFFER |D3DCLEAR_TARGET,  D3DCOLOR_XRGB(70,140,255), 1.0f, 0 );
#endif
}

void Cemulator::StartEmulation()
{
	display_xui=false;
	SelectedRender=RENDER_D3D;
};

void Cemulator::RenderXui()
{
	RunFrame();
	HRESULT hr=Render();
	if ( FAILED(hr) )
	{
		return;//Error
	}
	hr=XuiTimersRun();
	if ( FAILED(hr) )
	{
		return;//Error
	}
}

void Cemulator::RenderVideo()
{
	unsigned int iPass, cPasses;

	g_pd3dDevice->BeginScene();

	// Set effect variables as needed
    D3DXCOLOR colorMtrlDiffuse( 1.0f, 1.0f, 1.0f, 1.0f );
    D3DXCOLOR colorMtrlAmbient( 0.35f, 0.35f, 0.35f, 0 );

//-------------------------------------------------------------------------------------
// Clear screen
//-------------------------------------------------------------------------------------	
#ifdef _XBOX_PRED
	g_pd3dDevice->SetRenderTarget( 0, m_pBackBuffer );
	g_pd3dDevice->SetDepthStencilSurface( m_pDepthBuffer );
#endif
	ClearScreen();
//-------------------------------------------------------------------------------------
// Setup technique
//-------------------------------------------------------------------------------------	
	g_pTexelSize[0]=1.f/float(GetWidth());
	g_pTexelSize[1]=1.f/float(GetHeight());
	ftime+=0.1f;
	g_effect->SetValue( g_MaterialAmbientColor, &colorMtrlAmbient, sizeof( D3DXCOLOR ) );
    g_effect->SetValue( g_MaterialDiffuseColor, &colorMtrlDiffuse, sizeof( D3DXCOLOR ) );
	g_effect->SetValue ( g_fTime, &ftime, sizeof(float));
	g_effect->SetMatrix( g_mWorldViewProjection, &g_matWorldViewProjection );
	g_effect->SetTexture( g_MeshTexture, g_texture );
	g_effect->SetTechnique( g_technique_model );
    g_effect->SetFloatArray(g_TexelSize,g_pTexelSize,2);

	g_pd3dDevice->SetFVF( D3DFVF_XYZ|D3DFVF_TEX1 );

//-------------------------------------------------------------------------------------
// Render
//-------------------------------------------------------------------------------------	
	
//-------------------------------------------------------------------------------------
// Draw Bg
//-------------------------------------------------------------------------------------	
	g_effect->SetTechnique( g_technique_bg );
	g_effect->SetTexture( g_MeshTexture, g_bg_texture );
	g_effect->Begin( &cPasses, 0 );
	g_pd3dDevice->SetVertexDeclaration( g_pVertexDecl );
	g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(TEXTURED) );
	for( iPass = 0; iPass < cPasses; iPass++ )
	{
		g_effect->BeginPass( iPass );
		g_pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLESTRIP, 2, g_VerticesTextured, sizeof( TEXTURED ) );
		g_effect->EndPass();
	}
	g_effect->End();

//-------------------------------------------------------------------------------------
// Draw Game
//-------------------------------------------------------------------------------------	
	g_effect->SetTechnique( g_technique_model );
	g_effect->SetTexture( g_MeshTexture, g_texture );
	g_effect->Begin( &cPasses, 0 );
	for( iPass = 0; iPass < cPasses; iPass++ )
	{
		g_effect->BeginPass( iPass );
		mesh->DrawSubset(0);
		g_effect->EndPass();
	}
	g_effect->End();
//-------------------------------------------------------------------------------------
// Draw Xui
//-------------------------------------------------------------------------------------	
	if(SelectedRender==RENDER_XUI)
	{
		RenderXui();
	}
//-------------------------------------------------------------------------------------
// Affiche
//-------------------------------------------------------------------------------------	
	g_pd3dDevice->EndScene();
#ifdef _XBOX_PRED
	g_pd3dDevice->SetPredication( 0 );
	g_pd3dDevice->EndTiling( 0, NULL, m_pFrontBuffer, NULL, 1, 0, NULL );
    
    // Present the backbuffer contents to the display
    g_pd3dDevice->SynchronizeToPresentationInterval();
	g_pd3dDevice->Swap( m_pFrontBuffer, NULL );
#else
	g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
#endif
};



HRESULT Cemulator::Run()
{
//-------------------------------------------------------------------------------------
// Lance l'application
//-------------------------------------------------------------------------------------	
	if(FAILED( InitVideo()	))
	{
		printf("InitVideo failed\n");
		return E_FAIL;
	}
	if(FAILED( InitSystem()	))
	{
		printf("InitSystem failed\n");
		return E_FAIL;
	}

	return S_OK;
};


HRESULT Cemulator::CloseVideo()
{
	g_texture->Release();
	g_pd3dDevice->Release();
	g_pD3D->Release();

	return S_OK;	
};

HRESULT Cemulator::CloseSystem()
{
	return S_OK;	
};


HRESULT Cemulator::UnregisterXuiClasses()
{	
	SceneIsoSelection::Unregister();
	XuiIsoList::Unregister();
	return S_OK;
}

HRESULT Cemulator::RegisterXuiClasses()
{
	SceneIsoSelection::Register();
	XuiIsoList::Register();
	return S_OK;
}

unsigned short * PSXVram;
#define PSXRAM_SZE ((512*2)*1024 + (1024*1024))+(512 * 1024)
void Cemulator::InitE()
{
	mScreenWidth=640;
	mScreenHeight=512;

	end=false;
	defaut_rom=DEFAULT_GAME;

	PSXVram	=(unsigned short *)XPhysicalAlloc(PSXRAM_SZE, MAXULONG_PTR, 0,PAGE_READWRITE | MEM_LARGE_PAGES);
}

bool Cemulator::IsXuiDisplayed()
{
	return display_xui;

};


static bool display=false;

#define THREADCOUNT 1

static HANDLE h_sepRenderThread=NULL;

static void InitSemaphore()
{
	h_sepRenderThread = CreateSemaphoreA( 
		NULL,              // default security attributes
		THREADCOUNT,             // initially not owned
		THREADCOUNT,
		"ThreadedDisplay"
	);
}

HRESULT Cemulator::SetupThread()
{
	InitSemaphore();//bloque ...
	//release d3d
	g_pd3dDevice->ReleaseThreadOwnership();
	//loop le thread
	AttachThread(ThreadedDisplay);
	RunThread();
	return S_OK;
}

HRESULT Cemulator::Display()
{
	XMemCpy(PSXVram,psxVuw,PSXRAM_SZE-(1024));
	CurDisplay=PSXDisplay;
	OldDisplay=PreviousPSXDisplay;

#ifdef USE_DISPLAY_THREAD
	display=true;
	SelectedRender=RENDER_D3D;
	ReleaseSemaphore(h_sepRenderThread,1,NULL);
#else
	UpdateVideo();
	RenderVideo();
#endif
	return S_OK;
}

/**
Tourne en boucle
**/
DWORD WINAPI Cemulator::ThreadedDisplay(void * Obj)
{
	if(Obj==NULL)
		DebugBreak();
	
	g_pd3dDevice->AcquireThreadOwnership();
	while(1)
	{
		WaitForSingleObject(h_sepRenderThread, INFINITE);
		if(display)//affiche d3d
		{
			Cemulator::GetInstance().UpdateVideo();
			Cemulator::GetInstance().RenderVideo();
		}
		//affiche xui
		if(SelectedRender==RENDER_XUI)
		{
			Cemulator::GetInstance().RenderVideo();
		}
		InitSemaphore();
	}
	//rendu fini libere
	g_pd3dDevice->ReleaseThreadOwnership();
	//ReleaseSemaphore(h_sepRenderThread,1,NULL);
	return S_OK;
}
//-------------------------------------------------------------------------------------
// ATG !!
//-------------------------------------------------------------------------------------	

//--------------------------------------------------------------------------------------
// Name: LoadFile()
// Desc: Helper function to load a file
//--------------------------------------------------------------------------------------
HRESULT LoadFile( const CHAR* strFileName, VOID** ppFileData, DWORD* pdwFileSize )
{
	//assert( ppFileData );
    if( pdwFileSize )
        *pdwFileSize = 0L;

    // Open the file for reading
    HANDLE hFile = CreateFileA( strFileName, GENERIC_READ, 0, NULL,
                               OPEN_EXISTING, 0, NULL );

    if( INVALID_HANDLE_VALUE == hFile )
        return E_HANDLE;

    DWORD dwFileSize = GetFileSize( hFile, NULL );
    VOID* pFileData = malloc( dwFileSize );

    if( NULL == pFileData )
    {
        CloseHandle( hFile );
        return E_OUTOFMEMORY;
    }

    DWORD dwBytesRead;
    if( !ReadFile( hFile, pFileData, dwFileSize, &dwBytesRead, NULL ) )
    {
        CloseHandle( hFile );
        free( pFileData );
        return E_FAIL;
    }

    // Finished reading file
    CloseHandle( hFile );

    if( dwBytesRead != dwFileSize )
    {
        free( pFileData );
        return E_FAIL;
    }

    if( pdwFileSize )
        *pdwFileSize = dwFileSize;
    *ppFileData = pFileData;

    return S_OK;
}


//--------------------------------------------------------------------------------------
// Name: UnloadFile()
// Desc: Matching unload
//--------------------------------------------------------------------------------------
VOID UnloadFile( VOID* pFileData )
{
	//assert( pFileData != NULL );
    free( pFileData );
}


//#define PSXVram psxVuw
void BlitScreen32df(unsigned char *surf, int32_t x, int32_t y)
{
	unsigned char *pD=NULL;
	unsigned int startxy;
	uint32_t lu=0;
	unsigned short s, s1, s2, s3, s4, s5, s6, s7;
	int row, column;
	unsigned short dx = OldDisplay.Range.x1;
	unsigned short dy = (unsigned short)OldDisplay.DisplayMode.y;

	int32_t lPitch = PSXDISP.DisplayMode.x << 2;

	uint32_t *destpix;

	if (OldDisplay.Range.y0) // centering needed?
	{
		XMemSet(surf, 0, (OldDisplay.Range.y0 >> 1) * lPitch);

		dy -= PreviousPSXDisplay.Range.y0;
		surf += (OldDisplay.Range.y0 >> 1) * lPitch;

		XMemSet(surf + dy * lPitch,
			0, ((OldDisplay.Range.y0 + 1) >> 1) * lPitch);
	}

	if (OldDisplay.Range.x0)
	{
		for (column = 0; column < dy; column++)
		{
			destpix = (uint32_t *)(surf + (column * lPitch));
			XMemSet(destpix, 0, OldDisplay.Range.x0 << 2);
		}
		surf += OldDisplay.Range.x0 << 2;
	}

	if (PSXDISP.RGB24)//used for video
	{
		for (column = 0; column < dy; column++)
		{
			startxy = ((1024) * (column + y)) + x;
			//__dcbt(startxy,psxVuw);
			pD = (unsigned char *)&PSXVram[startxy];
			destpix = (uint32_t *)(surf + (column * lPitch));

			for (row = 0; row < dx; row++)
			{
				lu = *((uint32_t *)pD);
				destpix[row] = 
					0xff000000 | (RED(lu) << 16) | (GREEN(lu) << 8) | (BLUE(lu));
				pD += 3;
			}
		}
	}
	else
	{
		{
			for (column = 0;column<dy;column++)
			{
				startxy = (1024 * (column + y)) + x;
				destpix = (uint32_t *)(surf + (column * lPitch));

				for (row = 0; row < dx; row+=8)
				{			
					s = __loadshortbytereverse((int)&PSXVram[startxy++],0);
					s1 = __loadshortbytereverse((int)&PSXVram[startxy++],0);
					s2 = __loadshortbytereverse((int)&PSXVram[startxy++],0);
					s3 = __loadshortbytereverse((int)&PSXVram[startxy++],0);
					s4 = __loadshortbytereverse((int)&PSXVram[startxy++],0);
					s5 = __loadshortbytereverse((int)&PSXVram[startxy++],0);
					s6 = __loadshortbytereverse((int)&PSXVram[startxy++],0);
					s7 = __loadshortbytereverse((int)&PSXVram[startxy++],0);

					destpix[row] = 
						(((s << 19) & 0xf80000) | ((s << 6) & 0xf800) | ((s >> 7) & 0xf8)) | 0xff000000;
					destpix[row+1] = 
						(((s1 << 19) & 0xf80000) | ((s1 << 6) & 0xf800) | ((s1 >> 7) & 0xf8)) | 0xff000000;
					destpix[row+2] = 
						(((s2 << 19) & 0xf80000) | ((s2 << 6) & 0xf800) | ((s2 >> 7) & 0xf8)) | 0xff000000;
					destpix[row+3] = 
						(((s3 << 19) & 0xf80000) | ((s3 << 6) & 0xf800) | ((s3 >> 7) & 0xf8)) | 0xff000000;
					destpix[row+4] = 
						(((s4 << 19) & 0xf80000) | ((s4 << 6) & 0xf800) | ((s4 >> 7) & 0xf8)) | 0xff000000;
					destpix[row+5] = 
						(((s5 << 19) & 0xf80000) | ((s5 << 6) & 0xf800) | ((s5 >> 7) & 0xf8)) | 0xff000000;
					destpix[row+6] = 
						(((s6 << 19) & 0xf80000) | ((s6 << 6) & 0xf800) | ((s6 >> 7) & 0xf8)) | 0xff000000;
					destpix[row+7] = 
						(((s7 << 19) & 0xf80000) | ((s7 << 6) & 0xf800) | ((s7 >> 7) & 0xf8)) | 0xff000000;

				}
			}
		}
	}

}


























































#if 0// later use
HRESULT Cemulator::InitAudio()
{
//-------------------------------------------------------------------------------------
// Initialise Audio
//-------------------------------------------------------------------------------------	
	HRESULT hr;
	if( FAILED( hr = XAudio2Create( &g_pXAudio2, 0 ) ) )
    {
        printf( "Failed to init XAudio2 engine: %#X\n", hr );
        return E_FAIL;
    }

//-------------------------------------------------------------------------------------
// Create a mastering voice
//-------------------------------------------------------------------------------------	
    if( FAILED( hr = g_pXAudio2->CreateMasteringVoice( &g_pMasteringVoice ) ) )
    {
		printf( "Failed creating mastering voice: %#X\n", hr );
        return E_FAIL;
    }

//-------------------------------------------------------------------------------------
// Create source voice
//-------------------------------------------------------------------------------------	
	WAVEFORMATEXTENSIBLE wfx;
	XMemSet(&wfx, 0, sizeof(WAVEFORMATEXTENSIBLE));
	wfx.Format.wFormatTag           = WAVE_FORMAT_EXTENSIBLE;
	wfx.Format.nSamplesPerSec       = 44100;
	wfx.Format.nChannels            = 2;
	wfx.Format.wBitsPerSample       = 16;
	wfx.Format.nBlockAlign          = wfx.Format.nChannels*wfx.Format.wBitsPerSample/8;
	wfx.Format.nAvgBytesPerSec      = 44100 * wfx.Format.nBlockAlign;
	wfx.Format.cbSize               = sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX);
	wfx.Samples.wValidBitsPerSample = 16;
	wfx.dwChannelMask               = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
	wfx.SubFormat                   = KSDATAFORMAT_SUBTYPE_PCM;

	if(FAILED( g_pXAudio2->CreateSourceVoice(&g_pSourceVoice,(WAVEFORMATEX*)&wfx,0)	))
	{
		printf("CreateSourceVoice failed\n");
		return E_FAIL;
	}

//-------------------------------------------------------------------------------------
// Start sound
//-------------------------------------------------------------------------------------	
	if ( FAILED(g_pSourceVoice->Start( 0 ) ) )
	{
		printf("g_pSourceVoice failed\n");
		return E_FAIL;
	}
	return S_OK;
};

void Cemulator::UpdateAudio()
{
	
};

HRESULT Cemulator::InitInput()
{

	return S_OK;
}

void Cemulator::UpdateInput()
{
	
};

HRESULT Cemulator::CloseAudio()
{
//	g_pSourceVoice->Stop();
	g_pMasteringVoice->DestroyVoice();
	g_pSourceVoice->DestroyVoice();
	free(&g_SoundBuffer);
	return S_OK;	
};

HRESULT Cemulator::CloseInput()
{
	return S_OK;	
};
#endif