/*

  settings.cpp: Takes care of registry settings, property sheet etc.
  1st April 1997: Created it.
  
*/

#include "include.h"
#include <commctrl.h>

/*** string table ***/
enum language {
	LA_256,
	LA_HARDWARE,
	LA_FULLSCREEN,
	LA_WINDOWED,
	LA_ZBUFFER,
	LA_BILINEAR,
	LA_DITHER,
	LA_TRIPLE,
	LA_PERSP,
	LA_NONE,
	LA_NA,
	LA_ENABLED,
	LA_DISABLED,
	LA_CAMERA,
	LA_PASSED,
	LA_FAILED,
	LA_SETOK
};

//#define COLOUR "Colour"
#define COLOUR "Color"

#ifdef GERMAN
char *szLanguage[] = {
	"Software-Renderer 8 Bit Farbe",
	"3D-Beschleuniger",
	"Vollbild %dx%dx%d",
	"Fenster %dx%d%s",
	"Z-Buffer",
	"Bilinearer Filter",
	"Dithering",
	"Triple-Buffering",
	"Perspektivenkorrektur",
	"-",
	"-",
	"Enabled",
	"Disabled",
	"Kamera",
	"OK",
	"UNGENÜGEND",
	"Aktuelle Einstellungen OK"
};
#elif FRENCH
char *szLanguage[] = {
	"Par logiciel : 256 Couleurs",
	"Carte Accélératrice 3D",
	"Plein écran %dx%dx%d",
	"Fenêtre %dx%d%s",
	"Tampon Z",
	"Filtre Bilinéaire",
	"Lissage",
	"Tampon Triple",
	"Correction de Perspective",
	"-",
	"-",
	"Activer",
	"Désactiver",
	"Caméra",
	"REUSSI",
	"ECHEC",
	"Configuration actuelle OK"
};
#elif ITALIAN
char *szLanguage[] = {
	"Software a 256 colori",
	"Accelerazione hardware 3D",
	"A schermo pieno %dx%dx%d",
	"A finestra %dx%d%s",
	"Z Buffer",
	"Filtro bilineare",
	"Retinatura",
	"Buffer triplo",
	"Correzione prospettiva",
	"-",
	"-",
	"Attiuato",
	"Disattiuato",
	"Telecamera",
	"PASSATA",
	"FALLITA",
	"Impostazioni attuali OK"
};
#else
char *szLanguage[] = {
	"Software (256 " COLOUR "s)",
	"Hardware 3D Acceleration",
	"Full Screen %dx%dx%d",
	"Windowed %dx%d%s",
	"Z Buffered",
	"Bilinear Filtered",
	"Dithered",
	"Triple Buffered",
	"Perspective Correct",
	"None",
	"n/a",
	"Enabled",
	"Disabled",
	"Camera",
	"PASSED",
	"FAILED",
	"Current Settings OK"
};
#endif

/*** globals ***/
defglobal AppSettings G_AppSettings;

/*** locals ***/
local AppSettings L_NewSettings;
local Position L_PrimaryDisplayAdapter;
local WNDPROC LpOrigWndProc;
local HWND LhPropertySheetDlg;
local HWND LhWndFrontPage,LhWndVideoPage,LhWndAudioPage,LhWndControlsPage;
local bool LtTestInProgress;
local bool LtInitialisedCommonControls=false;
local bool LtCentred;
local ScreenMode L_FullScreenMode;

DefLocalString(RegistryLocation,"Software\\Core Design\\Tomb Raider II");
DefLocalString(SystemSubKey,"System");
DefLocalString(SettingsCaption,"Tomb Raider II");
DefValueName(PreferredDisplayAdapterGUID);
DefValueName(PreferredSoundAdapterGUID);
DefValueName(PreferredJoystickGUID);
DefValueName(RenderMode);
DefValueName(PerspectiveCorrect);
DefValueName(Dither);
DefValueName(ZBuffer);
DefValueName(BilinearFiltering);
DefValueName(TripleBuffering);
DefValueName(FullScreen);
DefValueName(WindowWidth);
DefValueName(WindowHeight);
DefValueName(AspectMode);
DefValueName(FullScreenWidth);
DefValueName(FullScreenHeight);
DefValueName(FullScreenBPP);
DefValueName(SoundEnabled);
DefValueName(LaraMic);
//DefValueName(MipMap);
//DefValueName(Antialias);
DefValueName(JoystickEnabled);
DefValueName(Disable16BitTextures);
DefValueName(DontSortPrimitives);
DefValueName(TexelAdjustMode);
DefValueName(NearestAdjustment);
DefValueName(LinearAdjustment);
DefValueName(FlipBroken);
DefValueName(DisableFMV);

/*** code ***/
bool SE_OpenRegistry(char* szSubKeyName)
	{
	if (szSubKeyName)
		{
		char buf[256];
		sprintf(buf,"%s\\%s",LocalString(RegistryLocation),szSubKeyName);
		return REG_OpenKey(buf);
		}
	return REG_OpenKey(LocalString(RegistryLocation));
	}

void SE_CloseRegistry()
	{
	REG_CloseKey();
	}

bool SE_WriteAppSettings(AppSettings& as)
	{
	Log(LT_Enter,"SE_WriteSettings");
	if (!SE_OpenRegistry(LocalString(SystemSubKey)))
		return false;
	
	if (as.DisplayAdapter && as.DisplayAdapter!=G_PrimaryDisplayAdapter)
		REG_WriteValue(ValueName(PreferredDisplayAdapterGUID),G_DisplayAdapterList[as.DisplayAdapter].AdapterGUID);
	else
		REG_DeleteValue(ValueName(PreferredDisplayAdapterGUID));

	if (as.SoundAdapter && as.SoundAdapter!=G_PrimarySoundAdapter)
		REG_WriteValue(ValueName(PreferredSoundAdapterGUID),G_SoundAdapterList[as.SoundAdapter].AdapterGUID);
	else
		REG_DeleteValue(ValueName(PreferredSoundAdapterGUID));

	if (as.Joystick)
		REG_WriteValue(ValueName(PreferredJoystickGUID),G_JoystickList[as.Joystick].AdapterGUID);
	else
		REG_DeleteValue(ValueName(PreferredJoystickGUID));

	REG_WriteValue(ValueName(RenderMode),as.nRenderMode);
	REG_WriteValue(ValueName(PerspectiveCorrect),as.tPerspectiveCorrect);
	REG_WriteValue(ValueName(Dither),as.tDither);
	REG_WriteValue(ValueName(ZBuffer),as.tZBuffer);
	REG_WriteValue(ValueName(BilinearFiltering),as.tBilinearFiltering);
	REG_WriteValue(ValueName(TripleBuffering),as.tTripleBuffering);
	REG_WriteValue(ValueName(FullScreen),as.tFullScreen);
	REG_WriteValue(ValueName(WindowWidth),as.nWindowWidth);
	REG_WriteValue(ValueName(WindowHeight),as.nWindowHeight);
	REG_WriteValue(ValueName(AspectMode),as.nAspectMode);
//	REG_WriteValue(ValueName(MipMap),as.tMipMap);
//	REG_WriteValue(ValueName(Antialias),as.tAntialias);
	REG_WriteValue(ValueName(NearestAdjustment),as.nNearestAdjustment);
	REG_WriteValue(ValueName(LinearAdjustment),as.nLinearAdjustment);
	REG_WriteValue(ValueName(DisableFMV),as.tDisableFMV);

	if (as.DisplayAdapter && as.FullScreenMode)
		{
		DisplayAdapter& adapter=G_DisplayAdapterList[as.DisplayAdapter];
		List<ScreenMode>& rModeList=(as.nRenderMode==RENDERER_HAL)?adapter.HAL_Modes:adapter.Internal_Modes;
		ScreenMode& rMode=rModeList[as.FullScreenMode];
		REG_WriteValue(ValueName(FullScreenWidth),rMode.nWidth);
		REG_WriteValue(ValueName(FullScreenHeight),rMode.nHeight);
		REG_WriteValue(ValueName(FullScreenBPP),rMode.nBPP);
		}
	else
		{
		REG_DeleteValue(ValueName(FullScreenWidth));
		REG_DeleteValue(ValueName(FullScreenHeight));
		REG_DeleteValue(ValueName(FullScreenBPP));
		}
	REG_WriteValue(ValueName(SoundEnabled),as.tSoundEnabled);
	REG_WriteValue(ValueName(LaraMic),as.tLaraMic);
	REG_WriteValue(ValueName(JoystickEnabled),as.tJoystickEnabled);

	REG_WriteValue(ValueName(Disable16BitTextures),as.tDisable16BitTextures);
	REG_WriteValue(ValueName(DontSortPrimitives),as.tDontSortPrimitives);
	REG_WriteValue(ValueName(TexelAdjustMode),as.nTexelAdjustMode);
	
	SE_CloseRegistry();
	return true;
	}

