// DirectDrawHook.h : Declaration of the CDirectDrawHook

#ifndef __DIRECTDRAWHOOK_H_
#define __DIRECTDRAWHOOK_H_

#include "resource.h"       // main symbols

#include "Direct3DHook.h"

/////////////////////////////////////////////////////////////////////////////
// CDirectDrawHook
class ATL_NO_VTABLE CDirectDrawHook : 
	public CComObjectRootEx<CComMultiThreadModel>,
   public IDirectDraw,
   public IDirectDraw2,
   public IDirectDraw4,
   public IDirect3D,
   public IDirect3D2,
   public IDirect3D3
{
public:
	CDirectDrawHook()
      : m_pDevice2( NULL ),
      m_pDevice3( NULL ), m_nSurfaceCount( 0 )
	{
	}

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CDirectDrawHook)
   COM_INTERFACE_ENTRY_IID(IID_IDirectDraw, IDirectDraw)
   COM_INTERFACE_ENTRY_IID(IID_IDirectDraw2, IDirectDraw2)
   COM_INTERFACE_ENTRY_IID(IID_IDirectDraw4, IDirectDraw4)
   COM_INTERFACE_ENTRY_IID(IID_IDirect3D, IDirect3D)
   COM_INTERFACE_ENTRY_IID(IID_IDirect3D2, IDirect3D2)
   COM_INTERFACE_ENTRY_IID(IID_IDirect3D3, IDirect3D3)
END_COM_MAP()

   void setObject( IDirectDraw *pDD );

   CComPtr< IDirectDraw > m_pDD;
   CComPtr< IDirectDraw2 > m_pDD2;
   CComPtr< IDirectDraw4 > m_pDD4;

   CComPtr< IDirect3D > m_pD3D;
   CComPtr< IDirect3D2 > m_pD3D2;
   CComPtr< IDirect3D3 > m_pD3D3;

   IDirect3DDevice2 *m_pDevice2;
   IDirect3DDevice3 *m_pDevice3;
   IDirectDrawSurface4 *m_pPrimary;

   long m_nSurfaceCount;

