#include "include.h"

/*** defines ***/
//#define PARANOID	// cos I am

/*** globals ***/
defglobal RenderInfo G_RenderInfo;
defglobal IDirectDrawSurface3* G_FrontBuffer;
defglobal IDirectDrawSurface3* G_BackBuffer;
defglobal IDirectDrawSurface3* G_ThirdBuffer;
defglobal IDirectDrawSurface3* G_ZBuffer;
defglobal IDirectDrawSurface3* G_RenderBuffer;
defglobal IDirectDrawSurface3* G_PictureBuffer;
defglobal IDirectDrawClipper* G_Clipper;
defglobal IDirectDrawPalette* G_Palette;
defglobal PALETTEENTRY G_PaletteEntries[256];

/*** locals ***/

/*** code ***/
void DX_MakeFlippingSurfaces()
	{
	Log(LT_Enter,"DX_MakeFlippingSurfaces");
	DDSURFACEDESC ddsd;
	InitDXStruct(ddsd);
	ddsd.dwFlags=DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
	ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX;
	if (G_AppSettings.nRenderMode!=RENDERER_INTERNAL)
		ddsd.ddsCaps.dwCaps|=DDSCAPS_3DDEVICE;
	ddsd.dwBackBufferCount=1+G_AppSettings.tTripleBuffering;
	if (DX_TRY(DD_CreateSurface(ddsd,G_FrontBuffer)))
		throw INIT_ERR_CreateScreenBuffers;
	DD_ClearSurface(G_FrontBuffer);
	DDSCAPS ddscaps;
	ddscaps.dwCaps=DDSCAPS_BACKBUFFER;
	if (DX_TRY(G_FrontBuffer->GetAttachedSurface(&ddscaps,&G_BackBuffer)))
		throw INIT_ERR_GetBackBuffer;
	DD_ClearSurface(G_BackBuffer);
	if (G_AppSettings.tTripleBuffering)
		{
		ddscaps.dwCaps=DDSCAPS_FLIP;
		if (DX_TRY(G_BackBuffer->GetAttachedSurface(&ddscaps,&G_ThirdBuffer)))
			throw INIT_ERR_GetThirdBuffer;
		DD_ClearSurface(G_ThirdBuffer);
		}
	}

void DX_MakePrimarySurface()
	{
	Log(LT_Enter,"DX_MakePrimarySurface");
	if ((G_RenderInfo.tPaletted && G_AppSettings.nRenderMode==RENDERER_HAL) ||
		(!G_RenderInfo.tPaletted && G_AppSettings.nRenderMode==RENDERER_INTERNAL))
		throw INIT_ERR_WrongBitDepth;
	DDSURFACEDESC ddsd;
	InitDXStruct(ddsd);
	ddsd.dwFlags=DDSD_CAPS;
	ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE;
	if (DX_TRY(DD_CreateSurface(ddsd,G_FrontBuffer)))
		throw INIT_ERR_CreatePrimarySurface;
	}

void DX_MakeBackSurface()
	{
	Log(LT_Enter,"DX_MakeBackSurface");
	DDSURFACEDESC ddsd;
	InitDXStruct(ddsd);
	ddsd.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS;
	ddsd.dwWidth=(DWORD)G_RenderInfo.nBufferWidth;
	ddsd.dwHeight=(DWORD)G_RenderInfo.nBufferHeight;
	ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN|DDSCAPS_3DDEVICE;
	switch (G_AppSettings.nRenderMode)
		{
		case RENDERER_HAL:
			ddsd.ddsCaps.dwCaps|=DDSCAPS_VIDEOMEMORY;
			break;
		}
	if (DX_TRY(DD_CreateSurface(ddsd,G_BackBuffer)))
		throw INIT_ERR_CreateBackBuffer;
	DD_ClearSurface(G_BackBuffer);	//(G_BackBuffer,NULL,GetRandomDraw());
	}

void DX_MakeClipper()
	{
	Log(LT_Enter,"DX_MakeClipper");
	if (DX_TRY(G_DirectDraw->CreateClipper(0,&G_Clipper,NULL)))
		throw INIT_ERR_CreateClipper;
	if (DX_TRY(G_Clipper->SetHWnd(0,GhWnd)))
		throw INIT_ERR_SetClipperHWnd;
	if (DX_TRY(G_FrontBuffer->SetClipper(G_Clipper)))
		throw INIT_ERR_SetClipper;
	//G_Clipper->Release();
	}