int SE_ReadAppSettings(AppSettings& as)
	{
	Log(LT_Enter,"SE_ReadSettings");
	if (!SE_OpenRegistry(LocalString(SystemSubKey)))
		{
		Log(LT_Error,"Can't open registry key");
		return SE_RS_ERROR;
		}
	
	GUID guid;
	bool tPreference;

	tPreference=REG_ReadValue(ValueName(PreferredDisplayAdapterGUID),guid,NULL);
	as.DisplayAdapter=DD_FindPreferredAdapter(tPreference?&guid:0);

	tPreference=REG_ReadValue(ValueName(PreferredSoundAdapterGUID),guid,NULL);
	as.SoundAdapter=DS_FindPreferredAdapter(tPreference?&guid:0);

	tPreference=REG_ReadValue(ValueName(PreferredJoystickGUID),guid,NULL);
	as.Joystick=DI_FindPreferredJoystick(tPreference?&guid:0);
	
	REG_ReadValue(ValueName(RenderMode),as.nRenderMode,RENDERER_HAL);
	REG_ReadValue(ValueName(Dither),as.tDither,false);
	REG_ReadValue(ValueName(ZBuffer),as.tZBuffer,true);
	REG_ReadValue(ValueName(BilinearFiltering),as.tBilinearFiltering,true);
	REG_ReadValue(ValueName(TripleBuffering),as.tTripleBuffering,false);
	REG_ReadValue(ValueName(FullScreen),as.tFullScreen,true);
	REG_ReadValue(ValueName(WindowWidth),as.nWindowWidth,512);
	REG_ReadValue(ValueName(WindowHeight),as.nWindowHeight,384);
	REG_ReadValue(ValueName(AspectMode),as.nAspectMode,0);
	ScreenMode FullScreenMode;
	REG_ReadValue(ValueName(FullScreenWidth),FullScreenMode.nWidth,640);
	REG_ReadValue(ValueName(FullScreenHeight),FullScreenMode.nHeight,480);
	REG_ReadValue(ValueName(FullScreenBPP),FullScreenMode.nBPP,16);
	REG_ReadValue(ValueName(SoundEnabled),as.tSoundEnabled,true);
	REG_ReadValue(ValueName(LaraMic),as.tLaraMic,false);
//	REG_ReadValue(ValueName(MipMap),as.tMipMap,false);
//	REG_ReadValue(ValueName(Antialias),as.tAntialias,false);
	REG_ReadValue(ValueName(JoystickEnabled),as.tJoystickEnabled,true);
	REG_ReadValue(ValueName(Disable16BitTextures),as.tDisable16BitTextures,false);
	REG_ReadValue(ValueName(DontSortPrimitives),as.tDontSortPrimitives,false);
	REG_ReadValue(ValueName(TexelAdjustMode),as.nTexelAdjustMode,TEXEL_ALWAYS);
	REG_ReadValue(ValueName(NearestAdjustment),as.nNearestAdjustment,16);
	REG_ReadValue(ValueName(LinearAdjustment),as.nLinearAdjustment,128);
	REG_ReadValue(ValueName(FlipBroken),as.tFlipBroken,false);
	REG_ReadValue(ValueName(DisableFMV),as.tDisableFMV,false);

	if (as.nRenderMode<=RENDERER_NONE || as.nRenderMode>=RENDERER_HOWMANY)
		as.nRenderMode=RENDERER_INTERNAL;
	if (as.nAspectMode<0 || as.nAspectMode>=ASPECT_HOWMANY)
		as.nAspectMode=ASPECT_4_3;
	if (as.nTexelAdjustMode<0 || as.nTexelAdjustMode>TEXEL_HOWMANY)
		as.nTexelAdjustMode=TEXEL_ALWAYS;

	if (as.nNearestAdjustment<0)
		as.nNearestAdjustment=0;
	if (as.nNearestAdjustment>256)
		as.nNearestAdjustment=256;
	if (as.nLinearAdjustment<0)
		as.nLinearAdjustment=0;
	if (as.nLinearAdjustment>256)
		as.nLinearAdjustment=256;

	REG_ReadValue(ValueName(PerspectiveCorrect),as.tPerspectiveCorrect,(as.nRenderMode!=RENDERER_INTERNAL));

	DisplayAdapter& adapter=G_DisplayAdapterList[as.DisplayAdapter];
	List<ScreenMode>& rModeList=(as.nRenderMode==RENDERER_HAL)?adapter.HAL_Modes:adapter.Internal_Modes;
	if (as.nRenderMode==RENDERER_INTERNAL)
		FullScreenMode.nBPP=8;
	FullScreenMode.nType=0;
	as.FullScreenMode=rModeList.Find(FullScreenMode);

	SE_CloseRegistry();
	if (REG_KeyWasCreated())
		{
		Log(LT_Info,"New registry key was created");
		return SE_RS_NEW;
		}
	return SE_RS_OK;
	}

//////////////////////////////////////////////////////////////////////////////////////////////////////

bool PP_Video_InitTest()
	{
	Log(LT_Enter,"PP_Video_InitTest");
	try
		{
		DD_Start();
		DX_Start();
		}
	catch (InitResult nERR)
		{
		SetDlgItemText(LhWndVideoPage,IDC_TEST_RESULT,szLanguage[LA_FAILED]);
		SetDlgItemText(LhWndVideoPage,IDC_TEST_RESULT2,ERR_Describe_Init(nERR));
		return false;
		}
	SetDlgItemText(LhWndVideoPage,IDC_TEST_RESULT,szLanguage[LA_PASSED]);
	SetDlgItemText(LhWndVideoPage,IDC_TEST_RESULT2,szLanguage[LA_SETOK]);
	return true;
	}

void PP_Video_CleanupTest()
	{
	Log(LT_Enter,"PP_Video_CleanupTest");
	DX_Finish();
	DD_Finish();
	DD_HideWindow();
	}

