#include "D3DApp.h"
#include "resource.h"
#include "..\utilities\fastmath.h"

#include <Winuser.h>
#include <Windows.h>
#include <math.h>
#include <stdio.h>
#include <fstream>
#include <time.h>
#include <oleauto.h>
#include <commctrl.h>
#include <objbase.h>
#include <wtypes.h>
#include <cguid.h>

#include "devicestatemanager.h"
#include "texturemanager.h"
#include "shadermanager.h"
#include "fontmanager.h"
#include "Compositor.h"

BOOL g_AllowFullScreen;
STSelMode * g_SelMode;
LList<STAdapter> *g_Adapters;

bool STSelMode::Save(XString fn)
{
	FILE *f;
	fopen_s(&f, fn.getbuffer(),"wb");
	if(f)
	{
		fwrite(&Adapter,sizeof(DWORD),1,f);
		fwrite(&Windowed,sizeof(bool),1,f);
		fwrite(&Width,sizeof(UINT),1,f);
		fwrite(&Height,sizeof(UINT),1,f);
		fwrite(&RefreshRate,sizeof(UINT),1,f);
		fwrite(&VSync,sizeof(bool),1,f);
		fwrite(&BB32Bit,sizeof(bool),1,f);
		fwrite(&Antialiasing,sizeof(DWORD),1,f);
		fclose(f);
		return true;
	}
	else
		return false;
}

bool STSelMode::Open(XString fn)
{
	FILE *f;
	fopen_s(&f, fn.getbuffer(),"rb");
	if(f)
	{
		fread(&Adapter,sizeof(DWORD),1,f);
		fread(&Windowed,sizeof(bool),1,f);
		fread(&Width,sizeof(UINT),1,f);
		fread(&Height,sizeof(UINT),1,f);
		fread(&RefreshRate,sizeof(UINT),1,f);
		fread(&VSync,sizeof(bool),1,f);
		fread(&BB32Bit,sizeof(bool),1,f);
		fread(&Antialiasing,sizeof(DWORD),1,f);
		fclose(f);
		return true;
	}
	else
		return false;
}

void STSelMode::SetDefault(void)
{
	Adapter = 0;
	Windowed = false;
	Width = 1024;
	Height = 768;
    RefreshRate = 0;
	VSync = false;
	BB32Bit = true;
	Antialiasing = 0;
}

D3DApp::D3DApp(void)
{
	build_sqrt_table();
	build_sin_table();

	m_bDeviceLost = true;
	m_pD3D        = Direct3DCreate9( D3D_SDK_VERSION );
	m_pD3DDevice  = NULL;
	m_Device = NULL;

	m_Run = true;
	m_Active = true;

	EnumAdapters();
}

D3DApp::~D3DApp(void)
{
	Invalidate();

	SAFEDELETE(m_Device)

	SAFERELEASE(m_pD3DDevice)
	SAFERELEASE(m_pD3D)
	
	m_lAdapters.Clear();
	g_Adapters = NULL;
}
	
HRESULT D3DApp::Reset3D(const STSelMode& mode)
{
	if(!m_Device)
		return E_FAIL;

	m_Device->Invalidate();
	
	Invalidate();
	
	memcpy(&m_CurrentMode,&mode,sizeof(STSelMode));
	m_CurrentMode.InitPresentParam(m_PresentParam, m_hWnd);

	HRESULT hr = m_pD3DDevice->Reset(&m_PresentParam);
	
	if(FAILED(hr))
	{
		m_bDeviceLost = true;
		wlog("cant reset %r",hr);
		return E_FAIL;
	}

	//CreateObjects();

	m_pD3DDevice->BeginScene();

	m_Device->Restore();
	Restore();

	m_bDeviceLost = false;

	return S_OK;
}

void D3DApp::Render(void)
{
	HRESULT         hr;
		
	if (!m_pD3DDevice)
		return ;

	if (m_bDeviceLost)
		Sleep(50);

	if( FAILED( hr = m_pD3DDevice->TestCooperativeLevel() ) )
	{
		if( D3DERR_DEVICELOST == hr )
		{
			if (!m_bDeviceLost)
			{
				wlog("Device Lost");
				m_bDeviceLost = true;
			}
			return ;
		}
		if( D3DERR_DEVICENOTRESET == hr )
		{
			wlog("Reseting Device.");

			hr = Reset3D(m_CurrentMode);

			if (FAILED(hr))
			{
				wlog("Reset Failed.");
				return;
			}


			//m_Device->Restore();

			//Restore();

			/*if(!FAILED( hr = Restore() ) )
			{
				m_bDeviceLost = true;
				return ;
			}*/
		} 
		return ;
	}
 
	m_pD3DDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, 0, 1.0f, 0L );
	//m_pD3DDevice->Clear( 0L, NULL, D3DCLEAR_ZBUFFER, 0, 1.0f, 0L );

	UpdateScene(); 	

	RenderScene();
	
    m_pD3DDevice->EndScene();

	//hack to keep frame/ai correlative 
	D3DLOCKED_RECT rc;
	LPDIRECT3DSURFACE9 bb;
	m_pD3DDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&bb);
	bb->LockRect(&rc,NULL,0);
	bb->UnlockRect();
	bb->Release();

	hr = m_pD3DDevice->Present( NULL, NULL, NULL, NULL );


	m_Clock.Tick();

	// we make this here because maybe we want do some rendertotexture
	m_pD3DDevice->BeginScene();
}

