//---------------------------------------------------------------------------- // // rastctx.cpp // // Context functions + state functions. // // Copyright (C) Microsoft Corporation, 1997. // //---------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop // 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(); \ } \ } //---------------------------------------------------------------------------- // // 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_uFlags |= D3DCONTEXT_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; // 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, 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 = RGB_StoreLastPixelState; m_fnPrims.pfnDp2SetRenderStates = RGB_Dp2SetRenderStates; m_fnPrims.pfnDp2TextureStageState = RGB_Dp2TextureStageState; m_fnPrims.pfnDp2SetViewport = RGB_Dp2SetViewport; m_fnPrims.pfnDp2SetWRange = RGB_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; } //---------------------------------------------------------------------------- // // RastContextCreateC // // Calls RastContextCreate with the C bead set. // //---------------------------------------------------------------------------- DWORD __stdcall RastContextCreateC(LPD3DHAL_CONTEXTCREATEDATA pCtxData) { return RastContextCreate(pCtxData, (DWORD)D3DIBS_C); } //---------------------------------------------------------------------------- // // 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); } //---------------------------------------------------------------------------- // // 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) { // 8 bit surfaces no longer supported by DX7 // AnanKan: Need to return a proer error message. pCtxData->ddrval = DDERR_OUTOFMEMORY; return DDHAL_DRIVER_HANDLED; } 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(); 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 < D3DHAL_TSS_MAXSTAGES; i++) { switch(m_RastCtx.pdwTextureStageState[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: case D3DTOP_ADDSIGNED2X: case D3DTOP_SUBTRACT: case D3DTOP_ADDSMOOTH: case D3DTOP_MODULATEALPHA_ADDCOLOR: case D3DTOP_MODULATECOLOR_ADDALPHA: break; } switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_COLORARG1] & ~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT)) { default: return D3DERR_UNSUPPORTEDCOLORARG; case (D3DTA_TEXTURE): break; } switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_COLORARG2] & ~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT)) { default: return D3DERR_UNSUPPORTEDCOLORARG; case (D3DTA_TFACTOR): case (D3DTA_CURRENT): case (D3DTA_DIFFUSE): case (D3DTA_SPECULAR): break; } switch(m_RastCtx.pdwTextureStageState[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: case D3DTOP_ADDSIGNED2X: case D3DTOP_SUBTRACT: case D3DTOP_ADDSMOOTH: // only validate alpha args if alpha op is not disable switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_ALPHAARG1] & ~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT)) { default: return D3DERR_UNSUPPORTEDALPHAARG; case (D3DTA_TEXTURE): break; } switch(m_RastCtx.pdwTextureStageState[i][D3DTSS_ALPHAARG2] & ~(D3DTA_ALPHAREPLICATE|D3DTA_COMPLEMENT)) { default: return D3DERR_UNSUPPORTEDALPHAARG; case (D3DTA_TFACTOR): case (D3DTA_CURRENT): case (D3DTA_DIFFUSE): case (D3DTA_SPECULAR): break; } break; } } 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; } //---------------------------------------------------------------------------- // // 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: 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.pdwTextureStageState[0][D3DTSS_ADDRESS] = m_RastCtx.pdwTextureStageState[0][D3DTSS_ADDRESSU] = m_RastCtx.pdwTextureStageState[0][D3DTSS_ADDRESSV] = uStateVal; MapTextureStageState(0); break; case D3DRENDERSTATE_TEXTUREADDRESSU: m_RastCtx.pdwTextureStageState[0][D3DTSS_ADDRESSU] = uStateVal; MapTextureStageState(0); break; case D3DRENDERSTATE_TEXTUREADDRESSV: m_RastCtx.pdwTextureStageState[0][D3DTSS_ADDRESSV] = uStateVal; MapTextureStageState(0); break; case D3DRENDERSTATE_MIPMAPLODBIAS: m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPMAPLODBIAS] = uStateVal; MapTextureStageState(0); break; case D3DRENDERSTATE_BORDERCOLOR: m_RastCtx.pdwTextureStageState[0][D3DTSS_BORDERCOLOR] = uStateVal; MapTextureStageState(0); break; case D3DRENDERSTATE_TEXTUREMAG: case D3DRENDERSTATE_TEXTUREMIN: // map legacy filtering/sampling state to texture stage 0 MapLegacyTextureFilter(); // assign to current texture MapTextureStageState(0); 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.pdwTextureStageState[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 MapTextureStageState(0); UpdateActiveTexStageCount(); break; } return D3D_OK; } HRESULT D3DContext::SetTextureStageState(DWORD dwStage, DWORD dwState, DWORD uStateVal) { // Assume d3dim has filtered out unchanged states StateChanged(RAST_TSS_DIRTYBIT(dwStage, dwState)); m_RastCtx.pdwTextureStageState[dwStage][dwState] = uStateVal; switch (dwState) { case D3DTSS_TEXTUREMAP: // 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 (dwStage == 0) { if (m_RastCtx.pdwRenderState[D3DRENDERSTATE_TEXTUREHANDLE] == 0 ) { m_RastCtx.pTexture[0] = NULL; } } else { m_RastCtx.pTexture[dwStage] = NULL; } // disables higher stages also, but don't clear pTexture[i]'s // since they may be used later when this stage is set to non-NULL } else { // if lower stages are null, this will be noted by UpdateActiveTexStageCount m_RastCtx.pTexture[dwStage] = HANDLE_TO_SPANTEX(uStateVal); } #if DBG if (m_RastCtx.pTexture[dwStage]) { int iTexCount = 0; for (int i = 0; i < D3DHAL_TSS_MAXSTAGES; i++) { if (m_RastCtx.pTexture[dwStage] == m_RastCtx.pTexture[i]) { iTexCount ++; } } if (iTexCount > 1) { D3D_ERR( "Same texture handle was used more than once." ); return DDERR_INVALIDPARAMS; } } #endif // map stage state to texture MapTextureStageState(dwStage); UpdateActiveTexStageCount(); break; // map single set ADDRESS to both U and V controls for stages 0 & 1 case D3DTSS_ADDRESS: m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_ADDRESSU] = uStateVal; m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_ADDRESSV] = uStateVal; MapTextureStageState(dwStage); break; case D3DTSS_ADDRESSU: case D3DTSS_ADDRESSV: case D3DTSS_MIPMAPLODBIAS: case D3DTSS_MAXMIPLEVEL: case D3DTSS_BORDERCOLOR: case D3DTSS_MAGFILTER: case D3DTSS_MINFILTER: case D3DTSS_MIPFILTER: MapTextureStageState(dwStage); break; case D3DTSS_COLOROP: case D3DTSS_COLORARG1: case D3DTSS_COLORARG2: case D3DTSS_ALPHAOP: case D3DTSS_ALPHAARG1: case 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; iStagewStateCount; 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; // 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(RAST_TSS_DIRTYBIT(0, D3DTSS_TEXTUREMAP)) || IsStateChanged(RAST_TSS_DIRTYBIT(1, D3DTSS_TEXTUREMAP)) || 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 < D3DHAL_TSS_MAXSTAGES; 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; return D3D_OK; } //----------------------------------------------------------------------------- // // MapTextureStageState - Maps statestage texture state to spantex object // //----------------------------------------------------------------------------- void D3DContext::MapTextureStageState( DWORD dwStage ) { if (m_RastCtx.pTexture[dwStage] == NULL) return; // // assign texture state from stage 0 // m_RastCtx.pTexture[dwStage]->TexAddrU = (D3DTEXTUREADDRESS)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_ADDRESSU]); m_RastCtx.pTexture[dwStage]->TexAddrV = (D3DTEXTUREADDRESS)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_ADDRESSV]); m_RastCtx.pTexture[dwStage]->BorderColor = (D3DCOLOR)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_BORDERCOLOR]); m_RastCtx.pTexture[dwStage]->uMagFilter = (D3DTEXTUREMAGFILTER)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MAGFILTER]); m_RastCtx.pTexture[dwStage]->uMinFilter = (D3DTEXTUREMINFILTER)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MINFILTER]); m_RastCtx.pTexture[dwStage]->uMipFilter = (D3DTEXTUREMIPFILTER)(m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MIPFILTER]); m_RastCtx.pTexture[dwStage]->fLODBias = m_RastCtx.pfTextureStageState[dwStage][D3DTSS_MIPMAPLODBIAS]; if (m_RastCtx.pTexture[dwStage]->iMaxMipLevel != (INT32)m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MAXMIPLEVEL]) { m_RastCtx.pTexture[dwStage]->iMaxMipLevel = (INT32)m_RastCtx.pdwTextureStageState[dwStage][D3DTSS_MAXMIPLEVEL]; m_RastCtx.pTexture[dwStage]->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.pdwTextureStageState[0][D3DTSS_MAGFILTER] = D3DTFG_POINT; break; case D3DFILTER_LINEAR: // select based on aniso enable m_RastCtx.pdwTextureStageState[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.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_POINT; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_NONE; break; case D3DFILTER_MIPNEAREST: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_POINT; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_POINT; break; case D3DFILTER_LINEARMIPNEAREST: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_POINT; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_LINEAR; break; case D3DFILTER_LINEAR: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_LINEAR; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_NONE; break; case D3DFILTER_MIPLINEAR: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_LINEAR; m_RastCtx.pdwTextureStageState[0][D3DTSS_MIPFILTER] = D3DTFP_POINT; break; case D3DFILTER_LINEARMIPLINEAR: m_RastCtx.pdwTextureStageState[0][D3DTSS_MINFILTER] = D3DTFN_LINEAR; m_RastCtx.pdwTextureStageState[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.pdwTextureStageState[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.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_SELECTARG1; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG1; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; break; case D3DTBLEND_MODULATEMASK: // unsupported - do modulate case D3DTBLEND_MODULATE: m_RastCtx.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_MODULATE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG2] = D3DTA_DIFFUSE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG1; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG2] = D3DTA_DIFFUSE; break; case D3DTBLEND_MODULATEALPHA: m_RastCtx.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_MODULATE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG2] = D3DTA_DIFFUSE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_MODULATE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG2] = D3DTA_DIFFUSE; break; case D3DTBLEND_DECALALPHA: m_RastCtx.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_BLENDTEXTUREALPHA; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG2] = D3DTA_DIFFUSE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG2; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG2] = D3DTA_DIFFUSE; break; case D3DTBLEND_ADD: m_RastCtx.pdwTextureStageState[0][D3DTSS_COLOROP] = D3DTOP_ADD; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[0][D3DTSS_COLORARG2] = D3DTA_DIFFUSE; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAOP] = D3DTOP_SELECTARG2; m_RastCtx.pdwTextureStageState[0][D3DTSS_ALPHAARG1] = D3DTA_TEXTURE; m_RastCtx.pdwTextureStageState[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(); }