// a shitty little poly muckabout... put some sort of game engine test in.
bool PP_Video_RunTest()
	{
	Log(LT_Enter,"PP_Video_RunTest");
	return false;
	}

bool PP_Video_DoTest()
	{
	Log(LT_Enter,"PP_Video_DoTest");
	AppSettings old_settings=G_AppSettings;
	G_AppSettings=L_NewSettings;
	bool tClosed=false;
	if (PP_Video_InitTest())
		tClosed=PP_Video_RunTest();
	PP_Video_CleanupTest();
	G_AppSettings=old_settings;
	return tClosed;
	}

// update fullscreen mode list combo box
local void PP_Video_UpdateModeList(HWND hWnd)
	{
	Log(LT_Enter,"PP_Video_UpdateModeList");
	HWND hCtrl=GetDlgItem(hWnd,IDC_VIDEO_MODE);
	ComboBox_ResetContent(hCtrl);
	DisplayAdapter& adapter=G_DisplayAdapterList[L_NewSettings.DisplayAdapter];
	List<ScreenMode>& mode_list=L_NewSettings.nRenderMode==RENDERER_HAL?adapter.HAL_Modes:adapter.Internal_Modes;
	if (L_NewSettings.nRenderMode==RENDERER_INTERNAL)
		L_FullScreenMode.nBPP=8;
	L_FullScreenMode.nType=0;
	Position CurrentMode=mode_list.Find(L_FullScreenMode);
	if (mode_list.GetCount())
		{
		char buffer[256],* str;
		int nIndex,nSel;
		
		nSel=0;
		for_all(p,mode_list)
			{
			ScreenMode& mode=mode_list[p];
			switch(mode.nType)
				{
				default:
					str="";
					break;

				case MODETYPE_PALETTED:
					str="256 " COLOUR;
//					str="";
					break;

				case MODETYPE_RGB:
					if (mode.nBPP==16)
						str="High " COLOUR;
					else if (mode.nBPP==24)
						str="True " COLOUR;
					else if (mode.nBPP==32)
						str="True " COLOUR;
					break;

				case MODETYPE_MODEX:
//					str="256 Colour Mode X";
					str="Mode X";
					break;

				case MODETYPE_STANDARDVGA:
//					str="256 Colour VGA";
					str="Standard VGA";
					break;
				}
			sprintf(buffer,"%dx%d %s",mode.nWidth,mode.nHeight,str);
			nIndex=ComboBox_AddString(hCtrl,buffer);
			ComboBox_SetItemData(hCtrl,nIndex,p);
			if (p==CurrentMode)
				nSel=nIndex;
			}
		ComboBox_SetCurSel(hCtrl,nSel);
		Position mode_pos=reinterpret_cast<Position>(ComboBox_GetItemData(hCtrl,nSel));
		L_NewSettings.FullScreenMode=mode_pos;
		if (mode_pos)
			L_FullScreenMode=mode_list[mode_pos];
		}
	EnableWindow(hCtrl,(mode_list.GetCount()>1));
	}

// user changed the selected output device
local void PP_Video_UpdateAdapter(HWND hWnd,Position pos)
	{
	Log(LT_Enter,"PP_Video_UpdateAdapter");
	L_NewSettings.DisplayAdapter=pos;
	PP_Video_UpdateModeList(hWnd);
	}

local inline void EnableDlgItem(HWND hWnd,int nItem,bool tEnable)
	{
	EnableWindow(GetDlgItem(hWnd,nItem),tEnable);
	}

local inline void CheckButton(HWND hWnd,int nItem,bool tCheck)
	{
	CheckDlgButton(hWnd,nItem,tCheck?BST_CHECKED:BST_UNCHECKED);
	}

local inline void EnableAndCheckDlgButton(HWND hWnd,int nItem,bool tEnable,bool tCheck)
	{
	HWND hCtrl=GetDlgItem(hWnd,nItem);
	Button_Enable(hCtrl,tEnable);
	Button_SetCheck(hCtrl,tCheck);
	}