//void D3DApp::CreateObjects(void)
//{
//	D3DMATERIAL9 mtrl;
//
//	if (!m_pDevice)
//		return ;
//
//	ZeroMemory( &mtrl, sizeof(D3DMATERIAL9) );
//    mtrl.Diffuse.r = mtrl.Ambient.r = 1.0;
//    mtrl.Diffuse.g = mtrl.Ambient.g = 1.0;
//    mtrl.Diffuse.b = mtrl.Ambient.b = 1.0;
//    mtrl.Diffuse.a = mtrl.Ambient.a = 1.0;
//
//    m_pDeviceStateManager->SetMaterial( mtrl );
//
//   /* DXVector3 vFromPt( -20, 20, -20);
//    DXVector3 vLookatPt( 0.0f, 0.0f, 0.0f );
//    DXVector3 vUpVec( 0.0f, 1.0f, 0.0f );
//    D3DXMatrixLookAtLH( &matView, &vFromPt, &vLookatPt, &vUpVec );
//    pd3dDevice->SetTransform( D3DTS_VIEW, &matView );*/
//
//	RECT wndrc;
//
//	GetClientRect(m_hWnd,&wndrc);
//
//	D3DXMATRIX matProj;
//	//FLOAT fAspect = (float)(d3dpp.BackBufferWidth) / (float)(d3dpp.BackBufferHeight);
//	//float fov = D3DX_PI/4.f;
//	//if (fAspect>1.0f)
//	//	fov/=fAspect;
//
////    D3DXMatrixPerspectiveFovLH( &matProj, fov, fAspect, 1.0f, 1000.f);
//	float m;
//	if(m_PresentParam.BackBufferWidth>m_PresentParam.BackBufferHeight)
//		m=(float)m_PresentParam.BackBufferWidth;
//	else
//		m=(float)m_PresentParam.BackBufferHeight;
//	D3DXMatrixPerspectiveLH(&matProj,(m_PresentParam.BackBufferWidth)/m,(m_PresentParam.BackBufferHeight)/m,0.1f,3500.f);
//	//D3DXMatrixPerspectiveLH(&matProj,(wndrc.right-wndrc.left)/1280.f,(wndrc.bottom-wndrc.top)/1024.f,0.1f,10000.f);
//
//    m_pDeviceStateManager->SetProjMatrix( matProj );
//
//}

void STSelMode::InitPresentParam(D3DPRESENT_PARAMETERS& pp, HWND hWnd)
{
	ZeroMemory(&pp, sizeof(D3DPRESENT_PARAMETERS));

	pp.Windowed = Windowed;

	if(Windowed)
	{
		RECT wndrc;
	
		GetClientRect(hWnd, &wndrc);

		pp.BackBufferWidth  = (wndrc.right - wndrc.left );
		pp.BackBufferHeight = (wndrc.bottom - wndrc.top );
		Width = pp.BackBufferWidth;
		Height = pp.BackBufferHeight;

		pp.FullScreen_RefreshRateInHz = 0;
	}
	else
	{
		pp.BackBufferWidth  = Width;
		pp.BackBufferHeight = Height;

		if(VSync)
			pp.FullScreen_RefreshRateInHz = RefreshRate;
		else
			pp.FullScreen_RefreshRateInHz = 0;
	}

    pp.BackBufferCount        = 1;

    pp.EnableAutoDepthStencil = true;

	if(BB32Bit)
	{
		pp.AutoDepthStencilFormat = D3DFMT_D24S8;
		pp.BackBufferFormat = D3DFMT_X8R8G8B8;
	}
	else
	{
		pp.AutoDepthStencilFormat = D3DFMT_D16;
		pp.BackBufferFormat = D3DFMT_R5G6B5;
	}

    pp.hDeviceWindow          = hWnd; 

	if(Antialiasing)
	{
		pp.SwapEffect         = D3DSWAPEFFECT_DISCARD;
		pp.MultiSampleType    = D3DMULTISAMPLE_NONMASKABLE;
		pp.MultiSampleQuality = Antialiasing - 1;
	}
	else
	{
		pp.SwapEffect         = D3DSWAPEFFECT_FLIP;
		//pp.SwapEffect         = D3DSWAPEFFECT_DISCARD;
		pp.MultiSampleQuality = 0;
		pp.MultiSampleType    = D3DMULTISAMPLE_NONE;
	}

	pp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
 
	if(VSync)
		pp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
	else
		pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

}

HRESULT D3DApp::Run(void)
{
	MSG			msg;

	while(m_Run)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
        {
            if (!GetMessage(&msg, NULL, 0, 0))
			{
                //return msg.wParam;
				return E_FAIL;
			}
			
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else if (m_Active)
        {
			if(DeviceLost())
			{
				Sleep(100);
			}
			else
			{
				Render();
			}
        }
        else
        {
            WaitMessage();
        }
    }

	return S_OK;
}

