text: /**
  * Copyright (C) 2019 Elisha Riedlinger
  *
  * This software is  provided 'as-is', without any express  or implied  warranty. In no event will the
  * authors be held liable for any damages arising from the use of this software.
  * Permission  is granted  to anyone  to use  this software  for  any  purpose,  including  commercial
  * applications, and to alter it and redistribute it freely, subject to the following restrictions:
  *
  *   1. The origin of this software must not be misrepresented; you must not claim that you  wrote the
  *      original  software. If you use this  software  in a product, an  acknowledgment in the product
  *      documentation would be appreciated but is not required.
  *   2. Altered source versions must  be plainly  marked as such, and  must not be  misrepresented  as
  *      being the original software.
  *   3. This notice may not be removed or altered from any source distribution.
  */
  
  #include "ddraw.h"
  
  HRESULT m_IDirect3DDeviceX::QueryInterface(REFIID riid, LPVOID * ppvObj, DWORD DirectXVersion)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		if ((riid == IID_IDirect3DDevice || riid == IID_IDirect3DDevice2 || riid == IID_IDirect3DDevice3 || riid == IID_IDirect3DDevice7 || riid == IID_IUnknown) && ppvObj)
  		{
  			DWORD DxVersion = (riid == IID_IUnknown) ? DirectXVersion : GetIIDVersion(riid);
  
  			*ppvObj = GetWrapperInterfaceX(DxVersion);
  
  			::AddRef(*ppvObj);
  
  			return D3D_OK;
  		}
  	}
  	return ProxyQueryInterface(ProxyInterface, riid, ppvObj, GetWrapperType(DirectXVersion), WrapperInterface);
  }
  
  void *m_IDirect3DDeviceX::GetWrapperInterfaceX(DWORD DirectXVersion)
  {
  	switch (DirectXVersion)
  	{
  	case 1:
  		if (!UniqueProxyInterface.get())
  		{
  			UniqueProxyInterface = std::make_unique<m_IDirect3DDevice>(this);
  		}
  		return UniqueProxyInterface.get();
  	case 2:
  		if (!UniqueProxyInterface2.get())
  		{
  			UniqueProxyInterface2 = std::make_unique<m_IDirect3DDevice2>(this);
  		}
  		return UniqueProxyInterface2.get();
  	case 3:
  		if (!UniqueProxyInterface3.get())
  		{
  			UniqueProxyInterface3 = std::make_unique<m_IDirect3DDevice3>(this);
  		}
  		return UniqueProxyInterface3.get();
  	case 7:
  		if (!UniqueProxyInterface7.get())
  		{
  			UniqueProxyInterface7 = std::make_unique<m_IDirect3DDevice7>(this);
  		}
  		return UniqueProxyInterface7.get();
  	default:
  		LOG_LIMIT(100, __FUNCTION__ << " Error: wrapper interface version not found: " << DirectXVersion);
  		return nullptr;
  	}
  }
  
  ULONG m_IDirect3DDeviceX::AddRef()
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		return InterlockedIncrement(&RefCount);
  	}
  
  	return ProxyInterface->AddRef();
  }
  
  ULONG m_IDirect3DDeviceX::Release()
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	ULONG ref;
  
  	if (Config.Dd7to9)
  	{
  		ref = InterlockedDecrement(&RefCount);
  	}
  	else
  	{
  		ref = ProxyInterface->Release();
  	}
  
  	if (ref == 0)
  	{
  		if (WrapperInterface)
  		{
  			WrapperInterface->DeleteMe();
  		}
  		else
  		{
  			delete this;
  		}
  	}
  
  	return ref;
  }
  
  HRESULT m_IDirect3DDeviceX::Initialize(LPDIRECT3D lpd3d, LPGUID lpGUID, LPD3DDEVICEDESC lpd3ddvdesc)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion != 1)
  	{
  		return D3D_OK;
  	}
  
  	if (lpd3d)
  	{
  		lpd3d = static_cast<m_IDirect3D *>(lpd3d)->GetProxyInterface();
  	}
  
  	return GetProxyInterfaceV1()->Initialize(lpd3d, lpGUID, lpd3ddvdesc);
  }
  
  HRESULT m_IDirect3DDeviceX::CreateExecuteBuffer(LPD3DEXECUTEBUFFERDESC lpDesc, LPDIRECT3DEXECUTEBUFFER * lplpDirect3DExecuteBuffer, IUnknown * pUnkOuter)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion != 1)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	HRESULT hr = GetProxyInterfaceV1()->CreateExecuteBuffer(lpDesc, lplpDirect3DExecuteBuffer, pUnkOuter);
  
  	if (SUCCEEDED(hr) && lplpDirect3DExecuteBuffer)
  	{
  		*lplpDirect3DExecuteBuffer = ProxyAddressLookupTable.FindAddress<m_IDirect3DExecuteBuffer>(*lplpDirect3DExecuteBuffer);
  	}
  
  	return hr;
  }
  
  HRESULT m_IDirect3DDeviceX::Execute(LPDIRECT3DEXECUTEBUFFER lpDirect3DExecuteBuffer, LPDIRECT3DVIEWPORT lpDirect3DViewport, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion != 1)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpDirect3DExecuteBuffer)
  	{
  		lpDirect3DExecuteBuffer = static_cast<m_IDirect3DExecuteBuffer *>(lpDirect3DExecuteBuffer)->GetProxyInterface();
  	}
  	if (lpDirect3DViewport)
  	{
  		lpDirect3DViewport = static_cast<m_IDirect3DViewport *>(lpDirect3DViewport)->GetProxyInterface();
  	}
  
  	return GetProxyInterfaceV1()->Execute(lpDirect3DExecuteBuffer, lpDirect3DViewport, dwFlags);
  }
  
  HRESULT m_IDirect3DDeviceX::Pick(LPDIRECT3DEXECUTEBUFFER lpDirect3DExecuteBuffer, LPDIRECT3DVIEWPORT lpDirect3DViewport, DWORD dwFlags, LPD3DRECT lpRect)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion != 1)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpDirect3DExecuteBuffer)
  	{
  		lpDirect3DExecuteBuffer = static_cast<m_IDirect3DExecuteBuffer *>(lpDirect3DExecuteBuffer)->GetProxyInterface();
  	}
  	if (lpDirect3DViewport)
  	{
  		lpDirect3DViewport = static_cast<m_IDirect3DViewport *>(lpDirect3DViewport)->GetProxyInterface();
  	}
  
  	return GetProxyInterfaceV1()->Pick(lpDirect3DExecuteBuffer, lpDirect3DViewport, dwFlags, lpRect);
  }
  
  HRESULT m_IDirect3DDeviceX::GetPickRecords(LPDWORD lpCount, LPD3DPICKRECORD lpD3DPickRec)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion != 1)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV1()->GetPickRecords(lpCount, lpD3DPickRec);
  }
  
  HRESULT m_IDirect3DDeviceX::CreateMatrix(LPD3DMATRIXHANDLE lpD3DMatHandle)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion != 1)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV1()->CreateMatrix(lpD3DMatHandle);
  }
  
  HRESULT m_IDirect3DDeviceX::SetMatrix(D3DMATRIXHANDLE d3dMatHandle, const LPD3DMATRIX lpD3DMatrix)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion != 1)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV1()->SetMatrix(d3dMatHandle, lpD3DMatrix);
  }
  
  HRESULT m_IDirect3DDeviceX::GetMatrix(D3DMATRIXHANDLE lpD3DMatHandle, LPD3DMATRIX lpD3DMatrix)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion != 1)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV1()->GetMatrix(lpD3DMatHandle, lpD3DMatrix);
  }
  
  HRESULT m_IDirect3DDeviceX::DeleteMatrix(D3DMATRIXHANDLE d3dMatHandle)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion != 1)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV1()->DeleteMatrix(d3dMatHandle);
  }
  
  HRESULT m_IDirect3DDeviceX::SwapTextureHandles(LPDIRECT3DTEXTURE2 lpD3DTex1, LPDIRECT3DTEXTURE2 lpD3DTex2)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 2)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpD3DTex1)
  	{
  		lpD3DTex1 = static_cast<m_IDirect3DTexture2 *>(lpD3DTex1)->GetProxyInterface();
  	}
  	if (lpD3DTex2)
  	{
  		lpD3DTex2 = static_cast<m_IDirect3DTexture2 *>(lpD3DTex2)->GetProxyInterface();
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		return GetProxyInterfaceV1()->SwapTextureHandles((LPDIRECT3DTEXTURE)lpD3DTex1, (LPDIRECT3DTEXTURE)lpD3DTex2);
  	case 2:
  		return GetProxyInterfaceV2()->SwapTextureHandles(lpD3DTex1, lpD3DTex2);
  	default:
  		return DDERR_GENERIC;
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::EnumTextureFormats(LPD3DENUMTEXTUREFORMATSCALLBACK lpd3dEnumTextureProc, LPVOID lpArg)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		return GetProxyInterfaceV1()->EnumTextureFormats(lpd3dEnumTextureProc, lpArg);
  	case 2:
  		return GetProxyInterfaceV2()->EnumTextureFormats(lpd3dEnumTextureProc, lpArg);
  	default:
  	case 3:
  		return DDERR_GENERIC;
  	case 7:
  	case 9:
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetCaps(LPD3DDEVICEDESC lpD3DHWDevDesc, LPD3DDEVICEDESC lpD3DHELDevDesc)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		return GetProxyInterfaceV1()->GetCaps(lpD3DHWDevDesc, lpD3DHELDevDesc);
  	case 2:
  		return GetProxyInterfaceV2()->GetCaps(lpD3DHWDevDesc, lpD3DHELDevDesc);
  	case 3:
  		return GetProxyInterfaceV3()->GetCaps(lpD3DHWDevDesc, lpD3DHELDevDesc);
  	case 7:
  	case 9:
  	{
  		D3DDEVICEDESC7 D3DDevDesc;
  		HRESULT hr = GetCaps(&D3DDevDesc);
  
  		if (SUCCEEDED(hr))
  		{
  			if (lpD3DHWDevDesc)
  			{
  				ConvertDeviceDesc(*lpD3DHWDevDesc, D3DDevDesc);
  			}
  
  			if (lpD3DHELDevDesc)
  			{
  				ConvertDeviceDesc(*lpD3DHELDevDesc, D3DDevDesc);
  			}
  		}
  
  		return hr;
  	}
  	default:
  		return DDERR_GENERIC;
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetStats(LPD3DSTATS lpD3DStats)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		return GetProxyInterfaceV1()->GetStats(lpD3DStats);
  	case 2:
  		return GetProxyInterfaceV2()->GetStats(lpD3DStats);
  	case 3:
  		return GetProxyInterfaceV3()->GetStats(lpD3DStats);
  	default:
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::AddViewport(LPDIRECT3DVIEWPORT3 lpDirect3DViewport)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9 || ProxyDirectXVersion == 7)
  	{
  		if (!lpDirect3DViewport)
  		{
  			return DDERR_INVALIDPARAMS;
  		}
  
  		D3DVIEWPORT Viewport;
  
  		// ToDo: Validate Viewport address
  		HRESULT hr = lpDirect3DViewport->GetViewport(&Viewport);
  
  		if (SUCCEEDED(hr))
  		{
  			D3DVIEWPORT7 Viewport7;
  
  			ConvertViewport(Viewport7, Viewport);
  
  			hr = SetViewport(&Viewport7);
  		}
  
  		return D3D_OK;
  	}
  
  	if (lpDirect3DViewport)
  	{
  		lpDirect3DViewport = static_cast<m_IDirect3DViewport3 *>(lpDirect3DViewport)->GetProxyInterface();
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		return GetProxyInterfaceV1()->AddViewport(lpDirect3DViewport);
  	case 2:
  		return GetProxyInterfaceV2()->AddViewport(lpDirect3DViewport);
  	case 3:
  		return GetProxyInterfaceV3()->AddViewport(lpDirect3DViewport);
  	default:
  		return DDERR_GENERIC;
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::DeleteViewport(LPDIRECT3DVIEWPORT3 lpDirect3DViewport)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpDirect3DViewport)
  	{
  		lpDirect3DViewport = static_cast<m_IDirect3DViewport3 *>(lpDirect3DViewport)->GetProxyInterface();
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		return GetProxyInterfaceV1()->DeleteViewport(lpDirect3DViewport);
  	case 2:
  		return GetProxyInterfaceV2()->DeleteViewport(lpDirect3DViewport);
  	case 3:
  		return GetProxyInterfaceV3()->DeleteViewport(lpDirect3DViewport);
  	default:
  		return DDERR_GENERIC;
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::NextViewport(LPDIRECT3DVIEWPORT3 lpDirect3DViewport, LPDIRECT3DVIEWPORT3 * lplpDirect3DViewport, DWORD dwFlags, DWORD DirectXVersion)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpDirect3DViewport)
  	{
  		lpDirect3DViewport = static_cast<m_IDirect3DViewport3 *>(lpDirect3DViewport)->GetProxyInterface();
  	}
  
  	HRESULT hr = DDERR_GENERIC;
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		hr = GetProxyInterfaceV1()->NextViewport(lpDirect3DViewport, (LPDIRECT3DVIEWPORT*)lplpDirect3DViewport, dwFlags);
  		break;
  	case 2:
  		hr = GetProxyInterfaceV2()->NextViewport(lpDirect3DViewport, (LPDIRECT3DVIEWPORT2*)lplpDirect3DViewport, dwFlags);
  		break;
  	case 3:
  		hr = GetProxyInterfaceV3()->NextViewport(lpDirect3DViewport, lplpDirect3DViewport, dwFlags);
  		break;
  	}
  
  	if (SUCCEEDED(hr) && lplpDirect3DViewport)
  	{
  		*lplpDirect3DViewport = ProxyAddressLookupTable.FindAddress<m_IDirect3DViewport3>(*lplpDirect3DViewport, DirectXVersion);
  	}
  
  	return hr;
  }
  
  HRESULT m_IDirect3DDeviceX::SetCurrentViewport(LPDIRECT3DVIEWPORT3 lpd3dViewport)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9 || ProxyDirectXVersion == 7)
  	{
  		// ToDo: Validate Viewport address
  		// ToDo: Increment Viewport ref count
  		lpCurrentViewport = (m_IDirect3DViewportX*)lpd3dViewport;
  
  		return D3D_OK;
  	}
  
  	if (lpd3dViewport)
  	{
  		lpd3dViewport = static_cast<m_IDirect3DViewport3 *>(lpd3dViewport)->GetProxyInterface();
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->SetCurrentViewport(lpd3dViewport);
  	case 3:
  		return GetProxyInterfaceV3()->SetCurrentViewport(lpd3dViewport);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetCurrentViewport(LPDIRECT3DVIEWPORT3 * lplpd3dViewport, DWORD DirectXVersion)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9 || ProxyDirectXVersion == 7)
  	{
  		if (lplpd3dViewport && lpCurrentViewport)
  		{
  			// ToDo: Validate current Viewport address
  			*lplpd3dViewport = (LPDIRECT3DVIEWPORT3)lpCurrentViewport;
  			return D3D_OK;
  		}
  		else if (!lpCurrentViewport)
  		{
  			return D3DERR_NOCURRENTVIEWPORT;
  		}
  
  		return DDERR_INVALIDPARAMS;
  	}
  
  	HRESULT hr = DDERR_GENERIC;
  
  	switch (ProxyDirectXVersion)
  	{
  	case 2:
  		hr = GetProxyInterfaceV2()->GetCurrentViewport((LPDIRECT3DVIEWPORT2*)lplpd3dViewport);
  		break;
  	case 3:
  		hr = GetProxyInterfaceV3()->GetCurrentViewport(lplpd3dViewport);
  		break;
  	}
  
  	if (SUCCEEDED(hr) && lplpd3dViewport)
  	{
  		*lplpd3dViewport = ProxyAddressLookupTable.FindAddress<m_IDirect3DViewport3>(*lplpd3dViewport, DirectXVersion);
  	}
  
  	return hr;
  }
  
  HRESULT m_IDirect3DDeviceX::Begin(D3DPRIMITIVETYPE d3dpt, DWORD d3dvt, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->Begin(d3dpt, (D3DVERTEXTYPE)d3dvt, dwFlags);
  	case 3:
  		return GetProxyInterfaceV3()->Begin(d3dpt, d3dvt, dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::BeginIndexed(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dvtVertexType, LPVOID lpvVertices, DWORD dwNumVertices, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->BeginIndexed(dptPrimitiveType, (D3DVERTEXTYPE)dvtVertexType, lpvVertices, dwNumVertices, dwFlags);
  	case 3:
  		return GetProxyInterfaceV3()->BeginIndexed(dptPrimitiveType, dvtVertexType, lpvVertices, dwNumVertices, dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::Vertex(LPVOID lpVertexType)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->Vertex(lpVertexType);
  	case 3:
  		return GetProxyInterfaceV3()->Vertex(lpVertexType);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::Index(WORD wVertexIndex)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->Index(wVertexIndex);
  	case 3:
  		return GetProxyInterfaceV3()->Index(wVertexIndex);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::End(DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->End(dwFlags);
  	case 3:
  		return GetProxyInterfaceV3()->End(dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetLightState(D3DLIGHTSTATETYPE dwLightStateType, LPDWORD lpdwLightState)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->GetLightState(dwLightStateType, lpdwLightState);
  	case 3:
  		return GetProxyInterfaceV3()->GetLightState(dwLightStateType, lpdwLightState);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::SetLightState(D3DLIGHTSTATETYPE dwLightStateType, DWORD dwLightState)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->SetLightState(dwLightStateType, dwLightState);
  	case 3:
  		return GetProxyInterfaceV3()->SetLightState(dwLightStateType, dwLightState);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetTexture(DWORD dwStage, LPDIRECT3DTEXTURE2 * lplpTexture, DWORD DirectXVersion)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (ProxyDirectXVersion > 3)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	HRESULT hr = GetProxyInterfaceV3()->GetTexture(dwStage, lplpTexture);
  
  	if (SUCCEEDED(hr) && lplpTexture)
  	{
  		*lplpTexture = ProxyAddressLookupTable.FindAddress<m_IDirect3DTexture2>(*lplpTexture, DirectXVersion);
  	}
  
  	return hr;
  }
  
  HRESULT m_IDirect3DDeviceX::SetTexture(DWORD dwStage, LPDIRECT3DTEXTURE2 lpTexture)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (ProxyDirectXVersion == 7)
  	{
  		// ToDo: Validate Texture address
  		if (lpTexture)
  		{
  			lpTexture = (((m_IDirect3DTextureX*)lpTexture)->GetProxyInterface());
  		}
  
  		return ProxyInterface->SetTexture(dwStage, (LPDIRECTDRAWSURFACE7)lpTexture);
  	}
  
  	if (lpTexture)
  	{
  		lpTexture = static_cast<m_IDirect3DTexture2 *>(lpTexture)->GetProxyInterface();
  	}
  
  	return GetProxyInterfaceV3()->SetTexture(dwStage, lpTexture);
  }
  
  HRESULT m_IDirect3DDeviceX::GetCaps(LPD3DDEVICEDESC7 lpD3DDevDesc)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->GetCaps(lpD3DDevDesc);
  }
  
  HRESULT m_IDirect3DDeviceX::EnumTextureFormats(LPD3DENUMPIXELFORMATSCALLBACK lpd3dEnumPixelProc, LPVOID lpArg)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	case 2:
  	default:
  		return DDERR_GENERIC;
  	case 3:
  		return GetProxyInterfaceV3()->EnumTextureFormats(lpd3dEnumPixelProc, lpArg);
  	case 7:
  		return GetProxyInterfaceV7()->EnumTextureFormats(lpd3dEnumPixelProc, lpArg);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::BeginScene()
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		return GetProxyInterfaceV1()->BeginScene();
  	case 2:
  		return GetProxyInterfaceV2()->BeginScene();
  	case 3:
  		return GetProxyInterfaceV3()->BeginScene();
  	case 7:
  		return GetProxyInterfaceV7()->BeginScene();
  	default:
  		return DDERR_GENERIC;
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::EndScene()
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		return GetProxyInterfaceV1()->EndScene();
  	case 2:
  		return GetProxyInterfaceV2()->EndScene();
  	case 3:
  		return GetProxyInterfaceV3()->EndScene();
  	case 7:
  		return GetProxyInterfaceV7()->EndScene();
  	default:
  		return DDERR_GENERIC;
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetDirect3D(LPDIRECT3D7 * lplpD3D, DWORD DirectXVersion)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		// Increment Direct3D ref count
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	HRESULT hr = DDERR_GENERIC;
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  		hr = GetProxyInterfaceV1()->GetDirect3D((LPDIRECT3D*)lplpD3D);
  		break;
  	case 2:
  		hr = GetProxyInterfaceV2()->GetDirect3D((LPDIRECT3D2*)lplpD3D);
  		break;
  	case 3:
  		hr = GetProxyInterfaceV3()->GetDirect3D((LPDIRECT3D3*)lplpD3D);
  		break;
  	case 7:
  		hr = GetProxyInterfaceV7()->GetDirect3D(lplpD3D);
  		break;
  	}
  
  	if (SUCCEEDED(hr) && lplpD3D)
  	{
  		*lplpD3D = ProxyAddressLookupTable.FindAddress<m_IDirect3D7>(*lplpD3D, DirectXVersion);
  	}
  
  	return hr;
  }
  
  HRESULT m_IDirect3DDeviceX::SetRenderTarget(LPDIRECTDRAWSURFACE7 lpNewRenderTarget, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpNewRenderTarget)
  	{
  		lpNewRenderTarget = static_cast<m_IDirectDrawSurface7 *>(lpNewRenderTarget)->GetProxyInterface();
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->SetRenderTarget((LPDIRECTDRAWSURFACE)lpNewRenderTarget, dwFlags);
  	case 3:
  		return GetProxyInterfaceV3()->SetRenderTarget((LPDIRECTDRAWSURFACE4)lpNewRenderTarget, dwFlags);
  	case 7:
  		return GetProxyInterfaceV7()->SetRenderTarget(lpNewRenderTarget, dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetRenderTarget(LPDIRECTDRAWSURFACE7 * lplpRenderTarget, DWORD DirectXVersion)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	HRESULT hr = DDERR_GENERIC;
  
  	switch (ProxyDirectXVersion)
  	{
  	case 2:
  		hr = GetProxyInterfaceV2()->GetRenderTarget((LPDIRECTDRAWSURFACE*)lplpRenderTarget);
  		break;
  	case 3:
  		hr = GetProxyInterfaceV3()->GetRenderTarget((LPDIRECTDRAWSURFACE4*)lplpRenderTarget);
  		break;
  	case 7:
  		hr = GetProxyInterfaceV7()->GetRenderTarget(lplpRenderTarget);
  		break;
  	}
  
  	if (SUCCEEDED(hr) && lplpRenderTarget)
  	{
  		*lplpRenderTarget = ProxyAddressLookupTable.FindAddress<m_IDirectDrawSurface7>(*lplpRenderTarget, DirectXVersion);
  	}
  
  	return hr;
  }
  
  HRESULT m_IDirect3DDeviceX::Clear(DWORD dwCount, LPD3DRECT lpRects, DWORD dwFlags, D3DCOLOR dwColor, D3DVALUE dvZ, DWORD dwStencil)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->Clear(dwCount, lpRects, dwFlags, dwColor, dvZ, dwStencil);
  }
  
  HRESULT m_IDirect3DDeviceX::SetTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->SetTransform(dtstTransformStateType, lpD3DMatrix);
  	case 3:
  		return GetProxyInterfaceV3()->SetTransform(dtstTransformStateType, lpD3DMatrix);
  	case 7:
  		return GetProxyInterfaceV7()->SetTransform(dtstTransformStateType, lpD3DMatrix);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->GetTransform(dtstTransformStateType, lpD3DMatrix);
  	case 3:
  		return GetProxyInterfaceV3()->GetTransform(dtstTransformStateType, lpD3DMatrix);
  	case 7:
  		return GetProxyInterfaceV7()->GetTransform(dtstTransformStateType, lpD3DMatrix);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::SetViewport(LPD3DVIEWPORT7 lpViewport)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->SetViewport(lpViewport);
  }
  
  HRESULT m_IDirect3DDeviceX::MultiplyTransform(D3DTRANSFORMSTATETYPE dtstTransformStateType, LPD3DMATRIX lpD3DMatrix)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->MultiplyTransform(dtstTransformStateType, lpD3DMatrix);
  	case 3:
  		return GetProxyInterfaceV3()->MultiplyTransform(dtstTransformStateType, lpD3DMatrix);
  	case 7:
  		return GetProxyInterfaceV7()->MultiplyTransform(dtstTransformStateType, lpD3DMatrix);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetViewport(LPD3DVIEWPORT7 lpViewport)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->GetViewport(lpViewport);
  }
  
  HRESULT m_IDirect3DDeviceX::SetMaterial(LPD3DMATERIAL7 lpMaterial)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->SetMaterial(lpMaterial);
  }
  
  HRESULT m_IDirect3DDeviceX::GetMaterial(LPD3DMATERIAL7 lpMaterial)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->GetMaterial(lpMaterial);
  }
  
  HRESULT m_IDirect3DDeviceX::SetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpLight)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->SetLight(dwLightIndex, lpLight);
  }
  
  HRESULT m_IDirect3DDeviceX::GetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpLight)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->GetLight(dwLightIndex, lpLight);
  }
  
  HRESULT m_IDirect3DDeviceX::SetRenderState(D3DRENDERSTATETYPE dwRendStateType, DWORD dwRenderState)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->SetRenderState(dwRendStateType, dwRenderState);
  	case 3:
  		return GetProxyInterfaceV3()->SetRenderState(dwRendStateType, dwRenderState);
  	case 7:
  		return GetProxyInterfaceV7()->SetRenderState(dwRendStateType, dwRenderState);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetRenderState(D3DRENDERSTATETYPE dwRenderStateType, LPDWORD lpdwRenderState)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->GetRenderState(dwRenderStateType, lpdwRenderState);
  	case 3:
  		return GetProxyInterfaceV3()->GetRenderState(dwRenderStateType, lpdwRenderState);
  	case 7:
  		return GetProxyInterfaceV7()->GetRenderState(dwRenderStateType, lpdwRenderState);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::BeginStateBlock()
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->BeginStateBlock();
  }
  
  HRESULT m_IDirect3DDeviceX::EndStateBlock(LPDWORD lpdwBlockHandle)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->EndStateBlock(lpdwBlockHandle);
  }
  
  HRESULT m_IDirect3DDeviceX::PreLoad(LPDIRECTDRAWSURFACE7 lpddsTexture)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpddsTexture)
  	{
  		lpddsTexture = static_cast<m_IDirectDrawSurface7 *>(lpddsTexture)->GetProxyInterface();
  	}
  
  	return GetProxyInterfaceV7()->PreLoad(lpddsTexture);
  }
  
  HRESULT m_IDirect3DDeviceX::DrawPrimitive(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPVOID lpVertices, DWORD dwVertexCount, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->DrawPrimitive(dptPrimitiveType, (D3DVERTEXTYPE)dwVertexTypeDesc, lpVertices, dwVertexCount, dwFlags);
  	case 3:
  		return GetProxyInterfaceV3()->DrawPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, dwFlags);
  	case 7:
  		return GetProxyInterfaceV7()->DrawPrimitive(dptPrimitiveType, dwVertexTypeDesc, lpVertices, dwVertexCount, dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitive(D3DPRIMITIVETYPE d3dptPrimitiveType, DWORD dwVertexTypeDesc, LPVOID lpvVertices, DWORD dwVertexCount, LPWORD lpwIndices, DWORD dwIndexCount, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->DrawIndexedPrimitive(d3dptPrimitiveType, (D3DVERTEXTYPE)dwVertexTypeDesc, lpvVertices, dwVertexCount, lpwIndices, dwIndexCount, dwFlags);
  	case 3:
  		return GetProxyInterfaceV3()->DrawIndexedPrimitive(d3dptPrimitiveType, dwVertexTypeDesc, lpvVertices, dwVertexCount, lpwIndices, dwIndexCount, dwFlags);
  	case 7:
  		return GetProxyInterfaceV7()->DrawIndexedPrimitive(d3dptPrimitiveType, dwVertexTypeDesc, lpvVertices, dwVertexCount, lpwIndices, dwIndexCount, dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::SetClipStatus(LPD3DCLIPSTATUS lpD3DClipStatus)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->SetClipStatus(lpD3DClipStatus);
  	case 3:
  		return GetProxyInterfaceV3()->SetClipStatus(lpD3DClipStatus);
  	case 7:
  		return GetProxyInterfaceV7()->SetClipStatus(lpD3DClipStatus);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetClipStatus(LPD3DCLIPSTATUS lpD3DClipStatus)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	default:
  		return DDERR_GENERIC;
  	case 2:
  		return GetProxyInterfaceV2()->GetClipStatus(lpD3DClipStatus);
  	case 3:
  		return GetProxyInterfaceV3()->GetClipStatus(lpD3DClipStatus);
  	case 7:
  		return GetProxyInterfaceV7()->GetClipStatus(lpD3DClipStatus);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::DrawPrimitiveStrided(D3DPRIMITIVETYPE dptPrimitiveType, DWORD dwVertexTypeDesc, LPD3DDRAWPRIMITIVESTRIDEDDATA lpVertexArray, DWORD dwVertexCount, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	case 2:
  	default:
  		return DDERR_GENERIC;
  	case 3:
  		return GetProxyInterfaceV3()->DrawPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, dwFlags);
  	case 7:
  		return GetProxyInterfaceV7()->DrawPrimitiveStrided(dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitiveStrided(D3DPRIMITIVETYPE d3dptPrimitiveType, DWORD dwVertexTypeDesc, LPD3DDRAWPRIMITIVESTRIDEDDATA lpVertexArray, DWORD dwVertexCount, LPWORD lpwIndices, DWORD dwIndexCount, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	case 2:
  	default:
  		return DDERR_GENERIC;
  	case 3:
  		return GetProxyInterfaceV3()->DrawIndexedPrimitiveStrided(d3dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, lpwIndices, dwIndexCount, dwFlags);
  	case 7:
  		return GetProxyInterfaceV7()->DrawIndexedPrimitiveStrided(d3dptPrimitiveType, dwVertexTypeDesc, lpVertexArray, dwVertexCount, lpwIndices, dwIndexCount, dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::DrawPrimitiveVB(D3DPRIMITIVETYPE d3dptPrimitiveType, LPDIRECT3DVERTEXBUFFER7 lpd3dVertexBuffer, DWORD dwStartVertex, DWORD dwNumVertices, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpd3dVertexBuffer)
  	{
  		lpd3dVertexBuffer = static_cast<m_IDirect3DVertexBuffer7 *>(lpd3dVertexBuffer)->GetProxyInterface();
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	case 2:
  	default:
  		return DDERR_GENERIC;
  	case 3:
  		return GetProxyInterfaceV3()->DrawPrimitiveVB(d3dptPrimitiveType, (LPDIRECT3DVERTEXBUFFER)lpd3dVertexBuffer, dwStartVertex, dwNumVertices, dwFlags);
  	case 7:
  		return GetProxyInterfaceV7()->DrawPrimitiveVB(d3dptPrimitiveType, lpd3dVertexBuffer, dwStartVertex, dwNumVertices, dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::DrawIndexedPrimitiveVB(D3DPRIMITIVETYPE d3dptPrimitiveType, LPDIRECT3DVERTEXBUFFER7 lpd3dVertexBuffer, DWORD dwStartVertex, DWORD dwNumVertices, LPWORD lpwIndices, DWORD dwIndexCount, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpd3dVertexBuffer)
  	{
  		lpd3dVertexBuffer = static_cast<m_IDirect3DVertexBuffer7 *>(lpd3dVertexBuffer)->GetProxyInterface();
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	case 2:
  	default:
  		return DDERR_GENERIC;
  	case 3:
  		return GetProxyInterfaceV3()->DrawIndexedPrimitiveVB(d3dptPrimitiveType, (LPDIRECT3DVERTEXBUFFER)lpd3dVertexBuffer, lpwIndices, dwIndexCount, dwFlags);
  	case 7:
  		return GetProxyInterfaceV7()->DrawIndexedPrimitiveVB(d3dptPrimitiveType, lpd3dVertexBuffer, dwStartVertex, dwNumVertices, lpwIndices, dwIndexCount, dwFlags);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::ComputeSphereVisibility(LPD3DVECTOR lpCenters, LPD3DVALUE lpRadii, DWORD dwNumSpheres, DWORD dwFlags, LPDWORD lpdwReturnValues)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	case 2:
  	default:
  		return DDERR_GENERIC;
  	case 3:
  		return GetProxyInterfaceV3()->ComputeSphereVisibility(lpCenters, lpRadii, dwNumSpheres, dwFlags, lpdwReturnValues);
  	case 7:
  		return GetProxyInterfaceV7()->ComputeSphereVisibility(lpCenters, lpRadii, dwNumSpheres, dwFlags, lpdwReturnValues);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::GetTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7 * lplpTexture, DWORD DirectXVersion)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	HRESULT hr = GetProxyInterfaceV7()->GetTexture(dwStage, lplpTexture);
  
  	if (SUCCEEDED(hr) && lplpTexture)
  	{
  		*lplpTexture = ProxyAddressLookupTable.FindAddress<m_IDirectDrawSurface7>(*lplpTexture, DirectXVersion);
  	}
  
  	return hr;
  }
  
  HRESULT m_IDirect3DDeviceX::SetTexture(DWORD dwStage, LPDIRECTDRAWSURFACE7 lpTexture)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpTexture)
  	{
  		lpTexture = static_cast<m_IDirectDrawSurface7 *>(lpTexture)->GetProxyInterface();
  	}
  
  	return GetProxyInterfaceV7()->SetTexture(dwStage, lpTexture);
  }
  
  HRESULT m_IDirect3DDeviceX::GetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, LPDWORD lpdwValue)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	case 2:
  	default:
  		return DDERR_GENERIC;
  	case 3:
  		return GetProxyInterfaceV3()->GetTextureStageState(dwStage, dwState, lpdwValue);
  	case 7:
  		return GetProxyInterfaceV7()->GetTextureStageState(dwStage, dwState, lpdwValue);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::SetTextureStageState(DWORD dwStage, D3DTEXTURESTAGESTATETYPE dwState, DWORD dwValue)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	case 2:
  	default:
  		return DDERR_GENERIC;
  	case 3:
  		return GetProxyInterfaceV3()->SetTextureStageState(dwStage, dwState, dwValue);
  	case 7:
  		return GetProxyInterfaceV7()->SetTextureStageState(dwStage, dwState, dwValue);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::ValidateDevice(LPDWORD lpdwPasses)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	switch (ProxyDirectXVersion)
  	{
  	case 1:
  	case 2:
  	default:
  		return DDERR_GENERIC;
  	case 3:
  		return GetProxyInterfaceV3()->ValidateDevice(lpdwPasses);
  	case 7:
  		return GetProxyInterfaceV7()->ValidateDevice(lpdwPasses);
  	}
  }
  
  HRESULT m_IDirect3DDeviceX::ApplyStateBlock(DWORD dwBlockHandle)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->ApplyStateBlock(dwBlockHandle);
  }
  
  HRESULT m_IDirect3DDeviceX::CaptureStateBlock(DWORD dwBlockHandle)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->CaptureStateBlock(dwBlockHandle);
  }
  
  HRESULT m_IDirect3DDeviceX::DeleteStateBlock(DWORD dwBlockHandle)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->DeleteStateBlock(dwBlockHandle);
  }
  
  HRESULT m_IDirect3DDeviceX::CreateStateBlock(D3DSTATEBLOCKTYPE d3dsbtype, LPDWORD lpdwBlockHandle)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->CreateStateBlock(d3dsbtype, lpdwBlockHandle);
  }
  
  HRESULT m_IDirect3DDeviceX::Load(LPDIRECTDRAWSURFACE7 lpDestTex, LPPOINT lpDestPoint, LPDIRECTDRAWSURFACE7 lpSrcTex, LPRECT lprcSrcRect, DWORD dwFlags)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	if (lpDestTex)
  	{
  		lpDestTex = static_cast<m_IDirectDrawSurface7 *>(lpDestTex)->GetProxyInterface();
  	}
  	if (lpSrcTex)
  	{
  		lpSrcTex = static_cast<m_IDirectDrawSurface7 *>(lpSrcTex)->GetProxyInterface();
  	}
  
  	return GetProxyInterfaceV7()->Load(lpDestTex, lpDestPoint, lpSrcTex, lprcSrcRect, dwFlags);
  }
  
  HRESULT m_IDirect3DDeviceX::LightEnable(DWORD dwLightIndex, BOOL bEnable)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->LightEnable(dwLightIndex, bEnable);
  }
  
  HRESULT m_IDirect3DDeviceX::GetLightEnable(DWORD dwLightIndex, BOOL * pbEnable)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->GetLightEnable(dwLightIndex, pbEnable);
  }
  
  HRESULT m_IDirect3DDeviceX::SetClipPlane(DWORD dwIndex, D3DVALUE * pPlaneEquation)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->SetClipPlane(dwIndex, pPlaneEquation);
  }
  
  HRESULT m_IDirect3DDeviceX::GetClipPlane(DWORD dwIndex, D3DVALUE * pPlaneEquation)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->GetClipPlane(dwIndex, pPlaneEquation);
  }
  
  HRESULT m_IDirect3DDeviceX::GetInfo(DWORD dwDevInfoID, LPVOID pDevInfoStruct, DWORD dwSize)
  {
  	Logging::LogDebug() << __FUNCTION__ << " (" << this << ")";
  
  	if (Config.Dd7to9)
  	{
  		LOG_LIMIT(100, __FUNCTION__ << " Not Implemented");
  		return DDERR_UNSUPPORTED;
  	}
  
  	return GetProxyInterfaceV7()->GetInfo(dwDevInfoID, pDevInfoStruct, dwSize);
  }
  
  void m_IDirect3DDeviceX::ReleaseInterface()
  {
  	SetCriticalSection();
  	if (ddrawParent)
  	{
  		ddrawParent->ClearD3DDevice();
  	}
  	ReleaseCriticalSection();
  }
  