void DX_MakePalette()
	{
	Log(LT_Enter,"DX_MakePalette");
	int i;
	DWORD dwFlags=DDPCAPS_8BIT;	//|DDPCAPS_INITIALIZE;
	ZeroArray(G_PaletteEntries);
	if (G_RenderInfo.tUse236Palette)
		{
		Log(LT_Info,"Using 236 colour palette");
		for (i=0;i<10;++i)
			{
			G_PaletteEntries[i].peFlags=G_PaletteEntries[i+246].peFlags=PC_EXPLICIT;
			G_PaletteEntries[i].peRed=G_PaletteEntries[i+246].peRed=i;
			}
		for (i=10;i<246;++i)
			G_PaletteEntries[i].peFlags=PC_NOCOLLAPSE|PC_RESERVED;	// D3DPAL_FREE
		}
	else
		{
		Log(LT_Info,"Using 256 colour palette");
	    for (i=0;i<256;++i)
			G_PaletteEntries[i].peFlags=PC_RESERVED;	// D3DPAL_FREE
		dwFlags|=DDPCAPS_ALLOW256;
		}
	if (DX_TRY(G_DirectDraw->CreatePalette(dwFlags,G_PaletteEntries,&G_Palette,NULL)))
		throw INIT_ERR_CreatePalette;
	if (DX_TRY(G_FrontBuffer->SetPalette(G_Palette)))
		throw INIT_ERR_SetPalette;
	}

local int DX_ChooseZBufferDepth()
	{
	DWORD dwDZBBD;
	dwDZBBD=G_DisplayAdapter.HAL_Desc.dwDeviceZBufferBitDepth;
	if (dwDZBBD&DDBD_16)
		return 16;
	else if (dwDZBBD&DDBD_24)
		return 24;
	else if (dwDZBBD&DDBD_32)
		return 32;
	return 8;
	}

void DX_MakeZBuffer()
	{
	Log(LT_Enter,"DX_MakeZBuffer");
	if (G_DisplayAdapter.HAL_Desc.dpcTriCaps.dwRasterCaps&D3DPRASTERCAPS_ZBUFFERLESSHSR)
		{
		Log(LT_Info,"No Z Buffer required");
		return;
		}
	DDSURFACEDESC ddsd;
	InitDXStruct(ddsd);
	ddsd.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_ZBUFFERBITDEPTH;
	ddsd.ddsCaps.dwCaps=DDSCAPS_ZBUFFER|DDSCAPS_VIDEOMEMORY;
	ddsd.dwWidth=(DWORD)G_RenderInfo.nBufferWidth;
	ddsd.dwHeight=(DWORD)G_RenderInfo.nBufferHeight;
	ddsd.dwZBufferBitDepth=DX_ChooseZBufferDepth();

	if (DX_TRY(DD_CreateSurface(ddsd,G_ZBuffer)))
		throw INIT_ERR_CreateZBuffer;
	if (DX_TRY(G_BackBuffer->AddAttachedSurface(G_ZBuffer)))
		throw INIT_ERR_AttachZBuffer;
	}

void DX_MakeInternalRendererSurface()
	{
	Log(LT_Enter,"DX_MakeInternalRendererSurface");
	DDSURFACEDESC ddsd;
	InitDXStruct(ddsd);
	ddsd.dwFlags=DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT;
	ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
	ddsd.dwWidth=(DWORD)G_RenderInfo.nBufferWidth;
	ddsd.dwHeight=(DWORD)G_RenderInfo.nBufferHeight;
	if (DX_TRY(DD_CreateSurface(ddsd,G_RenderBuffer)))
		throw INIT_ERR_CreateRenderBuffer;
	if (!DD_ClearSurface(G_RenderBuffer))
		throw INIT_ERR_ClearRenderBuffer;
	}

void DX_MakePictureSurface()
	{
	Log(LT_Enter,"DX_MakePictureSurface");
	DDSURFACEDESC ddsd;
	InitDXStruct(ddsd);
	ddsd.dwFlags=DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT;
	ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
	ddsd.dwWidth=640;
	ddsd.dwHeight=480;
	if (DX_TRY(DD_CreateSurface(ddsd,G_PictureBuffer)))
		throw INIT_ERR_CreatePictureBuffer;
	}

