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

#include <windows.h>
#include <ddraw.h>
#define D3D_OVERLOADS
#include <d3d.h>
#include <assert.h>
#include "softm.h"
#ifdef MLYONS
//#include <mjl.h>
#endif
#include "globals.h"
#include "smddraw.h"
#include "smd3d.h"
#include "raster.h"

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

#define APPLY_VIEWPORT_FIX_BUT_OPTIMIZE_THIS_SOMETIME

#define SOFTWARE_DEVICE_INITIALIZED 1
#define SOFTWARE_DEVICE_IN_SCENE	2

#define ERRORMSG(sz)    \
	OutputDebugString(sz "\r\n");	\
	ASSERT(0 && sz);

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

// Flags indicating changed matricies.
#define XFM_WORLD_MATRIX_CHANGED            0x000000001
#define XFM_VIEW_MATRIX_CHANGED             0x000000002
#define XFM_PROJECTION_MATRIX_CHANGED       0x000000004
#define XFM_CLIP_MATRIX_CHANGED             0x000000008
#define XFM_INVCLIP_MATRIX_CHANGED          0x000000010

#define XFM_MATRIX_CHANGED_MASK             0x00000001F

// Combinations of the above flags.
#define XFM_PC_MATRIX_CHANGED   (XFM_CLIP_MATRIX_CHANGED | XFM_PROJECTION_MATRIX_CHANGED)
#define XFM_VPC_MATRIX_CHANGED  (XFM_CLIP_MATRIX_CHANGED | XFM_PROJECTION_MATRIX_CHANGED | XFM_VIEW_MATRIX_CHANGED)
#define XFM_WVPC_MATRIX_CHANGED (XFM_CLIP_MATRIX_CHANGED | XFM_PROJECTION_MATRIX_CHANGED | XFM_VIEW_MATRIX_CHANGED | XFM_WORLD_MATRIX_CHANGED)

// Flags indicating transformation optimizations.
#define XFM_PROJECTION_IS_PERSPECTIVE		0x000000020

// Flags for lighting
#define XFM_LIGHT_POS_CHANGED				0x000001000
#define XFM_LIGHT_AMBIENT_ONLY				0x000002000
#define XFM_LIGHT_RECALC					0x000004000

__forceinline DWORD CheckClipCodes(GRFCLIPVERTEX * pcv1, GRFCLIPVERTEX * pcv2)
{
	DWORD dwFlags = 0;

	if((pcv1->hx > pcv1->hw) || (pcv2->hx > pcv2->hw))
		dwFlags |= CLIP_SIDE_RIGHT;

	if((pcv1->hx < 0) || (pcv2->hx < 0))
		dwFlags |= CLIP_SIDE_LEFT;

	if((pcv1->hy > pcv1->hw) || (pcv2->hy > pcv2->hw))
		dwFlags |= CLIP_SIDE_BOTTOM;

	if((pcv1->hy < 0) || (pcv2->hy < 0))
		dwFlags |= CLIP_SIDE_TOP;

	return dwFlags;
}

__forceinline DWORD CheckClipCodesTri(GRFCLIPVERTEX** pcv, int nVertexCount)
{
	register GRFCLIPVERTEX** pCurV = pcv;

	--nVertexCount;

	do
	{
		if(pCurV[0]->hx > pCurV[0]->hw)
			return CLIP_SIDE_RIGHT;

		pCurV++;
	}
	while(nVertexCount--);

	return 0;
}

//========================================================================
//========================================================================
#ifdef _DEBUG
	static HRESULT NotImpl()
	{
		OutputDebugString("BLADE: **** WARNING returing E_NOTIMPL\r\n");
		//DebugBreak();
		return E_NOTIMPL;
	}
	#undef  E_NOTIMPL
	#define E_NOTIMPL	NotImpl()
#endif

//========================================================================
// material
//========================================================================
STDMETHODIMP CDirect3DMaterial::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
    if (IID_IUnknown == riid)
    {
        AddRef();
        *ppvObj = (void*)(IUnknown*)this;
        return S_OK;
    }
    else if (IID_IDirect3DMaterial3 == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirect3DMaterial3 *)this;
        return S_OK;
    }
    else
    {
        *ppvObj = NULL;
        return E_FAIL;
    }
}

ULONG CDirect3DMaterial::AddRef(void)
{
    return ++m_cRef;
}

ULONG CDirect3DMaterial::Release(void)
{
    if (--m_cRef == 0)
    {
        delete this;
        return 0;
    }
    return m_cRef;
}

/*** IDirect3DMaterial3 methods ***/
STDMETHODIMP CDirect3DMaterial::SetMaterial(D3DMATERIAL*pmat)
{
    m_mat = *pmat;
    return S_OK;
}

STDMETHODIMP CDirect3DMaterial::GetMaterial(D3DMATERIAL*pmat)
{
    *pmat = m_mat;
    return S_OK;
}

STDMETHODIMP CDirect3DMaterial::GetHandle(LPDIRECT3DDEVICE3 dev,LPD3DMATERIALHANDLE pHandle)
{
    *pHandle = (D3DMATERIALHANDLE)&m_mat;
    return S_OK;
}

//========================================================================
// light
//========================================================================
STDMETHODIMP CDirect3DLight::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
    if (IID_IUnknown == riid)
    {
        AddRef();
        *ppvObj = (void*)(IUnknown*)this;
        return S_OK;
    }
    else if (IID_IDirect3DLight == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirect3DLight *)this;
        return S_OK;
    }
    else
    {
        *ppvObj = NULL;
        return E_FAIL;
    }
}

ULONG CDirect3DLight::AddRef(void)
{
    return ++m_cRef;
}

ULONG CDirect3DLight::Release(void)
{
    if (--m_cRef == 0)
    {
        delete this;
        return 0;
    }
    return m_cRef;
}

/*** IDirect3DLight methods ***/
STDMETHODIMP CDirect3DLight::Initialize(LPDIRECT3D)
{
    return E_NOTIMPL;
}

STDMETHODIMP CDirect3DLight::SetLight(LPD3DLIGHT pLight)
{
    CopyMemory(&m_light, pLight, min(pLight->dwSize, sizeof(m_light)));
    return S_OK;
}

STDMETHODIMP CDirect3DLight::GetLight(LPD3DLIGHT pLight)
{
    CopyMemory(pLight, &m_light, min(pLight->dwSize, sizeof(m_light)));
    return S_OK;
}

//========================================================================
//========================================================================
HRESULT CDirect3DDevice::Static_GetCaps(D3DDEVICEDESC *pHAL, D3DDEVICEDESC *pHEL)
{
	//
	// make sure the structures are valid
	//
	if (IsBadWritePtr(pHAL, sizeof(*pHAL)))
		return DDERR_INVALIDPARAMS;
	if (IsBadWritePtr(pHEL, sizeof(*pHEL)))
		return DDERR_INVALIDPARAMS;
	if (pHAL->dwSize < sizeof(*pHAL))
		return DDERR_INVALIDPARAMS;
	if (pHEL->dwSize < sizeof(*pHEL))
		return DDERR_INVALIDPARAMS;

	ZeroMemory(pHAL, sizeof(*pHAL));
	ZeroMemory(pHEL, sizeof(*pHEL));

	pHAL->dwSize							= sizeof(*pHAL);
	pHEL->dwSize							= sizeof(*pHEL);
	pHEL->dwFlags							|= D3DDD_BCLIPPING;
	pHEL->dwFlags							|= D3DDD_COLORMODEL;
	pHEL->dwFlags							|= D3DDD_DEVCAPS;
	pHEL->dwFlags							|= D3DDD_DEVICERENDERBITDEPTH;
	pHEL->dwFlags							|= D3DDD_DEVICEZBUFFERBITDEPTH;
	pHEL->dwFlags							|= D3DDD_LIGHTINGCAPS;
	pHEL->dwFlags							|= D3DDD_LINECAPS;
	pHEL->dwFlags							|= D3DDD_MAXBUFFERSIZE;
	pHEL->dwFlags							|= D3DDD_MAXVERTEXCOUNT;
	pHEL->dwFlags							|= D3DDD_TRANSFORMCAPS;
	pHEL->dwFlags							|= D3DDD_TRICAPS;
	pHEL->dcmColorModel						|= D3DCOLOR_MONO;
//	pHEL->dcmColorModel						|= D3DCOLOR_RGB;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_CANRENDERAFTERFLIP;
	pHEL->dwDevCaps							|= D3DDEVCAPS_DRAWPRIMTLVERTEX;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_EXECUTESYSTEMMEMORY;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_EXECUTEVIDEOMEMORY;
	pHEL->dwDevCaps							|= D3DDEVCAPS_FLOATTLVERTEX;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_SEPARATETEXTUREMEMORIES;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_SORTDECREASINGZ;
	pHEL->dwDevCaps							|= D3DDEVCAPS_SORTEXACT;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_SORTINCREASINGZ;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_TEXREPEATNOTSCALEDBYSIZE;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_TEXTURENONLOCALVIDMEM;
	pHEL->dwDevCaps							|= D3DDEVCAPS_TEXTURESYSTEMMEMORY;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_TEXTUREVIDEOMEMORY;
	pHEL->dwDevCaps							|= D3DDEVCAPS_TLVERTEXSYSTEMMEMORY;
//	pHEL->dwDevCaps							|= D3DDEVCAPS_TLVERTEXVIDEOMEMORY;
	pHEL->dtcTransformCaps.dwSize			= sizeof(pHEL->dtcTransformCaps);
	pHEL->dtcTransformCaps.dwCaps			|= D3DTRANSFORMCAPS_CLIP;
	pHEL->bClipping							= FALSE;
	pHEL->dlcLightingCaps.dwSize			= sizeof(pHEL->dlcLightingCaps);
//	pHEL->dlcLightingCaps.dwCaps			|= D3DLIGHTCAPS_DIRECTIONAL;
//	pHEL->dlcLightingCaps.dwCaps			|= D3DLIGHTCAPS_GLSPOT;
//	pHEL->dlcLightingCaps.dwCaps			|= D3DLIGHTCAPS_PARALLELPOINT;
//	pHEL->dlcLightingCaps.dwCaps			|= D3DLIGHTCAPS_SPOT;
	pHEL->dlcLightingCaps.dwLightingModel	|= D3DLIGHTINGMODEL_MONO;
//	pHEL->dlcLightingCaps.dwLightingModel	|= D3DLIGHTINGMODEL_RGB;
	pHEL->dlcLightingCaps.dwNumLights		= 1;
	pHEL->dpcLineCaps.dwSize				= sizeof(pHEL->dpcLineCaps);
//	pHEL->dpcLineCaps.dwMiscCaps			|= D3DPMISCCAPS_CONFORMANT;
//	pHEL->dpcLineCaps.dwMiscCaps			|= D3DPMISCCAPS_CULLCCW;
//	pHEL->dpcLineCaps.dwMiscCaps			|= D3DPMISCCAPS_CULLCW;
//	pHEL->dpcLineCaps.dwMiscCaps			|= D3DPMISCCAPS_CULLNONE;
//	pHEL->dpcLineCaps.dwMiscCaps			|= D3DPMISCCAPS_LINEPATTERNREP;
//	pHEL->dpcLineCaps.dwMiscCaps			|= D3DPMISCCAPS_MASKPLANES;
//	pHEL->dpcLineCaps.dwMiscCaps			|= D3DPMISCCAPS_MASKZ;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_ANISOTROPY;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_ANTIALIASEDGES;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_DITHER;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_FOGRANGE;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_FOGTABLE;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_FOGVERTEX;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_MIPMAPLODBIAS;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_PAT;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_ROP2;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_STIPPLE;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_SUBPIXEL;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_SUBPIXELX;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_WBUFFER;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_WFOG;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_XOR;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_ZBIAS;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_ZBUFFERLESSHSR;
//	pHEL->dpcLineCaps.dwRasterCaps			|= D3DPRASTERCAPS_ZTEST;
	pHEL->dpcLineCaps.dwZCmpCaps			|= D3DPCMPCAPS_ALWAYS;
//	pHEL->dpcLineCaps.dwZCmpCaps			|= D3DPCMPCAPS_EQUAL;
//	pHEL->dpcLineCaps.dwZCmpCaps			|= D3DPCMPCAPS_GREATER;
//	pHEL->dpcLineCaps.dwZCmpCaps			|= D3DPCMPCAPS_GREATEREQUAL;
//	pHEL->dpcLineCaps.dwZCmpCaps			|= D3DPCMPCAPS_LESS;
//	pHEL->dpcLineCaps.dwZCmpCaps			|= D3DPCMPCAPS_LESSEQUAL;
//	pHEL->dpcLineCaps.dwZCmpCaps			|= D3DPCMPCAPS_NEVER;
//	pHEL->dpcLineCaps.dwZCmpCaps			|= D3DPCMPCAPS_NOTEQUAL;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_BOTHINVSRCALPHA;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_BOTHSRCALPHA;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_DESTALPHA;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_DESTCOLOR;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_INVDESTALPHA;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_INVDESTCOLOR;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_INVSRCALPHA;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_INVSRCCOLOR;
	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_ONE;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_SRCALPHA;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_SRCALPHASAT;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_SRCCOLOR;
//	pHEL->dpcLineCaps.dwSrcBlendCaps		|= D3DPBLENDCAPS_ZERO;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_BOTHINVSRCALPHA;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_BOTHSRCALPHA;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_DESTALPHA;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_DESTCOLOR;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_INVDESTALPHA;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_INVDESTCOLOR;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_INVSRCALPHA;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_INVSRCCOLOR;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_ONE;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_SRCALPHA;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_SRCALPHASAT;
//	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_SRCCOLOR;
	pHEL->dpcLineCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_ZERO;
//	pHEL->dpcLineCaps.dwAlphaCmpCaps		|= D3DPCMPCAPS_ALWAYS;
//	pHEL->dpcLineCaps.dwAlphaCmpCaps		|= D3DPCMPCAPS_EQUAL;
//	pHEL->dpcLineCaps.dwAlphaCmpCaps		|= D3DPCMPCAPS_GREATER;
//	pHEL->dpcLineCaps.dwAlphaCmpCaps		|= D3DPCMPCAPS_GREATEREQUAL;
//	pHEL->dpcLineCaps.dwAlphaCmpCaps		|= D3DPCMPCAPS_LESS;
//	pHEL->dpcLineCaps.dwAlphaCmpCaps		|= D3DPCMPCAPS_LESSEQUAL;
//	pHEL->dpcLineCaps.dwAlphaCmpCaps		|= D3DPCMPCAPS_NEVER;
//	pHEL->dpcLineCaps.dwAlphaCmpCaps		|= D3DPCMPCAPS_NOTEQUAL;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORFLATMONO;
	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORFLATRGB;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORGOURAUDMONO;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORGOURAUDRGB;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORPHONGMONO;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORPHONGRGB;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARFLATMONO;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARFLATRGB;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARGOURAUDMONO;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARGOURAUDRGB;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARPHONGMONO;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARPHONGRGB;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAFLATBLEND;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAFLATSTIPPLED;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAGOURAUDBLEND;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAPHONGBLEND;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAPHONGSTIPPLED;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_FOGFLAT;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_FOGGOURAUD;
//	pHEL->dpcLineCaps.dwShadeCaps			|= D3DPSHADECAPS_FOGPHONG;
//	pHEL->dpcLineCaps.dwTextureCaps			|= D3DPTEXTURECAPS_PERSPECTIVE;
//	pHEL->dpcLineCaps.dwTextureCaps			|= D3DPTEXTURECAPS_POW2;
//	pHEL->dpcLineCaps.dwTextureCaps			|= D3DPTEXTURECAPS_ALPHA;
//	pHEL->dpcLineCaps.dwTextureCaps			|= D3DPTEXTURECAPS_TRANSPARENCY;
//	pHEL->dpcLineCaps.dwTextureCaps			|= D3DPTEXTURECAPS_BORDER;
//	pHEL->dpcLineCaps.dwTextureCaps			|= D3DPTEXTURECAPS_SQUAREONLY;
	pHEL->dpcLineCaps.dwTextureCaps			|= D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE;
//	pHEL->dpcLineCaps.dwTextureCaps			|= D3DPTEXTURECAPS_ALPHAPALETTE;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_NEAREST;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_LINEAR;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MIPNEAREST;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MIPLINEAR;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_LINEARMIPNEAREST;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_LINEARMIPLINEAR;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MINFPOINT;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MINFLINEAR;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MINFANISOTROPIC;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MIPFPOINT;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MIPFLINEAR;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFPOINT;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFLINEAR;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFANISOTROPIC;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFAFLATCUBIC;
//	pHEL->dpcLineCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC;
//	pHEL->dpcLineCaps.dwTextureBlendCaps	|= D3DPTBLENDCAPS_DECAL;
	pHEL->dpcLineCaps.dwTextureBlendCaps	|= D3DPTBLENDCAPS_MODULATE;
//	pHEL->dpcLineCaps.dwTextureBlendCaps	|= D3DPTBLENDCAPS_DECALALPHA;
//	pHEL->dpcLineCaps.dwTextureBlendCaps	|= D3DPTBLENDCAPS_MODULATEALPHA;
//	pHEL->dpcLineCaps.dwTextureBlendCaps	|= D3DPTBLENDCAPS_DECALMASK;
//	pHEL->dpcLineCaps.dwTextureBlendCaps	|= D3DPTBLENDCAPS_MODULATEMASK;
//	pHEL->dpcLineCaps.dwTextureBlendCaps	|= D3DPTBLENDCAPS_COPY;
//	pHEL->dpcLineCaps.dwTextureBlendCaps	|= D3DPTBLENDCAPS_ADD;
//	pHEL->dpcLineCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_WRAP;
//	pHEL->dpcLineCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_MIRROR;
//	pHEL->dpcLineCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_CLAMP;
//	pHEL->dpcLineCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_BORDER;
//	pHEL->dpcLineCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_INDEPENDENTUV;
	pHEL->dpcLineCaps.dwStippleWidth		= 0;
	pHEL->dpcLineCaps.dwStippleHeight		= 0;
	pHEL->dpcTriCaps.dwSize					= sizeof(pHEL->dpcTriCaps);
//	pHEL->dpcTriCaps.dwMiscCaps				|= D3DPMISCCAPS_CONFORMANT;
	pHEL->dpcTriCaps.dwMiscCaps				|= D3DPMISCCAPS_CULLCCW;
	pHEL->dpcTriCaps.dwMiscCaps				|= D3DPMISCCAPS_CULLCW;
	pHEL->dpcTriCaps.dwMiscCaps				|= D3DPMISCCAPS_CULLNONE;
//	pHEL->dpcTriCaps.dwMiscCaps				|= D3DPMISCCAPS_LINEPATTERNREP;
//	pHEL->dpcTriCaps.dwMiscCaps				|= D3DPMISCCAPS_MASKPLANES;
//	pHEL->dpcTriCaps.dwMiscCaps				|= D3DPMISCCAPS_MASKZ;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_ANISOTROPY;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_ANTIALIASEDGES;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_DITHER;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_FOGRANGE;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_FOGTABLE;
	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_FOGVERTEX;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_MIPMAPLODBIAS;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_PAT;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_ROP2;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_STIPPLE;
	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_SUBPIXEL;
	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_SUBPIXELX;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_WBUFFER;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_WFOG;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_XOR;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_ZBIAS;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_ZBUFFERLESSHSR;
//	pHEL->dpcTriCaps.dwRasterCaps			|= D3DPRASTERCAPS_ZTEST;
	pHEL->dpcTriCaps.dwZCmpCaps				|= D3DPCMPCAPS_ALWAYS;
//	pHEL->dpcTriCaps.dwZCmpCaps				|= D3DPCMPCAPS_EQUAL;
//	pHEL->dpcTriCaps.dwZCmpCaps				|= D3DPCMPCAPS_GREATER;
//	pHEL->dpcTriCaps.dwZCmpCaps				|= D3DPCMPCAPS_GREATEREQUAL;
//	pHEL->dpcTriCaps.dwZCmpCaps				|= D3DPCMPCAPS_LESS;
	pHEL->dpcTriCaps.dwZCmpCaps				|= D3DPCMPCAPS_LESSEQUAL;
//	pHEL->dpcTriCaps.dwZCmpCaps				|= D3DPCMPCAPS_NEVER;
//	pHEL->dpcTriCaps.dwZCmpCaps				|= D3DPCMPCAPS_NOTEQUAL;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_BOTHINVSRCALPHA;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_BOTHSRCALPHA;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_DESTALPHA;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_DESTCOLOR;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_INVDESTALPHA;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_INVDESTCOLOR;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_INVSRCALPHA;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_INVSRCCOLOR;
	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_ONE;
	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_SRCALPHA;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_SRCALPHASAT;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_SRCCOLOR;
//	pHEL->dpcTriCaps.dwSrcBlendCaps			|= D3DPBLENDCAPS_ZERO;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_BOTHINVSRCALPHA;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_BOTHSRCALPHA;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_DESTALPHA;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_DESTCOLOR;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_INVDESTALPHA;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_INVDESTCOLOR;
	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_INVSRCALPHA;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_INVSRCCOLOR;
	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_ONE;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_SRCALPHA;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_SRCALPHASAT;
//	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_SRCCOLOR;
	pHEL->dpcTriCaps.dwDestBlendCaps		|= D3DPBLENDCAPS_ZERO;
//	pHEL->dpcTriCaps.dwAlphaCmpCaps			|= D3DPCMPCAPS_ALWAYS;
//	pHEL->dpcTriCaps.dwAlphaCmpCaps			|= D3DPCMPCAPS_EQUAL;
//	pHEL->dpcTriCaps.dwAlphaCmpCaps			|= D3DPCMPCAPS_GREATER;
//	pHEL->dpcTriCaps.dwAlphaCmpCaps			|= D3DPCMPCAPS_GREATEREQUAL;
//	pHEL->dpcTriCaps.dwAlphaCmpCaps			|= D3DPCMPCAPS_LESS;
//	pHEL->dpcTriCaps.dwAlphaCmpCaps			|= D3DPCMPCAPS_LESSEQUAL;
//	pHEL->dpcTriCaps.dwAlphaCmpCaps			|= D3DPCMPCAPS_NEVER;
	pHEL->dpcTriCaps.dwAlphaCmpCaps			|= D3DPCMPCAPS_NOTEQUAL;
	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORFLATMONO;
	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORFLATRGB;
	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORGOURAUDMONO;
	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORGOURAUDRGB;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORPHONGMONO;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_COLORPHONGRGB;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARFLATMONO;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARFLATRGB;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARGOURAUDMONO;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARGOURAUDRGB;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARPHONGMONO;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_SPECULARPHONGRGB;
	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAFLATBLEND;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAFLATSTIPPLED;
	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAGOURAUDBLEND;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAPHONGBLEND;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_ALPHAPHONGSTIPPLED;
	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_FOGFLAT;
	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_FOGGOURAUD;
//	pHEL->dpcTriCaps.dwShadeCaps			|= D3DPSHADECAPS_FOGPHONG;
	pHEL->dpcTriCaps.dwTextureCaps			|= D3DPTEXTURECAPS_PERSPECTIVE;
	pHEL->dpcTriCaps.dwTextureCaps			|= D3DPTEXTURECAPS_POW2;
	pHEL->dpcTriCaps.dwTextureCaps			|= D3DPTEXTURECAPS_ALPHA;
//	pHEL->dpcTriCaps.dwTextureCaps			|= D3DPTEXTURECAPS_TRANSPARENCY;
//	pHEL->dpcTriCaps.dwTextureCaps			|= D3DPTEXTURECAPS_BORDER;
	pHEL->dpcTriCaps.dwTextureCaps			|= D3DPTEXTURECAPS_SQUAREONLY;
	pHEL->dpcTriCaps.dwTextureCaps			|= D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE;
//	pHEL->dpcTriCaps.dwTextureCaps			|= D3DPTEXTURECAPS_ALPHAPALETTE;
	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_NEAREST;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_LINEAR;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MIPNEAREST;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MIPLINEAR;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_LINEARMIPNEAREST;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_LINEARMIPLINEAR;
	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MINFPOINT;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MINFLINEAR;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MINFANISOTROPIC;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MIPFPOINT;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MIPFLINEAR;
	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFPOINT;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFLINEAR;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFANISOTROPIC;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFAFLATCUBIC;
//	pHEL->dpcTriCaps.dwTextureFilterCaps	|= D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC;
	pHEL->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_DECAL;
	pHEL->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_MODULATE;
//	pHEL->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_DECALALPHA;
	pHEL->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_MODULATEALPHA;
//	pHEL->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_DECALMASK;
//	pHEL->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_MODULATEMASK;
	pHEL->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_COPY;
//	pHEL->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_ADD;
	pHEL->dpcTriCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_WRAP;
//	pHEL->dpcTriCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_MIRROR;
	pHEL->dpcTriCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_CLAMP;
//	pHEL->dpcTriCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_BORDER;
	pHEL->dpcTriCaps.dwTextureAddressCaps	|= D3DPTADDRESSCAPS_INDEPENDENTUV;
	pHEL->dpcTriCaps.dwStippleWidth			= 0;
	pHEL->dpcTriCaps.dwStippleHeight		= 0;
//	pHEL->dwDeviceRenderBitDepth			|= DDBD_8;
	pHEL->dwDeviceRenderBitDepth			|= DDBD_16;
//	pHEL->dwDeviceRenderBitDepth			|= DDBD_24;
//	pHEL->dwDeviceRenderBitDepth			|= DDBD_32;
//	pHEL->dwDeviceZBufferBitDepth			|= DDBD_8;
	pHEL->dwDeviceZBufferBitDepth			|= DDBD_16;
//	pHEL->dwDeviceZBufferBitDepth			|= DDBD_24;
//	pHEL->dwDeviceZBufferBitDepth			|= DDBD_32;
	pHEL->dwMaxBufferSize					= 0;
	pHEL->dwMaxVertexCount					= 2048;
	pHEL->dwMinTextureWidth					= 1;
	pHEL->dwMinTextureHeight				= 1;
	pHEL->dwMaxTextureWidth					= 256;
	pHEL->dwMaxTextureHeight				= 256;
	pHEL->dwMinStippleWidth					= 0;
	pHEL->dwMaxStippleWidth					= 0;
	pHEL->dwMinStippleHeight				= 0;
	pHEL->dwMaxStippleHeight				= 0;
	pHEL->dwMaxTextureRepeat				= 100;
	pHEL->dwMaxTextureAspectRatio			= 1;
	pHEL->dwMaxAnisotropy					= 16;
	pHEL->dvGuardBandLeft					= 0;
	pHEL->dvGuardBandTop					= 0;
	pHEL->dvGuardBandRight					= 0;
	pHEL->dvGuardBandBottom					= 0;
	pHEL->dvExtentsAdjust					= 0;
//	pHEL->dwStencilCaps						|= D3DSTENCILCAPS_DECR;
//	pHEL->dwStencilCaps						|= D3DSTENCILCAPS_DECRSAT;
//	pHEL->dwStencilCaps						|= D3DSTENCILCAPS_INCR;
//	pHEL->dwStencilCaps						|= D3DSTENCILCAPS_INCRSAT;
//	pHEL->dwStencilCaps						|= D3DSTENCILCAPS_INVERT;
//	pHEL->dwStencilCaps						|= D3DSTENCILCAPS_KEEP;
//	pHEL->dwStencilCaps						|= D3DSTENCILCAPS_REPLACE;
//	pHEL->dwStencilCaps						|= D3DSTENCILCAPS_ZERO;
//	pHEL->dwFVFCaps							|= D3DFVFCAPS_DONOTSTRIPELEMENTS;
	pHEL->dwFVFCaps							|= D3DFVFCAPS_TEXCOORDCOUNTMASK & (1);
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_ADD;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_ADDSIGNED;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_ADDSIGNED2X;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_ADDSMOOTH;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_BLENDCURRENTALPHA;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_BLENDDIFFUSEALPHA;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_BLENDFACTORALPHA;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_BLENDTEXTUREALPHA;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_BLENDTEXTUREALPHAPM;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_BUMPENVMAP;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_BUMPENVMAPLUMINANCE;
	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_DISABLE;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_DOTPRODUCT3;
	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_MODULATE;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_MODULATE2X;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_MODULATE4X;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_PREMODULATE;
	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_SELECTARG1;
	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_SELECTARG2;
//	pHEL->dwTextureOpCaps					|= D3DTEXOPCAPS_SUBTRACT;
	pHEL->wMaxTextureBlendStages			= 1;
	pHEL->wMaxSimultaneousTextures			= 1;

	return S_OK;
}