// this is a bit of a monster function...
local void PP_Video_UpdateUI(HWND hWnd)
	{
	Log(LT_Enter,"PP_Video_UpdateUI");

	bool tInternalCanDoFullScreen,tHALCanDoFullScreen;
	bool tInternalRendererSupported,tHALRendererSupported;
	bool tWindowedSupported,tFullScreenSupported,tMoreThanOneMode;
	bool tPerspectiveCorrectSupported,tDitherSupported,tZBufferSupported,tBilinearFilteringSupported,tTripleBufferingSupported;
	char buf[16];
	HWND hCtrl;
	
	DisplayAdapter& adapter=G_DisplayAdapterList[L_NewSettings.DisplayAdapter];

	tInternalCanDoFullScreen=!adapter.Internal_Modes.IsEmpty();
	tInternalRendererSupported=tInternalCanDoFullScreen||adapter.tInternalCanDoWindowed;
	tHALCanDoFullScreen=!adapter.HAL_Modes.IsEmpty();
	tHALRendererSupported=tHALCanDoFullScreen||adapter.tHALCanDoWindowed;
 
	if ((L_NewSettings.nRenderMode==RENDERER_INTERNAL && !tInternalRendererSupported) ||
		(L_NewSettings.nRenderMode==RENDERER_HAL && !tHALRendererSupported))
		L_NewSettings.nRenderMode=RENDERER_NONE;
	if (L_NewSettings.nRenderMode==RENDERER_NONE)
		{
		if (tHALRendererSupported)
			L_NewSettings.nRenderMode=RENDERER_HAL;
		else if (tInternalRendererSupported)
			L_NewSettings.nRenderMode=RENDERER_INTERNAL;
		PP_Video_UpdateModeList(hWnd);
		}

	switch (L_NewSettings.nRenderMode)
		{
		case RENDERER_NONE:
		default:
			tPerspectiveCorrectSupported=false;
			tDitherSupported=false;
			tZBufferSupported=false;
			tBilinearFilteringSupported=false;
			tWindowedSupported=false;
			tFullScreenSupported=false;
			tTripleBufferingSupported=false;
			break;

		case RENDERER_INTERNAL:
			tPerspectiveCorrectSupported=true;					// software renderer can do perspective correction
			tDitherSupported=false;
			tZBufferSupported=false;							// doesn't z buffer at all
			tBilinearFilteringSupported=false;					// doesn't bilinear filter
			tWindowedSupported=adapter.tInternalCanDoWindowed;
			tFullScreenSupported=tInternalCanDoFullScreen;
			tMoreThanOneMode=adapter.Internal_Modes.GetCount()>1;
			tTripleBufferingSupported=true;
			break;

		case RENDERER_HAL:
			tPerspectiveCorrectSupported=adapter.tHALPerspectiveCorrectSupported;
			tDitherSupported=adapter.tHALDitherSupported;
			tZBufferSupported=adapter.tHALZBufferSupported;
			tBilinearFilteringSupported=adapter.tHALBilinearFilteringSupported;
			tWindowedSupported=adapter.tHALCanDoWindowed;
			tFullScreenSupported=tHALCanDoFullScreen;
			tMoreThanOneMode=adapter.HAL_Modes.GetCount()>1;
			tTripleBufferingSupported=true;
			break;
		}

	if (!tWindowedSupported)
		L_NewSettings.tFullScreen=true;
	else if (!tFullScreenSupported)
		L_NewSettings.tFullScreen=false;

	if (!L_NewSettings.tFullScreen)
		tTripleBufferingSupported=false;

	if (!tPerspectiveCorrectSupported)
		L_NewSettings.tPerspectiveCorrect=false;
	if (!tDitherSupported)
		L_NewSettings.tDither=false;
	if (!tZBufferSupported)
		L_NewSettings.tZBuffer=false;
	if (!tBilinearFilteringSupported)
		L_NewSettings.tBilinearFiltering=false;
	if (!tTripleBufferingSupported)
		L_NewSettings.tTripleBuffering=false;

	EnableDlgItem(hWnd,IDC_GROUP_RENDERER,L_NewSettings.nRenderMode!=RENDERER_NONE);
	EnableAndCheckDlgButton(hWnd,IDC_INTERNAL_RENDERER,tInternalRendererSupported,L_NewSettings.nRenderMode==RENDERER_INTERNAL);
	EnableAndCheckDlgButton(hWnd,IDC_DIRECT3D_HARDWARE,tHALRendererSupported,L_NewSettings.nRenderMode==RENDERER_HAL);

	EnableAndCheckDlgButton(hWnd,IDC_PERSPECTIVE,tPerspectiveCorrectSupported,L_NewSettings.tPerspectiveCorrect);
	EnableAndCheckDlgButton(hWnd,IDC_DITHER,tDitherSupported,L_NewSettings.tDither);
	EnableAndCheckDlgButton(hWnd,IDC_TRIPLE_BUFFERING,tTripleBufferingSupported,L_NewSettings.tTripleBuffering);
	EnableAndCheckDlgButton(hWnd,IDC_ZBUFFER,tZBufferSupported,L_NewSettings.tZBuffer);
	EnableAndCheckDlgButton(hWnd,IDC_BILINEAR,tBilinearFilteringSupported,L_NewSettings.tBilinearFiltering);
//	EnableAndCheckDlgButton(hWnd,IDC_MIPMAP,tBilinearFilteringSupported,L_NewSettings.tMipMap);
//	EnableAndCheckDlgButton(hWnd,IDC_ANTIALIAS,tBilinearFilteringSupported,L_NewSettings.tAntialias);
	
	EnableDlgItem(hWnd,IDC_GROUP_DISPLAY_TYPE,tWindowedSupported||tFullScreenSupported);
	EnableAndCheckDlgButton(hWnd,IDC_WINDOWED,tWindowedSupported,!L_NewSettings.tFullScreen&&tWindowedSupported);
	EnableAndCheckDlgButton(hWnd,IDC_FULLSCREEN,tFullScreenSupported,L_NewSettings.tFullScreen&&tFullScreenSupported);

	bool tEnable=L_NewSettings.nRenderMode!=RENDERER_NONE && L_NewSettings.tFullScreen;
	EnableDlgItem(hWnd,IDC_GROUP_VMFHA,tEnable);
	EnableDlgItem(hWnd,IDC_VIDEO_MODE,tEnable&&tMoreThanOneMode);
	
	int nWidth=adapter.nMaxWindowWidth;
	hCtrl=GetDlgItem(hWnd,IDC_WSIZE_SLIDER);
	tEnable=!L_NewSettings.tFullScreen && nWidth;
	EnableDlgItem(hWnd,IDC_GROUP_WS,tEnable);
	EnableWindow(hCtrl,tEnable);
	EnableDlgItem(hWnd,IDC_WSIZE_SMALL,tEnable);
	EnableDlgItem(hWnd,IDC_WSIZE_LARGE,tEnable);
	EnableDlgItem(hWnd,IDC_WSIZE_TEXTBOX,tEnable);
	EnableAndCheckDlgButton(hWnd,IDC_ASPECT_4_TO_3,tEnable,L_NewSettings.nAspectMode==ASPECT_4_3);
	EnableAndCheckDlgButton(hWnd,IDC_ASPECT_16_TO_9,tEnable,L_NewSettings.nAspectMode==ASPECT_16_9);
	EnableAndCheckDlgButton(hWnd,IDC_ASPECT_ANY,tEnable,L_NewSettings.nAspectMode==ASPECT_ANY);

	if (nWidth)
		{
		nWidth-=320;
		nWidth>>=5;
		SendMessage(hCtrl,TBM_SETRANGE,TRUE,MAKELONG(0,nWidth));
		int nPos=SendMessage(hCtrl,TBM_GETPOS,0,0);
		L_NewSettings.nWindowWidth=(nPos<<5)+320;
		switch (L_NewSettings.nAspectMode)
			{
			case ASPECT_4_3:
				L_NewSettings.nWindowHeight=(L_NewSettings.nWindowWidth*3)>>2;
				break;

			case ASPECT_16_9:
				L_NewSettings.nWindowHeight=(L_NewSettings.nWindowWidth*9)>>4;
				break;

			case ASPECT_ANY:
				L_NewSettings.nWindowHeight=L_NewSettings.nWindowWidth*G_AppSettings.nWindowHeight/G_AppSettings.nWindowHeight;
				break;
			}
		sprintf(buf,"%dx%d",L_NewSettings.nWindowWidth,L_NewSettings.nWindowHeight);
		}
	else
		*buf=0;
	SetDlgItemText(hWnd,IDC_WSIZE_TEXTBOX,buf);

	tEnable=L_NewSettings.nRenderMode!=RENDERER_NONE;
	EnableDlgItem(hWnd,IDC_GROUP_RENDERING_OPTIONS,tEnable);
	EnableDlgItem(hWnd,IDC_GROUP_TEST,tEnable);
	EnableDlgItem(hWnd,IDC_TEST_MODE,tEnable);
	EnableDlgItem(hWnd,IDC_TEST_RESULT,tEnable);
	}

local void PP_Video_InitUI(HWND hWnd)
	{
	Log(LT_Enter,"PP_Video_InitUI");

	int nIndex,nSel;
	HWND hCtrl;
	
	hCtrl=GetDlgItem(hWnd,IDC_OUTPUT_DEVICE);
	ComboBox_ResetContent(hCtrl);
	nSel=0;
	L_PrimaryDisplayAdapter=0;
	for_all(p,G_DisplayAdapterList)
		{
		DisplayAdapter& adapter=G_DisplayAdapterList[p];
		nIndex=ComboBox_AddString(hCtrl,static_cast<char*>(adapter.strDescription));
		ComboBox_SetItemData(hCtrl,nIndex,p);
		if (p==L_NewSettings.DisplayAdapter)
			nSel=nIndex;
		if (!adapter.pGUID)	//save pos of primary adapter, so it can be updated on WM_DISPLAYCHANGE
			L_PrimaryDisplayAdapter=p;
		DD_DetermineWindowedCapabilities(adapter);	// can adapter can run in a window; in fact, if adapter.pGUID then it can't...
		}
	ComboBox_SetCurSel(hCtrl,nSel);

	int nAdapters=G_DisplayAdapterList.GetCount();
	EnableWindow(hCtrl,nAdapters>0);

	if (nAdapters)
		{
		Position adapter_pos=reinterpret_cast<Position>(ComboBox_GetItemData(hCtrl,nSel));
		if (L_NewSettings.FullScreenMode)
			{
			DisplayAdapter& adapter=G_DisplayAdapterList[adapter_pos];
			List<ScreenMode>& rModeList=(L_NewSettings.nRenderMode==RENDERER_HAL)?adapter.HAL_Modes:adapter.Internal_Modes;
			L_FullScreenMode=rModeList[L_NewSettings.FullScreenMode];
			}
		else
			L_FullScreenMode=ScreenMode(640,480,0,0);
		PP_Video_UpdateAdapter(hWnd,adapter_pos);
		}

	hCtrl=GetDlgItem(hWnd,IDC_WSIZE_SLIDER);
	SendMessage(hCtrl,TBM_SETPOS,TRUE,(L_NewSettings.nWindowWidth-320)>>5);

	PP_Video_UpdateUI(hWnd);
	}