void DX_ClearBuffers(DWORD dwClrFlags,DWORD dwColour)
	{
	//Log("DX_ClearBuffers: %x",dwClrFlags);
	RECT rc;
	if (dwClrFlags&DXCB_CLRWINDOW)
		{
		rc.left=phd_winxmin;
		rc.top=phd_winymin;
		rc.right=phd_winxmin+phd_winwidth;
		rc.bottom=phd_winymin+phd_winheight;
		}
	else
		{
		rc.left=rc.top=0;
		rc.right=G_RenderInfo.nWidth;
		rc.bottom=G_RenderInfo.nHeight;
		}
	if (G_AppSettings.nRenderMode==RENDERER_HAL)
		{
		DWORD dwFlags=0;
		if (dwClrFlags&DXCB_BACK)
			dwFlags=D3DCLEAR_TARGET;
		if (dwClrFlags&DXCB_ZBUFFER)
			dwFlags|=D3DCLEAR_ZBUFFER;
		if (dwFlags)
			{
			D3DRECT rc3d;
			rc3d.x1=rc.left;
			rc3d.y1=rc.top;
			rc3d.x2=rc.right;
			rc3d.y2=rc.bottom;
			DX_TRY(G_Viewport->Clear(1,&rc3d,dwFlags));
			}
		}
	else if (dwClrFlags&DXCB_BACK)
		DD_ClearSurface(G_BackBuffer,&rc,dwColour);
	if (dwClrFlags&DXCB_FRONT)
		DD_ClearSurface(G_FrontBuffer,&rc,dwColour);
	if (dwClrFlags&DXCB_THIRD)
		DD_ClearSurface(G_ThirdBuffer,&rc,dwColour);
	if (dwClrFlags&DXCB_RENDER)
		DD_ClearSurface(G_RenderBuffer,&rc,dwColour);
	if (dwClrFlags&DXCB_PICTURE)
		{
		rc.left=rc.top=0;
		rc.right=640; rc.bottom=480;
		DD_ClearSurface(G_PictureBuffer,&rc,dwColour);
		}
	if (dwClrFlags&DXCB_CLIENT)
		{
		rc.left=GnWindowPosX;
		rc.top=GnWindowPosY;
		rc.right=GnWindowPosX+GnWindowWidth;
		rc.bottom=GnWindowPosY+GnWindowHeight;
		DD_ClearSurface(G_FrontBuffer,&rc,dwColour);
		}
	}

bool DX_CheckForLostSurfaces(void)
	{
	if (!G_FrontBuffer)
		S_ExitSystem("Oops... no front buffer");
	bool tRestart=DX_TRY(DD_EnsureSurfaceAvailable(G_FrontBuffer,0,G_AppSettings.tFullScreen));
	if (G_AppSettings.tFullScreen || G_AppSettings.nRenderMode==RENDERER_HAL)
		tRestart=tRestart||DX_TRY(DD_EnsureSurfaceAvailable(G_BackBuffer,G_FrontBuffer,true));
	if (G_AppSettings.tTripleBuffering)
		tRestart=tRestart||DX_TRY(DD_EnsureSurfaceAvailable(G_ThirdBuffer,G_FrontBuffer,true));
	if (G_AppSettings.nRenderMode==RENDERER_INTERNAL)
		tRestart=tRestart||DX_TRY(DD_EnsureSurfaceAvailable(G_RenderBuffer));
	if (G_ZBuffer)
		tRestart=tRestart||DX_TRY(DD_EnsureSurfaceAvailable(G_ZBuffer,0));
	if (G_PictureBuffer)
		tRestart=tRestart||DX_TRY(DD_EnsureSurfaceAvailable(G_PictureBuffer));
	if (tRestart && !GtWindowClosed)
		{
		Log(LT_Info,"At least one surface cannot be restored... Restarting");
		DX_Restart();
		if (G_AppSettings.nRenderMode==RENDERER_HAL)
			HWR_GetAllTextureHandles();
		}
	return tRestart;
	}

