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

//========================================================================
// include files
//========================================================================
#include <windows.h>
#include <ddraw.h>
#include <d3d.h>
#include <assert.h>
#include "softm.h"
#include "globals.h"
#include "smddraw.h"
#include "smd3d.h"

#define ASSERT assert
#ifndef RELEASE
#define RELEASE(x) if(x) { (x)->Release(); (x)=NULL; }
#endif

#ifdef MLYONS
#define NO_DPRINTF
#include <mjl.h>
#endif

#ifdef MLYONS
//#define FORCE_BLADE_OVER_HAL
//#define FORCE_RGB_OVER_HAL
#endif

#ifdef MLYONS
//#define FORCE_TEXTURES_IN_SYSTEM_MEMORY
//#define FORCE_NO_TEXTUREMANAGE
#endif

//========================================================================
// CDirectDraw
//
// This is the implementation of the CDirectDraw object. The CDirectDraw
// object acts as a DirectDraw object, imlementing the IDirectDraw, the
// IDirectDraw4, the IDirect3D, and the IDirect3D3 interfaces.
//
//========================================================================
//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
    if (IID_IUnknown == riid)
    {
        AddRef();
        *ppvObj = (void*)this;
        return S_OK;
    }
    else if (IID_IDirectDraw == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirectDraw *)this;
        return S_OK;
    }
    else if (IID_IDirectDraw2 == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirectDraw2 *)this;
        return S_OK;
	}
    else if (IID_IDirectDraw4 == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirectDraw4 *)this;
        return S_OK;
	}
    else if (IID_IDirectDraw7 == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirectDraw7 *)this;
        return S_OK;
	}
	else if (IID_IDirect3D == riid)
	{
        AddRef();
        *ppvObj = (void*)(IDirect3D *)this;
        return S_OK;
	}
	else if (IID_IDirect3D3 == riid)
	{
        AddRef();
        *ppvObj = (void*)(IDirect3D3 *)this;
        return S_OK;
	}
#ifdef USE_DX7_INTERFACE
	else if (IID_IDirect3D7 == riid)
	{
        AddRef();
        *ppvObj = (void*)(IDirect3D7 *)this;
        return S_OK;
	}
#endif
	else
	{
        *ppvObj = NULL;
        return E_FAIL;
    }
}


//========================================================================
//========================================================================
ULONG CDirectDraw::AddRef(void)
{
    return ++m_cRef;
}

//========================================================================
//========================================================================
ULONG CDirectDraw::Release(void)
{
    if (--m_cRef == 0)
    {
		RELEASE(m_pDirect3D3);
		RELEASE(m_pDirect3D);
		RELEASE(m_pDirectDraw);
		RELEASE(m_pDirectDraw4);
        delete this;
        return 0;
    }
    return m_cRef;
}








//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::Compact()
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->Compact();
}

//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::CreateClipper(DWORD dwFlags, LPDIRECTDRAWCLIPPER FAR *lplpDDClipper, IUnknown FAR * pUnkOuter)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->CreateClipper(dwFlags, lplpDDClipper, pUnkOuter);
}

//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::CreatePalette(DWORD dwFlags, LPPALETTEENTRY lpColorTable, LPDIRECTDRAWPALETTE FAR * lplpDDPalette, IUnknown FAR *pUnkOuter)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->CreatePalette(dwFlags, lpColorTable, lplpDDPalette, pUnkOuter);
}

//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::CreateSurface( LPDDSURFACEDESC ddsd, LPDIRECTDRAWSURFACE FAR *lplpDDS, IUnknown FAR *p)
{
	ASSERT(m_pDirectDraw);

	if (m_pDirectDraw4)
	{
		HRESULT hr=m_pDirectDraw->CreateSurface(ddsd, lplpDDS, p);
		return hr;
	}
	else
	{
		HRESULT hr;

		//
		// we must create a CDirectDrawSurface object, since we're running
		// on NT
		//
		*lplpDDS = NULL;

		CDirectDrawSurface *pSurface = new CDirectDrawSurface();
		if (!pSurface)
			return E_OUTOFMEMORY;

		if (FAILED(hr = pSurface->CreateSurface(this, ddsd)))
		{
			delete pSurface;
			return hr;
		}

		*lplpDDS = (IDirectDrawSurface *)pSurface;
		pSurface->AddRef();
		return S_OK;
	}
}