HRESULT CDirect3DDevice::Static_GetCaps(D3DDEVICEDESC7 *dd7)
{
	//
	// make sure the structures are valid
	//
	if (IsBadWritePtr(dd7, sizeof(D3DDEVICEDESC7)))
		return DDERR_INVALIDPARAMS;

	ZeroMemory(dd7, sizeof(D3DDEVICEDESC7));

	dd7->dwDevCaps								|= D3DDEVCAPS_CANBLTSYSTONONLOCAL;
	dd7->dwDevCaps								|= D3DDEVCAPS_CANRENDERAFTERFLIP;
	dd7->dwDevCaps								|= D3DDEVCAPS_DRAWPRIMTLVERTEX;
//	dd7->dwDevCaps								|= D3DDEVCAPS_EXECUTESYSTEMMEMORY;
//	dd7->dwDevCaps								|= D3DDEVCAPS_EXECUTEVIDEOMEMORY;
	dd7->dwDevCaps								|= D3DDEVCAPS_FLOATTLVERTEX;
//	dd7->dwDevCaps								|= D3DDEVCAPS_HWRASTERIZATION;
//	dd7->dwDevCaps								|= D3DDEVCAPS_HWTRANSFORMANDLIGHT;
//	dd7->dwDevCaps								|= D3DDEVCAPS_SEPARATETEXTUREMEMORIES;
//	dd7->dwDevCaps								|= D3DDEVCAPS_SORTDECREASINGZ;
//	dd7->dwDevCaps								|= D3DDEVCAPS_SORTEXACT;
//	dd7->dwDevCaps								|= D3DDEVCAPS_SORTINCREASINGZ;
//	dd7->dwDevCaps								|= D3DDEVCAPS_STRIDEDVERTICES;
//	dd7->dwDevCaps								|= D3DDEVCAPS_TEXTURENONLOCALVIDMEM;
	dd7->dwDevCaps								|= D3DDEVCAPS_TEXTURESYSTEMMEMORY;
//	dd7->dwDevCaps								|= D3DDEVCAPS_TEXTUREVIDEOMEMORY;
	dd7->dwDevCaps								|= D3DDEVCAPS_TLVERTEXSYSTEMMEMORY;
	dd7->dwDevCaps								|= D3DDEVCAPS_TLVERTEXVIDEOMEMORY;
	dd7->dpcLineCaps.dwSize						= sizeof(dd7->dpcLineCaps);
//	dd7->dpcLineCaps.dwMiscCaps					|= D3DPMISCCAPS_CONFORMANT;
//	dd7->dpcLineCaps.dwMiscCaps					|= D3DPMISCCAPS_CULLCCW;
//	dd7->dpcLineCaps.dwMiscCaps					|= D3DPMISCCAPS_CULLCW;
//	dd7->dpcLineCaps.dwMiscCaps					|= D3DPMISCCAPS_CULLNONE;
//	dd7->dpcLineCaps.dwMiscCaps					|= D3DPMISCCAPS_LINEPATTERNREP;
//	dd7->dpcLineCaps.dwMiscCaps					|= D3DPMISCCAPS_MASKPLANES;
//	dd7->dpcLineCaps.dwMiscCaps					|= D3DPMISCCAPS_MASKZ;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_ANISOTROPY;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_ANTIALIASEDGES;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_DITHER;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_FOGRANGE;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_FOGTABLE;
	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_FOGVERTEX;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_MIPMAPLODBIAS;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_PAT;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_ROP2;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_STIPPLE;
	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_SUBPIXEL;
	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_SUBPIXELX;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_WBUFFER;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_WFOG;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_XOR;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_ZBIAS;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_ZBUFFERLESSHSR;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_ZFOG;
//	dd7->dpcLineCaps.dwRasterCaps				|= D3DPRASTERCAPS_ZTEST;
//	dd7->dpcLineCaps.dwZCmpCaps					|= D3DPCMPCAPS_ALWAYS;
//	dd7->dpcLineCaps.dwZCmpCaps					|= D3DPCMPCAPS_EQUAL;
//	dd7->dpcLineCaps.dwZCmpCaps					|= D3DPCMPCAPS_GREATER;
//	dd7->dpcLineCaps.dwZCmpCaps					|= D3DPCMPCAPS_GREATEREQUAL;
//	dd7->dpcLineCaps.dwZCmpCaps					|= D3DPCMPCAPS_LESS;
//	dd7->dpcLineCaps.dwZCmpCaps					|= D3DPCMPCAPS_LESSEQUAL;
//	dd7->dpcLineCaps.dwZCmpCaps					|= D3DPCMPCAPS_NEVER;
//	dd7->dpcLineCaps.dwZCmpCaps					|= D3DPCMPCAPS_NOTEQUAL;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_BOTHINVSRCALPHA;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_BOTHSRCALPHA;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_DESTALPHA;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_DESTCOLOR;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_INVDESTALPHA;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_INVDESTCOLOR;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_INVSRCALPHA;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_INVSRCCOLOR;
	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_ONE;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_SRCALPHA;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_SRCALPHASAT;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_SRCCOLOR;
//	dd7->dpcLineCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_ZERO;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_BOTHINVSRCALPHA;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_BOTHSRCALPHA;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_DESTALPHA;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_DESTCOLOR;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_INVDESTALPHA;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_INVDESTCOLOR;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_INVSRCALPHA;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_INVSRCCOLOR;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_ONE;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_SRCALPHA;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_SRCALPHASAT;
//	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_SRCCOLOR;
	dd7->dpcLineCaps.dwDestBlendCaps			|= D3DPBLENDCAPS_ZERO;
//	dd7->dpcLineCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_ALWAYS;
//	dd7->dpcLineCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_EQUAL;
//	dd7->dpcLineCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_GREATER;
//	dd7->dpcLineCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_GREATEREQUAL;
//	dd7->dpcLineCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_LESS;
//	dd7->dpcLineCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_LESSEQUAL;
//	dd7->dpcLineCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_NEVER;
//	dd7->dpcLineCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_NOTEQUAL;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_ALPHAFLATBLEND;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_ALPHAFLATSTIPPLED;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_ALPHAGOURAUDBLEND;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_ALPHAPHONGBLEND;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_ALPHAPHONGSTIPPLED;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_COLORFLATMONO;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_COLORFLATRGB;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_COLORGOURAUDMONO;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_COLORGOURAUDRGB;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_COLORPHONGMONO;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_COLORPHONGRGB;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_FOGFLAT;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_FOGGOURAUD;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_FOGPHONG;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_SPECULARFLATMONO;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_SPECULARFLATRGB;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_SPECULARGOURAUDMONO;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_SPECULARGOURAUDRGB;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_SPECULARPHONGMONO;
//	dd7->dpcLineCaps.dwShadeCaps				|= D3DPSHADECAPS_SPECULARPHONGRGB;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_ALPHA;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_ALPHAPALETTE;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_BORDER;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_COLORKEYBLEND;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_CUBEMAP;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_NONPOW2CONDITIONAL;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_PERSPECTIVE;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_POW2;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_PROJECTED;
	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_SQUAREONLY;
	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE;
//	dd7->dpcLineCaps.dwTextureCaps				|= D3DPTEXTURECAPS_TRANSPARENCY;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_LINEAR;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_LINEARMIPLINEAR;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_LINEARMIPNEAREST;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MIPLINEAR;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MIPNEAREST;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_NEAREST;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MAGFAFLATCUBIC;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MAGFANISOTROPIC;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MAGFLINEAR;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MAGFPOINT;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MINFANISOTROPIC;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MINFLINEAR;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MINFPOINT;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MIPFLINEAR;
//	dd7->dpcLineCaps.dwTextureFilterCaps		|= D3DPTFILTERCAPS_MIPFPOINT;
	dd7->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_DECAL;
	dd7->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_MODULATE;
//	dd7->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_DECALALPHA;
	dd7->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_MODULATEALPHA;
//	dd7->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_DECALMASK;
//	dd7->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_MODULATEMASK;
	dd7->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_COPY;
//	dd7->dpcTriCaps.dwTextureBlendCaps		|= D3DPTBLENDCAPS_ADD;
//	dd7->dpcLineCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_BORDER;
//	dd7->dpcLineCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_CLAMP;
//	dd7->dpcLineCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_INDEPENDENTUV;
//	dd7->dpcLineCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_MIRROR;
//	dd7->dpcLineCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_WRAP;
	dd7->dpcLineCaps.dwStippleWidth				= 0;
	dd7->dpcLineCaps.dwStippleHeight			= 0;
	dd7->dpcTriCaps.dwSize						= sizeof(dd7->dpcTriCaps);
//	dd7->dpcTriCaps.dwMiscCaps					|= D3DPMISCCAPS_CONFORMANT;
	dd7->dpcTriCaps.dwMiscCaps					|= D3DPMISCCAPS_CULLCCW;
	dd7->dpcTriCaps.dwMiscCaps					|= D3DPMISCCAPS_CULLCW;
	dd7->dpcTriCaps.dwMiscCaps					|= D3DPMISCCAPS_CULLNONE;
//	dd7->dpcTriCaps.dwMiscCaps					|= D3DPMISCCAPS_LINEPATTERNREP;
//	dd7->dpcTriCaps.dwMiscCaps					|= D3DPMISCCAPS_MASKPLANES;
//	dd7->dpcTriCaps.dwMiscCaps					|= D3DPMISCCAPS_MASKZ;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_ANISOTROPY;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_ANTIALIASEDGES;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_DITHER;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_FOGRANGE;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_FOGTABLE;
	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_FOGVERTEX;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_MIPMAPLODBIAS;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_PAT;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_ROP2;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_STIPPLE;
	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_SUBPIXEL;
	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_SUBPIXELX;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_WBUFFER;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_WFOG;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_XOR;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_ZBIAS;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_ZBUFFERLESSHSR;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_ZFOG;
//	dd7->dpcTriCaps.dwRasterCaps				|= D3DPRASTERCAPS_ZTEST;
	dd7->dpcTriCaps.dwZCmpCaps					|= D3DPCMPCAPS_ALWAYS;
//	dd7->dpcTriCaps.dwZCmpCaps					|= D3DPCMPCAPS_EQUAL;
//	dd7->dpcTriCaps.dwZCmpCaps					|= D3DPCMPCAPS_GREATER;
//	dd7->dpcTriCaps.dwZCmpCaps					|= D3DPCMPCAPS_GREATEREQUAL;
//	dd7->dpcTriCaps.dwZCmpCaps					|= D3DPCMPCAPS_LESS;
	dd7->dpcTriCaps.dwZCmpCaps					|= D3DPCMPCAPS_LESSEQUAL;
	dd7->dpcTriCaps.dwZCmpCaps					|= D3DPCMPCAPS_NEVER;
//	dd7->dpcTriCaps.dwZCmpCaps					|= D3DPCMPCAPS_NOTEQUAL;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_BOTHINVSRCALPHA;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_BOTHSRCALPHA;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_DESTALPHA;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_DESTCOLOR;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_INVDESTALPHA;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_INVDESTCOLOR;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_INVSRCALPHA;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_INVSRCCOLOR;
	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_ONE;
	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_SRCALPHA;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_SRCALPHASAT;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_SRCCOLOR;
//	dd7->dpcTriCaps.dwSrcBlendCaps				|= D3DPBLENDCAPS_ZERO;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_BOTHINVSRCALPHA;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_BOTHSRCALPHA;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_DESTALPHA;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_DESTCOLOR;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_INVDESTALPHA;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_INVDESTCOLOR;
	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_INVSRCALPHA;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_INVSRCCOLOR;
	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_ONE;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_SRCALPHA;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_SRCALPHASAT;
//	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_SRCCOLOR;
	dd7->dpcTriCaps.dwDestBlendCaps				|= D3DPBLENDCAPS_ZERO;
//	dd7->dpcTriCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_ALWAYS;
//	dd7->dpcTriCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_EQUAL;
//	dd7->dpcTriCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_GREATER;
//	dd7->dpcTriCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_GREATEREQUAL;
//	dd7->dpcTriCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_LESS;
//	dd7->dpcTriCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_LESSEQUAL;
//	dd7->dpcTriCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_NEVER;
	dd7->dpcTriCaps.dwAlphaCmpCaps				|= D3DPCMPCAPS_NOTEQUAL;
	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_ALPHAFLATBLEND;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_ALPHAFLATSTIPPLED;
	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_ALPHAGOURAUDBLEND;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_ALPHAPHONGBLEND;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_ALPHAPHONGSTIPPLED;
	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_COLORFLATMONO;
	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_COLORFLATRGB;
	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_COLORGOURAUDMONO;
	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_COLORGOURAUDRGB;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_COLORPHONGMONO;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_COLORPHONGRGB;
	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_FOGFLAT;
	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_FOGGOURAUD;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_FOGPHONG;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_SPECULARFLATMONO;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_SPECULARFLATRGB;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_SPECULARGOURAUDMONO;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_SPECULARGOURAUDRGB;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_SPECULARPHONGMONO;
//	dd7->dpcTriCaps.dwShadeCaps					|= D3DPSHADECAPS_SPECULARPHONGRGB;
	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_ALPHA;
//	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_ALPHAPALETTE;
//	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_BORDER;
//	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_COLORKEYBLEND;
//	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_CUBEMAP;
//	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_NONPOW2CONDITIONAL;
	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_PERSPECTIVE;
	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_POW2;
//	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_PROJECTED;
	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_SQUAREONLY;
	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE;
//	dd7->dpcTriCaps.dwTextureCaps				|= D3DPTEXTURECAPS_TRANSPARENCY;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_LINEAR;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_LINEARMIPLINEAR;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_LINEARMIPNEAREST;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MIPLINEAR;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MIPNEAREST;
	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_NEAREST;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MAGFAFLATCUBIC;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MAGFANISOTROPIC;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MAGFLINEAR;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MAGFPOINT;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MINFANISOTROPIC;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MINFLINEAR;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MINFPOINT;
//	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MIPFLINEAR;
	dd7->dpcTriCaps.dwTextureFilterCaps			|= D3DPTFILTERCAPS_MIPFPOINT;
//	dd7->dpcTriCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_BORDER;
	dd7->dpcTriCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_CLAMP;
	dd7->dpcTriCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_INDEPENDENTUV;
//	dd7->dpcTriCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_MIRROR;
	dd7->dpcTriCaps.dwTextureAddressCaps		|= D3DPTADDRESSCAPS_WRAP;
	dd7->dpcTriCaps.dwStippleWidth				= 0;
	dd7->dpcTriCaps.dwStippleHeight				= 0;

	dd7->dwDeviceRenderBitDepth					= DDBD_16;
	dd7->dwDeviceZBufferBitDepth				= DDBD_16;
	dd7->dwMinTextureWidth						= 1;
	dd7->dwMinTextureHeight						= 1;
	dd7->dwMaxTextureWidth						= 256;
	dd7->dwMaxTextureHeight						= 256;
	dd7->dwMaxTextureRepeat						= 100;
	dd7->dwMaxTextureAspectRatio				= 1;
	dd7->dwMaxAnisotropy						= 0;
	dd7->dvGuardBandLeft						= 0;
	dd7->dvGuardBandTop							= 0;
	dd7->dvGuardBandRight						= 0;
	dd7->dvGuardBandBottom						= 0;
	dd7->dvExtentsAdjust						= 0;
//	dd7->dwStencilCaps							|= D3DSTENCILCAPS_DECR;
//	dd7->dwStencilCaps							|= D3DSTENCILCAPS_DECRSAT;
//	dd7->dwStencilCaps							|= D3DSTENCILCAPS_INCR;
//	dd7->dwStencilCaps							|= D3DSTENCILCAPS_INCRSAT;
//	dd7->dwStencilCaps							|= D3DSTENCILCAPS_INVERT;
//	dd7->dwStencilCaps							|= D3DSTENCILCAPS_KEEP;
//	dd7->dwStencilCaps							|= D3DSTENCILCAPS_REPLACE;
//	dd7->dwStencilCaps							|= D3DSTENCILCAPS_ZERO;
//	dd7->dwFVFCaps								|= D3DFVFCAPS_DONOTSTRIPELEMENTS;
//	dd7->dwFVFCaps								|= D3DFVFCAPS_TEXCOORDCOUNTMASK  0;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_ADD;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_ADDSIGNED;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_ADDSIGNED2X;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_ADDSMOOTH;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_BLENDCURRENTALPHA;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_BLENDDIFFUSEALPHA;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_BLENDFACTORALPHA;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_BLENDTEXTUREALPHA;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_BLENDTEXTUREALPHAPM;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_BUMPENVMAP;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_BUMPENVMAPLUMINANCE;
	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_DISABLE;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_DOTPRODUCT3;
	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_MODULATE;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_MODULATE2X;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_MODULATE4X;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_PREMODULATE;
	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_SELECTARG1;
	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_SELECTARG2;
//	dd7->dwTextureOpCaps						|= D3DTEXOPCAPS_SUBTRACT;
	dd7->wMaxTextureBlendStages					= 1;
	dd7->wMaxSimultaneousTextures				= 1;
	dd7->dwMaxActiveLights						= MAX_LIGHTS;
	dd7->dvMaxVertexW							= 0;
	dd7->deviceGUID								= IID_IDirect3DBladeDevice;
	dd7->wMaxUserClipPlanes						= 0;
	dd7->wMaxVertexBlendMatrices				= 2;
//	dd7->dwVertexProcessingCaps					|= D3DVTXPCAPS_TEXGEN;
//	dd7->dwVertexProcessingCaps					|= D3DVTXPCAPS_MATERIALSOURCE7;
//	dd7->dwVertexProcessingCaps					|= D3DVTXPCAPS_VERTEXFOG;
//	dd7->dwVertexProcessingCaps					|= D3DVTXPCAPS_DIRECTIONALLIGHTS;
//	dd7->dwVertexProcessingCaps					|= D3DVTXPCAPS_POSITIONALLIGHTS;
//	dd7->dwVertexProcessingCaps					|= D3DVTXPCAPS_NONLOCALVIEWER;
	dd7->dwReserved1							= 0;
	dd7->dwReserved2							= 0;
	dd7->dwReserved3							= 0;
	dd7->dwReserved4							= 0;

	return S_OK;
}





