#pragma once

#include "wtypes.h"				// gives us WORD, DWORD, NULL,...
#include "d3d8types.h"			// defines texture types and exposes shader languages
#include "tchar.h"

class GosObj;
class GosClassInfo;
class GosUtil;
class GosApp;
class Gos3D;
class GosSound;
class GosAudio;
class GosSurface;
class GosTexture;
class GosVertexShader;
class GosPixelShader;
class GosVertexBuffer;
class GosIndexBuffer;
class GosStateBlock;
class GosFont3D;


#define STOP(x)	DebugBreak()

#ifdef _DEBUG

#ifndef LAB_ONLY
#define LAB_ONLY 1
#endif

#define LOG_API(api)  LOG_BLOCK(api)	// later, this will be distinct from other blocks
#define GOS_ASSERT(x)	\
	{					\
		if( !(x) )		\
		{				\
			OutputDebugString( _T(#x) ); \
			OutputDebugString( _T(" ASSERT FAILED\n") ); \
			DebugBreak(); \
		}				\
	}

// Example use of spew:  SPEW( "Render::Robot", ( "Coords %d,%d", x, y ) );
#define SPEW(cat,fmt) { static bool * pCat = GosDebug::Cat(cat); if(*pCat) GosDebug::Output fmt; }
#define SPEWV(cat,fmt) { static bool * pCat = GosDebug::Cat(cat); if(*pCat) GosDebug::OutputV fmt; }
#define PAUSE(x) (void)0

#define SPEW_ENABLE(cat) { static bool * pCat = GosDebug::Cat(cat); GosDebug::EnableCat(pCat); }
#define SPEW_DISABLE(cat) { static bool * pCat = GosDebug::Cat(cat); GosDebug::DisableCat(pCat); }

#define DBGNAME(FixedName) _T(FixedName)

#else

#define LOG_API(api)
#define GOS_ASSERT(x) {}
#define SPEW(cat,fmt) {}
#define SPEWV(cat,fmt) {}
#define PAUSE(x) (void)0
#define SPEW_ENABLE(cat) {}
#define SPEW_DISABLE(cat) {}

#define DBGNAME(FixedName) _T("")

#endif

class GosObj
{
private:
	friend					GosClassInfo;
							GosObj();
public:
	unsigned long			m_ID;		// id used by debugger to track this object
	GosObj *				m_pPrev;	// previous object of this type
	GosObj *				m_pNext;	// next object of this type
							GosObj( GosClassInfo *pClassInfo );
							~GosObj();
};

class GosClassInfo : public GosObj
{
public:
	static GosClassInfo *(*RegisterClass)( _TCHAR *className );
};


class GosVideo
{
public:
	enum VideoProperty
	{
		Origin,			// float x, float y
		Scale,			// float xScale, float yScale
		Volume,			// float volume
		Panning,		// float panning
		PlayState,		// bool playing, bool looping, bool hideWhenDone
		SeekPosition,	// float hundredthsOfSeconds
		Duration,		// float hundredthsOfSeconds
		HideEnd,		// bool hideEnd
		Dimensions,		// int height, int width	/* Get=native size, Set=alter xScale,yScale */
		Bits,			// void *pData, int pitch
	};
	static GosVideo *		(*OpenFullScreen)( TCHAR *pFileName );
	static GosVideo *		(*OpenToTexture)( GosTexture **ppTexture, TCHAR *pFileName );
	static void				(*Shutdown)();
	virtual					~GosVideo(){;}
	virtual	void			Set( VideoProperty Property,... )=0;
	virtual	void			Get( VideoProperty Property,... )=0;
	virtual	void			Play( bool Looping=false, bool HideWhenDone=true )=0;
	virtual	void			Seek( float HundredthsOfSeconds=0.f )=0;
	virtual	void			Stop()=0;
	virtual	void			Pause()=0;
};

class GosAudio
{
public:
	enum ChannelProperty
	{
		// Channels & system
		Volume,			// float volume
		Position,		// float x, float y, float z
		Velocity,		// float x, float y, float z

		// System only
		SpeakerConfig,	// int numSpeakers, int feetSeparation, int degreesArc
		ListenerFront,	// float x, float y, float z
		ListenerTop,	// float x, float y, float z
		Rolloff,		// float rolloff
		Distance,		// float distance
		Reverb,			// float reverb
		Decay,			// float decay

		// Channels only
		Panning,		// float panning
		Frequency,		// float frequency
		PositionPercent,// float positionPercent
		AudibleRange,	// float minDistance, float maxDistance
		AudibleCone,	// float degreesInner, float degreesOuter
		ConeAngle,		// float x, float y, float z
		PlayState,		// bool playing, bool looping, int seekPosition
		AssignedSound,	// GosAudioSound *pSound


	};
	// e.g. GosAudio::System()->Set( 0, GosAudio::SpeakerConfig,2,10,60);
	static void				(*Set)( int Channel, ChannelProperty Property,... );
	static void				(*Get)( int Channel, ChannelProperty Property,... );
	static int				(*NumChannels)();	// e.g 3 means: channel 0 = system, channel 1,2,3 can be assigned sounds

	static void				(*AssignSound)( int Channel, GosSound *pSound );
	static void				(*Play)( int Channel, bool Loop=false, int SeekPosition=-1 );	// seekPosition = -1 means continue
	static void				(*Pause)( int Channel );
	static void				(*Stop)( int Channel );
};


class GosSound : public GosObj
{
public:
	struct Format
	{
		WORD		formatTag;			// 1=PCM, 2=Microsoft ADPCM.
		WORD		nChannels; 			// 1=Mono, 2 = Stereo.
		DWORD		nSamplesPerSec;		// e.g. 8000, 11025, 22050, or 44100
		DWORD		nAvgBytesPerSec;    // Required average data-transfer rate PCM: nSamplesPerSec x nBlockAlign. 
		WORD		nBlockAlign; 		// PCM: nChannels * bitsPerSample / 8. ADPCM: block size e.g. 512
		WORD		bitsPerSample;		// PCM: 8 or 16, For ADPCM: typically 4
		WORD		cbSize;				// Bytes, of extra format information appended. PCM:0, ADPCM:32
	};

	static GosSound *		(*OpenFixed)( TCHAR *pFileName );
	static GosSound *		(*OpenStreamed)( TCHAR *pFileName );
	static GosSound *		(*DecodeFromMemory)( void *pData, int Size=0 );
	static GosSound *		(*OpenFromMemory)( Format *pFormat, void *pData, int Size=0 );
	static GosSound *		(*OpenSequence)( int NumSounds, DWORD **ppData, DWORD *pLength );
	virtual					~GosSound(){;}
};


class GosText
{
public:
	enum TextProperty
	{
		Font,			// GosFont3D *pFont
		ForegroundColor,// DWORD argb
		Size,			// float size		/* >0 = scale, <0 = point size */
		WordWrap,		// bool wordWrap
		Proportional,	// bool proportional
		Bold,			// bool bold
		Italic,			// bool italic
		Alignment,		// DWORD alignment
		Position,		// int x, int y
		RegionStart,	// int left, int top
		RegionEnd,		// int right, int bottom
	};
	static void				(*Set)( TextProperty Property,... );
	static void				(*Get)( TextProperty Property,... );
	static void				(*Draw)( _TCHAR *Message,... );
	static void				(*DrawUncached)(  _TCHAR *,... );
	static void				(*StringLength)( DWORD* pWidth, DWORD* pHeight, const TCHAR *Message, ... );

	static void				(*DrawBackground)( int Left, int Top, int Right, int Bottom, DWORD color );
	static void				(*SetAttributes)( GosFont3D *pFont, DWORD Foreground, float Size, bool WordWrap, bool Proportional, bool Bold, bool Italic, DWORD Alignment=0 );
	static void				(*SetRegion)( int Left, int Top, int Right, int Bottom );
	static void				(*SelectFont)( GosFont3D *pFont );
	static void				(*Flush)( bool DeleteAll = false );

	// For use by GOS Framework
	static	bool			(*Initialize)();
	static	void			(*Shutdown)();
};


class GosFont3D
{
public:
	static GosFont3D *		(*CreateFromFile)( TCHAR *pFileName, DWORD StartLine = 0, int CharCount=256 );
	static GosFont3D *		(*CreateFromTexture)( GosTexture *pTexture, DWORD StartLine = 0, int CharCount=256 );
	virtual					~GosFont3D(){;}
};

class GosResourceDll
{
public:
	static GosResourceDll *	(*Open)( TCHAR *pFileName );
	virtual 				~GosResourceDll(){;}
	virtual _TCHAR *		GetString( DWORD ID )=0;
	virtual void *			GetData( DWORD ID, _TCHAR *pTypeName, size_t *pSize )=0;
};


class GosFile
{
public:
	static GosFile *		(*Read)( const TCHAR *pFileName, DWORD Offset=0, DWORD MaxSize=0xFFFFFFFF, void *Buffer=NULL );
	static GosFile *		(*Open)( const TCHAR *pFileName );
	virtual void			Write( void *Buffer, DWORD Size )=0;
	static GosFile *		(*BackgroundRead)( const TCHAR *pFileName, DWORD Offset=0, DWORD MaxSize=0xFFFFFFFF, void *Buffer=NULL );
	static GosFile *		(*MemoryMap)( const TCHAR *pFileName );
	static bool				(*Exists)( const TCHAR *pFileName );
	static void				(*Shutdown)();
	static void				(*GetFullPathName)( TCHAR* FullPath, const TCHAR *pFileName );

	virtual					~GosFile(){;}	// free's allocation
	virtual DWORD			Size()=0;
	virtual bool			Ready()=0;
	virtual void *			Data()=0;
};


class GosHeap
{
public:
	static void				(*Initialize)();
	static void				(*Shutdown)();
	static GosHeap *		(*Create)( _TCHAR *pName, DWORD MaxBytes );
	virtual _TCHAR *		Name()=0;
	static void				(*PushCurrent)( GosHeap *pHeap );
	static void				(*PopCurrent)();
	static GosHeap *		(*Current)();
	virtual void *			Malloc( DWORD SizeBytes, const TCHAR *pDescription=NULL )=0;
	static void				(*Free)( void *pData );
	static DWORD			(*GetID)( void *pData );
	virtual void			FreeLocal( void *pData )=0;
	virtual DWORD			GetIDLocal( void *pData )=0;
	virtual void			VerifyEmpty()=0;
};

inline void *GosMalloc( DWORD SizeBytes, GosHeap *pHeap = GosHeap::Current() )
{
	return pHeap->Malloc( SizeBytes );
}

inline void *GosMalloc( DWORD SizeBytes, const TCHAR *pDescription, GosHeap *pHeap = GosHeap::Current() )
{
	return pHeap->Malloc(SizeBytes, pDescription);
}

inline void GosFree( void *pData )
{
	GosHeap::Free(pData);
}

#pragma warning( disable : 4291 )	// disable the message "..no matching operator delete found.."
void* __cdecl operator new (size_t Size);
void* __cdecl operator new (size_t Size, GosHeap *pHeap);
void* __cdecl operator new (size_t Size, const _TCHAR * pDesc);
void* __cdecl operator new (size_t Size, const _TCHAR * pDesc, GosHeap *pHeap);

inline __int64 __declspec(naked) __stdcall GetCPUCycles()
{
	_asm rdtsc;
	_asm ret;
}

class GosUtil
{
public:

	static bool				(*Initialize)();
	static void				(*Shutdown)();

	static DWORD			(*LZCompress)( BYTE *pDest, BYTE *pSrc, DWORD SrcLen );
	static DWORD			(*LZDecompress)( BYTE *pDest, BYTE *pSrc, DWORD SrcLen );

	static int				(*Rand)();

	static _int64			(*Time_uS)(bool Clamp=true);	// time in uS since app was started
	static DWORD			(*Time_mS)(bool Clamp=true);	// time in mS since app was started WRAPS EVERY 46 DAYS!
	static double			(*Time_S)(bool Clamp=true);		// time in S since app was started

	static DWORD			(*GetClipboardText)( TCHAR *Dest, DWORD MaxSize );
	static void				(*SetClipboardText)( TCHAR *Text );
};

class GosUser
{
public:
	enum KeyStatus
	{
		KeyFree,
		KeyPressed,
		KeyHeld,
		KeyReleased
	};

	enum JoystickAxis
	{
		JoyXAxis = 0,
		JoyYAxis = 1,
		JoyZAxis = 2,
		JoyThrottle = 2,
		JoyRXAxis = 3,
		JoyRYAxis = 4,
		JoyRZAxis = 5,
		JoyRudder = 5,
		JoySlider1 = 6,
		JoySlider2 = 7,
		JoyHat1 = 8,
		JoyPov1 = 8,
		JoyHat2 = 9,
		JoyPov2 = 9,
		JoyHat3 = 10,
		JoyPov3 = 10,
		JoyHat4 = 11,
		JoyPov4 = 11,
		JoyMax = 12
	};

	struct JoystickInfo
	{
		const TCHAR*	lpstrName;				// the brand and model name
		DWORD		bAxisValid:JoyMax;		// yes/no bitflags.
		DWORD  		nAxes:4;				// number of availab axes
		DWORD  		nButtons:5;				// number of available buttons
		DWORD  		nSliders:4;				// number of slidesr
		DWORD  		nPOVs:4;				// number of point of view hats
		DWORD  		bIsPolled:1;			// whether or not this stick is polled
		DWORD 		bIsForceFeedback:1;
												// 1 spare bit
	};

	static void				(*Initialize)( HWND hWnd, HINSTANCE hInst );

	// For now, - Poll is called automatically each frame, - just call GetStatus to read
	// the status of the first game controller
	static void				(*GetStatus)( DWORD *pButtons, long *pX, long *pY );
	static void				(*Poll)();
	static void				(*Shutdown)();

	static KeyStatus		(*GetKeyStatus)( int KeyIndex );
	static int				(*GetKey)();
	static float			(*GetAxis)( int Joystick, JoystickAxis Axis );
	static bool				(*GetJoystickButtonStatus)( int Joystick, int Button );
	static void				(*SetJoystickPolling)( int Joystick, bool YesNo, float howOften=0.03333f );
	static void				(*GetJoystickInfo)( int Joystick, JoystickInfo *pInfo );
	static DWORD			(*CountJoysticks)();
	static void				(*KeyboardFlush)();
	static void				(*GetMouseInfo)( float* pXPosition, float* pYPosition, int* pXDelta, int* pYDelta, int* pWheelDelta, DWORD* pButtonsPressed );
	static void				(*SetMouse)( WORD Buttons, WORD X, WORD Y );
};

class GosIME
{
public:
	static DWORD			(*GetStatus)(); // (DWORD)  Bit 0 is true when the IME is open.
	static void				(*SetPosition)(int X, int Y, DWORD BaseColor=0xffffffff, DWORD BorderColor=0xff000000, BYTE SymbolTranslucence=0xA0, BYTE SymbolSize=24, BYTE SymbolPlacement=0, DWORD SymbolColor = 0 );
	static void				(*Display)();
	static void				(*Hide)();
	static void				(*Enable)();
	static void				(*Disable)();
};


//
// To initialize an application, define a class derived from GosApp
// Implement the pure virtual functions, and create a single instance of the class


class GosApp
{
public:
							GosApp();			// constructor which initiates the program
	static GosApp *			(*CurrentApp)();	// returns pointer to registered app
	// Function(s) the app *may* override
	virtual void			PreferredDisplay( int &Windowed, unsigned int &Width, unsigned int &Height, D3DFORMAT &Format );	// Called BEFORE init
	// Functions which the app must provide
	virtual bool			Initialize(_TCHAR* pCommandLine)=0;		// Initialize the application's state
	static  void			(*Body)();			// Default body which simply calls MsgLoop - override in app as reqd
	static  bool			(*MsgLoop)();		// Handles window messages
	virtual bool			Step()=0;			// Move the scene forward one frame
	virtual void			Render()=0;			// Render a single frame
	virtual void			Shutdown()=0;		// Called at game shutdown time
	static void				(*Terminate)();
	virtual	TCHAR			*Name()=0;			// Name of the game
	static DWORD			(*GetStatus)();		// (DWORD)  Bit 0 is true when the app is active, Bit 1 is true when the app has keyboard focus
	static bool				(*RunMainLoop)( void(__stdcall *DoGameLogic)() );
	static bool				(*InternalRunLogic)( void(__stdcall *DoGameLogic)() );
};


class Gos3D
{
public:
	// For use by GOS Framework
	static	bool			(*Initialize)( HWND hWnd );
	static	void			(*Shutdown)();
	static	void			(*Done)();
	// Cursor
	static	HRESULT 		(*SetCursorProperties)( UINT XHotSpot, UINT YHotSpot, GosSurface* pCursorBitmap );
	static	void 			(*SetCursorPosition)( UINT XScreenSpace, UINT YScreenSpace, DWORD Flags );
	static	BOOL 			(*ShowCursor)( BOOL bShow );
	// Display control
	static	void			(*SetDisplay)(UINT width, UINT height, D3DFORMAT format, bool windowed );
	static	DWORD			(*Left)();	// Left screen coord for windor ( 0 for full-screen)
	static	DWORD			(*Top)();	// Top screen coord for window (0 for full-screen)
	static	DWORD			(*Width)(); // Width of window ( or screen )
	static	DWORD			(*Height)();// Height of window ( or screen )
	static	void 			(*SetGammaRamp)( DWORD Flags, D3DGAMMARAMP* pRamp );
	static	void 			(*GetGammaRamp)( D3DGAMMARAMP* pRamp );
	static	HRESULT 		(*GetRasterStatus)( D3DRASTER_STATUS* pRasterStatus );
	// Bltting
	static	HRESULT 		(*CopyRects)( GosSurface* pSourceSurface, RECT* pSourceRectsArray, UINT cRects, GosSurface* pDestinationSurface, POINT* pDestPointsArray );
	static	HRESULT 		(*GetFrontBuffer)( GosSurface* pDestSurface );
	// Begin/Clear/End Scene, RenderTarget
	static	HRESULT 		(*BeginScene)();
	static	HRESULT 		(*EndScene)();
	static	HRESULT 		(*Clear)( DWORD Count, D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil );
	static	HRESULT 		(*SetRenderTarget)( GosSurface* pRenderTarget, GosSurface* pNewZStencil );
	static	HRESULT 		(*GetRenderTarget)( GosSurface** ppRenderTarget );
	static	HRESULT 		(*GetDepthStencilSurface)( GosSurface** ppZStencilSurface );
	// Geometry
	static	HRESULT 		(*SetTransform)( D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix );
	static	HRESULT 		(*GetTransform)( D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix );
	static	HRESULT 		(*MultiplyTransform)( D3DTRANSFORMSTATETYPE State, D3DMATRIX* pMatrix );
	// Lights & Materials
	static	HRESULT 		(*SetMaterial)( D3DMATERIAL8* pMaterial );
	static	HRESULT 		(*GetMaterial)( D3DMATERIAL8* pMaterial );
	static	HRESULT 		(*SetLight)( DWORD Index, D3DLIGHT8* pLight );
	static	HRESULT 		(*GetLight)( DWORD Index, D3DLIGHT8* pLight );
	static	HRESULT 		(*LightEnable)( DWORD Index, BOOL Enable );
	static	HRESULT 		(*GetLightEnable)( DWORD Index, BOOL* pEnable );
	// Render States
	static	HRESULT 		(*SetRenderState)( D3DRENDERSTATETYPE State, DWORD Value );
	static	HRESULT 		(*GetRenderState)( D3DRENDERSTATETYPE State, DWORD* pValue );
	static	HRESULT			(*ApplyStateBlock)( GosStateBlock *pBlock );
	// Clipping & Viewport
	static	HRESULT 		(*SetClipPlane)( DWORD Index, float* pPlane );
	static	HRESULT 		(*GetClipPlane)( DWORD Index, float* pPlane );
	static	HRESULT 		(*SetClipStatus)( D3DCLIPSTATUS8* pClipStatus );
	static	HRESULT 		(*GetClipStatus)( D3DCLIPSTATUS8* pClipStatus );
	static	HRESULT 		(*SetViewport)( D3DVIEWPORT8* pViewport );
	static	HRESULT 		(*GetViewport)( D3DVIEWPORT8* pViewport );
	// Texturing
	static	HRESULT 		(*SetTexture)( DWORD Stage, GosTexture* pTexture );
	static	HRESULT 		(*GetTexture)( DWORD Stage, GosTexture** ppTexture );
	static	HRESULT 		(*SetTextureStageState)( DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value );
	static	HRESULT 		(*GetTextureStageState)( DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD* pValue );
	// Palettes
	static	HRESULT 		(*SetPaletteEntries)( UINT PaletteNumber, PALETTEENTRY* pEntries );
	static	HRESULT 		(*GetPaletteEntries)( UINT PaletteNumber, PALETTEENTRY* pEntries );
	static	HRESULT 		(*SetCurrentTexturePalette)( UINT PaletteNumber );
	static	HRESULT 		(*GetCurrentTexturePalette)( UINT *PaletteNumber );
	// Vertex & Index Buffers
	static	HRESULT 		(*SetStreamSource)( UINT StreamNumber, GosVertexBuffer* pStreamData, UINT Stride );
	static	HRESULT 		(*GetStreamSource)( UINT StreamNumber, GosVertexBuffer** ppStreamData, UINT* pStride );
	static	HRESULT 		(*SetIndices)( GosIndexBuffer* pIndexData, UINT BaseVertexIndex );
	static	HRESULT 		(*GetIndices)( GosIndexBuffer** ppIndexData, UINT* pBaseVertexIndex );
	// Rendering
	static	HRESULT 		(*DrawPrimitive)( D3DPRIMITIVETYPE PrimitiveType, UINT StartVertex, UINT PrimitiveCount );
	static	HRESULT 		(*DrawIndexedPrimitive)( D3DPRIMITIVETYPE PrimitiveType, UINT minIndex, UINT NumIndices, UINT startIndex, UINT primCount );
	static	HRESULT 		(*DrawPrimitiveUP)( D3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, void* pVertexStreamZeroData, UINT VertexStreamZeroStride );
	static	HRESULT 		(*DrawQuadUP)( UINT PrimitiveCount, void* pVertexStreamZeroData, UINT VertexStreamZeroStride );
	static	HRESULT 		(*DrawIndexedPrimitiveUP)( D3DPRIMITIVETYPE PrimitiveType, UINT MinVertexIndex, UINT NumVertexIndices, UINT PrimitiveCount, void* pIndexData, D3DFORMAT IndexDataFormat, void* pVertexStreamZeroData, UINT VertexStreamZeroStride );
	static	HRESULT 		(*ProcessVertices)( UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, GosVertexBuffer* pDestBuffer, DWORD Flags );
	// Vertex Shaders
	static	HRESULT			(*SetFVFShader)( DWORD vertexFormat );
	static	HRESULT 		(*SetVertexShader)( GosVertexShader *pVertexShader );
	static	HRESULT 		(*GetVertexShader)( GosVertexShader **ppVertexShader );
	static	HRESULT 		(*SetVertexShaderConstant)( DWORD Register, void* pConstantData, DWORD ConstantCount );
	static	HRESULT 		(*GetVertexShaderConstant)( DWORD Register, void* pConstantData, DWORD ConstantCount );
	// Pixel Shaders
	static	HRESULT 		(*SetPixelShader)( GosPixelShader *pPixelShader );
	static	HRESULT 		(*GetPixelShader)( GosPixelShader **ppPixelShader );
	static	HRESULT 		(*SetPixelShaderConstant)( DWORD Register, void* pConstantData, DWORD ConstantCount );
	static	HRESULT 		(*GetPixelShaderConstant)( DWORD Register, void* pConstantData, DWORD ConstantCount );
	// High-Order Surfaces
	static	HRESULT 		(*DrawRectPatch)( UINT Handle, float* pNumSegs, D3DRECTPATCH_INFO* pSurf );
	static	HRESULT 		(*DrawTriPatch)( UINT Handle, float* pNumSegs, D3DTRIPATCH_INFO* pSurf );
	// Misc
	static  DWORD			TextureOffset() { return 0; }
	static  void			(*SetupViewport)( bool FillZ, float ZBuffer, bool FillBG, DWORD BGColor, float top, float left, float bottom, float right, bool ClearStencil=0, DWORD StencilValue=0 );
};

class GosSurface
{
public:
	static	GosSurface*		(*CreateEmpty)( UINT Width, UINT Height, D3DFORMAT Format );
	static	GosSurface*		(*CreateEmptyDepthStencil)( UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample );
	static	GosSurface*		(*CreateRenderTarget)( UINT Width, UINT Height, D3DFORMAT Format, D3DMULTISAMPLE_TYPE MultiSample, BOOL Lockable );
    virtual HRESULT         Desc( D3DSURFACE_DESC *pDesc )=0;
	virtual HRESULT			LoadFromFile( TCHAR *pName )=0;
	virtual HRESULT			Lock( D3DLOCKED_RECT *pLockedRect, RECT *pRect=NULL )=0;
	virtual HRESULT			Unlock()=0;
	virtual					~GosSurface();
};

class GosTexture
{
public:
	// Standard Textures
	// the following is a temporary workaround for a compiler bug . should be D3DFORMAT Format = D3DFMT_UNKNOWN );
	static	GosTexture*		(*CreateFromFile)( TCHAR *pFileName , bool CreateMip=true , /* D3DFORMAT */ int Format=0   );
	static	GosTexture*		(*CreateFromMemory)( LPCVOID pSrcData, UINT SrcDataSize, bool CreateMip , /* D3DFORMAT */ int Format=0, int Pool=0 );
	static	GosTexture*		(*CreateEmpty)( UINT Width, UINT Height, UINT Levels, D3DFORMAT Format, D3DPOOL Pool, const TCHAR *pName=NULL, bool fUse3D=false );
	virtual HRESULT			Lock( D3DLOCKED_RECT *pLockedRect, UINT Level=0, RECT *pRect=NULL )=0;
	virtual GosSurface*		LevelSurface( UINT Level=0 )=0;		// yields the GosSurface for a level of a mipmap
    virtual HRESULT         LevelDesc( D3DSURFACE_DESC *pDesc, UINT Level=0 )=0;

	// Volume Textures
	static	GosTexture*		(*CreateVolume)( UINT Width, UINT Height, UINT Depth, UINT Levels, D3DFORMAT Format );
	virtual HRESULT			Lock( D3DLOCKED_BOX *pLockedBox, UINT Level=0, D3DBOX *pBox=NULL )=0;
	// Cube Textures
	static	GosTexture*		(*CreateCube)( UINT EdgeLength, UINT Levels, D3DFORMAT Format );
	static	HRESULT			Lock( D3DLOCKED_RECT *pLockedRect, D3DCUBEMAP_FACES Face, UINT Level=0, RECT *pRect = NULL );
	// All Textures
	virtual void			SetName( const TCHAR *pName )=0;
	virtual HRESULT			Unlock( UINT Level=0, D3DCUBEMAP_FACES Face=D3DCUBEMAP_FACE_POSITIVE_X )=0;
	virtual HRESULT 		Update( GosTexture* pSourceTexture )=0;
	virtual					~GosTexture();
	virtual bool			HasAlpha()=0;
};

class GosVertexBuffer
{
public:
	static	GosVertexBuffer*(*CreateEmpty)(UINT Length, DWORD FVF, DWORD Usage);
	static	GosVertexBuffer*(*CreateFromMemory)(void *pData,UINT Length, DWORD FVF, DWORD Usage);
	virtual void *			Lock( DWORD Usage=0 )=0;
	virtual void			Unlock()=0;
	virtual					~GosVertexBuffer();
};

class GosIndexBuffer
{
public:
	static	GosIndexBuffer*	(*CreateEmpty)(UINT Length, DWORD Usage, D3DFORMAT Format);
	static	GosIndexBuffer*	(*CreateFromMemory)(void *pData,UINT Length, DWORD Usage, D3DFORMAT Format);
	virtual void *			Lock()=0;
	virtual void			Unlock()=0;
	virtual					~GosIndexBuffer();
};

class GosPixelShader
{
public:
	static	GosPixelShader*	(*CreateFromMemory)(DWORD *pFunction );
	virtual DWORD			GetFunction( DWORD *pBuffer )=0;
	virtual					~GosPixelShader();
};

class GosVertexShader
{
public:
	static	GosVertexShader*(*CreateFromMemory)(DWORD *pDeclaration, DWORD *pFunction=NULL);
	virtual DWORD			GetDeclaration( DWORD *pBuffer )=0;
	virtual DWORD			GetFunction( DWORD *pBuffer )=0;
	virtual					~GosVertexShader();
};

class GosStateBlock
{
public:
	static	GosStateBlock*	(*CreateCurrent)( bool GetPixelState, bool GetVertexState );
	static	GosStateBlock*	(*CreateRecording)();
	virtual void			EndRecording()=0;
	virtual void			Update()=0;
	virtual					~GosStateBlock();
};


class GosDebug
{
public:
	enum GosErrorID
	{
		ErrorNoContinue		=1,		// No CONTINUE is allowed from errors
		ErrorNoRegisters	=2,		// Register are not valid (takes address from where called)
		ErrorAssert			=4,		// Set to signify assert ( assumes gos_ErrorNoRegisters )
		ErrorVerify			=8,		// Set to signify verify ( assumes gos_ErrorNoRegisters )
		ErrorException		=16,	// Set to signify exception handler
		ErrorDump			=32,	// ErrorTitle must be valid
		ErrorPop			=64,	// Pop one more level of stack
		ErrorPop2			=128,	// Pop two more levels of stack
		ErrorStop			=256,	// Stop - display message
		ErrorMessage		=512,	// Display message without a STOP: or Verify:
		ErrorFileLine		=1024,	// Global variables gosErrorFile and gosErrorLine contain line to display (Pass a COMPLETE path\file name)
		ErrorRetry			=2048,	// Retry instead of continue button
		ErrorGameInfoFirst	=4096,	// Show the information from GetGameInformation routine immediately after File/Line information
		ErrorAppendRoutine	=8192	// append ' in Routine()+xxx' to the error  (or address if no symbols)
	};
	static int				(*HandleError)( int Flags, TCHAR *Text );
	static DWORD			s_ErrorLine;
	static TCHAR *			s_pErrorFileName;

	static bool *			(*Cat)( _TCHAR *pCategoryName );
	static void				(*EnableCat)( bool *pCat );
	static void				(*DisableCat)( bool *pCat );
	static void				(*Output)( _TCHAR *pFmt,... );
	static void				(*OutputV)( _TCHAR *pFmt, va_list arglist );
};

///////////////////////////////////////////////////////////////////////////////
///////////////////////////// EVENT LOGGING MACROS ////////////////////////////
///////////////////////////////////////////////////////////////////////////////

#ifdef LAB_ONLY		// debug, armor, or profile

#define LOG_REF(refobj,reftype,refname) static GosLogRef refobj(GosLogRef::reftype,refname,__FILE__,__LINE__)
#define LOG_BLOCK(funcname)											\
LOG_REF(gosLogFuncRef,logEnter,funcname);							\
GosLogFuncScope gosLogFuncScope( gosLogFuncRef );

#define LOG_START_CHECK												\
GosEventLog::LogStartPoint();

#else	// retail
#define LOG_BLOCK(funcname)												
#define LOG_START_CHECK {;}
#endif

///////////////////////////////////////////////////////////////////////////////
///////////////////////// CLASSES FOR GOS MACRO USE ONLY //////////////////////
///////////////////////////////////////////////////////////////////////////////


class GosLogRef
{
	unsigned long	m_Count;
	///void			(*m_pFunc)(GosLogRef &);
	///void			*m_pObj;
	DWORD			m_id;
public:

	enum EventType
	{
		logEnter = 0,	// return must be 1 more than enter
		logReturn = 1,
		logCount,
		logLevel,
		logAlloc,
		logFree,
		logNew,
		logDelete,
		log,
	};
	GosLogRef( EventType type, char *name, char *filename, int lineno );
	operator DWORD() { return m_id; }
	bool ShouldLog() {  m_Count++; return true; }	// change to return (m_pFunc != NULL);
};


class GosEventLog
{
	static DWORD		*pLogBase;
	static DWORD		LogOffset;		// Offset into log in DWORDS
	static DWORD		LogMod;			// Mod in DWORDS
	static DWORD		NullLog[16];
	static bool			WaitingToStart;
	static bool			LoggingInProgress;

	// after stopping, the following members point to the frozen log
	static char *		m_pLogStart1;
	static DWORD		m_nLogSize1;	// size of first part in bytes
	static char *		m_pLogStart2;
	static DWORD		m_nLogSize2;	// size of second part in bytes

public:
	static void Log( DWORD id )
	{
		unsigned long time;
		LogOffset &= LogMod;
		pLogBase[LogOffset++] = id;
		_asm rdtsc
		_asm mov time,eax
		pLogBase[LogOffset++] = time;
	}
	static void LogStart();
	static void LogStartPoint();
	static void LogStop();
	static void PushStop();
	static void PopStop();
	static char *LogAddr( int part ) { return part?m_pLogStart2:m_pLogStart1; }
	static DWORD LogBytes( int part ) { return part?m_nLogSize2:m_nLogSize1; }
	static bool Logging() { return LoggingInProgress; }
	static void Cleanup();
};

class GosLogFuncScope
{
private:
	DWORD		 m_Caller;
	static DWORD Current;
public:
	GosLogFuncScope( DWORD newId )
	{
		m_Caller = Current;
		GosEventLog::Log(newId);
		Current = newId+0x00100000;	// so future logs will be the *return* to this function scope
	}
	~GosLogFuncScope()
	{
		if( m_Caller )
		{
			Current = m_Caller;
			GosEventLog::Log(Current);	// i.e. log the return to the function
		}
	}
};