#ifdef MLYONS
#if 0
void printddsd(DDSURFACEDESC2 *ddsd)
{
	//
	// let's look at what caps we've got
	//
	dprintf("New surface:\n");
	if (ddsd->ddsCaps.dwCaps & DDSCAPS_RESERVED1)
		dprintf("   Cap: DDSCAPS_RESERVED1\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_ALPHA)
		dprintf("   Cap: DDSCAPS_ALPHA\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_BACKBUFFER)
		dprintf("   Cap: DDSCAPS_BACKBUFFER\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_COMPLEX)
		dprintf("   Cap: DDSCAPS_COMPLEX\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_FLIP)
		dprintf("   Cap: DDSCAPS_FLIP\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
		dprintf("   Cap: DDSCAPS_FRONTBUFFER\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN)
		dprintf("   Cap: DDSCAPS_OFFSCREENPLAIN\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_OVERLAY)
		dprintf("   Cap: DDSCAPS_OVERLAY\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_PALETTE)
		dprintf("   Cap: DDSCAPS_PALETTE\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
		dprintf("   Cap: DDSCAPS_PRIMARYSURFACE\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_RESERVED3)
		dprintf("   Cap: DDSCAPS_RESERVED3\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
		dprintf("   Cap: DDSCAPS_SYSTEMMEMORY\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
		dprintf("   Cap: DDSCAPS_TEXTURE\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
		dprintf("   Cap: DDSCAPS_3DDEVICE\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
		dprintf("   Cap: DDSCAPS_VIDEOMEMORY\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_VISIBLE)
		dprintf("   Cap: DDSCAPS_VISIBLE\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_WRITEONLY)
		dprintf("   Cap: DDSCAPS_WRITEONLY\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
		dprintf("   Cap: DDSCAPS_ZBUFFER\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_OWNDC)
		dprintf("   Cap: DDSCAPS_OWNDC\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_LIVEVIDEO)
		dprintf("   Cap: DDSCAPS_LIVEVIDEO\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_HWCODEC)
		dprintf("   Cap: DDSCAPS_HWCODEC\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_MODEX)
		dprintf("   Cap: DDSCAPS_MODEX\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_MIPMAP)
		dprintf("   Cap: DDSCAPS_MIPMAP\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_RESERVED2)
		dprintf("   Cap: DDSCAPS_RESERVED2\n");

//	if (ddsd->ddsCaps.dwCaps & DDSCAPS_UNKNOWN1)
//		dprintf("   Cap: DDSCAPS_UNKNOWN1\n");
//
//	if (ddsd->ddsCaps.dwCaps & DDSCAPS_UNKNOWN2)
//		dprintf("   Cap: DDSCAPS_UNKNOWN2\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD)
		dprintf("   Cap: DDSCAPS_ALLOCONLOAD\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_VIDEOPORT)
		dprintf("   Cap: DDSCAPS_VIDEOPORT\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_LOCALVIDMEM)
		dprintf("   Cap: DDSCAPS_LOCALVIDMEM\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_NONLOCALVIDMEM)
		dprintf("   Cap: DDSCAPS_NONLOCALVIDMEM\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_STANDARDVGAMODE)
		dprintf("   Cap: DDSCAPS_STANDARDVGAMODE\n");

	if (ddsd->ddsCaps.dwCaps & DDSCAPS_OPTIMIZED)
		dprintf("   Cap: DDSCAPS_OPTIMIZED\n");



	if (ddsd->dwFlags & DDSD_ALPHABITDEPTH)
		dprintf("  Flag: DDSD_ALPHABITDEPTH\n");

	if (ddsd->dwFlags & DDSD_BACKBUFFERCOUNT)
		dprintf("  Flag: DDSD_BACKBUFFERCOUNT\n");

	if (ddsd->dwFlags & DDSD_CAPS)
		dprintf("  Flag: DDSD_CAPS\n");

	if (ddsd->dwFlags & DDSD_CKDESTBLT)
		dprintf("  Flag: DDSD_CKDESTBLT\n");

	if (ddsd->dwFlags & DDSD_CKDESTOVERLAY)
		dprintf("  Flag: DDSD_CKDESTOVERLAY\n");

	if (ddsd->dwFlags & DDSD_CKSRCBLT)
		dprintf("  Flag: DDSD_CKSRCBLT\n");

	if (ddsd->dwFlags & DDSD_CKSRCOVERLAY)
		dprintf("  Flag: DDSD_CKSRCOVERLAY\n");

	if (ddsd->dwFlags & DDSD_HEIGHT)
		dprintf("  Flag: DDSD_HEIGHT\n");

	if (ddsd->dwFlags & DDSD_LINEARSIZE)
		dprintf("  Flag: DDSD_LINEARSIZE\n");

	if (ddsd->dwFlags & DDSD_LPSURFACE)
		dprintf("  Flag: DDSD_LPSURFACE\n");

	if (ddsd->dwFlags & DDSD_MIPMAPCOUNT)
		dprintf("  Flag: DDSD_MIPMAPCOUNT\n");

	if (ddsd->dwFlags & DDSD_PITCH)
		dprintf("  Flag: DDSD_PITCH\n");

	if (ddsd->dwFlags & DDSD_PIXELFORMAT)
		dprintf("  Flag: DDSD_PIXELFORMAT\n");

	if (ddsd->dwFlags & DDSD_REFRESHRATE)
		dprintf("  Flag: DDSD_REFRESHRATE\n");

	if (ddsd->dwFlags & DDSD_TEXTURESTAGE)
		dprintf("  Flag: DDSD_TEXTURESTAGE\n");

	if (ddsd->dwFlags & DDSD_WIDTH)
		dprintf("  Flag: DDSD_WIDTH\n");

	if (ddsd->dwFlags & DDSD_ZBUFFERBITDEPTH)
		dprintf("  Flag: DDSD_ZBUFFERBITDEPTH\n");
}
#else
#define printddsd(x)
#endif
#endif // MLYONS

//========================================================================
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirectDraw::CreateSurface( LPDDSURFACEDESC2 ddsd, LPDIRECTDRAWSURFACE7 FAR *lplpDDS, IUnknown FAR *p)
{
#ifdef MLYONS
#ifdef FORCE_BLADE_OVER_HAL
	if (ddsd->ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
	{
        ddsd->ddsCaps.dwCaps &= ~(DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM | DDSCAPS_VIDEOMEMORY);
        ddsd->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;

	}
#endif
#ifdef FORCE_RGB_OVER_HAL
	if (ddsd->ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
	{
        ddsd->ddsCaps.dwCaps &= ~(DDSCAPS_LOCALVIDMEM | DDSCAPS_NONLOCALVIDMEM | DDSCAPS_VIDEOMEMORY);
        ddsd->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;

	}
#endif
#endif

	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
	{
#ifdef MLYONS
		printddsd(ddsd);
#ifdef FORCE_TEXTURES_IN_SYSTEM_MEMORY
		if (ddsd->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
		{
			ddsd->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
			ddsd->ddsCaps.dwCaps &= ~(DDSCAPS_VIDEOMEMORY);
		}
#endif
#ifdef FORCE_NO_TEXTUREMANAGE
		if (ddsd->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
		{
			ddsd->ddsCaps.dwCaps2 &= ~(DDSCAPS2_TEXTUREMANAGE);
		}
#endif
#endif
		HRESULT hr=m_pDirectDraw4->CreateSurface(ddsd, lplpDDS, p);
		return hr;
	}
	else
	{
#ifdef MLYONS_TEST
		//
		// if we're creating a primary surface with a back buffer, change
		//
		__asm nop;
#endif
		HRESULT hr;

		//
		// we must create a CDirectDrawSurface object, since we're running
		// on NT
		//
		*lplpDDS = NULL;

		CDirectDrawSurface *pSurface = new CDirectDrawSurface();
		if (!pSurface)
			return E_OUTOFMEMORY;

		//
		// if 1555 and not a texture, which we don't like, make it 0555
		//
		if ((ddsd->ddsCaps.dwCaps & DDSCAPS_TEXTURE) == 0)
		{
			if ((ddsd->ddpfPixelFormat.dwRGBBitCount == 16) &&
				(ddsd->ddpfPixelFormat.dwRBitMask == 0x7C00) &&
				(ddsd->ddpfPixelFormat.dwGBitMask == 0x03E0) &&
				(ddsd->ddpfPixelFormat.dwBBitMask == 0x001F) &&
				(ddsd->ddpfPixelFormat.dwRGBAlphaBitMask == 0x8000))
			{
				ddsd->ddpfPixelFormat.dwRGBAlphaBitMask = 0;
				ddsd->ddpfPixelFormat.dwFlags &= ~(DDPF_ALPHA | DDPF_ALPHAPIXELS);

			}
		}


		if (FAILED(hr = pSurface->CreateSurface(this, ddsd)))
		{
#ifdef MLYONS
			dprintf("Error: %s\n", ddErrorString(hr));
#endif
			delete pSurface;
			return hr;
		}

		*lplpDDS = (IDirectDrawSurface7 *)pSurface;
		pSurface->AddRef();
		return S_OK;
	}
}
STDMETHODIMP CDirectDraw::CreateSurface( LPDDSURFACEDESC2 ddsd, LPDIRECTDRAWSURFACE4 FAR *lplpDDS, IUnknown FAR *p)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
	{
		LPDIRECTDRAWSURFACE7 lpDDS=NULL;

		HRESULT hr=m_pDirectDraw4->CreateSurface(ddsd, &lpDDS, p);
		if (SUCCEEDED(hr))
			hr=lpDDS->QueryInterface(IID_IDirectDrawSurface4, (void **)lplpDDS);

		RELEASE(lpDDS);
		return hr;
	}
	else
	{
		HRESULT hr;

		//
		// we must create a CDirectDrawSurface object, since we're running
		// on NT
		//
		*lplpDDS = NULL;

		CDirectDrawSurface *pSurface = new CDirectDrawSurface();
		if (!pSurface)
			return E_OUTOFMEMORY;

		if (FAILED(hr = pSurface->CreateSurface(this, ddsd)))
		{
			delete pSurface;
			return hr;
		}

		*lplpDDS = (IDirectDrawSurface4 *)pSurface;
		pSurface->AddRef();
		return S_OK;
	}
}
#else
STDMETHODIMP CDirectDraw::CreateSurface( LPDDSURFACEDESC2 ddsd, LPDIRECTDRAWSURFACE4 FAR *lplpDDS, IUnknown FAR *p)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
	{
		HRESULT hr=m_pDirectDraw4->CreateSurface(ddsd, lplpDDS, p);
		return hr;
	}
	else
	{
		HRESULT hr;

		//
		// we must create a CDirectDrawSurface object, since we're running
		// on NT
		//
		*lplpDDS = NULL;

		CDirectDrawSurface *pSurface = new CDirectDrawSurface();
		if (!pSurface)
			return E_OUTOFMEMORY;

		if (FAILED(hr = pSurface->CreateSurface(this, ddsd)))
		{
			delete pSurface;
			return hr;
		}

		*lplpDDS = (IDirectDrawSurface4 *)pSurface;
		pSurface->AddRef();
		return S_OK;
	}
}
#endif



//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::DuplicateSurface( LPDIRECTDRAWSURFACE lpDDS, LPDIRECTDRAWSURFACE FAR * lplpDDS)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->DuplicateSurface(lpDDS, lplpDDS);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::EnumDisplayModes( DWORD dwFlags, LPDDSURFACEDESC ddsd, LPVOID lpContext, LPDDENUMMODESCALLBACK lpCallBack)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->EnumDisplayModes(dwFlags, ddsd, lpContext, lpCallBack);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::EnumSurfaces(DWORD dwFlags, LPDDSURFACEDESC ddsd, LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpCallBack)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->EnumSurfaces(dwFlags, ddsd, lpContext, lpCallBack);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::FlipToGDISurface()
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->FlipToGDISurface();
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetCaps( LPDDCAPS ddcaps1, LPDDCAPS ddcaps2)
{
	ASSERT(m_pDirectDraw);

	if (m_pDirectDraw4)
		return m_pDirectDraw->GetCaps(ddcaps1, ddcaps2);
	else
	{
		if (ddcaps1 && ddcaps2 && (ddcaps1->dwSize != ddcaps2->dwSize))
			return DDERR_INVALIDPARAMS;

		DWORD dwSize;
		if (ddcaps1)
			dwSize=ddcaps1->dwSize;
		else if (ddcaps2)
			dwSize=ddcaps2->dwSize;
		else
			dwSize=0;

		if (dwSize == sizeof(_DDCAPS_DX3))
			return m_pDirectDraw->GetCaps(ddcaps1, ddcaps2);
		else if (dwSize == sizeof(_DDCAPS_DX5))
		{
			HRESULT hr;

			if (ddcaps1)
			{
				ZeroMemory(ddcaps1, ddcaps1->dwSize);
				ddcaps1->dwSize = sizeof(_DDCAPS_DX3);
			}
			if (ddcaps2)
			{
				ZeroMemory(ddcaps2, ddcaps2->dwSize);
				ddcaps2->dwSize = sizeof(_DDCAPS_DX3);
			}

			hr = m_pDirectDraw->GetCaps(ddcaps1, ddcaps2);

			if (ddcaps1)
			{
				ddcaps1->dwSize = sizeof(_DDCAPS_DX5);
				ddcaps1->dwCaps2 |= DDCAPS2_CANRENDERWINDOWED;
			}
			if (ddcaps2)
			{
				ddcaps2->dwSize = sizeof(_DDCAPS_DX5);
				ddcaps2->dwCaps2 |= DDCAPS2_CANRENDERWINDOWED;
			}
			return hr;
		}
		else if (dwSize == sizeof(_DDCAPS_DX6))
		{
			HRESULT hr;

			if (ddcaps1)
			{
				ZeroMemory(ddcaps1, ddcaps1->dwSize);
				ddcaps1->dwSize = sizeof(_DDCAPS_DX3);
			}
			if (ddcaps2)
			{
				ZeroMemory(ddcaps2, ddcaps2->dwSize);
				ddcaps2->dwSize = sizeof(_DDCAPS_DX3);
			}

			hr = m_pDirectDraw->GetCaps(ddcaps1, ddcaps2);

			if (ddcaps1)
			{
				ddcaps1->dwSize = sizeof(_DDCAPS_DX6);
				ddcaps1->dwCaps2 |= DDCAPS2_CANRENDERWINDOWED;
			}
			if (ddcaps2)
			{
				ddcaps2->dwSize = sizeof(_DDCAPS_DX6);
				ddcaps2->dwCaps2 |= DDCAPS2_CANRENDERWINDOWED;
			}
			return hr;
		}
		else
			return DDERR_INVALIDPARAMS;
	}
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetDisplayMode( LPDDSURFACEDESC ddsd)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->GetDisplayMode(ddsd);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetFourCCCodes( LPDWORD lpdwCC1, LPDWORD lpdwCC2)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->GetFourCCCodes( lpdwCC1, lpdwCC2);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetGDISurface(LPDIRECTDRAWSURFACE FAR *lpDDS)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->GetGDISurface(lpDDS);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetMonitorFrequency(LPDWORD lpdwFlags)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->GetMonitorFrequency(lpdwFlags);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetScanLine(LPDWORD lpdw)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->GetScanLine(lpdw);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetVerticalBlankStatus(LPBOOL lpb)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->GetVerticalBlankStatus(lpb);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::Initialize(GUID FAR *lpGUID)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->Initialize(lpGUID);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::RestoreDisplayMode()
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->RestoreDisplayMode();
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::SetCooperativeLevel(HWND hWnd, DWORD dw)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw->SetCooperativeLevel(hWnd, dw);
	else
	{
		//
		// turn off flags not supported by DX3
		//
		dw &= ~(DDSCL_CREATEDEVICEWINDOW | DDSCL_FPUSETUP | DDSCL_MULTITHREADED | DDSCL_NOWINDOWCHANGES | DDSCL_SETDEVICEWINDOW | DDSCL_SETFOCUSWINDOW);
		return m_pDirectDraw->SetCooperativeLevel(hWnd, dw);
	}
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::SetDisplayMode(DWORD dw1, DWORD dw2, DWORD dw3)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->SetDisplayMode(dw1, dw2, dw3);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::WaitForVerticalBlank(DWORD dw, HANDLE h)
{
	ASSERT(m_pDirectDraw);
	return m_pDirectDraw->WaitForVerticalBlank(dw, h);
}


//========================================================================
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirectDraw::DuplicateSurface( LPDIRECTDRAWSURFACE4 lpdds, LPDIRECTDRAWSURFACE4 FAR * lplpdds)
{
	HRESULT hr;
	IDirectDraw4 * pDirectDraw4 = NULL;

	ASSERT(m_pDirectDraw);
	if (!m_pDirectDraw4)
		return E_FAIL;


	if (FAILED(hr=m_pDirectDraw4->QueryInterface(IID_IDirectDraw4, (void **)&m_pDirectDraw4)))
		return hr;

	hr=pDirectDraw4->DuplicateSurface(lpdds, lplpdds);
	RELEASE(pDirectDraw4);
	return hr;
}
#else
STDMETHODIMP CDirectDraw::DuplicateSurface( LPDIRECTDRAWSURFACE4 lpdds, LPDIRECTDRAWSURFACE4 FAR * lplpdds)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->DuplicateSurface(lpdds, lplpdds);
	else
		return E_FAIL;
}
#endif

//========================================================================
//========================================================================
typedef struct tagENUMMODESSTUB
{
	LPDDENUMMODESCALLBACK2	lpCallback;
	LPVOID					lpContext;

} ENUMMODESSTUB;

static HRESULT WINAPI EnumModesCallbackStub(LPDDSURFACEDESC lpDDSurfaceDesc, ENUMMODESSTUB* lpContext)
{
	return lpContext->lpCallback((LPDDSURFACEDESC2)lpDDSurfaceDesc, lpContext->lpContext);

}

//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::EnumDisplayModes( DWORD dw, LPDDSURFACEDESC2 pddsd, LPVOID lpv, LPDDENUMMODESCALLBACK2 lpc)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->EnumDisplayModes(dw, pddsd, lpv, lpc);
	else
	{
		DWORD			dwFlags;
		ENUMMODESSTUB	ems;

		ems.lpCallback	= lpc;
		ems.lpContext	= lpv;

		dwFlags = 0;
		if (dw & DDEDM_REFRESHRATES)
			dwFlags |= DDEDM_REFRESHRATES;

		if (pddsd)
		{
			DDSURFACEDESC	ddsd;

			ddsd = *(DDSURFACEDESC *)pddsd;
			ddsd.dwSize = sizeof(ddsd);

			return m_pDirectDraw->EnumDisplayModes(dwFlags, &ddsd, &ems, (LPDDENUMMODESCALLBACK)EnumModesCallbackStub);
		}
		else
		{
			return m_pDirectDraw->EnumDisplayModes(dwFlags, NULL, &ems, (LPDDENUMMODESCALLBACK)EnumModesCallbackStub);
		}
		return E_FAIL;
	}
}


//========================================================================
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirectDraw::EnumSurfaces(DWORD dw, LPDDSURFACEDESC2 ddsd, LPVOID lpv, LPDDENUMSURFACESCALLBACK2 lpc)
{
	HRESULT hr;
	IDirectDraw4 * pDirectDraw4 = NULL;

	ASSERT(m_pDirectDraw);
	if (!m_pDirectDraw4)
		return E_FAIL;


	if (FAILED(hr=m_pDirectDraw4->QueryInterface(IID_IDirectDraw4, (void **)&m_pDirectDraw4)))
		return hr;

	hr=pDirectDraw4->EnumSurfaces(dw, ddsd, lpv, lpc);
	RELEASE(pDirectDraw4);
	return hr;
}
STDMETHODIMP CDirectDraw::EnumSurfaces(DWORD dw, LPDDSURFACEDESC2 ddsd, LPVOID lpv, LPDDENUMSURFACESCALLBACK7 lpc)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->EnumSurfaces(dw, ddsd, lpv, lpc);
	else
		return E_FAIL;
}
#else
STDMETHODIMP CDirectDraw::EnumSurfaces(DWORD dw, LPDDSURFACEDESC2 ddsd, LPVOID lpv, LPDDENUMSURFACESCALLBACK2 lpc)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->EnumSurfaces(dw, ddsd, lpv, lpc);
	else
		return E_FAIL;
}
#endif


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetDisplayMode(LPDDSURFACEDESC2 ddsd)
{
	HRESULT hr;
	ASSERT(m_pDirectDraw);

	if (m_pDirectDraw4)
	{
		hr = m_pDirectDraw4->GetDisplayMode(ddsd);
	}
	else
	{
		ASSERT(ddsd->dwSize == sizeof(DDSURFACEDESC2));
		ZeroMemory(ddsd,sizeof(DDSURFACEDESC2));
		ddsd->dwSize = sizeof(DDSURFACEDESC);
		hr = m_pDirectDraw->GetDisplayMode((LPDDSURFACEDESC)ddsd);
		ddsd->dwSize = sizeof(DDSURFACEDESC2);
	}
	return hr;
}


//========================================================================
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirectDraw::GetGDISurface(LPDIRECTDRAWSURFACE4 FAR *lpdds)
{
	HRESULT hr;
	IDirectDraw4 * pDirectDraw4 = NULL;

	ASSERT(m_pDirectDraw);
	if (!m_pDirectDraw4)
		return E_FAIL;


	if (FAILED(hr=m_pDirectDraw4->QueryInterface(IID_IDirectDraw4, (void **)&m_pDirectDraw4)))
		return hr;

	hr=pDirectDraw4->GetGDISurface(lpdds);
	RELEASE(pDirectDraw4);
	return hr;
}
#else
STDMETHODIMP CDirectDraw::GetGDISurface(LPDIRECTDRAWSURFACE4 FAR *lpdds)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->GetGDISurface(lpdds);
	else
		return E_FAIL;
}
#endif


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::SetDisplayMode(DWORD dw1, DWORD dw2,DWORD dw3, DWORD dw4, DWORD dw5)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->SetDisplayMode(dw1, dw2, dw3, dw4, dw5);
	else
		return m_pDirectDraw->SetDisplayMode(dw1, dw2, dw3);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetAvailableVidMem(LPDDSCAPS2 ddsc, LPDWORD lpdw1, LPDWORD lpdw2)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->GetAvailableVidMem(ddsc, lpdw1, lpdw2);
	else
		return E_FAIL;
}


//========================================================================
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirectDraw::GetSurfaceFromDC (HDC hdc, LPDIRECTDRAWSURFACE4 *lpdds)
{
	HRESULT hr;
	IDirectDraw4 * pDirectDraw4 = NULL;

	ASSERT(m_pDirectDraw);
	if (!m_pDirectDraw4)
		return E_FAIL;


	if (FAILED(hr=m_pDirectDraw4->QueryInterface(IID_IDirectDraw4, (void **)&m_pDirectDraw4)))
		return hr;

	hr=pDirectDraw4->GetSurfaceFromDC (hdc, lpdds);
	RELEASE(pDirectDraw4);
	return hr;
}
#else
STDMETHODIMP CDirectDraw::GetSurfaceFromDC (HDC hdc, LPDIRECTDRAWSURFACE4 *lpdds)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->GetSurfaceFromDC (hdc, lpdds);
	else
		return E_FAIL;
}
#endif


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::RestoreAllSurfaces()
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->RestoreAllSurfaces();
	else
		return E_FAIL;
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::TestCooperativeLevel()
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
		return m_pDirectDraw4->TestCooperativeLevel();
	else
		return S_OK;
}


//========================================================================
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirectDraw::GetDeviceIdentifier(LPDDDEVICEIDENTIFIER lpdddi, DWORD dw)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
	{
		HRESULT hr;
		IDirectDraw4 * pDirectDraw4 = NULL;

		if (FAILED(hr=m_pDirectDraw4->QueryInterface(IID_IDirectDraw4, (void **)&pDirectDraw4)))
			return hr;

		hr=pDirectDraw4->GetDeviceIdentifier(lpdddi, dw);
		RELEASE(pDirectDraw4);
		return hr;
	}
	else
	{
		if (lpdddi)
		{
			strcpy(lpdddi->szDriver, "driver");
			strcpy(lpdddi->szDescription, "Windows NT Video Driver");
			*(__int64 *)&lpdddi->liDriverVersion = 1;
			lpdddi->dwVendorId = 0;
			lpdddi->dwDeviceId = 0;
			lpdddi->dwSubSysId = 0;
			lpdddi->dwRevision = 0;
			ZeroMemory(&lpdddi->guidDeviceIdentifier, sizeof(lpdddi->guidDeviceIdentifier));

			return E_NOTIMPL;
		}

		return DDERR_INVALIDPARAMS;
	}
}
#else
STDMETHODIMP CDirectDraw::GetDeviceIdentifier(LPDDDEVICEIDENTIFIER lpdddi, DWORD dw)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
	{
		return m_pDirectDraw4->GetDeviceIdentifier(lpdddi, dw);
	}
	else
	{
		if (lpdddi)
		{
			strcpy(lpdddi->szDriver, "driver");
			strcpy(lpdddi->szDescription, "Windows NT Video Driver");
			*(__int64 *)&lpdddi->liDriverVersion = 1;
			lpdddi->dwVendorId = 0;
			lpdddi->dwDeviceId = 0;
			lpdddi->dwSubSysId = 0;
			lpdddi->dwRevision = 0;
			ZeroMemory(&lpdddi->guidDeviceIdentifier, sizeof(lpdddi->guidDeviceIdentifier));

			return E_NOTIMPL;
		}

		return DDERR_INVALIDPARAMS;
	}
}
#endif






//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::Initialize(REFCLSID clsid)
{
	ASSERT(m_pDirect3D);
	return m_pDirect3D->Initialize(clsid);

}

//========================================================================
// CDirectDraw::EnumDevices
//
// Enumerates the SoftMonkey device, then calls the DirectDraw method
// to enumerate the remaining devices.
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirectDraw::EnumDevices(LPD3DENUMDEVICESCALLBACK7 pEnumCallback, LPVOID lpv)
{
	HRESULT hr;

	// Validate the arguments.
	if (NULL == pEnumCallback)
		return DDERR_INVALIDPARAMS;

	//D3DDEVICEDESC d3ddd_Hal = { sizeof(d3ddd_Hal) };
	//D3DDEVICEDESC d3ddd_Hel = { sizeof(d3ddd_Hel) };
	//CDirect3DDevice::Static_GetCaps(&d3ddd_Hal, &d3ddd_Hel);

	D3DDEVICEDESC7 dd7 = {0};
	CDirect3DDevice::Static_GetCaps(&dd7);

	//hr = (pEnumCallback)((LPGUID)&IID_IDirect3DBladeDevice, (LPSTR)g_szDeviceName, (LPSTR)g_szDeviceDesc, &d3ddd_Hal, &d3ddd_Hel, lpv);
	hr = (pEnumCallback)((LPSTR)g_szDeviceName, (LPSTR)g_szDeviceDesc, &dd7, lpv);

	// only enumerate DX native devices on DX6+

	if (m_pDirectDraw4 && hr==D3DENUMRET_OK)
		hr = m_pDirect3D3->EnumDevices(pEnumCallback, lpv);

	return hr;
}
STDMETHODIMP CDirectDraw::EnumDevices(LPD3DENUMDEVICESCALLBACK pEnumCallback, LPVOID lpv)
{
	ASSERT(0);
	return E_FAIL;
}
#else
STDMETHODIMP CDirectDraw::EnumDevices(LPD3DENUMDEVICESCALLBACK pEnumCallback, LPVOID lpv)
{
	ASSERT(m_pDirect3D);

	// Validate the arguments.
	if (NULL == pEnumCallback)
		return DDERR_INVALIDPARAMS;

	D3DDEVICEDESC d3ddd_Hal = { sizeof(d3ddd_Hal) };
	D3DDEVICEDESC d3ddd_Hel = { sizeof(d3ddd_Hel) };

	CDirect3DDevice::Static_GetCaps(&d3ddd_Hal, &d3ddd_Hel);

	HRESULT hr = (pEnumCallback)((LPGUID)&IID_IDirect3DBladeDevice, (LPSTR)g_szDeviceName, (LPSTR)g_szDeviceDesc, &d3ddd_Hal, &d3ddd_Hel, lpv);

	// only enumerate DX native devices on DX6+
	if ((hr == D3DENUMRET_OK) && m_pDirectDraw4)
		hr = m_pDirect3D->EnumDevices(pEnumCallback, lpv);

	return hr;
}
#endif


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::CreateLight(LPDIRECT3DLIGHT* lplpd3dl, IUnknown* p)
{
	ASSERT(m_pDirect3D);

#ifndef USE_DX7_INTERFACE
	if (m_pDirect3D3)
	{
		return m_pDirect3D3->CreateLight(lplpd3dl, p);
	}
	else
#endif
	{
		*lplpd3dl = (LPDIRECT3DLIGHT)(new CDirect3DLight);
		(*lplpd3dl)->AddRef();
		return S_OK;
	}
}

//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::CreateMaterial(LPDIRECT3DMATERIAL* lplpd3dm, IUnknown* p)
{
	ASSERT(m_pDirect3D);
	return m_pDirect3D->CreateMaterial(lplpd3dm, p);
}

//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::CreateViewport(LPDIRECT3DVIEWPORT* lpd3dv, IUnknown* p)
{
	ASSERT(m_pDirect3D);
	return m_pDirect3D->CreateViewport(lpd3dv, p);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::FindDevice(LPD3DFINDDEVICESEARCH lpd3dfds, LPD3DFINDDEVICERESULT lpr)
{
	ASSERT(m_pDirect3D);
	if ((lpd3dfds->dwFlags & D3DFDS_GUID) && (lpd3dfds->guid == IID_IDirect3DBladeDevice))
	{
		if (lpr->dwSize == sizeof(D3DFINDDEVICERESULT))
		{
			lpr->guid = IID_IDirect3DBladeDevice;

			lpr->ddHwDesc.dwSize = sizeof(lpr->ddHwDesc);
			lpr->ddSwDesc.dwSize = sizeof(lpr->ddSwDesc);
			CDirect3DDevice::Static_GetCaps(&lpr->ddHwDesc, &lpr->ddSwDesc);

			return S_OK;
		}
		else
			return DDERR_INVALIDPARAMS;
	}
	return m_pDirect3D->FindDevice(lpd3dfds, lpr);
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::CreateMaterial(LPDIRECT3DMATERIAL3* lpd3dm,LPUNKNOWN p)
{
	ASSERT(m_pDirect3D);

#ifndef USE_DX7_INTERFACE
	if (m_pDirect3D3)
	{
		return m_pDirect3D3->CreateMaterial(lpd3dm, p);
	}
	else
#endif
	{
		*lpd3dm = (LPDIRECT3DMATERIAL3)(new CDirect3DMaterial);
		(*lpd3dm)->AddRef();
		return S_OK;
	}
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::CreateViewport(LPDIRECT3DVIEWPORT3* lpd3v,LPUNKNOWN p)
{
#ifndef USE_DX7_INTERFACE
	ASSERT(m_pDirect3D);

	if (m_pDirect3D3)
	{
		return m_pDirect3D3->CreateViewport(lpd3v, p);
	}
	else
#endif
	{
		CDirect3DViewport *pvp = new CDirect3DViewport;
		pvp->AddRef();

		*lpd3v = (IDirect3DViewport3 *)pvp;
		return S_OK;
	}
}


//========================================================================
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirectDraw::CreateDevice(REFCLSID clsid, LPDIRECTDRAWSURFACE4 lpdds, LPDIRECT3DDEVICE3* lplpd3dd, LPUNKNOWN p)
{
	ASSERT(0);
	return E_FAIL;
}
STDMETHODIMP CDirectDraw::CreateDevice(REFCLSID clsid, LPDIRECTDRAWSURFACE7 lpdds, LPDIRECT3DDEVICE7* lplpd3dd)
{
//	ASSERT(m_pDirect3D);

	m_bUseBlade = false;

#ifdef FORCE_BLADE_OVER_HAL
	if ((IID_IDirect3DHALDevice == clsid) ||
		(IID_IDirect3DBladeDevice == clsid) ||
		(m_pDirectDraw4 == NULL && IID_IDirect3DRGBDevice == clsid))
#else
	if (IID_IDirect3DBladeDevice == clsid ||
		(m_pDirectDraw4 == NULL && IID_IDirect3DRGBDevice == clsid))
#endif
	{
		HRESULT				hr = 0;
		IDirect3DDevice7 *	pDevice3;

		// Initializtions.
		*lplpd3dd	= NULL;
		pDevice3	= NULL;

		// Create a software device.
		if (m_pDirect3D3)
		{
			hr = m_pDirect3D3->CreateDevice(IID_IDirect3DRGBDevice, lpdds, &pDevice3);
			///lpdds->Release();

			if (FAILED(hr))
			{
#ifdef MLYONS
				dprintf("Error! %s\n", ddErrorString(hr));
#endif
				goto done;
			}
		}

		// Create our proxy object.
		*lplpd3dd = (IDirect3DDevice7 *) new CDirect3DDevice((IDirect3D *)this, (IDirect3DDevice *)pDevice3);

        if (pDevice3)
		    pDevice3->Release();

		if (NULL == *lplpd3dd)
		{
			hr = E_FAIL;
			goto done;
		}

		(*lplpd3dd)->SetRenderTarget(lpdds, 0);

		//
		// for the DX7 interface, let's create a viewport
		//
		IDirect3DViewport3	*pViewport3;
		IDirect3DDevice3	*pDevice;
		pViewport3 = NULL;
		pDevice = NULL;

		if (FAILED(hr=(*lplpd3dd)->QueryInterface(IID_IDirect3DDevice3, (void **)&pDevice)))
		{
			ASSERT(0);
			return hr;
		}

		CreateViewport(&pViewport3, NULL);
		pDevice->SetCurrentViewport(pViewport3);
		RELEASE(pDevice);
		RELEASE(pViewport3);

		//JJ Fix-A-Roo
		//Be sure that we have enough room...
		ASSERT(CDirect3DDevice::s_nDevCnt < MAX_DEVICES);

		if (CDirect3DDevice::s_nDevCnt < MAX_DEVICES)
		{
			//Add the Blade Device to the list & increment the count
			CDirect3DDevice::s_pDeviceList[CDirect3DDevice::s_nDevCnt] = *lplpd3dd;
			CDirect3DDevice::s_nDevCnt++;
		}
		m_bUseBlade = true;

		hr = DD_OK;

	done:
		return hr;

	}

	if (m_pDirect3D3)
	{
		HRESULT hr;

#ifdef FORCE_RGB_OVER_HAL
		if (IID_IDirect3DHALDevice == clsid)
			hr=m_pDirect3D3->CreateDevice(IID_IDirect3DRGBDevice, lpdds, lplpd3dd);
#else
		hr=m_pDirect3D3->CreateDevice(clsid, lpdds, lplpd3dd);
#endif
#ifdef MLYONS
		if (FAILED(hr))
			dprintf("Error! %s\n", ddErrorString(hr));
		else
#endif
			return hr;
	}
	else
		return E_FAIL;
}
#else
STDMETHODIMP CDirectDraw::CreateDevice(REFCLSID clsid, LPDIRECTDRAWSURFACE4 lpdds, LPDIRECT3DDEVICE3* lplpd3dd, LPUNKNOWN p)
{
	ASSERT(m_pDirect3D);

	if (IID_IDirect3DBladeDevice == clsid ||
		(m_pDirectDraw4 == NULL && IID_IDirect3DRGBDevice == clsid))
	{
		HRESULT				hr = 0;
		IDirect3DDevice3 *	pDevice3;

		// Initializtions.
		*lplpd3dd	= NULL;
		pDevice3	= NULL;

		// Aggregation is not supported.
		if (NULL != p)
			return DDERR_INVALIDPARAMS;

		// Create a software device.
		if (m_pDirect3D3)
		{
			hr = m_pDirect3D3->CreateDevice(IID_IDirect3DRGBDevice, lpdds, &pDevice3, p);
			///lpdds->Release();

			if (FAILED(hr))
			{
				goto done;
			}
		}

		// Create our proxy object.
		*lplpd3dd = (IDirect3DDevice3 *) new CDirect3DDevice((IDirect3D *)this, (IDirect3DDevice *)pDevice3);

        if (pDevice3)
		    pDevice3->Release();

		if (NULL == *lplpd3dd)
		{
			hr = E_FAIL;
			goto done;
		}

		hr = (*lplpd3dd)->SetRenderTarget(lpdds, 0);

        if (hr == S_OK)
            hr = DD_OK;
        else
            hr = E_FAIL;

	done:
		return hr;

	}

	if (m_pDirect3D3)
		return m_pDirect3D3->CreateDevice(clsid, lpdds, lplpd3dd, p);
	else
		return E_FAIL;
}
#endif

//========================================================================
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirectDraw::CreateVertexBuffer(LPD3DVERTEXBUFFERDESC lp, LPDIRECT3DVERTEXBUFFER* lplpvb, DWORD dw,LPUNKNOWN lpu)
{
	ASSERT(0);
	return E_FAIL;
}
#else
STDMETHODIMP CDirectDraw::CreateVertexBuffer(LPD3DVERTEXBUFFERDESC lp, LPDIRECT3DVERTEXBUFFER* lplpvb, DWORD dw,LPUNKNOWN lpu)
{

	ASSERT(m_pDirect3D);
	if (m_pDirect3D3)
		return m_pDirect3D3->CreateVertexBuffer(lp, lplpvb, dw, lpu);
	else
		return E_FAIL;
	
}
#endif


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::EnumZBufferFormats(REFCLSID clsid, LPD3DENUMPIXELFORMATSCALLBACK lp, LPVOID lpv)
{
#ifndef USE_DX7_INTERFACE
	ASSERT(m_pDirect3D);
#endif

	if (clsid == IID_IDirect3DBladeDevice)
	{
		D3DDEVICEDESC	hal = {sizeof(hal)};
		D3DDEVICEDESC	hel = {sizeof(hel)};
		DDPIXELFORMAT	ddpf = {sizeof(ddpf)};

		CDirect3DDevice::Static_GetCaps(&hal, &hel);

		ddpf.dwSize				= sizeof(ddpf);
		ddpf.dwFlags			= DDPF_ZBUFFER;
		ddpf.dwFourCC			= 0;
		ddpf.dwZBufferBitDepth	= 16;
		ddpf.dwRBitMask			= 0;
		ddpf.dwZBitMask			= 0x0000FFFF;
		ddpf.dwBBitMask			= 0;
		ddpf.dwRGBZBitMask		= 0;

		if ((lp)(&ddpf, lpv) == DDENUMRET_CANCEL)
			return S_OK;
	}
	else if (m_pDirect3D3)
		return m_pDirect3D3->EnumZBufferFormats(clsid, lp, lpv);
	else
	{
		return E_FAIL;
	}

	return S_OK;
}


//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::EvictManagedTextures()
{
	ASSERT(m_pDirect3D);
	if (m_pDirect3D3)
		return m_pDirect3D3->EvictManagedTextures();
	else
		return E_FAIL;
}








//========================================================================
//========================================================================
CDirectDrawSurface * CDirectDraw::FindSurface(IDirectDrawSurface *dds)
{
	CDirectDrawSurface *p;
	p = m_pFirstSurface;

	while (p)
	{
		if (p->m_pDirectDrawSurface == dds)
			return p;
		p = p->m_pNextSurface;
	}

	return NULL;
}

//========================================================================
//========================================================================
HRESULT CDirectDraw::AddSurfaceToList(CDirectDrawSurface *surface)
{
	surface->m_pNextSurface = m_pFirstSurface;
	m_pFirstSurface = surface;

	return S_OK;
}

//========================================================================
//========================================================================
HRESULT CDirectDraw::RemoveSurfaceFromList(CDirectDrawSurface *surface)
{
	CDirectDrawSurface **pp;

	pp = &m_pFirstSurface;

	while (*pp)
	{
		if (*pp == surface)
		{
			*pp = surface->m_pNextSurface;
			surface->m_pNextSurface = NULL;
			return S_OK;
		}

		pp = &((*pp)->m_pNextSurface);
	}

	return -1;
}


#ifdef USE_DX7_INTERFACE
//STDMETHODIMP CDirectDraw::CreateSurface(LPDDSURFACEDESC2 ddsd, LPDIRECTDRAWSURFACE7 FAR *ppdds, IUnknown FAR *iu)
//{
//	ASSERT(0);
//	return E_FAIL;
//}

STDMETHODIMP CDirectDraw::DuplicateSurface(LPDIRECTDRAWSURFACE7 pdds, LPDIRECTDRAWSURFACE7 FAR * ppdds)
{
	ASSERT(0);
	return E_FAIL;
}

//STDMETHODIMP CDirectDraw::EnumSurfaces(DWORD dwFlags, LPDDSURFACEDESC2 pddsd, LPVOID lpContext, LPDDENUMSURFACESCALLBACK7 lpCallback)
//{
//	ASSERT(0);
//	return E_FAIL;
//}

//========================================================================
//========================================================================
STDMETHODIMP CDirectDraw::GetGDISurface(LPDIRECTDRAWSURFACE7 FAR *ppdds)
{
	ASSERT(m_pDirectDraw);
	if (!m_pDirectDraw4)
		return E_FAIL;

	return m_pDirectDraw4->GetGDISurface(ppdds);
}


STDMETHODIMP CDirectDraw::GetSurfaceFromDC(HDC hdc, LPDIRECTDRAWSURFACE7 *ppdds)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirectDraw::GetDeviceIdentifier(LPDDDEVICEIDENTIFIER2 di, DWORD dwFlags)
{
	ASSERT(m_pDirectDraw);
	if (m_pDirectDraw4)
	{
		HRESULT hr;
		IDirectDraw7 * pDirectDraw4 = NULL;

		if (FAILED(hr=m_pDirectDraw4->QueryInterface(IID_IDirectDraw7, (void **)&pDirectDraw4)))
			return hr;

		hr=pDirectDraw4->GetDeviceIdentifier(di, dwFlags);
		RELEASE(pDirectDraw4);
		return hr;
	}
	else
	{
		if (di)
		{
			strcpy(di->szDriver, "driver");
			strcpy(di->szDescription, "Windows NT Video Driver");
			*(__int64 *)&di->liDriverVersion = 1;
			di->dwVendorId = 0;
			di->dwDeviceId = 0;
			di->dwSubSysId = 0;
			di->dwRevision = 0;
			ZeroMemory(&di->guidDeviceIdentifier, sizeof(di->guidDeviceIdentifier));

			return S_OK;
		}

		return DDERR_INVALIDPARAMS;
	}
}

STDMETHODIMP CDirectDraw::StartModeTest(LPSIZE p, DWORD dwNumEntries, DWORD dwFlags)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirectDraw::EvaluateMode(DWORD dwFlags, DWORD *pSecondTilTimeout )
{
	ASSERT(0);
	return E_FAIL;
}
STDMETHODIMP CDirectDraw::CreateVertexBuffer(LPD3DVERTEXBUFFERDESC lpVBDesc, LPDIRECT3DVERTEXBUFFER7* lpD3DVertexBuffer, DWORD dwFlags)
{

	// make sure pointer is valid
	if (IsBadReadPtr((const void *)lpVBDesc, 4))
		return DDERR_INVALIDPARAMS;

	// make sure size is valid
	if (lpVBDesc->dwSize != sizeof(D3DVERTEXBUFFERDESC))
		return DDERR_INVALIDPARAMS;

	// make sure entire buffer is valid
	if (IsBadReadPtr((const void *)lpVBDesc, lpVBDesc->dwSize))
		return DDERR_INVALIDPARAMS;

	// make sure the FVF desired is one we support
	switch (lpVBDesc->dwFVF)
	{
	case D3DFVF_VERTEX:
//		dwVertexSize = sizeof(D3DVERTEX);
//		break;

	case D3DFVF_LVERTEX:
//		dwVertexSize = sizeof(D3DLVERTEX);
//		break;

	case D3DFVF_TLVERTEX:
//		dwVertexSize = sizeof(D3DTLVERTEX);
//		break;

	case (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1):
//		dwVertexSize = sizeof(D3DVALUE) * 5 + sizeof(D3DCOLOR) * 2;
//		break;

	case (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2):
//		dwVertexSize = sizeof(D3DVALUE) * 7 + sizeof(D3DCOLOR) * 2;
//		break;

	//
	// For Andy Glaister:
	// D3DFVF_XYZ			3 values
	// D3DFVF_XYZRHW		4 values
	// D3DFVF_DIFFUSE		1 color
	// D3DFVF_SPECULAR		1 color
	// D3DFVF_TEX1			2 values
	// D3DFVF_TEX2			4 values
	// D3DFVF_TEX3			6 values
	// D3DFVF_TEX4			8 values
	// D3DFVF_NORMAL		3 values
	// D3DFVF_XYZB1			4 values
	//
	case D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2:
//		dwVertexSize = sizeof(D3DVALUE) * 8 + sizeof(D3DCOLOR) * 2;
//		break;

	case D3DFVF_XYZ    | D3DFVF_NORMAL  | D3DFVF_TEX2:
//		dwVertexSize = sizeof(D3DVALUE) * 10 + sizeof(D3DCOLOR) * 0;
//		break;

	case D3DFVF_XYZB1  | D3DFVF_NORMAL  | D3DFVF_TEX1:
//		dwVertexSize = sizeof(D3DVALUE) * 9 + sizeof(D3DCOLOR) * 0;
//		break;

	case D3DFVF_XYZB1  | D3DFVF_NORMAL  | D3DFVF_TEX2:
//		dwVertexSize = sizeof(D3DVALUE) * 11 + sizeof(D3DCOLOR) * 0;
		break;

	default:
		return D3DERR_INVALIDVERTEXFORMAT;
	}


	CDirect3DVertexBuffer *	pVB = new CDirect3DVertexBuffer;
	if (!pVB)
	{
		// !TODO
		// memory allocation and/or constructor error!
		return DDERR_OUTOFMEMORY;
	}

	pVB->m_VBDesc		= *lpVBDesc;
	pVB->m_pOptimizedBuf= NULL;
	pVB->m_pRawBuf = NULL;


	HRESULT hRes = m_pDirect3D3->CreateVertexBuffer(lpVBDesc, &(pVB->m_pRawBuf), dwFlags);
	if(FAILED(hRes))
	{
		delete pVB;
		return DDERR_OUTOFMEMORY;
	}

	hRes = m_pDirect3D3->CreateVertexBuffer(lpVBDesc, &(pVB->m_pOptimizedBuf), dwFlags);

	if(FAILED(hRes))
	{
		pVB->m_pRawBuf->Release();
		delete pVB;
		return DDERR_OUTOFMEMORY;
	}

	*lpD3DVertexBuffer = (IDirect3DVertexBuffer7 *)pVB;
	//Add one to our own reference count...
	pVB->m_cRef++;

	pVB->m_bOptimized = false;

	return S_OK;

}

#endif


//JJ Fix-A-Roo

//Static members...
IDirect3DDevice7* CDirect3DDevice::s_pDeviceList[MAX_DEVICES] = {0};
int CDirect3DDevice::s_nDevCnt = 0;
/*
	This is the GetDXVB function that is exported in our DLL.  This should be called on all VertexBuffers being passed
	into an IDirect3DDevice7 method.
*/

LPDIRECT3DVERTEXBUFFER7 WINAPI GetDXVB(LPDIRECT3DVERTEXBUFFER7 pVBuf, LPDIRECT3DDEVICE7 pDevice)
{
	CDirect3DVertexBuffer* pVB = (CDirect3DVertexBuffer*)pVBuf;

	for(int i = 0; i < CDirect3DDevice::s_nDevCnt; i++)
	{
		if(CDirect3DDevice::s_pDeviceList[i] == pDevice)
			return pVB->m_pRawBuf;
	}
	if(pVB->m_bOptimized)
		return pVB->m_pOptimizedBuf;
	else
		return pVB->m_pRawBuf;
}
