//=================================================================
//
// Copyright (c) Microsoft Corporation 1999 - All Rights Reserved.
//
//=================================================================

#pragma once

class CDirectDraw;
class CDirectDrawSurface;

//========================================================================
// CDirectDraw
//========================================================================
#ifdef USE_DX7_INTERFACE
class CDirectDraw : public IDirectDraw, public IDirectDraw4, public IDirectDraw7, public IDirect3D, public IDirect3D3, public IDirect3D7
#else
class CDirectDraw : public IDirectDraw, public IDirectDraw4, public IDirect3D, public IDirect3D3
#endif
{
	friend HRESULT WINAPI DirectDrawCreate( GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter );
	friend HRESULT WINAPI DirectDrawCreateEx( GUID FAR *lpGUID, LPVOID *lplpDD, REFIID iid, IUnknown FAR *pUnkOuter );
	friend class CDirectDrawSurface;

public:
    /*** IUnknown methods ***/
    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj);
    STDMETHOD_(ULONG,AddRef) (THIS) ;
    STDMETHOD_(ULONG,Release) (THIS);
    /*** IDirectDraw methods ***/
    STDMETHOD(Compact)(THIS);
    STDMETHOD(CreateClipper)(THIS_ DWORD, LPDIRECTDRAWCLIPPER FAR*, IUnknown FAR * );
    STDMETHOD(CreatePalette)(THIS_ DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE FAR*, IUnknown FAR * );
    STDMETHOD(CreateSurface)(THIS_  LPDDSURFACEDESC, LPDIRECTDRAWSURFACE FAR *, IUnknown FAR *);
    STDMETHOD(DuplicateSurface)( THIS_ LPDIRECTDRAWSURFACE, LPDIRECTDRAWSURFACE FAR * );
    STDMETHOD(EnumDisplayModes)( THIS_ DWORD, LPDDSURFACEDESC, LPVOID, LPDDENUMMODESCALLBACK );
    STDMETHOD(EnumSurfaces)(THIS_ DWORD, LPDDSURFACEDESC, LPVOID,LPDDENUMSURFACESCALLBACK );
    STDMETHOD(FlipToGDISurface)(THIS);
    STDMETHOD(GetCaps)( THIS_ LPDDCAPS, LPDDCAPS);
    STDMETHOD(GetDisplayMode)( THIS_ LPDDSURFACEDESC);
    STDMETHOD(GetFourCCCodes)(THIS_  LPDWORD, LPDWORD );
    STDMETHOD(GetGDISurface)(THIS_ LPDIRECTDRAWSURFACE FAR *);
    STDMETHOD(GetMonitorFrequency)(THIS_ LPDWORD);
    STDMETHOD(GetScanLine)(THIS_ LPDWORD);
    STDMETHOD(GetVerticalBlankStatus)(THIS_ LPBOOL );
    STDMETHOD(Initialize)(THIS_ GUID FAR *);
    STDMETHOD(RestoreDisplayMode)(THIS);
    STDMETHOD(SetCooperativeLevel)(THIS_ HWND, DWORD);
    STDMETHOD(SetDisplayMode)(THIS_ DWORD, DWORD,DWORD);
    STDMETHOD(WaitForVerticalBlank)(THIS_ DWORD, HANDLE );



    /*** Changed V1 methods in the V4 interface ***/
    STDMETHOD(CreateSurface)(THIS_  LPDDSURFACEDESC2, LPDIRECTDRAWSURFACE4 FAR *, IUnknown FAR *);
    STDMETHOD(DuplicateSurface)( THIS_ LPDIRECTDRAWSURFACE4, LPDIRECTDRAWSURFACE4 FAR * );
    STDMETHOD(EnumDisplayModes)( THIS_ DWORD, LPDDSURFACEDESC2, LPVOID, LPDDENUMMODESCALLBACK2 );
    STDMETHOD(EnumSurfaces)(THIS_ DWORD, LPDDSURFACEDESC2, LPVOID,LPDDENUMSURFACESCALLBACK2 );
    STDMETHOD(GetDisplayMode)( THIS_ LPDDSURFACEDESC2);
    STDMETHOD(GetGDISurface)(THIS_ LPDIRECTDRAWSURFACE4 FAR *);
    STDMETHOD(SetDisplayMode)(THIS_ DWORD, DWORD,DWORD, DWORD, DWORD);

    /*** Added in the v2 interface ***/
    STDMETHOD(GetAvailableVidMem)(THIS_ LPDDSCAPS2, LPDWORD, LPDWORD);

    /*** Added in the V4 Interface ***/
    STDMETHOD(GetSurfaceFromDC) (THIS_ HDC, LPDIRECTDRAWSURFACE4 *);
    STDMETHOD(RestoreAllSurfaces)(THIS);
    STDMETHOD(TestCooperativeLevel)(THIS);
    STDMETHOD(GetDeviceIdentifier)(THIS_ LPDDDEVICEIDENTIFIER, DWORD );