void D3DApp::Init3D(int wnd,const STSelMode& mode, bool multithreaded)
{
	HRESULT hr;

	m_hWnd = (HWND)wnd;

	memcpy(&m_CurrentMode,&mode,sizeof(STSelMode));
	m_CurrentMode.InitPresentParam(m_PresentParam, m_hWnd);
	
	DWORD flags = D3DCREATE_PUREDEVICE | D3DCREATE_HARDWARE_VERTEXPROCESSING | (multithreaded ? D3DCREATE_MULTITHREADED : 0);

	//if( FAILED( hr = m_pD3D->CreateDevice(1, D3DDEVTYPE_REF, m_hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING ,&m_PresentParam,  &m_pD3DDevice) ) )
	if( FAILED( hr = m_pD3D->CreateDevice(m_CurrentMode.Adapter, D3DDEVTYPE_HAL, m_hWnd, flags, &m_PresentParam,  &m_pD3DDevice) ) )
	//if( FAILED( hr = m_pD3D->CreateDevice(m_CurrentMode.Adapter, D3DDEVTYPE_REF, m_hWnd, flags, &m_PresentParam,  &m_pD3DDevice) ) )
	{
		//if( FAILED( hr = m_pD3D->CreateDevice(m_CurrentMode.Adapter, D3DDEVTYPE_HAL, m_hWnd,flags, &m_PresentParam,  &m_pDevice) ) )
		{
			if( FAILED( hr = m_pD3D->CreateDevice(m_CurrentMode.Adapter, D3DDEVTYPE_HAL, m_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING  ,&m_PresentParam,  &m_pD3DDevice) ) )
			{
				MessageBox((HWND)wnd,"Couldn't create device!","Error",MB_ICONERROR);
				return ;
			}
		}
	}

	//SAFEDELETE(m_DeviceStateManager)
	m_Device = new DeviceStateManager(m_pD3DDevice, this);
		
	m_pD3DDevice->BeginScene();

	OnCreateDevice();

	Restore();

	m_Clock.Reset();

	m_bDeviceLost = false;
}

bool D3DApp::SelectDeviceSettings(HWND hwnd,bool allowfullscreen,STSelMode*selmode)
{
	g_AllowFullScreen = allowfullscreen;
	g_SelMode = selmode;
	g_Adapters = &m_lAdapters;

	HMODULE hmdl = GetModuleHandle("DXFunctions.dll");
	if(DialogBox(hmdl,MAKEINTRESOURCE(IDD_DEVICESETTINGS),hwnd,(DLGPROC)DDProc) != -1)
	{
		//testmode
		if(!m_lAdapters.GetElement(selmode->Adapter))
			return false;

		STAdapter *adapter = m_lAdapters.GetElement(selmode->Adapter)->GetInfo();

		return true;
	}
	else
		return false;
}

void D3DApp::EnumAdapters(void)
{
	if(!m_pD3D)
		return ;

	m_lAdapters.Clear();

	DWORD adaptercount = m_pD3D->GetAdapterCount();

	for(DWORD iadapter=0;iadapter < adaptercount;iadapter++)
	{
		STAdapter *newadapter = new STAdapter;
		m_pD3D->GetAdapterIdentifier(iadapter,0,&(newadapter->AdapterInfo));
			
		DWORD modecount = m_pD3D->GetAdapterModeCount(iadapter,D3DFMT_X8R8G8B8);
		D3DDISPLAYMODE tempmode;
		for(DWORD imode =0;imode <modecount;imode++)
		{
			m_pD3D->EnumAdapterModes(iadapter,D3DFMT_X8R8G8B8,imode,&tempmode);
			DWORD id = (tempmode.Height<<16) + tempmode.Width;
			if(!(newadapter->Modes32.GetElement(id)))
			{
				STMode *newmode = new STMode;
				newmode->Width = tempmode.Width;
				newmode->Height = tempmode.Height;
				newadapter->Modes32.AddHead(newmode,id);
			}
			if(!(newadapter->Modes32.GetElement(id)->GetInfo()->RefreshRates.GetElement(tempmode.RefreshRate)))
			{
				UINT *refreshrate = new UINT;
				*refreshrate = tempmode.RefreshRate;
				newadapter->Modes32.GetElement(id)->GetInfo()->RefreshRates.AddHead(refreshrate,tempmode.RefreshRate);
			}

		}

		m_pD3D->CheckDeviceMultiSampleType(iadapter,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,false,D3DMULTISAMPLE_NONMASKABLE,&(newadapter->FSAntialiasing32));
		m_pD3D->CheckDeviceMultiSampleType(iadapter,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,true,D3DMULTISAMPLE_NONMASKABLE,&(newadapter->WDAntialiasing32));

		modecount = m_pD3D->GetAdapterModeCount(iadapter,D3DFMT_R5G6B5);
		for(DWORD imode =0;imode <modecount;imode++)
		{
			m_pD3D->EnumAdapterModes(iadapter,D3DFMT_R5G6B5,imode,&tempmode);
			DWORD id = (tempmode.Height<<16) + tempmode.Width;
			if(!(newadapter->Modes16.GetElement(id)))
			{
				STMode *newmode = new STMode;
				newmode->Width = tempmode.Width;
				newmode->Height = tempmode.Height;
				newadapter->Modes16.AddHead(newmode,id);
			}
			if(!(newadapter->Modes16.GetElement(id)->GetInfo()->RefreshRates.GetElement(tempmode.RefreshRate)))
			{
				UINT *refreshrate = new UINT;
				*refreshrate = tempmode.RefreshRate;
				newadapter->Modes16.GetElement(id)->GetInfo()->RefreshRates.AddHead(refreshrate,tempmode.RefreshRate);
			}
		}

		m_pD3D->CheckDeviceMultiSampleType(iadapter,D3DDEVTYPE_HAL,D3DFMT_R5G6B5,false,D3DMULTISAMPLE_NONMASKABLE,&(newadapter->FSAntialiasing16));
		m_pD3D->CheckDeviceMultiSampleType(iadapter,D3DDEVTYPE_HAL,D3DFMT_R5G6B5,true,D3DMULTISAMPLE_NONMASKABLE,&(newadapter->WDAntialiasing16));

		m_lAdapters.AddHead(newadapter,iadapter);
	}
}