void PP_Video_SetDefaults()
	{
	//Zero(L_NewSettings);  VERY bad!!! fucks SoundAdapter
	Position hardware=0,primary=0;
	for_all(p,G_DisplayAdapterList)
		{
		DisplayAdapter& adapter=G_DisplayAdapterList[p];
		if (!adapter.pGUID)
			primary=p;
		if (adapter.tHAL && !((primary==p) && hardware))	// don't use if this is a primary adapter and we already have hardware
			{
			hardware=p;																		// found a card with hardware acceleration...
			L_NewSettings.tPerspectiveCorrect=adapter.tHALPerspectiveCorrectSupported;	// set default settings
			L_NewSettings.tDither=adapter.tHALDitherSupported;
			L_NewSettings.tZBuffer=adapter.tHALZBufferSupported;						// these might be bad choices for some cards...
			L_NewSettings.tBilinearFiltering=adapter.tHALBilinearFilteringSupported;
//				break;	// oops...
			}
		}
	if (hardware)
		{
		L_NewSettings.DisplayAdapter=hardware;
		L_NewSettings.nRenderMode=RENDERER_HAL;
		}
	else
		{
		L_NewSettings.DisplayAdapter=primary;
		L_NewSettings.nRenderMode=RENDERER_INTERNAL;
		L_NewSettings.tPerspectiveCorrect=true;
		}
	L_NewSettings.tFullScreen=true;		// hmm what if fullscreen is a no-no?
	L_NewSettings.nWindowWidth=512;
	L_NewSettings.nWindowHeight=384;

	if (L_NewSettings.DisplayAdapter)
		{
		DisplayAdapter& adapter=G_DisplayAdapterList[L_NewSettings.DisplayAdapter];
		List<ScreenMode>& rModeList=(L_NewSettings.nRenderMode==RENDERER_HAL)?adapter.HAL_Modes:adapter.Internal_Modes;
		L_NewSettings.FullScreenMode=rModeList.Find(ScreenMode(640,480,16,MODETYPE_RGB));
		}
	}

local BOOL CALLBACK PP_Video_DlgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
	switch (msg)
		{
		case WM_INITDIALOG:
			LhWndVideoPage=hWnd;
			LtTestInProgress=false;
			if (!LtCentred)
				{
				UT_CenterWindow(GetParent(hWnd));
				LtCentred=true;
				}
			PP_Video_InitUI(hWnd);
			return 1;
			
		case WM_COMMAND:
			if (HIWORD(wParam)==BN_CLICKED)
				{
				int nState=Button_GetCheck(reinterpret_cast<HWND>(lParam));
				bool tState=(nState==BST_CHECKED);
				switch (LOWORD(wParam))
					{
					case IDC_INTERNAL_RENDERER:
						L_NewSettings.nRenderMode=RENDERER_INTERNAL;
						PP_Video_UpdateModeList(hWnd);
						break;

					case IDC_DIRECT3D_HARDWARE:
						L_NewSettings.nRenderMode=RENDERER_HAL;
						PP_Video_UpdateModeList(hWnd);
						break;

					case IDC_PERSPECTIVE:
						L_NewSettings.tPerspectiveCorrect=tState;
						break;

					case IDC_DITHER:
						L_NewSettings.tDither=tState;
						break;

					case IDC_ZBUFFER:
						L_NewSettings.tZBuffer=tState;
						break;
						
					case IDC_BILINEAR:
						L_NewSettings.tBilinearFiltering=tState;
						break;

					case IDC_TRIPLE_BUFFERING:
						L_NewSettings.tTripleBuffering=tState;
						break;

					case IDC_FULLSCREEN:
						L_NewSettings.tFullScreen=true;
						break;
						
					case IDC_WINDOWED:
						L_NewSettings.tFullScreen=false;
						break;

					case IDC_TEST_MODE:
						LtTestInProgress=true;
						if (PP_Video_DoTest())
							PostMessage(LhPropertySheetDlg,PSM_PRESSBUTTON,PSBTN_CANCEL,0);
						LtTestInProgress=false;
						break;

					case IDC_ASPECT_4_TO_3:
						L_NewSettings.nAspectMode=ASPECT_4_3;
						break;

					case IDC_ASPECT_16_TO_9:
						L_NewSettings.nAspectMode=ASPECT_16_9;
						break;

					case IDC_ASPECT_ANY:
						L_NewSettings.nAspectMode=ASPECT_ANY;
						break;

//					case IDC_ANTIALIAS:
//						L_NewSettings.tAntialias=tState;
//						break;

					case IDC_VIDEO_RESET:
						PP_Video_SetDefaults();
						PP_Video_InitUI(hWnd);	// harsh but needed to setup output device
						return false;
						
					default:
						break;
					}
				PP_Video_UpdateUI(hWnd);
				}
			else if (HIWORD(wParam)==CBN_SELCHANGE)
				{
				HWND hCtrl=reinterpret_cast<HWND>(lParam);
				int nSel=ComboBox_GetCurSel(hCtrl);
				Position pos=reinterpret_cast<Position>(ComboBox_GetItemData(hCtrl,nSel));
				switch (LOWORD(wParam))
					{
					case IDC_OUTPUT_DEVICE:
						Log(LT_WindowMessage,"Display output device selected");
						PP_Video_UpdateAdapter(hWnd,pos);
						PP_Video_UpdateUI(hWnd);
						break;

					case IDC_VIDEO_MODE:
						Log(LT_WindowMessage,"Video mode selected");
						DisplayAdapter& adapter=G_DisplayAdapterList[L_NewSettings.DisplayAdapter];
						List<ScreenMode>& mode_list=L_NewSettings.nRenderMode==RENDERER_HAL?adapter.HAL_Modes:adapter.Internal_Modes;
						L_NewSettings.FullScreenMode=pos;
						L_FullScreenMode=mode_list[pos];
						break;
					}
				}
			break;
			
		case WM_HSCROLL:
			if (reinterpret_cast<HWND>(lParam)==GetDlgItem(hWnd,IDC_WSIZE_SLIDER))
				PP_Video_UpdateUI(hWnd);
			break;

		case WM_DISPLAYCHANGE:
			Log(LT_WindowMessage,"Display changed to %dx%dx%d",int(LOWORD(lParam)),int(HIWORD(lParam)),int(wParam));
			if (LtTestInProgress)
				{
				Log(LT_WindowMessage,"Test in progress... not calling DX_DetermineWindowedCapabilities");
				break;
				}
			if (L_PrimaryDisplayAdapter)	// stop us crashing when display mode changes during test!!!
				DD_DetermineWindowedCapabilities(G_DisplayAdapterList[L_PrimaryDisplayAdapter]);
			PP_Video_UpdateUI(hWnd);
			break;

		case WM_DESTROY:
			LhWndVideoPage=0;
			break;
			
		default:
			break;
		}
	return false;
	}