//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetCaps(LPD3DDEVICEDESC hal, LPD3DDEVICEDESC hel)
{
	return Static_GetCaps(hal, hel);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::EnumTextureFormats(LPD3DENUMPIXELFORMATSCALLBACK TextureCallback, LPVOID pv)
{
	//  size, flags, 4cc, bpp, Rmask, Gmask, Bmask, Amask
	static DDPIXELFORMAT TextureFormats[] = {
		{sizeof(DDPIXELFORMAT), DDPF_RGB,						0, 16, 0x7C00,0x03E0,0x001F,0x0000},  // 0555
		{sizeof(DDPIXELFORMAT), DDPF_RGB,						0, 16, 0xF800,0x07E0,0x001F,0x0000},  // 0565
		{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS,	0, 16, 0x7C00,0x03E0,0x001F,0x8000},  // 1555
		{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS,	0, 16, 0x0F00,0x00F0,0x000F,0xF000},  // 4444
	};

    // allow only whichever of 555 or 565 matches the target format
	for (int i = 0; i < sizeof(TextureFormats)/sizeof(TextureFormats[0]); i++)
	{
		if (TextureFormats[i].dwRGBBitCount == 16 && (TextureFormats[i].dwRGBAlphaBitMask == 0))
		{
			if (m_Target.fmt != GetPixelFormat(&TextureFormats[i]))
				continue;
		}

		if ((*TextureCallback)(&TextureFormats[i], pv) != DDENUMRET_OK)
			break;
	}

	return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::BeginScene(void)
{
	HRESULT hr;

	// make sure we are not actually in a scene right now
	if (0 != (m_dwStatus & SOFTWARE_DEVICE_IN_SCENE))
	{
		ERRORMSG("nested call call to BeginScene");
		return E_FAIL;
	}

    // notice that we are locking all three possible surfaces (even though
    //   we might only have one of them).  This is OK since the surface
    //   class makes sure there is a surface before attempting the lock.

    hr = m_ZBuffer.Lock();
    if (FAILED(hr))
    {
        goto fail;
    }

    hr = m_Target.Lock();
    if (FAILED(hr))
    {
        goto fail;
    }

	if (m_Texture.locked == -1)
	{
		//
		// if we get here, that means we're starting a new scene when we didn't have the texture
		// locked at the end of the old scene
		//
		m_Texture.locked = 0;
	}
	else
	{
		hr = m_Texture.Lock();
		if (FAILED(hr))
		{
			goto fail;
		}
	}

    m_dwStatus |= SOFTWARE_DEVICE_IN_SCENE;

    UpdateClipTransform();

	ASSERT(NULL != m_Target.SurfaceDesc.lpSurface);

	m_imgdev.SetScreen((BYTE*)m_Target.SurfaceDesc.lpSurface);
	m_imgdev.SetScreenPitch(m_Target.SurfaceDesc.lPitch);
	m_imgdev.SetZBuffer((BYTE*)m_ZBuffer.SurfaceDesc.lpSurface);
	m_imgdev.SetZBufferPitch(m_ZBuffer.SurfaceDesc.lPitch);

	hr = S_OK;

fail:
    // on failure make sure that none of the surfaces are locked
    if (FAILED(hr))
    {
        m_ZBuffer.Unlock();
        m_Target.Unlock();
        m_Texture.Unlock();
    }

	return hr;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::EndScene(void)
{
    HRESULT hr, hrResult;

    // make sure we are in a scene right now
    if (0 == (m_dwStatus & SOFTWARE_DEVICE_IN_SCENE))
    {
		ERRORMSG("EndScene called without BeginScene")
        return E_FAIL;
    }

    // initializations
    hr = S_OK;

    // since we tried to lock all three possible surfaces above, we need to
    //   unlock them here.
    hrResult = m_ZBuffer.Unlock();
    if (FAILED(hrResult))
    {
        hr = E_FAIL;
    }

    hrResult = m_Target.Unlock();
    if (FAILED(hrResult))
    {
        hr = E_FAIL;
    }

	//
	// if the texture isn't locked, then we really shouldn't have a texture
	//
	if (!m_Texture.locked)
	{
		//
		// this will tell us NOT to lock the texture on the next BeginScene
		//
		m_Texture.locked = -1;
	}
	else
	{
		hrResult = m_Texture.Unlock();
		if (FAILED(hrResult))
		{
			hr = E_FAIL;
		}
	}

    m_dwStatus &= ~SOFTWARE_DEVICE_IN_SCENE;

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

    m_imgdev.SetScreen((BYTE*)0xDeadBeef);

    hr = S_OK;

fail:
	return hr;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetTexture(DWORD dwStage, LPDIRECT3DTEXTURE2 *ppTexture)
{
	if (m_Texture.pSurface)
	{
		*ppTexture = NULL;
		m_Texture.pSurface->QueryInterface(IID_IDirect3DTexture2, (void**)ppTexture);
	}
	else
	{
		*ppTexture = NULL;
	}

	return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::SetTexture(DWORD dwStage, LPDIRECT3DTEXTURE2 pTexture)
{
	return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
// NOTE mikeab this must stay in sync with ReevaluateState()
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::ValidateDevice(LPDWORD lpdwPasses)
{

    *lpdwPasses = 0;

    if (AlphaBlend())
    {
        if (SrcBlend() == D3DBLEND_ONE)
        {
            if (DestBlend() == D3DBLEND_ONE)
            {
            }
            else if (DestBlend() == D3DBLEND_INVSRCALPHA)
            {
            }
            else
            {
                if (DestBlend() != D3DBLEND_ZERO)
                {
                    return D3DERR_UNSUPPORTEDALPHAOPERATION;
                }
            }
        }
        else if (SrcBlend() == D3DBLEND_SRCALPHA)
        {
            if (DestBlend() == D3DBLEND_INVSRCALPHA)
            {
            }
            else
            {
                return D3DERR_UNSUPPORTEDALPHAOPERATION;
            }
        }
        else
        {
            return D3DERR_UNSUPPORTEDALPHAOPERATION;
        }
    }

    BOOL fTexture = FALSE;

    if (TextureMap())
    {
        fTexture = TRUE;

        switch (TexelFormat())
        {
        case 4444:
        case 1555:
        case 555:
        case 565:
            break;

        default:
            return D3DERR_WRONGTEXTUREFORMAT;
        }
    }

    // if there's no texture map, we have no choice but to be in modulate alpha
    if (!fTexture || TexBlendModulateAlpha())
    {
    }
    else if (TexBlendDecal())
    {
    }
    else if (TexBlendModulateUseDiffuseAlpha())
    {
    }
    else if (TexBlendModulateUseNoAlpha())
    {
    }
    else if (TexBlendDecalUseNoAlpha())
    {
    }
    else if (TexBlendModulateUseTextureAlpha())
    {
    }
    else
    {
        // NOTE mikeab There's no general "bad texture stage settings" error return,
        // so this will have to do
#ifdef _DEBUG
		//
		// hey, let's print out the texture blend methods, eh?
		//
		if (true)
		{
			char	szErrorString[2048];
			char *	pszTextureOp[] = {
				"?????????", "D3DTOP_DISABLE", "D3DTOP_SELECTARG1", "D3DTOP_SELECTARG2", "D3DTOP_MODULATE", "D3DTOP_MODULATE2X", "D3DTOP_MODULATE4X", "D3DTOP_ADD",
				"D3DTOP_ADDSIGNED", "D3DTOP_ADDSIGNED2X", "D3DTOP_SUBTRACT", "D3DTOP_ADDSMOOTH", "D3DTOP_BLENDDIFFUSEALPHA", "D3DTOP_BLENDTEXTUREALPHA", "D3DTOP_BLENDFACTORALPHA",
				"D3DTOP_BLENDTEXTUREALPHAPM", "D3DTOP_BLENDCURRENTALPHA", "D3DTOP_PREMODULATE", "D3DTOP_MODULATEALPHA_ADDCOLOR", "D3DTOP_MODULATECOLOR_ADDALPHA",
				"D3DTOP_MODULATEINVALPHA_ADDCOLOR", "D3DTOP_MODULATEINVCOLOR_ADDALPHA", "D3DTOP_BUMPENVMAP", "D3DTOP_BUMPENVMAPLUMINANCE", "D3DTOP_DOTPRODUCT3",
			};

			char *	pszTextureArg[] = {
				"D3DTA_DIFFUSE", "D3DTA_CURRENT", "D3DTA_TEXTURE", "D3DTA_TFACTOR", "D3DTA_SPECULAR", "0x05", "0x06", "0x07", "0x08", "0x09", "0x0A", "0x0B", "0x0C", "0x0D", "0x0E", "0x0F",
				"D3DTA_COMPLEMENT | D3DTA_DIFFUSE", "D3DTA_COMPLEMENT | D3DTA_CURRENT", "D3DTA_COMPLEMENT | D3DTA_TEXTURE", "D3DTA_COMPLEMENT | D3DTA_TFACTOR", "D3DTA_COMPLEMENT | D3DTA_SPECULAR", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1A", "0x1B", "0x1C", "0x1D", "0x1E", "0x1F",
				"D3DTA_ALPHAREPLICATE | D3DTA_DIFFUSE", "D3DTA_ALPHAREPLICATE | D3DTA_CURRENT", "D3DTA_ALPHAREPLICATE | D3DTA_TEXTURE", "D3DTA_ALPHAREPLICATE | D3DTA_TFACTOR", "D3DTA_ALPHAREPLICATE | D3DTA_SPECULAR", "0x25", "0x26", "0x27", "0x28", "0x29", "0x2A", "0x2B", "0x2C", "0x2D", "0x2E", "0x2F",
				"D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT | D3DTA_DIFFUSE", "D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT | D3DTA_CURRENT", "D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT | D3DTA_TEXTURE", "D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT | D3DTA_TFACTOR", "D3DTA_ALPHAREPLICATE | D3DTA_COMPLEMENT | D3DTA_SPECULAR",
			};

			szErrorString[0]=0;

			wsprintf(szErrorString, "\nD3DTSS_COLOROP:    %s\nD3DTSS_COLORARG1:  %s\nD3DTSS_COLORARG2:  %s\nD3DTSS_ALPHAOP:    %s\nD3DTSS_ALPHAARG1:  %s\nD3DTSS_ALPHAARG2:  %s\n",
				pszTextureOp[m_rgdwTextureStageState[D3DTSS_COLOROP]],
				pszTextureArg[m_rgdwTextureStageState[D3DTSS_COLORARG1]],
				pszTextureArg[m_rgdwTextureStageState[D3DTSS_COLORARG2]],
				pszTextureOp[m_rgdwTextureStageState[D3DTSS_ALPHAOP]],
				pszTextureArg[m_rgdwTextureStageState[D3DTSS_ALPHAARG1]],
				pszTextureArg[m_rgdwTextureStageState[D3DTSS_ALPHAARG2]]);

			OutputDebugString(szErrorString);
		}
#endif
        return D3DERR_UNSUPPORTEDCOLOROPERATION;
    }

    *lpdwPasses = 1;

    return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CDirect3DDevice::DrawLine(D3DTLVERTEX *P0, D3DTLVERTEX *P1)
{
	assert(m_Target.pSurface != NULL);

	if (m_Target.pSurface == NULL)
        return;

	ASSERT(P0->sx >= 0.0);
	ASSERT(P0->sy >= 0.0);
	ASSERT(P0->sx <= m_imgdev.GetScreenWidth());
	ASSERT(P0->sy <= m_imgdev.GetScreenHeight());

	ASSERT(P1->sx >= 0.0);
	ASSERT(P1->sy >= 0.0);
	ASSERT(P1->sx <= m_imgdev.GetScreenWidth());
	ASSERT(P1->sy <= m_imgdev.GetScreenHeight());

	ASSERT(m_imgdev.GetScreenWidth()  == (int)m_Target.SurfaceDesc.dwWidth);
	ASSERT(m_imgdev.GetScreenHeight() == (int)m_Target.SurfaceDesc.dwHeight);

    int x0, y0, x1, y1, w, h;

    x0 = (int)P0->sx;
    y0 = (int)P0->sy;
    x1 = (int)P1->sx;
    y1 = (int)P1->sy;
    w = m_imgdev.GetScreenWidth();
    h = m_imgdev.GetScreenHeight();

    // if a line endpoint is just off the bottom or left edge of the screen, bump it back onscreen
    // (these are onscreen points for unclipped polygons, because of top-left filling, but
    // not for points)
    // NOTE: this does not result in quite the right line, but then neither does truncating to integers,
    // and since we don't support z, alpha, or fog for lines, these are unlikely to be used as part of
    // 3D scenes, so there aren't likely to be alignment problems with polygons
    if (x0 >= w)
        x0 = w - 1;

    if (x1 >= w)
        x1 = w - 1;

    if (y0 >= h)
        y0 = h - 1;

    if (y1 >= h)
        y1 = h - 1;

	m_imgdev.Line((unsigned int)P0->color, x0, y0, x1, y1);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CDirect3DDevice::DrawPoint(D3DTLVERTEX *P)
{
	assert(m_Target.pSurface != NULL);

	if (m_Target.pSurface == NULL)
        return;

	ASSERT(P->sx >= 0.0);
	ASSERT(P->sy >= 0.0);
	ASSERT(P->sx <= m_imgdev.GetScreenWidth());
	ASSERT(P->sy <= m_imgdev.GetScreenHeight());

	ASSERT(m_imgdev.GetScreenWidth()  == (int)m_Target.SurfaceDesc.dwWidth);
	ASSERT(m_imgdev.GetScreenHeight() == (int)m_Target.SurfaceDesc.dwHeight);

    int x, y;

    x = (int)P->sx;
    y = (int)P->sy;

    // don't bother drawing points that are just off the bottom or right edge of the screen
    // (these are onscreen points for unclipped polygons, because of top-left filling, but
    // not for points)
    if ((x >= (int)m_imgdev.GetScreenWidth()) ||
        (y >= (int)m_imgdev.GetScreenHeight()))
    {
        return;
    }

	m_imgdev.Point((unsigned int)P->color, x, y);
}




//
// Default render states.
//


static DWORD s_rgdwRenderStateInit[] = {
	0x00000000,				// D3DRENDERSTATE_TEXTUREHANDLE					(1)
	NULL,					// D3DRENDERSTATE_ANTIALIAS						(2)
	D3DANTIALIAS_NONE,		// D3DRENDERSTATE_TEXTUREADDRESS				(3)
	D3DTADDRESS_WRAP,		// D3DRENDERSTATE_TEXTUREPERSPECTIVE			(4)
	TRUE,					// D3DRENDERSTATE_WRAPU							(5)
	FALSE,					// D3DRENDERSTATE_WRAPV							(6)
	FALSE,					// D3DRENDERSTATE_ZENABLE						(7)
	D3DZB_FALSE,			// D3DRENDERSTATE_FILLMODE						(8)
	D3DFILL_SOLID,			// D3DRENDERSTATE_SHADEMODE						(9)
	D3DSHADE_GOURAUD,		// D3DRENDERSTATE_LINEPATTERN					(10)
	0x00000000,				// D3DRENDERSTATE_MONOENABLE					(11)
	FALSE,					// D3DRENDERSTATE_ROP2							(12)
	R2_COPYPEN,				// D3DRENDERSTATE_PLANEMASK						(13)
	0xFFFFFFFF,				// D3DRENDERSTATE_ZWRITEENABLE					(14)
	TRUE,					// D3DRENDERSTATE_ALPHATESTENABLE				(15)
	FALSE,					// D3DRENDERSTATE_LASTPIXEL						(16)
	TRUE,					// D3DRENDERSTATE_TEXTUREMAG					(17)
	D3DFILTER_NEAREST,		// D3DRENDERSTATE_TEXTUREMIN					(18)
	D3DFILTER_NEAREST,		// D3DRENDERSTATE_SRCBLEND						(19)
	D3DBLEND_ONE,			// D3DRENDERSTATE_DESTBLEND						(20)
	D3DBLEND_ZERO,			// D3DRENDERSTATE_TEXTUREMAPBLEND				(21)
	D3DTBLEND_MODULATE,		// D3DRENDERSTATE_CULLMODE						(22)
	D3DCULL_CCW,			// D3DRENDERSTATE_ZFUNC							(23)
	D3DCMP_LESSEQUAL,		// D3DRENDERSTATE_ALPHAREF						(24)
	0x00000000,				// D3DRENDERSTATE_ALPHAFUNC						(25)
	D3DCMP_ALWAYS,			// D3DRENDERSTATE_DITHERENABLE					(26)
	FALSE,					// D3DRENDERSTATE_ALPHABLENDENABLE				(27)
	FALSE,					// D3DRENDERSTATE_FOGENABLE						(28)
	FALSE,					// D3DRENDERSTATE_SPECULARENABLE				(29)
	FALSE,					// D3DRENDERSTATE_ZVISIBLE						(30)
	FALSE,					// D3DRENDERSTATE_SUBPIXEL						(31)
	FALSE,					// D3DRENDERSTATE_SUBPIXELX						(32)
	FALSE,					// D3DRENDERSTATE_STIPPLEDALPHA					(33)
	FALSE,					// D3DRENDERSTATE_FOGCOLOR						(34)
	0x00000000,				// D3DRENDERSTATE_FOGTABLEMODE					(35)
	D3DFOG_NONE,			// D3DRENDERSTATE_FOGTABLESTART					(36)
	0x00000000,				// D3DRENDERSTATE_FOGTABLEEND					(37)
	0x00000000,				// D3DRENDERSTATE_FOGTABLEDENSITY				(38)
	0x00000000,				// D3DRENDERSTATE_STIPPLEENABLE					(39)
	FALSE,					// D3DRENDERSTATE_EDGEANTIALIAS					(40)
	FALSE,					// D3DRENDERSTATE_COLORKEYENABLE				(41)
	FALSE,					// - FILLER -									(42)
	0x00000000,				// D3DRENDERSTATE_BORDERCOLOR					(43)
	0x00000000,				// D3DRENDERSTATE_TEXTUREADDRESSU				(44)
	D3DTADDRESS_WRAP,		// D3DRENDERSTATE_TEXTUREADDRESSV				(45)
	D3DTADDRESS_WRAP,		// D3DRENDERSTATE_MIPMAPLODBIAS					(46)
	0x00000000,				// D3DRENDERSTATE_ZBIAS							(47)
	0x00000000,				// D3DRENDERSTATE_RANGEFOGENABLE				(48)
	FALSE,					// D3DRENDERSTATE_ANISOTROPY					(49)
	0x00000000,				// D3DRENDERSTATE_FLUSHBATCH					(50)
	FALSE,					// D3DRENDERSTATE_TRANSLUCENTSORTINDEPENDENT	(51)
	FALSE,					// D3DRENDERSTATE_STENCILENABLE					(52)
	FALSE,					// D3DRENDERSTATE_STENCILFAIL					(53)
	D3DSTENCILOP_KEEP,		// D3DRENDERSTATE_STENCILZFAIL					(54)
	D3DSTENCILOP_KEEP,		// D3DRENDERSTATE_STENCILPASS					(55)
	D3DSTENCILOP_KEEP,		// D3DRENDERSTATE_STENCILFUNC					(56)
	D3DCMP_ALWAYS,			// D3DRENDERSTATE_STENCILREF					(57)
	0x00000000,				// D3DRENDERSTATE_STENCILMASK					(58)
	0xFFFFFFFF,				// D3DRENDERSTATE_STENCILWRITEMASK				(59)
	0xFFFFFFFF,				// D3DRENDERSTATE_TEXTUREFACTOR					(60)
	0x00000000,				// - FILLER -									(61)
	0x00000000,				// - FILLER -									(62)
	0x00000000,				// - FILLER -									(63)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN00				(64)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN01				(65)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN02				(66)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN03				(67)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN04				(68)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN05				(69)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN06				(70)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN07				(71)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN08				(72)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN09				(73)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN10				(74)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN11				(75)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN12				(76)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN13				(77)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN14				(78)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN15				(79)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN16				(80)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN17				(81)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN18				(82)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN19				(83)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN20				(84)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN21				(85)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN22				(86)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN23				(87)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN24				(88)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN25				(89)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN26				(90)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN27				(91)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN28				(92)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN29				(93)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN30				(94)
	0x00000000,				// D3DRENDERSTATE_STIPPLEPATTERN31				(95)
	0x00000000,				// - FILLER -									(96)
	0x00000000,				// - FILLER -									(97)
	0x00000000,				// - FILLER -									(98)
	0x00000000,				// - FILLER -									(99)
	0x00000000,				// - FILLER -									(100)
	0x00000000,				// - FILLER -									(101)
	0x00000000,				// - FILLER -									(102)
	0x00000000,				// - FILLER -									(103)
	0x00000000,				// - FILLER -									(104)
	0x00000000,				// - FILLER -									(105)
	0x00000000,				// - FILLER -									(106)
	0x00000000,				// - FILLER -									(107)
	0x00000000,				// - FILLER -									(108)
	0x00000000,				// - FILLER -									(109)
	0x00000000,				// - FILLER -									(110)
	0x00000000,				// - FILLER -									(111)
	0x00000000,				// - FILLER -									(112)
	0x00000000,				// - FILLER -									(113)
	0x00000000,				// - FILLER -									(114)
	0x00000000,				// - FILLER -									(115)
	0x00000000,				// - FILLER -									(116)
	0x00000000,				// - FILLER -									(117)
	0x00000000,				// - FILLER -									(118)
	0x00000000,				// - FILLER -									(119)
	0x00000000,				// - FILLER -									(120)
	0x00000000,				// - FILLER -									(121)
	0x00000000,				// - FILLER -									(122)
	0x00000000,				// - FILLER -									(123)
	0x00000000,				// - FILLER -									(124)
	0x00000000,				// - FILLER -									(125)
	0x00000000,				// - FILLER -									(126)
	0x00000000,				// - FILLER -									(127)
	0x00000000,				// D3DRENDERSTATE_WRAP0							(128)
	0x00000000,				// D3DRENDERSTATE_WRAP1							(129)
	0x00000000,				// D3DRENDERSTATE_WRAP2							(130)
	0x00000000,				// D3DRENDERSTATE_WRAP3							(131)
	0x00000000,				// D3DRENDERSTATE_WRAP4							(132)
	0x00000000,				// D3DRENDERSTATE_WRAP5							(133)
	0x00000000,				// D3DRENDERSTATE_WRAP6							(134)
	0x00000000,				// D3DRENDERSTATE_WRAP7							(135)
	TRUE,					// D3DRENDERSTATE_CLIPPING						(136)
	TRUE,					// D3DRENDERSTATE_LIGHTING						(137)
	FALSE,					// D3DRENDERSTATE_EXTENTS						(138)
	D3DRGBA(0,0,0,0),		// D3DRENDERSTATE_AMBIENT						(139)
	D3DFOG_NONE,			// D3DRENDERSTATE_FOGVERTEXMODE					(140)
	TRUE,					// D3DRENDERSTATE_COLORVERTEX					(141)
	TRUE,					// D3DRENDERSTATE_LOCALVIEWER					(142)
	FALSE,					// D3DRENDERSTATE_NORMALIZENORMALS				(143)
	FALSE,					// D3DRENDERSTATE_COLORKEYBLENDENABLE			(144)
	D3DMCS_COLOR1,			// D3DRENDERSTATE_DIFFUSEMATERIALSOURCE			(145)
	D3DMCS_COLOR2,			// D3DRENDERSTATE_SPECULARMATERIALSOURCE		(146)
	D3DMCS_COLOR2,			// D3DRENDERSTATE_AMBIENTMATERIALSOURCE			(147)
	D3DMCS_MATERIAL,		// D3DRENDERSTATE_EMISSIVEMATERIALSOURCE		(148)
	0x00000000,				// - FILLER -									(149)
	0x00000000,				// - FILLER -									(150)
	D3DVBLEND_DISABLE,		// D3DRENDERSTATE_VERTEXBLEND					(151)
	0x00000000,				// D3DRENDERSTATE_CLIPPLANEENABLE				(152)
};

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
CDirect3DDevice::CDirect3DDevice(IDirect3D *pDirect3D, IDirect3DDevice * pDevice)
{
	if (true)
	{
		ZeroMemory(m_rgwColorTable, sizeof(m_rgwColorTable));
		ZeroMemory(&m_imgdev, sizeof(m_imgdev));

		m_cxTexWidth  = 0;
		m_cyTexHeight = 0;

		m_cfxTexWidth  = 0.0F;
		m_cfyTexHeight = 0.0F;
	}

    m_cRef = 1;

//	m_pDirect3D			= NULL;
//	m_pDevice			= NULL;
	m_pDirect3D3		= NULL;
	m_pDevice3			= NULL;
	m_pViewport3		= NULL;
#ifdef USE_DX7_INTERFACE
	m_pDevice7			= NULL;
#endif

    if (pDirect3D)
	{
//        pDirect3D->QueryInterface(IID_IDirect3D, (void **)&m_pDirect3D);
        pDirect3D->QueryInterface(IID_IDirect3D3, (void **)&m_pDirect3D3);
	}

    if (pDevice)
	{
//        pDevice->QueryInterface(IID_IDirect3DDevice, (void **)&m_pDevice);
        pDevice->QueryInterface(IID_IDirect3DDevice3, (void **)&m_pDevice3);
	}

#ifdef USE_DX7_INTERFACE
    if (pDevice)
	{
        pDevice->QueryInterface(IID_IDirect3DDevice7, (void **)&m_pDevice7);
	}

#endif

    Identity4x4Matrix(&m_mtxWorld);
    Identity4x4Matrix(&m_mtxView);
    Identity4x4Matrix(&m_mtxProjection);
    Identity4x4Matrix(&m_mtxClip);

    ZeroMemory(&m_mtxPC, sizeof(D3DMATRIX));
    ZeroMemory(&m_mtxVPC, sizeof(D3DMATRIX));
    ZeroMemory(&m_mtxWVPC, sizeof(D3DMATRIX));

    ZeroMemory(&m_vdViewportData, sizeof(D3DVIEWPORT2));

    m_csClipStatus.minx = 100000.0F;
    m_csClipStatus.maxx = 0.0F;
    m_csClipStatus.miny = 100000.0F;
    m_csClipStatus.maxy = 0.0F;

    m_xScale  = 1.0F;
    m_yScale  = 1.0F;

    m_xOffset = 0.0F;
    m_yOffset = 0.0F;

    m_dwTransformFlags = 0;

    // set the default values of the render state.
    memcpy(m_rgdwRenderState, s_rgdwRenderStateInit, sizeof(s_rgdwRenderStateInit));

    ZeroMemory(m_rgdwTextureStageState, sizeof(m_rgdwTextureStageState));

    m_dwStatus = SOFTWARE_DEVICE_INITIALIZED;

    g_grdRenderData.Const1 = 1.0f;
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
CDirect3DDevice::~CDirect3DDevice()
{
    SetRenderTarget((LPDIRECTDRAWSURFACE7)NULL, 0);
    SetTexture(0, (LPDIRECTDRAWSURFACE7)NULL);

//	RELEASE(m_pDevice);
	RELEASE(m_pDevice3);
//	RELEASE(m_pDirect3D);
	RELEASE(m_pDirect3D3);
}

#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirect3DDevice::GetCaps(LPD3DDEVICEDESC7 pd3ddd7)
{
	return Static_GetCaps(pd3ddd7);
}

STDMETHODIMP CDirect3DDevice::GetDirect3D(LPDIRECT3D7*)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::SetRenderTarget(LPDIRECTDRAWSURFACE7 pSurface, DWORD dw)
{
    IDirectDrawSurface7 *pZBuffer = NULL;

    // If the render target is already the same surface nothing needs to be done.
    if (m_Target.pSurface == pSurface)
    {
        return S_OK;
    }

    if (pSurface)
    {
        DDSCAPS2 caps = {DDSCAPS_ZBUFFER};
        pSurface->GetAttachedSurface(&caps, &pZBuffer);

        // Fill out the GRF ImageDev structure.
		ZeroMemory(&m_imgdev, sizeof(m_imgdev));
    }

    m_ZBuffer.Set(pZBuffer);
    m_Target.Set(pSurface);

    if (pZBuffer)
    {
        pZBuffer->Release();
        m_rgdwRenderState[D3DRENDERSTATE_ZENABLE] = D3DZB_TRUE;
    }
    else
    {
        m_rgdwRenderState[D3DRENDERSTATE_ZENABLE] = D3DZB_FALSE;
    }

    if (m_Target.pSurface)
    {
		m_imgdev.SetTargetIs555(FALSE);

        if (m_Target.fmt == 565)
        {
            m_imgdev.SetMunged3ToTargetShift0(4);
            m_imgdev.SetMunged3ToTargetShift1(9);
        }
        else if (m_Target.fmt == 555)
        {
            m_imgdev.SetMunged3ToTargetShift0(5);
            m_imgdev.SetMunged3ToTargetShift1(10);
		m_imgdev.SetTargetIs555(TRUE);
        }
        else if (m_Target.fmt == 1555)
        {
            // 1555 means they're drawing to a texture; treat as 565 so they can
            // draw to the alpha bit
            m_imgdev.SetMunged3ToTargetShift0(4);
            m_imgdev.SetMunged3ToTargetShift1(9);
        }
        else
        {
#ifdef _DEBUG
		OutputDebugString("BLADE: Render target must be 555 or 565\r\n");
#endif	
            return D3DERR_INVALID_DEVICE;
        }
    }

#ifdef _DEBUG
    if (m_Target.pSurface && !(m_Target.SurfaceDesc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
    {
        OutputDebugString("BLADE: Render target is in video memory");
    }
    else
    {
        OutputDebugString("BLADE: Render target is in system memory");
    }
#endif	

    if (m_ZBuffer.pSurface && !(m_ZBuffer.SurfaceDesc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
    {
        ERRORMSG("zbuffer must be in system memory");
        return E_FAIL;
    }

	if (pSurface)
	{
		// allow the RenderDevice access to the CDirect3DDevice so it can examine state
		m_imgdev.SetCD3DD(this);

		// force state reevaluation first time
		m_imgdev.StateReevaluationNeeded();

		m_imgdev.InitScreen(m_Target.fmt, (BYTE*)m_Target.SurfaceDesc.lpSurface, m_Target.SurfaceDesc.lPitch,
							m_Target.SurfaceDesc.dwWidth, m_Target.SurfaceDesc.dwHeight);
	}

    return S_OK;
}

STDMETHODIMP CDirect3DDevice::GetRenderTarget(LPDIRECTDRAWSURFACE7 *ppTarget)
{
    if (m_Target.pSurface)
    {
		m_Target.pSurface->AddRef();
        *ppTarget = m_Target.pSurface;
		return S_OK;
    }
    else
    {
        *ppTarget = NULL;
		return DDERR_INVALIDOBJECT;
    }
    return S_OK;
}

STDMETHODIMP CDirect3DDevice::Clear(DWORD dwCount, LPD3DRECT lpRects, DWORD dwFlags, D3DCOLOR dwColor, D3DVALUE dvS, DWORD dwStencil)
{
	if (m_pViewport3)
	{
		if (!dwCount)
		{
			D3DRECT rect;

			dwCount = 1;
			lpRects = &rect;
			rect.x1	= m_viewport.dwX;
			rect.y1	= m_viewport.dwY;
			rect.x2	= m_viewport.dwWidth  + m_viewport.dwX;
			rect.y2	= m_viewport.dwHeight + m_viewport.dwY;

			if (((CDirect3DViewport *)m_pViewport3)->m_pDevice->m_ZBuffer.pSurface == NULL)
				dwFlags &= ~D3DCLEAR_ZBUFFER;
		}

		HRESULT hr;
		hr = m_pViewport3->Clear2(dwCount, lpRects, dwFlags, dwColor, dvS, dwStencil);
#ifdef MLYONS
		if (FAILED(hr))
		{
//			dprintf("Error! %s\n", ddErrorString(hr));
		}
#endif
		return hr;
	}
	else
	{
		// TODO

		return S_OK;
	}

}

STDMETHODIMP CDirect3DDevice::SetViewport(LPD3DVIEWPORT7 pv)
{
	m_viewport = *pv;
	return S_OK;
}

STDMETHODIMP CDirect3DDevice::GetViewport(LPD3DVIEWPORT7 pv)
{
	*pv = m_viewport;
	return S_OK;
}

STDMETHODIMP CDirect3DDevice::SetMaterial(LPD3DMATERIAL7 lpMaterial)
{
	m_material = *lpMaterial;
    m_dwTransformFlags |= XFM_LIGHT_RECALC;
	return S_OK;
}

STDMETHODIMP CDirect3DDevice::GetMaterial(LPD3DMATERIAL7 lpMaterial)
{
	*lpMaterial = m_material;
	return S_OK;
}

STDMETHODIMP CDirect3DDevice::SetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpLight)
{
	if (dwLightIndex >= (sizeof(m_light)/sizeof(m_light[0])))
		return E_FAIL;

    m_dwTransformFlags |= XFM_LIGHT_RECALC;
	m_light[dwLightIndex] = *lpLight;
	return S_OK;
}

STDMETHODIMP CDirect3DDevice::GetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpLight)
{
	if (dwLightIndex > (sizeof(m_light)/sizeof(m_light[0])))
		return E_FAIL;

	*lpLight = m_light[dwLightIndex];
	return S_OK;
}

STDMETHODIMP CDirect3DDevice::BeginStateBlock(void)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::EndStateBlock(LPDWORD)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::PreLoad(LPDIRECTDRAWSURFACE7)
{
	//
	// all textures are in system memory, loaded already to where we want them!
	//
	return S_OK;
}

STDMETHODIMP CDirect3DDevice::DrawPrimitiveVB(D3DPRIMITIVETYPE type, LPDIRECT3DVERTEXBUFFER7 pvb, DWORD dwStartVertex, DWORD dwNumVertices, DWORD dwFlags)
{
	//JJ Fix-A-Roo
	D3DVERTEXBUFFERDESC VBDesc;
	pvb->GetVertexBufferDesc(&VBDesc);

	HRESULT hRes = 0x0;
	LPVOID pBuffer = NULL;

	pvb->Lock(DDLOCK_READONLY, &pBuffer, NULL);

	hRes =  DrawPrimitive(type,
						 VBDesc.dwFVF, 
						 pBuffer,
						 dwNumVertices,
						 dwFlags);
	pvb->Unlock();

	return hRes;
}

STDMETHODIMP CDirect3DDevice::DrawIndexedPrimitiveVB(D3DPRIMITIVETYPE type, LPDIRECT3DVERTEXBUFFER7 pvb, DWORD dwStartVertex, DWORD dwNumVertices, LPWORD lpwIndices, DWORD dwIndexCount, DWORD dwFlags)
{
	//JJ Fix-A-Roo
	D3DVERTEXBUFFERDESC VBDesc;
	pvb->GetVertexBufferDesc(&VBDesc);

	LPVOID pBuffer = NULL;
	pvb->Lock(DDLOCK_READONLY, &pBuffer, NULL);

	HRESULT hRes = 0x0;
	hRes =  DrawIndexedPrimitive(type,
								VBDesc.dwFVF,
								pBuffer,
								dwNumVertices, 
								lpwIndices,
								dwIndexCount,
								dwFlags);

	pvb->Unlock();
	return hRes;
}

STDMETHODIMP CDirect3DDevice::GetTexture(DWORD dwStage,LPDIRECTDRAWSURFACE7 *pps)
{
	if (m_Texture.pSurface)
		return m_Texture.pSurface->AddRef();

	*pps = m_Texture.pSurface;
	return S_OK;
}

STDMETHODIMP CDirect3DDevice::SetTexture(DWORD dwStage,LPDIRECTDRAWSURFACE7 pTexture)
{
	HRESULT					hr;

	// force reevaluation next time
	m_imgdev.StateReevaluationNeeded();

	if (dwStage != 0)
	{
        if (pTexture == NULL)
			return S_OK;
        else
		    return E_FAIL;
	}

	m_Texture.Set(pTexture);

	//
	// tell GRF about this texture
	//
	if (m_Texture.pSurface)
	{
		if (!(m_Texture.SurfaceDesc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY))
		{
			ERRORMSG("texture must be in system memory");
			SetTexture(0,(LPDIRECT3DTEXTURE2)NULL);
			return E_FAIL;
		}

		hr = m_Texture.Lock();

		if (FAILED(hr))
		{
			return hr;
		}

		// make sure we are using system memory for the texture
		ASSERT(NULL != m_Texture.SurfaceDesc.lpSurface);

		m_cfxTexWidth  = (float)m_Texture.SurfaceDesc.dwWidth;
		m_cfyTexHeight = (float)m_Texture.SurfaceDesc.dwHeight;

		m_cxTexWidth  = log2(m_Texture.SurfaceDesc.dwWidth);
		m_cyTexHeight = log2(m_Texture.SurfaceDesc.dwHeight);

		m_imgdev.InitTexture(m_Texture.fmt,							       // DWORD   dwFormat
							 (BYTE*)m_Texture.SurfaceDesc.lpSurface,       // BYTE  * pbTexture
							 m_Texture.SurfaceDesc.lPitch,                 // DWORD   cbPitch
							 m_Texture.SurfaceDesc.dwWidth,                // DWORD   cxWidth
							 m_Texture.SurfaceDesc.dwHeight,               // DWORD   cyHeight
							 m_Texture.fmt == 8 ? m_rgwColorTable : NULL); // WORD  * pwColorTable

		m_Texture.Unlock();
	}

	return S_OK;
}

STDMETHODIMP CDirect3DDevice::ApplyStateBlock(DWORD)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::CaptureStateBlock(DWORD)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::DeleteStateBlock(DWORD)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::GetInfo(DWORD,LPVOID,DWORD)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::Load(LPDIRECTDRAWSURFACE7 dds1, LPPOINT lpp, LPDIRECTDRAWSURFACE7 dds2, LPRECT lpr, DWORD dw)
{
	// todo!
	if (m_pDevice7)
		return m_pDevice7->Load(dds1, lpp, dds2, lpr, dw);
	else
	{
		HRESULT hr;
		IDirect3DTexture2 *pTexture1;
		IDirect3DTexture2 *pTexture2;

		if (FAILED(hr=dds1->QueryInterface(IID_IDirect3DTexture2, (void **)&pTexture1)))
			return hr;

		if (FAILED(hr=dds2->QueryInterface(IID_IDirect3DTexture2, (void **)&pTexture2)))
		{
			RELEASE(pTexture1);
			return hr;
		}

		if (FAILED(hr=pTexture1->Load(pTexture2)))
		{
			//
			// okay, try to blt instead
			//
			hr=dds1->Blt(NULL, dds2, NULL, DDBLT_WAIT, NULL);
		}

		return hr;
	}
}
//========================================================================
//========================================================================
//STDMETHODIMP CDirectDrawSurface::Load(LPDIRECT3DTEXTURE2 psrc2)
//{
//	HRESULT hr;
//
//	IDirect3DTexture*	psrc1 = NULL;
//	IDirect3DTexture*	pdst1 = NULL;
//
//	hr = ((CDirectDrawSurface *)psrc2)->m_pDirectDrawSurface->QueryInterface(IID_IDirect3DTexture, (void **)&psrc1);
//
//	if (FAILED(hr))
//		goto done;
//
//	hr = m_pDirectDrawSurface->QueryInterface(IID_IDirect3DTexture, (void **)&pdst1);
//
//	if (FAILED(hr))
//		goto done;
//
//	hr = pdst1->Load(psrc1);
//
//done:
//	RELEASE(pdst1);
//	RELEASE(psrc1);
//
//	return hr;
//}


STDMETHODIMP CDirect3DDevice::LightEnable(DWORD,BOOL)
{
	return S_OK;
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::GetLightEnable(DWORD,BOOL*)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::SetClipPlane(DWORD,D3DVALUE*)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::GetClipPlane(DWORD,D3DVALUE*)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DDevice::CreateStateBlock(THIS_ D3DSTATEBLOCKTYPE,LPDWORD)
{
	ASSERT(0);
	return E_FAIL;
}
#endif


STDMETHODIMP CDirect3DViewport::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
    if (IID_IUnknown == riid)
    {
        AddRef();
        *ppvObj = (void*)(IUnknown*)this;
        return S_OK;
    }
    else if (IID_IDirect3DViewport3 == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirect3DViewport3 *)this;
        return S_OK;
    }
    else
    {
        *ppvObj = NULL;
        return E_FAIL;
    }
}


ULONG CDirect3DViewport::AddRef(void)
{
    return ++m_cRef;
}

ULONG CDirect3DViewport::Release(void)
{
    if (--m_cRef == 0)
    {
        delete this;
        return 0;
    }
    return m_cRef;
}

    /*** IDirect3DViewport2 methods ***/
STDMETHODIMP CDirect3DViewport::Initialize(LPDIRECT3D)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::GetViewport(LPD3DVIEWPORT)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::SetViewport(LPD3DVIEWPORT)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::TransformVertices(DWORD,LPD3DTRANSFORMDATA,DWORD,LPDWORD)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::LightElements(DWORD,LPD3DLIGHTDATA)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::SetBackground(D3DMATERIALHANDLE)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::GetBackground(LPD3DMATERIALHANDLE,LPBOOL)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::SetBackgroundDepth(LPDIRECTDRAWSURFACE)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::GetBackgroundDepth(LPDIRECTDRAWSURFACE*,LPBOOL)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::Clear(DWORD,LPD3DRECT,DWORD)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::AddLight(LPDIRECT3DLIGHT pLight)
{
	if (pLight)
	{
		RELEASE(m_pLight);
		m_pLight = pLight;
		m_pLight->AddRef();
	}
	return S_OK;
}
STDMETHODIMP CDirect3DViewport::DeleteLight(LPDIRECT3DLIGHT pLight)
{
	if (pLight == m_pLight)
		RELEASE(m_pLight);

	return S_OK;
}
STDMETHODIMP CDirect3DViewport::NextLight(LPDIRECT3DLIGHT pLight,LPDIRECT3DLIGHT*ppLight,DWORD dwFlags)
{
	if (m_pLight && (dwFlags & (D3DNEXT_HEAD|D3DNEXT_TAIL)))
	{
		*ppLight = m_pLight;
		m_pLight->AddRef();
	}
	else
	{
		*ppLight = NULL;
	}
	return S_OK;
}
STDMETHODIMP CDirect3DViewport::GetViewport2(LPD3DVIEWPORT2 data)
{
	*data = m_data;
	return S_OK;
}
STDMETHODIMP CDirect3DViewport::SetViewport2(LPD3DVIEWPORT2 data)
{
	if (data->dwSize == sizeof(m_data))
	{
		m_data = *data;
		return S_OK;
	}

	return DDERR_INVALIDPARAMS;
}
STDMETHODIMP CDirect3DViewport::SetBackgroundDepth2(LPDIRECTDRAWSURFACE4)
{
	return E_NOTIMPL;
}
STDMETHODIMP CDirect3DViewport::GetBackgroundDepth2(LPDIRECTDRAWSURFACE4*,LPBOOL)
{
	return E_NOTIMPL;
}

//========================================================================
//========================================================================
int GetTopBitLocation(int x)
{
	int topbit=31;

	while ((x & 0x80000000) == 0)
	{
		topbit--;
		x <<= 1;
	}

	return topbit;
}

//========================================================================
//========================================================================
int ShiftBitsLeft(int bits, int shift)
{
	if (shift<0)
		return bits >> (-shift);
	else
		return bits << (shift);

}

//========================================================================
//========================================================================
STDMETHODIMP CDirect3DViewport::Clear2(DWORD dwCount, LPD3DRECT lpRects, DWORD dwFlags, D3DCOLOR color, D3DVALUE dvZ, DWORD dwStencil)
{
	HRESULT hr = S_OK;

	if (dwFlags & D3DCLEAR_STENCIL)
	{
		return E_NOTIMPL;
	}

	if (dwFlags & D3DCLEAR_TARGET)
	{
		//
		// convert the color to the desti8nation's format
		//
		DDBLTFX ddbfx = {sizeof(ddbfx)};
		DDSURFACEDESC2 ddsd = {sizeof(ddsd)};

		if (FAILED(hr=m_pDevice->m_Target.pSurface->GetSurfaceDesc(&ddsd))) goto done;

		// get the location of the top bits
		int r = GetTopBitLocation(ddsd.ddpfPixelFormat.dwRBitMask) - GetTopBitLocation(RGB_MAKE(255,0,0));
		int g = GetTopBitLocation(ddsd.ddpfPixelFormat.dwGBitMask) - GetTopBitLocation(RGB_MAKE(0,255,0));
		int b = GetTopBitLocation(ddsd.ddpfPixelFormat.dwBBitMask) - GetTopBitLocation(RGB_MAKE(0,0,255));

		r = ShiftBitsLeft(color & RGB_MAKE(255,0,0), r);
		g = ShiftBitsLeft(color & RGB_MAKE(0,255,0), g);
		b = ShiftBitsLeft(color & RGB_MAKE(0,0,255), b);

		r &= ddsd.ddpfPixelFormat.dwRBitMask;
		g &= ddsd.ddpfPixelFormat.dwGBitMask;
		b &= ddsd.ddpfPixelFormat.dwBBitMask;

		ddbfx.dwFillColor = r | g | b;

		//
		// make sure we're not in the scene
		//
		for (DWORD i=0; i<dwCount; i++)
		{
			hr=m_pDevice->m_Target.pSurface->Blt((RECT *)&lpRects[i], NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbfx);
			if (hr == DDERR_SURFACEBUSY)
			{
				if (m_pDevice->m_dwStatus & SOFTWARE_DEVICE_IN_SCENE)
				{
					//
					// we can't clear if we're in the scene, so gte out of it, and then back in
					//
					m_pDevice->EndScene();
					hr=m_pDevice->m_Target.pSurface->Blt((RECT *)&lpRects[i], NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbfx);
					m_pDevice->BeginScene();
				}
			}
		}
	}

	if (dwFlags & D3DCLEAR_ZBUFFER)
	{
		//
		// convert the z value to a 16-bit word
		//
		DDBLTFX ddbfx = {sizeof(ddbfx)};
		ddbfx.dwFillColor = (WORD)(dvZ * 65535.0f);
		ddbfx.dwFillDepth = ddbfx.dwFillColor;

		for (DWORD i=0; i<dwCount; i++)
		{
			hr=m_pDevice->m_ZBuffer.pSurface->Blt((RECT *)&lpRects[i], NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbfx);
			if (FAILED(hr))
			{
				if (hr == DDERR_INVALIDPARAMS)
				{
					// try to color fill the zbuffer another way
					hr=m_pDevice->m_ZBuffer.pSurface->Blt((RECT *)&lpRects[i], NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &ddbfx);

				}
				else if (hr == DDERR_SURFACEBUSY)
				{
					hr=m_pDevice->m_ZBuffer.pSurface->Unlock(NULL);

					hr=m_pDevice->m_ZBuffer.pSurface->Blt((RECT *)&lpRects[i], NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbfx);
					if (hr == DDERR_INVALIDPARAMS)
						hr=m_pDevice->m_ZBuffer.pSurface->Blt((RECT *)&lpRects[i], NULL, NULL, DDBLT_DEPTHFILL | DDBLT_WAIT, &ddbfx);

					DDSURFACEDESC2 ddsd = { sizeof(ddsd) };
					hr=m_pDevice->m_ZBuffer.pSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK, NULL);

				}

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

done:
	return hr;
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
    if (IID_IUnknown == riid)
    {
        AddRef();
        *ppvObj = (void*)this;
        return S_OK;
    }
    else if (IID_IDirect3DDevice3 == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirect3DDevice3*)this;
        return S_OK;
    }
    else if (IID_IDirect3DBladeDevice == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirect3DDevice3*)this;
        return S_OK;
    }
    else
    {
        *ppvObj = NULL;
        return E_FAIL;
    }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
ULONG CDirect3DDevice::AddRef()
{
    return ++m_cRef;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
ULONG CDirect3DDevice::Release()
{
    if (--m_cRef == 0)
    {
		//
		// check to see if the 3D Device has been added to our list of devices
		//
		if (true)
		{
			IDirect3DDevice7 *pd3dd7 = (IDirect3DDevice7 *)this;
			for (int i=0 ; i<s_nDevCnt ; i++)
			{
				if (s_pDeviceList[i] == pd3dd7)
				{
					//
					// we found it, so bump down the count, then move the one
					// we just lost off the end of the list to the location
					// of the current one
					//
					s_nDevCnt--;
					s_pDeviceList[i]			= s_pDeviceList[s_nDevCnt];
					s_pDeviceList[s_nDevCnt]	= NULL;
				}
			}
		}


		RELEASE(m_Target.pSurface);
		RELEASE(m_ZBuffer.pSurface);
		RELEASE(m_Texture.pSurface);
		
		RELEASE(m_pDevice3);
#ifdef USE_DX7_INTERFACE
		RELEASE(m_pDevice7);
#endif
		RELEASE(m_pDirect3D3);
		RELEASE(m_pViewport3);

        delete this;
        return 0;
    }
    return m_cRef;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetStats(LPD3DSTATS)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::AddViewport(LPDIRECT3DVIEWPORT3 pViewport3)
{
	if (m_pDevice3)
	{
		return m_pDevice3->AddViewport(pViewport3);
	}
	else if (pViewport3)
	{
		RELEASE(m_pViewport3);
		m_pViewport3 = pViewport3;
		m_pViewport3->AddRef();
		return S_OK;
	}

	return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::DeleteViewport(LPDIRECT3DVIEWPORT3 pViewport3)
{
	if (m_pDevice3)
	{
		return m_pDevice3->DeleteViewport(pViewport3);
	}
	else
	{
		return E_NOTIMPL;
	}
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::NextViewport(LPDIRECT3DVIEWPORT3 pViewport, LPDIRECT3DVIEWPORT3 * ppViewport, DWORD dw)
{
	if (m_pDevice3)
	{
		return m_pDevice3->NextViewport(pViewport, ppViewport, dw);
	}
	else
	{
		return E_NOTIMPL;
	}
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetDirect3D(LPDIRECT3D3 * ppDirect3D)
{
    ASSERT(m_pDirect3D3);

    *ppDirect3D = m_pDirect3D3;
    m_pDirect3D3->AddRef();

    return(D3D_OK);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::SetCurrentViewport(LPDIRECT3DVIEWPORT3 pViewport3)
{
	if (m_pDevice3)
	{
		return m_pDevice3->SetCurrentViewport(pViewport3);
	}
	else
	{
		RELEASE(m_pViewport3);
		m_pViewport3 = pViewport3;
		m_pViewport3->AddRef();
		((CDirect3DViewport*)pViewport3)->m_pDevice = this;
		return S_OK;
	}
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetCurrentViewport(LPDIRECT3DVIEWPORT3 *ppViewport)
{
	if (m_pDevice3)
	{
		return m_pDevice3->GetCurrentViewport(ppViewport);
	}
	else if (m_pViewport3)
	{
		m_pViewport3->AddRef();
		*ppViewport = m_pViewport3;
		return S_OK;
	}
	return E_FAIL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::SetRenderTarget(LPDIRECTDRAWSURFACE4 pSurface, DWORD)
{
	return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetRenderTarget(LPDIRECTDRAWSURFACE4 * ppTarget)
{
	return E_NOTIMPL;
}


//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::Begin(D3DPRIMITIVETYPE,DWORD,DWORD)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::BeginIndexed(D3DPRIMITIVETYPE,DWORD,LPVOID,DWORD,DWORD)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::Vertex(LPVOID)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::Index(WORD)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::End(DWORD)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetRenderState(D3DRENDERSTATETYPE dwStateType, LPDWORD pdwState)
{
    if (dwStateType <= MAX_RENDER_STATE)
    {
        *pdwState = m_rgdwRenderState[dwStateType];
    }
    else
    {
        *pdwState = 0;
    }

    return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::SetRenderState(D3DRENDERSTATETYPE dwStateType, DWORD dwState)
{
    if ((dwStateType <= MAX_RENDER_STATE) && (dwState != -1))
    {
        if (m_ZBuffer.pSurface == NULL && dwStateType == D3DRENDERSTATE_ZENABLE)
        {
            dwState = D3DZB_FALSE;
        }

        m_rgdwRenderState[dwStateType] = dwState;

        // convert old-style texblend to texture stage settings
        if (dwStateType == D3DRENDERSTATE_TEXTUREMAPBLEND)
        {
            switch (dwState)
            {
            case D3DTBLEND_DECAL:
            case D3DTBLEND_COPY:
                m_rgdwTextureStageState[D3DTSS_COLOROP] = D3DTOP_SELECTARG1;
                m_rgdwTextureStageState[D3DTSS_COLORARG1] = D3DTA_TEXTURE;
                m_rgdwTextureStageState[D3DTSS_ALPHAOP] = D3DTOP_SELECTARG1;
                m_rgdwTextureStageState[D3DTSS_ALPHAARG1] = D3DTA_TEXTURE;
                break;

            case D3DTBLEND_MODULATE:
                m_rgdwTextureStageState[D3DTSS_COLOROP] = D3DTOP_MODULATE;
                m_rgdwTextureStageState[D3DTSS_COLORARG1] = D3DTA_TEXTURE;
                m_rgdwTextureStageState[D3DTSS_COLORARG2] = D3DTA_DIFFUSE;
                m_rgdwTextureStageState[D3DTSS_ALPHAOP] = D3DTOP_SELECTARG1;
                m_rgdwTextureStageState[D3DTSS_ALPHAARG1] = D3DTA_TEXTURE;
                break;

            case D3DTBLEND_MODULATEALPHA:
                m_rgdwTextureStageState[D3DTSS_COLOROP] = D3DTOP_MODULATE;
                m_rgdwTextureStageState[D3DTSS_COLORARG1] = D3DTA_TEXTURE;
                m_rgdwTextureStageState[D3DTSS_COLORARG2] = D3DTA_DIFFUSE;
                m_rgdwTextureStageState[D3DTSS_ALPHAOP] = D3DTOP_MODULATE;
                m_rgdwTextureStageState[D3DTSS_ALPHAARG1] = D3DTA_TEXTURE;
                m_rgdwTextureStageState[D3DTSS_ALPHAARG2] = D3DTA_DIFFUSE;
                break;
            }
        }

        if (dwStateType == D3DRENDERSTATE_AMBIENT)
		{
			m_dwTransformFlags |= XFM_LIGHT_RECALC;
		}

        // force reevaluation next time
        m_imgdev.StateReevaluationNeeded();
    }

    return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetLightState(D3DLIGHTSTATETYPE dwStateType, LPDWORD pdwState)
{
    ASSERT(m_pDevice3);
    return m_pDevice3->GetLightState(dwStateType, pdwState);
//#ifdef USE_DX7_INTERFACE
//	if (m_pDevice7)
//	    return m_pDevice7->GetLightState(dwStateType, pdwState);
//#else
//    ASSERT(m_pDevice3);
//#endif
//    return m_pDevice3->GetLightState(dwStateType, pdwState);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::SetLightState(D3DLIGHTSTATETYPE dwStateType, DWORD dwState)
{
    if (m_pDevice3)
	    return m_pDevice3->SetLightState(dwStateType, dwState);
	else
		return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::SetClipStatus(LPD3DCLIPSTATUS pcs)
{
    m_csClipStatus = *pcs;
    return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetClipStatus(LPD3DCLIPSTATUS pcs)
{
    *pcs = m_csClipStatus;
    return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CDirect3DDevice::UpdateWorldTransform()
{
    // Mark the world matrix as dirty (anything dependent on it needs to be updated).
    m_dwTransformFlags |= XFM_WORLD_MATRIX_CHANGED;
    m_dwTransformFlags |= XFM_LIGHT_POS_CHANGED;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CDirect3DDevice::UpdateViewTransform()
{
    // Mark the view matrix as dirty (anything dependent on it needs to be updated).
    m_dwTransformFlags |= XFM_VIEW_MATRIX_CHANGED;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CDirect3DDevice::UpdateProjectionTransform()
{
    // Mark the projection matrix as dirty (anything dependent on it needs to be updated).
    m_dwTransformFlags |= XFM_PROJECTION_MATRIX_CHANGED;

    // Check if the it is a perspective projection (we optimize for this).
    if (0.0F == m_mtxProjection._12 &&
        0.0F == m_mtxProjection._13 &&
        0.0F == m_mtxProjection._14 &&
        0.0F == m_mtxProjection._21 &&
        0.0F == m_mtxProjection._23 &&
        0.0F == m_mtxProjection._24 &&
        0.0F == m_mtxProjection._31 &&
        0.0F == m_mtxProjection._33 &&
        0.0F == m_mtxProjection._41 &&
        0.0F == m_mtxProjection._42 &&
        1.0F == m_mtxProjection._34)
    {
        m_dwTransformFlags |= XFM_PROJECTION_IS_PERSPECTIVE;
    }
    else
    {
        m_dwTransformFlags &= ~XFM_PROJECTION_IS_PERSPECTIVE;
    }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CDirect3DDevice::UpdateClipTransform()
{
    D3DVIEWPORT2         vdViewportData;

#ifdef USE_DX7_INTERFACE
		D3DVIEWPORT7 d3dViewport7;

		if (FAILED(GetViewport(&d3dViewport7)))
		{
			ASSERT(0);
		}

		//vdViewportData

		ZeroMemory(&vdViewportData, sizeof(D3DVIEWPORT2));
		vdViewportData.dwSize = sizeof(D3DVIEWPORT2);

		vdViewportData.dwX			= d3dViewport7.dwX;
		vdViewportData.dwY			= d3dViewport7.dwY;
		vdViewportData.dwWidth		= d3dViewport7.dwWidth;
		vdViewportData.dwHeight		= d3dViewport7.dwHeight;
		vdViewportData.dvClipX		= 0;//(float)d3dViewport7.dwX;
		vdViewportData.dvClipY		= 0;//(float)d3dViewport7.dwY;
		vdViewportData.dvClipWidth	= 2.0f;
		vdViewportData.dvClipHeight	= 2.0f;
		vdViewportData.dvMinZ		= d3dViewport7.dvMinZ;
		vdViewportData.dvMaxZ		= d3dViewport7.dvMaxZ;

#else
    IDirect3DViewport3 * pvpViewport;

	if (SUCCEEDED(GetCurrentViewport(&pvpViewport)))
	{
		ZeroMemory(&vdViewportData, sizeof(D3DVIEWPORT2));
		vdViewportData.dwSize = sizeof(D3DVIEWPORT2);

		if (FAILED(pvpViewport->GetViewport2(&vdViewportData)))
		{
			RELEASE(pvpViewport);
			return;
		}

		RELEASE(pvpViewport);
	}
	else
	{
		return; // E_FAIL
	}
#endif

    // Check if the viewport data has changed.
    if ((vdViewportData.dwX          != m_vdViewportData.dwX)          ||
        (vdViewportData.dwY          != m_vdViewportData.dwY)          ||
        (vdViewportData.dwWidth      != m_vdViewportData.dwWidth)      ||
        (vdViewportData.dwHeight     != m_vdViewportData.dwHeight)     ||
        (vdViewportData.dvClipX      != m_vdViewportData.dvClipX)      ||
        (vdViewportData.dvClipY      != m_vdViewportData.dvClipY)      ||
        (vdViewportData.dvClipWidth  != m_vdViewportData.dvClipWidth)  ||
        (vdViewportData.dvClipHeight != m_vdViewportData.dvClipHeight) ||
        (vdViewportData.dvMinZ       != m_vdViewportData.dvMinZ)       ||
        (vdViewportData.dvMaxZ       != m_vdViewportData.dvMaxZ))
    {
        m_dwTransformFlags |= XFM_CLIP_MATRIX_CHANGED;

        // Copy over the new viewport data.
        memcpy(&m_vdViewportData, &vdViewportData, sizeof(D3DVIEWPORT2));

        // Make sure that there wont be a divide by zero.
        if ((0    == vdViewportData.dwWidth)      ||
            (0    == vdViewportData.dwHeight)     ||
            (0.0F == vdViewportData.dvClipWidth)  ||
            (0.0F == vdViewportData.dvClipHeight) ||
            (0.0F == vdViewportData.dvMaxZ - vdViewportData.dvMinZ))
        {
            Identity4x4Matrix(&m_mtxClip);
            return;
        }

#ifdef APPLY_VIEWPORT_FIX_BUT_OPTIMIZE_THIS_SOMETIME

		Identity4x4Matrix(&m_mtxClip);

		m_mtxClip._11 = 1.0f / (1.0f - -1.0f);
		m_mtxClip._12 = 0.0f;
		m_mtxClip._13 = 0.0f;
		m_mtxClip._14 = 0.0f;

		m_mtxClip._21 = 0.0f;
		m_mtxClip._22 = 1.0f / (1.0f - -1.0f);
		m_mtxClip._23 = 0.0f;
		m_mtxClip._24 = 0.0f;

		m_mtxClip._31 = 0.0f;
		m_mtxClip._32 = 0.0f;
		m_mtxClip._33 = 1.0f / (vdViewportData.dvMaxZ - vdViewportData.dvMinZ);
		m_mtxClip._34 = 0.0f;

		m_mtxClip._41 = 1.0f / (1.0f - -1.0f);
		m_mtxClip._42 = 1.0f / (1.0f - -1.0f);
		m_mtxClip._43 = 0.0f;
		m_mtxClip._44 = 1.0f;
#endif

#ifndef USE_DX7_INTERFACE
        // Generate the clip matrix (commented out sections never change so don't need to be updated).
        //   The clip matrix translates the coordinates from:
        //       MinX - MaxX: 0.0 - 1.0
        //       MinY - MaxY: 0.0 - 1.0
        //       MinZ - MaxZ: 0.0 - Zfar

        m_mtxClip._11 = 1.0F / vdViewportData.dvClipWidth;

//        m_mtxClip._12 = 0.0F;
//        m_mtxClip._13 = 0.0F;
//        m_mtxClip._14 = 0.0F;

//        m_mtxClip._21 = 0.0F;
        m_mtxClip._22 = 1.0F / vdViewportData.dvClipHeight;
//        m_mtxClip._23 = 0.0F;
//        m_mtxClip._24 = 0.0F;

//        m_mtxClip._31 = 0.0F;
//        m_mtxClip._32 = 0.0F;
        m_mtxClip._33 = 1.0F / (vdViewportData.dvMaxZ - vdViewportData.dvMinZ);
//        m_mtxClip._34 = 0.0F;

        m_mtxClip._41 =      - m_mtxClip._11 * vdViewportData.dvClipX;
        m_mtxClip._42 = 1.0F - m_mtxClip._22 * vdViewportData.dvClipY;
        m_mtxClip._43 =      - m_mtxClip._33 * vdViewportData.dvMinZ;
//        m_mtxClip._44 = 1.0F;
#endif

        // Scale from "0.0 - 1.0" to "0 - screen width" and "0 - screen height"

        m_xScale = (float)(vdViewportData.dwWidth);
        m_yScale = - (float)(vdViewportData.dwHeight);

        // Top left corner of view window.

        m_xOffset = (float)(vdViewportData.dwX);
        m_yOffset = (float)(vdViewportData.dwY + vdViewportData.dwHeight);
    }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline D3DVECTOR InverseRotate(const D3DVECTOR& vin, const D3DMATRIX& mat)
{
    D3DVECTOR vout;
    D3DVALUE x = vin.x;
    D3DVALUE y = vin.y;
    D3DVALUE z = vin.z;
    vout.x = x * mat._11 + y * mat._12 + z * mat._13;
    vout.y = x * mat._21 + y * mat._22 + z * mat._23;
    vout.z = x * mat._31 + y * mat._32 + z * mat._33;
    return vout;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CDirect3DDevice::UpdateLighting()
{
    if (m_dwTransformFlags & XFM_LIGHT_RECALC)
    {
		D3DCOLOR rgb = m_rgdwRenderState[D3DRENDERSTATE_AMBIENT];

		//
		// precompute material diffuse *  light diffuse
		//
		m_diffuse.r = m_material.diffuse.r * m_light[0].dcvDiffuse.r;
		m_diffuse.g = m_material.diffuse.g * m_light[0].dcvDiffuse.g;
		m_diffuse.b = m_material.diffuse.b * m_light[0].dcvDiffuse.b;
		m_diffuse.a = m_material.diffuse.a;

		//
		// precompute light ambient + material emissive + material ambient * global ambient
		//
		m_ambient = m_light[0].dcvAmbient;

		m_ambient.r += m_material.emissive.r;
		m_ambient.g += m_material.emissive.g;
		m_ambient.b += m_material.emissive.b;

		m_ambient.r += m_material.ambient.r * RGBA_GETRED(rgb)	/ 255.0f;
		m_ambient.g += m_material.ambient.g * RGBA_GETGREEN(rgb) / 255.0f;
		m_ambient.b += m_material.ambient.b * RGBA_GETBLUE(rgb)	/ 255.0f;

		m_ambient.r = max(0.0f, min(m_ambient.r, 1.0f));
		m_ambient.g = max(0.0f, min(m_ambient.g, 1.0f));
		m_ambient.b = max(0.0f, min(m_ambient.b, 1.0f));

		m_ambient_color = D3DRGBA(m_ambient.r, m_ambient.g, m_ambient.b, m_diffuse.a);

		if (m_diffuse.r == 0 && m_diffuse.g == 0 && m_diffuse.b == 0)
		{
			m_dwTransformFlags |= XFM_LIGHT_AMBIENT_ONLY;
		}
		else
		{
			m_dwTransformFlags &= ~XFM_LIGHT_AMBIENT_ONLY;
		}

		m_dwTransformFlags &= ~XFM_LIGHT_RECALC;
	}

    if (m_dwTransformFlags & XFM_LIGHT_POS_CHANGED)
    {
        if (!(m_dwTransformFlags & XFM_LIGHT_AMBIENT_ONLY))
        {
            m_light_dir = m_light[0].dvDirection * -1.0;
            m_light_dir = InverseRotate(m_light_dir, m_mtxWorld);
            m_light_dir = Normalize(m_light_dir);
        }

        m_dwTransformFlags &= ~XFM_LIGHT_POS_CHANGED;
    }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CDirect3DDevice::UpdateTransforms()
{
    // Calculate the Projection x Clip matrix.
    if (m_dwTransformFlags & (XFM_PC_MATRIX_CHANGED))
    {

#ifdef CLIP_NEG1_TO_1
		m_mtxPC = m_mtxProjection;
#else
#ifdef APPLY_CLIP_MATRIX_SEPARATELY
		m_mtxPC = m_mtxProjection;
#else
        m_mtxPC._11 = m_mtxProjection._11 * m_mtxClip._11 +
                      m_mtxProjection._14 * m_mtxClip._41;
        m_mtxPC._12 = m_mtxProjection._12 * m_mtxClip._22 +
                      m_mtxProjection._14 * m_mtxClip._42;
        m_mtxPC._13 = m_mtxProjection._13 * m_mtxClip._33 +
                      m_mtxProjection._14 * m_mtxClip._43;
        m_mtxPC._14 = m_mtxProjection._14;

        m_mtxPC._21 = m_mtxProjection._21 * m_mtxClip._11 +
                      m_mtxProjection._24 * m_mtxClip._41;
        m_mtxPC._22 = m_mtxProjection._22 * m_mtxClip._22 +
                      m_mtxProjection._24 * m_mtxClip._42;
        m_mtxPC._23 = m_mtxProjection._23 * m_mtxClip._33 +
                      m_mtxProjection._24 * m_mtxClip._43;
        m_mtxPC._24 = m_mtxProjection._24;

        m_mtxPC._31 = m_mtxProjection._31 * m_mtxClip._11 +
                      m_mtxProjection._34 * m_mtxClip._41;
        m_mtxPC._32 = m_mtxProjection._32 * m_mtxClip._22 +
                      m_mtxProjection._34 * m_mtxClip._42;
        m_mtxPC._33 = m_mtxProjection._33 * m_mtxClip._33 +
                      m_mtxProjection._34 * m_mtxClip._43;
        m_mtxPC._34 = m_mtxProjection._34;

        m_mtxPC._41 = m_mtxProjection._41 * m_mtxClip._11 +
                      m_mtxProjection._44 * m_mtxClip._41;
        m_mtxPC._42 = m_mtxProjection._42 * m_mtxClip._22 +
                      m_mtxProjection._44 * m_mtxClip._42;
        m_mtxPC._43 = m_mtxProjection._43 * m_mtxClip._33 +
                      m_mtxProjection._44 * m_mtxClip._43;
        m_mtxPC._44 = m_mtxProjection._44;
#endif
#endif
    }

    // Calculate the View x Projection x Clip matrix.
    if (m_dwTransformFlags & (XFM_VPC_MATRIX_CHANGED))
    {
        Mult4x4Matrix(&m_mtxView, &m_mtxPC, &m_mtxVPC);
    }

    // Calculate the World x View x Projection x Clip matrix.
    if (m_dwTransformFlags & (XFM_WVPC_MATRIX_CHANGED))
    {
        Mult4x4Matrix(&m_mtxWorld, &m_mtxVPC, &m_mtxWVPC);
    }

    // Clear the dirty bits.
    m_dwTransformFlags &= ~XFM_MATRIX_CHANGED_MASK;
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void Interpolate(GRFCLIPVERTEX * pcvIn1,
                 GRFCLIPVERTEX * pcvIn2,
                 float           dNum,
                 float           dDenom,
                 DWORD           dwFlag,
                 GRFCLIPVERTEX * pcvOut)
{
    if (dDenom == 0)
    {
        // the two points are right on top of each other

        // Mark the vertex as having been generated by clipping (i.e. it
        //   needs to be translated to screen coordinates before the
        //   actual drawing.

        pcvOut->dwFlags = ((pcvIn1->dwFlags & pcvIn2->dwFlags) & CLIPPED_MASK) | dwFlag;

        pcvOut->hx = pcvIn1->hx;
        pcvOut->hy = pcvIn1->hy;
        pcvOut->hz = pcvIn1->hz;
        pcvOut->hw = pcvIn1->hw;

        pcvOut->tu = pcvIn1->tu;
        pcvOut->tv = pcvIn1->tv;

        pcvOut->color = pcvIn1->color;
        pcvOut->specular = pcvIn1->specular;
    }
    else
    {
        float dNumDenom = dNum / dDenom;

        // Mark the vertex as having been generated by clipping (i.e. it
        //   needs to be translated to screen coordinates before the
        //   actual drawing.

        pcvOut->dwFlags = ((pcvIn1->dwFlags & pcvIn2->dwFlags) & CLIPPED_MASK) | dwFlag;

        pcvOut->hx = pcvIn1->hx + (pcvIn2->hx - pcvIn1->hx) * dNumDenom;
        pcvOut->hy = pcvIn1->hy + (pcvIn2->hy - pcvIn1->hy) * dNumDenom;
        pcvOut->hz = pcvIn1->hz + (pcvIn2->hz - pcvIn1->hz) * dNumDenom;
        pcvOut->hw = pcvIn1->hw + (pcvIn2->hw - pcvIn1->hw) * dNumDenom;

        pcvOut->tu = pcvIn1->tu + (pcvIn2->tu - pcvIn1->tu) * dNumDenom;
        pcvOut->tv = pcvIn1->tv + (pcvIn2->tv - pcvIn1->tv) * dNumDenom;

        int r1 = RGBA_GETRED(pcvIn1->color);
        int g1 = RGBA_GETGREEN(pcvIn1->color);
        int b1 = RGBA_GETBLUE(pcvIn1->color);
        int a1 = RGBA_GETALPHA(pcvIn1->color);

        int r2 = RGBA_GETRED(pcvIn2->color);
        int g2 = RGBA_GETGREEN(pcvIn2->color);
        int b2 = RGBA_GETBLUE(pcvIn2->color);
        int a2 = RGBA_GETALPHA(pcvIn2->color);

        pcvOut->color = RGBA_MAKE((WORD)(r1 + (r2 - r1) * dNumDenom),
                                  (WORD)(g1 + (g2 - g1) * dNumDenom),
                                  (WORD)(b1 + (b2 - b1) * dNumDenom),
                                  (WORD)(a1 + (a2 - a1) * dNumDenom));

        pcvOut->specular = pcvIn1->specular;
    }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#define _CLIP_TRI_FN_NAME_  ClipTriFront
#define _CLIP_LINE_FN_NAME_ ClipLineFront
#define _CLIP_FLAG_         CLIPPED_FRONT
#define _CLIP_COORD_        hz
#undef  _CLIP_HW_
#include "..\inc\clip.h"

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define _CLIP_TRI_FN_NAME_  ClipTriBack
#define _CLIP_LINE_FN_NAME_ ClipLineBack
#define _CLIP_FLAG_         CLIPPED_BACK
#define _CLIP_COORD_        hz
#undef  _CLIP_HW_
#include "..\inc\clip.h"

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define _CLIP_TRI_FN_NAME_  ClipTriLeft
#define _CLIP_LINE_FN_NAME_ ClipLineLeft
#define _CLIP_FLAG_         CLIPPED_LEFT
#define _CLIP_COORD_        hx
#undef  _CLIP_HW_
#include "..\inc\clip.h"

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define _CLIP_TRI_FN_NAME_  ClipTriRight
#define _CLIP_LINE_FN_NAME_ ClipLineRight
#define _CLIP_FLAG_         CLIPPED_RIGHT
#define _CLIP_COORD_        hx
#define _CLIP_HW_
#include "..\inc\clip.h"

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define _CLIP_TRI_FN_NAME_  ClipTriTop
#define _CLIP_LINE_FN_NAME_ ClipLineTop
#define _CLIP_FLAG_         CLIPPED_TOP
#define _CLIP_COORD_        hy
#undef  _CLIP_HW_
#include "..\inc\clip.h"

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
#define _CLIP_TRI_FN_NAME_  ClipTriBottom
#define _CLIP_LINE_FN_NAME_ ClipLineBottom
#define _CLIP_FLAG_         CLIPPED_BOTTOM
#define _CLIP_COORD_        hy
#define _CLIP_HW_
#include "..\inc\clip.h"

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

void CDirect3DDevice::ComputeScreenCoordinates(GRFCLIPVERTEX ** rgpcvIn, int cIn)
{
    GRFCLIPVERTEX * pcv;
    int             iIn;
    float           invhw;

    for (iIn = 0; iIn < cIn; iIn++)
    {
        pcv = rgpcvIn[iIn];

        // Was this vertex generated during clipping?
#if 0
        if (pcv->dwFlags & CLIPPED_MASK)
        {

            switch(pcv->dwFlags & (CLIPPED_FRONT|CLIPPED_BACK))
            {
            case CLIPPED_FRONT:

// This is somewhat bogus - it needs to be based on the minimum and maximum allowable z
//   values.

                invhw   = 0.9999999999F;
                pcv->sz = 0.0000000001F;
                break;

            case CLIPPED_BACK:

// This is somewhat bogus - it needs to be based on the minimum and maximum allowable z
//   values.

                invhw   = 0.0000000001F;
                pcv->sz = 0.9999999999F;
                break;

            default:

                invhw = 1.0F / pcv->hw;
                if (invhw < 0.0000000001F)
                {
                    invhw = 0.0000000001F;
                }

// Only true if z goes from one to infinity.

//                else if (invhw > 0.9999999999F)
//                {
//                    invhw = 0.9999999999F;
//                }

                pcv->sz = pcv->hz * invhw;
                break;
            }
		}
#else

            switch(pcv->dwFlags & (CLIPPED_FRONT|CLIPPED_BACK))
            {
            case CLIPPED_FRONT:

// This is somewhat bogus - it needs to be based on the minimum and maximum allowable z
//   values.

                invhw   = 0.9999999999F;
                pcv->sz = 0.0000000001F;
                break;

            case CLIPPED_BACK:

// This is somewhat bogus - it needs to be based on the minimum and maximum allowable z
//   values.

                invhw   = 0.0000000001F;
                pcv->sz = 0.9999999999F;
                break;

            default:

                invhw = 1.0F / pcv->hw;
                if (invhw < 0.0000000001F)
                {
                    invhw = 0.0000000001F;
                }

// Only true if z goes from one to infinity.

//                else if (invhw > 0.9999999999F)
//                {
//                    invhw = 0.9999999999F;
//                }

                pcv->sz = pcv->hz * invhw;
				if (pcv->sz < 0.0f)
					pcv->sz = 0.0f;
				if (pcv->sz > 1.0f)
					pcv->sz = 1.0f;
                break;
            }
#endif

        switch(pcv->dwFlags & (CLIPPED_LEFT|CLIPPED_RIGHT))
        {
        case CLIPPED_LEFT:

// Shouldn't have to putz with the multiplier here.

            pcv->sx = 0.0000000001F * m_xScale + m_xOffset;
            break;
        case CLIPPED_RIGHT:

// Shouldn't have to putz with the multiplier here.

            pcv->sx = 0.9999999999F * m_xScale + m_xOffset;
            break;
        default:
            pcv->sx = pcv->hx * m_xScale * invhw + m_xOffset;
			if (pcv->sx < 0.0f)
				pcv->sx = 0.0f;
			if (pcv->sx > (float)(m_vdViewportData.dwX + m_vdViewportData.dwWidth))
				pcv->sx = (float)(m_vdViewportData.dwX + m_vdViewportData.dwWidth);
            break;
        }

        switch(pcv->dwFlags & (CLIPPED_TOP|CLIPPED_BOTTOM))
        {
        case CLIPPED_TOP:

// Shouldn't have to putz with the multiplier here.

            pcv->sy = 0.0000000001F * m_yScale + m_yOffset;
            break;
        case CLIPPED_BOTTOM:

// Shouldn't have to putz with the multiplier here.

            pcv->sy = 0.9999999999F * m_yScale + m_yOffset;
            break;
        default:
            pcv->sy = pcv->hy * m_yScale * invhw + m_yOffset;
			if (pcv->sy < 0.0f)
				pcv->sy = 0.0f;
			if (pcv->sy > (float)(m_vdViewportData.dwY + m_vdViewportData.dwHeight))
				pcv->sy = (float)(m_vdViewportData.dwY + m_vdViewportData.dwHeight);
            break;
        }

        pcv->rhw = invhw;

        ASSERT(pcv->sx >= (float)m_vdViewportData.dwX);
        ASSERT(pcv->sy >= (float)m_vdViewportData.dwY);

        ASSERT(pcv->sx <= (float)(m_vdViewportData.dwX + m_vdViewportData.dwWidth));
        ASSERT(pcv->sy <= (float)(m_vdViewportData.dwY + m_vdViewportData.dwHeight));

        ASSERT(pcv->sz >= 0.0F);
        ASSERT(pcv->sz <= 1.0F);

    }
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

#define MAX_CLIP_VERTECIES  15
#define SWAP(in, out, swap) swap = in; in = out; out = swap;

void CDirect3DDevice::ClipAndDrawTriangle(GRFCLIPVERTEX * pcv1,
                                         GRFCLIPVERTEX * pcv2,
                                         GRFCLIPVERTEX * pcv3,
                                         DWORD           dwClipFlags)
{
    GRFCLIPVERTEX  rgcvTemp[MAX_CLIP_VERTECIES];
    GRFCLIPVERTEX  * rgpcv[MAX_CLIP_VERTECIES * 2];
    GRFCLIPVERTEX  ** ppcvIn, ** ppcvOut, ** ppcvSwap;

    int            cIn, cTemp;
    int            iIn;

    // Setup the buffers to use for storing the clipped pointers.
    ppcvIn  = rgpcv;
    ppcvOut = rgpcv + MAX_CLIP_VERTECIES;

    // Setup the input buffer pointers.
    ppcvIn[0] = pcv1;
    ppcvIn[1] = pcv2;
    ppcvIn[2] = pcv3;

    // Start with 3 vertecies in and 0 vertecies generated.
    cIn   = 3;
    cTemp = 0;

    // Perform the clipping, one clipping plane at a time (note that we don't update the
    //   clip flags, so we might be checking some clipping planes that we don't need to
    //   after having clipped to another clipping plane).

    if (dwClipFlags & CLIP_SIDE_FRONT)
    {
        cIn = ClipTriFront(ppcvIn, cIn, ppcvOut, rgcvTemp, &cTemp);
        if (cIn < 3)
            goto done;
		
		dwClipFlags |= CheckClipCodesTri(ppcvOut, cIn);

        SWAP(ppcvIn, ppcvOut, ppcvSwap);
    }

    if (dwClipFlags & CLIP_SIDE_BACK)
    {
        cIn = ClipTriBack(ppcvIn, cIn, ppcvOut, rgcvTemp, &cTemp);
        if (cIn < 3)
            goto done;
        SWAP(ppcvIn, ppcvOut, ppcvSwap);
    }

    if (dwClipFlags & CLIP_SIDE_LEFT)
    {
        cIn = ClipTriLeft(ppcvIn, cIn, ppcvOut, rgcvTemp, &cTemp);
        if (cIn < 3)
            goto done;
        SWAP(ppcvIn, ppcvOut, ppcvSwap);
    }

    if (dwClipFlags & CLIP_SIDE_RIGHT)
    {
        cIn = ClipTriRight(ppcvIn, cIn, ppcvOut, rgcvTemp, &cTemp);
        if (cIn < 3)
            goto done;
        SWAP(ppcvIn, ppcvOut, ppcvSwap);
    }

    if (dwClipFlags & CLIP_SIDE_TOP)
    {
        cIn = ClipTriTop(ppcvIn, cIn, ppcvOut, rgcvTemp, &cTemp);
        if (cIn < 3)
            goto done;
        SWAP(ppcvIn, ppcvOut, ppcvSwap);
    }

    if (dwClipFlags & CLIP_SIDE_BOTTOM)
    {
        cIn = ClipTriBottom(ppcvIn, cIn, ppcvOut, rgcvTemp, &cTemp);
        if (cIn < 3)
            goto done;
        SWAP(ppcvIn, ppcvOut, ppcvSwap);
    }

    // Convert the triangles to screen space.
    ComputeScreenCoordinates(ppcvIn, cIn);
	
	//
	// if we're in flat shaded mode, make sure all the colors of all the
	// newly generated vertices match the color of vertex 0
	if (m_rgdwRenderState[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_FLAT)
	{
	    for (iIn = 0; iIn < cIn ; iIn++)
			ppcvIn[iIn]->color = pcv1->color;
	}

    // Draw the clipped portions as a triangle fan.
    for (iIn = 0; iIn < cIn - 2; iIn++)
    {
        DrawTriangle((D3DTLVERTEX *) ppcvIn[0],
                     (D3DTLVERTEX *) ppcvIn[iIn + 1],
                     (D3DTLVERTEX *) ppcvIn[iIn + 2]);
    }

done:
    return;

}

void CDirect3DDevice::ClipAndDrawLine(GRFCLIPVERTEX * pcv1,
                                     GRFCLIPVERTEX * pcv2,
                                     DWORD           dwClipFlags)
{
    // Perform the clipping, one clipping plane at a time (note that we don't update the
    //   clip flags, so we might be checking some clipping planes that we don't need to
    //   after having clipped to another clipping plane).

    if (dwClipFlags & CLIP_SIDE_FRONT)
    {
        if (!ClipLineFront(pcv1, pcv2))
            goto done;

		dwClipFlags |= CheckClipCodes(pcv1,pcv2);
    }

    if (dwClipFlags & CLIP_SIDE_BACK)
    {
        if (!ClipLineBack(pcv1, pcv2))
            goto done;
    }

    if (dwClipFlags & CLIP_SIDE_LEFT)
    {
        if (!ClipLineLeft(pcv1, pcv2))
            goto done;
    }

    if (dwClipFlags & CLIP_SIDE_RIGHT)
    {
        if (!ClipLineRight(pcv1, pcv2))
            goto done;
    }

    if (dwClipFlags & CLIP_SIDE_TOP)
    {
        if (!ClipLineTop(pcv1, pcv2))
            goto done;
    }

    if (dwClipFlags & CLIP_SIDE_BOTTOM)
    {
        if (!ClipLineBottom(pcv1, pcv2))
            goto done;
    }

    // Convert the line to screen space.
    ComputeScreenCoordinates(&pcv1, 1);
    ComputeScreenCoordinates(&pcv2, 1);

    // Draw the clipped line.
    DrawLine((D3DTLVERTEX *) pcv1, (D3DTLVERTEX *) pcv2);

done:
    return;
}

#undef MAX_VERTECIES
#undef SWAP

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::SetTransform(D3DTRANSFORMSTATETYPE dwStateType, D3DMATRIX * pmtx)
{
    if (NULL == pmtx)
        return DDERR_INVALIDPARAMS;

    switch(dwStateType)
    {
        case D3DTRANSFORMSTATE_WORLD:
            m_mtxWorld = *pmtx;
            UpdateWorldTransform();
            return D3D_OK;

        case D3DTRANSFORMSTATE_VIEW:
            m_mtxView = *pmtx;
            UpdateViewTransform();
            return D3D_OK;

        case D3DTRANSFORMSTATE_PROJECTION:
            m_mtxProjection = *pmtx;
            UpdateProjectionTransform();
            return D3D_OK;

        case D3DTRANSFORMSTATE_WORLD1:
        case D3DTRANSFORMSTATE_WORLD2:
        case D3DTRANSFORMSTATE_WORLD3:
			return S_OK;

        default:
            return DDERR_INVALIDPARAMS;
    }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetTransform(D3DTRANSFORMSTATETYPE dwStateType, D3DMATRIX * pmtx)
{
    if (NULL == pmtx)
        return DDERR_INVALIDPARAMS;

    switch(dwStateType)
    {
        case D3DTRANSFORMSTATE_WORLD:
            *pmtx = m_mtxWorld;
            return D3D_OK;

        case D3DTRANSFORMSTATE_VIEW:
            *pmtx = m_mtxView;
            return D3D_OK;

        case D3DTRANSFORMSTATE_PROJECTION:
            *pmtx = m_mtxProjection;
            return D3D_OK;

        default:
            return DDERR_INVALIDPARAMS;
    }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::MultiplyTransform(D3DTRANSFORMSTATETYPE dwStateType,
                                             D3DMATRIX *           pmtx)
{
    D3DMATRIX mtxResult;

    if (NULL == pmtx)
        return DDERR_INVALIDPARAMS;

    switch(dwStateType)
    {
        case D3DTRANSFORMSTATE_WORLD:
            Mult4x4Matrix(pmtx, &m_mtxWorld, &mtxResult);
            m_mtxWorld = mtxResult;
            UpdateWorldTransform();
            return D3D_OK;

        case D3DTRANSFORMSTATE_VIEW:
            Mult4x4Matrix(pmtx, &m_mtxView, &mtxResult);
            m_mtxView = mtxResult;
            UpdateViewTransform();
            return D3D_OK;

        case D3DTRANSFORMSTATE_PROJECTION:
            Mult4x4Matrix(pmtx, &m_mtxProjection, &mtxResult);
            m_mtxProjection = mtxResult;
            UpdateProjectionTransform();
            return D3D_OK;

        default:
            return DDERR_INVALIDPARAMS;
    }
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

#define MAX_VERTEX_BUFFER   0x10000

static D3DLVERTEX     s_rgInVertex[MAX_VERTEX_BUFFER];
static GRFCLIPVERTEX  s_rgOutClipVertex[MAX_VERTEX_BUFFER];
static D3DTLVERTEX    s_rgOutTLVertex[MAX_VERTEX_BUFFER];

typedef struct tagD3DLVERTEX_NORESERVED
{
    D3DVALUE     x;
    D3DVALUE     y;
    D3DVALUE     z;
    D3DCOLOR     color;
    D3DCOLOR     specular;
    D3DVALUE     tu;
    D3DVALUE     tv;
} D3DLVERTEX_NORESERVED;

typedef struct tagD3DLVERTEX2_NORESERVED
{
    D3DVALUE     x;
    D3DVALUE     y;
    D3DVALUE     z;
    D3DCOLOR     color;
    D3DCOLOR     specular;
    D3DVALUE     tu;
    D3DVALUE     tv;
    D3DVALUE     tu2;
    D3DVALUE     tv2;
} D3DLVERTEX2_NORESERVED;

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
static float f255 = 255.0f;

inline unsigned int float_to_byte(float f)
{
    int i;
    _asm fld	f
    _asm fmul	f255
    _asm fistp  i
    if (i < 0) i = 0; else if (i > 255) i = 255;
    return (unsigned int)i;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline D3DCOLOR MakeRGBA(float fr, float fg, float fb, unsigned int a)
{
    unsigned int r = float_to_byte(fr);
    unsigned int g = float_to_byte(fg);
    unsigned int b = float_to_byte(fb);
    return RGBA_MAKE(r,g,b,a);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
inline D3DCOLOR MakeRGBA(float fi, unsigned int a)
{
    unsigned int i = float_to_byte(fi);
    return RGBA_MAKE(i,i,i,a);
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::DrawPrimitive(D3DPRIMITIVETYPE type,
                                           DWORD            dwFVF,
                                           LPVOID           pVertex,
                                           DWORD            cVertex,
                                           DWORD            dwFlags)
{

//#ifdef USE_DX7_INTERFACE
//	if (dwFlags & ~(D3DDP_WAIT))
//		return DDERR_INVALIDPARAMS;
//#endif

    WORD    fpstate, oldfpstate;
    unsigned int    i;

    if (0 == (m_dwStatus & SOFTWARE_DEVICE_IN_SCENE))
    {
		ERRORMSG("DrawPrimitive called without BeginScene");
        return E_FAIL;
    }

    int retval = S_OK;

    _asm fnstcw [oldfpstate]
    fpstate = (oldfpstate & ~0x300) | 0x3F;
    _asm fldcw [fpstate]

    switch (dwFVF)
    {
	case D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2:
        for (i = 0; i < cVertex; i++)
		{
            s_rgInVertex[i].x			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].x;
            s_rgInVertex[i].y			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].y;
            s_rgInVertex[i].z			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].z;
			s_rgInVertex[i].color		= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].color;
			s_rgInVertex[i].specular	= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].specular;
            s_rgInVertex[i].tu			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].tu;
            s_rgInVertex[i].tv			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].tv;
		}
        pVertex = (void *) s_rgInVertex;
		goto D3DFVF_LVERTEX_label;


	case D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1:
        for (i = 0; i < cVertex; i++)
		{
            s_rgInVertex[i].x			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].x;
            s_rgInVertex[i].y			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].y;
            s_rgInVertex[i].z			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].z;
			s_rgInVertex[i].color		= ((D3DLVERTEX_NORESERVED *)pVertex)[i].color;
			s_rgInVertex[i].specular	= ((D3DLVERTEX_NORESERVED *)pVertex)[i].specular;
            s_rgInVertex[i].tu			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].tu;
            s_rgInVertex[i].tv			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].tv;
		}
        pVertex = (void *) s_rgInVertex;
		goto D3DFVF_LVERTEX_label;

    case D3DFVF_VERTEX:

        UpdateLighting();

        for (i = 0; i < cVertex; i++)
        {
            s_rgInVertex[i].x =  ((D3DVERTEX *)pVertex)[i].x;
            s_rgInVertex[i].y =  ((D3DVERTEX *)pVertex)[i].y;
            s_rgInVertex[i].z =  ((D3DVERTEX *)pVertex)[i].z;
            s_rgInVertex[i].tu = ((D3DVERTEX *)pVertex)[i].tu;
            s_rgInVertex[i].tv = ((D3DVERTEX *)pVertex)[i].tv;
            s_rgInVertex[i].specular = 0xFF000000;

            if (m_dwTransformFlags & XFM_LIGHT_AMBIENT_ONLY)
            {
                s_rgInVertex[i].color    = m_ambient_color;
            }
            else
            {
                float nx = ((D3DVERTEX *)pVertex)[i].nx;
                float ny = ((D3DVERTEX *)pVertex)[i].ny;
                float nz = ((D3DVERTEX *)pVertex)[i].nz;

                float dot = m_light_dir.x * nx + m_light_dir.y * ny + m_light_dir.z * nz;

                if (dot < 0.0F)
                {
                    dot = 0.0F;
                }
                else if (dot > 1.0F)
                {
                    dot = 1.0F;
                }

				if (MonoEnable())
				{
					float ci = m_ambient.r + dot * m_diffuse.r;
					s_rgInVertex[i].color = MakeRGBA(ci, RGBA_GETALPHA(m_ambient_color));
				}
				else
				{	
					float cr = m_ambient.r + dot * m_diffuse.r;
					float cg = m_ambient.g + dot * m_diffuse.g;
					float cb = m_ambient.b + dot * m_diffuse.b;
					s_rgInVertex[i].color = MakeRGBA(cr, cg, cb, RGBA_GETALPHA(m_ambient_color));
				}
            }
        }

        pVertex = (void *) s_rgInVertex;

        // Fall through.

D3DFVF_LVERTEX_label:

	case D3DFVF_LVERTEX:

        UpdateTransforms();

//#ifdef USE_DX7_INTERFACE
//		if (0 == ())
//#else
        if (0 == (dwFlags & D3DDP_DONOTCLIP))
//#endif
        {
            TransformClip((D3DLVERTEX *) pVertex, cVertex, &m_mtxWVPC, &m_vdViewportData, s_rgOutClipVertex);

#define  _TYPE_ type
#define  _VERTECIES_ s_rgOutClipVertex
#define  _NUM_VERTECIES_ cVertex
#undef   _INDEX_
#define  _CLIP_

            if (0 == (dwFlags & D3DDP_DONOTUPDATEEXTENTS))
            {
#define   _EXTENTS_
#include "..\inc\drawprimitive.h"
            }
            else
            {
#undef    _EXTENTS_
#include "..\inc\drawprimitive.h"
            }

#undef   _TYPE_
#undef   _VERTECIES_
#undef   _NUM_VERTECIES_
#undef   _INDEX_
#undef   _CLIP_

        }
        else
        {
            Transform((D3DLVERTEX *) pVertex, cVertex, &m_mtxWVPC, &m_vdViewportData, s_rgOutTLVertex);

#define  _TYPE_ type
#define  _VERTECIES_ s_rgOutTLVertex
#define  _NUM_VERTECIES_ cVertex
#undef   _INDEX_
#undef   _CLIP_

            if (0 == (dwFlags & D3DDP_DONOTUPDATEEXTENTS))
            {
#define   _EXTENTS_
#include "..\inc\drawprimitive.h"
            }
            else
            {
#undef    _EXTENTS_
#include "..\inc\drawprimitive.h"
            }

#undef   _TYPE_
#undef   _VERTECIES_
#undef   _NUM_VERTECIES_
#undef   _INDEX_
#undef   _CLIP_

        }

        break;

    case D3DFVF_TLVERTEX:

        if (0 == (dwFlags & D3DDP_DONOTCLIP))
        {

            SetClipCodes((D3DTLVERTEX *) pVertex, s_rgOutClipVertex, cVertex);

#define  _TYPE_ type
#define  _VERTECIES_ s_rgOutClipVertex
#define  _NUM_VERTECIES_ cVertex
#undef   _INDEX_
#define  _CLIP_

            if (0 == (dwFlags & D3DDP_DONOTUPDATEEXTENTS))
            {
#define   _EXTENTS_
#include "..\inc\drawprimitive.h"
            }
            else
            {
#undef    _EXTENTS_
#include "..\inc\drawprimitive.h"
            }

#undef   _TYPE_
#undef   _VERTECIES_
#undef   _NUM_VERTECIES_
#undef   _INDEX_
#undef   _CLIP_

        }
        else
        {

#define  _TYPE_ type
#define  _VERTECIES_ ((D3DTLVERTEX *)pVertex)
#define  _NUM_VERTECIES_ cVertex
#undef   _INDEX_
#undef   _CLIP_

            if (0 == (dwFlags & D3DDP_DONOTUPDATEEXTENTS))
            {
#define   _EXTENTS_
#include "..\inc\drawprimitive.h"
            }
            else
            {
#undef    _EXTENTS_
#include "..\inc\drawprimitive.h"
            }

#undef   _TYPE_
#undef   _VERTECIES_
#undef   _NUM_VERTECIES_
#undef   _INDEX_
#undef   _CLIP_

        }

        break;

    default:
        retval = E_FAIL;
        goto Exit;
    }

Exit:
    _asm fninit // discard any pending floating-point errors
    _asm fldcw [oldfpstate]
    return retval;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::DrawIndexedPrimitive(D3DPRIMITIVETYPE type,
                                                  DWORD            dwFVF,
                                                  LPVOID           pVertex,
                                                  DWORD            cVertex,
                                                  LPWORD           pIndex,
                                                  DWORD            cIndex,
                                                  DWORD            dwFlags)
{
    WORD    fpstate, oldfpstate;
    unsigned int  i;

    if (0 == (m_dwStatus & SOFTWARE_DEVICE_IN_SCENE))
    {
		ERRORMSG("DrawIndexedPrim called without BeginScene");
        return E_FAIL;
    }

    int retval = S_OK;

    _asm fnstcw [oldfpstate]
    fpstate = (oldfpstate & ~0x300) | 0x3F;
    _asm fldcw [fpstate]

    switch (dwFVF)
    {
	case D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX2:
        for (i = 0; i < cVertex; i++)
		{
            s_rgInVertex[i].x			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].x;
            s_rgInVertex[i].y			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].y;
            s_rgInVertex[i].z			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].z;
			s_rgInVertex[i].color		= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].color;
			s_rgInVertex[i].specular	= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].specular;
            s_rgInVertex[i].tu			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].tu;
            s_rgInVertex[i].tv			= ((D3DLVERTEX2_NORESERVED *)pVertex)[i].tv;
		}
        pVertex = (void *) s_rgInVertex;
		goto D3DFVF_LVERTEX_label;


	case D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_SPECULAR | D3DFVF_TEX1:
        for (i = 0; i < cVertex; i++)
		{
            s_rgInVertex[i].x			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].x;
            s_rgInVertex[i].y			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].y;
            s_rgInVertex[i].z			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].z;
			s_rgInVertex[i].color		= ((D3DLVERTEX_NORESERVED *)pVertex)[i].color;
			s_rgInVertex[i].specular	= ((D3DLVERTEX_NORESERVED *)pVertex)[i].specular;
            s_rgInVertex[i].tu			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].tu;
            s_rgInVertex[i].tv			= ((D3DLVERTEX_NORESERVED *)pVertex)[i].tv;
		}
        pVertex = (void *) s_rgInVertex;
		goto D3DFVF_LVERTEX_label;

	case D3DFVF_XYZB1|D3DFVF_NORMAL|D3DFVF_TEX1:
		// fall through

    case D3DFVF_VERTEX:

        UpdateLighting();

        for (i = 0; i < cVertex; i++)
        {
            s_rgInVertex[i].x =  ((D3DVERTEX *)pVertex)[i].x;
            s_rgInVertex[i].y =  ((D3DVERTEX *)pVertex)[i].y;
            s_rgInVertex[i].z =  ((D3DVERTEX *)pVertex)[i].z;
            s_rgInVertex[i].tu = ((D3DVERTEX *)pVertex)[i].tu;
            s_rgInVertex[i].tv = ((D3DVERTEX *)pVertex)[i].tv;
            s_rgInVertex[i].specular = 0xFF000000;

            if (m_dwTransformFlags & XFM_LIGHT_AMBIENT_ONLY)
            {
                s_rgInVertex[i].color    = m_ambient_color;
            }
            else
            {
                float nx = ((D3DVERTEX *)pVertex)[i].nx;
                float ny = ((D3DVERTEX *)pVertex)[i].ny;
                float nz = ((D3DVERTEX *)pVertex)[i].nz;

                float dot = m_light_dir.x * nx + m_light_dir.y * ny + m_light_dir.z * nz;

                if (dot < 0.0F)
                {
                    dot = 0.0F;
                }
                else if (dot > 1.0F)
                {
                    dot = 1.0F;
                }

				if (MonoEnable())
				{
					float ci = m_ambient.r + dot * m_diffuse.r;
					s_rgInVertex[i].color = MakeRGBA(ci, RGBA_GETALPHA(m_ambient_color));
				}
				else
				{	
					float cr = m_ambient.r + dot * m_diffuse.r;
					float cg = m_ambient.g + dot * m_diffuse.g;
					float cb = m_ambient.b + dot * m_diffuse.b;
					s_rgInVertex[i].color = MakeRGBA(cr, cg, cb, RGBA_GETALPHA(m_ambient_color));
				}
            }
        }

        pVertex = (void *) s_rgInVertex;

        // Fall through.
D3DFVF_LVERTEX_label:
	case D3DFVF_LVERTEX:

        UpdateTransforms();

        if (0 == (dwFlags & D3DDP_DONOTCLIP))
        {
            TransformClip((D3DLVERTEX *) pVertex, cVertex, &m_mtxWVPC, &m_vdViewportData, s_rgOutClipVertex);

#define  _TYPE_ type
#define  _VERTECIES_ s_rgOutClipVertex
#define  _NUM_VERTECIES_ cIndex
#define  _INDEX_ pIndex
#define  _CLIP_

            if (0 == (dwFlags & D3DDP_DONOTUPDATEEXTENTS))
            {
#define   _EXTENTS_
#include "..\inc\drawprimitive.h"
            }
            else
            {
#undef    _EXTENTS_
#include "..\inc\drawprimitive.h"
            }

#undef   _TYPE_
#undef   _VERTECIES_
#undef   _NUM_VERTECIES_
#undef   _INDEX_
#undef   _CLIP_

        }
        else
        {
            Transform((D3DLVERTEX *) pVertex, cVertex, &m_mtxWVPC, &m_vdViewportData, s_rgOutTLVertex);

#define  _TYPE_ type
#define  _VERTECIES_ s_rgOutTLVertex
#define  _NUM_VERTECIES_ cIndex
#define  _INDEX_ pIndex
#undef   _CLIP_

            if (0 == (dwFlags & D3DDP_DONOTUPDATEEXTENTS))
            {
#define   _EXTENTS_
#include "..\inc\drawprimitive.h"
            }
            else
            {
#undef    _EXTENTS_
#include "..\inc\drawprimitive.h"
            }

#undef   _TYPE_
#undef   _VERTECIES_
#undef   _NUM_VERTECIES_
#undef   _INDEX_
#undef   _CLIP_

        }

        break;

	case D3DFVF_TLVERTEX:

        if (0 == (dwFlags & D3DDP_DONOTCLIP))
        {
            SetClipCodes((D3DTLVERTEX *) pVertex, s_rgOutClipVertex, cVertex);

#define  _TYPE_ type
#define  _VERTECIES_ s_rgOutClipVertex
#define  _NUM_VERTECIES_ cIndex
#define  _INDEX_ pIndex
#define  _CLIP_

            if (0 == (dwFlags & D3DDP_DONOTUPDATEEXTENTS))
            {
#define   _EXTENTS_
#include "..\inc\drawprimitive.h"
            }
            else
            {
#undef    _EXTENTS_
#include "..\inc\drawprimitive.h"
            }

#undef   _TYPE_
#undef   _VERTECIES_
#undef   _INDEX_
#undef   _CLIP_

        }
        else
        {

#define  _TYPE_ type
#define  _VERTECIES_ ((D3DTLVERTEX *) pVertex)
#define  _NUM_VERTECIES_ cIndex
#define  _INDEX_ pIndex
#undef   _CLIP_

            if (0 == (dwFlags & D3DDP_DONOTUPDATEEXTENTS))
            {
#define   _EXTENTS_
#include "..\inc\drawprimitive.h"
            }
            else
            {
#undef    _EXTENTS_
#include "..\inc\drawprimitive.h"
            }

#undef   _TYPE_
#undef   _VERTECIES_
#undef   _INDEX_
#undef   _CLIP_

        }

        break;

    default:
        retval = E_FAIL;
        goto Exit;
    }

Exit:
    _asm fninit // discard any pending floating-point errors
    _asm fldcw [oldfpstate]
    return retval;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::DrawPrimitiveStrided(D3DPRIMITIVETYPE,
                                                  DWORD,
                                                  LPD3DDRAWPRIMITIVESTRIDEDDATA,
                                                  DWORD,
                                                  DWORD)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::DrawIndexedPrimitiveStrided(D3DPRIMITIVETYPE,
                                                         DWORD,
                                                         LPD3DDRAWPRIMITIVESTRIDEDDATA,
                                                         DWORD,
                                                         LPWORD,
                                                         DWORD,
                                                         DWORD)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::DrawPrimitiveVB(D3DPRIMITIVETYPE,
                                             LPDIRECT3DVERTEXBUFFER,
                                             DWORD,
                                             DWORD,
                                             DWORD)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::DrawIndexedPrimitiveVB(D3DPRIMITIVETYPE,
                                                    LPDIRECT3DVERTEXBUFFER,
                                                    LPWORD,
                                                    DWORD,
                                                    DWORD)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::ComputeSphereVisibility(LPD3DVECTOR,LPD3DVALUE,DWORD,DWORD,LPDWORD)
{
    return E_NOTIMPL;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::GetTextureStageState(DWORD                    dwStage,
                                                  D3DTEXTURESTAGESTATETYPE dwStateType,
                                                  LPDWORD                  pdwValue)
{
    if (dwStage == 0 && dwStateType <= MAX_TEXTURE_STAGE_STATE)
    {
        *pdwValue = m_rgdwTextureStageState[dwStateType];
    }
    else
    {
        *pdwValue = 0;
    }

    return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
STDMETHODIMP CDirect3DDevice::SetTextureStageState(DWORD                    dwStage,
                                                  D3DTEXTURESTAGESTATETYPE dwStateType,
                                                  DWORD                    dwValue)
{

    if (dwStage == 0 && dwStateType <= MAX_TEXTURE_STAGE_STATE)
    {
		if ((dwStateType == D3DTSS_COLORARG1) ||
			(dwStateType == D3DTSS_COLORARG2) ||
			(dwStateType == D3DTSS_ALPHAARG1) ||
			(dwStateType == D3DTSS_ALPHAARG2))
		{
			if (dwValue == D3DTA_CURRENT)
			{
				dwValue = D3DTA_DIFFUSE;
			}
		}

        m_rgdwTextureStageState[dwStateType] = dwValue;

        // whichever of address or addressu/v is set last controls
        // clamp vs. wrap
        if (dwStateType == D3DTSS_ADDRESS)
        {
            m_rgdwTextureStageState[D3DTSS_ADDRESSU] = 0;
            m_rgdwTextureStageState[D3DTSS_ADDRESSV] = 0;
        }
        else if ((dwStateType == D3DTSS_ADDRESSU) ||
                 (dwStateType == D3DTSS_ADDRESSV))
        {
            m_rgdwTextureStageState[D3DTSS_ADDRESS] = 0;
        }

        // force reevaluation next time
        m_imgdev.StateReevaluationNeeded();
    }

    return S_OK;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
SurfaceClass::SurfaceClass()
{
    ZeroMemory(this, sizeof(*this));
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
SurfaceClass::~SurfaceClass()
{
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
HRESULT SurfaceClass::Lock()
{
    HRESULT hr;

    // initializations (assume the worst)
    hr = E_FAIL;

    if (pSurface && !locked)
    {
        hr = pSurface->Lock(NULL, &SurfaceDesc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK, NULL);

        if (FAILED(hr))
        {
            //Set(NULL);
            goto fail;
        }

        locked = TRUE;
    }

    hr = S_OK;

fail:
    return hr;
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------

HRESULT SurfaceClass::Unlock()
{
    HRESULT hr;

    // initializations (assume the worst)
    hr = E_FAIL;

    if (pSurface && locked)
    {
		pSurface->Unlock(NULL);
		locked = FALSE;
    }

    hr = S_OK;
    return hr;
}

//-----------------------------------------------------------------------------
// Used for textures.
//-----------------------------------------------------------------------------

HRESULT SurfaceClass::Set(IDirectDrawSurface7 *p)
{
    HRESULT hr;
    int     was_locked;

    // initializations (assume the worst)
    hr = E_FAIL;

    // remember if we were locked so we can restore the surface to
    // the correct state
    was_locked = locked;
    Unlock();

    fmt = 0;

    RELEASE(pSurface);

    ZeroMemory(&SurfaceDesc, sizeof(SurfaceDesc));

    if (p != NULL)
    {
        SurfaceDesc.dwSize = sizeof(SurfaceDesc);

        p->AddRef();
        pSurface = p;

        hr = pSurface->GetSurfaceDesc(&SurfaceDesc);

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

        fmt = GetPixelFormat(&SurfaceDesc.ddpfPixelFormat);

        if (was_locked)
        {
            hr = Lock();
            if (FAILED(hr))
            {
                goto fail;
            }
        }
    }

    hr = S_OK;

fail:
    return hr;
}

//-----------------------------------------------------------------------------
// Used for pixel buffers and z buffers.
//-----------------------------------------------------------------------------

void CDirect3DDevice::SetClipCodes(D3DTLVERTEX * ptlvIn, GRFCLIPVERTEX * pcvOut, int c)
{
    DWORD dwFlags;

    float hx, hy, hz, hw;
    int   i;

    // Transform the verticies.
    for (i = 0; i < c; i++)
    {

        // Generate the homogenous coordinates.
        hw = 1.0F / ptlvIn->rhw;
        hx = (ptlvIn->sx - m_xOffset) * hw / m_xScale;
        hy = (ptlvIn->sy - m_yOffset) * hw / m_yScale;

        if (ptlvIn->sz < 0.0f)
        {
            hz = - ptlvIn->sz * hw;
        }
        else
        {
            hz = ptlvIn->sz * hw;
        }

        // Generate clipping codes.
        if (hx < 0)
        {
            dwFlags = CLIP_SIDE_LEFT;
        }
        else if (hx > hw)
        {
            dwFlags = CLIP_SIDE_RIGHT;
        }
        else
        {
            dwFlags = 0;
        }

        if (hy < 0)
        {
            dwFlags |= CLIP_SIDE_TOP;
        }
        else if (hy > hw)
        {
            dwFlags |= CLIP_SIDE_BOTTOM;
        }

        if (hz < 0)
        {
            dwFlags |= CLIP_SIDE_FRONT;
        }
        else if (hz > hw)
        {
            dwFlags |= CLIP_SIDE_BACK;
        }

        pcvOut->dwFlags = dwFlags;

        pcvOut->hx = hx;
        pcvOut->hy = hy;
        pcvOut->hz = hz;
        pcvOut->hw = hw;

        // Copy the rest of the structure.
        pcvOut->sx       = ptlvIn->sx;
        pcvOut->sy       = ptlvIn->sy;
        pcvOut->sz       = ptlvIn->sz;
        pcvOut->rhw      = ptlvIn->rhw;
        pcvOut->tu       = ptlvIn->tu;
        pcvOut->tv       = ptlvIn->tv;
        pcvOut->color    = ptlvIn->color;
        pcvOut->specular = ptlvIn->specular;

        ptlvIn++;
        pcvOut++;
    }
}


//-----------------------------------------------------------------------------
// Routines to return D3D renderstate.
//-----------------------------------------------------------------------------

BOOL CDirect3DDevice::AlphaTest(void)
{

    assert(!m_rgdwRenderState[D3DRENDERSTATE_ALPHATESTENABLE]  ||
           (m_rgdwRenderState[D3DRENDERSTATE_ALPHATESTENABLE] &&
            ((m_rgdwRenderState[D3DRENDERSTATE_ALPHAFUNC] == D3DCMP_ALWAYS)   ||
             (((m_rgdwRenderState[D3DRENDERSTATE_ALPHAFUNC] == D3DCMP_NOTEQUAL) ||
               (m_rgdwRenderState[D3DRENDERSTATE_ALPHAFUNC] == D3DCMP_GREATER))  &&
              (m_rgdwRenderState[D3DRENDERSTATE_ALPHAREF] == 0)))));

    if (m_rgdwRenderState[D3DRENDERSTATE_ALPHATESTENABLE] &&
        ((m_rgdwRenderState[D3DRENDERSTATE_ALPHAFUNC] == D3DCMP_NOTEQUAL) ||
         (m_rgdwRenderState[D3DRENDERSTATE_ALPHAFUNC] == D3DCMP_GREATER))  &&
        (m_rgdwRenderState[D3DRENDERSTATE_ALPHAREF] == 0))
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}


BOOL CDirect3DDevice::ZWrite(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_ZWRITEENABLE] &&
           m_rgdwRenderState[D3DRENDERSTATE_ZENABLE];
}


BOOL CDirect3DDevice::ZCompare(void)
{
    assert((m_rgdwRenderState[D3DRENDERSTATE_ZFUNC] == D3DCMP_ALWAYS) ||
           (m_rgdwRenderState[D3DRENDERSTATE_ZFUNC] == D3DCMP_LESSEQUAL));

    return ((m_rgdwRenderState[D3DRENDERSTATE_ZFUNC] == D3DCMP_LESSEQUAL) &&
            m_rgdwRenderState[D3DRENDERSTATE_ZENABLE]);
}


BOOL CDirect3DDevice::Fog(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_FOGENABLE];
}


BOOL CDirect3DDevice::TexBlendDecal(void)
{
    return ((m_rgdwTextureStageState[D3DTSS_COLOROP] == D3DTOP_SELECTARG1) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAOP] == D3DTOP_SELECTARG1) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG1] == D3DTA_TEXTURE));
}


BOOL CDirect3DDevice::TexBlendModulateUseTextureAlpha(void)
{
    return ((m_rgdwTextureStageState[D3DTSS_COLOROP] == D3DTOP_MODULATE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG2] == D3DTA_DIFFUSE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAOP] == D3DTOP_SELECTARG1) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG1] == D3DTA_TEXTURE));
}


BOOL CDirect3DDevice::TexBlendModulateUseDiffuseAlpha(void)
{
    return ((m_rgdwTextureStageState[D3DTSS_COLOROP] == D3DTOP_MODULATE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG2] == D3DTA_DIFFUSE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAOP] == D3DTOP_SELECTARG2) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG2] == D3DTA_DIFFUSE));
}


BOOL CDirect3DDevice::TexBlendModulateUseNoAlpha(void)
{
    return ((m_rgdwTextureStageState[D3DTSS_COLOROP] == D3DTOP_MODULATE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG2] == D3DTA_DIFFUSE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAOP] == D3DTOP_DISABLE));
}


BOOL CDirect3DDevice::TexBlendDecalUseNoAlpha(void)
{
    return ((m_rgdwTextureStageState[D3DTSS_COLOROP] == D3DTOP_SELECTARG1) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAOP] == D3DTOP_DISABLE));
}


BOOL CDirect3DDevice::TexBlendModulateAlpha(void)
{
    return ((m_rgdwTextureStageState[D3DTSS_COLOROP] == D3DTOP_MODULATE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG2] == D3DTA_DIFFUSE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAOP] == D3DTOP_MODULATE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG2] == D3DTA_DIFFUSE));
}

#ifdef USE_DX7_INTERFACE
BOOL CDirect3DDevice::TexBlendAlphaOnly(void)
{
    return ((m_rgdwTextureStageState[D3DTSS_COLOROP] == D3DTOP_DISABLE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG2] == D3DTA_DIFFUSE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAOP] == D3DTOP_SELECTARG2) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG2] == D3DTA_DIFFUSE));
}

BOOL CDirect3DDevice::TexBlendAlphaModulateOnly(void)
{
    return (
			((m_rgdwTextureStageState[D3DTSS_COLOROP] == D3DTOP_DISABLE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG2] == D3DTA_DIFFUSE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAOP] == D3DTOP_MODULATE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG2] == D3DTA_DIFFUSE))
			||
			((m_rgdwTextureStageState[D3DTSS_COLOROP] == D3DTOP_DISABLE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_COLORARG2] == D3DTA_DIFFUSE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAOP] == D3DTOP_SELECTARG1) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG1] == D3DTA_TEXTURE) &&
            (m_rgdwTextureStageState[D3DTSS_ALPHAARG2] == D3DTA_TEXTURE)));



}
#endif