BOOL CALLBACK DDProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
	ListElement<STAdapter> *adapter;
	DWORD cursel;
	XString str;

	switch(msg)
	{
		case WM_INITDIALOG:
			adapter = g_Adapters->GetHead();
			SendDlgItemMessage(hwndDlg,IDC_CB_ADAPTER,CB_RESETCONTENT,0,0);
			while(adapter)
			{
				SendDlgItemMessage(hwndDlg,IDC_CB_ADAPTER,CB_ADDSTRING,0,(LPARAM)(adapter->GetInfo()->AdapterInfo.Description));
				adapter = adapter->GetNext();
			}

			SendDlgItemMessage(hwndDlg,IDC_CB_ADAPTER,CB_SETCURSEL,(LPARAM)(g_SelMode->Adapter),0);
			
			OnSelectAdapter(hwndDlg);

			SendDlgItemMessage(hwndDlg,IDC_CK_VSYNC,BM_SETCHECK,(LPARAM)(g_SelMode->VSync),0);

			return TRUE;
		break;

		case WM_HSCROLL:
		case WM_VSCROLL:

			if(wParam == SB_ENDSCROLL)
			{
				if((HWND)lParam == GetDlgItem(hwndDlg,IDC_SL_ANTIALIASING))
				{
					g_SelMode->Antialiasing = (unsigned)(SendDlgItemMessage(hwndDlg,IDC_SL_ANTIALIASING,TBM_GETPOS,0,0));
					if(g_SelMode->Antialiasing > 0)
					{
						str = (int)g_SelMode->Antialiasing;
						SetWindowText(GetDlgItem(hwndDlg,IDC_LB_ANTIALIASING),str.getbuffer());
					}
					else
						SetWindowText(GetDlgItem(hwndDlg,IDC_LB_ANTIALIASING),"Off");
				}
			}
			return TRUE;
			break;

		case WM_COMMAND:

			switch(LOWORD(wParam))
			{
				case IDC_BTN_OK:

					EndDialog(hwndDlg,0);
					return TRUE;
					break;
				case IDC_BTN_CANCEL:

					EndDialog(hwndDlg,-1);
					return TRUE;
					break;

				case IDC_RD_WINDOWED:
					SendDlgItemMessage(hwndDlg,IDC_RD_WINDOWED,BM_SETCHECK,1,0);
					SendDlgItemMessage(hwndDlg,IDC_RD_FULLSCREEN,BM_SETCHECK,0,0);

					EnableWindow(GetDlgItem(hwndDlg,IDC_CB_RESOLUTION),0);
					EnableWindow(GetDlgItem(hwndDlg,IDC_CB_REFRESHRATE),0);
					g_SelMode->Windowed = true;

					return TRUE;
					break;

				case IDC_RD_FULLSCREEN:
					SendDlgItemMessage(hwndDlg,IDC_RD_WINDOWED,BM_SETCHECK,0,0);
					SendDlgItemMessage(hwndDlg,IDC_RD_FULLSCREEN,BM_SETCHECK,1,0);

					EnableWindow(GetDlgItem(hwndDlg,IDC_CB_RESOLUTION),1);
					EnableWindow(GetDlgItem(hwndDlg,IDC_CB_REFRESHRATE),1);
					g_SelMode->Windowed = false;

					return TRUE;
					break;

				case IDC_RD_16BIT:

					SendDlgItemMessage(hwndDlg,IDC_RD_16BIT,BM_SETCHECK,1,0);
					SendDlgItemMessage(hwndDlg,IDC_RD_32BIT,BM_SETCHECK,0,0);

					g_SelMode->BB32Bit = false;
					OnSelectAdapter(hwndDlg);

					return TRUE;
					break;

				case IDC_RD_32BIT:

					SendDlgItemMessage(hwndDlg,IDC_RD_16BIT,BM_SETCHECK,0,0);
					SendDlgItemMessage(hwndDlg,IDC_RD_32BIT,BM_SETCHECK,1,0);

					g_SelMode->BB32Bit = true;
					OnSelectAdapter(hwndDlg);

					return TRUE;
					break;

				case IDC_CK_VSYNC:
					g_SelMode->VSync = (SendDlgItemMessage(hwndDlg,IDC_CK_VSYNC,BM_GETCHECK,0,0) != 0);

					return TRUE;
					break;
			}

			switch(HIWORD(wParam))
			{
				case CBN_SELENDOK:
					switch(LOWORD(wParam))
					{
							case IDC_CB_ADAPTER:
								OnSelectAdapter(hwndDlg);
								break;

							case IDC_CB_RESOLUTION:

								OnSelectResolution(hwndDlg);
								break;

							case IDC_CB_REFRESHRATE:
								cursel = (DWORD)(SendDlgItemMessage(hwndDlg,IDC_CB_REFRESHRATE,CB_GETCURSEL,0,0));
								g_SelMode->RefreshRate = (UINT)(SendDlgItemMessage(hwndDlg,IDC_CB_REFRESHRATE,CB_GETITEMDATA,cursel,0));
								
								break;
					}

				break;
			}


			return TRUE;
		break;
	}

	return FALSE;
}

