#define WIN32_LEAN_AND_MEAN
#define STRICT
#include "no_shit.h"
#include <windows.h>
#include <mmsystem.h>
#include <ddraw.h>
#include <d3d.h>
#include <dinput.h>
#include <dsound.h>
#include <windowsx.h>
#include <time.h>
#include "specific.h"
//#include "..\resource.h"


#include "cpu.h"


#if !defined(__cplusplus)
#error Dude insists on C++ !!!
#endif

/***** internal specific stuff *****/

/*** display.cpp ***/
void		IncreaseScreenSize		();
void		DecreaseScreenSize		();
void		change_window_size		();
void		setup_screen_size		();
void		switch_resolution		();
void		TempVideoRemove			();

/*** file.cpp ***/
void		build_ext				(char* fname,char* ext);
char		*GetFullPath			(char* filename);
int			FindCdDrive				();
int			GetLevelNum				(char* levname);
void		ReloadLevelGraphics		();

/*** frontend.cpp ***/
int 		EscapeFMV				(int sequence,int mode);
int			EscapeFMVfile			(char *fname, int mode );

/*** init.cpp ***/
void		ShutdownGame			();
void		init_game_malloc		();
void 		CalculateWibbleTable	();

/*** main.cpp ***/
int			SwitchVideoMode			(int width,int height);
int			DecompPCX				(uint8* pSrc,int nLength,uint8* pDest,uint8* pPalette);
void		SaveScreen				();
void		FadeToPal				(int nframes,uint8* pal);
void		ScreenClear				(bool tWindow=false);

/*** option.cpp ***/
void		DefaultConflict			();

/*** output.cpp ***/
void 		AnimateTextures			(int nframes);
void		FadeWait				();
void		ScreenDump				();
void		ScreenPartialDump		();

/*** smain.cpp ***/
int			GameMain				();

/*** time.cpp ***/
int			Sync					();

/*** viewer.c (not used at the moment)
void		view_texture_page		();
void		view_objects			();
void		view_depthq				();
*/

/************************************ Dude's Stuff ****************************************/

/*** handy pragmas, let's not have silly warnings... ***/
//#pragma warning(disable: 4201)	// nameless struct/union
//#pragma warning(disable: 4514)	// unreferenced inline
//#pragma warning(disable: 4710)	// function not expanded
//#pragma warning(disable: 4800)	// convert to bool warning

/*** handy global/local stuff ***/
#define global extern
#define local static
#define defglobal

/*** handy typedefs ***/
typedef void* Handle;

/*** debug.cpp ***/
enum
	{
	LOG_OUTPUT,
	LOG_RESET,
	LOG_END
	};

#define LOG_DO_STRLEN 0xffffffff