public:

   // IDirectDraw Methods
    STDMETHOD(Compact)()
    {
       return m_pDD->Compact();
    }

    STDMETHOD(CreateClipper)(DWORD p1, LPDIRECTDRAWCLIPPER FAR *p2, IUnknown FAR *p3 )
    {
       return m_pDD->CreateClipper( p1, p2, p3 );
    }

    STDMETHOD(CreatePalette)(DWORD p1, LPPALETTEENTRY p2, LPDIRECTDRAWPALETTE FAR*p3, IUnknown FAR *p4 )
    {
       return m_pDD->CreatePalette( p1, p2, p3, p4 );
    }

    STDMETHOD(CreateSurface)(LPDDSURFACEDESC p1, LPDIRECTDRAWSURFACE FAR *p2, IUnknown FAR *p3 )
    {
       return m_pDD->CreateSurface( p1, p2, p3 );
    }

    STDMETHOD(DuplicateSurface)( LPDIRECTDRAWSURFACE p1, LPDIRECTDRAWSURFACE FAR *p2 )
    {
       return m_pDD->DuplicateSurface( p1, p2 );
    }

    STDMETHOD(EnumDisplayModes)( DWORD p1, LPDDSURFACEDESC p2, LPVOID p3, LPDDENUMMODESCALLBACK p4 )
    {
       return m_pDD->EnumDisplayModes( p1, p2, p3, p4 );
    }

    STDMETHOD(EnumSurfaces)(DWORD p1, LPDDSURFACEDESC p2, LPVOID p3, LPDDENUMSURFACESCALLBACK p4 )
    {
       return m_pDD->EnumSurfaces( p1, p2, p3, p4 );
    }

    STDMETHOD(FlipToGDISurface)()
    {
       return m_pDD4->FlipToGDISurface();
    }

    STDMETHOD(GetCaps)( LPDDCAPS p1, LPDDCAPS p2 )
    {
       return m_pDD4->GetCaps( p1, p2 );
    }

    STDMETHOD(GetDisplayMode)( LPDDSURFACEDESC p1 )
    {
       return m_pDD->GetDisplayMode( p1 );
    }

    STDMETHOD(GetFourCCCodes)(LPDWORD p1, LPDWORD p2 )
    {
       return m_pDD->GetFourCCCodes( p1, p2 );
    }

    STDMETHOD(GetGDISurface)(LPDIRECTDRAWSURFACE FAR *p1)
    {
       return m_pDD->GetGDISurface( p1 );
    }
    
    STDMETHOD(GetMonitorFrequency)(LPDWORD p1)
    {
       return m_pDD->GetMonitorFrequency( p1 );
    }

    STDMETHOD(GetScanLine)(LPDWORD p1)
    {
       return m_pDD->GetScanLine( p1 );
    }

    STDMETHOD(GetVerticalBlankStatus)(LPBOOL p1 )
    {
       return m_pDD->GetVerticalBlankStatus( p1 );
    }

    STDMETHOD(Initialize)(GUID FAR *p1)
    {
       return m_pDD->Initialize( p1 );
    }

    STDMETHOD(RestoreDisplayMode)()
    {
       return m_pDD->RestoreDisplayMode();
    }

    STDMETHOD(SetCooperativeLevel)(HWND p1, DWORD p2);

    STDMETHOD(SetDisplayMode)(DWORD p1, DWORD p2, DWORD p3);

    STDMETHOD(WaitForVerticalBlank)(DWORD p1, HANDLE p2 )
    {
       return m_pDD->WaitForVerticalBlank( p1, p2 );
    }

    /*** Added in the v2 interface ***/
    STDMETHOD(GetAvailableVidMem)(LPDDSCAPS p1, LPDWORD p2, LPDWORD p3)
    {
       return m_pDD2->GetAvailableVidMem( p1, p2, p3 );
    }

    /*** Added in the V4 Interface ***/
    STDMETHOD(GetAvailableVidMem)(LPDDSCAPS2 p1, LPDWORD p2, LPDWORD p3)
    {
       return m_pDD4->GetAvailableVidMem( p1, p2, p3 );
    }

    STDMETHOD(CreateSurface)(LPDDSURFACEDESC2 p1, LPDIRECTDRAWSURFACE4 FAR *p2, IUnknown FAR *p3);

    STDMETHOD(DuplicateSurface)( LPDIRECTDRAWSURFACE4 p1, LPDIRECTDRAWSURFACE4 FAR *p2 )
    {
       return m_pDD4->DuplicateSurface( p1, p2 );
    }

    STDMETHOD(EnumDisplayModes)( DWORD p1, LPDDSURFACEDESC2 p2, LPVOID p3, LPDDENUMMODESCALLBACK2 p4 )
    {
       return m_pDD4->EnumDisplayModes( p1, p2, p3, p4 );
    }

    STDMETHOD(EnumSurfaces)(DWORD p1, LPDDSURFACEDESC2 p2, LPVOID p3, LPDDENUMSURFACESCALLBACK2 p4 )
    {
       return m_pDD4->EnumSurfaces( p1, p2, p3, p4 );
    }

    STDMETHOD(GetDisplayMode)( LPDDSURFACEDESC2 p1 )
    {
       return m_pDD4->GetDisplayMode( p1 );
    }

    STDMETHOD(GetGDISurface)(LPDIRECTDRAWSURFACE4 FAR *p1)
    {
       return m_pDD4->GetGDISurface( p1 );
    }

    STDMETHOD(GetSurfaceFromDC) (HDC p1, LPDIRECTDRAWSURFACE4 *p2)
    {
       return m_pDD4->GetSurfaceFromDC( p1, p2 );
    }

    STDMETHOD(RestoreAllSurfaces)()
    {
       return m_pDD4->RestoreAllSurfaces();
    }

    STDMETHOD(TestCooperativeLevel)()
    {
       return m_pDD4->TestCooperativeLevel();
    }

    STDMETHOD(GetDeviceIdentifier)(LPDDDEVICEIDENTIFIER p1, DWORD p2 )
    {
       return m_pDD4->GetDeviceIdentifier( p1, p2 );
    }

    // Methods for the IDirect3D Interface
    STDMETHOD(Initialize)(REFCLSID p1)
    {
       return m_pD3D->Initialize( p1 );
    }

    STDMETHOD(EnumDevices)(LPD3DENUMDEVICESCALLBACK p1,LPVOID p2)
    {
       return m_pD3D->EnumDevices( p1, p2 );
    }

    STDMETHOD(CreateLight)(LPDIRECT3DLIGHT*p1,IUnknown*p2)
    {
       return m_pD3D->CreateLight( p1, p2 );
    }

    STDMETHOD(CreateMaterial)(LPDIRECT3DMATERIAL *p1,IUnknown *p2);

    STDMETHOD(CreateViewport)(LPDIRECT3DVIEWPORT*p1,IUnknown*p2)
    {
       return m_pD3D->CreateViewport( p1, p2 );
    }

    STDMETHOD(FindDevice)(LPD3DFINDDEVICESEARCH p1,LPD3DFINDDEVICERESULT p2)
    {
       return m_pD3D->FindDevice( p1, p2 );
    }

    // Methods for the IDirect3D2 Interface
    STDMETHOD(SetDisplayMode)(DWORD p1, DWORD p2, DWORD p3, DWORD p4, DWORD p5);

    STDMETHOD(CreateMaterial)(LPDIRECT3DMATERIAL2*p1,IUnknown*p2);

    STDMETHOD(CreateViewport)(LPDIRECT3DVIEWPORT2*p1,IUnknown*p2)
    {
       return m_pD3D2->CreateViewport( p1, p2 );
    }

    STDMETHOD(CreateDevice)(REFCLSID cls,LPDIRECTDRAWSURFACE pDDS,LPDIRECT3DDEVICE2 *ppD3D);

    // Methods for the IDirect3D3 Interface
    STDMETHOD(CreateMaterial)(LPDIRECT3DMATERIAL3*p1,LPUNKNOWN p2);

    STDMETHOD(CreateViewport)(LPDIRECT3DVIEWPORT3*p1,LPUNKNOWN p2)
    {
       return m_pD3D3->CreateViewport( p1, p2 );
    }

    STDMETHOD(CreateDevice)(REFCLSID cls,LPDIRECTDRAWSURFACE4 pDDS,LPDIRECT3DDEVICE3* ppD3D,LPUNKNOWN pUnk);

    STDMETHOD(CreateVertexBuffer)(LPD3DVERTEXBUFFERDESC p1,LPDIRECT3DVERTEXBUFFER*p2,DWORD p3,LPUNKNOWN p4)
    {
       return m_pD3D3->CreateVertexBuffer( p1, p2, p3, p4 );
    }

    STDMETHOD(EnumZBufferFormats)(REFCLSID p1,LPD3DENUMPIXELFORMATSCALLBACK p2,LPVOID p3)
    {
       return m_pD3D3->EnumZBufferFormats( p1, p2, p3 );
    }

    STDMETHOD(EvictManagedTextures)()
    {
       return m_pD3D3->EvictManagedTextures();
    }
};

#endif //__DIRECTDRAWHOOK_H_
