|
|
//----------------------------------------------------------------------------
//
// 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(); }
|