Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1282 lines
43 KiB

//----------------------------------------------------------------------------
//
// rastctx.cpp
//
// Context functions + state functions.
//
// Copyright (C) Microsoft Corporation, 1997.
//
//----------------------------------------------------------------------------
#include "pch.cpp"
#pragma hdrstop
#include "rampif.h"
#include "rampmat.hpp"
// Unlock previous texture if necessary. It's called before the texture handle
// is going to be changed.
#define CHECK_AND_UNLOCK_TEXTURE \
{ \
if (m_uFlags & D3DCONTEXT_TEXTURE_LOCKED) \
{ \
RastUnlockSpanTexture(); \
} \
}
inline void
D3DContext::RampSetFogData(UINT32 uState, UINT32 uStateVal)
{
RLDDIRampLightingDriver *pRampdrv =
(RLDDIRampLightingDriver*)m_RastCtx.pRampDrv;
if (pRampdrv != NULL)
{
switch(uState)
{
case D3DRENDERSTATE_FOGENABLE :
pRampdrv->fog_enable = uStateVal;
break;
case D3DRENDERSTATE_FOGCOLOR :
pRampdrv->fog_color = uStateVal;
break;
case D3DRENDERSTATE_FOGTABLEMODE :
pRampdrv->driver.fog_mode = (D3DFOGMODE)uStateVal;
break;
case D3DRENDERSTATE_FOGTABLESTART :
pRampdrv->driver.fog_start = (FLOAT)uStateVal;
break;
case D3DRENDERSTATE_FOGTABLEEND :
pRampdrv->driver.fog_end = (FLOAT)uStateVal;
break;
case D3DRENDERSTATE_FOGTABLEDENSITY:
pRampdrv->driver.fog_density = (FLOAT)uStateVal;
break;
}
}
}
//----------------------------------------------------------------------------
//
// FillContext
//
// Fill the context with the info. from the surfaces.
//
//----------------------------------------------------------------------------
HRESULT
D3DContext::FillContext(LPDIRECTDRAWSURFACE pDDS,
LPDIRECTDRAWSURFACE pDDSZ)
{
HRESULT hr;
LPDDRAWI_DDRAWSURFACE_LCL pLcl =
((LPDDRAWI_DDRAWSURFACE_INT)(pDDS))->lpLcl;
m_RastCtx.iSurfaceStride = DDSurf_Pitch(pLcl);
m_RastCtx.iSurfaceBitCount = DDSurf_BitDepth(pLcl);
m_RastCtx.iSurfaceStep = m_RastCtx.iSurfaceBitCount/8;
HR_RET(FindOutSurfFormat(&(DDSurf_PixFmt(pLcl)),
(D3DI_SPANTEX_FORMAT *)&(m_RastCtx.iSurfaceType)));
m_RastCtx.Clip.left = m_RastCtx.Clip.top = 0;
m_RastCtx.Clip.bottom = DDSurf_Height(pLcl);
m_RastCtx.Clip.right = DDSurf_Width(pLcl);
if (pDDSZ != NULL)
{
pLcl = ((LPDDRAWI_DDRAWSURFACE_INT)(pDDSZ))->lpLcl;
m_RastCtx.pZBits = (PUINT8)SURFACE_MEMORY(pDDSZ);
m_RastCtx.iZStride = DDSurf_Pitch(pLcl);
m_RastCtx.iZBitCount = DDSurf_BitDepth(pLcl);
m_RastCtx.iZStep = m_RastCtx.iZBitCount/8;
}
else
{
m_RastCtx.pZBits = NULL;
m_RastCtx.iZStride = 0;
m_RastCtx.iZBitCount = 0;
m_RastCtx.iZStep = 0;
}
m_RastCtx.pDDS = pDDS;
m_RastCtx.pDDSZ = pDDSZ;
m_RastCtx.dwSize = sizeof(D3DI_RASTCTX);
// Make sure SpanInit is called at least once
SetAllStatesDirtyBits();
// Check for MsGolf AppHack
if (pLcl->lpSurfMore->lpDD_lcl->dwAppHackFlags & DDRAW_APPCOMPAT_FORCEMODULATED)
{
m_RastCtx.uFlags |= RASTCTXFLAGS_APPHACK_MSGOLF;
}
return D3D_OK;
}
HRESULT
D3DContext::Initialize(LPDIRECTDRAWSURFACE pDDS,
LPDIRECTDRAWSURFACE pDDSZ,
DWORD BeadSet,
DWORD devVer)
{
HRESULT hr;
// Initialize the primitive processor.
HR_RET(m_PrimProc.Initialize());
memset(&m_RastCtx, 0, sizeof(m_RastCtx));
m_uFlags = 0;
HR_RET(FillContext(pDDS, pDDSZ));
m_PrimProc.SetCtx(&m_RastCtx);
dwSize = sizeof(D3DContext);
// Initialize bead table enum
m_RastCtx.BeadSet = (D3DI_BEADSET)BeadSet;
STATESET_INIT(m_renderstate_override);
// Init FVF data as legacy TL vertex
m_fvfData.preFVF = -1;
CheckFVF(D3DFVF_TLVERTEX);
m_RastCtx.uDevVer = devVer;
// All render and texture stage state is initialized by
// DIRECT3DDEVICEI::stateInitialize
// Init prim function table. It will be updated for RAMP, or when FVF
// control word changes or when fill mode changes.
m_fnPrims.pfnTri = RGB_TriNoPackSolid;
m_fnPrims.pfnPoint = RGB_PointNoPack;
m_fnPrims.pfnLine = RGB_LineNoPack;
// This one should be always the same.
m_fnPrims.pfnStoreLastPixelState = RGBRAMP_StoreLastPixelState;
m_fnPrims.pfnDp2SetRenderStates = RGBRAMP_Dp2SetRenderStates;
m_fnPrims.pfnDp2TextureStageState = RGBRAMP_Dp2TextureStageState;
m_fnPrims.pfnDp2SetViewport = RGBRAMP_Dp2SetViewport;
m_fnPrims.pfnDp2SetWRange = RGBRAMP_Dp2SetWRange;
// Enable MMX Fast Paths (Monolithics) if a registry key for it is not 0
m_RastCtx.dwMMXFPDisableMask[0] = 0x0; // enable MMX FP's by default
HKEY hKey = (HKEY) NULL;
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey) )
{
DWORD dwType;
DWORD dwValue;
DWORD dwDisableMask[MMX_FP_DISABLE_MASK_NUM] = {0x0};
DWORD dwSize = 4;
// only code up looking at one mask, for now
DDASSERT(MMX_FP_DISABLE_MASK_NUM == 1);
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "MMXFPDisableMask0", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
dwType == REG_DWORD )
{
dwDisableMask[0] = dwValue;
}
if ( ERROR_SUCCESS == RegQueryValueEx( hKey, "MMX Fast Path", NULL, &dwType, (LPBYTE) &dwValue, &dwSize) &&
dwType == REG_DWORD)
{
if (dwValue == 0)
{
// Override MMXFPDisableMask0 and disable all MMX Fast Paths
m_RastCtx.dwMMXFPDisableMask[0] = 0xffffffff;
}
else
{
// Take all MMX paths not disabled by MMXFPDisableMask0
m_RastCtx.dwMMXFPDisableMask[0] = dwDisableMask[0];
}
}
RegCloseKey( hKey );
}
return D3D_OK;
}
HRESULT
D3DContext::SetViewport(LPD3DHAL_DP2VIEWPORTINFO pVpt)
{
m_RastCtx.Clip.left = pVpt->dwX;
m_RastCtx.Clip.top = pVpt->dwY;
m_RastCtx.Clip.bottom = pVpt->dwY + pVpt->dwHeight;
m_RastCtx.Clip.right = pVpt->dwX + pVpt->dwWidth;
return D3D_OK;
}
inline HRESULT
D3DContext::CreateRampLightingDriver(void)
{
m_RastCtx.pRampDrv = RLDDIRampCreate(&m_RastCtx);
if (m_RastCtx.pRampDrv == NULL)
{
return DDERR_OUTOFMEMORY;
}
else
{
return D3D_OK;
}
}
inline void
D3DContext::DestroyRampLightingDriver(void)
{
RLDDIRampDestroy((RLDDIRampLightingDriver*)m_RastCtx.pRampDrv);
m_RastCtx.pRampDrv = NULL;
}
//----------------------------------------------------------------------------
//
// RastContextCreateC
//
// Calls RastContextCreate with the C bead set.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastContextCreateC(LPD3DHAL_CONTEXTCREATEDATA pCtxData)
{
return RastContextCreate(pCtxData, (DWORD)D3DIBS_C);
}
//----------------------------------------------------------------------------
//
// RastContextCreateCMMX
//
// Calls RastContextCreate with the CMMX bead set.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastContextCreateCMMX(LPD3DHAL_CONTEXTCREATEDATA pCtxData)
{
return RastContextCreate(pCtxData, (DWORD)D3DIBS_CMMX);
}
//----------------------------------------------------------------------------
//
// RastContextCreateMMX
//
// Calls RastContextCreate with the MMX bead set.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastContextCreateMMX(LPD3DHAL_CONTEXTCREATEDATA pCtxData)
{
return RastContextCreate(pCtxData, (DWORD)D3DIBS_MMX);
}
//----------------------------------------------------------------------------
//
// RastContextCreateMMXAsRGB
//
// Calls RastContextCreate with the MMX bead set, but remember that we
// came from RGB.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastContextCreateMMXAsRGB(LPD3DHAL_CONTEXTCREATEDATA pCtxData)
{
return RastContextCreate(pCtxData, (DWORD)D3DIBS_MMXASRGB);
}
//----------------------------------------------------------------------------
//
// RastContextCreateRamp
//
// Calls RastContextCreate with the ramp bead set.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastContextCreateRamp(LPD3DHAL_CONTEXTCREATEDATA pCtxData)
{
HRESULT hr;
hr = RastContextCreate(pCtxData, (DWORD)D3DIBS_RAMP);
if (pCtxData->ddrval != D3D_OK)
{
return hr;
}
// Create a RampLightingDriver
D3DContext *pDCtx = (D3DContext *)pCtxData->dwhContext;
pCtxData->ddrval = pDCtx->CreateRampLightingDriver();
// Init prim function table for RAMP
pDCtx->InitRampFuncs();
return hr;
}
//----------------------------------------------------------------------------
//
// RastContextCreate
//
// Creates a RASTCTX and initializes it with the info passed in.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastContextCreate(LPD3DHAL_CONTEXTCREATEDATA pCtxData, DWORD BeadSet)
{
DDASSERT(pCtxData != NULL);
D3DContext *pDCtx = new D3DContext;
if (pDCtx == NULL)
{
pCtxData->ddrval = DDERR_OUTOFMEMORY;
return DDHAL_DRIVER_HANDLED;
}
pCtxData->ddrval =
pDCtx->Initialize(pCtxData->lpDDS,
pCtxData->lpDDSZ,
BeadSet,
(DWORD)pCtxData->dwhContext);
pCtxData->dwhContext = (ULONG_PTR)pDCtx;
PD3DI_RASTCTX pCtx = pDCtx->GetRastCtx();
if ((D3DI_SPTFMT_PALETTE8 == pCtx->iSurfaceType) &&
(D3DIBS_RAMP != BeadSet))
{
// need a ramp lighting driver for 8 bit palettized RGB output
pCtxData->ddrval = pDCtx->CreateRampLightingDriver();
if (pCtxData->ddrval == D3D_OK)
{
// initialize the RGB8 palette
RLDDIRampMakePaletteRGB8((RLDDIRampLightingDriver*)pCtx->pRampDrv);
// Make sure DD Palette is updated after it gets set by FindLightingRange
RLDDIRampUpdateDDPalette(pCtx);
}
}
return DDHAL_DRIVER_HANDLED;
}
//----------------------------------------------------------------------------
//
// RastContextDestroy
//
// Destroy a rast context.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastContextDestroy(LPD3DHAL_CONTEXTDESTROYDATA pCtxDestroyData)
{
D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastContextDestroy", pCtxDestroyData);
PD3DI_RASTCTX pCtx = pDCtx->GetRastCtx();
if (pCtx->pRampDrv)
{
// destroy the ramp lighting driver, if one was created
pDCtx->DestroyRampLightingDriver();
}
delete pDCtx;
pCtxDestroyData->ddrval = D3D_OK;
return DDHAL_DRIVER_HANDLED;
}
//----------------------------------------------------------------------------
//
// ValidateTextureStageState
//
// Utility function that returns an appropriate D3DERR_ if the current
// multi-texture setup can not be rendered, D3D_OK otherwise.
//
//----------------------------------------------------------------------------
HRESULT
D3DContext::ValidateTextureStageState(void)
{
#if DBG
if ((m_RastCtx.pTexture[0] == m_RastCtx.pTexture[1]) &&
(m_RastCtx.pTexture[0] != NULL) )
{
// except under very special circumstances, this will not work in RGB/MMX
// since we keep a lot of stage state in the D3DI_SPANTEX structure
D3D_ERR("(Rast) ValidateTextureStageState Warning, pTexture[0] == pTexture[1]");
}
#endif
for (INT i = 0; i < 2; i++)
{
switch(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(i,D3DTSS_COLOROP)])
{
default:
return D3DERR_UNSUPPORTEDCOLOROPERATION;
case D3DTOP_DISABLE:
return D3D_OK; // don't have to validate further if the stage is disabled
case D3DTOP_SELECTARG1:
case D3DTOP_SELECTARG2:
case D3DTOP_MODULATE:
case D3DTOP_MODULATE2X:
case D3DTOP_MODULATE4X:
case D3DTOP_ADD:
case D3DTOP_ADDSIGNED:
case D3DTOP_BLENDDIFFUSEALPHA:
case D3DTOP_BLENDTEXTUREALPHA:
case D3DTOP_BLENDFACTORALPHA:
case D3DTOP_BLENDTEXTUREALPHAPM:
break;
}
switch(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(i,D3DTSS_COLORARG1)] &
~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT))
{
default:
return D3DERR_UNSUPPORTEDCOLORARG;
case (D3DTA_TEXTURE):
break;
}
switch(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(i,D3DTSS_COLORARG2)] &
~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT))
{
default:
return D3DERR_UNSUPPORTEDCOLORARG;
case (D3DTA_TFACTOR):
case (D3DTA_CURRENT):
case (D3DTA_DIFFUSE):
break;
}
switch(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(i,D3DTSS_ALPHAOP)])
{
default:
return D3DERR_UNSUPPORTEDALPHAOPERATION;
case D3DTOP_DISABLE:
break;
case D3DTOP_SELECTARG1:
case D3DTOP_SELECTARG2:
case D3DTOP_MODULATE:
case D3DTOP_MODULATE2X:
case D3DTOP_MODULATE4X:
case D3DTOP_ADD:
case D3DTOP_ADDSIGNED:
case D3DTOP_BLENDDIFFUSEALPHA:
case D3DTOP_BLENDTEXTUREALPHA:
case D3DTOP_BLENDFACTORALPHA:
case D3DTOP_BLENDTEXTUREALPHAPM:
// only validate alpha args if alpha op is not disable
switch(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(i,D3DTSS_ALPHAARG1)] &
~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT))
{
default:
return D3DERR_UNSUPPORTEDALPHAARG;
case (D3DTA_TEXTURE):
break;
}
switch(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(i,D3DTSS_ALPHAARG2)] &
~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT))
{
default:
return D3DERR_UNSUPPORTEDALPHAARG;
case (D3DTA_TFACTOR):
case (D3DTA_CURRENT):
case (D3DTA_DIFFUSE):
break;
}
break;
}
}
// allow unused state to be zero'ed since this is so common
if ( !((m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(2,D3DTSS_COLOROP)] == D3DTOP_DISABLE) ||
(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(2,D3DTSS_COLOROP)] == 0)) )
{
return D3DERR_TOOMANYOPERATIONS;
}
return D3D_OK;
}
//----------------------------------------------------------------------------
//
// RastValidateTextureStageState
//
// Returns whether the current multitexture setup can be rendered and, if
// so, the number of passes required to render it.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastValidateTextureStageState(LPD3DHAL_VALIDATETEXTURESTAGESTATEDATA pData)
{
D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastValidateTextureStageState", pData);
pData->dwNumPasses = 1;
pData->ddrval = pDCtx->ValidateTextureStageState();
return DDHAL_DRIVER_HANDLED;
}
//----------------------------------------------------------------------------
//
// RastContextDestroyRamp
//
// Destroy a rast context.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastContextDestroyRamp(LPD3DHAL_CONTEXTDESTROYDATA pCtxDestroyData)
{
D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastContextDestroy", pCtxDestroyData);
pDCtx->DestroyRampLightingDriver();
delete pDCtx;
pCtxDestroyData->ddrval = D3D_OK;
return DDHAL_DRIVER_HANDLED;
}
//----------------------------------------------------------------------------
//
// RastSetRenderTarget
//
// Update a rast context with the info from a new render target.
//
//----------------------------------------------------------------------------
DWORD __stdcall
RastSetRenderTarget(LPD3DHAL_SETRENDERTARGETDATA pTgtData)
{
D3DContext *pDCtx;
VALIDATE_D3DCONTEXT("RastSetRenderTarget", pTgtData);
pTgtData->ddrval = pDCtx->FillContext(pTgtData->lpDDS, pTgtData->lpDDSZ);
return DDHAL_DRIVER_HANDLED;
}
//----------------------------------------------------------------------------
//
// SetRenderState
//
// Check to see if a state change requires an update to the D3DCTX.
//
//----------------------------------------------------------------------------
HRESULT
D3DContext::SetRenderState(UINT32 uState, UINT32 uStateVal)
{
// Assume d3dim has filtered out unchanged states
StateChanged(uState);
m_RastCtx.pdwRenderState[uState] = uStateVal;
switch(uState)
{
case D3DRENDERSTATE_FOGENABLE :
case D3DRENDERSTATE_FOGCOLOR :
case D3DRENDERSTATE_FOGTABLEMODE :
case D3DRENDERSTATE_FOGTABLESTART :
case D3DRENDERSTATE_FOGTABLEEND :
case D3DRENDERSTATE_FOGTABLEDENSITY:
RampSetFogData(uState, uStateVal);
break;
case D3DRENDERSTATE_CULLMODE:
// Set face culling sign from state.
switch(uStateVal)
{
case D3DCULL_CCW:
m_RastCtx.uCullFaceSign = 1;
break;
case D3DCULL_CW:
m_RastCtx.uCullFaceSign = 0;
break;
case D3DCULL_NONE:
m_RastCtx.uCullFaceSign = 2;
break;
}
break;
case D3DRENDERSTATE_ZENABLE:
if ( (D3DZB_FALSE != uStateVal) && (NULL == m_RastCtx.pDDSZ) )
{
DPF(0, "(ERROR) (Rast) SetRenderState: Can't set D3DRENDERSTATE_ZENABLE to %d if there is no Z Buffer", uStateVal);
m_RastCtx.pdwRenderState[uState] = D3DZB_FALSE;
}
break;
case D3DRENDERSTATE_LASTPIXEL:
// Set last-pixel flag from state.
if (uStateVal)
{
m_PrimProc.SetFlags(PPF_DRAW_LAST_LINE_PIXEL);
}
else
{
m_PrimProc.ClrFlags(PPF_DRAW_LAST_LINE_PIXEL);
}
break;
// map legacy modes with one-to-one mappings to texture stage 0
case D3DRENDERSTATE_TEXTUREADDRESS:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESS)] =
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSU)] =
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSV)] = uStateVal;
MapTextureStage0State();
break;
case D3DRENDERSTATE_TEXTUREADDRESSU:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSU)] = uStateVal;
MapTextureStage0State();
break;
case D3DRENDERSTATE_TEXTUREADDRESSV:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSV)] = uStateVal;
MapTextureStage0State();
break;
case D3DRENDERSTATE_MIPMAPLODBIAS:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MIPMAPLODBIAS)] = uStateVal;
MapTextureStage0State();
break;
case D3DRENDERSTATE_BORDERCOLOR:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_BORDERCOLOR)] = uStateVal;
MapTextureStage0State();
break;
case D3DRENDERSTATE_TEXTUREMAG:
case D3DRENDERSTATE_TEXTUREMIN:
// map legacy filtering/sampling state to texture stage 0
MapLegacyTextureFilter();
// assign to current texture
MapTextureStage0State();
break;
case D3DRENDERSTATE_TEXTUREMAPBLEND:
// map legacy blending state to texture stage 0
MapLegacyTextureBlend();
break;
// map legacy WRAPU/V to per-index controls
case D3DRENDERSTATE_WRAPU:
m_RastCtx.pdwRenderState[D3DRENDERSTATE_WRAP0] &= ~D3DWRAP_U;
m_RastCtx.pdwRenderState[D3DRENDERSTATE_WRAP0] |= ((uStateVal) ? D3DWRAP_U : 0);
StateChanged(D3DRENDERSTATE_WRAP0);
break;
case D3DRENDERSTATE_WRAPV:
m_RastCtx.pdwRenderState[D3DRENDERSTATE_WRAP0] &= ~D3DWRAP_V;
m_RastCtx.pdwRenderState[D3DRENDERSTATE_WRAP0] |= ((uStateVal) ? D3DWRAP_V : 0);
StateChanged(D3DRENDERSTATE_WRAP0);
break;
//
// NOTE - this compututation of cActTex does not account for blend-only stages
//
case D3DRENDERSTATE_TEXTUREHANDLE:
CHECK_AND_UNLOCK_TEXTURE;
// map handle thru to stage 0
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_TEXTUREMAP)] = uStateVal;
m_RastCtx.pTexture[1] = NULL;
// set up for single stage
if (uStateVal == 0)
{
m_RastCtx.pTexture[0] = NULL;
}
else
{
m_RastCtx.pTexture[0] = HANDLE_TO_SPANTEX(uStateVal);
}
// map stage 0 state to first texture
MapTextureStage0State();
UpdateActiveTexStageCount();
break;
case D3DHAL_TSS_TEXTUREMAP0:
// Silently zero out legacy handle. They didn't mean it.
if (m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] != 0 &&
uStateVal != 0)
{
m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] = 0;
}
CHECK_AND_UNLOCK_TEXTURE;
if (uStateVal == 0)
{
if (m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] == 0)
{
m_RastCtx.pTexture[0] = NULL;
}
// don't set m_RastCtx.pTexture[1] = NULL (in case the handle is never
// sent again). cActTex will keep it from being used until pTexture[0] is
// set to something
}
else
{
#if DBG
if (HANDLE_TO_SPANTEX(uStateVal) == m_RastCtx.pTexture[1])
{
D3D_ERR( "Stage1 and 2 have same texture handle." );
return DDERR_INVALIDPARAMS;
}
#endif
m_RastCtx.pTexture[0] = HANDLE_TO_SPANTEX(uStateVal);
}
// map stage 0 state to first texture
MapTextureStage0State();
UpdateActiveTexStageCount();
break;
case D3DHAL_TSS_TEXTUREMAP1:
// Silently zero out legacy handle. They didn't mean it.
if (m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] != 0 &&
uStateVal != 0)
{
m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] = 0;
}
CHECK_AND_UNLOCK_TEXTURE;
if (uStateVal == 0)
{
m_RastCtx.pTexture[1] = NULL;
}
else
{
// 2nd texture can only be enabled if there's an active
// 1st texture, but computation of cActTex will prevent this
// from happening
#if DBG
if (HANDLE_TO_SPANTEX(uStateVal) == m_RastCtx.pTexture[0])
{
D3D_ERR( "Stage1 and 2 have same texture handle." );
return DDERR_INVALIDPARAMS;
}
#endif
m_RastCtx.pTexture[1] = HANDLE_TO_SPANTEX(uStateVal);
}
// map stage 1 state to second texture
MapTextureStage1State();
UpdateActiveTexStageCount();
break;
// map single set ADDRESS to both U and V controls for stages 0 & 1
case D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESS):
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSU)] = uStateVal;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSV)] = uStateVal;
MapTextureStage0State();
break;
case D3DHAL_TSS_OFFSET(1,D3DTSS_ADDRESS):
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_ADDRESSU)] = uStateVal;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_ADDRESSV)] = uStateVal;
MapTextureStage1State();
break;
case D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSU):
case D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSV):
case D3DHAL_TSS_OFFSET(0,D3DTSS_MIPMAPLODBIAS):
case D3DHAL_TSS_OFFSET(0,D3DTSS_MAXMIPLEVEL):
case D3DHAL_TSS_OFFSET(0,D3DTSS_BORDERCOLOR):
case D3DHAL_TSS_OFFSET(0,D3DTSS_MAGFILTER):
case D3DHAL_TSS_OFFSET(0,D3DTSS_MINFILTER):
case D3DHAL_TSS_OFFSET(0,D3DTSS_MIPFILTER):
MapTextureStage0State();
break;
case D3DHAL_TSS_OFFSET(1,D3DTSS_ADDRESSU):
case D3DHAL_TSS_OFFSET(1,D3DTSS_ADDRESSV):
case D3DHAL_TSS_OFFSET(1,D3DTSS_MIPMAPLODBIAS):
case D3DHAL_TSS_OFFSET(1,D3DTSS_MAXMIPLEVEL):
case D3DHAL_TSS_OFFSET(1,D3DTSS_BORDERCOLOR):
case D3DHAL_TSS_OFFSET(1,D3DTSS_MAGFILTER):
case D3DHAL_TSS_OFFSET(1,D3DTSS_MINFILTER):
case D3DHAL_TSS_OFFSET(1,D3DTSS_MIPFILTER):
MapTextureStage1State();
break;
case D3DHAL_TSS_OFFSET(0,D3DTSS_COLOROP):
case D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG1):
case D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG2):
case D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAOP):
case D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG1):
case D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG2):
case D3DHAL_TSS_OFFSET(1,D3DTSS_COLOROP):
case D3DHAL_TSS_OFFSET(1,D3DTSS_COLORARG1):
case D3DHAL_TSS_OFFSET(1,D3DTSS_COLORARG2):
case D3DHAL_TSS_OFFSET(1,D3DTSS_ALPHAOP):
case D3DHAL_TSS_OFFSET(1,D3DTSS_ALPHAARG1):
case D3DHAL_TSS_OFFSET(1,D3DTSS_ALPHAARG2):
// anything that effects the validity of the texture blending
// could change the number of active texture stages
UpdateActiveTexStageCount();
break;
}
return D3D_OK;
}
//-----------------------------------------------------------------------------
//
// UpdateActiveTexStageCount - Steps through per-stage renderstate and computes
// a count of currently active texture stages. For legacy texture, the count
// is at most one.
//
//-----------------------------------------------------------------------------
HRESULT D3DContext::UpdateActiveTexStageCount( void )
{
HRESULT hr;
UINT cNewActTex = 0;
// conservative but correct
if ((hr = ValidateTextureStageState()) == D3D_OK)
{
// always one active texture stage for legacy texture mode
if ( NULL != m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] )
{
cNewActTex = 1;
}
else
{
// count number of contiguous-from-zero active texture blend stages
for ( INT iStage=0; iStage<2; iStage++ )
{
// check for disabled stage (subsequent are thus inactive)
// also conservatively checks for incorrectly enabled stage (might be legacy)
if ( ( m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(iStage,D3DTSS_COLOROP)] == D3DTOP_DISABLE ) ||
( m_RastCtx.pTexture[iStage] == NULL ) )
{
break;
}
// stage is active
cNewActTex ++;
}
}
}
if (m_RastCtx.cActTex != cNewActTex)
{
CHECK_AND_UNLOCK_TEXTURE;
StateChanged(D3DRENDERSTATE_TEXTUREHANDLE);
m_RastCtx.cActTex = cNewActTex;
}
return hr;
}
//----------------------------------------------------------------------------
//
// UpdateRenderStates
//
// Update a list of render states and notify components of state change.
//
//----------------------------------------------------------------------------
HRESULT D3DContext::
UpdateRenderStates(LPDWORD puStateChange, UINT cStateChanges)
{
HRESULT hr;
INT i;
UINT32 State, StateVal;
if (cStateChanges == 0)
{
return D3D_OK;
}
// Update the D3DCTX
for (i = 0; i < (INT)cStateChanges; i++)
{
State = *puStateChange ++;
StateVal = * puStateChange++;
HR_RET(SetRenderState(State, StateVal));
}
return D3D_OK;
}
//----------------------------------------------------------------------------
//
// UpdateAllRenderStates
//
// Update all render states.
// It is still kept here because we probably need it in the case of fail-over.
//
//----------------------------------------------------------------------------
HRESULT
D3DContext::UpdateAllRenderStates(LPDWORD puStates)
{
HRESULT hr, hrSet;
INT i;
DDASSERT(puStates != NULL);
// Update D3DCTX.
// Attempt to set as many states as possible, even if there are
// errors on some. This allows context initialization to work
// even though some of the states fail due to dependencies on
// other state, such as active texture handles.
// SetRenderState failures are noted and returned eventually,
// even if everything else succeeds.
hrSet = D3D_OK;
for (i = 0; i < D3DHAL_MAX_RSTATES_AND_STAGES; i++)
{
if ((hr = SetRenderState(i, puStates[i])) != D3D_OK)
{
hrSet = hr;
}
}
return hrSet;
}
//----------------------------------------------------------------------------
//
// Dp2SetRenderStates
//
// Called by Drawprim2 to set render states..
//
//----------------------------------------------------------------------------
HRESULT
D3DContext::Dp2SetRenderStates(LPD3DHAL_DP2COMMAND pCmd, LPDWORD lpdwRuntimeRStates)
{
WORD wStateCount = pCmd->wStateCount;
INT i;
HRESULT hr;
D3DHAL_DP2RENDERSTATE *pRenderState =
(D3DHAL_DP2RENDERSTATE *)(pCmd + 1);
// Flush the prim proc before any state changs
HR_RET(End(FALSE));
for (i = 0; i < (INT)wStateCount; i++, pRenderState++)
{
UINT32 type = (UINT32) pRenderState->RenderState;
// Check for overrides
if (IS_OVERRIDE(type)) {
UINT32 override = GET_OVERRIDE(type);
if (pRenderState->dwState)
STATESET_SET(m_renderstate_override, override);
else
STATESET_CLEAR(m_renderstate_override, override);
continue;
}
if (STATESET_ISSET(m_renderstate_override, type))
continue;
// Set the runtime copy (if necessary)
if (NULL != lpdwRuntimeRStates)
{
lpdwRuntimeRStates[pRenderState->RenderState] = pRenderState->dwState;
}
// Set the state
HR_RET(SetRenderState(pRenderState->RenderState,
pRenderState->dwState));
}
hr = Begin();
return hr;
}
//----------------------------------------------------------------------------
//
// Begin - Before rendering preparation
//
//
//----------------------------------------------------------------------------
HRESULT
D3DContext::Begin(void)
{
HRESULT hr;
DDASSERT((m_uFlags & D3DCONTEXT_IN_BEGIN) == 0);
// ATTENTION call this less often?
UpdateColorKeyAndPalette();
// Check for state changes
if (IsAnyStatesChanged())
{
// Check for fillmode change
if (IsStateChanged(D3DRENDERSTATE_FILLMODE))
{
UpdatePrimFunctionTbl();
}
BOOL bMaxMipLevelsDirty = FALSE;
for (INT j = 0; j < (INT)m_RastCtx.cActTex; j++)
{
PD3DI_SPANTEX pSpanTex = m_RastCtx.pTexture[j];
if (pSpanTex)
{
bMaxMipLevelsDirty = bMaxMipLevelsDirty || (pSpanTex->uFlags & D3DI_SPANTEX_MAXMIPLEVELS_DIRTY);
}
}
if (IsStateChanged(D3DRENDERSTATE_TEXTUREHANDLE) ||
IsStateChanged(D3DHAL_TSS_TEXTUREMAP0) ||
IsStateChanged(D3DHAL_TSS_TEXTUREMAP1) ||
bMaxMipLevelsDirty)
{
// Relock texture if texture handles have changed.
// SetRenderState should have already unlocked the texture.
if (m_uFlags & D3DCONTEXT_TEXTURE_LOCKED)
{
RastUnlockSpanTexture();
}
HR_RET(RastLockSpanTexture());
}
// Check for WRAP state change
for (int iWrap=0; iWrap<8; iWrap++)
{
D3DRENDERSTATETYPE iWrapState = (D3DRENDERSTATETYPE)(D3DRENDERSTATE_WRAP0+iWrap);
if (IsStateChanged(iWrapState))
{
int i;
for (i=0; i < 2; i++)
{
if (m_fvfData.TexIdx[i] == iWrap)
{
m_RastCtx.pdwWrap[i] = m_RastCtx.pdwRenderState[iWrapState];
}
}
}
}
// Notify primitive Processor of state change.
m_PrimProc.StateChanged();
// Clear state dirtybits
ClearAllStatesDirtyBits();
// Must call SpanInit AFTER texture is locked, since this
// sets various flags and fields that are needed for bead choosing
// Call SpanInit to setup the beads
HR_RET(SpanInit(&m_RastCtx));
}
// If texture is not locked yet, lock it
if (!(m_uFlags & D3DCONTEXT_TEXTURE_LOCKED))
{
HR_RET(RastLockSpanTexture());
}
// Lock rendering target.
if ((hr=LockSurface(m_RastCtx.pDDS, (LPVOID *)&(m_RastCtx.pSurfaceBits))) != D3D_OK)
{
RastUnlockSpanTexture();
return hr;
}
if (m_RastCtx.pDDSZ != NULL)
{
if ((hr=LockSurface(m_RastCtx.pDDSZ, (LPVOID *)&(m_RastCtx.pZBits))) != D3D_OK)
{
RastUnlockSpanTexture();
UnlockSurface(m_RastCtx.pDDS);
return hr;
}
}
else
{
m_RastCtx.pZBits = NULL;
}
// Prepare the primitive processor
m_PrimProc.Begin();
m_uFlags |= D3DCONTEXT_IN_BEGIN;
if (m_RastCtx.pRampDrv)
{
pTexRampmapSave = m_RastCtx.pTexRampMap;
}
return D3D_OK;
}
//-----------------------------------------------------------------------------
//
// MapTextureStage0/1State - Maps state0/stage1 texture state to spantex object
//
//-----------------------------------------------------------------------------
void
D3DContext::MapTextureStage0State( void )
{
if (m_RastCtx.pTexture[0] == NULL) return;
//
// assign texture state from stage 0
//
m_RastCtx.pTexture[0]->TexAddrU = (D3DTEXTUREADDRESS)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSU)]);
m_RastCtx.pTexture[0]->TexAddrV = (D3DTEXTUREADDRESS)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ADDRESSV)]);
m_RastCtx.pTexture[0]->BorderColor = (D3DCOLOR)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_BORDERCOLOR)]);
m_RastCtx.pTexture[0]->uMagFilter = (D3DTEXTUREMAGFILTER)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MAGFILTER)]);
m_RastCtx.pTexture[0]->uMinFilter = (D3DTEXTUREMINFILTER)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MINFILTER)]);
m_RastCtx.pTexture[0]->uMipFilter = (D3DTEXTUREMIPFILTER)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MIPFILTER)]);
m_RastCtx.pTexture[0]->cLOD =
(D3DTFP_NONE == m_RastCtx.pTexture[0]->uMipFilter)
? 0 : m_RastCtx.pTexture[0]->cLODTex;
{
m_RastCtx.pTexture[0]->fLODBias = m_RastCtx.pfRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MIPMAPLODBIAS)];
}
if (m_RastCtx.pTexture[0]->iMaxMipLevel != (INT32)m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MAXMIPLEVEL)])
{
m_RastCtx.pTexture[0]->iMaxMipLevel = (INT32)m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MAXMIPLEVEL)];
m_RastCtx.pTexture[0]->uFlags |= D3DI_SPANTEX_MAXMIPLEVELS_DIRTY;
}
}
void
D3DContext::MapTextureStage1State( void )
{
if (m_RastCtx.pTexture[1] == NULL) return;
//
// assign texture state from stage 0
//
m_RastCtx.pTexture[1]->TexAddrU = (D3DTEXTUREADDRESS)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_ADDRESSU)]);
m_RastCtx.pTexture[1]->TexAddrV = (D3DTEXTUREADDRESS)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_ADDRESSV)]);
m_RastCtx.pTexture[1]->BorderColor = (D3DCOLOR)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_BORDERCOLOR)]);
m_RastCtx.pTexture[1]->uMagFilter = (D3DTEXTUREMAGFILTER)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_MAGFILTER)]);
m_RastCtx.pTexture[1]->uMinFilter = (D3DTEXTUREMINFILTER)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_MINFILTER)]);
m_RastCtx.pTexture[1]->uMipFilter = (D3DTEXTUREMIPFILTER)(m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_MIPFILTER)]);
m_RastCtx.pTexture[1]->cLOD =
(D3DTFP_NONE == m_RastCtx.pTexture[1]->uMipFilter)
? 0 : m_RastCtx.pTexture[1]->cLODTex;
{
m_RastCtx.pTexture[1]->fLODBias = m_RastCtx.pfRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_MIPMAPLODBIAS)];
}
if (m_RastCtx.pTexture[1]->iMaxMipLevel != (INT32)m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_MAXMIPLEVEL)])
{
m_RastCtx.pTexture[1]->iMaxMipLevel = (INT32)m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_MAXMIPLEVEL)];
m_RastCtx.pTexture[1]->uFlags |= D3DI_SPANTEX_MAXMIPLEVELS_DIRTY;
}
}
//-----------------------------------------------------------------------------
//
// MapLegacyTextureFilter -
//
//-----------------------------------------------------------------------------
void
D3DContext::MapLegacyTextureFilter( void )
{
// D3D legacy filter specifications are (XXXMIP)YYY where XXX is the
// mip filter and YYY is the filter used within an LOD
// map MAG filter - legacy support is point or linear (and maybe aniso)
switch ( m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREMAG] )
{
default:
case D3DFILTER_NEAREST:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MAGFILTER)] = D3DTFG_POINT;
break;
case D3DFILTER_LINEAR:
// select based on aniso enable
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MAGFILTER)] = D3DTFG_LINEAR;
break;
}
// map MIN and MIP filter at the same time - legacy support
// has them intermingled...
switch ( m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREMIN] )
{
case D3DFILTER_NEAREST:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MINFILTER)] = D3DTFN_POINT;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MIPFILTER)] = D3DTFP_NONE;
break;
case D3DFILTER_MIPNEAREST:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MINFILTER)] = D3DTFN_POINT;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MIPFILTER)] = D3DTFP_POINT;
break;
case D3DFILTER_LINEARMIPNEAREST:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MINFILTER)] = D3DTFN_POINT;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MIPFILTER)] = D3DTFP_LINEAR;
break;
case D3DFILTER_LINEAR:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MINFILTER)] = D3DTFN_LINEAR;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MIPFILTER)] = D3DTFP_NONE;
break;
case D3DFILTER_MIPLINEAR:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MINFILTER)] = D3DTFN_LINEAR;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MIPFILTER)] = D3DTFP_POINT;
break;
case D3DFILTER_LINEARMIPLINEAR:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MINFILTER)] = D3DTFN_LINEAR;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_MIPFILTER)] = D3DTFP_LINEAR;
break;
}
}
//-----------------------------------------------------------------------------
//
// MapLegacyTextureBlend - Maps legacy (pre-DX6) texture blend modes to DX6
// texture blending controls. Uses per-stage program mode (first stage only).
// This mapping is done whenever the legacy TBLEND renderstate is set, and
// does overwrite any previously set DX6 texture blending controls.
//
//-----------------------------------------------------------------------------
void
D3DContext::MapLegacyTextureBlend( void )
{
// disable texture blend processing stage 1 (this also disables subsequent stages)
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(1,D3DTSS_COLOROP)] = D3DTOP_DISABLE;
// set texture blend processing stage 0 to match legacy mode
switch ( m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREMAPBLEND] )
{
default:
case D3DTBLEND_DECALMASK: // unsupported - do decal
case D3DTBLEND_DECAL:
case D3DTBLEND_COPY:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLOROP)] = D3DTOP_SELECTARG1;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG1)] = D3DTA_TEXTURE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAOP)] = D3DTOP_SELECTARG1;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG1)] = D3DTA_TEXTURE;
break;
case D3DTBLEND_MODULATEMASK: // unsupported - do modulate
case D3DTBLEND_MODULATE:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLOROP)] = D3DTOP_MODULATE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG1)] = D3DTA_TEXTURE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG2)] = D3DTA_DIFFUSE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAOP)] = D3DTOP_SELECTARG1;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG1)] = D3DTA_TEXTURE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG2)] = D3DTA_DIFFUSE;
break;
case D3DTBLEND_MODULATEALPHA:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLOROP)] = D3DTOP_MODULATE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG1)] = D3DTA_TEXTURE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG2)] = D3DTA_DIFFUSE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAOP)] = D3DTOP_MODULATE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG1)] = D3DTA_TEXTURE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG2)] = D3DTA_DIFFUSE;
break;
case D3DTBLEND_DECALALPHA:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLOROP)] = D3DTOP_BLENDTEXTUREALPHA;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG1)] = D3DTA_TEXTURE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG2)] = D3DTA_DIFFUSE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAOP)] = D3DTOP_SELECTARG2;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG1)] = D3DTA_TEXTURE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG2)] = D3DTA_DIFFUSE;
break;
case D3DTBLEND_ADD:
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLOROP)] = D3DTOP_ADD;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG1)] = D3DTA_TEXTURE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_COLORARG2)] = D3DTA_DIFFUSE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAOP)] = D3DTOP_SELECTARG2;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG1)] = D3DTA_TEXTURE;
m_RastCtx.pdwRenderState[D3DHAL_TSS_OFFSET(0,D3DTSS_ALPHAARG2)] = D3DTA_DIFFUSE;
break;
}
// since we change [D3DHAL_TSS_OFFSET(0,D3DTSS_COLOROP), we can go from DISABLE to
// something else, and we can need to update the TexStageCount
UpdateActiveTexStageCount();
}