void OnSelectAdapter(HWND hwndDlg)
{
	ListElement<STAdapter> *adapter = g_Adapters->GetElement(g_SelMode->Adapter);
	ListElement<STMode> *mode;
	XString str;
	DWORD shouldsel = 0;
	int i = 0;

	if(!g_AllowFullScreen)
	{
		if(!g_SelMode->Windowed)
			g_SelMode->Windowed = true;
		EnableWindow(GetDlgItem(hwndDlg,IDC_RD_FULLSCREEN),0);
	}

	if(adapter)
	{
		//if(adapter->GetInfo()->Modes16.GetElementCount() > 0)
		//	EnableWindow(GetDlgItem(hwndDlg,IDC_RD_16BIT),1);
		//else
		//	EnableWindow(GetDlgItem(hwndDlg,IDC_RD_16BIT),0);

		if(adapter->GetInfo()->Modes32.GetElementCount() > 0)
			EnableWindow(GetDlgItem(hwndDlg,IDC_RD_32BIT),1);
		else
			EnableWindow(GetDlgItem(hwndDlg,IDC_RD_32BIT),0);

		if(g_SelMode->BB32Bit)
		{
			SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_RESETCONTENT,0,0);
			mode = adapter->GetInfo()->Modes32.GetHead();
			while(mode)
			{
				if(mode->GetInfo()->Width == g_SelMode->Width && mode->GetInfo()->Height == g_SelMode->Height) 
					shouldsel = i;
				str = (int)mode->GetInfo()->Width;
				str.appand(" x ");
				str.appand((int)mode->GetInfo()->Height);
				SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_ADDSTRING,0,(LPARAM)(str.getbuffer()));
				SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_SETITEMDATA,i++,(LPARAM)(mode->GetInfo()));

				mode = mode->GetNext();
			}

			g_SelMode->Width =  adapter->GetInfo()->Modes32[shouldsel]->GetInfo()->Width;
			g_SelMode->Height =  adapter->GetInfo()->Modes32[shouldsel]->GetInfo()->Height;
			SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_SETCURSEL,shouldsel,0);
			OnSelectResolution(hwndDlg);

			if(g_SelMode->Windowed)
			{
				if(adapter->GetInfo()->WDAntialiasing32)
					EnableWindow(GetDlgItem(hwndDlg,IDC_SL_ANTIALIASING),1);
				else
					EnableWindow(GetDlgItem(hwndDlg,IDC_SL_ANTIALIASING),0);
				SendDlgItemMessage(hwndDlg,IDC_SL_ANTIALIASING,TBM_SETRANGE,1,(LPARAM) MAKELONG (0,adapter->GetInfo()->WDAntialiasing32));
				if(g_SelMode->Antialiasing > adapter->GetInfo()->WDAntialiasing32)
					g_SelMode->Antialiasing = adapter->GetInfo()->WDAntialiasing32;
			}
			else
			{
				if(adapter->GetInfo()->FSAntialiasing32)
					EnableWindow(GetDlgItem(hwndDlg,IDC_SL_ANTIALIASING),1);
				else
					EnableWindow(GetDlgItem(hwndDlg,IDC_SL_ANTIALIASING),0);
				SendDlgItemMessage(hwndDlg,IDC_SL_ANTIALIASING,TBM_SETRANGE,1,(LPARAM) MAKELONG (0,adapter->GetInfo()->FSAntialiasing32));
				if(g_SelMode->Antialiasing > adapter->GetInfo()->FSAntialiasing32)
					g_SelMode->Antialiasing = adapter->GetInfo()->FSAntialiasing32;
			}
		}
		else
		{
			SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_RESETCONTENT,0,0);
			mode = adapter->GetInfo()->Modes16.GetHead();
			while(mode)
			{
				if(mode->GetInfo()->Width == g_SelMode->Width && mode->GetInfo()->Height == g_SelMode->Height) 
					shouldsel = i;
				str = (int)mode->GetInfo()->Width;
				str.appand(" x ");
				str.appand((int)mode->GetInfo()->Height);
				SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_ADDSTRING,0,(LPARAM)(str.getbuffer()));
				SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_SETITEMDATA,i++,(LPARAM)(mode->GetInfo()));

				mode = mode->GetNext();
			}

			g_SelMode->Width =  adapter->GetInfo()->Modes16[shouldsel]->GetInfo()->Width;
			g_SelMode->Height =  adapter->GetInfo()->Modes16[shouldsel]->GetInfo()->Height;
			SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_SETCURSEL,shouldsel,0);
			OnSelectResolution(hwndDlg);
			
			if(g_SelMode->Windowed)
			{
				if(adapter->GetInfo()->WDAntialiasing16)
					EnableWindow(GetDlgItem(hwndDlg,IDC_SL_ANTIALIASING),1);
				else
					EnableWindow(GetDlgItem(hwndDlg,IDC_SL_ANTIALIASING),0);
				SendDlgItemMessage(hwndDlg,IDC_SL_ANTIALIASING,TBM_SETRANGE,1,(LPARAM) MAKELONG (0,adapter->GetInfo()->WDAntialiasing16));
				if(g_SelMode->Antialiasing > adapter->GetInfo()->WDAntialiasing16)
					g_SelMode->Antialiasing = adapter->GetInfo()->WDAntialiasing16;
			}
			else
			{
				if(adapter->GetInfo()->FSAntialiasing16)
					EnableWindow(GetDlgItem(hwndDlg,IDC_SL_ANTIALIASING),1);
				else
					EnableWindow(GetDlgItem(hwndDlg,IDC_SL_ANTIALIASING),0);
				SendDlgItemMessage(hwndDlg,IDC_SL_ANTIALIASING,TBM_SETRANGE,1,(LPARAM) MAKELONG (0,adapter->GetInfo()->FSAntialiasing16));
				if(g_SelMode->Antialiasing > adapter->GetInfo()->FSAntialiasing16)
					g_SelMode->Antialiasing = adapter->GetInfo()->FSAntialiasing16;
			}
		}
	}
	SendDlgItemMessage(hwndDlg,IDC_SL_ANTIALIASING,TBM_SETPOS,1,g_SelMode->Antialiasing);
	if(g_SelMode->Antialiasing > 0)
	{
		str = (int)g_SelMode->Antialiasing;
		SetWindowText(GetDlgItem(hwndDlg,IDC_LB_ANTIALIASING),str.getbuffer());
	}
	else
		SetWindowText(GetDlgItem(hwndDlg,IDC_LB_ANTIALIASING),"Off");

	if(g_SelMode->Windowed)
	{
		SendDlgItemMessage(hwndDlg,IDC_RD_WINDOWED,BM_SETCHECK,1,0);
		SendDlgItemMessage(hwndDlg,IDC_RD_FULLSCREEN,BM_SETCHECK,0,0);

		EnableWindow(GetDlgItem(hwndDlg,IDC_CB_RESOLUTION),0);
		EnableWindow(GetDlgItem(hwndDlg,IDC_CB_REFRESHRATE),0);
	}
	else
	{
		SendDlgItemMessage(hwndDlg,IDC_RD_WINDOWED,BM_SETCHECK,0,0);
		SendDlgItemMessage(hwndDlg,IDC_RD_FULLSCREEN,BM_SETCHECK,1,0);

		EnableWindow(GetDlgItem(hwndDlg,IDC_CB_RESOLUTION),1);
		EnableWindow(GetDlgItem(hwndDlg,IDC_CB_REFRESHRATE),1);
	}

	if(g_SelMode->BB32Bit)
	{
		SendDlgItemMessage(hwndDlg,IDC_RD_16BIT,BM_SETCHECK,0,0);
		SendDlgItemMessage(hwndDlg,IDC_RD_32BIT,BM_SETCHECK,1,0);
	}
	else
	{
		SendDlgItemMessage(hwndDlg,IDC_RD_16BIT,BM_SETCHECK,1,0);
		SendDlgItemMessage(hwndDlg,IDC_RD_32BIT,BM_SETCHECK,0,0);
	}
}