bool DX_UpdateFrame(bool tSpinMessageLoop,RECT* prcWindow)
	{
	if (!prcWindow)
		prcWindow=&G_RenderInfo.rcRender;
	DX_CheckForLostSurfaces();
	if (G_AppSettings.tFullScreen)
		{
		if (G_AppSettings.nRenderMode==RENDERER_INTERNAL)
			{
			G_BackBuffer->Blt(prcWindow,G_RenderBuffer,prcWindow,DDBLT_WAIT,NULL);
			}
		G_FrontBuffer->Flip(NULL,DDFLIP_WAIT);
		}
	else
		{
		RECT rcDest;
		rcDest.left=GnWindowPosX+prcWindow->left;
		rcDest.top=GnWindowPosY+prcWindow->top;
		rcDest.right=GnWindowPosX+prcWindow->right;
		rcDest.bottom=GnWindowPosY+prcWindow->bottom;
		IDirectDrawSurface3* pSrcSurf;
		if (G_AppSettings.nRenderMode==RENDERER_INTERNAL)
			pSrcSurf=G_RenderBuffer;
		else
			pSrcSurf=G_BackBuffer;
		G_FrontBuffer->Blt(&rcDest,pSrcSurf,prcWindow,DDBLT_WAIT,NULL);
		}
	if (tSpinMessageLoop)
		return DD_SpinMessageLoop();
	return true;
	}

/*bool DX_PaintRemappedRenderSurface(HWND hWnd)
	{
	}*/

void DX_DoFlipWait()
	{
	if (G_AppSettings.tFlipBroken && G_AppSettings.tFullScreen)
		while (G_FrontBuffer->GetFlipStatus(DDGFS_ISFLIPDONE)==DDERR_WASSTILLDRAWING);
	}

bool DX_Init()
	{
	Log(LT_Enter,"DX_Init");
	return true;
	}

void DX_Cleanup()
	{
	Log(LT_Enter,"DX_Cleanup");
	}