#ifdef USE_DX7_INTERFACE
    /*** Added in the V7 Interface ***/
    STDMETHOD(CreateSurface)(THIS_  LPDDSURFACEDESC2, LPDIRECTDRAWSURFACE7 FAR *, IUnknown FAR *);
    STDMETHOD(DuplicateSurface)( THIS_ LPDIRECTDRAWSURFACE7, LPDIRECTDRAWSURFACE7 FAR * );
    STDMETHOD(EnumSurfaces)(THIS_ DWORD, LPDDSURFACEDESC2, LPVOID,LPDDENUMSURFACESCALLBACK7 );
    STDMETHOD(GetGDISurface)(THIS_ LPDIRECTDRAWSURFACE7 FAR *);
    STDMETHOD(GetSurfaceFromDC) (THIS_ HDC, LPDIRECTDRAWSURFACE7 *);
    STDMETHOD(GetDeviceIdentifier)(THIS_ LPDDDEVICEIDENTIFIER2, DWORD );
    STDMETHOD(StartModeTest)(THIS_ LPSIZE, DWORD, DWORD );
    STDMETHOD(EvaluateMode)(THIS_ DWORD, DWORD * );
#endif


    /*** IDirect3D methods ***/
    STDMETHOD(Initialize)(THIS_ REFCLSID);
    STDMETHOD(EnumDevices)(THIS_ LPD3DENUMDEVICESCALLBACK,LPVOID);
    STDMETHOD(CreateLight)(THIS_ LPDIRECT3DLIGHT*,IUnknown*);
    STDMETHOD(CreateMaterial)(THIS_ LPDIRECT3DMATERIAL*,IUnknown*);
    STDMETHOD(CreateViewport)(THIS_ LPDIRECT3DVIEWPORT*,IUnknown*);
    STDMETHOD(FindDevice)(THIS_ LPD3DFINDDEVICESEARCH,LPD3DFINDDEVICERESULT);

    /*** IDirect3D3 methods ***/
    STDMETHOD(CreateMaterial)(THIS_ LPDIRECT3DMATERIAL3*,LPUNKNOWN);
    STDMETHOD(CreateViewport)(THIS_ LPDIRECT3DVIEWPORT3*,LPUNKNOWN);
    STDMETHOD(CreateDevice)(THIS_ REFCLSID,LPDIRECTDRAWSURFACE4,LPDIRECT3DDEVICE3*,LPUNKNOWN);
    STDMETHOD(CreateVertexBuffer)(THIS_ LPD3DVERTEXBUFFERDESC,LPDIRECT3DVERTEXBUFFER*,DWORD,LPUNKNOWN);
    STDMETHOD(EnumZBufferFormats)(THIS_ REFCLSID,LPD3DENUMPIXELFORMATSCALLBACK,LPVOID);
    STDMETHOD(EvictManagedTextures)(THIS);