void OnSelectResolution(HWND hwndDlg)
{
	DWORD cursel = (DWORD)(SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_GETCURSEL,0,0));

	STMode* mode = (STMode*)SendDlgItemMessage(hwndDlg,IDC_CB_RESOLUTION,CB_GETITEMDATA,cursel,0);

	g_SelMode->Height = mode->Height;
	g_SelMode->Width = mode->Width;

	SendDlgItemMessage(hwndDlg,IDC_CB_REFRESHRATE,CB_RESETCONTENT,0,0);

	XString str;
	int i = 0;
	DWORD shouldsel = 0;
	ListElement<UINT> *refreshrate=mode->RefreshRates.GetHead();
	while(refreshrate)
	{
		if(g_SelMode->RefreshRate == *(refreshrate->GetInfo()))
			shouldsel = i;
		str = (int)(*(refreshrate->GetInfo()));
		str.appand(" Hz");
		SendDlgItemMessage(hwndDlg,IDC_CB_REFRESHRATE,CB_ADDSTRING,0,(LPARAM)(str.getbuffer()));
		SendDlgItemMessage(hwndDlg,IDC_CB_REFRESHRATE,CB_SETITEMDATA,i++,*(refreshrate->GetInfo()));

		refreshrate = refreshrate->GetNext();
	}
 
	g_SelMode->RefreshRate = *(mode->RefreshRates[shouldsel]->GetInfo());
	SendDlgItemMessage(hwndDlg,IDC_CB_REFRESHRATE,CB_SETCURSEL,shouldsel,0);
}