BOOL CDirect3DDevice::ShadeGouraud(void)
{
    assert((m_rgdwRenderState[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_FLAT) ||
           (m_rgdwRenderState[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_GOURAUD));

    return (m_rgdwRenderState[D3DRENDERSTATE_SHADEMODE] == D3DSHADE_GOURAUD);
}


BOOL CDirect3DDevice::TextureMap(void)
{
    return (m_Texture.pSurface != NULL);
}


DWORD CDirect3DDevice::TexelFormat(void)
{
    return (m_Texture.fmt);
}


BOOL CDirect3DDevice::AlphaBlend(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_ALPHABLENDENABLE];
}


BOOL CDirect3DDevice::SrcBlend(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_SRCBLEND];
}


BOOL CDirect3DDevice::DestBlend(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_DESTBLEND];
}


BOOL CDirect3DDevice::MonoEnable(void)
{
    // we overload this function to control pixel doubling, so test only the low bit

    return m_rgdwRenderState[D3DRENDERSTATE_MONOENABLE] & BLADE_INTENSITYSHADING;
}


BOOL CDirect3DDevice::PixDouble(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_MONOENABLE] & BLADE_PIXDOUBLE;
}


BOOL CDirect3DDevice::Perspective(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE];
}




//========================================================================
//CDirect3DVertexBuffer
//========================================================================
#ifdef USE_DX7_INTERFACE
STDMETHODIMP CDirect3DVertexBuffer::QueryInterface(REFIID riid, LPVOID * ppvObj)
{
    if (IID_IUnknown == riid)
    {
        AddRef();
        *ppvObj = (void*)this;
        return S_OK;
    }
    else if (IID_IDirect3DVertexBuffer == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirect3DVertexBuffer *)this;
        return S_OK;
    }
    else if (IID_IDirect3DVertexBuffer7 == riid)
    {
        AddRef();
        *ppvObj = (void*)(IDirect3DVertexBuffer7 *)this;
        return S_OK;
    }
    else
    {
        *ppvObj = NULL;
        return E_FAIL;
    }
}