// try to initialise everything necessary to render, full screen or windowed, internal or Direct3D renderer.
void DX_Start(bool tStartAll)
	{
	if (tStartAll)
		{
		G_RenderInfo.tStarted=false;
		Log(LT_Enter,"DX_Start (full init)");
		}
	else
		Log(LT_Enter,"DX_Start (reinit)");
	ScreenMode mode;

	if (G_AppSettings.tFullScreen)
		{
		if (!G_AppSettings.FullScreenMode)
			throw INIT_ERR_GoFullScreen;
		if (G_AppSettings.nRenderMode==RENDERER_HAL)
			mode=G_DisplayAdapter.HAL_Modes[G_AppSettings.FullScreenMode];
		else
			mode=G_DisplayAdapter.Internal_Modes[G_AppSettings.FullScreenMode];
		if (!DD_GoFullScreen(mode))
			throw INIT_ERR_GoFullScreen;
		DX_MakeFlippingSurfaces();
		G_RenderInfo.nWidth=G_RenderInfo.nBufferWidth=mode.nWidth;
		G_RenderInfo.nHeight=G_RenderInfo.nBufferHeight=mode.nHeight;
		G_RenderInfo.nBPP=mode.nBPP;
		G_RenderInfo.tPaletted=(mode.nType!=MODETYPE_RGB);
		G_RenderInfo.tUse236Palette=false;
		G_RenderInfo.tIsStandardVGA=(mode.nType==MODETYPE_STANDARDVGA);
		Log(LT_Info,"Full screen %dx%dx%d",mode.nWidth,mode.nHeight,mode.nBPP);
		}
	else
		{
		int nMinWidth,nMinHeight;
		nMinWidth=320;
		nMinHeight=DD_CalcAspectAdjustedHeight(320,200);
		if (nMinHeight<200)
			{
			nMinWidth=DD_CalcAspectAdjustedWidth(320,200);
			nMinHeight=200;
			}
		DD_SetMinWindowSize(nMinWidth,nMinHeight);		// this shouldn't be here probably
		if (!DD_GoWindowed(G_AppSettings.nWindowWidth,G_AppSettings.nWindowHeight,mode))
			throw INIT_ERR_GoWindowed;
		G_RenderInfo.nWidth=mode.nWidth;							// DD_GoWindowed can decide on a different window size
		G_RenderInfo.nHeight=mode.nHeight;
		G_RenderInfo.nBufferWidth=(G_RenderInfo.nWidth+31)&(~31);	// make buffer a bit bigger to allow for a bit of sizing
		G_RenderInfo.nBufferHeight=(G_RenderInfo.nHeight+31)&(~31);
		G_RenderInfo.nBPP=mode.nBPP;
		G_RenderInfo.tPaletted=(mode.nType!=MODETYPE_RGB);
		G_RenderInfo.tUse236Palette=G_RenderInfo.tPaletted;			// windowed mode: might need 236 colour frig
		G_RenderInfo.tIsStandardVGA=false;							// its not going to be standard vga mode if its in a window...
		DX_MakePrimarySurface();
		if (G_AppSettings.nRenderMode!=RENDERER_INTERNAL)
			DX_MakeBackSurface();
		DX_MakeClipper();
		}

	DDPIXELFORMAT ddpf;
	InitDXStruct(ddpf);
	if (DX_TRY(G_FrontBuffer->GetPixelFormat(&ddpf)))
		throw INIT_ERR_GetPixelFormat;
	G_RenderInfo.pf.SetFromDDPF(ddpf);

	if (G_RenderInfo.tPaletted)				// is this ok?
		DX_MakePalette();
	if (G_AppSettings.nRenderMode!=RENDERER_INTERNAL && G_AppSettings.tZBuffer)
		DX_MakeZBuffer();
	if (G_AppSettings.nRenderMode==RENDERER_INTERNAL)
		{
		DX_MakeInternalRendererSurface();
		if (!G_PictureBuffer)
			DX_MakePictureSurface();
		}
	else
		{
		D3D_Start(G_BackBuffer);
//		D3D_Start(G_FrontBuffer);
		TX_Start();
		}

	if (!G_RenderInfo.tStarted)
		{
		G_RenderInfo.tUsing236Palette=G_RenderInfo.tUse236Palette;
		G_RenderInfo.tUsing16BitTextures=(G_TextureSettings.nBPP>=16);
		}
	else
		{
		bool t16BitTexturesNeeded=(G_TextureSettings.nBPP>=16);
		bool tNewPalette=(G_RenderInfo.tUse236Palette!=G_RenderInfo.tUsing236Palette);
		bool tNewTextures=(t16BitTexturesNeeded!=G_RenderInfo.tUsing16BitTextures);
		if (tNewPalette||tNewTextures)
			{
			S_ReloadLevelGraphics(tNewPalette,tNewTextures);
			G_RenderInfo.tUsing236Palette=G_RenderInfo.tUse236Palette;
			G_RenderInfo.tUsing16BitTextures=t16BitTexturesNeeded;
			}
		else
			{
			if (G_AppSettings.nRenderMode==RENDERER_HAL)
				{
				TX_RestoreAllTextures(true);	// D3D Device has changed so force new device surfaces
				HWR_GetAllTextureHandles();
				}
			}
		}

	G_RenderInfo.rcBuffer.left=0;
	G_RenderInfo.rcBuffer.top=0;
	G_RenderInfo.rcBuffer.right=G_RenderInfo.nBufferWidth;
	G_RenderInfo.rcBuffer.bottom=G_RenderInfo.nBufferHeight;
	G_RenderInfo.rcRender.left=0;
	G_RenderInfo.rcRender.top=0;
	G_RenderInfo.rcRender.right=G_RenderInfo.nWidth;
	G_RenderInfo.rcRender.bottom=G_RenderInfo.nHeight;
	
	game_setup.dump_width=G_RenderInfo.nWidth;
	game_setup.dump_height=G_RenderInfo.nHeight;
	setup_screen_size();

	G_RenderInfo.tStarted=true;
	Log(LT_Info,"DX_Start: OK!");			// if we get this far, everything is kewl!
	}

void DX_Finish(bool tFinishAll)
	{
	if (tFinishAll)
		Log(LT_Enter,"DX_Finish (full)");
	else
		Log(LT_Enter,"DX_Finish (partial)");

	if (G_AppSettings.nRenderMode==RENDERER_HAL)
		{
		if (tFinishAll)
			{
			HWR_FreeTexturePages();
			TX_Finish();
			}
		D3D_Finish();
		RELEASE(G_ZBuffer);
		}
	else
		{
		if (tFinishAll)
			RELEASE(G_PictureBuffer);	// hmm
		RELEASE(G_RenderBuffer);
		}
	RELEASE(G_Palette);
	RELEASE(G_Clipper);	// hmm
	RELEASE(G_ThirdBuffer);
	RELEASE(G_BackBuffer);
	RELEASE(G_FrontBuffer);

	if (tFinishAll)
		G_RenderInfo.tStarted=false;
	}