bool PP_Audio_InitTest()
	{
	Log(LT_Enter,"PP_Audio_InitTest");
	//DD_ShowWindow();
	try
		{
		DS_Start(LhWndAudioPage);
		}
	catch (InitResult)
		{
		return false;
		}

	DWORD* pWave=(DWORD*)UT_GetResource(MAKEINTRESOURCE(IDR_WAVE1),"WAVE");
	WAVEFORMATEX* pWF=reinterpret_cast<WAVEFORMATEX*>(pWave+5);
	WAVEFORMATEX wf=*pWF;
	wf.cbSize=0;
	DWORD dwWaveLength;
	dwWaveLength=pWave[10];
	char* pWaveData=reinterpret_cast<char*>(pWave+11);
	if (!DS_MakeSample(0,&wf,pWaveData,dwWaveLength))
		return false;

	return true;
	}

void PP_Audio_CleanupTest()
	{
	Log(LT_Enter,"PP_Audio_CleanupTest");
	DS_Finish();
	//DD_HideWindow();
	}

bool PP_Audio_RunTest()
	{
	Log(LT_Enter,"PP_Audio_RunTest");
	int nHandle=DS_StartSample(0,-1000,0x10000,0,0);
	if (nHandle<0)
		return false;
	while (DS_IsChannelPlaying(nHandle))
		;
	return false;
	}

bool PP_Audio_DoTest()
	{
	Log(LT_Enter,"PP_Audio_DoTest");
	AppSettings old_settings=G_AppSettings;
	G_AppSettings=L_NewSettings;
	bool tClosed=false;
	if (PP_Audio_InitTest())
		tClosed=PP_Audio_RunTest();
	PP_Audio_CleanupTest();
	G_AppSettings=old_settings;
	return tClosed;
	}

local void PP_Audio_UpdateAdapter(HWND hWnd,Position pos)
	{
	Log(LT_Enter,"PP_Audio_UpdateAdapter");
	L_NewSettings.SoundAdapter=pos;
	}

local void PP_Audio_UpdateUI(HWND hWnd)
	{
	Log(LT_Enter,"PP_Audio_UpdateUI");
	bool tAdapters=G_SoundAdapterList.GetCount()>0;
	EnableDlgItem(hWnd,IDC_MIC_POS,tAdapters);
	EnableDlgItem(hWnd,IDC_SOUND_OUTPUT,tAdapters);
	EnableAndCheckDlgButton(hWnd,IDC_SOUND_ENABLED,tAdapters,L_NewSettings.tSoundEnabled&&tAdapters);
	EnableAndCheckDlgButton(hWnd,IDC_MIC_CAMERA,tAdapters,!L_NewSettings.tLaraMic);
	EnableAndCheckDlgButton(hWnd,IDC_MIC_LARA,tAdapters,L_NewSettings.tLaraMic);
	EnableDlgItem(hWnd,IDC_SOUND_TEST,tAdapters);
	}

local void PP_Audio_InitUI(HWND hWnd)
	{
	Log(LT_Enter,"PP_Audio_InitUI");

	int nIndex,nSel;
	HWND hCtrl;
	
	hCtrl=GetDlgItem(hWnd,IDC_SOUND_DEVICE);
	ComboBox_ResetContent(hCtrl);
	nSel=0;
	for_all(p,G_SoundAdapterList)
		{
		SoundAdapter& adapter=G_SoundAdapterList[p];
		nIndex=ComboBox_AddString(hCtrl,static_cast<char*>(adapter.strDescription));
		ComboBox_SetItemData(hCtrl,nIndex,p);
		if (p==L_NewSettings.SoundAdapter)
			nSel=nIndex;
		}
	ComboBox_SetCurSel(hCtrl,nSel);

	int nAdapters=G_SoundAdapterList.GetCount();
	EnableWindow(hCtrl,nAdapters>1);
	if (nAdapters)
		{
		Position adapter_pos=reinterpret_cast<Position>(ComboBox_GetItemData(hCtrl,nSel));
		PP_Audio_UpdateAdapter(hWnd,adapter_pos);
		}

	PP_Audio_UpdateUI(hWnd);
	}

local BOOL CALLBACK PP_Audio_DlgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
	static HWND hLaraPicCtrl;

	switch (msg)
		{
		case WM_INITDIALOG:
			LhWndAudioPage=hWnd;
			hLaraPicCtrl=GetDlgItem(hWnd,IDC_LARABIKEPIC);
			PP_Audio_InitUI(hWnd);
			return 1;

		case WM_COMMAND:
			if (HIWORD(wParam)==BN_CLICKED)
				{
				int nState=Button_GetCheck(reinterpret_cast<HWND>(lParam));
				switch (LOWORD(wParam))
					{
					case IDC_SOUND_ENABLED:
						L_NewSettings.tSoundEnabled=(nState==BST_CHECKED);
						break;

					case IDC_MIC_CAMERA:
						L_NewSettings.tLaraMic=false;
						break;

					case IDC_MIC_LARA:
						L_NewSettings.tLaraMic=true;
						break;
					case IDC_SOUND_TEST:
						if (PP_Audio_DoTest())
							PostMessage(LhPropertySheetDlg,PSM_PRESSBUTTON,PSBTN_CANCEL,0);
						SendMessage(reinterpret_cast<HWND>(lParam),BM_SETCHECK,BST_UNCHECKED,0);
						break;
					}
				}
			else if (HIWORD(wParam)==CBN_SELCHANGE)
				{
				HWND hCtrl=reinterpret_cast<HWND>(lParam);
				int nSel=ComboBox_GetCurSel(hCtrl);
				Position pos=reinterpret_cast<Position>(ComboBox_GetItemData(hCtrl,nSel));
				switch (LOWORD(wParam))
					{
					case IDC_SOUND_DEVICE:
						Log(LT_WindowMessage,"Sound output device selected");
						PP_Audio_UpdateAdapter(hWnd,pos);
						PP_Audio_UpdateUI(hWnd);
						break;
					}
				}
			break;

		default:
			break;
		}
	DW_HandlePaletteChanges(hLaraPicCtrl,msg,wParam);
	return false;
	}

local void PP_Controls_UpdateJoystick(HWND hWnd,Position pos)
	{
	Log(LT_Enter,"PP_Controls_UpdateJoystick");
	L_NewSettings.Joystick=pos;
	}

local void PP_Controls_UpdateUI(HWND hWnd)
	{
	Log(LT_Enter,"PP_Controls_UpdateUI");
	bool tAdapters=G_JoystickList.GetCount()>0;
	EnableAndCheckDlgButton(hWnd,IDC_JOYSTICK_ENABLE,tAdapters,L_NewSettings.tJoystickEnabled&&tAdapters);
	}

local void PP_Controls_InitUI(HWND hWnd)
	{
	Log(LT_Enter,"PP_Controls_InitUI");

	int nIndex,nSel;
	HWND hCtrl;
	
	hCtrl=GetDlgItem(hWnd,IDC_JOYSTICK_DEVICE);
	ComboBox_ResetContent(hCtrl);
	nSel=0;
	for_all(p,G_JoystickList)
		{
		Joystick& joystick=G_JoystickList[p];
		nIndex=ComboBox_AddString(hCtrl,static_cast<char*>(joystick.strDescription));
		ComboBox_SetItemData(hCtrl,nIndex,p);
		if (p==L_NewSettings.Joystick)
			nSel=nIndex;
		}
	ComboBox_SetCurSel(hCtrl,nSel);

	int nCount=G_JoystickList.GetCount();
	EnableWindow(hCtrl,nCount>0);
	if (nCount)
		PP_Controls_UpdateJoystick(hWnd,reinterpret_cast<Position>(ComboBox_GetItemData(hCtrl,nSel)));
	PP_Controls_UpdateUI(hWnd);
	}