#ifdef USE_DX7_INTERFACE
    /*** IDirect3D7 methods ***/
    STDMETHOD(EnumDevices)(THIS_ LPD3DENUMDEVICESCALLBACK7,LPVOID);
    STDMETHOD(CreateDevice)(THIS_ REFCLSID,LPDIRECTDRAWSURFACE7,LPDIRECT3DDEVICE7*);
    STDMETHOD(CreateVertexBuffer)(THIS_ LPD3DVERTEXBUFFERDESC,LPDIRECT3DVERTEXBUFFER7*,DWORD);
#endif


	CDirectDraw() :
		m_cRef(0),
		m_pDirectDraw(NULL),
		m_pDirectDraw4(NULL),
		m_pDirect3D(NULL),
		m_pDirect3D3(NULL),
		m_pFirstSurface(NULL)
		{;}
	~CDirectDraw() {;}

	int GetDirectXBaseObjectRefCount(void)
	{
		m_pDirectDraw->AddRef();
		return m_pDirectDraw->Release();
	}


private:
	int						m_cRef;
	bool					m_bUseBlade;
	IDirectDraw *			m_pDirectDraw;
	IDirect3D *				m_pDirect3D;
#ifdef USE_DX7_INTERFACE
	IDirectDraw7 *			m_pDirectDraw4;
	IDirect3D7 *			m_pDirect3D3;
#else
	IDirectDraw4 *			m_pDirectDraw4;
	IDirect3D3 *			m_pDirect3D3;
#endif

	//
	// surface linked list
	//
	CDirectDrawSurface *	m_pFirstSurface;

	CDirectDrawSurface *	FindSurface(IDirectDrawSurface *);
	HRESULT AddSurfaceToList(CDirectDrawSurface *);
	HRESULT RemoveSurfaceFromList(CDirectDrawSurface *);

};