bool DX_Restart(AppSettings& rNewSettings)
	{
	Log(LT_Enter,"DX_Restart");

	DX_Finish(false);
	AppSettings oldSettings=G_AppSettings;
	if (&rNewSettings!=&G_AppSettings)
		G_AppSettings=rNewSettings;
	bool tNewSettingsOK=true;
	try
		{
		DX_Start(false);
		}
	catch (InitResult nErr)
		{
#ifdef DBLOG
		Log(ERR_Describe_Init(nErr));
#else
		nErr;
#endif
		tNewSettingsOK=false;
		DX_Finish(false);
		G_AppSettings=oldSettings;
		try
			{
			DX_Start(false);
			}
		catch (InitResult nErr)
			{
#ifdef DBLOG
			Log(ERR_Describe_Init(nErr));
#else
			nErr;
#endif
			DX_Finish(false);
			G_AppSettings.DisplayAdapter=G_PrimaryDisplayAdapter;
			G_AppSettings.tTripleBuffering=false;
			G_AppSettings.tFullScreen=true;
			G_AppSettings.nRenderMode=RENDERER_INTERNAL;
			G_AppSettings.FullScreenMode=G_DisplayAdapterList[G_PrimaryDisplayAdapter].Internal_Modes.Find(ScreenMode(640,480,0,0));
			try
				{
				DX_Start(false);
				}
			catch (InitResult nErr)
				{
#ifdef DBLOG
				Log(ERR_Describe_Init(nErr));
#else
				nErr;
#endif
				S_ExitSystem("Can't reinitialise renderer");
				}
			}
		}
	S_InitialiseScreen(-1);
	if (G_AppSettings.nRenderMode!=oldSettings.nRenderMode)
		S_ReloadLevelGraphics(true,true);
	else if ((G_AppSettings.nRenderMode==RENDERER_INTERNAL) && (G_AppSettings.tFullScreen!=oldSettings.tFullScreen))
		S_ReloadLevelGraphics(true,false);
	char buffer[64];
	if (G_AppSettings.tFullScreen)
		sprintf(buffer,"%dx%dx%d",G_RenderInfo.nWidth,G_RenderInfo.nHeight,G_RenderInfo.nBPP);
	else
		sprintf(buffer,"%dx%d",G_RenderInfo.nWidth,G_RenderInfo.nHeight);
	DisplayModeInfo(buffer);
	return tNewSettingsOK;
	}

void DX_PostFMVStart(void)
	{
	Log(LT_Enter,"DX_PostFMVStart");

	try
		{
		DX_Start();
		}
	catch (InitResult /*nErr*/)
		{
		DX_Finish();
		G_AppSettings.DisplayAdapter=G_PrimaryDisplayAdapter;
		G_AppSettings.tTripleBuffering=false;
		G_AppSettings.tFullScreen=true;
		G_AppSettings.nRenderMode=RENDERER_INTERNAL;
		G_AppSettings.FullScreenMode=G_DisplayAdapterList[G_PrimaryDisplayAdapter].Internal_Modes.Find(ScreenMode(640,480,0,0));
		try
			{
			DX_Start();
			}
		catch (InitResult /*nErr*/)
			{
			S_ExitSystem("Can't reinitialise renderer");
			}
		}
	}