ULONG CDirect3DVertexBuffer::AddRef(void)
{
    return ++m_cRef;
}

ULONG CDirect3DVertexBuffer::Release(void)
{
	
    if (--m_cRef == 0)
    {
		if (m_pRawBuf)
		{
			m_pRawBuf->Release();
			m_pRawBuf = NULL;
		}
		if (m_pOptimizedBuf)
		{
			m_pOptimizedBuf->Release();
			m_pOptimizedBuf = NULL;
		}

        delete this;
        return 0;
    }
    return m_cRef;
}


STDMETHODIMP CDirect3DVertexBuffer::Lock(DWORD dwFlags,LPVOID * lplpData, LPDWORD lpdwSize)
{
	//JJ Fix-A-Roo
	//Since you cannot Lock an optimized buffer, Caller must want Raw Buffer

	return this->m_pRawBuf->Lock(dwFlags, lplpData, lpdwSize);
}

STDMETHODIMP CDirect3DVertexBuffer::Unlock(void)
{
	//JJ Fix-A-Roo

	return this->m_pRawBuf->Unlock();
}

STDMETHODIMP CDirect3DVertexBuffer::ProcessVertices(THIS_ DWORD,DWORD,DWORD,LPDIRECT3DVERTEXBUFFER,DWORD,LPDIRECT3DDEVICE3,DWORD)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DVertexBuffer::GetVertexBufferDesc(LPD3DVERTEXBUFFERDESC lpVBDesc)
{
	if (lpVBDesc->dwSize < m_VBDesc.dwSize)
		return DDERR_INVALIDPARAMS;

	*lpVBDesc = m_VBDesc;
	return S_OK;
}