#ifdef DBLOG
extern "C" void __cdecl DB_Log(char* format,...);
void DB_InitLog(char* sLogName);
void DB_SendLogMessage(DWORD dwType,PVOID pData,DWORD dwLen);
void DB_FlushLogStore();
void DB_LogWindowsMessage(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
#define Log DB_Log
#define IfLog
#define InitLog(a) DB_InitLog(a)
#define SendLogMessage(a,b,c) DB_SendLogMessage(a,b,c)
#define FlushLogStore DB_FlushLogStore
#define LogWindowsMessage DB_LogWindowsMessage
#else
// check this!!! totally nukes the Logs
#define Log 0&&
#define IfLog 0&&
#define InitLog(a)
#define SendLogMessage(a,b,c)
#define FlushLogStore()
#define LogWindowsMessage(a,b,c,d)
#endif
#define EndLog() SendLogMessage(LOG_END,0,0)

/*** handy macros... ***/
#define RELEASE_NOLOG(x) if (x) {(x)->Release();(x)=0;}
#define RELEASE_LOGTYPE(x,lt) if (x) {int nRef=(x)->Release();Log((lt),"Releasing " #x " -> %d",nRef);(x)=0;}
#define RELEASE(x) RELEASE_LOGTYPE(x,LT_Release)
#ifdef DBLOG
#define RELEASEARRAY(x) {int n=0; for (int i=0;i<ArraySize(x);++i) if ((x)[i]) {(x)[i]->Release();(x)[i]=0;++n;} Log(LT_Release,"Released %d of "#x"[%d]",n,ArraySize(x));}
#else
#define RELEASEARRAY(x) for (int i=0;i<ArraySize(x);++i) if ((x)[i]) {(x)[i]->Release();(x)[i]=0;}
#endif
#define RELEASECHECK(x) ReleaseChecker x##_Checker((IUnknown*)x,#x);
#define ArraySize(a) (sizeof(a)/sizeof((a)[0]))
#define Zero(thing) memset(&(thing),0,sizeof(thing))
#define ZeroArray(a) memset((a),0,sizeof(a))
#define EndOfArray(a) ((a)+ArraySize(a))
#define InitDXStruct(s) memset(&(s),0,sizeof(s)),(s).dwSize=sizeof(s)
#define DefLocalString(x,y) local char Lsz##x[]=y
#define LocalString(x) Lsz##x
#define DefValueName(x) local char Lsz##x[]=#x
#define ValueName(x) Lsz##x
#define Align(x,b) (x)=(x)&~((b)-1)

/*** classy classes ***/
class TempString	// hmm this is a bit shitty
	{
	char* pString;
	bool tDelete;
public:
	TempString(int nSize=256) {pString=new char[nSize];*pString=0;tDelete=TRUE;}
	TempString(char* s) {pString=s;tDelete=FALSE;}
	~TempString() {if (tDelete) delete[] pString;}
	operator char*() {return pString;}
	TempString& operator=(TempString& r)	// assignment operator
		{
		if (this!=&r)
			{
			if (!tDelete)
				pString=new char[strlen(r.pString)+1];
			strcpy(pString,r.pString);
			}
		return *this;
		}
	};

typedef void* Position;	// iterator for linked lists etc

template <class TYPE> class List	// doubly linked intrusive linked list template class!!!
	{
	struct Node
		{
		Node* pNext;
		Node* pPrev;
		TYPE data;
		Node(Node* pNewPrev,Node* pNewNext)
			: pNext(pNewNext),pPrev(pNewPrev) {}
		};
	Node* m_pHead;
	Node* m_pTail;
	int m_nCount;
public:
	List()
		{
		m_pHead=0;
		m_pTail=0;
		m_nCount=0;
		}
	void RemoveAll();
	~List() {RemoveAll();}
	TYPE& NewHead();
	TYPE& NewTail();
	void AddHead(TYPE& rData)
		{
		NewHead()=rData;
		}
	void AddTail(TYPE& rData)
		{
		NewTail()=rData;
		}
	Position GetHead() {return (Position)m_pHead;}
	Position GetTail() {return (Position)m_pTail;}
	Position GetNext(Position pos)
		{
		Node* pNode=(Node*)pos;
		if (pNode)
			pNode=pNode->pNext;
		return (Position)pNode;
		}
	Position GetPrev(Position pos)
		{
		Node* pNode=(Node*)pos;
		if (pNode)
			pNode=pNode->pPrev;
		return (Position)pNode;
		}
	void Remove(Position pos);
	TYPE& operator[](Position pos) {return ((Node*)pos)->data;}
	int GetCount() {return m_nCount;}
	bool IsEmpty() {return m_nCount==0;}
	List<TYPE>& operator=(List<TYPE>& rList);
	void Insert(TYPE& rData);
	Position Find(TYPE& rData);
	};

template <class TYPE> Position List<TYPE>::Find(TYPE& rData)
	{
	Node* pNode=m_pHead;
	if (!pNode)
		return 0;
	do
		{
		if (!(pNode->data<rData))
			return (Position)pNode;
		pNode=pNode->pNext;
		}
	while (pNode);
	return (Position)m_pTail;
	}

template <class TYPE> void List<TYPE>::Insert(TYPE& rData)
	{
	Node* pNode=m_pHead;
	if (!pNode)
		{
		AddHead(rData);
		return;
		}
	while (pNode)
		{
		if (rData<pNode->data)
			{
			Node* pPrevNode=pNode->pPrev;
			Node* pNewNode=new Node(pPrevNode,pNode);
			pNewNode->data=rData;
			if (pPrevNode==0)
				m_pHead=pNewNode;
			else
				pPrevNode->pNext=pNewNode;
			pNode->pPrev=pNewNode;
			return;
			}
		pNode=pNode->pNext;
		}
	AddTail(rData);
	}

template <class TYPE> void List<TYPE>::RemoveAll()
	{
	Node* pNode=m_pHead;
	while (pNode)
		{
		Node* pNext=pNode->pNext;
		delete pNode;
		pNode=pNext;
		}
	m_pHead=0;
	m_pTail=0;
	m_nCount=0;
	}

template <class TYPE> TYPE& List<TYPE>::NewHead()
	{
	Node* pNode=new Node(0,m_pHead);
	if (m_pHead)
		m_pHead->pPrev=pNode;
	else
		m_pTail=pNode;
	m_pHead=pNode;
	++m_nCount;
	return pNode->data;
	}

template <class TYPE> TYPE& List<TYPE>::NewTail()
	{
	Node* pNode=new Node(m_pTail,0);
	if (m_pTail)
		m_pTail->pNext=pNode;
	else
		m_pHead=pNode;
	m_pTail=pNode;
	++m_nCount;
	return pNode->data;
	}

template <class TYPE> void List<TYPE>::Remove(Position pos)
	{
	Node* pNode=(Node*)pos;
	if (pNode==m_pHead)
		m_pHead=pNode->pNext;
	else
		pNode->pPrev->pNext=pNode->pNext;
	if (pNode==m_pTail)
		m_pTail=pNode->pPrev;
	else
		pNode->pNext->pPrev=pNode->pPrev;
	delete pNode;
	}

template <class TYPE> List<TYPE>& List<TYPE>::operator=(List<TYPE>& rList)
	{
	if (this!=&rList)
		{
		RemoveAll();
		Node* pNode=rList.m_pHead;
		while (pNode)
			{
			NewTail()=pNode->data;
			pNode=pNode->pNext;
			}
		}
	return *this;
	}

#define for_all(p,l) for (Position p=(l).GetHead();p;p=(l).GetNext(p))

struct GenericAdapter
	{
	GUID* pGUID;						// NULL for primary device, else =&AdapterGuid
	GUID AdapterGUID;					// GUIDs of secondary devices
	TempString strDescription,strName;	// description strings
	void SetGUID(const GUID* pNewGUID)
		{
		if (pNewGUID)
			{
			AdapterGUID= *pNewGUID;
			pGUID=&AdapterGUID;
			}
		else
			{
			Zero(AdapterGUID);
			pGUID=0;
			}
		}
	};

class ReleaseChecker
	{
	IUnknown* m_pObject;
	char* m_szName;
public:
	ReleaseChecker(IUnknown* pObject,char* szName) {m_pObject=pObject; m_szName=szName; m_pObject->AddRef();}
	~ReleaseChecker() {int nRefCount=m_pObject->Release(); if (nRefCount) Log(LT_Error,"Oops, %s->Release() -> %d",m_szName,nRefCount);}
	};

/*** debug.cpp ***/
TempString ERR_Describe_RC(char* szResource);

/*** dxerror.cpp ***/
char* ERR_Describe_DX(HRESULT hr);
char* ERR_Describe_Init(int nError);
enum InitResult	// possible initialisation results
	{
	INIT_OK,

	INIT_ERR_PreferredAdapterNotFound,
	INIT_ERR_CantCreateWindow,
	INIT_ERR_CantCreateDirectDraw,
	INIT_ERR_CantInitRenderer,
	INIT_ERR_CantCreateDirectInput,
	INIT_ERR_CantCreateKeyboardDevice,
	INIT_ERR_CantSetKBCooperativeLevel,
	INIT_ERR_CantSetKBDataFormat,
	INIT_ERR_CantAcquireKeyboard,
	INIT_ERR_CantSetDSCooperativeLevel,

	INIT_ERR_DD_SetExclusiveMode,
	INIT_ERR_DD_ClearExclusiveMode,
	INIT_ERR_SetDisplayMode,
	INIT_ERR_CreateScreenBuffers,
	INIT_ERR_GetBackBuffer,
	INIT_ERR_CreatePalette,
	INIT_ERR_SetPalette,
	INIT_ERR_CreatePrimarySurface,
	INIT_ERR_CreateBackBuffer,
	INIT_ERR_CreateClipper,
	INIT_ERR_SetClipperHWnd,
	INIT_ERR_SetClipper,
	INIT_ERR_CreateZBuffer,
	INIT_ERR_AttachZBuffer,
	INIT_ERR_CreateRenderBuffer,
	INIT_ERR_CreatePictureBuffer,
	INIT_ERR_D3D_Create,
	INIT_ERR_CreateDevice,
	INIT_ERR_CreateViewport,
	INIT_ERR_AddViewport,
	INIT_ERR_SetViewport2,
	INIT_ERR_SetCurrentViewport,

	INIT_ERR_ClearRenderBuffer,
	INIT_ERR_UpdateRenderInfo,
	INIT_ERR_GetThirdBuffer,

	INIT_ERR_GoFullScreen,
	INIT_ERR_GoWindowed,

	INIT_ERR_WrongBitDepth,
	INIT_ERR_GetPixelFormat,
	INIT_ERR_GetDisplayMode
	};

/*** utils.cpp ***/
bool UT_ExecAndWait(char* sProgramName,DWORD dwTimeout);
void* UT_GetResource(char* szResource,char* szType);
double UT_RDTSC();
#define DOUBLE_TO_DWORD_FRIG_FACTOR ((double)(4294967296+1048576*4294967296))
inline DWORD UT_DoubleToDWORD(double d)
	{
	double dT=d+DOUBLE_TO_DWORD_FRIG_FACTOR;
	return *((DWORD*)&dT);
	}
void UT_InitAccurateTimer();
double UT_GetAccurateTimer();
time_t UT_ConvertDateToTimeT(char* szTime,char* szDate);
void UT_CenterWindow(HWND hWnd);
char* UT_FindArg(char* arg);					// beware!! this is currently shit, it only compares arg with argv[1]...
bool UT_GetArg(char* szArg,int& rnValue);
void UT_ErrorBox(char* szString,HWND hWndOwner=0);
void UT_ErrorBox(int nID,HWND hWndOwner=0);
bool UT_OKCancelBox(char* szDlgResource,HWND hWndOwner);
char* UT_StringFromGUID(GUID& pGUID);
bool UT_GUIDFromString(char* pString,GUID& rGUID);
#define GUID_STRING_LENGTH (16*2+3+2)	// was 16*2+10+2
bool UT_SendMail(char* szTo,char* szSubject=0,char* szBody=0,bool tAllowLogonDialog=true);

bool REG_OpenKey(char* szLocation);
bool REG_KeyWasCreated();
void REG_CloseKey();
void REG_DeleteValue(char* szName);
void REG_WriteValue(char* szName,DWORD dwValue);
void REG_WriteValue(char* szName,bool tValue);
void REG_WriteValue(char* szName,double dValue);
void REG_WriteValue(char* szName,void* pData,int nSize);
void REG_WriteValue(char* szName,char* szString,int nLength=-1);	// default value means calc nLength=strlen(szString)
bool REG_ReadValue(char* szName,DWORD& rdwValue,DWORD dwDefault=0);
bool REG_ReadValue(char* szName,bool& rtBool,bool tDefault=false);
bool REG_ReadValue(char* szName,double& rdDouble,double dDefault=0.0);
bool REG_ReadValue(char* szName,void* pData,int nSize,void* pDefaultData=0);
bool REG_ReadValue(char* szName,char* szString,int nMax,char* szDefault=0);
bool REG_ReadValue(char* szName,GUID& rGUID,GUID* pDefaultGUID=0);
inline void REG_WriteValue(char* szName,int nValue) {REG_WriteValue(szName,(DWORD)nValue);}
inline void REG_WriteValue(char* szName,GUID& rGUID) {REG_WriteValue(szName,UT_StringFromGUID(rGUID),GUID_STRING_LENGTH);}
inline bool REG_ReadValue(char* szName,int& rnValue,int nDefault=0) {return REG_ReadValue(szName,(DWORD&)rnValue,(DWORD)nDefault);}

class DIB
	{
public:
	DIB() :m_pBMI(0),m_pImage(0),m_hPalette(0) {}
	~DIB();
	void LoadFromResource(char* szResource);
	bool Make(int nWidth,int nHeight,uint8* pPalette);
	void Draw(HDC hdc,int nX,int nY);
	void WM_PaletteChanged(HWND hWnd,HWND hWndChangedBy);
	void WM_QueryNewPalette(HWND hWnd);
	int GetWidth() {return m_pBMI->bmiHeader.biWidth;}
	int GetHeight() {return m_pBMI->bmiHeader.biHeight;}
	uint8* GetImageData() {return (uint8*)m_pImage;}
private:
	BITMAPINFO* m_pBMI;
	void* m_pImage;
	HPALETTE m_hPalette;
	DWORD m_dwFlags;
	};

#define DIB_FLAG_DELETEIMAGE 1

bool DW_RegisterWindowClass();
void DW_LoadFromResource(HWND hWnd,char* szResource=0);
void DW_HandlePaletteChanges(HWND hWnd,UINT msg,WPARAM wParam);

void UT_MemBlt(uint8* pDest,int nDX,int nDY,int nDW,int nDH,int nDStride,uint8* pSrc,int nSX,int nSY,int nSStride);

/*** dd.cpp ***/
struct PixelFormat
	{
	DWORD dwRMask,dwGMask,dwBMask,dwAMask;
	int nRBits,nGBits,nBBits,nABits;
	int nRShift,nGShift,nBShift,nAShift;
	void SetFromDDPF(DDPIXELFORMAT& rDDPF);
	};

// Screen mode: used for both full screen and windowed modes.
struct ScreenMode
	{
	int nWidth;			// x-res of mode
	int nHeight;		// y-res of mode
	int nBPP;			// bits per pixel
	int nType;			// linear/modex/standard vga
	ScreenMode() {}
	ScreenMode(int nW,int nH,int nD,int nT) : nWidth(nW),nHeight(nH),nBPP(nD),nType(nT) {}
	void Set(int nW,int nH,int nD,int nT) {nWidth=nW; nHeight=nH; nBPP=nD; nType=nT;}
	bool operator==(ScreenMode& r) {return nWidth==r.nWidth && nHeight==r.nHeight && nBPP==r.nBPP && nType==r.nType;}
	bool operator<(ScreenMode& r);
	};
enum
	{
	MODETYPE_RGB,
	MODETYPE_PALETTED,
	MODETYPE_MODEX,
	MODETYPE_STANDARDVGA
	};

// DisplayAdapter: eg SVGA, Permedia, 3DFX, Rendition
// One or more of these should be installed in a machine.
struct DisplayAdapter : GenericAdapter
	{
	DDCAPS DriverCaps,HELCaps;			// the (2d) capabilities of the adapter / HEL

	GUID HAL_GUID;						// HAL Driver GUID
	D3DDEVICEDESC HAL_Desc;				// HAL driver capabilities
	List<ScreenMode> HAL_Modes;			// list of full screen modes capable of hardware acceleration

	List<ScreenMode> Internal_Modes;	// list of full screen modes our internal renderer can use (8 bit ones...)

	ScreenMode Lores_Mode,Hires_Mode;	// 320x200 and 640x480 modes.  Contain MODEX/STANDARDVGA info...

	int nMaxWindowWidth;				// max x size of window, multiple of 64, y=x*3/4 must also fit.
	bool tHAL;							// true if a HAL is available for this adapter
	bool tInternalCanDoWindowed;		// true if internal software renderer can be used to run in a window given the current display mode
	bool tHALCanDoWindowed;				// true if Direct3D HAL for this adapter will render to a window given the current display mode
	bool tInternalCanDoFullScreen320;	// true if 320x200x8 fullscreen mode is supported
	bool tInternalCanDoFullScreen640;	// true if 640x480x8 fullscreen mode is supported
	bool tHALPerspectiveCorrectSupported;// true if hardware supports perspective correct texture mapping
	bool tHALDitherSupported;			// true if hardware can dither to reduce banding
	bool tHALZBufferSupported;			// true if hardware can render using Z buffer
	bool tHALBilinearFilteringSupported;// true if hardware supports bilinear filtered texture mapping
	bool tHALNeedsStippledAlpha;		// true if hardware wants stippled alpha!!!
	};
global int GnDirectDrawLocks;
global List<DisplayAdapter> G_DisplayAdapterList;
global DisplayAdapter G_DisplayAdapter;
global Position G_PrimaryDisplayAdapter;
global IDirectDraw2* G_DirectDraw;
global HWND GhWnd;
global int GnWindowPosX,GnWindowPosY;
global int GnWindowWidth,GnWindowHeight;
global int GnAppReturnValue;
global bool GtWindowClosed;

bool DD_Init();
void DD_Cleanup();
void DD_Start();
void DD_Finish();

HWND DD_FindWindow();
bool DD_SpinMessageLoop(bool tWait=false);
void DD_ShowWindow(int nShow=SW_SHOW);
void DD_HideWindow();
void DD_MoveWindow(int nX,int nY);
void DD_SizeWindow(int nWidth,int nHeight);
bool DD_SetExclusiveMode(bool tAllowWindowChanges=true);
bool DD_ClearExclusiveMode();
HRESULT DD_CreateSurface(DDSURFACEDESC& ddsd,IDirectDrawSurface3*& rpSurf);
HRESULT DD_EnsureSurfaceAvailable(IDirectDrawSurface3* pSurf,IDirectDrawSurface3* pTopSurf=0,bool tClearIfLost=false);
bool DD_ClearSurface(IDirectDrawSurface3* pSurf,RECT* pRect=0,DWORD dwColour=0);
bool DD_ClearZBuffer(IDirectDrawSurface3* pSurf,RECT* pRect=0);
HRESULT DD_LockSurface(IDirectDrawSurface3* pSurf,DDSURFACEDESC& rDDSD,DWORD dwFlags=DDLOCK_WAIT|DDLOCK_WRITEONLY);
HRESULT DD_UnlockSurface(IDirectDrawSurface3* pSurf,DDSURFACEDESC& rDDSD);
bool DD_CopyBitmapToSurface(IDirectDrawSurface3* pSurf,void* pSrc);
DWORD DD_BPPToDDBD(int bpp);
DWORD DD_PixelFromRGB(PixelFormat& rPF,int nR,int nG,int nB);
DWORD DD_PixelFromRGBA(PixelFormat& rPF,int nR,int nG,int nB,int nA);
bool DD_GetDisplayMode(ScreenMode& rMode);
bool DD_GoFullScreen(const ScreenMode& rMode);
bool DD_GoWindowed(int nWidth,int nHeight,ScreenMode& rModeUsed);
void DD_SetMinWindowSize(int nWidth,int nHeight);
void DD_ClearMinWindowSize();
void DD_SetMaxWindowSize(int nWidth,int nHeight);
void DD_ClearMaxWindowSize();
int DD_CalcAspectAdjustedWidth(int nWidth,int nHeight);
int DD_CalcAspectAdjustedHeight(int nWidth,int nHeight);
void DD_DetermineWindowedCapabilities(DisplayAdapter& adapter);
Position DD_FindPreferredAdapter(GUID* pGUID);

/*** d3d.cpp ***/
global IDirect3D2* G_Direct3D;
global IDirect3DDevice2* G_Direct3DDevice;
global IDirect3DViewport2* G_Viewport;
global IDirect3DMaterial2* G_BlackMaterial;

int D3D_Init();
void D3D_Cleanup();
void D3D_Start(IDirectDrawSurface3* pRenderTarget);
void D3D_Finish();

void D3D_FindDrivers(DisplayAdapter& adapter);
bool D3D_UpdateViewport();
bool D3D_RenderToSurface(IDirectDrawSurface3* pRenderTarget,IDirectDrawSurface3** ppOldRenderTarget=0);

/*** settings.cpp ***/
struct AppSettings
	{
	Position DisplayAdapter;			// G_DisplayAdapterList[DisplayAdapter] is the one we're using...
	Position SoundAdapter;				// same for sound card
	Position Joystick;					// and joystick
	Position FullScreenMode;			// hardware fullscreen mode x/y/bpp
	int nRenderMode;					// none/internal/HAL/RGB
	int nWindowWidth,nWindowHeight;		// size of desktop window
	int nAspectMode;					// 4:3 / 16:9 / any
	bool tPerspectiveCorrect;			// perspective correct textures
	bool tDither;						// dithering on/off
	bool tZBuffer;						// render using z buffer
	bool tBilinearFiltering;			// use bilinear filtering when texture mapping
	bool tTripleBuffering;				// use three buffers instead of two, for better performance but more memory usage
//	bool tMipMap;						// use mipmapped textures
//	bool tAntialias;					// antialias edges
	bool tFullScreen;					// switch to full screen or run in window
	bool tSoundEnabled;					// false = disable sound
	bool tLaraMic;						// position mic at lara instead of camera (for paul & toby)
	bool tJoystickEnabled;				// false = disable joystick
	bool tDisable16BitTextures;			// true = disable 16 bit textures (for 2MB Mystique etc)
	bool tDontSortPrimitives;			// true = no need to sort primitives (for PowerVR)
	bool tFlipBroken;					// true = driver doesn't wait for flip to finish before rendering.  must do it myself...
	bool tDisableFMV;					// true = don't play any FMVs
	int nTexelAdjustMode;				// never / when filtering / always
	int nNearestAdjustment;				// non-filtered texel adjustment
	int nLinearAdjustment;				// bilinear filtered texel adjustment
	};
enum
	{
	RENDERER_NONE,
	RENDERER_INTERNAL,
	RENDERER_HAL,
	RENDERER_HOWMANY
	};
enum
	{
	ASPECT_4_3,
	ASPECT_16_9,
	ASPECT_ANY,
	ASPECT_HOWMANY
	};
enum
	{
	TEXEL_NEVER,
	TEXEL_WHENFILTERING,
	TEXEL_ALWAYS,
	TEXEL_HOWMANY
	};
global AppSettings G_AppSettings;

bool SE_WriteAppSettings(AppSettings& as);
int SE_ReadAppSettings(AppSettings& as);
enum
	{
	SE_RS_ERROR,
	SE_RS_OK,
	SE_RS_NEW
	};
bool SE_OpenRegistry(char* szSubKeyName=0);
void SE_CloseRegistry();
bool SE_DoPropertySheet(HWND hWndOwner,bool tFirstTime);
HWND SE_FindWindow();

/*** dx.cpp ***/
struct RenderInfo
	{
	List<ScreenMode>* pModeList;
	Position CurrentScreenMode;
	ScreenMode FullScreenMode;		// want to take this out maybe
	PixelFormat pf;
	RECT rcBuffer;
	RECT rcRender;
	int nWidth;
	int nHeight;
	int nBPP;
	int nBufferWidth;
	int nBufferHeight;
	int nUVAdd;
	bool tPaletted;
	bool tUse236Palette;
	bool tIsStandardVGA;
	bool tUsing236Palette;
	bool tUsing16BitTextures;
	bool tStarted;
	};

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

bool DX_Init();
void DX_Cleanup();
void DX_Start(bool tStartAll=true);
void DX_Finish(bool tFinishAll=true);
bool DX_Restart(AppSettings& rNewSettings=G_AppSettings);
void DX_PostFMVStart();
bool DX_CheckForLostSurfaces(void);
bool DX_UpdateFrame(bool tSpinMessageLoop=true,RECT* prcWindow=0);
bool DX_PaintRemappedRenderSurface(HWND hWnd);
void DX_DoFlipWait();
void DX_WindowResized();
bool DX_ChangeSettings(AppSettings& rNewSettings);
void DX_ClearBuffers(DWORD dwClrFlags,DWORD dwColour=0);

#define DXCB_FRONT 1
#define DXCB_BACK 2
#define DXCB_THIRD 4
#define DXCB_ZBUFFER 8
#define DXCB_RENDER 16
#define DXCB_PICTURE 32
#define DXCB_CLIENT 64
#define DXCB_CLRWINDOW 256


/*** ds.cpp ***/
struct SoundAdapter : GenericAdapter
	{
	};
global List<SoundAdapter> G_SoundAdapterList;
global SoundAdapter G_SoundAdapter;
global Position G_PrimarySoundAdapter;

bool DS_Init();
void DS_Cleanup();
void DS_Start(HWND hWnd=0);
void DS_Finish();

Position DS_FindPreferredAdapter(GUID* pGUID);
bool DS_IsSoundEnabled();

bool DS_MakeSample(int nSample,WAVEFORMATEX* pWF,void* pWaveData,DWORD dwWaveLength);
void DS_FreeAllSamples();
int DS_StartSample(int nSample,int nVolume,int nPitch,int nPan,DWORD dwFlags);
void DS_AdjustVolumeAndPan(int nHandle,int nVolume,int nPan);
void DS_AdjustPitch(int nHandle,int nPitch);
void DS_StopSample(int nHandle);
void DS_StopAllSamples();
bool DS_IsChannelPlaying(int nSlot);
int DS_HowManyChannelsPlaying();

#define	DS_ERR_SOUND_FAILED			(-2)
#define	DS_ERR_SOUND_NO_FREE_SLOTS	(-1)

/*** di.cpp ***/
struct Joystick : GenericAdapter
	{
	};
global List<Joystick> G_JoystickList;
global Joystick G_Joystick;


bool DI_Create();
void DI_Release();
bool DI_Init();
void DI_Cleanup();
void DI_Start();
void DI_Finish();
void DI_SetupJoystick(HWND hWnd);

Position DI_FindPreferredJoystick(GUID* pGUID);
void DI_ReadKeyboard(unsigned char* keymap);
int DI_ReadJoystick(int& joy_x,int& joy_y);

/*** swr.cpp ***/
void SWR_DrawPolyList();
void SWR_Make236Palette(uint8* pSrc,uint8* pImage,int nPixels,uint8* pDest);
uint8 SWR_FindNearestPaletteEntry(uint8* pPal,int nR,int nG,int nB,bool tDontUseWindowsColours=false);
void SWR_ConvertImage(uint8* pSrc,int nSX,int nSY,int nSP,uint8* pOldPalette,uint8* pDest,int nDP,uint8* pNewPalette,bool tDontUseWindowsColours=false);

/*** hwrender.cpp ***/
global D3DTLVERTEX* CurrentTLVertex;
global DWORD GhCurTextureHandle;
global bool GtColorKeyEnabled;
global DWORD GahTextureHandle[];

bool HWR_Init();
void HWR_InitVertexList();
bool HWR_IsVertexBufferFull();
void HWR_InitState();
void HWR_BeginScene();
void HWR_EndScene();
void HWR_DrawPolyList();
void HWR_LoadTexturePages(int nPages,char* pImage,uint8* pPalette);
void HWR_FreeTexturePages();
void HWR_RestoreTexturePages();
void HWR_ResetCurrentTexture();
void HWR_ResetColorKey();
void HWR_ResetZBuffer();
void HWR_SetCurrentTexture(DWORD dwHandle);
void HWR_EnableColorKey(bool tEnable);
void HWR_EnableZBuffer(bool tWrite,bool tCompare);
void HWR_GetAllTextureHandles();
extern "C" void __cdecl HWR_DrawRoomBucket(void*);

/*** fmv.cpp ***/
int FMV_Play(char* szMovieName);
int FMV_PlayIntro(char *szMovie1, char *szMovie2);

/*** time.cpp ***/
bool TIME_Init();

/*** main.cpp ***/
//global HINSTANCE GhInstance;
global char* GpCmdLine;

void SaveDDBuffer(IDirectDrawSurface3* pSurf);

/*** bgnd.cpp ***/
bool BGND_Init(void);
void BGND_Make640x480(uint8* pImage,uint8* pPalette);
void BGND_Draw(void);
void BGND_Free(void);

/*** misc ***/
inline bool DX_TRY(HRESULT hr)
	{
	if (SUCCEEDED(hr))
		return false;
	Log(ERR_Describe_DX(hr));
	return true;
	}

inline bool DX_FAILED(HRESULT hr)
	{
	return FAILED(hr);
	}

global int GnTexturePages;
global bool GtWireFrameMode;
global bool GtFullScreenClearNeeded;
global bool GtDumpOnly;
global bool GtDisableFullScreenWindowedToggle;
global RECT GrcDumpWindow;