void wlog(char *str,...)
{
	char	buf[30];
	FILE	*fp; 
	int		i;

	va_list vl;

    va_start(vl,str);

	fopen_s(&fp, "error.log", "a");

	if(!fp)
		return;

    _strdate_s(buf);
    fprintf(fp,"%s ",buf );
	_strtime_s(buf);
    fprintf(fp,"%s ",buf );

	for(i=0;str[i]!='\0';i++)
    {
		if(str[i]=='%')
        {
			i++;
			switch(str[i])
			{
				case 'd':fprintf(fp,"%d",va_arg(vl,int));break;
				case 'D':fprintf(fp,"%d",va_arg(vl,short));break;
				case 'c':fprintf(fp,"%c",va_arg(vl,char));break;
				case 'f':fprintf(fp,"%f",va_arg(vl,double));break;
				case 's':fprintf(fp,"%s",va_arg(vl,char*));break;
				case 'S':fprintf(fp,"%S",va_arg(vl,wchar_t*));break;
				case 'r':switch(va_arg(vl,HRESULT))
						 {	
							case S_OK:fprintf(fp,"%s","S_OK");break;
							/*case DDERR_SURFACELOST:fprintf(fp,"%s","DDERR_SURFACELOST");break; 
							case DDERR_WASSTILLDRAWING:fprintf(fp,"%s","DDERR_WASSTILLDRAWING");break;
							case DDERR_INVALIDOBJECT:fprintf(fp,"%s","DDERR_INVALIDOBJECT");break;
							case DDERR_INVALIDPARAMS:fprintf(fp,"%s","DDERR_INVALIDPARAMS");break;
							case DDERR_NOTFOUND:fprintf(fp,"%s","DDERR_NOTFOUND");break;
							case DDERR_NOTINITIALIZED:fprintf(fp,"%s","DDERR_NOTINITIALIZED");break;
							case DDERR_OUTOFMEMORY:fprintf(fp,"%s","DDERR_OUTOFMEMORY");break;
							case DDERR_GENERIC:fprintf(fp,"%s","DDERR_GENERIC");break;
							case DDERR_INVALIDMODE:fprintf(fp,"%s","DDERR_INVALIDMODE");break;
							case DDERR_LOCKEDSURFACES:fprintf(fp,"%s","DDERR_LOCKEDSURFACES");break;
							case DDERR_NOEXCLUSIVEMODE:fprintf(fp,"%s","DDERR_NOEXCLUSIVEMODE");break;
							case DDERR_SURFACEBUSY:fprintf(fp,"%s","DDERR_SURFACEBUSY");break;
							case DDERR_UNSUPPORTED:fprintf(fp,"%s","DDERR_UNSUPPORTED");break;
							case DDERR_UNSUPPORTEDMODE:fprintf(fp,"%s","DDERR_UNSUPPORTEDMODE");break;*/
							case D3DERR_INVALIDCALL:fprintf(fp,"%s","D3DERR_INVALIDCALL");break;  
							case D3DERR_NOTAVAILABLE:fprintf(fp,"%s","D3DERR_NOTAVAILABLE");break;  
							case D3DERR_OUTOFVIDEOMEMORY:fprintf(fp,"%s","D3DERR_OUTOFVIDEOMEMORY");break;	
							case D3DERR_DEVICELOST:fprintf(fp,"%s","D3DERR_DEVICELOST");break;  
							case D3DERR_DEVICENOTRESET:fprintf(fp,"%s","D3DERR_DEVICENOTRESET");break;
/*							case DPNERR_HOSTREJECTEDCONNECTION :fprintf(fp,"%s","DPNERR_HOSTREJECTEDCONNECTION");break;
							case DPNERR_INVALIDAPPLICATION:fprintf(fp,"%s","DPNERR_INVALIDAPPLICATION");break; 
							case DPNERR_INVALIDDEVICEADDRESS:fprintf(fp,"%s","DPNERR_INVALIDDEVICEADDRESS");break; 
							case DPNERR_INVALIDFLAGS:fprintf(fp,"%s","DPNERR_INVALIDFLAGS");break; 
							case DPNERR_INVALIDHOSTADDRESS:fprintf(fp,"%s","DPNERR_INVALIDHOSTADDRESS");break; 
							case DPNERR_INVALIDINSTANCE:fprintf(fp,"%s","DPNERR_INVALIDINSTANCE");break; 
							case DPNERR_INVALIDINTERFACE:fprintf(fp,"%s","DPNERR_INVALIDINTERFACE");break; 
							case DPNERR_INVALIDPASSWORD:fprintf(fp,"%s","DPNERR_INVALIDPASSWORD");break; 
							case DPNERR_NOCONNECTION:fprintf(fp,"%s","DPNERR_NOCONNECTION");break; 
							case DPNERR_NOTHOST:fprintf(fp,"%s","DPNERR_NOTHOST");break; 
							case DPNERR_SESSIONFULL:fprintf(fp,"%s","DPNERR_SESSIONFULL");break; 
							case DPNERR_ALREADYCONNECTED:fprintf(fp,"%s","DPNERR_ALREADYCONNECTED");break; 
							case DPNERR_ABORTED:fprintf(fp,"%s","DPNERR_ALREADYCONNECTED");break;  
							case DPNERR_ADDRESSING:fprintf(fp,"%s","DPNERR_ADDRESSING");break;  
							case DPNERR_ALREADYCLOSING:fprintf(fp,"%s","DPNERR_ALREADYCLOSING");break;  
							case DPNERR_ALREADYDISCONNECTING:fprintf(fp,"%s","DPNERR_ALREADYDISCONNECTING");break;  
							case DPNERR_ALREADYINITIALIZED :fprintf(fp,"%s","DPNERR_ALREADYINITIALIZED");break; 
							case DPNERR_BUFFERTOOSMALL :fprintf(fp,"%s","DPNERR_BUFFERTOOSMALL");break; 
							case DPNERR_CANNOTCANCEL :fprintf(fp,"%s","DPNERR_CANNOTCANCEL");break; 
							case DPNERR_CANTCREATEGROUP :fprintf(fp,"%s","DPNERR_CANTCREATEGROUP");break; 
							case DPNERR_CANTCREATEPLAYER :fprintf(fp,"%s","DPNERR_CANTCREATEPLAYER");break; 
							case DPNERR_CANTLAUNCHAPPLICATION :fprintf(fp,"%s","DPNERR_CANTLAUNCHAPPLICATION");break; 
							case DPNERR_CONNECTING :fprintf(fp,"%s","DPNERR_CONNECTING");break; 
							case DPNERR_CONNECTIONLOST :fprintf(fp,"%s","DPNERR_CONNECTIONLOST");break; 
							case DPNERR_DATATOOLARGE :fprintf(fp,"%s","DPNERR_DATATOOLARGE");break; 
							case DPNERR_DOESNOTEXIST :fprintf(fp,"%s","DPNERR_DOESNOTEXIST");break; 
							case DPNERR_ENUMQUERYTOOLARGE :fprintf(fp,"%s","DPNERR_ENUMQUERYTOOLARGE");break; 
							case DPNERR_ENUMRESPONSETOOLARGE :fprintf(fp,"%s","DPNERR_ENUMRESPONSETOOLARGE");break; 
							case DPNERR_EXCEPTION :fprintf(fp,"%s","DPNERR_EXCEPTION");break; 
							case DPNERR_GROUPNOTEMPTY :fprintf(fp,"%s","DPNERR_GROUPNOTEMPTY");break; 
							case DPNERR_HOSTTERMINATEDSESSION :fprintf(fp,"%s","DPNERR_HOSTTERMINATEDSESSION");break; 
							case DPNERR_INCOMPLETEADDRESS :fprintf(fp,"%s","DPNERR_INCOMPLETEADDRESS");break; 
							case DPNERR_INVALIDADDRESSFORMAT :fprintf(fp,"%s","DPNERR_INVALIDADDRESSFORMAT");break; 
							case DPNERR_INVALIDCOMMAND :fprintf(fp,"%s","DPNERR_INVALIDCOMMAND");break; 
							case DPNERR_INVALIDGROUP :fprintf(fp,"%s","DPNERR_INVALIDGROUP");break; 
							case DPNERR_INVALIDHANDLE :fprintf(fp,"%s","DPNERR_INVALIDHANDLE");break; 
							case DPNERR_INVALIDOBJECT :fprintf(fp,"%s","DPNERR_INVALIDOBJECT");break; 
							case DPNERR_INVALIDPLAYER :fprintf(fp,"%s","DPNERR_INVALIDPLAYER");break; 
							case DPNERR_INVALIDPOINTER :fprintf(fp,"%s","DPNERR_INVALIDPOINTER");break; 
							case DPNERR_INVALIDPRIORITY :fprintf(fp,"%s","DPNERR_INVALIDPRIORITY");break; 
							case DPNERR_INVALIDSTRING :fprintf(fp,"%s","DPNERR_INVALIDXString");break; 
							case DPNERR_INVALIDURL :fprintf(fp,"%s","DPNERR_INVALIDURL");break; 
							case DPNERR_INVALIDVERSION :fprintf(fp,"%s","DPNERR_INVALIDVERSION");break; 
							case DPNERR_NOCAPS :fprintf(fp,"%s","DPNERR_NOCAPS");break; 
							case DPNERR_NOHOSTPLAYER :fprintf(fp,"%s","DPNERR_NOHOSTPLAYER");break; 
							case DPNERR_NOINTERFACE :fprintf(fp,"%s","DPNERR_NOINTERFACE");break; 
							case DPNERR_NORESPONSE :fprintf(fp,"%s","DPNERR_NORESPONSE");break; 
							case DPNERR_NOTALLOWED :fprintf(fp,"%s","DPNERR_NOTALLOWED");break; 
							case DPNERR_PENDING :fprintf(fp,"%s","DPNERR_PENDING");break; 
							case DPNERR_PLAYERLOST :fprintf(fp,"%s","DPNERR_PLAYERLOST");break; 
							case DPNERR_PLAYERNOTREACHABLE :fprintf(fp,"%s","DPNERR_PLAYERNOTREACHABLE");break; 
							case DPNERR_TIMEDOUT :fprintf(fp,"%s","DPNERR_TIMEDOUT");break; 
							case DPNERR_UNINITIALIZED :fprintf(fp,"%s","DPNERR_UNINITIALIZED");break; 
							case DPNERR_USERCANCEL :fprintf(fp,"%s","DPNERR_USERCANCEL");break; */
							case D3DXERR_INVALIDDATA:fprintf(fp,"%s","D3DXERR_INVALIDDATA");break; 
							default: fprintf(fp,"UNKNOWN RESULT: %d",va_arg(vl,HRESULT));break;
						 }break;
				default:fprintf(fp,"%c",str[i]);break;
			}
		}
		else
			fprintf(fp,"%c",str[i]);
    }
	fputs("\n",fp);
	fclose(fp);
	va_end(vl);
}