STDMETHODIMP CDirect3DVertexBuffer::Optimize(THIS_ LPDIRECT3DDEVICE3,DWORD)
{
	ASSERT(0);
	return E_FAIL;
}

STDMETHODIMP CDirect3DVertexBuffer::ProcessVertices(THIS_ DWORD dwVertexOp, DWORD dwDestIndex, DWORD dwCount, LPDIRECT3DVERTEXBUFFER7 lpSrcBuffer, DWORD dwSrcIndex, LPDIRECT3DDEVICE7 lpD3DDevice, DWORD dwFlags)
{
	//JJ Fix-A-Roo

	//See if we have a Blade Device...
	for(int i = 0; i < CDirect3DDevice::s_nDevCnt; i++)
	{
		if(CDirect3DDevice::s_pDeviceList[i] == lpD3DDevice)
		{	
			((CDirect3DDevice*)lpD3DDevice)->m_pDevice7->SetTransform(D3DTRANSFORMSTATE_WORLD, &(((CDirect3DDevice*)lpD3DDevice)->m_mtxWorld));
			((CDirect3DDevice*)lpD3DDevice)->m_pDevice7->SetTransform(D3DTRANSFORMSTATE_VIEW, &(((CDirect3DDevice*)lpD3DDevice)->m_mtxView));
			((CDirect3DDevice*)lpD3DDevice)->m_pDevice7->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &(((CDirect3DDevice*)lpD3DDevice)->m_mtxProjection));
			//We are Blade.  Process the Verticies into the Raw Buffer
			return this->m_pRawBuf->ProcessVertices(dwVertexOp,
													dwDestIndex,
													dwCount,
													((CDirect3DVertexBuffer*)lpSrcBuffer)->m_pRawBuf,
													dwSrcIndex,
													((CDirect3DDevice*)lpD3DDevice)->m_pDevice7,
													dwFlags);
		}
	}

	//We are Hardware.  We should process the verticies into the Optimized *and* the unoptimized buffer...that way
	//Blade could read them if it needed to.

	this->m_pOptimizedBuf->ProcessVertices(dwVertexOp,
										   dwDestIndex,
										   dwCount,
										   ((CDirect3DVertexBuffer*)lpSrcBuffer)->m_pOptimizedBuf,
										   dwSrcIndex,
										   lpD3DDevice,
										   dwFlags);

	return this->m_pRawBuf->ProcessVertices(dwVertexOp,
											dwDestIndex,
											dwCount,
											((CDirect3DVertexBuffer*)lpSrcBuffer)->m_pRawBuf,
											dwSrcIndex,
											lpD3DDevice,
											dwFlags);
}