//========================================================================
// CDirectDrawSurface
//========================================================================
#ifdef USE_DX7_INTERFACE
class CDirectDrawSurface : public IDirectDrawSurface, public IDirectDrawSurface2, public IDirectDrawSurface4, public IDirectDrawSurface7, public IDirect3DTexture2
#else
class CDirectDrawSurface : public IDirectDrawSurface, public IDirectDrawSurface2, public IDirectDrawSurface4, public IDirect3DTexture2
#endif
{
	friend class CDirectDraw;

public:
    /*** IUnknown methods ***/
    STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj);
    STDMETHOD_(ULONG,AddRef) (THIS) ;
    STDMETHOD_(ULONG,Release) (THIS);

    /*** IDirectDrawSurface methods ***/
    STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE);
    STDMETHOD(AddOverlayDirtyRect)(THIS_ LPRECT);
    STDMETHOD(Blt)(THIS_ LPRECT,LPDIRECTDRAWSURFACE, LPRECT,DWORD, LPDDBLTFX);
    STDMETHOD(BltBatch)(THIS_ LPDDBLTBATCH, DWORD, DWORD );
    STDMETHOD(BltFast)(THIS_ DWORD,DWORD,LPDIRECTDRAWSURFACE, LPRECT,DWORD);
    STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD,LPDIRECTDRAWSURFACE);
    STDMETHOD(EnumAttachedSurfaces)(THIS_ LPVOID,LPDDENUMSURFACESCALLBACK);
    STDMETHOD(EnumOverlayZOrders)(THIS_ DWORD,LPVOID,LPDDENUMSURFACESCALLBACK);
    STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE, DWORD);
    STDMETHOD(GetAttachedSurface)(THIS_ LPDDSCAPS, LPDIRECTDRAWSURFACE FAR *);
    STDMETHOD(GetBltStatus)(THIS_ DWORD);
    STDMETHOD(GetCaps)(THIS_ LPDDSCAPS);
    STDMETHOD(GetClipper)(THIS_ LPDIRECTDRAWCLIPPER FAR*);
    STDMETHOD(GetColorKey)(THIS_ DWORD, LPDDCOLORKEY);
    STDMETHOD(GetDC)(THIS_ HDC FAR *);
    STDMETHOD(GetFlipStatus)(THIS_ DWORD);
    STDMETHOD(GetOverlayPosition)(THIS_ LPLONG, LPLONG );
    STDMETHOD(GetPalette)(THIS_ LPDIRECTDRAWPALETTE FAR*);
    STDMETHOD(GetPixelFormat)(THIS_ LPDDPIXELFORMAT);
    STDMETHOD(GetSurfaceDesc)(THIS_ LPDDSURFACEDESC);
    STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW, LPDDSURFACEDESC);
    STDMETHOD(IsLost)(THIS);
    STDMETHOD(Lock)(THIS_ LPRECT,LPDDSURFACEDESC,DWORD,HANDLE);
    STDMETHOD(ReleaseDC)(THIS_ HDC);
    STDMETHOD(Restore)(THIS);
    STDMETHOD(SetClipper)(THIS_ LPDIRECTDRAWCLIPPER);
    STDMETHOD(SetColorKey)(THIS_ DWORD, LPDDCOLORKEY);
    STDMETHOD(SetOverlayPosition)(THIS_ LONG, LONG );
    STDMETHOD(SetPalette)(THIS_ LPDIRECTDRAWPALETTE);
    STDMETHOD(Unlock)(THIS_ LPVOID);
    STDMETHOD(UpdateOverlay)(THIS_ LPRECT, LPDIRECTDRAWSURFACE,LPRECT,DWORD, LPDDOVERLAYFX);
    STDMETHOD(UpdateOverlayDisplay)(THIS_ DWORD);
    STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD, LPDIRECTDRAWSURFACE);

    /*** IDirectDrawSurface2 methods ***/
    STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE2);
    STDMETHOD(Blt)(THIS_ LPRECT,LPDIRECTDRAWSURFACE2, LPRECT,DWORD, LPDDBLTFX);
    STDMETHOD(BltFast)(THIS_ DWORD,DWORD,LPDIRECTDRAWSURFACE2, LPRECT,DWORD);
    STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD,LPDIRECTDRAWSURFACE2);
    STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE2, DWORD);
    STDMETHOD(GetAttachedSurface)(THIS_ LPDDSCAPS, LPDIRECTDRAWSURFACE2 FAR *);
    STDMETHOD(UpdateOverlay)(THIS_ LPRECT, LPDIRECTDRAWSURFACE2,LPRECT,DWORD, LPDDOVERLAYFX);
    STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD, LPDIRECTDRAWSURFACE2);

    /*** IDirectDrawSurface4 methods ***/
    STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE4);
    STDMETHOD(Blt)(THIS_ LPRECT,LPDIRECTDRAWSURFACE4, LPRECT,DWORD, LPDDBLTFX);
    STDMETHOD(BltFast)(THIS_ DWORD,DWORD,LPDIRECTDRAWSURFACE4, LPRECT,DWORD);
    STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD,LPDIRECTDRAWSURFACE4);
    STDMETHOD(EnumAttachedSurfaces)(THIS_ LPVOID,LPDDENUMSURFACESCALLBACK2);
    STDMETHOD(EnumOverlayZOrders)(THIS_ DWORD,LPVOID,LPDDENUMSURFACESCALLBACK2);
    STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE4, DWORD);
    STDMETHOD(GetAttachedSurface)(THIS_ LPDDSCAPS2, LPDIRECTDRAWSURFACE4 FAR *);
    STDMETHOD(GetCaps)(THIS_ LPDDSCAPS2);
    STDMETHOD(GetSurfaceDesc)(THIS_ LPDDSURFACEDESC2);
    STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW, LPDDSURFACEDESC2);
    STDMETHOD(Lock)(THIS_ LPRECT,LPDDSURFACEDESC2,DWORD,HANDLE);
    STDMETHOD(Unlock)(THIS_ LPRECT);
    STDMETHOD(UpdateOverlay)(THIS_ LPRECT, LPDIRECTDRAWSURFACE4,LPRECT,DWORD, LPDDOVERLAYFX);
    STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD, LPDIRECTDRAWSURFACE4);
    /*** Added in the v2 interface ***/
    STDMETHOD(GetDDInterface)(THIS_ LPVOID FAR *);
    STDMETHOD(PageLock)(THIS_ DWORD);
    STDMETHOD(PageUnlock)(THIS_ DWORD);
    /*** Added in the v3 interface ***/
    STDMETHOD(SetSurfaceDesc)(THIS_ LPDDSURFACEDESC2, DWORD);
    /*** Added in the v4 interface ***/
    STDMETHOD(SetPrivateData)(THIS_ REFGUID, LPVOID, DWORD, DWORD);
    STDMETHOD(GetPrivateData)(THIS_ REFGUID, LPVOID, LPDWORD);
    STDMETHOD(FreePrivateData)(THIS_ REFGUID);
    STDMETHOD(GetUniquenessValue)(THIS_ LPDWORD);
    STDMETHOD(ChangeUniquenessValue)(THIS);