bool DX_ChangeSettings(AppSettings& rNewSettings)
	{
	Log(LT_Enter,"DX_ChangeSettings");

	bool tRestart=false,tRenderStateChange=false,tUVChange=false,tResizeBuffers=false;
	bool tNewSettingsOK=true;

	if (rNewSettings.DisplayAdapter!=G_AppSettings.DisplayAdapter ||
		rNewSettings.SoundAdapter!=G_AppSettings.SoundAdapter ||
		rNewSettings.Joystick!=G_AppSettings.Joystick)
		return false;
	if (rNewSettings.nRenderMode!=G_AppSettings.nRenderMode ||
		rNewSettings.FullScreenMode!=G_AppSettings.FullScreenMode ||
		rNewSettings.tFullScreen!=G_AppSettings.tFullScreen ||
		rNewSettings.tZBuffer!=G_AppSettings.tZBuffer ||
		rNewSettings.tTripleBuffering!=G_AppSettings.tTripleBuffering)
		tRestart=true;
	if (rNewSettings.tPerspectiveCorrect!=G_AppSettings.tPerspectiveCorrect ||
		rNewSettings.tDither!=G_AppSettings.tDither ||
		rNewSettings.tBilinearFiltering!=G_AppSettings.tBilinearFiltering)
		tRenderStateChange=true;
	if (rNewSettings.tBilinearFiltering!=G_AppSettings.tBilinearFiltering ||
		rNewSettings.nRenderMode!=G_AppSettings.nRenderMode)
		tUVChange=true;
	if (!tRestart && !rNewSettings.tFullScreen && ((rNewSettings.nWindowWidth!=G_AppSettings.nWindowWidth)||(rNewSettings.nWindowHeight!=G_AppSettings.nWindowHeight)))
		{
		ScreenMode mode;
		if (!DD_GoWindowed(rNewSettings.nWindowWidth,rNewSettings.nWindowHeight,mode))
			return false;
		rNewSettings.nWindowWidth=mode.nWidth;
		rNewSettings.nWindowHeight=mode.nHeight;
		if ((rNewSettings.nWindowWidth!=G_AppSettings.nWindowWidth)||(rNewSettings.nWindowHeight!=G_AppSettings.nWindowHeight))
			{
			int nDX=rNewSettings.nWindowWidth-G_RenderInfo.nBufferWidth;
			int nDY=rNewSettings.nWindowHeight-G_RenderInfo.nBufferHeight;
			if (nDX>0 || nDX<-64 || nDY>0 || nDY<-64)
				tResizeBuffers=true;
			else
				{
				G_AppSettings.nWindowWidth=rNewSettings.nWindowWidth;
				G_AppSettings.nWindowHeight=rNewSettings.nWindowHeight;
				G_RenderInfo.nWidth=rNewSettings.nWindowWidth;
				G_RenderInfo.nHeight=rNewSettings.nWindowHeight;
				G_RenderInfo.rcRender.right=rNewSettings.nWindowWidth;
				G_RenderInfo.rcRender.bottom=rNewSettings.nWindowHeight;
				if (G_AppSettings.nRenderMode==RENDERER_HAL)
					D3D_UpdateViewport();
				setup_screen_size();
				GtFullScreenClearNeeded=false;
				}
			}
		}

	if (tRestart)
		{
		tNewSettingsOK=DX_Restart(rNewSettings);
		tRenderStateChange=false;
		tResizeBuffers=false;
		}
	if (tRenderStateChange)
		{
		G_AppSettings.tPerspectiveCorrect=rNewSettings.tPerspectiveCorrect;
		G_AppSettings.tDither=rNewSettings.tDither;
		G_AppSettings.tBilinearFiltering=rNewSettings.tBilinearFiltering;
		if (G_AppSettings.nRenderMode==RENDERER_HAL)
			HWR_InitState();
		}
	if (tUVChange)
		S_AdjustTexelCoordinates();
	if (tResizeBuffers)
		{
		DX_ClearBuffers(DXCB_CLIENT);
		tNewSettingsOK=DX_Restart(rNewSettings);	// too painful
		}
	return tNewSettingsOK;
	}

void DX_WindowResized()
	{
	Log(LT_Enter,"DX_WindowResized: %dx%d",GnWindowWidth,GnWindowHeight);
	// frig frig frig
	AppSettings newSettings=G_AppSettings;
	newSettings.nWindowWidth=GnWindowWidth;
	newSettings.nWindowHeight=GnWindowHeight;
	DX_ChangeSettings(newSettings);
	char buffer[64];
	sprintf(buffer,"%dx%d",G_RenderInfo.nWidth,G_RenderInfo.nHeight);
	DisplayModeInfo(buffer);
//	G_RenderInfo.nWidth=GnWindowWidth;
//	G_RenderInfo.nHeight=GnWindowHeight;
//	setup_screen_size();
	}