STDMETHODIMP CDirect3DVertexBuffer::Optimize(THIS_ LPDIRECT3DDEVICE7 lpD3DDevice, DWORD dwFlags)
{
	//JJ Fix-A-Roo
	DWORD dwSizeRaw = 0;
	DWORD dwSizeOpt = 0;
	LPVOID pBufferRaw = NULL;
	LPVOID pBufferOpt = NULL;
	HRESULT hRes = 0x0;

	hRes = this->m_pRawBuf->Lock(DDLOCK_READONLY, &pBufferRaw, &dwSizeRaw);
	ASSERT(SUCCEEDED(hRes));

	hRes = this->m_pOptimizedBuf->Lock(DDLOCK_WRITEONLY, &pBufferOpt, &dwSizeOpt);
	ASSERT(SUCCEEDED(hRes));

	//This is true as the buffers are supposed to be the same!
	ASSERT(dwSizeRaw == dwSizeOpt);

	//Copy the memory into the optimized buffer so that we can optimize it for the *hardware* if necessary
	pBufferOpt = memcpy(pBufferOpt, pBufferRaw, dwSizeOpt);

	hRes = this->m_pRawBuf->Unlock();
	hRes = this->m_pOptimizedBuf->Unlock();
		
	for(int i = 0; i < CDirect3DDevice::s_nDevCnt; i++)
	{
		if(CDirect3DDevice::s_pDeviceList[i] == lpD3DDevice)
		{
			//Don't optimize for Blade...
			return S_OK;//this->m_pRawBuf;//->Optimize(((CDirect3DDevice*)lpD3DDevice)->m_pDevice7,dwFlags);
		}
	}
	
	//We have a hardware device; Optimize for it...
	hRes = this->m_pOptimizedBuf->Optimize(lpD3DDevice, dwFlags);

	//Key for getting hardware the correct buffer it wants.
	this->m_bOptimized = true;

	return hRes;
}