#ifdef USE_DX7_INTERFACE
    /*** Added in the v7 interface ***/
    STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE7);
    STDMETHOD(Blt)(THIS_ LPRECT,LPDIRECTDRAWSURFACE7, LPRECT,DWORD, LPDDBLTFX);
    STDMETHOD(BltFast)(THIS_ DWORD,DWORD,LPDIRECTDRAWSURFACE7, LPRECT,DWORD);
    STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD,LPDIRECTDRAWSURFACE7);
    STDMETHOD(EnumAttachedSurfaces)(THIS_ LPVOID,LPDDENUMSURFACESCALLBACK7);
    STDMETHOD(EnumOverlayZOrders)(THIS_ DWORD,LPVOID,LPDDENUMSURFACESCALLBACK7);
    STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE7, DWORD);
    STDMETHOD(GetAttachedSurface)(THIS_ LPDDSCAPS2, LPDIRECTDRAWSURFACE7 FAR *);
    STDMETHOD(UpdateOverlay)(THIS_ LPRECT, LPDIRECTDRAWSURFACE7,LPRECT,DWORD, LPDDOVERLAYFX);
    STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD, LPDIRECTDRAWSURFACE7);
    /*** Moved Texture7 methods here ***/
    STDMETHOD(SetPriority)(THIS_ DWORD);
    STDMETHOD(GetPriority)(THIS_ LPDWORD);
    STDMETHOD(SetLOD)(THIS_ DWORD);
    STDMETHOD(GetLOD)(THIS_ LPDWORD);
#endif

    /*** IDirect3DTexture2 methods ***/
    STDMETHOD(GetHandle)(THIS_ LPDIRECT3DDEVICE2,LPD3DTEXTUREHANDLE);
    STDMETHOD(PaletteChanged)(THIS_ DWORD,DWORD);
    STDMETHOD(Load)(THIS_ LPDIRECT3DTEXTURE2);
#ifdef _DEBUG
	int GetDirectXBaseObjectRefCount(void)
	{
		if (m_cRef)
		{
			m_pDirectDrawSurface->AddRef();
			int cRef=m_pDirectDrawSurface->Release();
			ASSERT(cRef == m_cRef);
			return cRef;
		}
		else
			return 0;
	}
#endif

private:
	CDirectDrawSurface() :
		m_pDirectDrawSurface(NULL),
		m_cRef(0),
		m_pDirectDraw(NULL),
		m_pNextSurface(NULL),
		m_pZBuffer(NULL),
		m_bZBuffer(false)
	{
	}

	~CDirectDrawSurface() {;}

	HRESULT CreateSurface(CDirectDraw *, DDSURFACEDESC *);
	HRESULT CreateSurface(CDirectDraw *, DDSURFACEDESC2 *);


	int						m_cRef;
	IDirectDrawSurface *	m_pDirectDrawSurface;
	CDirectDraw *			m_pDirectDraw;
	CDirectDrawSurface *	m_pNextSurface;
	CDirectDrawSurface *	m_pZBuffer; 		// attached zbuffer
	bool					m_bZBuffer:1;		// this surface is a z buffer
};