local BOOL CALLBACK PP_Controls_DlgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
	static HWND hLaraPicCtrl;

	switch (msg)
		{
		case WM_INITDIALOG:
			LhWndControlsPage=hWnd;
			hLaraPicCtrl=GetDlgItem(hWnd,IDC_LARALOVEPIC);
			PP_Controls_InitUI(hWnd);
			return 1;

		case WM_COMMAND:
			if (HIWORD(wParam)==CBN_SELCHANGE)
				{
				HWND hCtrl=reinterpret_cast<HWND>(lParam);
				int nSel=ComboBox_GetCurSel(hCtrl);
				Position pos=reinterpret_cast<Position>(ComboBox_GetItemData(hCtrl,nSel));
				switch (LOWORD(wParam))
					{
					case IDC_JOYSTICK_DEVICE:
						Log(LT_WindowMessage,"Joystick selected");
						PP_Controls_UpdateJoystick(hWnd,pos);
						PP_Controls_UpdateUI(hWnd);
						break;
					}
				}
			else if (HIWORD(wParam)==BN_CLICKED)
			{
				int nState=Button_GetCheck(reinterpret_cast<HWND>(lParam));
				switch (LOWORD(wParam))
				{
				case IDC_JOYSTICK_ENABLE:
					L_NewSettings.tJoystickEnabled=(nState==BST_CHECKED);
					break;

				case IDC_JOYSTICK_CONFIG:
					Log("Setup Joystick");
					DI_Create();
					DI_SetupJoystick(hWnd);
					DI_Release();
					break;
				}
			}
			break;

		default:
			break;
		}
	DW_HandlePaletteChanges(hLaraPicCtrl,msg,wParam);
	return false;
	}

local void DoOption(char*& rpBuffer,bool tPresent,bool& rtDoComma,char* szName)
	{
	if (!tPresent)
		return;
	if (rtDoComma)
		{
		*rpBuffer++=',';
		*rpBuffer++=' ';
		}
	while (*szName)
		*rpBuffer++=*szName++;
	rtDoComma=true;
	}


local void PP_Front_UpdateUI(HWND hWnd)
	{
	Log(LT_Enter,"PP_Front_UpdateUI");

	char acBuffer[256];
	char* szText;

	if (L_NewSettings.DisplayAdapter)
		{
		szText=G_DisplayAdapterList[L_NewSettings.DisplayAdapter].strDescription;
		SetDlgItemText(hWnd,IDC_FR_GFX_DRIVER,(LPCTSTR)szText);

		if (L_NewSettings.nRenderMode==RENDERER_INTERNAL)
			szText=szLanguage[LA_256];
		else
			szText=szLanguage[LA_HARDWARE];
		SetDlgItemText(hWnd,IDC_FR_GFX_USING,(LPCTSTR)szText);

		if (L_NewSettings.tFullScreen && L_NewSettings.FullScreenMode)
			{
			DisplayAdapter& adapter=G_DisplayAdapterList[L_NewSettings.DisplayAdapter];
			List<ScreenMode>& mode_list=L_NewSettings.nRenderMode==RENDERER_HAL?adapter.HAL_Modes:adapter.Internal_Modes;
			ScreenMode& mode=mode_list[L_NewSettings.FullScreenMode];
			sprintf(acBuffer,szLanguage[LA_FULLSCREEN],mode.nWidth,mode.nHeight,mode.nBPP);
			}
		else
			{
			static char* aszAspect[]={" (4:3)"," (16:9)",""};
			sprintf(acBuffer,szLanguage[LA_WINDOWED],L_NewSettings.nWindowWidth,L_NewSettings.nWindowHeight,aszAspect[L_NewSettings.nAspectMode]);
			}
		SetDlgItemText(hWnd,IDC_FR_GFX_DISPLAY,(LPCTSTR)acBuffer);

		bool tDoComma=false;
		szText=acBuffer;
		DoOption(szText,L_NewSettings.tZBuffer,tDoComma,szLanguage[LA_ZBUFFER]);
		DoOption(szText,L_NewSettings.tBilinearFiltering,tDoComma,szLanguage[LA_BILINEAR]);
//		DoOption(szText,L_NewSettings.tMipMap,tDoComma,"Mip Mapped");
//		DoOption(szText,L_NewSettings.tAntialias,tDoComma,"Antialiased");
		DoOption(szText,L_NewSettings.tDither,tDoComma,szLanguage[LA_DITHER]);
		DoOption(szText,L_NewSettings.tTripleBuffering,tDoComma,szLanguage[LA_TRIPLE]);
		DoOption(szText,L_NewSettings.tPerspectiveCorrect,tDoComma,szLanguage[LA_PERSP]);
		*szText=0;
		SetDlgItemText(hWnd,IDC_FR_GFX_OPTIONS,acBuffer);
		}
	else
		{
		SetDlgItemText(hWnd,IDC_FR_GFX_DRIVER,szLanguage[LA_NONE]);
		SetDlgItemText(hWnd,IDC_FR_GFX_USING,szLanguage[LA_NA]);
		SetDlgItemText(hWnd,IDC_FR_GFX_DISPLAY,szLanguage[LA_NA]);
		SetDlgItemText(hWnd,IDC_FR_GFX_OPTIONS,szLanguage[LA_NA]);
		}

	if (L_NewSettings.SoundAdapter)
		szText=G_SoundAdapterList[L_NewSettings.SoundAdapter].strDescription;
	else
		szText=szLanguage[LA_NONE];
	SetDlgItemText(hWnd,IDC_FR_SND_DRIVER,(LPCTSTR)szText);

	SetDlgItemText(hWnd,IDC_FR_SND_ENABLED,L_NewSettings.tSoundEnabled?szLanguage[LA_ENABLED]:szLanguage[LA_DISABLED]);
	SetDlgItemText(hWnd,IDC_FR_SND_MIC_POS,L_NewSettings.tLaraMic?"Lara":szLanguage[LA_CAMERA]);

	if (L_NewSettings.Joystick)
		szText=G_JoystickList[L_NewSettings.Joystick].strDescription;
	else
		szText=szLanguage[LA_NONE];
	SetDlgItemText(hWnd,IDC_FR_JOY_DRIVER,(LPCTSTR)szText);
	}

local BOOL CALLBACK PP_Front_DlgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
	static HWND hLaraPicCtrl;

	switch (msg)
		{
		case WM_INITDIALOG:
			LhWndFrontPage=hWnd;
			if (!LtCentred)
				{
				UT_CenterWindow(GetParent(hWnd));
				LtCentred=true;
				}
			hLaraPicCtrl=GetDlgItem(hWnd,IDC_LARAPIC);
			return 1;

		case WM_NOTIFY:
			if (((NMHDR*)lParam)->code==PSN_SETACTIVE)
				PP_Front_UpdateUI(hWnd);
			break;

		default:
			break;
		}
	DW_HandlePaletteChanges(hLaraPicCtrl,msg,wParam);
	return false;
	}