STDMETHODIMP CDirect3DVertexBuffer::ProcessVerticesStrided(THIS_ DWORD,DWORD,DWORD,LPD3DDRAWPRIMITIVESTRIDEDDATA,DWORD,LPDIRECT3DDEVICE7,DWORD)
{
	ASSERT(0);
	return E_FAIL;
}

CDirect3DVertexBuffer::CDirect3DVertexBuffer() : m_cRef(0) //JJ Fix-A-Roo m_pBuffer(NULL)
{
}

CDirect3DVertexBuffer::~CDirect3DVertexBuffer()
{
}

#endif // USE_DX7_INTERFACE

BOOL CDirect3DDevice::CullCCW(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_CULLMODE] == D3DCULL_CCW;
}


BOOL CDirect3DDevice::CullCW(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_CULLMODE] == D3DCULL_CW;
}


BOOL CDirect3DDevice::TextureWrapU(void)
{
    assert((m_rgdwTextureStageState[D3DTSS_ADDRESS] == D3DTADDRESS_WRAP) ||
           (m_rgdwTextureStageState[D3DTSS_ADDRESS] == D3DTADDRESS_CLAMP) ||
           (m_rgdwTextureStageState[D3DTSS_ADDRESS] == 0));

    switch (m_rgdwTextureStageState[D3DTSS_ADDRESS])
    {
    case D3DTADDRESS_WRAP:
        return TRUE;

    case D3DTADDRESS_CLAMP:
        return FALSE;

    default:
        break;
    }

    assert((m_rgdwTextureStageState[D3DTSS_ADDRESSU] == D3DTADDRESS_WRAP) ||
           (m_rgdwTextureStageState[D3DTSS_ADDRESSU] == D3DTADDRESS_CLAMP));
    assert((m_rgdwTextureStageState[D3DTSS_ADDRESSV] == D3DTADDRESS_WRAP) ||
           (m_rgdwTextureStageState[D3DTSS_ADDRESSV] == D3DTADDRESS_CLAMP));

    return m_rgdwTextureStageState[D3DTSS_ADDRESSU] == D3DTADDRESS_WRAP;
}


BOOL CDirect3DDevice::TextureWrapV(void)
{
    assert((m_rgdwTextureStageState[D3DTSS_ADDRESS] == D3DTADDRESS_WRAP) ||
           (m_rgdwTextureStageState[D3DTSS_ADDRESS] == D3DTADDRESS_CLAMP) ||
           (m_rgdwTextureStageState[D3DTSS_ADDRESS] == 0));

    switch (m_rgdwTextureStageState[D3DTSS_ADDRESS])
    {
    case D3DTADDRESS_WRAP:
        return TRUE;

    case D3DTADDRESS_CLAMP:
        return FALSE;

    default:
        break;
    }

    assert((m_rgdwTextureStageState[D3DTSS_ADDRESSU] == D3DTADDRESS_WRAP) ||
           (m_rgdwTextureStageState[D3DTSS_ADDRESSU] == D3DTADDRESS_CLAMP));
    assert((m_rgdwTextureStageState[D3DTSS_ADDRESSV] == D3DTADDRESS_WRAP) ||
           (m_rgdwTextureStageState[D3DTSS_ADDRESSV] == D3DTADDRESS_CLAMP));

    return m_rgdwTextureStageState[D3DTSS_ADDRESSV] == D3DTADDRESS_WRAP;
}


BOOL CDirect3DDevice::MonoFog(void)
{
    return m_rgdwRenderState[D3DRENDERSTATE_MONOENABLE] & BLADE_MONO_FOG;
}