local void PP_Extra_UpdateUI(HWND hWnd)
	{
	Log(LT_Enter,"PP_Extra_UpdateUI");

	CheckButton(hWnd,IDC_DISABLE16,L_NewSettings.tDisable16BitTextures);
//	CheckButton(hWnd,IDC_MIPMAP,L_NewSettings.tMipMap);
	CheckButton(hWnd,IDC_NOSORT,L_NewSettings.tDontSortPrimitives);
	CheckButton(hWnd,IDC_DISABLE_FMV,L_NewSettings.tDisableFMV);
	CheckButton(hWnd,IDC_TEXEL1,L_NewSettings.nTexelAdjustMode==TEXEL_NEVER);
	CheckButton(hWnd,IDC_TEXEL2,L_NewSettings.nTexelAdjustMode==TEXEL_WHENFILTERING);
	CheckButton(hWnd,IDC_TEXEL3,L_NewSettings.nTexelAdjustMode==TEXEL_ALWAYS);
	}

local void PP_Extra_InitUI(HWND hWnd)
	{
	Log(LT_Enter,"PP_Extra_InitUI");

	PP_Extra_UpdateUI(hWnd);
	}

local BOOL CALLBACK PP_Extra_DlgProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
	static HWND hLaraPicCtrl;

	switch (msg)
		{
		case WM_INITDIALOG:
			LhWndControlsPage=hWnd;
			hLaraPicCtrl=GetDlgItem(hWnd,IDC_DRESS);
			PP_Extra_InitUI(hWnd);
			return 1;

		case WM_COMMAND:
			if (HIWORD(wParam)==BN_CLICKED)
				{
				int nState=Button_GetCheck(reinterpret_cast<HWND>(lParam));
				bool tState=(nState==BST_CHECKED);
				switch (LOWORD(wParam))
					{
					case IDC_DISABLE16:
						L_NewSettings.tDisable16BitTextures=tState;
						break;

//					case IDC_MIPMAP:
//						L_NewSettings.tMipMap=tState;
//						break;

					case IDC_NOSORT:
						L_NewSettings.tDontSortPrimitives=tState;
						break;

					case IDC_DISABLE_FMV:
						L_NewSettings.tDisableFMV=tState;
						break;

					case IDC_TEXEL1:
						L_NewSettings.nTexelAdjustMode=TEXEL_NEVER;
						break;

					case IDC_TEXEL2:
						L_NewSettings.nTexelAdjustMode=TEXEL_WHENFILTERING;
						break;

					case IDC_TEXEL3:
						L_NewSettings.nTexelAdjustMode=TEXEL_ALWAYS;
						break;
					}
				PP_Extra_UpdateUI(hWnd);
				}
			break;

		default:
			break;
		}
	DW_HandlePaletteChanges(hLaraPicCtrl,msg,wParam);
	return false;
	}

local LRESULT CALLBACK PP_SubclassProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
	{
	switch (msg)
		{
		case WM_DISPLAYCHANGE:
			if (LhWndVideoPage)
				PostMessage(LhWndVideoPage,msg,wParam,lParam);
			break;

		case WM_DESTROY:
			SubclassWindow(hWnd,LpOrigWndProc);
			break;
		}
	//LogWindowsMessage(hWnd,msg,wParam,lParam);
	return CallWindowProc((WNDPROC)LpOrigWndProc,hWnd,msg,wParam,lParam);
	}

int CALLBACK PP_Proc(HWND hDlg,UINT msg,LPARAM lParam)
	{
	if (msg==PSCB_PRECREATE)
		LhWndVideoPage=0;
	else if (msg==PSCB_INITIALIZED)
		{
		LhPropertySheetDlg=hDlg;
		LpOrigWndProc=SubclassWindow(hDlg,PP_SubclassProc);	// subclass the property sheet for WM_DISPLAYCHANGE
		}
	return 0;
	}

bool SE_DoPropertySheet(HWND hWndOwner,bool tFirstTime)
	{
	Log(LT_Enter,"SE_DoPropertySheet");

	L_NewSettings=G_AppSettings;

	if (tFirstTime)
		{
		PP_Video_SetDefaults();
		L_NewSettings.tSoundEnabled=true;
		}
	
	PROPSHEETPAGE psp[5],*pp;
	PROPSHEETHEADER psh;
	
	ZeroArray(psp);
	pp=psp;
	pp->dwSize=sizeof(PROPSHEETPAGE);
	pp->dwFlags=0;
	pp->hInstance=GhInstance;
	pp->pszTemplate=MAKEINTRESOURCE(IDD_PP_FRONT);
	pp->pfnDlgProc=(DLGPROC)PP_Front_DlgProc;
	++pp;
	pp->dwSize=sizeof(PROPSHEETPAGE);
	pp->dwFlags=0;
	pp->hInstance=GhInstance;
	pp->pszTemplate=MAKEINTRESOURCE(IDD_PP_VIDEO);
	pp->pfnDlgProc=(DLGPROC)PP_Video_DlgProc;
	++pp;
	pp->dwSize=sizeof(PROPSHEETPAGE);
	pp->dwFlags=0;
	pp->hInstance=GhInstance;
	pp->pszTemplate=MAKEINTRESOURCE(IDD_PP_AUDIO);
	pp->pfnDlgProc=(DLGPROC)PP_Audio_DlgProc;
	++pp;
	pp->dwSize=sizeof(PROPSHEETPAGE);
	pp->dwFlags=0;
	pp->hInstance=GhInstance;
	pp->pszTemplate=MAKEINTRESOURCE(IDD_PP_CONTROLS);
	pp->pfnDlgProc=(DLGPROC)PP_Controls_DlgProc;
	++pp;
	pp->dwSize=sizeof(PROPSHEETPAGE);
	pp->dwFlags=0;
	pp->hInstance=GhInstance;
	pp->pszTemplate=MAKEINTRESOURCE(IDD_PP_EXTRA);
	pp->pfnDlgProc=(DLGPROC)PP_Extra_DlgProc;
	
	Zero(psh);
	psh.dwSize=sizeof(PROPSHEETHEADER);
	psh.dwFlags=PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW|PSH_USECALLBACK|PSH_USEHICON;//|PSH_USEICONID;
	psh.hwndParent=hWndOwner;
	psh.hInstance=GhInstance;
//	psh.pszIcon=MAKEINTRESOURCE(IDI_APP);
//	psh.hIcon=LoadIcon(GhInstance,MAKEINTRESOURCE(IDI_APP));
	psh.hIcon=(HICON)LoadImage(GhInstance,MAKEINTRESOURCE(IDI_APP),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);
	psh.pszCaption=LocalString(SettingsCaption);
	psh.nPages=ArraySize(psp);
//	psh.nStartPage=0;	//tFirstTime?0:1;
	psh.nStartPage=1;	// a bit painful.
	psh.ppsp=(LPCPROPSHEETPAGE)&psp;
	psh.pfnCallback=PP_Proc;
	
	if (!LtInitialisedCommonControls)
		{
		InitCommonControls();	// make sure handy common controls (like property sheets) are available!
		DW_RegisterWindowClass();
		LtInitialisedCommonControls=true;
		}
	LtCentred=false;
	int nRet=PropertySheet(&psh);
	if (nRet!=IDOK)	// this is a bit of a frig, i'm not sure this is documented behaviour of PropertySheet
		{
		Log(LT_Info,"Property sheet canceled");
		return false;
		}

	Log(LT_Info,"OK... keeping new settings");
	G_AppSettings=L_NewSettings;
	return true;
	}

HWND SE_FindWindow()
	{
	return FindWindow(WC_DIALOG,LocalString(SettingsCaption));
	}
